Skip to content

Commit 32de28a

Browse files
committed
good shit
1 parent a1bbc9e commit 32de28a

File tree

7 files changed

+298
-121
lines changed

7 files changed

+298
-121
lines changed

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

Lines changed: 59 additions & 33 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+
// TODO
369+
#[derive(Debug)]
370+
pub(super) struct FailedCandidateInfo {
371+
pub param_env_usages: CandidateUsages,
372+
}
373+
358374
impl<D, I> EvalCtxt<'_, D>
359375
where
360376
D: SolverDelegate<Interner = I>,
@@ -364,16 +380,20 @@ where
364380
&mut self,
365381
goal: Goal<I, G>,
366382
assemble_from: AssembleCandidatesFrom,
367-
) -> Vec<Candidate<I>> {
383+
) -> (Vec<Candidate<I>>, FailedCandidateInfo) {
384+
let mut candidates = vec![];
385+
let mut failed_candidate_info =
386+
FailedCandidateInfo { param_env_usages: CandidateUsages::default() };
368387
let Ok(normalized_self_ty) =
369388
self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
370389
else {
371-
return vec![];
390+
return (candidates, failed_candidate_info);
372391
};
373392

374393
if normalized_self_ty.is_ty_var() {
375394
debug!("self type has been normalized to infer");
376-
return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect();
395+
candidates.extend(self.forced_ambiguity(MaybeCause::Ambiguity));
396+
return (candidates, failed_candidate_info);
377397
}
378398

379399
let goal: Goal<I, G> = goal
@@ -382,16 +402,15 @@ where
382402
// normalizing the self type as well, since type variables are not uniquified.
383403
let goal = self.resolve_vars_if_possible(goal);
384404

385-
let mut candidates = vec![];
386-
387405
if let TypingMode::Coherence = self.typing_mode()
388406
&& let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal)
389407
{
390-
return vec![candidate];
408+
candidates.push(candidate);
409+
return (candidates, failed_candidate_info);
391410
}
392411

393412
self.assemble_alias_bound_candidates(goal, &mut candidates);
394-
self.assemble_param_env_candidates(goal, &mut candidates);
413+
self.assemble_param_env_candidates(goal, &mut candidates, &mut failed_candidate_info);
395414

396415
match assemble_from {
397416
AssembleCandidatesFrom::All => {
@@ -423,7 +442,7 @@ where
423442
AssembleCandidatesFrom::EnvAndBounds => {}
424443
}
425444

426-
candidates
445+
(candidates, failed_candidate_info)
427446
}
428447

429448
pub(super) fn forced_ambiguity(
@@ -584,9 +603,15 @@ where
584603
&mut self,
585604
goal: Goal<I, G>,
586605
candidates: &mut Vec<Candidate<I>>,
606+
failed_candidate_info: &mut FailedCandidateInfo,
587607
) {
588608
for assumption in goal.param_env.caller_bounds().iter() {
589-
candidates.extend(G::probe_and_consider_param_env_candidate(self, goal, assumption));
609+
match G::probe_and_consider_param_env_candidate(self, goal, assumption) {
610+
Ok(candidate) => candidates.push(candidate),
611+
Err(candidate_usages) => {
612+
failed_candidate_info.param_env_usages.add_usages(candidate_usages)
613+
}
614+
}
590615
}
591616
}
592617

@@ -661,7 +686,11 @@ where
661686
if let Ok(result) =
662687
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
663688
{
664-
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
689+
candidates.push(Candidate {
690+
source: CandidateSource::AliasBound,
691+
result,
692+
candidate_usages: CandidateUsages::default(),
693+
});
665694
}
666695
return;
667696
}
@@ -959,7 +988,7 @@ where
959988
// Even when a trait bound has been proven using a where-bound, we
960989
// still need to consider alias-bounds for normalization, see
961990
// `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`.
962-
let mut candidates: Vec<_> = self
991+
let (mut candidates, _) = self
963992
.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds);
964993

965994
// We still need to prefer where-bounds over alias-bounds however.
@@ -972,23 +1001,20 @@ where
9721001
return inject_normalize_to_rigid_candidate(self);
9731002
}
9741003

975-
if let Some(response) = self.try_merge_candidates(&candidates) {
1004+
if let Some((response, _)) = self.try_merge_candidates(&candidates) {
9761005
Ok(response)
9771006
} else {
9781007
self.flounder(&candidates)
9791008
}
9801009
}
9811010
TraitGoalProvenVia::Misc => {
982-
let mut candidates =
1011+
let (mut candidates, _) =
9831012
self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
9841013

9851014
// Prefer "orphaned" param-env normalization predicates, which are used
9861015
// (for example, and ideally only) when proving item bounds for an impl.
987-
let candidates_from_env: Vec<_> = candidates
988-
.extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_)))
989-
.collect();
990-
if let Some(response) = self.try_merge_candidates(&candidates_from_env) {
991-
return Ok(response);
1016+
if candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) {
1017+
candidates.retain(|c| matches!(c.source, CandidateSource::ParamEnv(_)));
9921018
}
9931019

9941020
// We drop specialized impls to allow normalization via a final impl here. In case
@@ -997,7 +1023,7 @@ where
9971023
// means we can just ignore inference constraints and don't have to special-case
9981024
// constraining the normalized-to `term`.
9991025
self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates);
1000-
if let Some(response) = self.try_merge_candidates(&candidates) {
1026+
if let Some((response, _)) = self.try_merge_candidates(&candidates) {
10011027
Ok(response)
10021028
} else {
10031029
self.flounder(&candidates)

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(

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::marker::PhantomData;
22

3+
use rustc_type_ir::search_graph::CandidateUsages;
34
use rustc_type_ir::{InferCtxtLike, Interner};
45
use tracing::instrument;
56

@@ -25,6 +26,20 @@ where
2526
D: SolverDelegate<Interner = I>,
2627
I: Interner,
2728
{
29+
pub(in crate::solve) fn enter_unique_candidate(
30+
self,
31+
f: impl FnOnce(&mut EvalCtxt<'_, D>) -> T,
32+
) -> (T, CandidateUsages) {
33+
self.ecx.search_graph.enter_unique_candidate();
34+
let mut candidate_usages = CandidateUsages::default();
35+
let result = self.enter(|ecx| {
36+
let result = f(ecx);
37+
candidate_usages = ecx.search_graph.finish_unique_candidate();
38+
result
39+
});
40+
(result, candidate_usages)
41+
}
42+
2843
pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> T) -> T {
2944
let ProbeCtxt { ecx: outer, probe_kind, _result } = self;
3045

@@ -78,7 +93,8 @@ where
7893
self,
7994
f: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
8095
) -> Result<Candidate<I>, NoSolution> {
81-
self.cx.enter(|ecx| f(ecx)).map(|result| Candidate { source: self.source, result })
96+
let (result, candidate_usages) = self.cx.enter_unique_candidate(f);
97+
result.map(|result| Candidate { source: self.source, result, candidate_usages })
8298
}
8399
}
84100

compiler/rustc_next_trait_solver/src/solve/mod.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,12 @@ where
236236
}
237237
}
238238

239+
#[derive(Debug)]
240+
enum MergeCandidateInfo {
241+
AlwaysApplicable(usize),
242+
EqualResponse,
243+
}
244+
239245
impl<D, I> EvalCtxt<'_, D>
240246
where
241247
D: SolverDelegate<Interner = I>,
@@ -248,23 +254,25 @@ where
248254
fn try_merge_candidates(
249255
&mut self,
250256
candidates: &[Candidate<I>],
251-
) -> Option<CanonicalResponse<I>> {
257+
) -> Option<(CanonicalResponse<I>, MergeCandidateInfo)> {
252258
if candidates.is_empty() {
253259
return None;
254260
}
255261

262+
let always_applicable = candidates.iter().enumerate().find(|(_, candidate)| {
263+
candidate.result.value.certainty == Certainty::Yes
264+
&& has_no_inference_or_external_constraints(candidate.result)
265+
});
266+
if let Some((i, c)) = always_applicable {
267+
return Some((c.result, MergeCandidateInfo::AlwaysApplicable(i)));
268+
}
269+
256270
let one: CanonicalResponse<I> = candidates[0].result;
257271
if candidates[1..].iter().all(|candidate| candidate.result == one) {
258-
return Some(one);
272+
return Some((one, MergeCandidateInfo::EqualResponse));
259273
}
260274

261-
candidates
262-
.iter()
263-
.find(|candidate| {
264-
candidate.result.value.certainty == Certainty::Yes
265-
&& has_no_inference_or_external_constraints(candidate.result)
266-
})
267-
.map(|candidate| candidate.result)
275+
None
268276
}
269277

270278
fn bail_with_ambiguity(&mut self, candidates: &[Candidate<I>]) -> CanonicalResponse<I> {

0 commit comments

Comments
 (0)