rustc_next_trait_solver/solve/
search_graph.rs1use std::convert::Infallible;
2use std::marker::PhantomData;
3
4use rustc_type_ir::Interner;
5use rustc_type_ir::search_graph::{self, PathKind};
6use rustc_type_ir::solve::{AccessedOpaques, Certainty, NoSolution, QueryResult, RerunResultExt};
7
8use crate::canonical::response_no_constraints_raw;
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: I::CanonicalInput,
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: I::CanonicalInput,
49 ) -> (QueryResult<I>, AccessedOpaques<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 => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
70 }
71 }
72
73 fn is_initial_provisional_result(
74 result: (QueryResult<I>, AccessedOpaques<I>),
75 ) -> Option<PathKind> {
76 match result.0 {
77 Ok(response) => {
78 if has_no_inference_or_external_constraints(response) {
79 if response.value.certainty == Certainty::Yes {
80 return Some(PathKind::Coinductive);
81 } else if response.value.certainty == Certainty::overflow(false) {
82 return Some(PathKind::Unknown);
83 }
84 }
85
86 None
87 }
88 Err(NoSolution) => Some(PathKind::Inductive),
89 }
90 }
91
92 fn stack_overflow_result(
93 cx: I,
94 input: I::CanonicalInput,
95 ) -> (QueryResult<I>, AccessedOpaques<I>) {
96 response_no_constraints(cx, input, Certainty::overflow(true))
97 }
98
99 const FIXPOINT_OVERFLOW_AMBIGUITY_KIND: Certainty = Certainty::overflow(false);
100 fn fixpoint_overflow_result(
101 cx: I,
102 input: I::CanonicalInput,
103 ) -> (QueryResult<I>, AccessedOpaques<I>) {
104 response_no_constraints(cx, input, Certainty::overflow(false))
105 }
106
107 fn is_ambiguous_result(result: (QueryResult<I>, AccessedOpaques<I>)) -> Option<Certainty> {
108 result.0.ok().and_then(|response| {
109 if has_no_inference_or_external_constraints(response)
110 && #[allow(non_exhaustive_omitted_patterns)] match response.value.certainty {
Certainty::Maybe { .. } => true,
_ => false,
}matches!(response.value.certainty, Certainty::Maybe { .. })
111 {
112 Some(response.value.certainty)
113 } else {
114 None
115 }
116 })
117 }
118
119 fn compute_goal(
120 search_graph: &mut SearchGraph<D>,
121 cx: I,
122 input: I::CanonicalInput,
123 inspect: &mut Self::ProofTreeBuilder,
124 ) -> (QueryResult<I>, AccessedOpaques<I>) {
125 EvalCtxt::enter_canonical(cx, search_graph, input, inspect, |ecx, goal| {
126 let result = ecx.compute_goal(goal).map_err_to_rerun()?;
128
129 ecx.inspect.query_result(result);
130 result.map_err(Into::into)
131 })
132 }
133}
134
135fn response_no_constraints<I: Interner>(
136 cx: I,
137 input: I::CanonicalInput,
138 certainty: Certainty,
139) -> (QueryResult<I>, AccessedOpaques<I>) {
140 (
141 Ok(response_no_constraints_raw(
142 cx,
143 input.canonical.max_universe,
144 input.canonical.var_kinds,
145 certainty,
146 )),
147 AccessedOpaques::default(),
148 )
149}