Skip to main content

rustc_trait_selection/solve/inspect/
analyse.rs

1//! An infrastructure to mechanically analyse proof trees.
2//!
3//! It is unavoidable that this representation is somewhat
4//! lossy as it should hide quite a few semantically relevant things,
5//! e.g. canonicalization and the order of nested goals.
6//!
7//! @lcnr: However, a lot of the weirdness here is not strictly necessary
8//! and could be improved in the future. This is mostly good enough for
9//! coherence right now and was annoying to implement, so I am leaving it
10//! as is until we start using it for something else.
11
12use 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::{RequiredDepth, TyCtxt, VisitorResult, try_visit};
18use rustc_middle::{bug, ty};
19use rustc_next_trait_solver::canonical::instantiate_canonical_state;
20use rustc_next_trait_solver::solve::{MaybeCause, MaybeInfo, SolverDelegateEvalExt as _, inspect};
21use rustc_span::Span;
22use thin_vec::ThinVec;
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    // Record how deep we are in nested goals from the root goal.
34    depth: usize,
35    // Required depth to complete the evaluation of this goal.
36    required_depth: RequiredDepth,
37    orig_values: ThinVec<ty::GenericArg<'tcx>>,
38    prev_universe: ty::UniverseIndex,
39    goal: Goal<'tcx, ty::Predicate<'tcx>>,
40    result: Result<Certainty, NoSolution>,
41    final_revision: &'tcx inspect::Probe<TyCtxt<'tcx>>,
42    source: GoalSource,
43}
44
45pub struct InspectCandidate<'a, 'tcx> {
46    goal: &'a InspectGoal<'a, 'tcx>,
47    kind: inspect::ProbeKind<TyCtxt<'tcx>>,
48    steps: Vec<&'a inspect::ProbeStep<TyCtxt<'tcx>>>,
49    final_state: inspect::CanonicalState<TyCtxt<'tcx>, ()>,
50    result: QueryResult<'tcx>,
51    shallow_certainty: Certainty,
52}
53
54impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
55    pub fn kind(&self) -> inspect::ProbeKind<TyCtxt<'tcx>> {
56        self.kind
57    }
58
59    pub fn result(&self) -> Result<Certainty, NoSolution> {
60        self.result.map(|c| c.value.certainty)
61    }
62
63    pub fn goal(&self) -> &'a InspectGoal<'a, 'tcx> {
64        self.goal
65    }
66
67    /// Certainty passed into `evaluate_added_goals_and_make_canonical_response`.
68    ///
69    /// If this certainty is `Yes`, then we must be confident that the candidate
70    /// must hold iff it's nested goals hold. This is not true if the certainty is
71    /// `Maybe(..)`, which suggests we forced ambiguity instead.
72    ///
73    /// This is *not* the certainty of the candidate's full nested evaluation, which
74    /// can be accessed with [`Self::result`] instead.
75    pub fn shallow_certainty(&self) -> Certainty {
76        self.shallow_certainty
77    }
78
79    /// Visit all nested goals of this candidate without rolling
80    /// back their inference constraints. This function modifies
81    /// the state of the `infcx`.
82    pub fn visit_nested_no_probe<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {
83        for goal in self.instantiate_nested_goals(visitor.span()) {
84            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));
85        }
86
87        V::Result::output()
88    }
89
90    /// Instantiate the nested goals for the candidate without rolling back their
91    /// inference constraints. This function modifies the state of the `infcx`.
92    ///
93    /// See [`Self::instantiate_impl_args`] if you need the impl args too.
94    {}
#[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("/rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs"),
                                    ::tracing_core::__macro_support::Option::Some(94u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::solve::inspect::analyse"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("goal")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("goal");
                                                        NAME.as_str()
                                                    },
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("steps")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("steps");
                                                        NAME.as_str()
                                                    }], ::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};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.goal.goal)
                                                            as &dyn ::tracing::field::Value)),
                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.steps)
                                                            as &dyn ::tracing::field::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 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,
                                    self.goal.prev_universe, &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,
                    self.goal.prev_universe, &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(
95        level = "debug",
96        skip_all,
97        fields(goal = ?self.goal.goal, steps = ?self.steps)
98    )]
99    pub fn instantiate_nested_goals(&self, span: Span) -> Vec<InspectGoal<'a, 'tcx>> {
100        let infcx = self.goal.infcx;
101        let mut orig_values = self.goal.orig_values.clone();
102
103        let mut instantiated_goals = vec![];
104        for step in &self.steps {
105            match **step {
106                inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push((
107                    source,
108                    instantiate_canonical_state(
109                        infcx,
110                        span,
111                        self.goal.prev_universe,
112                        &mut orig_values,
113                        goal,
114                    ),
115                )),
116                inspect::ProbeStep::RecordImplArgs { .. } => {}
117                inspect::ProbeStep::MakeCanonicalResponse { .. }
118                | inspect::ProbeStep::NestedProbe(_) => unreachable!(),
119            }
120        }
121
122        let () = instantiate_canonical_state(
123            infcx,
124            span,
125            self.goal.prev_universe,
126            &mut orig_values,
127            self.final_state,
128        );
129
130        instantiated_goals
131            .into_iter()
132            .map(|(source, goal)| self.instantiate_proof_tree_for_nested_goal(source, goal, span))
133            .collect()
134    }
135
136    /// Instantiate the args of an impl if this candidate came from a
137    /// `CandidateSource::Impl`. This function modifies the state of the
138    /// `infcx`.
139    {}
#[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("/rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs"),
                                    ::tracing_core::__macro_support::Option::Some(139u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::solve::inspect::analyse"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("goal")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("goal");
                                                        NAME.as_str()
                                                    },
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("steps")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("steps");
                                                        NAME.as_str()
                                                    }], ::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};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.goal.goal)
                                                            as &dyn ::tracing::field::Value)),
                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.steps)
                                                            as &dyn ::tracing::field::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;
        }
        {
            use rustc_middle::ty::InferCtxtLike;
            let infcx = self.goal.infcx;
            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,
                                self.goal.prev_universe, &mut orig_values, impl_args);
                        let () =
                            instantiate_canonical_state(infcx, span,
                                self.goal.prev_universe, &mut orig_values,
                                self.final_state);

                        #[allow(rustc::usage_of_type_ir_traits)]
                        return infcx.deeply_resolve_via_unification_table(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(
140        level = "debug",
141        skip_all,
142        fields(goal = ?self.goal.goal, steps = ?self.steps)
143    )]
144    pub fn instantiate_impl_args(&self, span: Span) -> ty::GenericArgsRef<'tcx> {
145        use rustc_middle::ty::InferCtxtLike;
146
147        let infcx = self.goal.infcx;
148        let mut orig_values = self.goal.orig_values.clone();
149
150        for step in &self.steps {
151            match **step {
152                inspect::ProbeStep::RecordImplArgs { impl_args } => {
153                    let impl_args = instantiate_canonical_state(
154                        infcx,
155                        span,
156                        self.goal.prev_universe,
157                        &mut orig_values,
158                        impl_args,
159                    );
160
161                    let () = instantiate_canonical_state(
162                        infcx,
163                        span,
164                        self.goal.prev_universe,
165                        &mut orig_values,
166                        self.final_state,
167                    );
168
169                    // We *want* this folder to live in `rustc_type_ir`. Our best way to call into it is
170                    // through `InferCtxtLike` and it is not defined as an inherent method on `InferCtxt`.
171                    #[allow(rustc::usage_of_type_ir_traits)]
172                    return infcx.deeply_resolve_via_unification_table(impl_args);
173                }
174                inspect::ProbeStep::AddGoal(..) => {}
175                inspect::ProbeStep::MakeCanonicalResponse { .. }
176                | inspect::ProbeStep::NestedProbe(_) => unreachable!(),
177            }
178        }
179
180        bug!("expected impl args probe step for `instantiate_impl_args`");
181    }
182
183    pub fn instantiate_proof_tree_for_nested_goal(
184        &self,
185        source: GoalSource,
186        goal: Goal<'tcx, ty::Predicate<'tcx>>,
187        span: Span,
188    ) -> InspectGoal<'a, 'tcx> {
189        let infcx = self.goal.infcx;
190        match goal.predicate.kind().no_bound_vars() {
191            Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { .. })) => {
192                // We don't handle `NormalizesTo` as a nested goal
193                ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
194            }
195            _ => {
196                // We're using a probe here as evaluating a goal could constrain
197                // inference variables by choosing one candidate. If we then recurse
198                // into another candidate who ends up with different inference
199                // constraints, we get an ICE if we already applied the constraints
200                // from the chosen candidate.
201                let proof_tree =
202                    infcx.probe(|_| infcx.evaluate_root_goal_for_proof_tree(goal, span).1);
203                InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, source)
204            }
205        }
206    }
207
208    /// Visit all nested goals of this candidate, rolling back
209    /// all inference constraints.
210    pub fn visit_nested_in_probe<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {
211        self.goal.infcx.probe(|_| self.visit_nested_no_probe(visitor))
212    }
213}
214
215impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
216    pub fn infcx(&self) -> &'a InferCtxt<'tcx> {
217        self.infcx
218    }
219
220    pub fn goal(&self) -> Goal<'tcx, ty::Predicate<'tcx>> {
221        self.goal
222    }
223
224    pub fn result(&self) -> Result<Certainty, NoSolution> {
225        self.result
226    }
227
228    pub fn source(&self) -> GoalSource {
229        self.source
230    }
231
232    pub fn depth(&self) -> usize {
233        self.depth
234    }
235
236    pub fn required_depth(&self) -> RequiredDepth {
237        self.required_depth
238    }
239
240    pub fn orig_values(&self) -> &[ty::GenericArg<'tcx>] {
241        &self.orig_values
242    }
243
244    fn candidates_recur(
245        &'a self,
246        candidates: &mut Vec<InspectCandidate<'a, 'tcx>>,
247        steps: &mut Vec<&'a inspect::ProbeStep<TyCtxt<'tcx>>>,
248        probe: &'a inspect::Probe<TyCtxt<'tcx>>,
249    ) {
250        let mut shallow_certainty = None;
251        for step in &probe.steps {
252            match *step {
253                inspect::ProbeStep::AddGoal(..) | inspect::ProbeStep::RecordImplArgs { .. } => {
254                    steps.push(step)
255                }
256                inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
257                    {
    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!(
258                        shallow_certainty.replace(c),
259                        None | Some(Certainty::Maybe(MaybeInfo {
260                            cause: MaybeCause::Ambiguity,
261                            opaque_types_jank: _,
262                            stalled_on_coroutines: _,
263                        }))
264                    );
265                }
266                inspect::ProbeStep::NestedProbe(ref probe) => {
267                    match probe.kind {
268                        // These never assemble candidates for the goal we're trying to solve.
269                        inspect::ProbeKind::ProjectionCompatibility
270                        | inspect::ProbeKind::ShadowedEnvProbing => continue,
271
272                        inspect::ProbeKind::NormalizedSelfTyAssembly
273                        | inspect::ProbeKind::UnsizeAssembly
274                        | inspect::ProbeKind::Root { .. }
275                        | inspect::ProbeKind::TraitCandidate { .. }
276                        | inspect::ProbeKind::OpaqueTypeStorageLookup { .. }
277                        | inspect::ProbeKind::RigidAlias { .. } => {
278                            // Nested probes have to prove goals added in their parent
279                            // but do not leak them, so we truncate the added goals
280                            // afterwards.
281                            let num_steps = steps.len();
282                            self.candidates_recur(candidates, steps, probe);
283                            steps.truncate(num_steps);
284                        }
285                    }
286                }
287            }
288        }
289
290        match probe.kind {
291            inspect::ProbeKind::ProjectionCompatibility
292            | inspect::ProbeKind::ShadowedEnvProbing => {
293                ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!()
294            }
295
296            inspect::ProbeKind::NormalizedSelfTyAssembly | inspect::ProbeKind::UnsizeAssembly => {}
297
298            // We add a candidate even for the root evaluation if there
299            // is only one way to prove a given goal, e.g. for `WellFormed`.
300            inspect::ProbeKind::Root { result }
301            | inspect::ProbeKind::TraitCandidate { source: _, result }
302            | inspect::ProbeKind::OpaqueTypeStorageLookup { result }
303            | inspect::ProbeKind::RigidAlias { result } => {
304                // We only add a candidate if `shallow_certainty` was set, which means
305                // that we ended up calling `evaluate_added_goals_and_make_canonical_response`.
306                if let Some(shallow_certainty) = shallow_certainty {
307                    candidates.push(InspectCandidate {
308                        goal: self,
309                        kind: probe.kind,
310                        steps: steps.clone(),
311                        final_state: probe.final_state,
312                        shallow_certainty,
313                        result,
314                    });
315                }
316            }
317        }
318    }
319
320    pub fn candidates(&'a self) -> Vec<InspectCandidate<'a, 'tcx>> {
321        let mut candidates = ::alloc::vec::Vec::new()vec![];
322        let mut nested_goals = ::alloc::vec::Vec::new()vec![];
323        self.candidates_recur(&mut candidates, &mut nested_goals, &self.final_revision);
324        candidates
325    }
326
327    /// Returns the single candidate applicable for the current goal, if it exists.
328    ///
329    /// Returns `None` if there are either no or multiple applicable candidates.
330    pub fn unique_applicable_candidate(&'a self) -> Option<InspectCandidate<'a, 'tcx>> {
331        // FIXME(-Znext-solver): This does not handle impl candidates
332        // hidden by env candidates.
333        let mut candidates = self.candidates();
334        candidates.retain(|c| c.result().is_ok());
335        candidates.pop().filter(|_| candidates.is_empty())
336    }
337
338    fn new(
339        infcx: &'a InferCtxt<'tcx>,
340        depth: usize,
341        root: inspect::GoalEvaluation<TyCtxt<'tcx>>,
342        source: GoalSource,
343    ) -> Self {
344        use rustc_middle::ty::InferCtxtLike;
345
346        let infcx = <&SolverDelegate<'tcx>>::from(infcx);
347        let prev_universe = infcx.universe();
348
349        let inspect::GoalEvaluation {
350            uncanonicalized_goal,
351            orig_values,
352            final_revision,
353            result,
354            required_depth,
355        } = root;
356        // If there's a normalizes-to goal, AND the evaluation result with the result of
357        // constraining the normalizes-to RHS and computing the nested goals.
358        let result = result.map(|ok| ok.value.certainty);
359
360        InspectGoal {
361            infcx,
362            depth,
363            orig_values,
364            prev_universe,
365            // We *want* this folder to live in `rustc_type_ir`. Our best way to call into it is
366            // through `InferCtxtLike` and it is not defined as an inherent method on `InferCtxt`.
367            #[allow(rustc::usage_of_type_ir_traits)]
368            goal: infcx.deeply_resolve_via_unification_table(uncanonicalized_goal),
369            result,
370            final_revision,
371            source,
372            required_depth,
373        }
374    }
375
376    pub(crate) fn visit_with<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {
377        if self.depth < visitor.config().max_depth {
378            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));
379            V::Result::output()
380        } else {
381            visitor.on_recursion_limit()
382        }
383    }
384}
385
386/// The public API to interact with proof trees.
387pub trait ProofTreeVisitor<'tcx> {
388    type Result: VisitorResult = ();
389
390    fn span(&self) -> Span;
391
392    fn config(&self) -> InspectConfig {
393        InspectConfig { max_depth: 10 }
394    }
395
396    fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> Self::Result;
397
398    fn on_recursion_limit(&mut self) -> Self::Result {
399        Self::Result::output()
400    }
401}
402
403pub trait InferCtxtProofTreeExt<'tcx> {
    fn visit_proof_tree<V: ProofTreeVisitor<'tcx>>(&self,
    goal: Goal<'tcx, ty::Predicate<'tcx>>, visitor: &mut V)
    -> V::Result;
    fn visit_proof_tree_at_depth<V: ProofTreeVisitor<'tcx>>(&self,
    goal: Goal<'tcx, ty::Predicate<'tcx>>, depth: usize, visitor: &mut V)
    -> V::Result;
}
impl<'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>)]
404impl<'tcx> InferCtxt<'tcx> {
405    fn visit_proof_tree<V: ProofTreeVisitor<'tcx>>(
406        &self,
407        goal: Goal<'tcx, ty::Predicate<'tcx>>,
408        visitor: &mut V,
409    ) -> V::Result {
410        self.visit_proof_tree_at_depth(goal, 0, visitor)
411    }
412
413    fn visit_proof_tree_at_depth<V: ProofTreeVisitor<'tcx>>(
414        &self,
415        goal: Goal<'tcx, ty::Predicate<'tcx>>,
416        depth: usize,
417        visitor: &mut V,
418    ) -> V::Result {
419        let (_, proof_tree) = <&SolverDelegate<'tcx>>::from(self)
420            .evaluate_root_goal_for_proof_tree(goal, visitor.span());
421        visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, GoalSource::Misc))
422    }
423}