blob: e5658ba32ff67838815b00dce1b3c1ce09f955ff [file] [log] [blame]
use std::marker::PhantomData;
use rustc_type_ir::search_graph::CandidateHeadUsages;
use rustc_type_ir::{InferCtxtLike, Interner};
use tracing::instrument;
use crate::delegate::SolverDelegate;
use crate::solve::assembly::Candidate;
use crate::solve::{
BuiltinImplSource, CandidateSource, EvalCtxt, NoSolution, QueryResult, inspect,
};
pub(in crate::solve) struct ProbeCtxt<'me, 'a, D, I, F, T>
where
D: SolverDelegate<Interner = I>,
I: Interner,
{
ecx: &'me mut EvalCtxt<'a, D, I>,
probe_kind: F,
_result: PhantomData<T>,
}
impl<D, I, F, T> ProbeCtxt<'_, '_, D, I, F, T>
where
F: FnOnce(&T) -> inspect::ProbeKind<I>,
D: SolverDelegate<Interner = I>,
I: Interner,
{
pub(in crate::solve) fn enter_single_candidate(
self,
f: impl FnOnce(&mut EvalCtxt<'_, D>) -> T,
) -> (T, CandidateHeadUsages) {
self.ecx.search_graph.enter_single_candidate();
let mut candidate_usages = CandidateHeadUsages::default();
let result = self.enter(|ecx| {
let result = f(ecx);
candidate_usages = ecx.search_graph.finish_single_candidate();
result
});
(result, candidate_usages)
}
pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> T) -> T {
let ProbeCtxt { ecx: outer, probe_kind, _result } = self;
let delegate = outer.delegate;
let max_input_universe = outer.max_input_universe;
let mut nested = EvalCtxt {
delegate,
variables: outer.variables,
var_values: outer.var_values,
current_goal_kind: outer.current_goal_kind,
max_input_universe,
initial_opaque_types_storage_num_entries: outer
.initial_opaque_types_storage_num_entries,
search_graph: outer.search_graph,
nested_goals: outer.nested_goals.clone(),
origin_span: outer.origin_span,
tainted: outer.tainted,
inspect: outer.inspect.take_and_enter_probe(),
};
let r = nested.delegate.probe(|| {
let r = f(&mut nested);
nested.inspect.probe_final_state(delegate, max_input_universe);
r
});
if !nested.inspect.is_noop() {
let probe_kind = probe_kind(&r);
nested.inspect.probe_kind(probe_kind);
outer.inspect = nested.inspect.finish_probe();
}
r
}
}
pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, D, I, F>
where
D: SolverDelegate<Interner = I>,
I: Interner,
{
cx: ProbeCtxt<'me, 'a, D, I, F, QueryResult<I>>,
source: CandidateSource<I>,
}
impl<D, I, F> TraitProbeCtxt<'_, '_, D, I, F>
where
D: SolverDelegate<Interner = I>,
I: Interner,
F: FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>,
{
#[instrument(level = "debug", skip_all, fields(source = ?self.source))]
pub(in crate::solve) fn enter(
self,
f: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
) -> Result<Candidate<I>, NoSolution> {
let (result, head_usages) = self.cx.enter_single_candidate(f);
result.map(|result| Candidate { source: self.source, result, head_usages })
}
}
impl<'a, D, I> EvalCtxt<'a, D, I>
where
D: SolverDelegate<Interner = I>,
I: Interner,
{
/// `probe_kind` is only called when proof tree building is enabled so it can be
/// as expensive as necessary to output the desired information.
pub(in crate::solve) fn probe<F, T>(&mut self, probe_kind: F) -> ProbeCtxt<'_, 'a, D, I, F, T>
where
F: FnOnce(&T) -> inspect::ProbeKind<I>,
{
ProbeCtxt { ecx: self, probe_kind, _result: PhantomData }
}
pub(in crate::solve) fn probe_builtin_trait_candidate(
&mut self,
source: BuiltinImplSource,
) -> TraitProbeCtxt<'_, 'a, D, I, impl FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>> {
self.probe_trait_candidate(CandidateSource::BuiltinImpl(source))
}
pub(in crate::solve) fn probe_trait_candidate(
&mut self,
source: CandidateSource<I>,
) -> TraitProbeCtxt<'_, 'a, D, I, impl FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>> {
TraitProbeCtxt {
cx: ProbeCtxt {
ecx: self,
probe_kind: move |result: &QueryResult<I>| inspect::ProbeKind::TraitCandidate {
source,
result: *result,
},
_result: PhantomData,
},
source,
}
}
}