Skip to content

Commit e367c04

Browse files
committed
introduce a separate set of types for finalized proof trees
1 parent 7a3665d commit e367c04

File tree

7 files changed

+335
-188
lines changed

7 files changed

+335
-188
lines changed

compiler/rustc_middle/src/traits/solve/inspect.rs

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::{CanonicalInput, Certainty, Goal, NoSolution, QueryInput, QueryResult
22
use crate::ty;
33
use std::fmt::{Debug, Write};
44

5-
#[derive(Eq, PartialEq, Hash, HashStable)]
5+
#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
66
pub enum CacheHit {
77
Provisional,
88
Global,
@@ -11,16 +11,16 @@ pub enum CacheHit {
1111
#[derive(Eq, PartialEq, Hash, HashStable)]
1212
pub struct GoalEvaluation<'tcx> {
1313
pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
14-
pub canonicalized_goal: Option<CanonicalInput<'tcx>>,
15-
16-
/// To handle coinductive cycles we can end up re-evaluating a goal
17-
/// multiple times with different results for a nested goal. Each rerun
18-
/// is represented as an entry in this vec.
19-
pub evaluation_steps: Vec<GoalEvaluationStep<'tcx>>,
14+
pub canonicalized_goal: CanonicalInput<'tcx>,
2015

21-
pub cache_hit: Option<CacheHit>,
16+
pub kind: GoalEvaluationKind<'tcx>,
2217

23-
pub result: Option<QueryResult<'tcx>>,
18+
pub result: QueryResult<'tcx>,
19+
}
20+
#[derive(Eq, PartialEq, Hash, HashStable)]
21+
pub enum GoalEvaluationKind<'tcx> {
22+
CacheHit(CacheHit),
23+
Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> },
2424
}
2525
impl Debug for GoalEvaluation<'_> {
2626
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -31,7 +31,7 @@ impl Debug for GoalEvaluation<'_> {
3131
#[derive(Eq, PartialEq, Hash, HashStable)]
3232
pub struct AddedGoalsEvaluation<'tcx> {
3333
pub evaluations: Vec<Vec<GoalEvaluation<'tcx>>>,
34-
pub result: Option<Result<Certainty, NoSolution>>,
34+
pub result: Result<Certainty, NoSolution>,
3535
}
3636
impl Debug for AddedGoalsEvaluation<'_> {
3737
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -46,7 +46,7 @@ pub struct GoalEvaluationStep<'tcx> {
4646
pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
4747
pub candidates: Vec<GoalCandidate<'tcx>>,
4848

49-
pub result: Option<QueryResult<'tcx>>,
49+
pub result: QueryResult<'tcx>,
5050
}
5151
impl Debug for GoalEvaluationStep<'_> {
5252
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -58,9 +58,14 @@ impl Debug for GoalEvaluationStep<'_> {
5858
pub struct GoalCandidate<'tcx> {
5959
pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
6060
pub candidates: Vec<GoalCandidate<'tcx>>,
61-
62-
pub name: Option<String>,
63-
pub result: Option<QueryResult<'tcx>>,
61+
pub kind: CandidateKind<'tcx>,
62+
}
63+
#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
64+
pub enum CandidateKind<'tcx> {
65+
/// Probe entered when normalizing the self ty during candidate assembly
66+
NormalizedSelfTyAssembly,
67+
/// A normal candidate for proving a goal
68+
Candidate { name: String, result: QueryResult<'tcx> },
6469
}
6570
impl Debug for GoalCandidate<'_> {
6671
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -97,19 +102,23 @@ impl ProofTreeFormatter<'_, '_> {
97102
writeln!(f, "GOAL: {:?}", goal.uncanonicalized_goal)?;
98103
writeln!(f, "CANONICALIZED: {:?}", goal.canonicalized_goal)?;
99104

100-
match goal.cache_hit {
101-
Some(CacheHit::Global) => writeln!(f, "GLOBAL CACHE HIT: {:?}", goal.result),
102-
Some(CacheHit::Provisional) => writeln!(f, "PROVISIONAL CACHE HIT: {:?}", goal.result),
103-
None => {
104-
for (n, step) in goal.evaluation_steps.iter().enumerate() {
105+
match &goal.kind {
106+
GoalEvaluationKind::CacheHit(CacheHit::Global) => {
107+
writeln!(f, "GLOBAL CACHE HIT: {:?}", goal.result)
108+
}
109+
GoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
110+
writeln!(f, "PROVISIONAL CACHE HIT: {:?}", goal.result)
111+
}
112+
GoalEvaluationKind::Uncached { revisions } => {
113+
for (n, step) in revisions.iter().enumerate() {
105114
let f = &mut *self.f;
106-
writeln!(f, "REVISION {n}: {:?}", step.result.unwrap())?;
115+
writeln!(f, "REVISION {n}: {:?}", step.result)?;
107116
let mut f = self.nested();
108117
f.format_evaluation_step(step)?;
109118
}
110119

111120
let f = &mut *self.f;
112-
writeln!(f, "RESULT: {:?}", goal.result.unwrap())
121+
writeln!(f, "RESULT: {:?}", goal.result)
113122
}
114123
}
115124
}
@@ -136,12 +145,14 @@ impl ProofTreeFormatter<'_, '_> {
136145
fn format_candidate(&mut self, candidate: &GoalCandidate<'_>) -> std::fmt::Result {
137146
let f = &mut *self.f;
138147

139-
match (candidate.name.as_ref(), candidate.result) {
140-
(Some(name), Some(result)) => writeln!(f, "CANDIDATE {}: {:?}", name, result,)?,
141-
(None, None) => writeln!(f, "MISC PROBE")?,
142-
(None, Some(_)) => unreachable!("unexpected probe with no name but a result"),
143-
(Some(_), None) => unreachable!("unexpected probe with a name but no candidate"),
144-
};
148+
match &candidate.kind {
149+
CandidateKind::NormalizedSelfTyAssembly => {
150+
writeln!(f, "NORMALIZING SELF TY FOR ASSEMBLY:")
151+
}
152+
CandidateKind::Candidate { name, result } => {
153+
writeln!(f, "CANDIDATE {}: {:?}", name, result)
154+
}
155+
}?;
145156

146157
let mut f = self.nested();
147158
for candidate in &candidate.candidates {
@@ -159,7 +170,7 @@ impl ProofTreeFormatter<'_, '_> {
159170
nested_goal_evaluation: &AddedGoalsEvaluation<'_>,
160171
) -> std::fmt::Result {
161172
let f = &mut *self.f;
162-
writeln!(f, "TRY_EVALUATE_ADDED_GOALS: {:?}", nested_goal_evaluation.result.unwrap())?;
173+
writeln!(f, "TRY_EVALUATE_ADDED_GOALS: {:?}", nested_goal_evaluation.result)?;
163174

164175
for (n, revision) in nested_goal_evaluation.evaluations.iter().enumerate() {
165176
let f = &mut *self.f;

compiler/rustc_trait_selection/src/solve/alias_relate.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::{EvalCtxt, SolverMode};
22
use rustc_infer::traits::query::NoSolution;
3+
use rustc_middle::traits::solve::inspect::CandidateKind;
34
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
45
use rustc_middle::ty;
56

@@ -109,12 +110,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
109110
direction: ty::AliasRelationDirection,
110111
invert: Invert,
111112
) -> QueryResult<'tcx> {
112-
self.probe_candidate(
113+
self.probe(
113114
|ecx| {
114115
ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?;
115116
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
116117
},
117-
|| "normalizes-to".into(),
118+
|r| CandidateKind::Candidate { name: "normalizes-to".into(), result: *r },
118119
)
119120
}
120121

@@ -156,7 +157,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
156157
alias_rhs: ty::AliasTy<'tcx>,
157158
direction: ty::AliasRelationDirection,
158159
) -> QueryResult<'tcx> {
159-
self.probe_candidate(
160+
self.probe(
160161
|ecx| {
161162
match direction {
162163
ty::AliasRelationDirection::Equate => {
@@ -169,7 +170,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
169170

170171
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
171172
},
172-
|| "substs relate".into(),
173+
|r| CandidateKind::Candidate { name: "substs relate".into(), result: *r },
173174
)
174175
}
175176

@@ -180,7 +181,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
180181
rhs: ty::Term<'tcx>,
181182
direction: ty::AliasRelationDirection,
182183
) -> QueryResult<'tcx> {
183-
self.probe_candidate(
184+
self.probe(
184185
|ecx| {
185186
ecx.normalizes_to_inner(
186187
param_env,
@@ -198,7 +199,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
198199
)?;
199200
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
200201
},
201-
|| "bidir normalizes-to".into(),
202+
|r| CandidateKind::Candidate { name: "bidir normalizes-to".into(), result: *r },
202203
)
203204
}
204205
}

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

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_hir::def_id::DefId;
88
use rustc_infer::traits::query::NoSolution;
99
use rustc_infer::traits::util::elaborate;
1010
use rustc_infer::traits::Reveal;
11+
use rustc_middle::traits::solve::inspect::CandidateKind;
1112
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult};
1213
use rustc_middle::ty::fast_reject::TreatProjections;
1314
use rustc_middle::ty::TypeFoldable;
@@ -336,37 +337,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
336337
return
337338
};
338339

339-
let normalized_self_candidates: Result<_, NoSolution> = self.probe(|ecx| {
340-
ecx.with_incremented_depth(
341-
|ecx| {
342-
let result = ecx.evaluate_added_goals_and_make_canonical_response(
343-
Certainty::Maybe(MaybeCause::Overflow),
344-
)?;
345-
Ok(vec![Candidate { source: CandidateSource::BuiltinImpl, result }])
346-
},
347-
|ecx| {
348-
let normalized_ty = ecx.next_ty_infer();
349-
let normalizes_to_goal = goal.with(
350-
tcx,
351-
ty::Binder::dummy(ty::ProjectionPredicate {
352-
projection_ty,
353-
term: normalized_ty.into(),
354-
}),
355-
);
356-
ecx.add_goal(normalizes_to_goal);
357-
let _ = ecx.try_evaluate_added_goals().inspect_err(|_| {
358-
debug!("self type normalization failed");
359-
})?;
360-
let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty);
361-
debug!(?normalized_ty, "self type normalized");
362-
// NOTE: Alternatively we could call `evaluate_goal` here and only
363-
// have a `Normalized` candidate. This doesn't work as long as we
364-
// use `CandidateSource` in winnowing.
365-
let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
366-
Ok(ecx.assemble_and_evaluate_candidates(goal))
367-
},
368-
)
369-
});
340+
let normalized_self_candidates: Result<_, NoSolution> = self.probe(
341+
|ecx| {
342+
ecx.with_incremented_depth(
343+
|ecx| {
344+
let result = ecx.evaluate_added_goals_and_make_canonical_response(
345+
Certainty::Maybe(MaybeCause::Overflow),
346+
)?;
347+
Ok(vec![Candidate { source: CandidateSource::BuiltinImpl, result }])
348+
},
349+
|ecx| {
350+
let normalized_ty = ecx.next_ty_infer();
351+
let normalizes_to_goal = goal.with(
352+
tcx,
353+
ty::Binder::dummy(ty::ProjectionPredicate {
354+
projection_ty,
355+
term: normalized_ty.into(),
356+
}),
357+
);
358+
ecx.add_goal(normalizes_to_goal);
359+
let _ = ecx.try_evaluate_added_goals().inspect_err(|_| {
360+
debug!("self type normalization failed");
361+
})?;
362+
let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty);
363+
debug!(?normalized_ty, "self type normalized");
364+
// NOTE: Alternatively we could call `evaluate_goal` here and only
365+
// have a `Normalized` candidate. This doesn't work as long as we
366+
// use `CandidateSource` in winnowing.
367+
let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
368+
Ok(ecx.assemble_and_evaluate_candidates(goal))
369+
},
370+
)
371+
},
372+
|_| CandidateKind::NormalizedSelfTyAssembly,
373+
);
370374

371375
if let Ok(normalized_self_candidates) = normalized_self_candidates {
372376
candidates.extend(normalized_self_candidates);

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_infer::infer::{
99
use rustc_infer::traits::query::NoSolution;
1010
use rustc_infer::traits::ObligationCause;
1111
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
12+
use rustc_middle::traits::solve::inspect::CandidateKind;
1213
use rustc_middle::traits::solve::{
1314
CanonicalInput, CanonicalResponse, Certainty, MaybeCause, PredefinedOpaques,
1415
PredefinedOpaquesData, QueryResult,
@@ -78,7 +79,7 @@ pub struct EvalCtxt<'a, 'tcx> {
7879
inspect: ProofTreeBuilder<'tcx>,
7980
}
8081

81-
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
82+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
8283
pub(super) enum IsNormalizesToHack {
8384
Yes,
8485
No,
@@ -157,7 +158,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
157158
};
158159
let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal);
159160

160-
if let Some(tree) = ecx.inspect.into_proof_tree() {
161+
if let Some(tree) = ecx.inspect.finalize() {
161162
println!("{:?}", tree);
162163
}
163164

@@ -509,7 +510,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
509510
}
510511

511512
impl<'tcx> EvalCtxt<'_, 'tcx> {
512-
pub(super) fn probe<T>(&mut self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T {
513+
/// `probe_kind` is only called when proof tree building is enabled so it can be
514+
/// as expensive as necessary to output the desired information.
515+
pub(super) fn probe<T>(
516+
&mut self,
517+
f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T,
518+
probe_kind: impl FnOnce(&T) -> CandidateKind<'tcx>,
519+
) -> T {
513520
let mut ecx = EvalCtxt {
514521
infcx: self.infcx,
515522
var_values: self.var_values,
@@ -521,23 +528,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
521528
inspect: self.inspect.new_goal_candidate(),
522529
};
523530
let r = self.infcx.probe(|_| f(&mut ecx));
524-
self.inspect.goal_candidate(ecx.inspect);
531+
if !self.inspect.is_noop() {
532+
let cand_kind = probe_kind(&r);
533+
ecx.inspect.candidate_kind(cand_kind);
534+
self.inspect.goal_candidate(ecx.inspect);
535+
}
525536
r
526537
}
527538

528-
pub(super) fn probe_candidate(
529-
&mut self,
530-
f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
531-
mut name: impl FnMut() -> String,
532-
) -> QueryResult<'tcx> {
533-
self.probe(|ecx| {
534-
let result = f(ecx);
535-
ecx.inspect.candidate_name(&mut name);
536-
ecx.inspect.query_result(result);
537-
result
538-
})
539-
}
540-
541539
pub(super) fn tcx(&self) -> TyCtxt<'tcx> {
542540
self.infcx.tcx
543541
}
@@ -858,7 +856,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
858856
ecx.add_item_bounds_for_hidden_type(candidate_key, param_env, candidate_ty);
859857
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
860858
},
861-
|| "opaque type storage".into(),
859+
|r| CandidateKind::Candidate { name: "opaque type storage".into(), result: *r },
862860
));
863861
}
864862
values

0 commit comments

Comments
 (0)