trait_sel: skip elaboration of sizedness supertrait

As a performance optimization, skip elaborating the supertraits of
`Sized`, and if a `MetaSized` obligation is being checked, then look for
a `Sized` predicate in the parameter environment. This makes the
`ParamEnv` smaller which should improve compiler performance as it avoids
all the iteration over the larger `ParamEnv`.
This commit is contained in:
David Wood
2025-03-17 10:24:56 +00:00
parent 47abf2e144
commit 607eb322a8
16 changed files with 268 additions and 40 deletions

View File

@@ -215,6 +215,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
selcx.infcx.probe(|_| {
let bound = util::lazily_elaborate_sizedness_candidate(
selcx.infcx,
obligation,
bound,
);
// We checked the polarity already
match selcx.match_normalize_trait_ref(
obligation,
@@ -259,14 +265,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.caller_bounds()
.iter()
.filter_map(|p| p.as_trait_clause())
// Micro-optimization: filter out predicates relating to different traits.
.filter(|p| p.def_id() == stack.obligation.predicate.def_id())
// Micro-optimization: filter out predicates with different polarities.
.filter(|p| p.polarity() == stack.obligation.predicate.polarity());
let drcx = DeepRejectCtxt::relate_rigid_rigid(self.tcx());
let obligation_args = stack.obligation.predicate.skip_binder().trait_ref.args;
// Keep only those bounds which may apply, and propagate overflow if it occurs.
for bound in bounds {
let bound =
util::lazily_elaborate_sizedness_candidate(self.infcx, stack.obligation, bound);
// Micro-optimization: filter out predicates relating to different traits.
if bound.def_id() != stack.obligation.predicate.def_id() {
continue;
}
let bound_trait_ref = bound.map_bound(|t| t.trait_ref);
if !drcx.args_may_unify(obligation_args, bound_trait_ref.skip_binder().args) {
continue;

View File

@@ -166,10 +166,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
)
.break_value()
.expect("expected to index into clause that exists");
let candidate = candidate_predicate
let candidate_predicate = candidate_predicate
.as_trait_clause()
.expect("projection candidate is not a trait predicate")
.map_bound(|t| t.trait_ref);
.expect("projection candidate is not a trait predicate");
let candidate_predicate =
util::lazily_elaborate_sizedness_candidate(self.infcx, obligation, candidate_predicate);
let candidate = candidate_predicate.map_bound(|t| t.trait_ref);
let candidate = self.infcx.instantiate_binder_with_fresh_vars(
obligation.cause.span,
@@ -226,6 +229,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> PredicateObligations<'tcx> {
debug!(?obligation, ?param, "confirm_param_candidate");
let param = util::lazily_elaborate_sizedness_candidate(
self.infcx,
obligation,
param.upcast(self.infcx.tcx),
)
.map_bound(|p| p.trait_ref);
// During evaluation, we already checked that this
// where-clause trait-ref could be unified with the obligation
// trait-ref. Repeat that unification now without any