116 lines
3.8 KiB
Rust
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,
|
|
}
|
|
}
|
|
}
|