Skip to content

Commit 040aa58

Browse files
committed
add flag for disabling global cache and printing proof trees on error
1 parent 8931edf commit 040aa58

File tree

8 files changed

+175
-48
lines changed

8 files changed

+175
-48
lines changed

Diff for: compiler/rustc_session/src/config.rs

+8
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,14 @@ pub enum TraitSolver {
745745
NextCoherence,
746746
}
747747

748+
#[derive(Default, Debug, Copy, Clone, Hash, PartialEq, Eq)]
749+
pub enum SolverProofTreeCondition {
750+
#[default]
751+
Never,
752+
Always,
753+
OnError,
754+
}
755+
748756
pub enum Input {
749757
/// Load source code from a file.
750758
File(PathBuf),

Diff for: compiler/rustc_session/src/options.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ mod desc {
418418
"a `,` separated combination of `bti`, `b-key`, `pac-ret`, or `leaf`";
419419
pub const parse_proc_macro_execution_strategy: &str =
420420
"one of supported execution strategies (`same-thread`, or `cross-thread`)";
421+
pub const parse_solver_proof_tree_condition: &str = "one of: `always`, `never`, `on_error`";
421422
}
422423

423424
mod parse {
@@ -1238,6 +1239,19 @@ mod parse {
12381239
};
12391240
true
12401241
}
1242+
1243+
pub(crate) fn parse_solver_proof_tree_condition(
1244+
slot: &mut SolverProofTreeCondition,
1245+
v: Option<&str>,
1246+
) -> bool {
1247+
match v {
1248+
None | Some("always") => *slot = SolverProofTreeCondition::Always,
1249+
Some("never") => *slot = SolverProofTreeCondition::Never,
1250+
Some("on-error") => *slot = SolverProofTreeCondition::OnError,
1251+
_ => return false,
1252+
};
1253+
true
1254+
}
12411255
}
12421256

12431257
options! {
@@ -1463,8 +1477,10 @@ options! {
14631477
"output statistics about monomorphization collection"),
14641478
dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED],
14651479
"the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"),
1466-
dump_solver_proof_tree: bool = (false, parse_bool, [UNTRACKED],
1467-
"dump a proof tree for every goal evaluated by the new trait solver"),
1480+
dump_solver_proof_tree: SolverProofTreeCondition = (SolverProofTreeCondition::Never, parse_solver_proof_tree_condition, [UNTRACKED],
1481+
"dump a proof tree for every goal evaluated by the new trait solver. The default is `always`"),
1482+
dump_solver_proof_tree_uses_cache: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
1483+
"determines whether proof tree generation uses the global cache"),
14681484
dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
14691485
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
14701486
dylib_lto: bool = (false, parse_bool, [UNTRACKED],

Diff for: compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

+53-7
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ use rustc_middle::ty::{
1919
self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
2020
TypeVisitableExt, TypeVisitor,
2121
};
22+
use rustc_session::config::SolverProofTreeCondition;
2223
use rustc_span::DUMMY_SP;
24+
use std::io::Write;
2325
use std::ops::ControlFlow;
2426

2527
use crate::traits::specialization_graph;
@@ -113,9 +115,23 @@ impl NestedGoals<'_> {
113115

114116
#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
115117
pub enum GenerateProofTree {
118+
Yes(DisableGlobalCache),
119+
No,
120+
}
121+
122+
#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
123+
pub enum DisableGlobalCache {
116124
Yes,
117125
No,
118126
}
127+
impl DisableGlobalCache {
128+
pub fn from_bool(disable_cache: bool) -> Self {
129+
match disable_cache {
130+
true => DisableGlobalCache::Yes,
131+
false => DisableGlobalCache::No,
132+
}
133+
}
134+
}
119135

120136
pub trait InferCtxtEvalExt<'tcx> {
121137
/// Evaluates a goal from **outside** of the trait solver.
@@ -164,6 +180,36 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
164180
let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
165181
let mut search_graph = search_graph::SearchGraph::new(infcx.tcx, mode);
166182

183+
let inspect = {
184+
let generate_proof_tree = match (
185+
infcx.tcx.sess.opts.unstable_opts.dump_solver_proof_tree,
186+
infcx.tcx.sess.opts.unstable_opts.dump_solver_proof_tree_uses_cache,
187+
generate_proof_tree,
188+
) {
189+
(_, Some(use_cache), GenerateProofTree::Yes(_)) => {
190+
GenerateProofTree::Yes(DisableGlobalCache::from_bool(!use_cache))
191+
}
192+
193+
(SolverProofTreeCondition::Always, use_cache, GenerateProofTree::No) => {
194+
let use_cache = use_cache.unwrap_or(true);
195+
GenerateProofTree::Yes(DisableGlobalCache::from_bool(!use_cache))
196+
}
197+
198+
(_, None, GenerateProofTree::Yes(_)) => generate_proof_tree,
199+
// `Never` is kind of weird- it doesn't actually force us to not generate proof trees
200+
// its just the default setting for rustflags forced proof tree generation.
201+
(SolverProofTreeCondition::Never, _, _) => generate_proof_tree,
202+
(SolverProofTreeCondition::OnError, _, _) => generate_proof_tree,
203+
};
204+
205+
match generate_proof_tree {
206+
GenerateProofTree::No => ProofTreeBuilder::new_noop(),
207+
GenerateProofTree::Yes(global_cache_disabled) => {
208+
ProofTreeBuilder::new_root(global_cache_disabled)
209+
}
210+
}
211+
};
212+
167213
let mut ecx = EvalCtxt {
168214
search_graph: &mut search_graph,
169215
infcx: infcx,
@@ -177,17 +223,17 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
177223
var_values: CanonicalVarValues::dummy(),
178224
nested_goals: NestedGoals::new(),
179225
tainted: Ok(()),
180-
inspect: (infcx.tcx.sess.opts.unstable_opts.dump_solver_proof_tree
181-
|| matches!(generate_proof_tree, GenerateProofTree::Yes))
182-
.then(ProofTreeBuilder::new_root)
183-
.unwrap_or_else(ProofTreeBuilder::new_noop),
226+
inspect,
184227
};
185228
let result = f(&mut ecx);
186229

187230
let tree = ecx.inspect.finalize();
188-
if let Some(tree) = &tree {
189-
// module to allow more granular RUSTC_LOG filtering to just proof tree output
190-
super::inspect::dump::print_tree(tree);
231+
if let (Some(tree), SolverProofTreeCondition::Always) =
232+
(&tree, infcx.tcx.sess.opts.unstable_opts.dump_solver_proof_tree)
233+
{
234+
let mut lock = std::io::stdout().lock();
235+
let _ = lock.write_fmt(format_args!("{tree:?}"));
236+
let _ = lock.flush();
191237
}
192238

193239
assert!(

Diff for: compiler/rustc_trait_selection/src/solve/inspect.rs

+61-31
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_middle::traits::solve::{
55
};
66
use rustc_middle::ty;
77

8-
pub mod dump;
8+
use super::eval_ctxt::DisableGlobalCache;
99

1010
#[derive(Eq, PartialEq, Debug, Hash, HashStable)]
1111
pub struct WipGoalEvaluation<'tcx> {
@@ -145,11 +145,15 @@ impl<'tcx> From<WipGoalCandidate<'tcx>> for DebugSolver<'tcx> {
145145

146146
pub struct ProofTreeBuilder<'tcx> {
147147
state: Option<Box<DebugSolver<'tcx>>>,
148+
disable_global_cache: DisableGlobalCache,
148149
}
149150

150151
impl<'tcx> ProofTreeBuilder<'tcx> {
151-
fn new(state: impl Into<DebugSolver<'tcx>>) -> ProofTreeBuilder<'tcx> {
152-
ProofTreeBuilder { state: Some(Box::new(state.into())) }
152+
fn new(
153+
state: impl Into<DebugSolver<'tcx>>,
154+
disable_global_cache: DisableGlobalCache,
155+
) -> ProofTreeBuilder<'tcx> {
156+
ProofTreeBuilder { state: Some(Box::new(state.into())), disable_global_cache }
153157
}
154158

155159
fn as_mut(&mut self) -> Option<&mut DebugSolver<'tcx>> {
@@ -165,12 +169,16 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
165169
}
166170
}
167171

168-
pub fn new_root() -> ProofTreeBuilder<'tcx> {
169-
ProofTreeBuilder::new(DebugSolver::Root)
172+
pub fn disable_global_cache(&self) -> DisableGlobalCache {
173+
self.disable_global_cache
174+
}
175+
176+
pub fn new_root(disable_global_cache: DisableGlobalCache) -> ProofTreeBuilder<'tcx> {
177+
ProofTreeBuilder::new(DebugSolver::Root, disable_global_cache)
170178
}
171179

172180
pub fn new_noop() -> ProofTreeBuilder<'tcx> {
173-
ProofTreeBuilder { state: None }
181+
ProofTreeBuilder { state: None, disable_global_cache: DisableGlobalCache::No }
174182
}
175183

176184
pub fn is_noop(&self) -> bool {
@@ -183,18 +191,24 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
183191
is_normalizes_to_hack: IsNormalizesToHack,
184192
) -> ProofTreeBuilder<'tcx> {
185193
if self.state.is_none() {
186-
return ProofTreeBuilder { state: None };
194+
return ProofTreeBuilder {
195+
state: None,
196+
disable_global_cache: self.disable_global_cache,
197+
};
187198
}
188199

189-
ProofTreeBuilder::new(WipGoalEvaluation {
190-
uncanonicalized_goal: goal,
191-
canonicalized_goal: None,
192-
evaluation_steps: vec![],
193-
is_normalizes_to_hack,
194-
cache_hit: None,
195-
returned_goals: vec![],
196-
result: None,
197-
})
200+
ProofTreeBuilder::new(
201+
WipGoalEvaluation {
202+
uncanonicalized_goal: goal,
203+
canonicalized_goal: None,
204+
evaluation_steps: vec![],
205+
is_normalizes_to_hack,
206+
cache_hit: None,
207+
returned_goals: vec![],
208+
result: None,
209+
},
210+
self.disable_global_cache,
211+
)
198212
}
199213

200214
pub fn canonicalized_goal(&mut self, canonical_goal: CanonicalInput<'tcx>) {
@@ -250,15 +264,21 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
250264
instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
251265
) -> ProofTreeBuilder<'tcx> {
252266
if self.state.is_none() {
253-
return ProofTreeBuilder { state: None };
267+
return ProofTreeBuilder {
268+
state: None,
269+
disable_global_cache: self.disable_global_cache,
270+
};
254271
}
255272

256-
ProofTreeBuilder::new(WipGoalEvaluationStep {
257-
instantiated_goal,
258-
nested_goal_evaluations: vec![],
259-
candidates: vec![],
260-
result: None,
261-
})
273+
ProofTreeBuilder::new(
274+
WipGoalEvaluationStep {
275+
instantiated_goal,
276+
nested_goal_evaluations: vec![],
277+
candidates: vec![],
278+
result: None,
279+
},
280+
self.disable_global_cache,
281+
)
262282
}
263283
pub fn goal_evaluation_step(&mut self, goal_eval_step: ProofTreeBuilder<'tcx>) {
264284
if let Some(this) = self.as_mut() {
@@ -273,14 +293,17 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
273293

274294
pub fn new_goal_candidate(&mut self) -> ProofTreeBuilder<'tcx> {
275295
if self.state.is_none() {
276-
return ProofTreeBuilder { state: None };
296+
return ProofTreeBuilder {
297+
state: None,
298+
299+
disable_global_cache: self.disable_global_cache,
300+
};
277301
}
278302

279-
ProofTreeBuilder::new(WipGoalCandidate {
280-
nested_goal_evaluations: vec![],
281-
candidates: vec![],
282-
kind: None,
283-
})
303+
ProofTreeBuilder::new(
304+
WipGoalCandidate { nested_goal_evaluations: vec![], candidates: vec![], kind: None },
305+
self.disable_global_cache,
306+
)
284307
}
285308

286309
pub fn candidate_kind(&mut self, candidate_kind: CandidateKind<'tcx>) {
@@ -309,10 +332,17 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
309332

310333
pub fn new_evaluate_added_goals(&mut self) -> ProofTreeBuilder<'tcx> {
311334
if self.state.is_none() {
312-
return ProofTreeBuilder { state: None };
335+
return ProofTreeBuilder {
336+
state: None,
337+
338+
disable_global_cache: self.disable_global_cache,
339+
};
313340
}
314341

315-
ProofTreeBuilder::new(WipAddedGoalsEvaluation { evaluations: vec![], result: None })
342+
ProofTreeBuilder::new(
343+
WipAddedGoalsEvaluation { evaluations: vec![], result: None },
344+
self.disable_global_cache,
345+
)
316346
}
317347

318348
pub fn evaluate_added_goals_loop_start(&mut self) {

Diff for: compiler/rustc_trait_selection/src/solve/inspect/dump.rs

-5
This file was deleted.

Diff for: compiler/rustc_trait_selection/src/solve/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ mod search_graph;
3333
mod trait_goals;
3434
mod weak_types;
3535

36-
pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt, InferCtxtSelectExt};
36+
pub use eval_ctxt::{
37+
DisableGlobalCache, EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt,
38+
};
3739
pub use fulfill::FulfillmentCtxt;
3840
pub(crate) use normalize::deeply_normalize;
3941

Diff for: compiler/rustc_trait_selection/src/solve/search_graph/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_middle::traits::solve::{CanonicalInput, Certainty, MaybeCause, QueryRe
1313
use rustc_middle::ty::TyCtxt;
1414
use std::{collections::hash_map::Entry, mem};
1515

16+
use super::eval_ctxt::DisableGlobalCache;
1617
use super::inspect::ProofTreeBuilder;
1718
use super::SolverMode;
1819

@@ -213,7 +214,9 @@ impl<'tcx> SearchGraph<'tcx> {
213214
inspect: &mut ProofTreeBuilder<'tcx>,
214215
mut loop_body: impl FnMut(&mut Self, &mut ProofTreeBuilder<'tcx>) -> QueryResult<'tcx>,
215216
) -> QueryResult<'tcx> {
216-
if self.should_use_global_cache() {
217+
if self.should_use_global_cache()
218+
&& inspect.disable_global_cache() == DisableGlobalCache::No
219+
{
217220
if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_input, tcx) {
218221
debug!(?canonical_input, ?result, "cache hit");
219222
inspect.cache_hit(CacheHit::Global);

0 commit comments

Comments
 (0)