1
Fork 0
This commit is contained in:
Boxy 2023-07-04 14:56:05 +01:00
parent 276d628cac
commit 284b61417f
7 changed files with 95 additions and 102 deletions

View file

@ -746,11 +746,11 @@ pub enum TraitSolver {
} }
#[derive(Default, Debug, Copy, Clone, Hash, PartialEq, Eq)] #[derive(Default, Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum SolverProofTreeCondition { pub enum DumpSolverProofTree {
#[default]
OnRequest,
Always, Always,
OnError, OnError,
#[default]
Never,
} }
pub enum Input { pub enum Input {

View file

@ -418,8 +418,7 @@ mod desc {
"a `,` separated combination of `bti`, `b-key`, `pac-ret`, or `leaf`"; "a `,` separated combination of `bti`, `b-key`, `pac-ret`, or `leaf`";
pub const parse_proc_macro_execution_strategy: &str = pub const parse_proc_macro_execution_strategy: &str =
"one of supported execution strategies (`same-thread`, or `cross-thread`)"; "one of supported execution strategies (`same-thread`, or `cross-thread`)";
pub const parse_solver_proof_tree_condition: &str = pub const parse_dump_solver_proof_tree: &str = "one of: `always`, `on-request`, `on-error`";
"one of: `always`, `on-request`, `on-error`";
} }
mod parse { mod parse {
@ -1241,14 +1240,14 @@ mod parse {
true true
} }
pub(crate) fn parse_solver_proof_tree_condition( pub(crate) fn parse_dump_solver_proof_tree(
slot: &mut SolverProofTreeCondition, slot: &mut DumpSolverProofTree,
v: Option<&str>, v: Option<&str>,
) -> bool { ) -> bool {
match v { match v {
None | Some("always") => *slot = SolverProofTreeCondition::Always, None | Some("always") => *slot = DumpSolverProofTree::Always,
Some("on-request") => *slot = SolverProofTreeCondition::OnRequest, Some("never") => *slot = DumpSolverProofTree::Never,
Some("on-error") => *slot = SolverProofTreeCondition::OnError, Some("on-error") => *slot = DumpSolverProofTree::OnError,
_ => return false, _ => return false,
}; };
true true
@ -1478,11 +1477,11 @@ options! {
"output statistics about monomorphization collection"), "output statistics about monomorphization collection"),
dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED], dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED],
"the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"), "the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"),
dump_solver_proof_tree: SolverProofTreeCondition = (SolverProofTreeCondition::OnRequest, parse_solver_proof_tree_condition, [UNTRACKED], dump_solver_proof_tree: DumpSolverProofTree = (DumpSolverProofTree::Never, parse_dump_solver_proof_tree, [UNTRACKED],
"dump a proof tree for every goal evaluated by the new trait solver. If the flag is specified without any options after it "dump a proof tree for every goal evaluated by the new trait solver. If the flag is specified without any options after it
then it defaults to `always`. If the flag is not specified at all it defaults to `on-request`."), then it defaults to `always`. If the flag is not specified at all it defaults to `on-request`."),
dump_solver_proof_tree_use_cache: Option<bool> = (None, parse_opt_bool, [UNTRACKED], dump_solver_proof_tree_use_cache: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
"determines whether proof tree generation uses the global cache"), "determines whether dumped proof trees use the global cache"),
dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED], dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
dylib_lto: bool = (false, parse_bool, [UNTRACKED], dylib_lto: bool = (false, parse_bool, [UNTRACKED],

View file

@ -19,7 +19,7 @@ use rustc_middle::ty::{
self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt, TypeVisitor, TypeVisitableExt, TypeVisitor,
}; };
use rustc_session::config::SolverProofTreeCondition; use rustc_session::config::DumpSolverProofTree;
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
use std::io::Write; use std::io::Write;
use std::ops::ControlFlow; use std::ops::ControlFlow;
@ -115,20 +115,20 @@ impl NestedGoals<'_> {
#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)] #[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
pub enum GenerateProofTree { pub enum GenerateProofTree {
Yes(DisableGlobalCache), Yes(UseGlobalCache),
No, No,
} }
#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)] #[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
pub enum DisableGlobalCache { pub enum UseGlobalCache {
Yes, Yes,
No, No,
} }
impl DisableGlobalCache { impl UseGlobalCache {
pub fn from_bool(disable_cache: bool) -> Self { pub fn from_bool(use_cache: bool) -> Self {
match disable_cache { match use_cache {
true => DisableGlobalCache::Yes, true => UseGlobalCache::Yes,
false => DisableGlobalCache::No, false => UseGlobalCache::No,
} }
} }
} }
@ -198,7 +198,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
let result = f(&mut ecx); let result = f(&mut ecx);
let tree = ecx.inspect.finalize(); let tree = ecx.inspect.finalize();
if let (Some(tree), SolverProofTreeCondition::Always) = if let (Some(tree), DumpSolverProofTree::Always) =
(&tree, infcx.tcx.sess.opts.unstable_opts.dump_solver_proof_tree) (&tree, infcx.tcx.sess.opts.unstable_opts.dump_solver_proof_tree)
{ {
let mut lock = std::io::stdout().lock(); let mut lock = std::io::stdout().lock();

View file

@ -4,9 +4,9 @@ use rustc_middle::traits::solve::{
CanonicalInput, Certainty, Goal, IsNormalizesToHack, QueryInput, QueryResult, CanonicalInput, Certainty, Goal, IsNormalizesToHack, QueryInput, QueryResult,
}; };
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, TyCtxt};
use rustc_session::config::SolverProofTreeCondition; use rustc_session::config::DumpSolverProofTree;
use super::eval_ctxt::DisableGlobalCache; use super::eval_ctxt::UseGlobalCache;
use super::GenerateProofTree; use super::GenerateProofTree;
#[derive(Eq, PartialEq, Debug, Hash, HashStable)] #[derive(Eq, PartialEq, Debug, Hash, HashStable)]
@ -146,24 +146,42 @@ impl<'tcx> From<WipGoalCandidate<'tcx>> for DebugSolver<'tcx> {
} }
pub struct ProofTreeBuilder<'tcx> { pub struct ProofTreeBuilder<'tcx> {
state: Option<Box<DebugSolver<'tcx>>>, state: Option<Box<BuilderData<'tcx>>>,
disable_global_cache: DisableGlobalCache, }
struct BuilderData<'tcx> {
tree: DebugSolver<'tcx>,
use_global_cache: UseGlobalCache,
} }
impl<'tcx> ProofTreeBuilder<'tcx> { impl<'tcx> ProofTreeBuilder<'tcx> {
fn new( fn new(
state: impl Into<DebugSolver<'tcx>>, state: impl Into<DebugSolver<'tcx>>,
disable_global_cache: DisableGlobalCache, use_global_cache: UseGlobalCache,
) -> ProofTreeBuilder<'tcx> { ) -> ProofTreeBuilder<'tcx> {
ProofTreeBuilder { state: Some(Box::new(state.into())), disable_global_cache } ProofTreeBuilder {
state: Some(Box::new(BuilderData { tree: state.into(), use_global_cache })),
}
}
fn nested(&self, state: impl Into<DebugSolver<'tcx>>) -> Self {
match &self.state {
Some(prev_state) => Self {
state: Some(Box::new(BuilderData {
tree: state.into(),
use_global_cache: prev_state.use_global_cache,
})),
},
None => Self { state: None },
}
} }
fn as_mut(&mut self) -> Option<&mut DebugSolver<'tcx>> { fn as_mut(&mut self) -> Option<&mut DebugSolver<'tcx>> {
self.state.as_mut().map(|boxed| &mut **boxed) self.state.as_mut().map(|boxed| &mut boxed.tree)
} }
pub fn finalize(self) -> Option<inspect::GoalEvaluation<'tcx>> { pub fn finalize(self) -> Option<inspect::GoalEvaluation<'tcx>> {
match *(self.state?) { match self.state?.tree {
DebugSolver::GoalEvaluation(wip_goal_evaluation) => { DebugSolver::GoalEvaluation(wip_goal_evaluation) => {
Some(wip_goal_evaluation.finalize()) Some(wip_goal_evaluation.finalize())
} }
@ -171,8 +189,11 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
} }
} }
pub fn disable_global_cache(&self) -> DisableGlobalCache { pub fn use_global_cache(&self) -> bool {
self.disable_global_cache self.state
.as_ref()
.map(|state| matches!(state.use_global_cache, UseGlobalCache::Yes))
.unwrap_or(true)
} }
pub fn new_maybe_root( pub fn new_maybe_root(
@ -185,17 +206,17 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
generate_proof_tree, generate_proof_tree,
) { ) {
(_, Some(use_cache), GenerateProofTree::Yes(_)) => { (_, Some(use_cache), GenerateProofTree::Yes(_)) => {
GenerateProofTree::Yes(DisableGlobalCache::from_bool(!use_cache)) GenerateProofTree::Yes(UseGlobalCache::from_bool(use_cache))
} }
(SolverProofTreeCondition::Always, use_cache, GenerateProofTree::No) => { (DumpSolverProofTree::Always, use_cache, GenerateProofTree::No) => {
let use_cache = use_cache.unwrap_or(true); let use_cache = use_cache.unwrap_or(true);
GenerateProofTree::Yes(DisableGlobalCache::from_bool(!use_cache)) GenerateProofTree::Yes(UseGlobalCache::from_bool(use_cache))
} }
(_, None, GenerateProofTree::Yes(_)) => generate_proof_tree, (_, None, GenerateProofTree::Yes(_)) => generate_proof_tree,
(SolverProofTreeCondition::OnRequest, _, _) => generate_proof_tree, (DumpSolverProofTree::Never, _, _) => generate_proof_tree,
(SolverProofTreeCondition::OnError, _, _) => generate_proof_tree, (DumpSolverProofTree::OnError, _, _) => generate_proof_tree,
}; };
match generate_proof_tree { match generate_proof_tree {
@ -206,12 +227,12 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
} }
} }
pub fn new_root(disable_global_cache: DisableGlobalCache) -> ProofTreeBuilder<'tcx> { pub fn new_root(use_global_cache: UseGlobalCache) -> ProofTreeBuilder<'tcx> {
ProofTreeBuilder::new(DebugSolver::Root, disable_global_cache) ProofTreeBuilder::new(DebugSolver::Root, use_global_cache)
} }
pub fn new_noop() -> ProofTreeBuilder<'tcx> { pub fn new_noop() -> ProofTreeBuilder<'tcx> {
ProofTreeBuilder { state: None, disable_global_cache: DisableGlobalCache::No } ProofTreeBuilder { state: None }
} }
pub fn is_noop(&self) -> bool { pub fn is_noop(&self) -> bool {
@ -224,24 +245,18 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
is_normalizes_to_hack: IsNormalizesToHack, is_normalizes_to_hack: IsNormalizesToHack,
) -> ProofTreeBuilder<'tcx> { ) -> ProofTreeBuilder<'tcx> {
if self.state.is_none() { if self.state.is_none() {
return ProofTreeBuilder { return ProofTreeBuilder { state: None };
state: None,
disable_global_cache: self.disable_global_cache,
};
} }
ProofTreeBuilder::new( self.nested(WipGoalEvaluation {
WipGoalEvaluation { uncanonicalized_goal: goal,
uncanonicalized_goal: goal, canonicalized_goal: None,
canonicalized_goal: None, evaluation_steps: vec![],
evaluation_steps: vec![], is_normalizes_to_hack,
is_normalizes_to_hack, cache_hit: None,
cache_hit: None, returned_goals: vec![],
returned_goals: vec![], result: None,
result: None, })
},
self.disable_global_cache,
)
} }
pub fn canonicalized_goal(&mut self, canonical_goal: CanonicalInput<'tcx>) { pub fn canonicalized_goal(&mut self, canonical_goal: CanonicalInput<'tcx>) {
@ -279,7 +294,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
} }
pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) { pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) {
if let Some(this) = self.as_mut() { if let Some(this) = self.as_mut() {
match (this, *goal_evaluation.state.unwrap()) { match (this, goal_evaluation.state.unwrap().tree) {
( (
DebugSolver::AddedGoalsEvaluation(WipAddedGoalsEvaluation { DebugSolver::AddedGoalsEvaluation(WipAddedGoalsEvaluation {
evaluations, .. evaluations, ..
@ -297,25 +312,19 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
) -> ProofTreeBuilder<'tcx> { ) -> ProofTreeBuilder<'tcx> {
if self.state.is_none() { if self.state.is_none() {
return ProofTreeBuilder { return ProofTreeBuilder { state: None };
state: None,
disable_global_cache: self.disable_global_cache,
};
} }
ProofTreeBuilder::new( self.nested(WipGoalEvaluationStep {
WipGoalEvaluationStep { instantiated_goal,
instantiated_goal, nested_goal_evaluations: vec![],
nested_goal_evaluations: vec![], candidates: vec![],
candidates: vec![], result: None,
result: None, })
},
self.disable_global_cache,
)
} }
pub fn goal_evaluation_step(&mut self, goal_eval_step: ProofTreeBuilder<'tcx>) { pub fn goal_evaluation_step(&mut self, goal_eval_step: ProofTreeBuilder<'tcx>) {
if let Some(this) = self.as_mut() { if let Some(this) = self.as_mut() {
match (this, *goal_eval_step.state.unwrap()) { match (this, goal_eval_step.state.unwrap().tree) {
(DebugSolver::GoalEvaluation(goal_eval), DebugSolver::GoalEvaluationStep(step)) => { (DebugSolver::GoalEvaluation(goal_eval), DebugSolver::GoalEvaluationStep(step)) => {
goal_eval.evaluation_steps.push(step); goal_eval.evaluation_steps.push(step);
} }
@ -326,17 +335,14 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
pub fn new_goal_candidate(&mut self) -> ProofTreeBuilder<'tcx> { pub fn new_goal_candidate(&mut self) -> ProofTreeBuilder<'tcx> {
if self.state.is_none() { if self.state.is_none() {
return ProofTreeBuilder { return ProofTreeBuilder { state: None };
state: None,
disable_global_cache: self.disable_global_cache,
};
} }
ProofTreeBuilder::new( self.nested(WipGoalCandidate {
WipGoalCandidate { nested_goal_evaluations: vec![], candidates: vec![], kind: None }, nested_goal_evaluations: vec![],
self.disable_global_cache, candidates: vec![],
) kind: None,
})
} }
pub fn candidate_kind(&mut self, candidate_kind: CandidateKind<'tcx>) { pub fn candidate_kind(&mut self, candidate_kind: CandidateKind<'tcx>) {
@ -352,7 +358,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
pub fn goal_candidate(&mut self, candidate: ProofTreeBuilder<'tcx>) { pub fn goal_candidate(&mut self, candidate: ProofTreeBuilder<'tcx>) {
if let Some(this) = self.as_mut() { if let Some(this) = self.as_mut() {
match (this, *candidate.state.unwrap()) { match (this, candidate.state.unwrap().tree) {
( (
DebugSolver::GoalCandidate(WipGoalCandidate { candidates, .. }) DebugSolver::GoalCandidate(WipGoalCandidate { candidates, .. })
| DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { candidates, .. }), | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { candidates, .. }),
@ -365,17 +371,10 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
pub fn new_evaluate_added_goals(&mut self) -> ProofTreeBuilder<'tcx> { pub fn new_evaluate_added_goals(&mut self) -> ProofTreeBuilder<'tcx> {
if self.state.is_none() { if self.state.is_none() {
return ProofTreeBuilder { return ProofTreeBuilder { state: None };
state: None,
disable_global_cache: self.disable_global_cache,
};
} }
ProofTreeBuilder::new( self.nested(WipAddedGoalsEvaluation { evaluations: vec![], result: None })
WipAddedGoalsEvaluation { evaluations: vec![], result: None },
self.disable_global_cache,
)
} }
pub fn evaluate_added_goals_loop_start(&mut self) { pub fn evaluate_added_goals_loop_start(&mut self) {
@ -402,7 +401,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
pub fn added_goals_evaluation(&mut self, goals_evaluation: ProofTreeBuilder<'tcx>) { pub fn added_goals_evaluation(&mut self, goals_evaluation: ProofTreeBuilder<'tcx>) {
if let Some(this) = self.as_mut() { if let Some(this) = self.as_mut() {
match (this, *goals_evaluation.state.unwrap()) { match (this, goals_evaluation.state.unwrap().tree) {
( (
DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep {
nested_goal_evaluations, nested_goal_evaluations,

View file

@ -34,7 +34,7 @@ mod trait_goals;
mod weak_types; mod weak_types;
pub use eval_ctxt::{ pub use eval_ctxt::{
DisableGlobalCache, EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt, EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt, UseGlobalCache,
}; };
pub use fulfill::FulfillmentCtxt; pub use fulfill::FulfillmentCtxt;
pub(crate) use normalize::deeply_normalize; pub(crate) use normalize::deeply_normalize;

View file

@ -13,7 +13,6 @@ use rustc_middle::traits::solve::{CanonicalInput, Certainty, MaybeCause, QueryRe
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use std::{collections::hash_map::Entry, mem}; use std::{collections::hash_map::Entry, mem};
use super::eval_ctxt::DisableGlobalCache;
use super::inspect::ProofTreeBuilder; use super::inspect::ProofTreeBuilder;
use super::SolverMode; use super::SolverMode;
@ -214,9 +213,7 @@ impl<'tcx> SearchGraph<'tcx> {
inspect: &mut ProofTreeBuilder<'tcx>, inspect: &mut ProofTreeBuilder<'tcx>,
mut loop_body: impl FnMut(&mut Self, &mut ProofTreeBuilder<'tcx>) -> QueryResult<'tcx>, mut loop_body: impl FnMut(&mut Self, &mut ProofTreeBuilder<'tcx>) -> QueryResult<'tcx>,
) -> QueryResult<'tcx> { ) -> QueryResult<'tcx> {
if self.should_use_global_cache() if self.should_use_global_cache() && inspect.use_global_cache() {
&& inspect.disable_global_cache() == DisableGlobalCache::No
{
if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_input, tcx) { if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_input, tcx) {
debug!(?canonical_input, ?result, "cache hit"); debug!(?canonical_input, ?result, "cache hit");
inspect.cache_hit(CacheHit::Global); inspect.cache_hit(CacheHit::Global);

View file

@ -10,7 +10,7 @@ use super::{
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{self, InferCtxt}; use crate::infer::{self, InferCtxt};
use crate::solve::{DisableGlobalCache, GenerateProofTree, InferCtxtEvalExt}; use crate::solve::{GenerateProofTree, InferCtxtEvalExt, UseGlobalCache};
use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::query::normalize::QueryNormalizeExt as _; use crate::traits::query::normalize::QueryNormalizeExt as _;
use crate::traits::specialize::to_pretty_impl_header; use crate::traits::specialize::to_pretty_impl_header;
@ -39,7 +39,7 @@ use rustc_middle::ty::{
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
TypeVisitable, TypeVisitableExt, TypeVisitable, TypeVisitableExt,
}; };
use rustc_session::config::{SolverProofTreeCondition, TraitSolver}; use rustc_session::config::{DumpSolverProofTree, TraitSolver};
use rustc_session::Limit; use rustc_session::Limit;
use rustc_span::def_id::LOCAL_CRATE; use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
@ -634,7 +634,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
) { ) {
let tcx = self.tcx; let tcx = self.tcx;
if tcx.sess.opts.unstable_opts.dump_solver_proof_tree == SolverProofTreeCondition::OnError { if tcx.sess.opts.unstable_opts.dump_solver_proof_tree == DumpSolverProofTree::OnError {
dump_proof_tree(root_obligation, self.infcx); dump_proof_tree(root_obligation, self.infcx);
} }
@ -1537,9 +1537,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) { fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) {
if self.tcx.sess.opts.unstable_opts.dump_solver_proof_tree if self.tcx.sess.opts.unstable_opts.dump_solver_proof_tree == DumpSolverProofTree::OnError {
== SolverProofTreeCondition::OnError
{
dump_proof_tree(&error.root_obligation, self.infcx); dump_proof_tree(&error.root_obligation, self.infcx);
} }
@ -3518,7 +3516,7 @@ pub fn dump_proof_tree<'tcx>(o: &Obligation<'tcx, ty::Predicate<'tcx>>, infcx: &
infcx.probe(|_| { infcx.probe(|_| {
let goal = Goal { predicate: o.predicate, param_env: o.param_env }; let goal = Goal { predicate: o.predicate, param_env: o.param_env };
let tree = infcx let tree = infcx
.evaluate_root_goal(goal, GenerateProofTree::Yes(DisableGlobalCache::Yes)) .evaluate_root_goal(goal, GenerateProofTree::Yes(UseGlobalCache::No))
.1 .1
.expect("proof tree should have been generated"); .expect("proof tree should have been generated");
let mut lock = std::io::stdout().lock(); let mut lock = std::io::stdout().lock();