Skip to main content

rustc_next_trait_solver/solve/eval_ctxt/
probe.rs

1use std::marker::PhantomData;
2
3use rustc_type_ir::search_graph::CandidateHeadUsages;
4use rustc_type_ir::solve::{
5    AccessedOpaques, CanonicalResponse, NoSolutionOrRerunNonErased, RerunResultExt,
6};
7use rustc_type_ir::{InferCtxtLike, Interner};
8use tracing::{instrument, warn};
9
10use crate::delegate::SolverDelegate;
11use crate::solve::assembly::Candidate;
12use crate::solve::{
13    BuiltinImplSource, CandidateSource, EvalCtxt, Goal, GoalSource, GoalStalledOn, NoSolution,
14    QueryResult, inspect,
15};
16
17pub(in crate::solve) struct ProbeCtxt<'me, 'a, D, I, F, T>
18where
19    D: SolverDelegate<Interner = I>,
20    I: Interner,
21{
22    ecx: &'me mut EvalCtxt<'a, D, I>,
23    probe_kind: F,
24    _result: PhantomData<T>,
25}
26
27impl<D, I, F, T> ProbeCtxt<'_, '_, D, I, F, T>
28where
29    F: FnOnce(&Result<T, NoSolution>) -> inspect::ProbeKind<I>,
30    D: SolverDelegate<Interner = I>,
31    I: Interner,
32{
33    pub(in crate::solve) fn enter_single_candidate(
34        self,
35        f: impl FnOnce(&mut EvalCtxt<'_, D>) -> Result<T, NoSolutionOrRerunNonErased>,
36    ) -> (Result<T, NoSolutionOrRerunNonErased>, CandidateHeadUsages) {
37        let mut candidate_usages = CandidateHeadUsages::default();
38
39        if let Err(e) = self.ecx.opaque_accesses.should_bail() {
40            return (Err(e.into()), candidate_usages);
41        }
42
43        self.ecx.search_graph.enter_single_candidate();
44        let result = self.enter(|ecx| {
45            let result = f(ecx);
46            candidate_usages = ecx.search_graph.finish_single_candidate();
47            result
48        });
49        (result, candidate_usages)
50    }
51
52    pub(in crate::solve) fn enter(
53        self,
54        f: impl FnOnce(&mut EvalCtxt<'_, D>) -> Result<T, NoSolutionOrRerunNonErased>,
55    ) -> Result<T, NoSolutionOrRerunNonErased> {
56        let nested_goals = self.ecx.nested_goals.clone();
57        self.enter_inner(f, nested_goals)
58    }
59
60    pub(in crate::solve) fn enter_without_propagated_nested_goals(
61        self,
62        f: impl FnOnce(&mut EvalCtxt<'_, D>) -> Result<T, NoSolutionOrRerunNonErased>,
63    ) -> Result<T, NoSolutionOrRerunNonErased> {
64        self.enter_inner(f, Default::default())
65    }
66
67    pub(in crate::solve) fn enter_inner(
68        self,
69        f: impl FnOnce(&mut EvalCtxt<'_, D>) -> Result<T, NoSolutionOrRerunNonErased>,
70        propagated_nested_goals: Vec<(GoalSource, Goal<I, I::Predicate>, Option<GoalStalledOn<I>>)>,
71    ) -> Result<T, NoSolutionOrRerunNonErased> {
72        let ProbeCtxt { ecx: outer, probe_kind, _result } = self;
73
74        outer.opaque_accesses.should_bail()?;
75
76        let delegate = outer.delegate;
77        let max_input_universe = outer.max_input_universe;
78        let mut nested = EvalCtxt {
79            delegate,
80            var_kinds: outer.var_kinds,
81            var_values: outer.var_values,
82            current_goal_kind: outer.current_goal_kind,
83            max_input_universe,
84            initial_opaque_types_storage_num_entries: outer
85                .initial_opaque_types_storage_num_entries,
86            search_graph: outer.search_graph,
87            nested_goals: propagated_nested_goals,
88            origin_span: outer.origin_span,
89            tainted: outer.tainted,
90            inspect: outer.inspect.take_and_enter_probe(),
91            opaque_accesses: AccessedOpaques::default(),
92        };
93        let r = nested.delegate.probe(|| {
94            let r = f(&mut nested);
95            nested.inspect.probe_final_state(delegate, max_input_universe);
96            r
97        });
98
99        outer.opaque_accesses.update(nested.opaque_accesses)?;
100
101        // Unwrap is unreachable, we would have returned on the line above.
102        let r = r.map_err_to_rerun().unwrap();
103
104        if !nested.inspect.is_noop() {
105            let probe_kind = probe_kind(&r);
106            nested.inspect.probe_kind(probe_kind);
107            outer.inspect = nested.inspect.finish_probe();
108        }
109
110        r.map_err(Into::into)
111    }
112}
113
114pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, D, I, F>
115where
116    D: SolverDelegate<Interner = I>,
117    I: Interner,
118{
119    cx: ProbeCtxt<'me, 'a, D, I, F, CanonicalResponse<I>>,
120    source: CandidateSource<I>,
121}
122
123impl<D, I, F> TraitProbeCtxt<'_, '_, D, I, F>
124where
125    D: SolverDelegate<Interner = I>,
126    I: Interner,
127    F: FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>,
128{
129    #[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("enter",
                                    "rustc_next_trait_solver::solve::eval_ctxt::probe",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs"),
                                    ::tracing_core::__macro_support::Option::Some(129u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_next_trait_solver::solve::eval_ctxt::probe"),
                                    ::tracing_core::field::FieldSet::new(&["source"],
                                        ::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.source)
                                                            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:
                    Result<Candidate<I>, NoSolutionOrRerunNonErased> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let (result, head_usages) = self.cx.enter_single_candidate(f);
            Ok(Candidate {
                    source: self.source,
                    result: result?,
                    head_usages,
                })
        }
    }
}#[instrument(level = "debug", skip_all, fields(source = ?self.source))]
130    pub(in crate::solve) fn enter(
131        self,
132        f: impl FnOnce(&mut EvalCtxt<'_, D>) -> Result<CanonicalResponse<I>, NoSolutionOrRerunNonErased>,
133    ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
134        let (result, head_usages) = self.cx.enter_single_candidate(f);
135        Ok(Candidate { source: self.source, result: result?, head_usages })
136    }
137}
138
139impl<'a, D, I> EvalCtxt<'a, D, I>
140where
141    D: SolverDelegate<Interner = I>,
142    I: Interner,
143{
144    /// `probe_kind` is only called when proof tree building is enabled so it can be
145    /// as expensive as necessary to output the desired information.
146    pub(in crate::solve) fn probe<F, T>(&mut self, probe_kind: F) -> ProbeCtxt<'_, 'a, D, I, F, T>
147    where
148        F: FnOnce(&Result<T, NoSolution>) -> inspect::ProbeKind<I>,
149    {
150        ProbeCtxt { ecx: self, probe_kind, _result: PhantomData }
151    }
152
153    pub(in crate::solve) fn probe_builtin_trait_candidate(
154        &mut self,
155        source: BuiltinImplSource,
156    ) -> TraitProbeCtxt<'_, 'a, D, I, impl FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>> {
157        self.probe_trait_candidate(CandidateSource::BuiltinImpl(source))
158    }
159
160    pub(in crate::solve) fn probe_trait_candidate(
161        &mut self,
162        source: CandidateSource<I>,
163    ) -> TraitProbeCtxt<'_, 'a, D, I, impl FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>> {
164        TraitProbeCtxt {
165            cx: ProbeCtxt {
166                ecx: self,
167                probe_kind: move |result: &QueryResult<I>| inspect::ProbeKind::TraitCandidate {
168                    source,
169                    result: *result,
170                },
171                _result: PhantomData,
172            },
173            source,
174        }
175    }
176}