rust/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
2024-05-19 19:38:28 -04:00

116 lines
3.8 KiB
Rust

use crate::solve::assembly::Candidate;
use super::EvalCtxt;
use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::BuiltinImplSource;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::{inspect, CandidateSource, QueryResult};
use rustc_middle::ty::TyCtxt;
use std::marker::PhantomData;
pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> {
ecx: &'me mut EvalCtxt<'a, InferCtxt<'tcx>>,
probe_kind: F,
_result: PhantomData<T>,
}
impl<'tcx, F, T> ProbeCtxt<'_, '_, 'tcx, F, T>
where
F: FnOnce(&T) -> inspect::ProbeKind<TyCtxt<'tcx>>,
{
pub(in crate::solve) fn enter(
self,
f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> T,
) -> T {
let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self;
let infcx = outer_ecx.infcx;
let max_input_universe = outer_ecx.max_input_universe;
let mut nested_ecx = EvalCtxt {
infcx,
variables: outer_ecx.variables,
var_values: outer_ecx.var_values,
is_normalizes_to_goal: outer_ecx.is_normalizes_to_goal,
predefined_opaques_in_body: outer_ecx.predefined_opaques_in_body,
max_input_universe,
search_graph: outer_ecx.search_graph,
nested_goals: outer_ecx.nested_goals.clone(),
tainted: outer_ecx.tainted,
inspect: outer_ecx.inspect.take_and_enter_probe(),
};
let r = nested_ecx.infcx.probe(|_| {
let r = f(&mut nested_ecx);
nested_ecx.inspect.probe_final_state(infcx, max_input_universe);
r
});
if !nested_ecx.inspect.is_noop() {
let probe_kind = probe_kind(&r);
nested_ecx.inspect.probe_kind(probe_kind);
outer_ecx.inspect = nested_ecx.inspect.finish_probe();
}
r
}
}
pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, 'tcx, F> {
cx: ProbeCtxt<'me, 'a, 'tcx, F, QueryResult<'tcx>>,
source: CandidateSource<'tcx>,
}
impl<'tcx, F> TraitProbeCtxt<'_, '_, 'tcx, F>
where
F: FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<TyCtxt<'tcx>>,
{
#[instrument(level = "debug", skip_all, fields(source = ?self.source))]
pub(in crate::solve) fn enter(
self,
f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>,
) -> Result<Candidate<'tcx>, NoSolution> {
self.cx.enter(|ecx| f(ecx)).map(|result| Candidate { source: self.source, result })
}
}
impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
/// `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, 'tcx, F, T>
where
F: FnOnce(&T) -> inspect::ProbeKind<TyCtxt<'tcx>>,
{
ProbeCtxt { ecx: self, probe_kind, _result: PhantomData }
}
pub(in crate::solve) fn probe_builtin_trait_candidate(
&mut self,
source: BuiltinImplSource,
) -> TraitProbeCtxt<
'_,
'a,
'tcx,
impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<TyCtxt<'tcx>>,
> {
self.probe_trait_candidate(CandidateSource::BuiltinImpl(source))
}
pub(in crate::solve) fn probe_trait_candidate(
&mut self,
source: CandidateSource<'tcx>,
) -> TraitProbeCtxt<
'_,
'a,
'tcx,
impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<TyCtxt<'tcx>>,
> {
TraitProbeCtxt {
cx: ProbeCtxt {
ecx: self,
probe_kind: move |result: &QueryResult<'tcx>| inspect::ProbeKind::TraitCandidate {
source,
result: *result,
},
_result: PhantomData,
},
source,
}
}
}