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::canonical::response_no_constraints_raw;
10use crate::delegate::SolverDelegate;
11use crate::solve::{
12 EvalCtxt, FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints, inspect,
13};
14
15pub(super) struct SearchGraphDelegate<D: SolverDelegate> {
18 _marker: PhantomData<D>,
19}
20pub(super) type SearchGraph<D> = search_graph::SearchGraph<SearchGraphDelegate<D>>;
21impl<D, I> search_graph::Delegate for SearchGraphDelegate<D>
22where
23 D: SolverDelegate<Interner = I>,
24 I: Interner,
25{
26 type Cx = D::Interner;
27
28 const ENABLE_PROVISIONAL_CACHE: bool = true;
29 type ValidationScope = Infallible;
30 fn enter_validation_scope(
31 _cx: Self::Cx,
32 _input: CanonicalInput<I>,
33 ) -> Option<Self::ValidationScope> {
34 None
35 }
36
37 const FIXPOINT_STEP_LIMIT: usize = FIXPOINT_STEP_LIMIT;
38
39 type ProofTreeBuilder = inspect::ProofTreeBuilder<D>;
40 fn inspect_is_noop(inspect: &mut Self::ProofTreeBuilder) -> bool {
41 inspect.is_noop()
42 }
43
44 const DIVIDE_AVAILABLE_DEPTH_ON_OVERFLOW: usize = 4;
45
46 fn initial_provisional_result(
47 cx: I,
48 kind: PathKind,
49 input: CanonicalInput<I>,
50 ) -> QueryResult<I> {
51 match kind {
52 PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes),
53 PathKind::Unknown | PathKind::ForcedAmbiguity => {
54 response_no_constraints(cx, input, Certainty::overflow(false))
55 }
56 PathKind::Inductive => match input.typing_mode {
66 TypingMode::Coherence => {
67 response_no_constraints(cx, input, Certainty::overflow(false))
68 }
69 TypingMode::Analysis { .. }
70 | TypingMode::Borrowck { .. }
71 | TypingMode::PostBorrowckAnalysis { .. }
72 | TypingMode::PostAnalysis => Err(NoSolution),
73 },
74 }
75 }
76
77 fn is_initial_provisional_result(result: QueryResult<I>) -> Option<PathKind> {
78 match result {
79 Ok(response) => {
80 if has_no_inference_or_external_constraints(response) {
81 if response.value.certainty == Certainty::Yes {
82 return Some(PathKind::Coinductive);
83 } else if response.value.certainty == Certainty::overflow(false) {
84 return Some(PathKind::Unknown);
85 }
86 }
87
88 None
89 }
90 Err(NoSolution) => Some(PathKind::Inductive),
91 }
92 }
93
94 fn stack_overflow_result(cx: I, input: CanonicalInput<I>) -> QueryResult<I> {
95 response_no_constraints(cx, input, Certainty::overflow(true))
96 }
97
98 fn fixpoint_overflow_result(cx: I, input: CanonicalInput<I>) -> QueryResult<I> {
99 response_no_constraints(cx, input, Certainty::overflow(false))
100 }
101
102 fn is_ambiguous_result(result: QueryResult<I>) -> Option<Certainty> {
103 result.ok().and_then(|response| {
104 if has_no_inference_or_external_constraints(response)
105 && matches!(response.value.certainty, Certainty::Maybe { .. })
106 {
107 Some(response.value.certainty)
108 } else {
109 None
110 }
111 })
112 }
113
114 fn propagate_ambiguity(
115 cx: I,
116 for_input: CanonicalInput<I>,
117 certainty: Certainty,
118 ) -> QueryResult<I> {
119 response_no_constraints(cx, for_input, certainty)
120 }
121
122 fn compute_goal(
123 search_graph: &mut SearchGraph<D>,
124 cx: I,
125 input: CanonicalInput<I>,
126 inspect: &mut Self::ProofTreeBuilder,
127 ) -> QueryResult<I> {
128 ensure_sufficient_stack(|| {
129 EvalCtxt::enter_canonical(cx, search_graph, input, inspect, |ecx, goal| {
130 let result = ecx.compute_goal(goal);
131 ecx.inspect.query_result(result);
132 result
133 })
134 })
135 }
136}
137
138fn response_no_constraints<I: Interner>(
139 cx: I,
140 input: CanonicalInput<I>,
141 certainty: Certainty,
142) -> QueryResult<I> {
143 Ok(response_no_constraints_raw(
144 cx,
145 input.canonical.max_universe,
146 input.canonical.variables,
147 certainty,
148 ))
149}