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_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
|
||||
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::ty::elaborate::supertrait_def_ids;
|
||||
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_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
|
||||
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::evaluate_obligation::InferCtxtExt;
|
||||
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 {
|
||||
self_ty: self
|
||||
.make_query_response_ignoring_pending_obligations(var_values, self_ty),
|
||||
self_ty_is_opaque: false,
|
||||
autoderefs: 0,
|
||||
from_unsafe_deref: 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
|
||||
// `Deref<Target=T>`. If arbitrary self types is enabled, we instead
|
||||
// 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 {
|
||||
self_ty: infcx
|
||||
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
|
||||
self_ty_is_opaque: self_ty_is_opaque(ty),
|
||||
autoderefs: d,
|
||||
from_unsafe_deref: reached_raw_pointer,
|
||||
unsize: false,
|
||||
@@ -643,6 +657,7 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
||||
let step = CandidateStep {
|
||||
self_ty: infcx
|
||||
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
|
||||
self_ty_is_opaque: self_ty_is_opaque(ty),
|
||||
autoderefs: d,
|
||||
from_unsafe_deref: reached_raw_pointer,
|
||||
unsize: false,
|
||||
@@ -659,7 +674,11 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
||||
};
|
||||
let final_ty = autoderef_via_deref.final_ty();
|
||||
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,
|
||||
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,
|
||||
Ty::new_slice(infcx.tcx, *elem_ty),
|
||||
),
|
||||
self_ty_is_opaque: false,
|
||||
autoderefs,
|
||||
// this could be from an unsafe deref if we had
|
||||
// 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
|
||||
})
|
||||
.find_map(|step| {
|
||||
let InferOk { value: self_ty, obligations: _ } = self
|
||||
let InferOk { value: self_ty, obligations: instantiate_self_ty_obligations } = self
|
||||
.fcx
|
||||
.probe_instantiate_query_response(
|
||||
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)
|
||||
});
|
||||
|
||||
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)
|
||||
if let Some(by_value_pick) = by_value_pick {
|
||||
@@ -1256,6 +1281,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
by_value_pick,
|
||||
step,
|
||||
self_ty,
|
||||
&instantiate_self_ty_obligations,
|
||||
mutbl,
|
||||
track_unstable_candidates,
|
||||
) {
|
||||
@@ -1270,6 +1296,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
let autoref_pick = self.pick_autorefd_method(
|
||||
step,
|
||||
self_ty,
|
||||
&instantiate_self_ty_obligations,
|
||||
hir::Mutability::Not,
|
||||
pick_diag_hints,
|
||||
None,
|
||||
@@ -1283,6 +1310,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
autoref_pick,
|
||||
step,
|
||||
self_ty,
|
||||
&instantiate_self_ty_obligations,
|
||||
hir::Mutability::Mut,
|
||||
track_unstable_candidates,
|
||||
) {
|
||||
@@ -1319,12 +1347,27 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
self.pick_autorefd_method(
|
||||
step,
|
||||
self_ty,
|
||||
&instantiate_self_ty_obligations,
|
||||
hir::Mutability::Mut,
|
||||
pick_diag_hints,
|
||||
None,
|
||||
)
|
||||
.or_else(|| self.pick_const_ptr_method(step, self_ty, pick_diag_hints))
|
||||
.or_else(|| self.pick_reborrow_pin_method(step, self_ty, pick_diag_hints))
|
||||
.or_else(|| {
|
||||
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>,
|
||||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
mutbl: hir::Mutability,
|
||||
track_unstable_candidates: bool,
|
||||
) -> Result<(), MethodError<'tcx>> {
|
||||
@@ -1412,6 +1456,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
let potentially_shadowed_pick = self.pick_autorefd_method(
|
||||
step,
|
||||
self_ty,
|
||||
instantiate_self_ty_obligations,
|
||||
mutbl,
|
||||
&mut pick_diag_hints,
|
||||
Some(&pick_constraints),
|
||||
@@ -1438,13 +1483,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
&self,
|
||||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
if step.unsize {
|
||||
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| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
|
||||
@@ -1481,6 +1527,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
&self,
|
||||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
mutbl: hir::Mutability,
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
pick_constraints: Option<&PickConstraintsForShadowed>,
|
||||
@@ -1497,7 +1544,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
let region = tcx.lifetimes.re_erased;
|
||||
|
||||
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| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref_or_ptr_adjustment =
|
||||
@@ -1513,6 +1566,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
&self,
|
||||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
if !self.tcx.features().pin_ergonomics() {
|
||||
@@ -1534,14 +1588,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
|
||||
let region = self.tcx.lifetimes.re_erased;
|
||||
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| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref_or_ptr_adjustment =
|
||||
Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not));
|
||||
pick
|
||||
})
|
||||
})
|
||||
self.pick_method(autopin_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map(
|
||||
|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref_or_ptr_adjustment =
|
||||
Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not));
|
||||
pick
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// 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,
|
||||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
// 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);
|
||||
self.pick_method(const_ptr_ty, pick_diag_hints, None).map(|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
|
||||
pick
|
||||
})
|
||||
})
|
||||
self.pick_method(const_ptr_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map(
|
||||
|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
|
||||
pick
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn pick_method(
|
||||
&self,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
pick_constraints: Option<&PickConstraintsForShadowed>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
@@ -1584,8 +1644,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
|
||||
{
|
||||
debug!("searching {} candidates", kind);
|
||||
let res =
|
||||
self.consider_candidates(self_ty, candidates, pick_diag_hints, pick_constraints);
|
||||
let res = self.consider_candidates(
|
||||
self_ty,
|
||||
instantiate_self_ty_obligations,
|
||||
candidates,
|
||||
pick_diag_hints,
|
||||
pick_constraints,
|
||||
);
|
||||
if let Some(pick) = res {
|
||||
return Some(pick);
|
||||
}
|
||||
@@ -1594,6 +1659,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
if self.private_candidate.get().is_none() {
|
||||
if let Some(Ok(pick)) = self.consider_candidates(
|
||||
self_ty,
|
||||
instantiate_self_ty_obligations,
|
||||
&self.private_candidates,
|
||||
&mut PickDiagHints {
|
||||
unstable_candidates: None,
|
||||
@@ -1610,6 +1676,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
fn consider_candidates(
|
||||
&self,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
candidates: &[Candidate<'tcx>],
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
pick_constraints: Option<&PickConstraintsForShadowed>,
|
||||
@@ -1626,6 +1693,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
probe,
|
||||
self.consider_probe(
|
||||
self_ty,
|
||||
instantiate_self_ty_obligations,
|
||||
probe,
|
||||
&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(
|
||||
&self,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
probe: &Candidate<'tcx>,
|
||||
possibly_unsatisfied_predicates: &mut Vec<(
|
||||
ty::Predicate<'tcx>,
|
||||
@@ -1821,8 +1890,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
Option<ObligationCause<'tcx>>,
|
||||
)>,
|
||||
) -> ProbeResult {
|
||||
debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
|
||||
|
||||
self.probe(|snapshot| {
|
||||
let outer_universe = self.universe();
|
||||
|
||||
@@ -1830,6 +1897,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
let cause = &self.misc(self.span);
|
||||
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 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
|
||||
// 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
|
||||
@@ -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
|
||||
/// 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.
|
||||
|
||||
@@ -85,11 +85,32 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
where
|
||||
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 {
|
||||
var_values: inference_vars,
|
||||
region_constraints: QueryRegionConstraints::default(),
|
||||
certainty: Certainty::Proven, // Ambiguities are OK!
|
||||
opaque_types: vec![],
|
||||
opaque_types,
|
||||
value: answer,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -154,6 +154,7 @@ impl<'tcx> FromIterator<DropckConstraint<'tcx>> for DropckConstraint<'tcx> {
|
||||
#[derive(Debug, HashStable)]
|
||||
pub struct CandidateStep<'tcx> {
|
||||
pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
|
||||
pub self_ty_is_opaque: bool,
|
||||
pub autoderefs: usize,
|
||||
/// `true` if the type results from a dereference of a raw pointer.
|
||||
/// when assembling candidates, we include these steps, but not when
|
||||
|
||||
@@ -194,7 +194,7 @@ where
|
||||
D: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn evaluate_root_goal(
|
||||
&self,
|
||||
goal: Goal<I, I::Predicate>,
|
||||
@@ -206,6 +206,7 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn root_goal_may_hold_opaque_types_jank(
|
||||
&self,
|
||||
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
|
||||
|
||||
@@ -381,6 +381,7 @@ where
|
||||
}
|
||||
|
||||
/// The result of evaluating a goal.
|
||||
#[derive_where(Debug; I: Interner)]
|
||||
pub struct GoalEvaluation<I: Interner> {
|
||||
/// The goal we've evaluated. This is the input goal, but potentially with its
|
||||
/// inference variables resolved. This never applies any inference constraints
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use rustc_infer::traits::solve::Goal;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::{span_bug, ty};
|
||||
use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
|
||||
|
||||
use crate::infer::InferCtxt;
|
||||
@@ -22,7 +22,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
/// for more details.
|
||||
fn predicate_may_hold_opaque_types_jank(&self, obligation: &PredicateObligation<'tcx>) -> bool {
|
||||
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,
|
||||
obligation.param_env,
|
||||
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
|
||||
/// `ParamEnv`, and returns `false` if not certain. However, this is
|
||||
/// 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
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@[current] run-pass
|
||||
//@ run-pass
|
||||
|
||||
trait Get {
|
||||
fn get(&mut self) -> u32;
|
||||
@@ -24,7 +24,6 @@ where
|
||||
fn foo(n: usize, m: &mut ()) -> impl Get + use<'_> {
|
||||
if n > 0 {
|
||||
let mut iter = foo(n - 1, m);
|
||||
//[next]~^ ERROR type annotations needed
|
||||
assert_eq!(iter.get(), 1);
|
||||
}
|
||||
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
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@[current] check-pass
|
||||
//@ check-pass
|
||||
|
||||
trait MyDebug {
|
||||
fn my_debug(&self);
|
||||
@@ -16,7 +16,6 @@ where
|
||||
fn my_foo() -> impl std::fmt::Debug {
|
||||
if false {
|
||||
let x = my_foo();
|
||||
//[next]~^ ERROR type annotations needed
|
||||
x.my_debug();
|
||||
}
|
||||
()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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();
|
||||
| ^^^^^^^^ method not found in `&impl Debug`
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
error[E0282]: type annotations needed for `&_`
|
||||
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:14:13
|
||||
error[E0599]: no method named `my_debug` found for reference `&_` in the current scope
|
||||
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:15:11
|
||||
|
|
||||
LL | let x = &my_foo();
|
||||
| ^
|
||||
LL |
|
||||
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
|
||||
|
||||
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 {
|
||||
if false {
|
||||
let x = &my_foo();
|
||||
//[next]~^ ERROR: type annotations needed
|
||||
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
|
||||
--> $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);
|
||||
| -------- 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
|
||||
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 {
|
||||
| ^^^^^^^^^^^^^
|
||||
@@ -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
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@ check-pass
|
||||
|
||||
trait MyDebug {
|
||||
fn my_debug(&self);
|
||||
@@ -12,20 +13,9 @@ where
|
||||
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 {
|
||||
if false {
|
||||
let x = &my_bar();
|
||||
//[next]~^ ERROR type annotations needed
|
||||
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
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@[current] check-pass
|
||||
//@ check-pass
|
||||
|
||||
fn foo(b: bool) -> impl Iterator<Item = ()> {
|
||||
if b {
|
||||
foo(false).next().unwrap();
|
||||
//[next]~^ ERROR type annotations needed
|
||||
}
|
||||
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`.
|
||||
@@ -1,10 +1,9 @@
|
||||
//! Test that we can evaluate nested obligations when invoking methods on recursive calls on
|
||||
//! an RPIT.
|
||||
|
||||
//@revisions: next current
|
||||
//@ revisions: next current
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
|
||||
//@[current] check-pass
|
||||
//@ check-pass
|
||||
|
||||
pub trait Parser<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> {
|
||||
move || recursive_fn().parse()
|
||||
//[next]~^ ERROR: type annotations needed
|
||||
}
|
||||
|
||||
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
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@[current] check-pass
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@ check-pass
|
||||
#![feature(coroutines, coroutine_trait)]
|
||||
|
||||
use std::ops::{Coroutine, CoroutineState};
|
||||
@@ -9,7 +9,6 @@ use std::ops::{Coroutine, CoroutineState};
|
||||
fn foo() -> impl Coroutine<Yield = (), Return = ()> {
|
||||
#[coroutine] || {
|
||||
let mut gen = Box::pin(foo());
|
||||
//[next]~^ ERROR type annotations needed
|
||||
let mut r = gen.as_mut().resume(());
|
||||
while let CoroutineState::Yielded(v) = r {
|
||||
yield v;
|
||||
|
||||
@@ -2,7 +2,13 @@ error[E0282]: type annotations needed
|
||||
--> $DIR/method_resolution_trait_method_from_opaque.rs:28:18
|
||||
|
|
||||
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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user