1use std::assert_matches;
13
14use rustc_infer::infer::InferCtxt;
15use rustc_macros::extension;
16use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult};
17use rustc_middle::ty::{TyCtxt, VisitorResult, try_visit};
18use rustc_middle::{bug, ty};
19use rustc_next_trait_solver::canonical::instantiate_canonical_state;
20use rustc_next_trait_solver::resolve::eager_resolve_vars;
21use rustc_next_trait_solver::solve::{MaybeCause, MaybeInfo, SolverDelegateEvalExt as _, inspect};
22use rustc_span::Span;
23use tracing::instrument;
24
25use crate::solve::delegate::SolverDelegate;
26
27pub struct InspectConfig {
28 pub max_depth: usize,
29}
30
31pub struct InspectGoal<'a, 'tcx> {
32 infcx: &'a SolverDelegate<'tcx>,
33 depth: usize,
34 orig_values: Vec<ty::GenericArg<'tcx>>,
35 goal: Goal<'tcx, ty::Predicate<'tcx>>,
36 result: Result<Certainty, NoSolution>,
37 final_revision: &'tcx inspect::Probe<TyCtxt<'tcx>>,
38 source: GoalSource,
39}
40
41pub struct InspectCandidate<'a, 'tcx> {
42 goal: &'a InspectGoal<'a, 'tcx>,
43 kind: inspect::ProbeKind<TyCtxt<'tcx>>,
44 steps: Vec<&'a inspect::ProbeStep<TyCtxt<'tcx>>>,
45 final_state: inspect::CanonicalState<TyCtxt<'tcx>, ()>,
46 result: QueryResult<'tcx>,
47 shallow_certainty: Certainty,
48}
49
50impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
51 pub fn kind(&self) -> inspect::ProbeKind<TyCtxt<'tcx>> {
52 self.kind
53 }
54
55 pub fn result(&self) -> Result<Certainty, NoSolution> {
56 self.result.map(|c| c.value.certainty)
57 }
58
59 pub fn goal(&self) -> &'a InspectGoal<'a, 'tcx> {
60 self.goal
61 }
62
63 pub fn shallow_certainty(&self) -> Certainty {
72 self.shallow_certainty
73 }
74
75 pub fn visit_nested_no_probe<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {
79 for goal in self.instantiate_nested_goals(visitor.span()) {
80 match ::rustc_ast_ir::visit::VisitorResult::branch(goal.visit_with(visitor)) {
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(goal.visit_with(visitor));
81 }
82
83 V::Result::output()
84 }
85
86 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("instantiate_nested_goals",
"rustc_trait_selection::solve::inspect::analyse",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/solve/inspect/analyse.rs"),
::tracing_core::__macro_support::Option::Some(90u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::solve::inspect::analyse"),
::tracing_core::field::FieldSet::new(&["goal", "steps"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&self.goal.goal)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&self.steps)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: Vec<InspectGoal<'a, 'tcx>> =
loop {};
return __tracing_attr_fake_return;
}
{
let infcx = self.goal.infcx;
let param_env = self.goal.goal.param_env;
let mut orig_values = self.goal.orig_values.clone();
let mut instantiated_goals = ::alloc::vec::Vec::new();
for step in &self.steps {
match **step {
inspect::ProbeStep::AddGoal(source, goal) =>
instantiated_goals.push((source,
instantiate_canonical_state(infcx, span, param_env,
&mut orig_values, goal))),
inspect::ProbeStep::RecordImplArgs { .. } => {}
inspect::ProbeStep::MakeCanonicalResponse { .. } |
inspect::ProbeStep::NestedProbe(_) =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
let () =
instantiate_canonical_state(infcx, span, param_env,
&mut orig_values, self.final_state);
instantiated_goals.into_iter().map(|(source, goal)|
self.instantiate_proof_tree_for_nested_goal(source, goal,
span)).collect()
}
}
}#[instrument(
91 level = "debug",
92 skip_all,
93 fields(goal = ?self.goal.goal, steps = ?self.steps)
94 )]
95 pub fn instantiate_nested_goals(&self, span: Span) -> Vec<InspectGoal<'a, 'tcx>> {
96 let infcx = self.goal.infcx;
97 let param_env = self.goal.goal.param_env;
98 let mut orig_values = self.goal.orig_values.clone();
99
100 let mut instantiated_goals = vec![];
101 for step in &self.steps {
102 match **step {
103 inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push((
104 source,
105 instantiate_canonical_state(infcx, span, param_env, &mut orig_values, goal),
106 )),
107 inspect::ProbeStep::RecordImplArgs { .. } => {}
108 inspect::ProbeStep::MakeCanonicalResponse { .. }
109 | inspect::ProbeStep::NestedProbe(_) => unreachable!(),
110 }
111 }
112
113 let () =
114 instantiate_canonical_state(infcx, span, param_env, &mut orig_values, self.final_state);
115
116 instantiated_goals
117 .into_iter()
118 .map(|(source, goal)| self.instantiate_proof_tree_for_nested_goal(source, goal, span))
119 .collect()
120 }
121
122 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("instantiate_impl_args",
"rustc_trait_selection::solve::inspect::analyse",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/solve/inspect/analyse.rs"),
::tracing_core::__macro_support::Option::Some(125u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::solve::inspect::analyse"),
::tracing_core::field::FieldSet::new(&["goal", "steps"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&self.goal.goal)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&self.steps)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: ty::GenericArgsRef<'tcx> =
loop {};
return __tracing_attr_fake_return;
}
{
let infcx = self.goal.infcx;
let param_env = self.goal.goal.param_env;
let mut orig_values = self.goal.orig_values.clone();
for step in &self.steps {
match **step {
inspect::ProbeStep::RecordImplArgs { impl_args } => {
let impl_args =
instantiate_canonical_state(infcx, span, param_env,
&mut orig_values, impl_args);
let () =
instantiate_canonical_state(infcx, span, param_env,
&mut orig_values, self.final_state);
return eager_resolve_vars(infcx, impl_args);
}
inspect::ProbeStep::AddGoal(..) => {}
inspect::ProbeStep::MakeCanonicalResponse { .. } |
inspect::ProbeStep::NestedProbe(_) =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
::rustc_middle::util::bug::bug_fmt(format_args!("expected impl args probe step for `instantiate_impl_args`"));
}
}
}#[instrument(
126 level = "debug",
127 skip_all,
128 fields(goal = ?self.goal.goal, steps = ?self.steps)
129 )]
130 pub fn instantiate_impl_args(&self, span: Span) -> ty::GenericArgsRef<'tcx> {
131 let infcx = self.goal.infcx;
132 let param_env = self.goal.goal.param_env;
133 let mut orig_values = self.goal.orig_values.clone();
134
135 for step in &self.steps {
136 match **step {
137 inspect::ProbeStep::RecordImplArgs { impl_args } => {
138 let impl_args = instantiate_canonical_state(
139 infcx,
140 span,
141 param_env,
142 &mut orig_values,
143 impl_args,
144 );
145
146 let () = instantiate_canonical_state(
147 infcx,
148 span,
149 param_env,
150 &mut orig_values,
151 self.final_state,
152 );
153
154 return eager_resolve_vars(infcx, impl_args);
155 }
156 inspect::ProbeStep::AddGoal(..) => {}
157 inspect::ProbeStep::MakeCanonicalResponse { .. }
158 | inspect::ProbeStep::NestedProbe(_) => unreachable!(),
159 }
160 }
161
162 bug!("expected impl args probe step for `instantiate_impl_args`");
163 }
164
165 pub fn instantiate_proof_tree_for_nested_goal(
166 &self,
167 source: GoalSource,
168 goal: Goal<'tcx, ty::Predicate<'tcx>>,
169 span: Span,
170 ) -> InspectGoal<'a, 'tcx> {
171 let infcx = self.goal.infcx;
172 match goal.predicate.kind().no_bound_vars() {
173 Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { .. })) => {
174 ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
176 }
177 _ => {
178 let proof_tree =
184 infcx.probe(|_| infcx.evaluate_root_goal_for_proof_tree(goal, span).1);
185 InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, source)
186 }
187 }
188 }
189
190 pub fn visit_nested_in_probe<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {
193 self.goal.infcx.probe(|_| self.visit_nested_no_probe(visitor))
194 }
195}
196
197impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
198 pub fn infcx(&self) -> &'a InferCtxt<'tcx> {
199 self.infcx
200 }
201
202 pub fn goal(&self) -> Goal<'tcx, ty::Predicate<'tcx>> {
203 self.goal
204 }
205
206 pub fn result(&self) -> Result<Certainty, NoSolution> {
207 self.result
208 }
209
210 pub fn source(&self) -> GoalSource {
211 self.source
212 }
213
214 pub fn depth(&self) -> usize {
215 self.depth
216 }
217
218 pub fn orig_values(&self) -> &[ty::GenericArg<'tcx>] {
219 &self.orig_values
220 }
221
222 fn candidates_recur(
223 &'a self,
224 candidates: &mut Vec<InspectCandidate<'a, 'tcx>>,
225 steps: &mut Vec<&'a inspect::ProbeStep<TyCtxt<'tcx>>>,
226 probe: &'a inspect::Probe<TyCtxt<'tcx>>,
227 ) {
228 let mut shallow_certainty = None;
229 for step in &probe.steps {
230 match *step {
231 inspect::ProbeStep::AddGoal(..) | inspect::ProbeStep::RecordImplArgs { .. } => {
232 steps.push(step)
233 }
234 inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
235 {
match shallow_certainty.replace(c) {
None |
Some(Certainty::Maybe(MaybeInfo {
cause: MaybeCause::Ambiguity,
opaque_types_jank: _,
stalled_on_coroutines: _ })) => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"None |\nSome(Certainty::Maybe(MaybeInfo\n{\n cause: MaybeCause::Ambiguity, opaque_types_jank: _, stalled_on_coroutines:\n _,\n}))",
::core::option::Option::None);
}
}
};assert_matches!(
236 shallow_certainty.replace(c),
237 None | Some(Certainty::Maybe(MaybeInfo {
238 cause: MaybeCause::Ambiguity,
239 opaque_types_jank: _,
240 stalled_on_coroutines: _,
241 }))
242 );
243 }
244 inspect::ProbeStep::NestedProbe(ref probe) => {
245 match probe.kind {
246 inspect::ProbeKind::ProjectionCompatibility
248 | inspect::ProbeKind::ShadowedEnvProbing => continue,
249
250 inspect::ProbeKind::NormalizedSelfTyAssembly
251 | inspect::ProbeKind::UnsizeAssembly
252 | inspect::ProbeKind::Root { .. }
253 | inspect::ProbeKind::TraitCandidate { .. }
254 | inspect::ProbeKind::OpaqueTypeStorageLookup { .. }
255 | inspect::ProbeKind::RigidAlias { .. } => {
256 let num_steps = steps.len();
260 self.candidates_recur(candidates, steps, probe);
261 steps.truncate(num_steps);
262 }
263 }
264 }
265 }
266 }
267
268 match probe.kind {
269 inspect::ProbeKind::ProjectionCompatibility
270 | inspect::ProbeKind::ShadowedEnvProbing => {
271 ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!()
272 }
273
274 inspect::ProbeKind::NormalizedSelfTyAssembly | inspect::ProbeKind::UnsizeAssembly => {}
275
276 inspect::ProbeKind::Root { result }
279 | inspect::ProbeKind::TraitCandidate { source: _, result }
280 | inspect::ProbeKind::OpaqueTypeStorageLookup { result }
281 | inspect::ProbeKind::RigidAlias { result } => {
282 if let Some(shallow_certainty) = shallow_certainty {
285 candidates.push(InspectCandidate {
286 goal: self,
287 kind: probe.kind,
288 steps: steps.clone(),
289 final_state: probe.final_state,
290 shallow_certainty,
291 result,
292 });
293 }
294 }
295 }
296 }
297
298 pub fn candidates(&'a self) -> Vec<InspectCandidate<'a, 'tcx>> {
299 let mut candidates = ::alloc::vec::Vec::new()vec![];
300 let mut nested_goals = ::alloc::vec::Vec::new()vec![];
301 self.candidates_recur(&mut candidates, &mut nested_goals, &self.final_revision);
302 candidates
303 }
304
305 pub fn unique_applicable_candidate(&'a self) -> Option<InspectCandidate<'a, 'tcx>> {
309 let mut candidates = self.candidates();
312 candidates.retain(|c| c.result().is_ok());
313 candidates.pop().filter(|_| candidates.is_empty())
314 }
315
316 fn new(
317 infcx: &'a InferCtxt<'tcx>,
318 depth: usize,
319 root: inspect::GoalEvaluation<TyCtxt<'tcx>>,
320 source: GoalSource,
321 ) -> Self {
322 let infcx = <&SolverDelegate<'tcx>>::from(infcx);
323
324 let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, final_revision, result } =
325 root;
326 let result = result.map(|ok| ok.value.certainty);
329
330 InspectGoal {
331 infcx,
332 depth,
333 orig_values,
334 goal: eager_resolve_vars(infcx, uncanonicalized_goal),
335 result,
336 final_revision,
337 source,
338 }
339 }
340
341 pub(crate) fn visit_with<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {
342 if self.depth < visitor.config().max_depth {
343 match ::rustc_ast_ir::visit::VisitorResult::branch(visitor.visit_goal(self)) {
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(visitor.visit_goal(self));
344 V::Result::output()
345 } else {
346 visitor.on_recursion_limit()
347 }
348 }
349}
350
351pub trait ProofTreeVisitor<'tcx> {
353 type Result: VisitorResult = ();
354
355 fn span(&self) -> Span;
356
357 fn config(&self) -> InspectConfig {
358 InspectConfig { max_depth: 10 }
359 }
360
361 fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> Self::Result;
362
363 fn on_recursion_limit(&mut self) -> Self::Result {
364 Self::Result::output()
365 }
366}
367
368impl<'tcx> InferCtxtProofTreeExt<'tcx> for InferCtxt<'tcx> {
fn visit_proof_tree<V: ProofTreeVisitor<'tcx>>(&self,
goal: Goal<'tcx, ty::Predicate<'tcx>>, visitor: &mut V) -> V::Result {
self.visit_proof_tree_at_depth(goal, 0, visitor)
}
fn visit_proof_tree_at_depth<V: ProofTreeVisitor<'tcx>>(&self,
goal: Goal<'tcx, ty::Predicate<'tcx>>, depth: usize, visitor: &mut V)
-> V::Result {
let (_, proof_tree) =
<&SolverDelegate<'tcx>>::from(self).evaluate_root_goal_for_proof_tree(goal,
visitor.span());
visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree,
GoalSource::Misc))
}
}#[extension(pub trait InferCtxtProofTreeExt<'tcx>)]
369impl<'tcx> InferCtxt<'tcx> {
370 fn visit_proof_tree<V: ProofTreeVisitor<'tcx>>(
371 &self,
372 goal: Goal<'tcx, ty::Predicate<'tcx>>,
373 visitor: &mut V,
374 ) -> V::Result {
375 self.visit_proof_tree_at_depth(goal, 0, visitor)
376 }
377
378 fn visit_proof_tree_at_depth<V: ProofTreeVisitor<'tcx>>(
379 &self,
380 goal: Goal<'tcx, ty::Predicate<'tcx>>,
381 depth: usize,
382 visitor: &mut V,
383 ) -> V::Result {
384 let (_, proof_tree) = <&SolverDelegate<'tcx>>::from(self)
385 .evaluate_root_goal_for_proof_tree(goal, visitor.span());
386 visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, GoalSource::Misc))
387 }
388}