rustc_next_trait_solver/solve/eval_ctxt/
probe.rs

1use std::marker::PhantomData;
2
3use rustc_type_ir::{InferCtxtLike, Interner};
4use tracing::instrument;
5
6use crate::delegate::SolverDelegate;
7use crate::solve::assembly::Candidate;
8use crate::solve::{
9    BuiltinImplSource, CandidateSource, EvalCtxt, NoSolution, QueryResult, inspect,
10};
11
12pub(in crate::solve) struct ProbeCtxt<'me, 'a, D, I, F, T>
13where
14    D: SolverDelegate<Interner = I>,
15    I: Interner,
16{
17    ecx: &'me mut EvalCtxt<'a, D, I>,
18    probe_kind: F,
19    _result: PhantomData<T>,
20}
21
22impl<D, I, F, T> ProbeCtxt<'_, '_, D, I, F, T>
23where
24    F: FnOnce(&T) -> inspect::ProbeKind<I>,
25    D: SolverDelegate<Interner = I>,
26    I: Interner,
27{
28    pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> T) -> T {
29        let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self;
30
31        let delegate = outer_ecx.delegate;
32        let max_input_universe = outer_ecx.max_input_universe;
33        let mut nested_ecx = EvalCtxt {
34            delegate,
35            variables: outer_ecx.variables,
36            var_values: outer_ecx.var_values,
37            is_normalizes_to_goal: outer_ecx.is_normalizes_to_goal,
38            predefined_opaques_in_body: outer_ecx.predefined_opaques_in_body,
39            max_input_universe,
40            search_graph: outer_ecx.search_graph,
41            nested_goals: outer_ecx.nested_goals.clone(),
42            origin_span: outer_ecx.origin_span,
43            tainted: outer_ecx.tainted,
44            inspect: outer_ecx.inspect.take_and_enter_probe(),
45        };
46        let r = nested_ecx.delegate.probe(|| {
47            let r = f(&mut nested_ecx);
48            nested_ecx.inspect.probe_final_state(delegate, max_input_universe);
49            r
50        });
51        if !nested_ecx.inspect.is_noop() {
52            let probe_kind = probe_kind(&r);
53            nested_ecx.inspect.probe_kind(probe_kind);
54            outer_ecx.inspect = nested_ecx.inspect.finish_probe();
55        }
56        r
57    }
58}
59
60pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, D, I, F>
61where
62    D: SolverDelegate<Interner = I>,
63    I: Interner,
64{
65    cx: ProbeCtxt<'me, 'a, D, I, F, QueryResult<I>>,
66    source: CandidateSource<I>,
67}
68
69impl<D, I, F> TraitProbeCtxt<'_, '_, D, I, F>
70where
71    D: SolverDelegate<Interner = I>,
72    I: Interner,
73    F: FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>,
74{
75    #[instrument(level = "debug", skip_all, fields(source = ?self.source))]
76    pub(in crate::solve) fn enter(
77        self,
78        f: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
79    ) -> Result<Candidate<I>, NoSolution> {
80        self.cx.enter(|ecx| f(ecx)).map(|result| Candidate { source: self.source, result })
81    }
82}
83
84impl<'a, D, I> EvalCtxt<'a, D, I>
85where
86    D: SolverDelegate<Interner = I>,
87    I: Interner,
88{
89    /// `probe_kind` is only called when proof tree building is enabled so it can be
90    /// as expensive as necessary to output the desired information.
91    pub(in crate::solve) fn probe<F, T>(&mut self, probe_kind: F) -> ProbeCtxt<'_, 'a, D, I, F, T>
92    where
93        F: FnOnce(&T) -> inspect::ProbeKind<I>,
94    {
95        ProbeCtxt { ecx: self, probe_kind, _result: PhantomData }
96    }
97
98    pub(in crate::solve) fn probe_builtin_trait_candidate(
99        &mut self,
100        source: BuiltinImplSource,
101    ) -> TraitProbeCtxt<'_, 'a, D, I, impl FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>> {
102        self.probe_trait_candidate(CandidateSource::BuiltinImpl(source))
103    }
104
105    pub(in crate::solve) fn probe_trait_candidate(
106        &mut self,
107        source: CandidateSource<I>,
108    ) -> TraitProbeCtxt<'_, 'a, D, I, impl FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>> {
109        TraitProbeCtxt {
110            cx: ProbeCtxt {
111                ecx: self,
112                probe_kind: move |result: &QueryResult<I>| inspect::ProbeKind::TraitCandidate {
113                    source,
114                    result: *result,
115                },
116                _result: PhantomData,
117            },
118            source,
119        }
120    }
121}