Skip to content

Commit 81e7a07

Browse files
committed
add rustc_filter_proof_tree_dump attribute
1 parent df5c2cf commit 81e7a07

File tree

6 files changed

+96
-41
lines changed

6 files changed

+96
-41
lines changed

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
795795
rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing,
796796
r#"`rustc_doc_primitive` is a rustc internal attribute"#,
797797
),
798+
rustc_attr!(
799+
rustc_filter_proof_tree_dump, Normal, template!(List: "filter1, filter2, ..."), DuplicatesOk,
800+
"the `#[rustc_filter_proof_tree_dump(...)]` attribute is used to filter out proof trees \
801+
from `-Zdump-solver-proof-tree` output.",
802+
),
798803

799804
// ==========================================================================
800805
// 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
@@ -1286,6 +1286,7 @@ symbols! {
12861286
rustc_error,
12871287
rustc_evaluate_where_clauses,
12881288
rustc_expected_cgu_reuse,
1289+
rustc_filter_proof_tree_dump,
12891290
rustc_has_incoherent_inherent_impls,
12901291
rustc_host,
12911292
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
@@ -41,46 +41,51 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
4141
self.instantiate_binder_with_placeholders(obligation.predicate),
4242
);
4343

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

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

82-
Ok(Some((candidate, certainty, nested_goals)))
83-
});
86+
Ok(Some((candidate, certainty, nested_goals)))
87+
},
88+
);
8489

8590
let (candidate, certainty, nested_goals) = match result {
8691
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`.

0 commit comments

Comments
 (0)