Skip to content

Commit 8f380a2

Browse files
committed
candidate assembly structural identity fast path
1 parent ab3579d commit 8f380a2

File tree

2 files changed

+59
-4
lines changed

2 files changed

+59
-4
lines changed

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,13 @@ where
112112
alias_ty: ty::AliasTy<I>,
113113
) -> Vec<Candidate<I>>;
114114

115+
fn assemble_param_env_candidates_fast_path(
116+
_ecx: &mut EvalCtxt<'_, D>,
117+
_goal: Goal<I, Self>,
118+
) -> Option<Candidate<I>> {
119+
None
120+
}
121+
115122
fn probe_and_consider_param_env_candidate(
116123
ecx: &mut EvalCtxt<'_, D>,
117124
goal: Goal<I, Self>,
@@ -582,8 +589,13 @@ where
582589
goal: Goal<I, G>,
583590
candidates: &mut Vec<Candidate<I>>,
584591
) {
585-
for assumption in goal.param_env.caller_bounds().iter() {
586-
candidates.extend(G::probe_and_consider_param_env_candidate(self, goal, assumption));
592+
if let Some(candidate) = G::assemble_param_env_candidates_fast_path(self, goal) {
593+
candidates.push(candidate);
594+
} else {
595+
for assumption in goal.param_env.caller_bounds().iter() {
596+
candidates
597+
.extend(G::probe_and_consider_param_env_candidate(self, goal, assumption));
598+
}
587599
}
588600
}
589601

@@ -1033,7 +1045,7 @@ where
10331045
/// The `i32: From<T::Assoc>` bound is non-global before normalization, but is global after.
10341046
/// Since the old trait solver normalized param-envs eagerly, we want to emulate this
10351047
/// behavior lazily.
1036-
fn characterize_param_env_assumption(
1048+
pub(super) fn characterize_param_env_assumption(
10371049
&mut self,
10381050
param_env: I::ParamEnv,
10391051
assumption: I::Clause,

compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
22
3+
use std::cell::Cell;
4+
35
use rustc_type_ir::data_structures::IndexSet;
46
use rustc_type_ir::fast_reject::DeepRejectCtxt;
57
use rustc_type_ir::inherent::*;
@@ -14,7 +16,7 @@ use tracing::{debug, instrument, trace};
1416
use crate::delegate::SolverDelegate;
1517
use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
1618
use crate::solve::assembly::{self, AllowInferenceConstraints, AssembleCandidatesFrom, Candidate};
17-
use crate::solve::inspect::ProbeKind;
19+
use crate::solve::inspect::{self, ProbeKind};
1820
use crate::solve::{
1921
BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
2022
NoSolution, ParamEnvSource, QueryResult, has_only_region_constraints,
@@ -41,6 +43,47 @@ where
4143
self.def_id()
4244
}
4345

46+
fn assemble_param_env_candidates_fast_path(
47+
ecx: &mut EvalCtxt<'_, D>,
48+
goal: Goal<I, Self>,
49+
) -> Option<Candidate<I>> {
50+
// This is kind of a mess. We need to detect whether there's an applicable
51+
// `ParamEnv` candidate without fully normalizing other candidates to avoid the
52+
// hang in trait-system-refactor-initiative#210. This currently uses structural
53+
// identity, which means it does not apply if there are normalizeable aliases
54+
// in the environment or if the goal is higher ranked.
55+
//
56+
// We generally need such a fast path if multiple potentially applicable where-bounds
57+
// contain aliases whose normalization tries to apply all these where-bounds yet again.
58+
// This can easily result in exponential blowup.
59+
for assumption in goal.param_env.caller_bounds().iter().filter_map(|c| c.as_trait_clause())
60+
{
61+
if assumption.no_bound_vars().is_some_and(|c| c == goal.predicate) {
62+
let source = Cell::new(CandidateSource::ParamEnv(ParamEnvSource::Global));
63+
let Ok(candidate) = ecx
64+
.probe(|result: &QueryResult<I>| inspect::ProbeKind::TraitCandidate {
65+
source: source.get(),
66+
result: *result,
67+
})
68+
.enter(|ecx| {
69+
source.set(ecx.characterize_param_env_assumption(
70+
goal.param_env,
71+
assumption.upcast(ecx.cx()),
72+
)?);
73+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
74+
})
75+
.map(|result| Candidate { source: source.get(), result })
76+
else {
77+
continue;
78+
};
79+
if candidate.source == CandidateSource::ParamEnv(ParamEnvSource::NonGlobal) {
80+
return Some(candidate);
81+
}
82+
}
83+
}
84+
None
85+
}
86+
4487
fn consider_additional_alias_assumptions(
4588
_ecx: &mut EvalCtxt<'_, D>,
4689
_goal: Goal<I, Self>,

0 commit comments

Comments
 (0)