Skip to content

Commit 53dd192

Browse files
committed
tis but a yeeet
1 parent addfcc3 commit 53dd192

File tree

7 files changed

+239
-98
lines changed

7 files changed

+239
-98
lines changed

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

Lines changed: 96 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::ops::ControlFlow;
88
use derive_where::derive_where;
99
use rustc_type_ir::inherent::*;
1010
use rustc_type_ir::lang_items::TraitSolverLangItem;
11+
use rustc_type_ir::search_graph::CandidateUsages;
1112
use rustc_type_ir::solve::SizedTraitKind;
1213
use rustc_type_ir::{
1314
self as ty, Interner, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable,
@@ -33,10 +34,11 @@ enum AliasBoundKind {
3334
///
3435
/// It consists of both the `source`, which describes how that goal would be proven,
3536
/// and the `result` when using the given `source`.
36-
#[derive_where(Clone, Debug; I: Interner)]
37+
#[derive_where(Debug; I: Interner)]
3738
pub(super) struct Candidate<I: Interner> {
3839
pub(super) source: CandidateSource<I>,
3940
pub(super) result: CanonicalResponse<I>,
41+
pub(super) candidate_usages: CandidateUsages,
4042
}
4143

4244
/// Methods used to assemble candidates for either trait or projection goals.
@@ -116,8 +118,11 @@ where
116118
ecx: &mut EvalCtxt<'_, D>,
117119
goal: Goal<I, Self>,
118120
assumption: I::Clause,
119-
) -> Result<Candidate<I>, NoSolution> {
120-
Self::fast_reject_assumption(ecx, goal, assumption)?;
121+
) -> Result<Candidate<I>, CandidateUsages> {
122+
match Self::fast_reject_assumption(ecx, goal, assumption) {
123+
Ok(()) => {}
124+
Err(NoSolution) => return Err(CandidateUsages::default()),
125+
}
121126

122127
// Dealing with `ParamEnv` candidates is a bit of a mess as we need to lazily
123128
// check whether the candidate is global while considering normalization.
@@ -126,18 +131,23 @@ where
126131
// in `probe` even if the candidate does not apply before we get there. We handle this
127132
// by using a `Cell` here. We only ever write into it inside of `match_assumption`.
128133
let source = Cell::new(CandidateSource::ParamEnv(ParamEnvSource::Global));
129-
ecx.probe(|result: &QueryResult<I>| inspect::ProbeKind::TraitCandidate {
130-
source: source.get(),
131-
result: *result,
132-
})
133-
.enter(|ecx| {
134-
Self::match_assumption(ecx, goal, assumption, |ecx| {
135-
ecx.try_evaluate_added_goals()?;
136-
source.set(ecx.characterize_param_env_assumption(goal.param_env, assumption)?);
137-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
134+
let (result, candidate_usages) = ecx
135+
.probe(|result: &QueryResult<I>| inspect::ProbeKind::TraitCandidate {
136+
source: source.get(),
137+
result: *result,
138138
})
139-
})
140-
.map(|result| Candidate { source: source.get(), result })
139+
.enter_unique_candidate(|ecx| {
140+
Self::match_assumption(ecx, goal, assumption, |ecx| {
141+
ecx.try_evaluate_added_goals()?;
142+
source.set(ecx.characterize_param_env_assumption(goal.param_env, assumption)?);
143+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
144+
})
145+
});
146+
147+
match result {
148+
Ok(result) => Ok(Candidate { source: source.get(), result, candidate_usages }),
149+
Err(NoSolution) => Err(candidate_usages),
150+
}
141151
}
142152

143153
/// Try equating an assumption predicate against a goal's predicate. If it
@@ -355,6 +365,12 @@ pub(super) enum AssembleCandidatesFrom {
355365
EnvAndBounds,
356366
}
357367

368+
#[derive_where(Debug, Default; I: Interner)]
369+
pub(super) struct Candidates<I: Interner> {
370+
pub applicable: Vec<Candidate<I>>,
371+
pub not_applicable_param_env: Vec<CandidateUsages>,
372+
}
373+
358374
impl<D, I> EvalCtxt<'_, D>
359375
where
360376
D: SolverDelegate<Interner = I>,
@@ -364,16 +380,18 @@ where
364380
&mut self,
365381
goal: Goal<I, G>,
366382
assemble_from: AssembleCandidatesFrom,
367-
) -> Vec<Candidate<I>> {
383+
) -> Candidates<I> {
384+
let mut candidates = Candidates::default();
368385
let Ok(normalized_self_ty) =
369386
self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
370387
else {
371-
return vec![];
388+
return candidates;
372389
};
373390

374391
if normalized_self_ty.is_ty_var() {
375392
debug!("self type has been normalized to infer");
376-
return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect();
393+
candidates.applicable.extend(self.forced_ambiguity(MaybeCause::Ambiguity));
394+
return candidates;
377395
}
378396

379397
let goal: Goal<I, G> = goal
@@ -382,12 +400,11 @@ where
382400
// normalizing the self type as well, since type variables are not uniquified.
383401
let goal = self.resolve_vars_if_possible(goal);
384402

385-
let mut candidates = vec![];
386-
387403
if let TypingMode::Coherence = self.typing_mode()
388404
&& let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal)
389405
{
390-
return vec![candidate];
406+
candidates.applicable.push(candidate);
407+
return candidates;
391408
}
392409

393410
self.assemble_alias_bound_candidates(goal, &mut candidates);
@@ -408,7 +425,7 @@ where
408425
// to worry about causing major performance regressions when doing so.
409426
// See trait-system-refactor-initiative#226 for some ideas here.
410427
if TypingMode::Coherence == self.typing_mode()
411-
|| !candidates.iter().any(|c| {
428+
|| !candidates.applicable.iter().any(|c| {
412429
matches!(
413430
c.source,
414431
CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)
@@ -445,7 +462,7 @@ where
445462
fn assemble_impl_candidates<G: GoalKind<D>>(
446463
&mut self,
447464
goal: Goal<I, G>,
448-
candidates: &mut Vec<Candidate<I>>,
465+
candidates: &mut Candidates<I>,
449466
) {
450467
let cx = self.cx();
451468
cx.for_each_relevant_impl(
@@ -460,7 +477,7 @@ where
460477
}
461478

462479
match G::consider_impl_candidate(self, goal, impl_def_id) {
463-
Ok(candidate) => candidates.push(candidate),
480+
Ok(candidate) => candidates.applicable.push(candidate),
464481
Err(NoSolution) => (),
465482
}
466483
},
@@ -471,7 +488,7 @@ where
471488
fn assemble_builtin_impl_candidates<G: GoalKind<D>>(
472489
&mut self,
473490
goal: Goal<I, G>,
474-
candidates: &mut Vec<Candidate<I>>,
491+
candidates: &mut Candidates<I>,
475492
) {
476493
let cx = self.cx();
477494
let trait_def_id = goal.predicate.trait_def_id(cx);
@@ -570,31 +587,36 @@ where
570587
}
571588
};
572589

573-
candidates.extend(result);
590+
candidates.applicable.extend(result);
574591

575592
// There may be multiple unsize candidates for a trait with several supertraits:
576593
// `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>`
577594
if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Unsize) {
578-
candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal));
595+
candidates
596+
.applicable
597+
.extend(G::consider_structural_builtin_unsize_candidates(self, goal));
579598
}
580599
}
581600

582601
#[instrument(level = "trace", skip_all)]
583602
fn assemble_param_env_candidates<G: GoalKind<D>>(
584603
&mut self,
585604
goal: Goal<I, G>,
586-
candidates: &mut Vec<Candidate<I>>,
605+
candidates: &mut Candidates<I>,
587606
) {
588607
for assumption in goal.param_env.caller_bounds().iter() {
589-
candidates.extend(G::probe_and_consider_param_env_candidate(self, goal, assumption));
608+
match G::probe_and_consider_param_env_candidate(self, goal, assumption) {
609+
Ok(candidate) => candidates.applicable.push(candidate),
610+
Err(candidate_usages) => candidates.not_applicable_param_env.push(candidate_usages),
611+
}
590612
}
591613
}
592614

593615
#[instrument(level = "trace", skip_all)]
594616
fn assemble_alias_bound_candidates<G: GoalKind<D>>(
595617
&mut self,
596618
goal: Goal<I, G>,
597-
candidates: &mut Vec<Candidate<I>>,
619+
candidates: &mut Candidates<I>,
598620
) {
599621
let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
600622
ecx.assemble_alias_bound_candidates_recur(
@@ -619,7 +641,7 @@ where
619641
&mut self,
620642
self_ty: I::Ty,
621643
goal: Goal<I, G>,
622-
candidates: &mut Vec<Candidate<I>>,
644+
candidates: &mut Candidates<I>,
623645
consider_self_bounds: AliasBoundKind,
624646
) {
625647
let (kind, alias_ty) = match self_ty.kind() {
@@ -661,7 +683,11 @@ where
661683
if let Ok(result) =
662684
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
663685
{
664-
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
686+
candidates.applicable.push(Candidate {
687+
source: CandidateSource::AliasBound,
688+
result,
689+
candidate_usages: CandidateUsages::default(),
690+
});
665691
}
666692
return;
667693
}
@@ -680,7 +706,7 @@ where
680706
.item_self_bounds(alias_ty.def_id)
681707
.iter_instantiated(self.cx(), alias_ty.args)
682708
{
683-
candidates.extend(G::probe_and_consider_implied_clause(
709+
candidates.applicable.extend(G::probe_and_consider_implied_clause(
684710
self,
685711
CandidateSource::AliasBound,
686712
goal,
@@ -695,7 +721,7 @@ where
695721
.item_non_self_bounds(alias_ty.def_id)
696722
.iter_instantiated(self.cx(), alias_ty.args)
697723
{
698-
candidates.extend(G::probe_and_consider_implied_clause(
724+
candidates.applicable.extend(G::probe_and_consider_implied_clause(
699725
self,
700726
CandidateSource::AliasBound,
701727
goal,
@@ -706,7 +732,9 @@ where
706732
}
707733
}
708734

709-
candidates.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty));
735+
candidates
736+
.applicable
737+
.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty));
710738

711739
if kind != ty::Projection {
712740
return;
@@ -728,7 +756,7 @@ where
728756
fn assemble_object_bound_candidates<G: GoalKind<D>>(
729757
&mut self,
730758
goal: Goal<I, G>,
731-
candidates: &mut Vec<Candidate<I>>,
759+
candidates: &mut Candidates<I>,
732760
) {
733761
let cx = self.cx();
734762
if !cx.trait_may_be_implemented_via_object(goal.predicate.trait_def_id(cx)) {
@@ -784,7 +812,7 @@ where
784812
}
785813
ty::ExistentialPredicate::Projection(_)
786814
| ty::ExistentialPredicate::AutoTrait(_) => {
787-
candidates.extend(G::probe_and_consider_object_bound_candidate(
815+
candidates.applicable.extend(G::probe_and_consider_object_bound_candidate(
788816
self,
789817
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
790818
goal,
@@ -800,7 +828,7 @@ where
800828
if let Some(principal) = bounds.principal() {
801829
let principal_trait_ref = principal.with_self_ty(cx, self_ty);
802830
for (idx, assumption) in elaborate::supertraits(cx, principal_trait_ref).enumerate() {
803-
candidates.extend(G::probe_and_consider_object_bound_candidate(
831+
candidates.applicable.extend(G::probe_and_consider_object_bound_candidate(
804832
self,
805833
CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)),
806834
goal,
@@ -959,24 +987,30 @@ where
959987
// Even when a trait bound has been proven using a where-bound, we
960988
// still need to consider alias-bounds for normalization, see
961989
// `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`.
962-
let mut candidates: Vec<_> = self
990+
let mut candidates = self
963991
.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds);
964992

965993
// We still need to prefer where-bounds over alias-bounds however.
966994
// See `tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs`.
967-
if candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) {
968-
candidates.retain(|c| matches!(c.source, CandidateSource::ParamEnv(_)));
969-
} else if candidates.is_empty() {
995+
if candidates
996+
.applicable
997+
.iter()
998+
.any(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
999+
{
1000+
for ignored in candidates
1001+
.applicable
1002+
.extract_if(.., |c| !matches!(c.source, CandidateSource::ParamEnv(_)))
1003+
{
1004+
self.ignore_candidate_usages(ignored.candidate_usages);
1005+
}
1006+
} else if candidates.applicable.is_empty() {
9701007
// If the trait goal has been proven by using the environment, we want to treat
9711008
// aliases as rigid if there are no applicable projection bounds in the environment.
9721009
return inject_normalize_to_rigid_candidate(self);
9731010
}
9741011

975-
if let Some(response) = self.try_merge_candidates(&candidates) {
976-
Ok(response)
977-
} else {
978-
self.flounder(&candidates)
979-
}
1012+
self.try_merge_candidates(candidates.applicable, vec![])
1013+
.or_else(|candidates| self.flounder(&candidates))
9801014
}
9811015
TraitGoalProvenVia::Misc => {
9821016
let mut candidates =
@@ -985,23 +1019,31 @@ where
9851019
// Prefer "orphaned" param-env normalization predicates, which are used
9861020
// (for example, and ideally only) when proving item bounds for an impl.
9871021
let candidates_from_env: Vec<_> = candidates
1022+
.applicable
9881023
.extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_)))
9891024
.collect();
990-
if let Some(response) = self.try_merge_candidates(&candidates_from_env) {
991-
return Ok(response);
1025+
if !candidates_from_env.is_empty() {
1026+
match self.try_merge_candidates(
1027+
candidates_from_env,
1028+
candidates.not_applicable_param_env,
1029+
) {
1030+
Ok(response) => return Ok(response),
1031+
Err(candidates_from_env) => return self.flounder(&candidates_from_env),
1032+
}
9921033
}
9931034

9941035
// We drop specialized impls to allow normalization via a final impl here. In case
9951036
// the specializing impl has different inference constraints from the specialized
9961037
// impl, proving the trait goal is already ambiguous, so we never get here. This
9971038
// means we can just ignore inference constraints and don't have to special-case
9981039
// constraining the normalized-to `term`.
999-
self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates);
1000-
if let Some(response) = self.try_merge_candidates(&candidates) {
1001-
Ok(response)
1002-
} else {
1003-
self.flounder(&candidates)
1004-
}
1040+
self.filter_specialized_impls(
1041+
AllowInferenceConstraints::Yes,
1042+
&mut candidates.applicable,
1043+
);
1044+
1045+
self.try_merge_candidates(candidates.applicable, vec![])
1046+
.or_else(|candidates| self.flounder(&candidates))
10051047
}
10061048
}
10071049
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt;
88
use rustc_type_ir::inherent::*;
99
use rustc_type_ir::relate::Relate;
1010
use rustc_type_ir::relate::solver_relating::RelateExt;
11-
use rustc_type_ir::search_graph::PathKind;
11+
use rustc_type_ir::search_graph::{CandidateUsages, PathKind};
1212
use rustc_type_ir::{
1313
self as ty, CanonicalVarValues, InferCtxtLike, Interner, TypeFoldable, TypeFolder,
1414
TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
@@ -399,6 +399,10 @@ where
399399
result
400400
}
401401

402+
pub(super) fn ignore_candidate_usages(&mut self, usages: CandidateUsages) {
403+
self.search_graph.ignore_candidate_usages(usages);
404+
}
405+
402406
/// Recursively evaluates `goal`, returning whether any inference vars have
403407
/// been constrained and the certainty of the result.
404408
fn evaluate_goal(

0 commit comments

Comments
 (0)