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