rustc_next_trait_solver/solve/
search_graph.rs
1use std::convert::Infallible;
2use std::marker::PhantomData;
3
4use rustc_type_ir::search_graph::{self, PathKind};
5use rustc_type_ir::solve::{CanonicalInput, Certainty, NoSolution, QueryResult};
6use rustc_type_ir::{Interner, TypingMode};
7
8use super::inspect::ProofTreeBuilder;
9use super::{FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints};
10use crate::delegate::SolverDelegate;
11
12pub(super) struct SearchGraphDelegate<D: SolverDelegate> {
15 _marker: PhantomData<D>,
16}
17pub(super) type SearchGraph<D> = search_graph::SearchGraph<SearchGraphDelegate<D>>;
18impl<D, I> search_graph::Delegate for SearchGraphDelegate<D>
19where
20 D: SolverDelegate<Interner = I>,
21 I: Interner,
22{
23 type Cx = D::Interner;
24
25 const ENABLE_PROVISIONAL_CACHE: bool = true;
26 type ValidationScope = Infallible;
27 fn enter_validation_scope(
28 _cx: Self::Cx,
29 _input: CanonicalInput<I>,
30 ) -> Option<Self::ValidationScope> {
31 None
32 }
33
34 const FIXPOINT_STEP_LIMIT: usize = FIXPOINT_STEP_LIMIT;
35
36 type ProofTreeBuilder = ProofTreeBuilder<D>;
37 fn inspect_is_noop(inspect: &mut Self::ProofTreeBuilder) -> bool {
38 inspect.is_noop()
39 }
40
41 const DIVIDE_AVAILABLE_DEPTH_ON_OVERFLOW: usize = 4;
42
43 fn initial_provisional_result(
44 cx: I,
45 kind: PathKind,
46 input: CanonicalInput<I>,
47 ) -> QueryResult<I> {
48 match kind {
49 PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes),
50 PathKind::Unknown => response_no_constraints(cx, input, Certainty::overflow(false)),
51 PathKind::Inductive => match input.typing_mode {
61 TypingMode::Coherence => {
62 response_no_constraints(cx, input, Certainty::overflow(false))
63 }
64 TypingMode::Analysis { .. }
65 | TypingMode::PostBorrowckAnalysis { .. }
66 | TypingMode::PostAnalysis => Err(NoSolution),
67 },
68 }
69 }
70
71 fn is_initial_provisional_result(
72 cx: Self::Cx,
73 kind: PathKind,
74 input: CanonicalInput<I>,
75 result: QueryResult<I>,
76 ) -> bool {
77 Self::initial_provisional_result(cx, kind, input) == result
78 }
79
80 fn on_stack_overflow(
81 cx: I,
82 inspect: &mut ProofTreeBuilder<D>,
83 input: CanonicalInput<I>,
84 ) -> QueryResult<I> {
85 inspect.canonical_goal_evaluation_overflow();
86 response_no_constraints(cx, input, Certainty::overflow(true))
87 }
88
89 fn on_fixpoint_overflow(cx: I, input: CanonicalInput<I>) -> QueryResult<I> {
90 response_no_constraints(cx, input, Certainty::overflow(false))
91 }
92
93 fn is_ambiguous_result(result: QueryResult<I>) -> bool {
94 result.is_ok_and(|response| {
95 has_no_inference_or_external_constraints(response)
96 && matches!(response.value.certainty, Certainty::Maybe(_))
97 })
98 }
99
100 fn propagate_ambiguity(
101 cx: I,
102 for_input: CanonicalInput<I>,
103 from_result: QueryResult<I>,
104 ) -> QueryResult<I> {
105 let certainty = from_result.unwrap().value.certainty;
106 response_no_constraints(cx, for_input, certainty)
107 }
108}
109
110fn response_no_constraints<I: Interner>(
111 cx: I,
112 input: CanonicalInput<I>,
113 certainty: Certainty,
114) -> QueryResult<I> {
115 Ok(super::response_no_constraints_raw(
116 cx,
117 input.canonical.max_universe,
118 input.canonical.variables,
119 certainty,
120 ))
121}