allow method calls on opaques
This commit is contained in:
@@ -13,7 +13,7 @@ use rustc_hir::def::DefKind;
|
|||||||
use rustc_hir_analysis::autoderef::{self, Autoderef};
|
use rustc_hir_analysis::autoderef::{self, Autoderef};
|
||||||
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
|
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
|
||||||
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TyCtxtInferExt};
|
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::{ObligationCauseCode, query};
|
use rustc_infer::traits::{ObligationCauseCode, PredicateObligation, query};
|
||||||
use rustc_middle::middle::stability;
|
use rustc_middle::middle::stability;
|
||||||
use rustc_middle::ty::elaborate::supertrait_def_ids;
|
use rustc_middle::ty::elaborate::supertrait_def_ids;
|
||||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type};
|
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type};
|
||||||
@@ -30,6 +30,7 @@ use rustc_span::edit_distance::{
|
|||||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
|
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
|
||||||
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
|
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
|
||||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||||
|
use rustc_trait_selection::solve::Goal;
|
||||||
use rustc_trait_selection::traits::query::CanonicalMethodAutoderefStepsGoal;
|
use rustc_trait_selection::traits::query::CanonicalMethodAutoderefStepsGoal;
|
||||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::query::method_autoderef::{
|
use rustc_trait_selection::traits::query::method_autoderef::{
|
||||||
@@ -417,6 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
steps: infcx.tcx.arena.alloc_from_iter([CandidateStep {
|
steps: infcx.tcx.arena.alloc_from_iter([CandidateStep {
|
||||||
self_ty: self
|
self_ty: self
|
||||||
.make_query_response_ignoring_pending_obligations(var_values, self_ty),
|
.make_query_response_ignoring_pending_obligations(var_values, self_ty),
|
||||||
|
self_ty_is_opaque: false,
|
||||||
autoderefs: 0,
|
autoderefs: 0,
|
||||||
from_unsafe_deref: false,
|
from_unsafe_deref: false,
|
||||||
unsize: false,
|
unsize: false,
|
||||||
@@ -590,6 +592,17 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We accept not-yet-defined opaque types in the autoderef
|
||||||
|
// chain to support recursive calls. We do error if the final
|
||||||
|
// infer var is not an opaque.
|
||||||
|
let self_ty_is_opaque = |ty: Ty<'_>| {
|
||||||
|
if let &ty::Infer(ty::TyVar(vid)) = ty.kind() {
|
||||||
|
infcx.has_opaques_with_sub_unified_hidden_type(vid)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// If arbitrary self types is not enabled, we follow the chain of
|
// If arbitrary self types is not enabled, we follow the chain of
|
||||||
// `Deref<Target=T>`. If arbitrary self types is enabled, we instead
|
// `Deref<Target=T>`. If arbitrary self types is enabled, we instead
|
||||||
// follow the chain of `Receiver<Target=T>`, but we also record whether
|
// follow the chain of `Receiver<Target=T>`, but we also record whether
|
||||||
@@ -623,6 +636,7 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
|||||||
let step = CandidateStep {
|
let step = CandidateStep {
|
||||||
self_ty: infcx
|
self_ty: infcx
|
||||||
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
|
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
|
||||||
|
self_ty_is_opaque: self_ty_is_opaque(ty),
|
||||||
autoderefs: d,
|
autoderefs: d,
|
||||||
from_unsafe_deref: reached_raw_pointer,
|
from_unsafe_deref: reached_raw_pointer,
|
||||||
unsize: false,
|
unsize: false,
|
||||||
@@ -643,6 +657,7 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
|||||||
let step = CandidateStep {
|
let step = CandidateStep {
|
||||||
self_ty: infcx
|
self_ty: infcx
|
||||||
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
|
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
|
||||||
|
self_ty_is_opaque: self_ty_is_opaque(ty),
|
||||||
autoderefs: d,
|
autoderefs: d,
|
||||||
from_unsafe_deref: reached_raw_pointer,
|
from_unsafe_deref: reached_raw_pointer,
|
||||||
unsize: false,
|
unsize: false,
|
||||||
@@ -659,7 +674,11 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
|||||||
};
|
};
|
||||||
let final_ty = autoderef_via_deref.final_ty();
|
let final_ty = autoderef_via_deref.final_ty();
|
||||||
let opt_bad_ty = match final_ty.kind() {
|
let opt_bad_ty = match final_ty.kind() {
|
||||||
ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
|
ty::Infer(ty::TyVar(_)) if !self_ty_is_opaque(final_ty) => Some(MethodAutoderefBadTy {
|
||||||
|
reached_raw_pointer,
|
||||||
|
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
|
||||||
|
}),
|
||||||
|
ty::Error(_) => Some(MethodAutoderefBadTy {
|
||||||
reached_raw_pointer,
|
reached_raw_pointer,
|
||||||
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
|
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
|
||||||
}),
|
}),
|
||||||
@@ -670,6 +689,7 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
|||||||
inference_vars,
|
inference_vars,
|
||||||
Ty::new_slice(infcx.tcx, *elem_ty),
|
Ty::new_slice(infcx.tcx, *elem_ty),
|
||||||
),
|
),
|
||||||
|
self_ty_is_opaque: false,
|
||||||
autoderefs,
|
autoderefs,
|
||||||
// this could be from an unsafe deref if we had
|
// this could be from an unsafe deref if we had
|
||||||
// a *mut/const [T; N]
|
// a *mut/const [T; N]
|
||||||
@@ -1234,7 +1254,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
!step.self_ty.value.references_error() && !step.from_unsafe_deref
|
!step.self_ty.value.references_error() && !step.from_unsafe_deref
|
||||||
})
|
})
|
||||||
.find_map(|step| {
|
.find_map(|step| {
|
||||||
let InferOk { value: self_ty, obligations: _ } = self
|
let InferOk { value: self_ty, obligations: instantiate_self_ty_obligations } = self
|
||||||
.fcx
|
.fcx
|
||||||
.probe_instantiate_query_response(
|
.probe_instantiate_query_response(
|
||||||
self.span,
|
self.span,
|
||||||
@@ -1245,7 +1265,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
|
span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
|
||||||
});
|
});
|
||||||
|
|
||||||
let by_value_pick = self.pick_by_value_method(step, self_ty, pick_diag_hints);
|
let by_value_pick = self.pick_by_value_method(
|
||||||
|
step,
|
||||||
|
self_ty,
|
||||||
|
&instantiate_self_ty_obligations,
|
||||||
|
pick_diag_hints,
|
||||||
|
);
|
||||||
|
|
||||||
// Check for shadowing of a by-reference method by a by-value method (see comments on check_for_shadowing)
|
// Check for shadowing of a by-reference method by a by-value method (see comments on check_for_shadowing)
|
||||||
if let Some(by_value_pick) = by_value_pick {
|
if let Some(by_value_pick) = by_value_pick {
|
||||||
@@ -1256,6 +1281,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
by_value_pick,
|
by_value_pick,
|
||||||
step,
|
step,
|
||||||
self_ty,
|
self_ty,
|
||||||
|
&instantiate_self_ty_obligations,
|
||||||
mutbl,
|
mutbl,
|
||||||
track_unstable_candidates,
|
track_unstable_candidates,
|
||||||
) {
|
) {
|
||||||
@@ -1270,6 +1296,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
let autoref_pick = self.pick_autorefd_method(
|
let autoref_pick = self.pick_autorefd_method(
|
||||||
step,
|
step,
|
||||||
self_ty,
|
self_ty,
|
||||||
|
&instantiate_self_ty_obligations,
|
||||||
hir::Mutability::Not,
|
hir::Mutability::Not,
|
||||||
pick_diag_hints,
|
pick_diag_hints,
|
||||||
None,
|
None,
|
||||||
@@ -1283,6 +1310,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
autoref_pick,
|
autoref_pick,
|
||||||
step,
|
step,
|
||||||
self_ty,
|
self_ty,
|
||||||
|
&instantiate_self_ty_obligations,
|
||||||
hir::Mutability::Mut,
|
hir::Mutability::Mut,
|
||||||
track_unstable_candidates,
|
track_unstable_candidates,
|
||||||
) {
|
) {
|
||||||
@@ -1319,12 +1347,27 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
self.pick_autorefd_method(
|
self.pick_autorefd_method(
|
||||||
step,
|
step,
|
||||||
self_ty,
|
self_ty,
|
||||||
|
&instantiate_self_ty_obligations,
|
||||||
hir::Mutability::Mut,
|
hir::Mutability::Mut,
|
||||||
pick_diag_hints,
|
pick_diag_hints,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.or_else(|| self.pick_const_ptr_method(step, self_ty, pick_diag_hints))
|
.or_else(|| {
|
||||||
.or_else(|| self.pick_reborrow_pin_method(step, self_ty, pick_diag_hints))
|
self.pick_const_ptr_method(
|
||||||
|
step,
|
||||||
|
self_ty,
|
||||||
|
&instantiate_self_ty_obligations,
|
||||||
|
pick_diag_hints,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
self.pick_reborrow_pin_method(
|
||||||
|
step,
|
||||||
|
self_ty,
|
||||||
|
&instantiate_self_ty_obligations,
|
||||||
|
pick_diag_hints,
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1348,6 +1391,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
possible_shadower: &Pick<'tcx>,
|
possible_shadower: &Pick<'tcx>,
|
||||||
step: &CandidateStep<'tcx>,
|
step: &CandidateStep<'tcx>,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
|
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||||
mutbl: hir::Mutability,
|
mutbl: hir::Mutability,
|
||||||
track_unstable_candidates: bool,
|
track_unstable_candidates: bool,
|
||||||
) -> Result<(), MethodError<'tcx>> {
|
) -> Result<(), MethodError<'tcx>> {
|
||||||
@@ -1412,6 +1456,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
let potentially_shadowed_pick = self.pick_autorefd_method(
|
let potentially_shadowed_pick = self.pick_autorefd_method(
|
||||||
step,
|
step,
|
||||||
self_ty,
|
self_ty,
|
||||||
|
instantiate_self_ty_obligations,
|
||||||
mutbl,
|
mutbl,
|
||||||
&mut pick_diag_hints,
|
&mut pick_diag_hints,
|
||||||
Some(&pick_constraints),
|
Some(&pick_constraints),
|
||||||
@@ -1438,13 +1483,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
step: &CandidateStep<'tcx>,
|
step: &CandidateStep<'tcx>,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
|
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||||
) -> Option<PickResult<'tcx>> {
|
) -> Option<PickResult<'tcx>> {
|
||||||
if step.unsize {
|
if step.unsize {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pick_method(self_ty, pick_diag_hints, None).map(|r| {
|
self.pick_method(self_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map(|r| {
|
||||||
r.map(|mut pick| {
|
r.map(|mut pick| {
|
||||||
pick.autoderefs = step.autoderefs;
|
pick.autoderefs = step.autoderefs;
|
||||||
|
|
||||||
@@ -1481,6 +1527,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
step: &CandidateStep<'tcx>,
|
step: &CandidateStep<'tcx>,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
|
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||||
mutbl: hir::Mutability,
|
mutbl: hir::Mutability,
|
||||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||||
pick_constraints: Option<&PickConstraintsForShadowed>,
|
pick_constraints: Option<&PickConstraintsForShadowed>,
|
||||||
@@ -1497,7 +1544,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
let region = tcx.lifetimes.re_erased;
|
let region = tcx.lifetimes.re_erased;
|
||||||
|
|
||||||
let autoref_ty = Ty::new_ref(tcx, region, self_ty, mutbl);
|
let autoref_ty = Ty::new_ref(tcx, region, self_ty, mutbl);
|
||||||
self.pick_method(autoref_ty, pick_diag_hints, pick_constraints).map(|r| {
|
self.pick_method(
|
||||||
|
autoref_ty,
|
||||||
|
instantiate_self_ty_obligations,
|
||||||
|
pick_diag_hints,
|
||||||
|
pick_constraints,
|
||||||
|
)
|
||||||
|
.map(|r| {
|
||||||
r.map(|mut pick| {
|
r.map(|mut pick| {
|
||||||
pick.autoderefs = step.autoderefs;
|
pick.autoderefs = step.autoderefs;
|
||||||
pick.autoref_or_ptr_adjustment =
|
pick.autoref_or_ptr_adjustment =
|
||||||
@@ -1513,6 +1566,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
step: &CandidateStep<'tcx>,
|
step: &CandidateStep<'tcx>,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
|
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||||
) -> Option<PickResult<'tcx>> {
|
) -> Option<PickResult<'tcx>> {
|
||||||
if !self.tcx.features().pin_ergonomics() {
|
if !self.tcx.features().pin_ergonomics() {
|
||||||
@@ -1534,14 +1588,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
|
|
||||||
let region = self.tcx.lifetimes.re_erased;
|
let region = self.tcx.lifetimes.re_erased;
|
||||||
let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not);
|
let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not);
|
||||||
self.pick_method(autopin_ty, pick_diag_hints, None).map(|r| {
|
self.pick_method(autopin_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map(
|
||||||
|
|r| {
|
||||||
r.map(|mut pick| {
|
r.map(|mut pick| {
|
||||||
pick.autoderefs = step.autoderefs;
|
pick.autoderefs = step.autoderefs;
|
||||||
pick.autoref_or_ptr_adjustment =
|
pick.autoref_or_ptr_adjustment =
|
||||||
Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not));
|
Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not));
|
||||||
pick
|
pick
|
||||||
})
|
})
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a
|
/// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a
|
||||||
@@ -1551,6 +1607,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
step: &CandidateStep<'tcx>,
|
step: &CandidateStep<'tcx>,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
|
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||||
) -> Option<PickResult<'tcx>> {
|
) -> Option<PickResult<'tcx>> {
|
||||||
// Don't convert an unsized reference to ptr
|
// Don't convert an unsized reference to ptr
|
||||||
@@ -1563,18 +1620,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let const_ptr_ty = Ty::new_imm_ptr(self.tcx, ty);
|
let const_ptr_ty = Ty::new_imm_ptr(self.tcx, ty);
|
||||||
self.pick_method(const_ptr_ty, pick_diag_hints, None).map(|r| {
|
self.pick_method(const_ptr_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map(
|
||||||
|
|r| {
|
||||||
r.map(|mut pick| {
|
r.map(|mut pick| {
|
||||||
pick.autoderefs = step.autoderefs;
|
pick.autoderefs = step.autoderefs;
|
||||||
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
|
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
|
||||||
pick
|
pick
|
||||||
})
|
})
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pick_method(
|
fn pick_method(
|
||||||
&self,
|
&self,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
|
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||||
pick_constraints: Option<&PickConstraintsForShadowed>,
|
pick_constraints: Option<&PickConstraintsForShadowed>,
|
||||||
) -> Option<PickResult<'tcx>> {
|
) -> Option<PickResult<'tcx>> {
|
||||||
@@ -1584,8 +1644,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
|
[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
|
||||||
{
|
{
|
||||||
debug!("searching {} candidates", kind);
|
debug!("searching {} candidates", kind);
|
||||||
let res =
|
let res = self.consider_candidates(
|
||||||
self.consider_candidates(self_ty, candidates, pick_diag_hints, pick_constraints);
|
self_ty,
|
||||||
|
instantiate_self_ty_obligations,
|
||||||
|
candidates,
|
||||||
|
pick_diag_hints,
|
||||||
|
pick_constraints,
|
||||||
|
);
|
||||||
if let Some(pick) = res {
|
if let Some(pick) = res {
|
||||||
return Some(pick);
|
return Some(pick);
|
||||||
}
|
}
|
||||||
@@ -1594,6 +1659,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
if self.private_candidate.get().is_none() {
|
if self.private_candidate.get().is_none() {
|
||||||
if let Some(Ok(pick)) = self.consider_candidates(
|
if let Some(Ok(pick)) = self.consider_candidates(
|
||||||
self_ty,
|
self_ty,
|
||||||
|
instantiate_self_ty_obligations,
|
||||||
&self.private_candidates,
|
&self.private_candidates,
|
||||||
&mut PickDiagHints {
|
&mut PickDiagHints {
|
||||||
unstable_candidates: None,
|
unstable_candidates: None,
|
||||||
@@ -1610,6 +1676,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
fn consider_candidates(
|
fn consider_candidates(
|
||||||
&self,
|
&self,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
|
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||||
candidates: &[Candidate<'tcx>],
|
candidates: &[Candidate<'tcx>],
|
||||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||||
pick_constraints: Option<&PickConstraintsForShadowed>,
|
pick_constraints: Option<&PickConstraintsForShadowed>,
|
||||||
@@ -1626,6 +1693,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
probe,
|
probe,
|
||||||
self.consider_probe(
|
self.consider_probe(
|
||||||
self_ty,
|
self_ty,
|
||||||
|
instantiate_self_ty_obligations,
|
||||||
probe,
|
probe,
|
||||||
&mut pick_diag_hints.unsatisfied_predicates,
|
&mut pick_diag_hints.unsatisfied_predicates,
|
||||||
),
|
),
|
||||||
@@ -1810,10 +1878,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "trace", skip(self, possibly_unsatisfied_predicates), ret)]
|
#[instrument(level = "debug", skip(self, possibly_unsatisfied_predicates), ret)]
|
||||||
fn consider_probe(
|
fn consider_probe(
|
||||||
&self,
|
&self,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
|
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||||
probe: &Candidate<'tcx>,
|
probe: &Candidate<'tcx>,
|
||||||
possibly_unsatisfied_predicates: &mut Vec<(
|
possibly_unsatisfied_predicates: &mut Vec<(
|
||||||
ty::Predicate<'tcx>,
|
ty::Predicate<'tcx>,
|
||||||
@@ -1821,8 +1890,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
Option<ObligationCause<'tcx>>,
|
Option<ObligationCause<'tcx>>,
|
||||||
)>,
|
)>,
|
||||||
) -> ProbeResult {
|
) -> ProbeResult {
|
||||||
debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
|
|
||||||
|
|
||||||
self.probe(|snapshot| {
|
self.probe(|snapshot| {
|
||||||
let outer_universe = self.universe();
|
let outer_universe = self.universe();
|
||||||
|
|
||||||
@@ -1830,6 +1897,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
let cause = &self.misc(self.span);
|
let cause = &self.misc(self.span);
|
||||||
let ocx = ObligationCtxt::new_with_diagnostics(self);
|
let ocx = ObligationCtxt::new_with_diagnostics(self);
|
||||||
|
|
||||||
|
// Subtle: we're not *really* instantiating the current self type while
|
||||||
|
// probing, but instead fully recompute the autoderef steps once we've got
|
||||||
|
// a final `Pick`. We can't nicely handle these obligations outside of a probe.
|
||||||
|
//
|
||||||
|
// We simply handle them for each candidate here for now. That's kinda scuffed
|
||||||
|
// and ideally we just put them into the `FnCtxt` right away. We need to consider
|
||||||
|
// them to deal with defining uses in `method_autoderef_steps`.
|
||||||
|
if self.next_trait_solver() {
|
||||||
|
ocx.register_obligations(instantiate_self_ty_obligations.iter().cloned());
|
||||||
|
let errors = ocx.select_where_possible();
|
||||||
|
if !errors.is_empty() {
|
||||||
|
unreachable!("unexpected autoderef error {errors:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut trait_predicate = None;
|
let mut trait_predicate = None;
|
||||||
let (mut xform_self_ty, mut xform_ret_ty);
|
let (mut xform_self_ty, mut xform_ret_ty);
|
||||||
|
|
||||||
@@ -2072,6 +2154,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.infcx.next_trait_solver() {
|
||||||
|
if self.should_reject_candidate_due_to_opaque_treated_as_rigid(trait_predicate) {
|
||||||
|
result = ProbeResult::NoMatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Previously, method probe used `evaluate_predicate` to determine if a predicate
|
// Previously, method probe used `evaluate_predicate` to determine if a predicate
|
||||||
// was impossible to satisfy. This did a leak check, so we must also do a leak
|
// was impossible to satisfy. This did a leak check, so we must also do a leak
|
||||||
// check here to prevent backwards-incompatible ambiguity being introduced. See
|
// check here to prevent backwards-incompatible ambiguity being introduced. See
|
||||||
@@ -2085,6 +2173,71 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait candidates for not-yet-defined opaque types are a somewhat hacky.
|
||||||
|
///
|
||||||
|
/// We want to only accept trait methods if they were hold even if the
|
||||||
|
/// opaque types were rigid. To handle this, we both check that for trait
|
||||||
|
/// candidates the goal were to hold even when treating opaques as rigid,
|
||||||
|
/// see [OpaqueTypesJank](rustc_trait_selection::solve::OpaqueTypesJank).
|
||||||
|
///
|
||||||
|
/// We also check that all opaque types encountered as self types in the
|
||||||
|
/// autoderef chain don't get constrained when applying the candidate.
|
||||||
|
/// Importantly, this also handles calling methods taking `&self` on
|
||||||
|
/// `impl Trait` to reject the "by-self" candidate.
|
||||||
|
///
|
||||||
|
/// This needs to happen at the end of `consider_probe` as we need to take
|
||||||
|
/// all the constraints from that into account.
|
||||||
|
#[instrument(level = "debug", skip(self), ret)]
|
||||||
|
fn should_reject_candidate_due_to_opaque_treated_as_rigid(
|
||||||
|
&self,
|
||||||
|
trait_predicate: Option<ty::Predicate<'tcx>>,
|
||||||
|
) -> bool {
|
||||||
|
// Check whether the trait candidate would not be applicable if the
|
||||||
|
// opaque type were rigid.
|
||||||
|
if let Some(predicate) = trait_predicate {
|
||||||
|
let goal = Goal { param_env: self.param_env, predicate };
|
||||||
|
if !self.infcx.goal_may_hold_opaque_types_jank(goal) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether any opaque types in the autoderef chain have been
|
||||||
|
// constrained.
|
||||||
|
for step in self.steps {
|
||||||
|
if step.self_ty_is_opaque {
|
||||||
|
debug!(?step.autoderefs, ?step.self_ty, "self_type_is_opaque");
|
||||||
|
let constrained_opaque = self.probe(|_| {
|
||||||
|
// If we fail to instantiate the self type of this
|
||||||
|
// step, this part of the deref-chain is no longer
|
||||||
|
// reachable. In this case we don't care about opaque
|
||||||
|
// types there.
|
||||||
|
let Ok(ok) = self.fcx.probe_instantiate_query_response(
|
||||||
|
self.span,
|
||||||
|
self.orig_steps_var_values,
|
||||||
|
&step.self_ty,
|
||||||
|
) else {
|
||||||
|
debug!("failed to instantiate self_ty");
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let ocx = ObligationCtxt::new(self);
|
||||||
|
let self_ty = ocx.register_infer_ok_obligations(ok);
|
||||||
|
if !ocx.select_where_possible().is_empty() {
|
||||||
|
debug!("failed to prove instantiate self_ty obligations");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
!self.resolve_vars_if_possible(self_ty).is_ty_var()
|
||||||
|
});
|
||||||
|
if constrained_opaque {
|
||||||
|
debug!("opaque type has been constrained");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Sometimes we get in a situation where we have multiple probes that are all impls of the
|
/// Sometimes we get in a situation where we have multiple probes that are all impls of the
|
||||||
/// same trait, but we don't know which impl to use. In this case, since in all cases the
|
/// same trait, but we don't know which impl to use. In this case, since in all cases the
|
||||||
/// external interface of the method can be determined from the trait, it's ok not to decide.
|
/// external interface of the method can be determined from the trait, it's ok not to decide.
|
||||||
|
|||||||
@@ -85,11 +85,32 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
where
|
where
|
||||||
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
|
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
|
||||||
{
|
{
|
||||||
|
// While we ignore region constraints and pending obligations,
|
||||||
|
// we do return constrained opaque types to avoid unconstrained
|
||||||
|
// inference variables in the response. This is still slightly
|
||||||
|
// insufficient as ambiguous `Projection` obligations have the
|
||||||
|
// same issue.
|
||||||
|
//
|
||||||
|
// FIXME(-Znext-solver): We could alternatively extend the `var_values`
|
||||||
|
// each time we call `make_query_response_ignoring_pending_obligations`
|
||||||
|
// and equate inference variables created inside of the query this way.
|
||||||
|
// This is what we do for `CanonicalState` and is probably a bit nicer.
|
||||||
|
let opaque_types = if self.next_trait_solver() {
|
||||||
|
self.inner
|
||||||
|
.borrow_mut()
|
||||||
|
.opaque_type_storage
|
||||||
|
.iter_opaque_types()
|
||||||
|
.map(|(k, v)| (k, v.ty))
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
self.canonicalize_response(QueryResponse {
|
self.canonicalize_response(QueryResponse {
|
||||||
var_values: inference_vars,
|
var_values: inference_vars,
|
||||||
region_constraints: QueryRegionConstraints::default(),
|
region_constraints: QueryRegionConstraints::default(),
|
||||||
certainty: Certainty::Proven, // Ambiguities are OK!
|
certainty: Certainty::Proven, // Ambiguities are OK!
|
||||||
opaque_types: vec![],
|
opaque_types,
|
||||||
value: answer,
|
value: answer,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ impl<'tcx> FromIterator<DropckConstraint<'tcx>> for DropckConstraint<'tcx> {
|
|||||||
#[derive(Debug, HashStable)]
|
#[derive(Debug, HashStable)]
|
||||||
pub struct CandidateStep<'tcx> {
|
pub struct CandidateStep<'tcx> {
|
||||||
pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
|
pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
|
||||||
|
pub self_ty_is_opaque: bool,
|
||||||
pub autoderefs: usize,
|
pub autoderefs: usize,
|
||||||
/// `true` if the type results from a dereference of a raw pointer.
|
/// `true` if the type results from a dereference of a raw pointer.
|
||||||
/// when assembling candidates, we include these steps, but not when
|
/// when assembling candidates, we include these steps, but not when
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ where
|
|||||||
D: SolverDelegate<Interner = I>,
|
D: SolverDelegate<Interner = I>,
|
||||||
I: Interner,
|
I: Interner,
|
||||||
{
|
{
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self), ret)]
|
||||||
fn evaluate_root_goal(
|
fn evaluate_root_goal(
|
||||||
&self,
|
&self,
|
||||||
goal: Goal<I, I::Predicate>,
|
goal: Goal<I, I::Predicate>,
|
||||||
@@ -206,6 +206,7 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self), ret)]
|
||||||
fn root_goal_may_hold_opaque_types_jank(
|
fn root_goal_may_hold_opaque_types_jank(
|
||||||
&self,
|
&self,
|
||||||
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
|
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
|
||||||
|
|||||||
@@ -381,6 +381,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The result of evaluating a goal.
|
/// The result of evaluating a goal.
|
||||||
|
#[derive_where(Debug; I: Interner)]
|
||||||
pub struct GoalEvaluation<I: Interner> {
|
pub struct GoalEvaluation<I: Interner> {
|
||||||
/// The goal we've evaluated. This is the input goal, but potentially with its
|
/// The goal we've evaluated. This is the input goal, but potentially with its
|
||||||
/// inference variables resolved. This never applies any inference constraints
|
/// inference variables resolved. This never applies any inference constraints
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use rustc_infer::traits::solve::Goal;
|
use rustc_infer::traits::solve::Goal;
|
||||||
use rustc_macros::extension;
|
use rustc_macros::extension;
|
||||||
use rustc_middle::span_bug;
|
use rustc_middle::{span_bug, ty};
|
||||||
use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
|
use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
|
||||||
|
|
||||||
use crate::infer::InferCtxt;
|
use crate::infer::InferCtxt;
|
||||||
@@ -22,7 +22,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
/// for more details.
|
/// for more details.
|
||||||
fn predicate_may_hold_opaque_types_jank(&self, obligation: &PredicateObligation<'tcx>) -> bool {
|
fn predicate_may_hold_opaque_types_jank(&self, obligation: &PredicateObligation<'tcx>) -> bool {
|
||||||
if self.next_trait_solver() {
|
if self.next_trait_solver() {
|
||||||
<&SolverDelegate<'tcx>>::from(self).root_goal_may_hold_opaque_types_jank(Goal::new(
|
self.goal_may_hold_opaque_types_jank(Goal::new(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
obligation.param_env,
|
obligation.param_env,
|
||||||
obligation.predicate,
|
obligation.predicate,
|
||||||
@@ -32,6 +32,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See the comment on [OpaqueTypesJank](crate::solve::OpaqueTypesJank)
|
||||||
|
/// for more details.
|
||||||
|
fn goal_may_hold_opaque_types_jank(&self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> bool {
|
||||||
|
assert!(self.next_trait_solver());
|
||||||
|
<&SolverDelegate<'tcx>>::from(self).root_goal_may_hold_opaque_types_jank(goal)
|
||||||
|
}
|
||||||
|
|
||||||
/// Evaluates whether the predicate can be satisfied in the given
|
/// Evaluates whether the predicate can be satisfied in the given
|
||||||
/// `ParamEnv`, and returns `false` if not certain. However, this is
|
/// `ParamEnv`, and returns `false` if not certain. However, this is
|
||||||
/// not entirely accurate if inference variables are involved.
|
/// not entirely accurate if inference variables are involved.
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
error[E0282]: type annotations needed
|
|
||||||
--> $DIR/call_method_ambiguous.rs:26:13
|
|
||||||
|
|
|
||||||
LL | let mut iter = foo(n - 1, m);
|
|
||||||
| ^^^^^^^^
|
|
||||||
LL |
|
|
||||||
LL | assert_eq!(iter.get(), 1);
|
|
||||||
| --- type must be known at this point
|
|
||||||
|
|
|
||||||
help: consider giving `iter` an explicit type
|
|
||||||
|
|
|
||||||
LL | let mut iter: /* Type */ = foo(n - 1, m);
|
|
||||||
| ++++++++++++
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0282`.
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
//@ revisions: current next
|
//@ revisions: current next
|
||||||
//@[next] compile-flags: -Znext-solver
|
//@[next] compile-flags: -Znext-solver
|
||||||
//@[current] run-pass
|
//@ run-pass
|
||||||
|
|
||||||
trait Get {
|
trait Get {
|
||||||
fn get(&mut self) -> u32;
|
fn get(&mut self) -> u32;
|
||||||
@@ -24,7 +24,6 @@ where
|
|||||||
fn foo(n: usize, m: &mut ()) -> impl Get + use<'_> {
|
fn foo(n: usize, m: &mut ()) -> impl Get + use<'_> {
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
let mut iter = foo(n - 1, m);
|
let mut iter = foo(n - 1, m);
|
||||||
//[next]~^ ERROR type annotations needed
|
|
||||||
assert_eq!(iter.get(), 1);
|
assert_eq!(iter.get(), 1);
|
||||||
}
|
}
|
||||||
m
|
m
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
error[E0282]: type annotations needed
|
|
||||||
--> $DIR/call_method_on_inherent_impl.rs:18:13
|
|
||||||
|
|
|
||||||
LL | let x = my_foo();
|
|
||||||
| ^
|
|
||||||
LL |
|
|
||||||
LL | x.my_debug();
|
|
||||||
| -------- type must be known at this point
|
|
||||||
|
|
|
||||||
help: consider giving `x` an explicit type
|
|
||||||
|
|
|
||||||
LL | let x: /* Type */ = my_foo();
|
|
||||||
| ++++++++++++
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0282`.
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
//@ revisions: current next
|
//@ revisions: current next
|
||||||
//@[next] compile-flags: -Znext-solver
|
//@[next] compile-flags: -Znext-solver
|
||||||
//@[current] check-pass
|
//@ check-pass
|
||||||
|
|
||||||
trait MyDebug {
|
trait MyDebug {
|
||||||
fn my_debug(&self);
|
fn my_debug(&self);
|
||||||
@@ -16,7 +16,6 @@ where
|
|||||||
fn my_foo() -> impl std::fmt::Debug {
|
fn my_foo() -> impl std::fmt::Debug {
|
||||||
if false {
|
if false {
|
||||||
let x = my_foo();
|
let x = my_foo();
|
||||||
//[next]~^ ERROR type annotations needed
|
|
||||||
x.my_debug();
|
x.my_debug();
|
||||||
}
|
}
|
||||||
()
|
()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
error[E0599]: no method named `my_debug` found for reference `&impl Debug` in the current scope
|
error[E0599]: no method named `my_debug` found for reference `&impl Debug` in the current scope
|
||||||
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:16:11
|
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:15:11
|
||||||
|
|
|
|
||||||
LL | x.my_debug();
|
LL | x.my_debug();
|
||||||
| ^^^^^^^^ method not found in `&impl Debug`
|
| ^^^^^^^^ method not found in `&impl Debug`
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
error[E0282]: type annotations needed for `&_`
|
error[E0599]: no method named `my_debug` found for reference `&_` in the current scope
|
||||||
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:14:13
|
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:15:11
|
||||||
|
|
|
|
||||||
LL | let x = &my_foo();
|
|
||||||
| ^
|
|
||||||
LL |
|
|
||||||
LL | x.my_debug();
|
LL | x.my_debug();
|
||||||
| -------- type must be known at this point
|
| ^^^^^^^^ method not found in `&_`
|
||||||
|
|
|
|
||||||
help: consider giving `x` an explicit type, where the placeholders `_` are specified
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
|
help: trait `MyDebug` which provides `my_debug` is implemented but not in scope; perhaps you want to import it
|
||||||
|
|
|
||||||
|
LL + use MyDebug;
|
||||||
|
|
|
|
||||||
LL | let x: &_ = &my_foo();
|
|
||||||
| ++++
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0282`.
|
For more information about this error, try `rustc --explain E0599`.
|
||||||
|
|||||||
@@ -12,9 +12,8 @@ impl MyDebug for &() {
|
|||||||
fn my_foo() -> impl std::fmt::Debug {
|
fn my_foo() -> impl std::fmt::Debug {
|
||||||
if false {
|
if false {
|
||||||
let x = &my_foo();
|
let x = &my_foo();
|
||||||
//[next]~^ ERROR: type annotations needed
|
|
||||||
x.my_debug();
|
x.my_debug();
|
||||||
//[current]~^ ERROR: no method named `my_debug`
|
//~^ ERROR: no method named `my_debug`
|
||||||
}
|
}
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
error[E0599]: no method named `my_debug` found for opaque type `impl Debug` in the current scope
|
error[E0599]: no method named `my_debug` found for opaque type `impl Debug` in the current scope
|
||||||
--> $DIR/call_method_on_inherent_impl_ref.rs:19:11
|
--> $DIR/call_method_on_inherent_impl_ref-err.rs:18:11
|
||||||
|
|
|
|
||||||
LL | fn my_debug(&self);
|
LL | fn my_debug(&self);
|
||||||
| -------- the method is available for `&impl Debug` here
|
| -------- the method is available for `&impl Debug` here
|
||||||
@@ -9,7 +9,7 @@ LL | x.my_debug();
|
|||||||
|
|
|
|
||||||
= help: items from traits can only be used if the trait is implemented and in scope
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it
|
note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it
|
||||||
--> $DIR/call_method_on_inherent_impl_ref.rs:4:1
|
--> $DIR/call_method_on_inherent_impl_ref-err.rs:4:1
|
||||||
|
|
|
|
||||||
LL | trait MyDebug {
|
LL | trait MyDebug {
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
error[E0599]: no method named `my_debug` found for type `_` in the current scope
|
||||||
|
--> $DIR/call_method_on_inherent_impl_ref-err.rs:18:11
|
||||||
|
|
|
||||||
|
LL | fn my_debug(&self);
|
||||||
|
| -------- the method is available for `&_` here
|
||||||
|
...
|
||||||
|
LL | x.my_debug();
|
||||||
|
| ^^^^^^^^ method not found in `_`
|
||||||
|
|
|
||||||
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
|
note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it
|
||||||
|
--> $DIR/call_method_on_inherent_impl_ref-err.rs:4:1
|
||||||
|
|
|
||||||
|
LL | trait MyDebug {
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0599`.
|
||||||
24
tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.rs
Normal file
24
tests/ui/impl-trait/call_method_on_inherent_impl_ref-err.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
//@ revisions: current next
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
trait MyDebug {
|
||||||
|
fn my_debug(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> MyDebug for &T
|
||||||
|
where
|
||||||
|
T: std::fmt::Debug,
|
||||||
|
{
|
||||||
|
fn my_debug(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn my_foo() -> impl std::fmt::Debug {
|
||||||
|
if false {
|
||||||
|
let x = my_foo();
|
||||||
|
x.my_debug();
|
||||||
|
//~^ ERROR no method named `my_debug` found
|
||||||
|
}
|
||||||
|
()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
//@ revisions: current next
|
//@ revisions: current next
|
||||||
//@[next] compile-flags: -Znext-solver
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
trait MyDebug {
|
trait MyDebug {
|
||||||
fn my_debug(&self);
|
fn my_debug(&self);
|
||||||
@@ -12,20 +13,9 @@ where
|
|||||||
fn my_debug(&self) {}
|
fn my_debug(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn my_foo() -> impl std::fmt::Debug {
|
|
||||||
if false {
|
|
||||||
let x = my_foo();
|
|
||||||
//[next]~^ ERROR type annotations needed
|
|
||||||
x.my_debug();
|
|
||||||
//[current]~^ ERROR no method named `my_debug` found
|
|
||||||
}
|
|
||||||
()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn my_bar() -> impl std::fmt::Debug {
|
fn my_bar() -> impl std::fmt::Debug {
|
||||||
if false {
|
if false {
|
||||||
let x = &my_bar();
|
let x = &my_bar();
|
||||||
//[next]~^ ERROR type annotations needed
|
|
||||||
x.my_debug();
|
x.my_debug();
|
||||||
}
|
}
|
||||||
()
|
()
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
error[E0282]: type annotations needed
|
|
||||||
--> $DIR/call_method_on_inherent_impl_ref.rs:17:13
|
|
||||||
|
|
|
||||||
LL | let x = my_foo();
|
|
||||||
| ^
|
|
||||||
LL |
|
|
||||||
LL | x.my_debug();
|
|
||||||
| -------- type must be known at this point
|
|
||||||
|
|
|
||||||
help: consider giving `x` an explicit type
|
|
||||||
|
|
|
||||||
LL | let x: /* Type */ = my_foo();
|
|
||||||
| ++++++++++++
|
|
||||||
|
|
||||||
error[E0282]: type annotations needed for `&_`
|
|
||||||
--> $DIR/call_method_on_inherent_impl_ref.rs:27:13
|
|
||||||
|
|
|
||||||
LL | let x = &my_bar();
|
|
||||||
| ^
|
|
||||||
LL |
|
|
||||||
LL | x.my_debug();
|
|
||||||
| -------- type must be known at this point
|
|
||||||
|
|
|
||||||
help: consider giving `x` an explicit type, where the placeholders `_` are specified
|
|
||||||
|
|
|
||||||
LL | let x: &_ = &my_bar();
|
|
||||||
| ++++
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0282`.
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
error[E0282]: type annotations needed
|
|
||||||
--> $DIR/method-resolution4.rs:13:20
|
|
||||||
|
|
|
||||||
LL | foo(false).next().unwrap();
|
|
||||||
| ^^^^ cannot infer type
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0282`.
|
|
||||||
@@ -6,12 +6,11 @@
|
|||||||
|
|
||||||
//@ revisions: current next
|
//@ revisions: current next
|
||||||
//@[next] compile-flags: -Znext-solver
|
//@[next] compile-flags: -Znext-solver
|
||||||
//@[current] check-pass
|
//@ check-pass
|
||||||
|
|
||||||
fn foo(b: bool) -> impl Iterator<Item = ()> {
|
fn foo(b: bool) -> impl Iterator<Item = ()> {
|
||||||
if b {
|
if b {
|
||||||
foo(false).next().unwrap();
|
foo(false).next().unwrap();
|
||||||
//[next]~^ ERROR type annotations needed
|
|
||||||
}
|
}
|
||||||
std::iter::empty()
|
std::iter::empty()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/method-resolution5-deref-no-constrain.rs:20:5
|
||||||
|
|
|
||||||
|
LL | fn via_deref() -> impl Deref<Target = Foo> {
|
||||||
|
| --- expected `&Foo` because of return type
|
||||||
|
...
|
||||||
|
LL | Box::new(Foo)
|
||||||
|
| ^^^^^^^^^^^^^ expected `&Foo`, found `Box<Foo>`
|
||||||
|
|
|
||||||
|
= note: expected reference `&Foo`
|
||||||
|
found struct `Box<Foo>`
|
||||||
|
help: consider borrowing here
|
||||||
|
|
|
||||||
|
LL | &Box::new(Foo)
|
||||||
|
| +
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
23
tests/ui/impl-trait/method-resolution5-deref-no-constrain.rs
Normal file
23
tests/ui/impl-trait/method-resolution5-deref-no-constrain.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
//! The recursive method call yields the opaque type. We want
|
||||||
|
//! to use the impl candidate for `Foo` here without constraining
|
||||||
|
//! the opaque to `&Foo`.
|
||||||
|
|
||||||
|
//@ revisions: current next
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
//@[next] check-pass
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
|
struct Foo;
|
||||||
|
impl Foo {
|
||||||
|
fn method(&self) {}
|
||||||
|
}
|
||||||
|
fn via_deref() -> impl Deref<Target = Foo> {
|
||||||
|
// Currently errors on stable, but should not
|
||||||
|
if false {
|
||||||
|
via_deref().method();
|
||||||
|
}
|
||||||
|
|
||||||
|
Box::new(Foo)
|
||||||
|
//[current]~^ ERROR mismatched types
|
||||||
|
}
|
||||||
|
fn main() {}
|
||||||
30
tests/ui/impl-trait/method-resolution5-deref.rs
Normal file
30
tests/ui/impl-trait/method-resolution5-deref.rs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
//! The recursive method call yields the opaque type. We want
|
||||||
|
//! to use the trait candidate for `impl Foo` here while not
|
||||||
|
//! applying it for the `impl Deref`.
|
||||||
|
|
||||||
|
//@ revisions: current next
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
|
trait Foo {
|
||||||
|
fn method(&self) {}
|
||||||
|
}
|
||||||
|
impl Foo for u32 {}
|
||||||
|
fn via_deref() -> impl Deref<Target = impl Foo> {
|
||||||
|
if false {
|
||||||
|
via_deref().method();
|
||||||
|
}
|
||||||
|
|
||||||
|
Box::new(1u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn via_deref_nested() -> Box<impl Deref<Target = impl Foo>> {
|
||||||
|
if false {
|
||||||
|
via_deref_nested().method();
|
||||||
|
}
|
||||||
|
|
||||||
|
Box::new(Box::new(1u32))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
error[E0282]: type annotations needed
|
|
||||||
--> $DIR/recursive-bound-eval.rs:20:28
|
|
||||||
|
|
|
||||||
LL | move || recursive_fn().parse()
|
|
||||||
| ^^^^^ cannot infer type
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0282`.
|
|
||||||
@@ -3,8 +3,7 @@
|
|||||||
|
|
||||||
//@ revisions: next current
|
//@ revisions: next current
|
||||||
//@[next] compile-flags: -Znext-solver
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
//@ check-pass
|
||||||
//@[current] check-pass
|
|
||||||
|
|
||||||
pub trait Parser<E> {
|
pub trait Parser<E> {
|
||||||
fn parse(&self) -> E;
|
fn parse(&self) -> E;
|
||||||
@@ -18,7 +17,6 @@ impl<E, T: Fn() -> E> Parser<E> for T {
|
|||||||
|
|
||||||
pub fn recursive_fn<E>() -> impl Parser<E> {
|
pub fn recursive_fn<E>() -> impl Parser<E> {
|
||||||
move || recursive_fn().parse()
|
move || recursive_fn().parse()
|
||||||
//[next]~^ ERROR: type annotations needed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
error[E0282]: type annotations needed
|
|
||||||
--> $DIR/recursive-coroutine-boxed.rs:11:23
|
|
||||||
|
|
|
||||||
LL | let mut gen = Box::pin(foo());
|
|
||||||
| ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box`
|
|
||||||
LL |
|
|
||||||
LL | let mut r = gen.as_mut().resume(());
|
|
||||||
| ------ type must be known at this point
|
|
||||||
|
|
|
||||||
help: consider specifying the generic argument
|
|
||||||
|
|
|
||||||
LL | let mut gen = Box::<T>::pin(foo());
|
|
||||||
| +++++
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0282`.
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
//@ revisions: current next
|
//@ revisions: current next
|
||||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||||
//@[current] check-pass
|
|
||||||
//@[next] compile-flags: -Znext-solver
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
//@ check-pass
|
||||||
#![feature(coroutines, coroutine_trait)]
|
#![feature(coroutines, coroutine_trait)]
|
||||||
|
|
||||||
use std::ops::{Coroutine, CoroutineState};
|
use std::ops::{Coroutine, CoroutineState};
|
||||||
@@ -9,7 +9,6 @@ use std::ops::{Coroutine, CoroutineState};
|
|||||||
fn foo() -> impl Coroutine<Yield = (), Return = ()> {
|
fn foo() -> impl Coroutine<Yield = (), Return = ()> {
|
||||||
#[coroutine] || {
|
#[coroutine] || {
|
||||||
let mut gen = Box::pin(foo());
|
let mut gen = Box::pin(foo());
|
||||||
//[next]~^ ERROR type annotations needed
|
|
||||||
let mut r = gen.as_mut().resume(());
|
let mut r = gen.as_mut().resume(());
|
||||||
while let CoroutineState::Yielded(v) = r {
|
while let CoroutineState::Yielded(v) = r {
|
||||||
yield v;
|
yield v;
|
||||||
|
|||||||
@@ -2,7 +2,13 @@ error[E0282]: type annotations needed
|
|||||||
--> $DIR/method_resolution_trait_method_from_opaque.rs:28:18
|
--> $DIR/method_resolution_trait_method_from_opaque.rs:28:18
|
||||||
|
|
|
|
||||||
LL | self.bar.next().unwrap();
|
LL | self.bar.next().unwrap();
|
||||||
| ^^^^ cannot infer type
|
| ^^^^
|
||||||
|
|
|
||||||
|
help: try using a fully qualified path to specify the expected types
|
||||||
|
|
|
||||||
|
LL - self.bar.next().unwrap();
|
||||||
|
LL + <_ as Iterator>::next(&mut self.bar).unwrap();
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user