rustc_next_trait_solver/solve/
search_graph.rs1use std::convert::Infallible;
2use std::marker::PhantomData;
3
4use rustc_type_ir::data_structures::ensure_sufficient_stack;
5use rustc_type_ir::search_graph::{self, PathKind};
6use rustc_type_ir::solve::{CanonicalInput, Certainty, NoSolution, QueryResult};
7use rustc_type_ir::{Interner, TypingMode};
8
9use crate::delegate::SolverDelegate;
10use crate::solve::{
11 EvalCtxt, FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints, inspect,
12};
13
14pub(super) struct SearchGraphDelegate<D: SolverDelegate> {
17 _marker: PhantomData<D>,
18}
19pub(super) type SearchGraph<D> = search_graph::SearchGraph<SearchGraphDelegate<D>>;
20impl<D, I> search_graph::Delegate for SearchGraphDelegate<D>
21where
22 D: SolverDelegate<Interner = I>,
23 I: Interner,
24{
25 type Cx = D::Interner;
26
27 const ENABLE_PROVISIONAL_CACHE: bool = true;
28 type ValidationScope = Infallible;
29 fn enter_validation_scope(
30 _cx: Self::Cx,
31 _input: CanonicalInput<I>,
32 ) -> Option<Self::ValidationScope> {
33 None
34 }
35
36 const FIXPOINT_STEP_LIMIT: usize = FIXPOINT_STEP_LIMIT;
37
38 type ProofTreeBuilder = inspect::ProofTreeBuilder<D>;
39 fn inspect_is_noop(inspect: &mut Self::ProofTreeBuilder) -> bool {
40 inspect.is_noop()
41 }
42
43 const DIVIDE_AVAILABLE_DEPTH_ON_OVERFLOW: usize = 4;
44
45 fn initial_provisional_result(
46 cx: I,
47 kind: PathKind,
48 input: CanonicalInput<I>,
49 ) -> QueryResult<I> {
50 match kind {
51 PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes),
52 PathKind::Unknown | PathKind::ForcedAmbiguity => {
53 response_no_constraints(cx, input, Certainty::overflow(false))
54 }
55 PathKind::Inductive => match input.typing_mode {
65 TypingMode::Coherence => {
66 response_no_constraints(cx, input, Certainty::overflow(false))
67 }
68 TypingMode::Analysis { .. }
69 | TypingMode::Borrowck { .. }
70 | TypingMode::PostBorrowckAnalysis { .. }
71 | TypingMode::PostAnalysis => Err(NoSolution),
72 },
73 }
74 }
75
76 fn is_initial_provisional_result(
77 cx: Self::Cx,
78 kind: PathKind,
79 input: CanonicalInput<I>,
80 result: QueryResult<I>,
81 ) -> bool {
82 Self::initial_provisional_result(cx, kind, input) == result
83 }
84
85 fn on_stack_overflow(cx: I, input: CanonicalInput<I>) -> QueryResult<I> {
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 fn compute_goal(
110 search_graph: &mut SearchGraph<D>,
111 cx: I,
112 input: CanonicalInput<I>,
113 inspect: &mut Self::ProofTreeBuilder,
114 ) -> QueryResult<I> {
115 ensure_sufficient_stack(|| {
116 EvalCtxt::enter_canonical(cx, search_graph, input, inspect, |ecx, goal| {
117 let result = ecx.compute_goal(goal);
118 ecx.inspect.query_result(result);
119 result
120 })
121 })
122 }
123}
124
125fn response_no_constraints<I: Interner>(
126 cx: I,
127 input: CanonicalInput<I>,
128 certainty: Certainty,
129) -> QueryResult<I> {
130 Ok(super::response_no_constraints_raw(
131 cx,
132 input.canonical.max_universe,
133 input.canonical.variables,
134 certainty,
135 ))
136}