Auto merge of #119849 - lcnr:eagerly-instantiate-binders, r=compiler-errors
more eagerly instantiate binders The old solver sometimes incorrectly used `sub`, change it to explicitly instantiate binders and use `eq` instead. While doing so I also moved the instantiation before the normalize calls. This caused some observable changes, will explain these inline. This PR therefore requires a crater run and an FCP. r? types
This commit is contained in:
commit
fd27e8745f
56 changed files with 531 additions and 415 deletions
|
@ -3409,6 +3409,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
self.dcx().try_steal_replace_and_emit_err(self.tcx.def_span(def_id), StashKey::Cycle, err)
|
||||
}
|
||||
|
||||
// FIXME(@lcnr): This function could be changed to trait `TraitRef` directly
|
||||
// instead of using a `Binder`.
|
||||
fn report_signature_mismatch_error(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
|
|
|
@ -165,7 +165,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
|
||||
let placeholder_trait_predicate =
|
||||
self.infcx.enter_forall_and_leak_universe(poly_trait_predicate);
|
||||
debug!(?placeholder_trait_predicate);
|
||||
|
||||
// The bounds returned by `item_bounds` may contain duplicates after
|
||||
// normalization, so try to deduplicate when possible to avoid
|
||||
|
@ -184,8 +183,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
selcx.infcx.probe(|_| {
|
||||
match selcx.match_normalize_trait_ref(
|
||||
obligation,
|
||||
bound.to_poly_trait_ref(),
|
||||
placeholder_trait_predicate.trait_ref,
|
||||
bound.to_poly_trait_ref(),
|
||||
) {
|
||||
Ok(None) => {
|
||||
candidates.vec.push(ProjectionCandidate(idx));
|
||||
|
@ -881,8 +880,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
self.infcx.probe(|_| {
|
||||
self.match_normalize_trait_ref(
|
||||
obligation,
|
||||
upcast_trait_ref,
|
||||
placeholder_trait_predicate.trait_ref,
|
||||
upcast_trait_ref,
|
||||
)
|
||||
.is_ok()
|
||||
})
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
use rustc_ast::Mutability;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
|
||||
use rustc_infer::infer::HigherRankedType;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
|
||||
use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
|
||||
use rustc_middle::ty::{
|
||||
|
@ -161,8 +161,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let placeholder_trait_predicate =
|
||||
self.infcx.enter_forall_and_leak_universe(trait_predicate).trait_ref;
|
||||
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
|
||||
let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
|
||||
|
||||
let candidate_predicate = self
|
||||
.for_each_item_bound(
|
||||
placeholder_self_ty,
|
||||
|
@ -182,6 +180,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
.expect("projection candidate is not a trait predicate")
|
||||
.map_bound(|t| t.trait_ref);
|
||||
|
||||
let candidate = self.infcx.instantiate_binder_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
HigherRankedType,
|
||||
candidate,
|
||||
);
|
||||
let mut obligations = Vec::new();
|
||||
let candidate = normalize_with_depth_to(
|
||||
self,
|
||||
|
@ -195,7 +198,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
obligations.extend(
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate)
|
||||
.eq(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate)
|
||||
.map(|InferOk { obligations, .. }| obligations)
|
||||
.map_err(|_| Unimplemented)?,
|
||||
);
|
||||
|
@ -499,7 +502,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
let trait_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
|
||||
let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty());
|
||||
let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref);
|
||||
let ty::Dynamic(data, ..) = *self_ty.kind() else {
|
||||
span_bug!(obligation.cause.span, "object candidate with non-object");
|
||||
};
|
||||
|
@ -520,19 +522,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let unnormalized_upcast_trait_ref =
|
||||
supertraits.nth(index).expect("supertraits iterator no longer has as many elements");
|
||||
|
||||
let upcast_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
HigherRankedType,
|
||||
unnormalized_upcast_trait_ref,
|
||||
);
|
||||
let upcast_trait_ref = normalize_with_depth_to(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
unnormalized_upcast_trait_ref,
|
||||
upcast_trait_ref,
|
||||
&mut nested,
|
||||
);
|
||||
|
||||
nested.extend(
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(DefineOpaqueTypes::No, obligation_trait_ref, upcast_trait_ref)
|
||||
.eq(DefineOpaqueTypes::No, trait_predicate.trait_ref, upcast_trait_ref)
|
||||
.map(|InferOk { obligations, .. }| obligations)
|
||||
.map_err(|_| Unimplemented)?,
|
||||
);
|
||||
|
@ -1021,7 +1028,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
obligation: &PolyTraitObligation<'tcx>,
|
||||
self_ty_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
let obligation_trait_ref = obligation.predicate.to_poly_trait_ref();
|
||||
let obligation_trait_ref =
|
||||
self.infcx.enter_forall_and_leak_universe(obligation.predicate.to_poly_trait_ref());
|
||||
let self_ty_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
HigherRankedType,
|
||||
self_ty_trait_ref,
|
||||
);
|
||||
// Normalize the obligation and expected trait refs together, because why not
|
||||
let Normalized { obligations: nested, value: (obligation_trait_ref, expected_trait_ref) } =
|
||||
ensure_sufficient_stack(|| {
|
||||
|
@ -1037,15 +1050,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// needed to define opaque types for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(DefineOpaqueTypes::Yes, obligation_trait_ref, expected_trait_ref)
|
||||
.eq(DefineOpaqueTypes::Yes, obligation_trait_ref, expected_trait_ref)
|
||||
.map(|InferOk { mut obligations, .. }| {
|
||||
obligations.extend(nested);
|
||||
obligations
|
||||
})
|
||||
.map_err(|terr| {
|
||||
SignatureMismatch(Box::new(SignatureMismatchData {
|
||||
expected_trait_ref: obligation_trait_ref,
|
||||
found_trait_ref: expected_trait_ref,
|
||||
expected_trait_ref: ty::Binder::dummy(obligation_trait_ref),
|
||||
found_trait_ref: ty::Binder::dummy(expected_trait_ref),
|
||||
terr,
|
||||
}))
|
||||
})
|
||||
|
|
|
@ -33,6 +33,7 @@ use rustc_errors::{Diag, EmissionGuarantee};
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::BoundRegionConversionTime;
|
||||
use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
|
||||
use rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_infer::traits::TraitObligation;
|
||||
use rustc_middle::dep_graph::dep_kinds;
|
||||
|
@ -42,7 +43,7 @@ use rustc_middle::ty::_match::MatchAgainstFreshVars;
|
|||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::GenericArgsRef;
|
||||
use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
|
||||
use rustc_middle::ty::{self, PolyProjectionPredicate, ToPredicate};
|
||||
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Symbol;
|
||||
|
@ -1651,15 +1652,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
fn match_normalize_trait_ref(
|
||||
&mut self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
trait_bound: ty::PolyTraitRef<'tcx>,
|
||||
placeholder_trait_ref: ty::TraitRef<'tcx>,
|
||||
) -> Result<Option<ty::PolyTraitRef<'tcx>>, ()> {
|
||||
trait_bound: ty::PolyTraitRef<'tcx>,
|
||||
) -> Result<Option<ty::TraitRef<'tcx>>, ()> {
|
||||
debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
|
||||
if placeholder_trait_ref.def_id != trait_bound.def_id() {
|
||||
// Avoid unnecessary normalization
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let trait_bound = self.infcx.instantiate_binder_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
HigherRankedType,
|
||||
trait_bound,
|
||||
);
|
||||
let Normalized { value: trait_bound, obligations: _ } = ensure_sufficient_stack(|| {
|
||||
normalize_with_depth(
|
||||
self,
|
||||
|
@ -1671,7 +1677,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
});
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(DefineOpaqueTypes::No, ty::Binder::dummy(placeholder_trait_ref), trait_bound)
|
||||
.eq(DefineOpaqueTypes::No, placeholder_trait_ref, trait_bound)
|
||||
.map(|InferOk { obligations: _, value: () }| {
|
||||
// This method is called within a probe, so we can't have
|
||||
// inference variables and placeholders escape.
|
||||
|
@ -1683,7 +1689,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
})
|
||||
.map_err(|_| ())
|
||||
}
|
||||
|
||||
fn where_clause_may_apply<'o>(
|
||||
&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>,
|
||||
|
@ -1733,7 +1738,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let is_match = self
|
||||
.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(DefineOpaqueTypes::No, obligation.predicate, infer_projection)
|
||||
.eq(DefineOpaqueTypes::No, obligation.predicate, infer_projection)
|
||||
.is_ok_and(|InferOk { obligations, value: () }| {
|
||||
self.evaluate_predicates_recursively(
|
||||
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
|
||||
|
@ -2533,7 +2538,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||
nested.extend(
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(
|
||||
.eq(
|
||||
DefineOpaqueTypes::No,
|
||||
upcast_principal.map_bound(|trait_ref| {
|
||||
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
|
||||
|
@ -2571,7 +2576,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||
nested.extend(
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(DefineOpaqueTypes::No, source_projection, target_projection)
|
||||
.eq(DefineOpaqueTypes::No, source_projection, target_projection)
|
||||
.map_err(|_| SelectionError::Unimplemented)?
|
||||
.into_obligations(),
|
||||
);
|
||||
|
@ -2615,9 +2620,15 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||
obligation: &PolyTraitObligation<'tcx>,
|
||||
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
|
||||
let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
|
||||
let trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
HigherRankedType,
|
||||
poly_trait_ref,
|
||||
);
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(DefineOpaqueTypes::No, obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
|
||||
.eq(DefineOpaqueTypes::No, predicate.trait_ref, trait_ref)
|
||||
.map(|InferOk { obligations, .. }| obligations)
|
||||
.map_err(|_| ())
|
||||
}
|
||||
|
|
|
@ -320,6 +320,7 @@ fn vtable_entries<'tcx>(
|
|||
}
|
||||
|
||||
/// Find slot base for trait methods within vtable entries of another trait
|
||||
// FIXME(@lcnr): This isn't a query, so why does it take a tuple as its argument.
|
||||
pub(super) fn vtable_trait_first_method_offset<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
key: (
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue