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