Skip to content

Commit 41fb9d4

Browse files
committed
Auto merge of #160605 - nnethercote:four-new-solver-speedups, r=jdonszelmann
Three new-solver speedups Details in individual commits. r? @lcnr
2 parents 793b589 + 3cf1de3 commit 41fb9d4

5 files changed

Lines changed: 56 additions & 31 deletions

File tree

compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,13 @@ where
209209
then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResultOrRerunNonErased<I>,
210210
) -> QueryResultOrRerunNonErased<I>;
211211

212+
/// Note: `goal_trait_ref` is derived from `goal`. Nonetheless, because
213+
/// `consider_impl_candidate` is always called in a loop, we precompute `goal_trait_ref` once
214+
/// and pass it in next to `goal` because the computation is expensive and loop-invariant.
212215
fn consider_impl_candidate(
213216
ecx: &mut EvalCtxt<'_, D>,
214217
goal: Goal<I, Self>,
218+
goal_trait_ref: ty::TraitRef<I>,
215219
impl_def_id: I::ImplId,
216220
then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResultOrRerunNonErased<I>,
217221
) -> Result<Candidate<I>, NoSolutionOrRerunNonErased>;
@@ -545,19 +549,25 @@ where
545549
candidates: &mut Vec<Candidate<I>>,
546550
) -> Result<(), RerunNonErased> {
547551
let cx = self.cx();
548-
cx.for_each_relevant_impl(goal.predicate.trait_ref(cx), |impl_def_id| -> Result<_, _> {
549-
// For every `default impl`, there's always a non-default `impl`
550-
// that will *also* apply. There's no reason to register a candidate
551-
// for this impl, since it is *not* proof that the trait goal holds.
552-
if cx.impl_is_default(impl_def_id) {
553-
return Ok(());
554-
}
555-
match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| {
556-
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
557-
})
552+
let goal_trait_ref = goal.predicate.trait_ref(cx);
553+
cx.for_each_relevant_impl(goal_trait_ref, |impl_def_id| -> Result<_, _> {
554+
match G::consider_impl_candidate(
555+
self,
556+
goal,
557+
goal_trait_ref,
558+
impl_def_id,
559+
|ecx, certainty| ecx.evaluate_added_goals_and_make_canonical_response(certainty),
560+
)
558561
.map_err_to_rerun()?
559562
{
560-
Ok(candidate) => candidates.push(candidate),
563+
Ok(candidate) => {
564+
// For every `default impl`, there's always a non-default `impl`
565+
// that will *also* apply. There's no reason to register a candidate
566+
// for this impl, since it is *not* proof that the trait goal holds.
567+
if !cx.impl_is_default(impl_def_id) {
568+
candidates.push(candidate);
569+
}
570+
}
561571
Err(NoSolution) => {}
562572
}
563573

@@ -1165,6 +1175,7 @@ where
11651175
// See tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs for an example.
11661176
if assemble_from.should_assemble_impl_candidates() {
11671177
let cx = self.cx();
1178+
let goal_trait_ref = goal.predicate.trait_ref(cx);
11681179
cx.for_each_blanket_impl(goal.predicate.trait_def_id(cx), |impl_def_id| {
11691180
// For every `default impl`, there's always a non-default `impl`
11701181
// that will *also* apply. There's no reason to register a candidate
@@ -1173,20 +1184,26 @@ where
11731184
return Ok(());
11741185
}
11751186

1176-
match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| {
1177-
if ecx.shallow_resolve(self_ty).is_ty_var() {
1178-
// We force the certainty of impl candidates to be `Maybe`.
1179-
let certainty = certainty.and(Certainty::AMBIGUOUS);
1180-
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
1181-
} else {
1182-
// We don't want to use impls if they constrain the opaque.
1183-
//
1184-
// FIXME(trait-system-refactor-initiative#229): This isn't
1185-
// perfect yet as it still allows us to incorrectly constrain
1186-
// other inference variables.
1187-
Err(NoSolution.into())
1188-
}
1189-
})
1187+
match G::consider_impl_candidate(
1188+
self,
1189+
goal,
1190+
goal_trait_ref,
1191+
impl_def_id,
1192+
|ecx, certainty| {
1193+
if ecx.shallow_resolve(self_ty).is_ty_var() {
1194+
// We force the certainty of impl candidates to be `Maybe`.
1195+
let certainty = certainty.and(Certainty::AMBIGUOUS);
1196+
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
1197+
} else {
1198+
// We don't want to use impls if they constrain the opaque.
1199+
//
1200+
// FIXME(trait-system-refactor-initiative#229): This isn't
1201+
// perfect yet as it still allows us to incorrectly constrain
1202+
// other inference variables.
1203+
Err(NoSolution.into())
1204+
}
1205+
},
1206+
)
11901207
.map_err_to_rerun()?
11911208
{
11921209
Ok(candidate) => candidates.push(candidate),

compiler/rustc_next_trait_solver/src/solve/effect_goals.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,15 @@ where
136136
fn consider_impl_candidate(
137137
ecx: &mut EvalCtxt<'_, D>,
138138
goal: Goal<I, Self>,
139+
goal_trait_ref: ty::TraitRef<I>,
139140
impl_def_id: I::ImplId,
140141
then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResultOrRerunNonErased<I>,
141142
) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
142143
let cx = ecx.cx();
143144

144145
let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
145146
if !DeepRejectCtxt::relate_rigid_infer(ecx.cx())
146-
.args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
147+
.args_may_unify(goal_trait_ref.args, impl_trait_ref.skip_binder().args)
147148
{
148149
return Err(NoSolution.into());
149150
}
@@ -170,7 +171,7 @@ where
170171
ecx.record_impl_args(impl_args);
171172
let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args).skip_norm_wip();
172173

173-
ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
174+
ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?;
174175
let where_clause_bounds = cx
175176
.clauses_of(impl_def_id.into())
176177
.iter_instantiated(cx, impl_args)

compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,13 @@ where
253253
fn consider_impl_candidate(
254254
ecx: &mut EvalCtxt<'_, D>,
255255
goal: Goal<I, NormalizesTo<I>>,
256+
goal_trait_ref: ty::TraitRef<I>,
256257
impl_def_id: I::ImplId,
257258
then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResultOrRerunNonErased<I>,
258259
) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
259260
let cx = ecx.cx();
260261

261262
let alias_def_id = goal.predicate.alias.expect_projection_def_id();
262-
let goal_trait_ref = goal.predicate.alias.trait_ref(cx);
263263
let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
264264
if !DeepRejectCtxt::relate_rigid_infer(ecx.cx())
265265
.args_may_unify(goal_trait_ref.args, impl_trait_ref.skip_binder().args)

compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,15 @@ where
6060
fn consider_impl_candidate(
6161
ecx: &mut EvalCtxt<'_, D>,
6262
goal: Goal<I, TraitPredicate<I>>,
63+
goal_trait_ref: TraitRef<I>,
6364
impl_def_id: I::ImplId,
6465
then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResultOrRerunNonErased<I>,
6566
) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
6667
let cx = ecx.cx();
6768

6869
let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
6970
if !DeepRejectCtxt::relate_rigid_infer(ecx.cx())
70-
.args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
71+
.args_may_unify(goal_trait_ref.args, impl_trait_ref.skip_binder().args)
7172
{
7273
return Err(NoSolution.into());
7374
}
@@ -109,7 +110,7 @@ where
109110
ecx.record_impl_args(impl_args);
110111
let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args).skip_norm_wip();
111112

112-
ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
113+
ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?;
113114
let where_clause_bounds = cx
114115
.clauses_of(impl_def_id.into())
115116
.iter_instantiated(cx, impl_args)

compiler/rustc_type_ir/src/predicate.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,13 @@ impl<I: Interner> TraitRef<I> {
137137

138138
pub fn from_assoc(interner: I, trait_id: I::TraitId, args: I::GenericArgs) -> TraitRef<I> {
139139
let generics = interner.generics_of(trait_id.into());
140-
TraitRef::new(interner, trait_id, args.iter().take(generics.count()))
140+
if generics.count() == args.len() {
141+
// Can reuse `args` in its entirety.
142+
TraitRef::new_from_args(interner, trait_id, args)
143+
} else {
144+
// Need only some of `args`.
145+
TraitRef::new(interner, trait_id, args.iter().take(generics.count()))
146+
}
141147
}
142148

143149
/// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi`

0 commit comments

Comments
 (0)