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