use std::convert::Infallible; use std::marker::PhantomData; use rustc_type_ir::Interner; use rustc_type_ir::inherent::*; use rustc_type_ir::search_graph::{self, PathKind}; use rustc_type_ir::solve::{CanonicalInput, Certainty, QueryResult}; use super::inspect::ProofTreeBuilder; use super::{FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints}; use crate::delegate::SolverDelegate; /// This type is never constructed. We only use it to implement `search_graph::Delegate` /// for all types which impl `SolverDelegate` and doing it directly fails in coherence. pub(super) struct SearchGraphDelegate { _marker: PhantomData, } pub(super) type SearchGraph = search_graph::SearchGraph>; impl search_graph::Delegate for SearchGraphDelegate where D: SolverDelegate, I: Interner, { type Cx = D::Interner; const ENABLE_PROVISIONAL_CACHE: bool = true; type ValidationScope = Infallible; fn enter_validation_scope( _cx: Self::Cx, _input: CanonicalInput, ) -> Option { None } const FIXPOINT_STEP_LIMIT: usize = FIXPOINT_STEP_LIMIT; type ProofTreeBuilder = ProofTreeBuilder; fn inspect_is_noop(inspect: &mut Self::ProofTreeBuilder) -> bool { inspect.is_noop() } const DIVIDE_AVAILABLE_DEPTH_ON_OVERFLOW: usize = 4; fn recursion_limit(cx: I) -> usize { cx.recursion_limit() } fn initial_provisional_result( cx: I, kind: PathKind, input: CanonicalInput, ) -> QueryResult { match kind { PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes), PathKind::Inductive => response_no_constraints(cx, input, Certainty::overflow(false)), } } fn is_initial_provisional_result( cx: Self::Cx, kind: PathKind, input: CanonicalInput, result: QueryResult, ) -> bool { match kind { PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes) == result, PathKind::Inductive => { response_no_constraints(cx, input, Certainty::overflow(false)) == result } } } fn on_stack_overflow( cx: I, inspect: &mut ProofTreeBuilder, input: CanonicalInput, ) -> QueryResult { inspect.canonical_goal_evaluation_overflow(); response_no_constraints(cx, input, Certainty::overflow(true)) } fn on_fixpoint_overflow(cx: I, input: CanonicalInput) -> QueryResult { response_no_constraints(cx, input, Certainty::overflow(false)) } fn is_ambiguous_result(result: QueryResult) -> bool { result.is_ok_and(|response| { has_no_inference_or_external_constraints(response) && matches!(response.value.certainty, Certainty::Maybe(_)) }) } fn propagate_ambiguity( cx: I, for_input: CanonicalInput, from_result: QueryResult, ) -> QueryResult { let certainty = from_result.unwrap().value.certainty; response_no_constraints(cx, for_input, certainty) } fn step_is_coinductive(cx: I, input: CanonicalInput) -> bool { input.value.goal.predicate.is_coinductive(cx) } } fn response_no_constraints( cx: I, goal: CanonicalInput, certainty: Certainty, ) -> QueryResult { Ok(super::response_no_constraints_raw(cx, goal.max_universe, goal.variables, certainty)) }