Skip to content

Commit 1b48947

Browse files
authored
Rollup merge of rust-lang#113694 - BoxyUwU:proof_tree_dump_filtering, r=compiler-errors
Allow filtering what proof trees are dumped to stdout via a rustc attr Adds a `#![rustc_filter_proof_tree_dump("...")]` attribute that can be placed on the crate root to filter the output of `-Zdump-solver-proof-tree=always`. It works by only generating proof trees if the debug output of the root goal's predicate is the same as the string. It doesn't feel ideal although I wasn't sure how else to make something like this work- actually trying to parse goal syntax seemed far harder. Ideally this would also work for `=on_error` but i haven't made that work yet. I was hoping this could be used to generate proof trees in ui tests but the output still seems kinda huge and its not deduplicated at all (the stdout file i commited literaly has the exact same proof tree Twice...) I'm not sure its actually worth adding `-Zdump-solver-proof-tree` to ui tests yet.
2 parents d842ef2 + 85bfe07 commit 1b48947

File tree

8 files changed

+199
-41
lines changed

8 files changed

+199
-41
lines changed

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
801801
rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing,
802802
r#"`rustc_doc_primitive` is a rustc internal attribute"#,
803803
),
804+
rustc_attr!(
805+
rustc_filter_proof_tree_dump, Normal, template!(List: "filter1, filter2, ..."), DuplicatesOk,
806+
"the `#[rustc_filter_proof_tree_dump(...)]` attribute is used to filter out proof trees \
807+
from `-Zdump-solver-proof-tree` output.",
808+
),
804809

805810
// ==========================================================================
806811
// Internal attributes, Testing:

compiler/rustc_span/src/def_id.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ pub struct LocalDefId {
388388
impl !Ord for LocalDefId {}
389389
impl !PartialOrd for LocalDefId {}
390390

391+
/// The [`DefId`] for the local crate root.
391392
pub const CRATE_DEF_ID: LocalDefId = LocalDefId { local_def_index: CRATE_DEF_INDEX };
392393

393394
impl Idx for LocalDefId {

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,6 +1287,7 @@ symbols! {
12871287
rustc_error,
12881288
rustc_evaluate_where_clauses,
12891289
rustc_expected_cgu_reuse,
1290+
rustc_filter_proof_tree_dump,
12901291
rustc_has_incoherent_inherent_impls,
12911292
rustc_host,
12921293
rustc_if_this_changed,

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,12 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
159159
Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
160160
Option<inspect::GoalEvaluation<'tcx>>,
161161
) {
162-
EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
163-
ecx.evaluate_goal(IsNormalizesToHack::No, goal)
164-
})
162+
EvalCtxt::enter_root(
163+
self,
164+
generate_proof_tree,
165+
|| format!("{:?}", goal.predicate),
166+
|ecx| ecx.evaluate_goal(IsNormalizesToHack::No, goal),
167+
)
165168
}
166169
}
167170

@@ -176,6 +179,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
176179
fn enter_root<R>(
177180
infcx: &InferCtxt<'tcx>,
178181
generate_proof_tree: GenerateProofTree,
182+
filter: impl FnOnce() -> String,
179183
f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R,
180184
) -> (R, Option<inspect::GoalEvaluation<'tcx>>) {
181185
let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
@@ -194,7 +198,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
194198
var_values: CanonicalVarValues::dummy(),
195199
nested_goals: NestedGoals::new(),
196200
tainted: Ok(()),
197-
inspect: ProofTreeBuilder::new_maybe_root(infcx.tcx, generate_proof_tree),
201+
inspect: ProofTreeBuilder::new_maybe_root(infcx.tcx, generate_proof_tree, filter),
198202
};
199203
let result = f(&mut ecx);
200204

compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -43,46 +43,51 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
4343
self.instantiate_binder_with_placeholders(obligation.predicate),
4444
);
4545

46-
let (result, _) = EvalCtxt::enter_root(self, GenerateProofTree::Never, |ecx| {
47-
let goal = Goal::new(ecx.tcx(), trait_goal.param_env, trait_goal.predicate);
48-
let (orig_values, canonical_goal) = ecx.canonicalize_goal(goal);
49-
let mut candidates = ecx.compute_canonical_trait_candidates(canonical_goal);
50-
51-
// pseudo-winnow
52-
if candidates.len() == 0 {
53-
return Err(SelectionError::Unimplemented);
54-
} else if candidates.len() > 1 {
55-
let mut i = 0;
56-
while i < candidates.len() {
57-
let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| {
58-
candidate_should_be_dropped_in_favor_of(
59-
ecx.tcx(),
60-
&candidates[i],
61-
&candidates[j],
62-
)
63-
});
64-
if should_drop_i {
65-
candidates.swap_remove(i);
66-
} else {
67-
i += 1;
68-
if i > 1 {
69-
return Ok(None);
46+
let (result, _) = EvalCtxt::enter_root(
47+
self,
48+
GenerateProofTree::Never,
49+
|| unreachable!("proof trees cannot be generated for selection"),
50+
|ecx| {
51+
let goal = Goal::new(ecx.tcx(), trait_goal.param_env, trait_goal.predicate);
52+
let (orig_values, canonical_goal) = ecx.canonicalize_goal(goal);
53+
let mut candidates = ecx.compute_canonical_trait_candidates(canonical_goal);
54+
55+
// pseudo-winnow
56+
if candidates.len() == 0 {
57+
return Err(SelectionError::Unimplemented);
58+
} else if candidates.len() > 1 {
59+
let mut i = 0;
60+
while i < candidates.len() {
61+
let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| {
62+
candidate_should_be_dropped_in_favor_of(
63+
ecx.tcx(),
64+
&candidates[i],
65+
&candidates[j],
66+
)
67+
});
68+
if should_drop_i {
69+
candidates.swap_remove(i);
70+
} else {
71+
i += 1;
72+
if i > 1 {
73+
return Ok(None);
74+
}
7075
}
7176
}
7277
}
73-
}
7478

75-
let candidate = candidates.pop().unwrap();
76-
let (certainty, nested_goals) = ecx
77-
.instantiate_and_apply_query_response(
78-
trait_goal.param_env,
79-
orig_values,
80-
candidate.result,
81-
)
82-
.map_err(|_| SelectionError::Unimplemented)?;
79+
let candidate = candidates.pop().unwrap();
80+
let (certainty, nested_goals) = ecx
81+
.instantiate_and_apply_query_response(
82+
trait_goal.param_env,
83+
orig_values,
84+
candidate.result,
85+
)
86+
.map_err(|_| SelectionError::Unimplemented)?;
8387

84-
Ok(Some((candidate, certainty, nested_goals)))
85-
});
88+
Ok(Some((candidate, certainty, nested_goals)))
89+
},
90+
);
8691

8792
let (candidate, certainty, nested_goals) = match result {
8893
Ok(Some((candidate, certainty, nested_goals))) => (candidate, certainty, nested_goals),

compiler/rustc_trait_selection/src/solve/inspect.rs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use rustc_middle::traits::solve::{
55
};
66
use rustc_middle::ty::{self, TyCtxt};
77
use rustc_session::config::DumpSolverProofTree;
8+
use rustc_span::def_id::CRATE_DEF_ID;
89

910
use super::eval_ctxt::UseGlobalCache;
1011
use super::GenerateProofTree;
@@ -199,15 +200,53 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
199200
pub fn new_maybe_root(
200201
tcx: TyCtxt<'tcx>,
201202
generate_proof_tree: GenerateProofTree,
203+
filter: impl FnOnce() -> String,
202204
) -> ProofTreeBuilder<'tcx> {
203205
match generate_proof_tree {
204206
GenerateProofTree::Never => ProofTreeBuilder::new_noop(),
205207
GenerateProofTree::IfEnabled => {
206208
let opts = &tcx.sess.opts.unstable_opts;
207209
match opts.dump_solver_proof_tree {
208210
DumpSolverProofTree::Always => {
209-
let use_cache = opts.dump_solver_proof_tree_use_cache.unwrap_or(true);
210-
ProofTreeBuilder::new_root(UseGlobalCache::from_bool(use_cache))
211+
let should_generate = if tcx
212+
.get_attrs(CRATE_DEF_ID, rustc_span::sym::rustc_filter_proof_tree_dump)
213+
.next()
214+
.is_some()
215+
{
216+
// dont do the filtering behaviour if there are no attributes anywhere
217+
let goal = filter();
218+
tcx
219+
.get_attrs(CRATE_DEF_ID, rustc_span::sym::rustc_filter_proof_tree_dump)
220+
.flat_map(|attr| {
221+
let meta = attr.meta_kind().unwrap();
222+
match meta {
223+
rustc_ast::MetaItemKind::Word
224+
| rustc_ast::MetaItemKind::NameValue(_) => {
225+
bug!("wrong attribute kind for `rustc_filter_proof_tree_dump`")
226+
}
227+
rustc_ast::MetaItemKind::List(nested_meta) => {
228+
nested_meta.into_iter().map(|nested_meta| {
229+
match nested_meta {
230+
rustc_ast::NestedMetaItem::MetaItem(_) => unreachable!("only string literals are supported in `rustc_filter_proof_tree_dump`"),
231+
rustc_ast::NestedMetaItem::Lit(lit) => match lit.kind {
232+
rustc_ast::LitKind::Str(sym, _) => sym,
233+
_ => unreachable!("only string literals are supported in `rustc_filter_proof_tree_dump`"),
234+
},
235+
}
236+
})
237+
}
238+
}
239+
}).any(|sym| goal.as_str() == sym.as_str())
240+
} else {
241+
true
242+
};
243+
244+
if should_generate {
245+
let use_cache = opts.dump_solver_proof_tree_use_cache.unwrap_or(true);
246+
ProofTreeBuilder::new_root(UseGlobalCache::from_bool(use_cache))
247+
} else {
248+
ProofTreeBuilder::new_noop()
249+
}
211250
}
212251
// `OnError` is handled by reevaluating goals in error
213252
// reporting with `GenerateProofTree::Yes`.

tests/ui/traits/new-solver/alias_eq_simple.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
// check-pass
22
// compile-flags: -Ztrait-solver=next
3+
// compile-flags: -Zdump-solver-proof-tree=always
4+
// compile-flags: -Zdump-solver-proof-tree-use-cache=no
5+
6+
#![feature(rustc_attrs)]
7+
#![rustc_filter_proof_tree_dump(
8+
"Binder { value: TraitPredicate(<(i32, u32) as TraitA>, polarity:Positive), bound_vars: [] }"
9+
)]
310

411
// test that the new solver can handle `alias-eq(<i32 as TraitB>::Assoc, u32)`
512

0 commit comments

Comments
 (0)