Skip to content

Commit bb743f8

Browse files
committed
allow caller to force proof tree generation
1 parent 51090b9 commit bb743f8

File tree

2 files changed

+89
-72
lines changed

2 files changed

+89
-72
lines changed

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

+25-14
Original file line numberDiff line numberDiff line change
@@ -9,7 +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;
12+
use rustc_middle::traits::solve::inspect::{self, CandidateKind};
1313
use rustc_middle::traits::solve::{
1414
CanonicalInput, CanonicalResponse, Certainty, MaybeCause, PredefinedOpaques,
1515
PredefinedOpaquesData, QueryResult,
@@ -108,6 +108,12 @@ impl NestedGoals<'_> {
108108
}
109109
}
110110

111+
#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
112+
pub enum GenerateProofTree {
113+
Yes,
114+
No,
115+
}
116+
111117
pub trait InferCtxtEvalExt<'tcx> {
112118
/// Evaluates a goal from **outside** of the trait solver.
113119
///
@@ -116,15 +122,23 @@ pub trait InferCtxtEvalExt<'tcx> {
116122
fn evaluate_root_goal(
117123
&self,
118124
goal: Goal<'tcx, ty::Predicate<'tcx>>,
119-
) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>;
125+
generate_proof_tree: GenerateProofTree,
126+
) -> (
127+
Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
128+
Option<inspect::GoalEvaluation<'tcx>>,
129+
);
120130
}
121131

122132
impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
123133
#[instrument(level = "debug", skip(self), ret)]
124134
fn evaluate_root_goal(
125135
&self,
126136
goal: Goal<'tcx, ty::Predicate<'tcx>>,
127-
) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
137+
generate_proof_tree: GenerateProofTree,
138+
) -> (
139+
Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
140+
Option<inspect::GoalEvaluation<'tcx>>,
141+
) {
128142
let mode = if self.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
129143
let mut search_graph = search_graph::SearchGraph::new(self.tcx, mode);
130144

@@ -141,19 +155,16 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
141155
var_values: CanonicalVarValues::dummy(),
142156
nested_goals: NestedGoals::new(),
143157
tainted: Ok(()),
144-
inspect: self
145-
.tcx
146-
.sess
147-
.opts
148-
.unstable_opts
149-
.dump_solver_proof_tree
150-
.then(ProofTreeBuilder::new_root)
151-
.unwrap_or_else(ProofTreeBuilder::new_noop),
158+
inspect: (self.tcx.sess.opts.unstable_opts.dump_solver_proof_tree
159+
|| matches!(generate_proof_tree, GenerateProofTree::Yes))
160+
.then(ProofTreeBuilder::new_root)
161+
.unwrap_or_else(ProofTreeBuilder::new_noop),
152162
};
153163
let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal);
154164

155-
if let Some(tree) = ecx.inspect.finalize() {
156-
println!("{:?}", tree);
165+
let tree = ecx.inspect.finalize();
166+
if let Some(tree) = &tree {
167+
debug!(?tree);
157168
}
158169

159170
assert!(
@@ -162,7 +173,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
162173
);
163174

164175
assert!(search_graph.is_empty());
165-
result
176+
(result, tree)
166177
}
167178
}
168179

compiler/rustc_trait_selection/src/solve/fulfill.rs

+64-58
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_infer::traits::{
1010
use rustc_middle::ty;
1111
use rustc_middle::ty::error::{ExpectedFound, TypeError};
1212

13+
use super::eval_ctxt::GenerateProofTree;
1314
use super::{Certainty, InferCtxtEvalExt};
1415

1516
/// A trait engine using the new trait solver.
@@ -46,8 +47,11 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
4647
self.obligations
4748
.drain(..)
4849
.map(|obligation| {
49-
let code =
50-
infcx.probe(|_| match infcx.evaluate_root_goal(obligation.clone().into()) {
50+
let code = infcx.probe(|_| {
51+
match infcx
52+
.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::No)
53+
.0
54+
{
5155
Ok((_, Certainty::Maybe(MaybeCause::Ambiguity), _)) => {
5256
FulfillmentErrorCode::CodeAmbiguity { overflow: false }
5357
}
@@ -60,7 +64,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
6064
Err(_) => {
6165
bug!("did not expect selection error when collecting ambiguity errors")
6266
}
63-
});
67+
}
68+
});
6469

6570
FulfillmentError {
6671
obligation: obligation.clone(),
@@ -81,61 +86,62 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
8186
let mut has_changed = false;
8287
for obligation in mem::take(&mut self.obligations) {
8388
let goal = obligation.clone().into();
84-
let (changed, certainty, nested_goals) = match infcx.evaluate_root_goal(goal) {
85-
Ok(result) => result,
86-
Err(NoSolution) => {
87-
errors.push(FulfillmentError {
88-
obligation: obligation.clone(),
89-
code: match goal.predicate.kind().skip_binder() {
90-
ty::PredicateKind::Clause(ty::Clause::Projection(_)) => {
91-
FulfillmentErrorCode::CodeProjectionError(
92-
// FIXME: This could be a `Sorts` if the term is a type
93-
MismatchedProjectionTypes { err: TypeError::Mismatch },
94-
)
95-
}
96-
ty::PredicateKind::AliasRelate(_, _, _) => {
97-
FulfillmentErrorCode::CodeProjectionError(
98-
MismatchedProjectionTypes { err: TypeError::Mismatch },
99-
)
100-
}
101-
ty::PredicateKind::Subtype(pred) => {
102-
let (a, b) = infcx.instantiate_binder_with_placeholders(
103-
goal.predicate.kind().rebind((pred.a, pred.b)),
104-
);
105-
let expected_found = ExpectedFound::new(true, a, b);
106-
FulfillmentErrorCode::CodeSubtypeError(
107-
expected_found,
108-
TypeError::Sorts(expected_found),
109-
)
110-
}
111-
ty::PredicateKind::Coerce(pred) => {
112-
let (a, b) = infcx.instantiate_binder_with_placeholders(
113-
goal.predicate.kind().rebind((pred.a, pred.b)),
114-
);
115-
let expected_found = ExpectedFound::new(false, a, b);
116-
FulfillmentErrorCode::CodeSubtypeError(
117-
expected_found,
118-
TypeError::Sorts(expected_found),
119-
)
120-
}
121-
ty::PredicateKind::Clause(_)
122-
| ty::PredicateKind::ObjectSafe(_)
123-
| ty::PredicateKind::ClosureKind(_, _, _)
124-
| ty::PredicateKind::Ambiguous => {
125-
FulfillmentErrorCode::CodeSelectionError(
126-
SelectionError::Unimplemented,
127-
)
128-
}
129-
ty::PredicateKind::ConstEquate(..)
130-
| ty::PredicateKind::TypeWellFormedFromEnv(_) => {
131-
bug!("unexpected goal: {goal:?}")
132-
}
133-
},
134-
root_obligation: obligation,
135-
});
136-
continue;
137-
}
138-
};
89+
let (changed, certainty, nested_goals) =
90+
match infcx.evaluate_root_goal(goal, GenerateProofTree::No).0 {
91+
Ok(result) => result,
92+
Err(NoSolution) => {
93+
errors.push(FulfillmentError {
94+
obligation: obligation.clone(),
95+
code: match goal.predicate.kind().skip_binder() {
96+
ty::PredicateKind::Clause(ty::Clause::Projection(_)) => {
97+
FulfillmentErrorCode::CodeProjectionError(
98+
// FIXME: This could be a `Sorts` if the term is a type
99+
MismatchedProjectionTypes { err: TypeError::Mismatch },
100+
)
101+
}
102+
ty::PredicateKind::AliasRelate(_, _, _) => {
103+
FulfillmentErrorCode::CodeProjectionError(
104+
MismatchedProjectionTypes { err: TypeError::Mismatch },
105+
)
106+
}
107+
ty::PredicateKind::Subtype(pred) => {
108+
let (a, b) = infcx.instantiate_binder_with_placeholders(
109+
goal.predicate.kind().rebind((pred.a, pred.b)),
110+
);
111+
let expected_found = ExpectedFound::new(true, a, b);
112+
FulfillmentErrorCode::CodeSubtypeError(
113+
expected_found,
114+
TypeError::Sorts(expected_found),
115+
)
116+
}
117+
ty::PredicateKind::Coerce(pred) => {
118+
let (a, b) = infcx.instantiate_binder_with_placeholders(
119+
goal.predicate.kind().rebind((pred.a, pred.b)),
120+
);
121+
let expected_found = ExpectedFound::new(false, a, b);
122+
FulfillmentErrorCode::CodeSubtypeError(
123+
expected_found,
124+
TypeError::Sorts(expected_found),
125+
)
126+
}
127+
ty::PredicateKind::Clause(_)
128+
| ty::PredicateKind::ObjectSafe(_)
129+
| ty::PredicateKind::ClosureKind(_, _, _)
130+
| ty::PredicateKind::Ambiguous => {
131+
FulfillmentErrorCode::CodeSelectionError(
132+
SelectionError::Unimplemented,
133+
)
134+
}
135+
ty::PredicateKind::ConstEquate(..)
136+
| ty::PredicateKind::TypeWellFormedFromEnv(_) => {
137+
bug!("unexpected goal: {goal:?}")
138+
}
139+
},
140+
root_obligation: obligation,
141+
});
142+
continue;
143+
}
144+
};
139145
// Push any nested goals that we get from unifying our canonical response
140146
// with our obligation onto the fulfillment context.
141147
self.obligations.extend(nested_goals.into_iter().map(|goal| {

0 commit comments

Comments
 (0)