rustc_type_ir/solve/mod.rs
1pub mod inspect;
2
3use std::fmt;
4use std::hash::Hash;
5
6use derive_where::derive_where;
7#[cfg(feature = "nightly")]
8use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
9use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
10
11use crate::search_graph::PathKind;
12use crate::{self as ty, Canonical, CanonicalVarValues, Interner, Upcast};
13
14pub type CanonicalInput<I, T = <I as Interner>::Predicate> =
15 ty::CanonicalQueryInput<I, QueryInput<I, T>>;
16pub type CanonicalResponse<I> = Canonical<I, Response<I>>;
17/// The result of evaluating a canonical query.
18///
19/// FIXME: We use a different type than the existing canonical queries. This is because
20/// we need to add a `Certainty` for `overflow` and may want to restructure this code without
21/// having to worry about changes to currently used code. Once we've made progress on this
22/// solver, merge the two responses again.
23pub type QueryResult<I> = Result<CanonicalResponse<I>, NoSolution>;
24
25#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
26#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
27pub struct NoSolution;
28
29/// A goal is a statement, i.e. `predicate`, we want to prove
30/// given some assumptions, i.e. `param_env`.
31///
32/// Most of the time the `param_env` contains the `where`-bounds of the function
33/// we're currently typechecking while the `predicate` is some trait bound.
34#[derive_where(Clone; I: Interner, P: Clone)]
35#[derive_where(Copy; I: Interner, P: Copy)]
36#[derive_where(Hash; I: Interner, P: Hash)]
37#[derive_where(PartialEq; I: Interner, P: PartialEq)]
38#[derive_where(Eq; I: Interner, P: Eq)]
39#[derive_where(Debug; I: Interner, P: fmt::Debug)]
40#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
41#[cfg_attr(
42 feature = "nightly",
43 derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
44)]
45pub struct Goal<I: Interner, P> {
46 pub param_env: I::ParamEnv,
47 pub predicate: P,
48}
49
50impl<I: Interner, P> Goal<I, P> {
51 pub fn new(cx: I, param_env: I::ParamEnv, predicate: impl Upcast<I, P>) -> Goal<I, P> {
52 Goal { param_env, predicate: predicate.upcast(cx) }
53 }
54
55 /// Updates the goal to one with a different `predicate` but the same `param_env`.
56 pub fn with<Q>(self, cx: I, predicate: impl Upcast<I, Q>) -> Goal<I, Q> {
57 Goal { param_env: self.param_env, predicate: predicate.upcast(cx) }
58 }
59}
60
61/// Why a specific goal has to be proven.
62///
63/// This is necessary as we treat nested goals different depending on
64/// their source. This is used to decide whether a cycle is coinductive.
65/// See the documentation of `EvalCtxt::step_kind_for_source` for more details
66/// about this.
67///
68/// It is also used by proof tree visitors, e.g. for diagnostics purposes.
69#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
70#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
71pub enum GoalSource {
72 Misc,
73 /// A nested goal required to prove that types are equal/subtypes.
74 /// This is always an unproductive step.
75 ///
76 /// This is also used for all `NormalizesTo` goals as we they are used
77 /// to relate types in `AliasRelate`.
78 TypeRelating,
79 /// We're proving a where-bound of an impl.
80 ImplWhereBound,
81 /// Const conditions that need to hold for `~const` alias bounds to hold.
82 AliasBoundConstCondition,
83 /// Instantiating a higher-ranked goal and re-proving it.
84 InstantiateHigherRanked,
85 /// Predicate required for an alias projection to be well-formed.
86 /// This is used in two places: projecting to an opaque whose hidden type
87 /// is already registered in the opaque type storage, and for rigid projections.
88 AliasWellFormed,
89 /// In case normalizing aliases in nested goals cycles, eagerly normalizing these
90 /// aliases in the context of the parent may incorrectly change the cycle kind.
91 /// Normalizing aliases in goals therefore tracks the original path kind for this
92 /// nested goal. See the comment of the `ReplaceAliasWithInfer` visitor for more
93 /// details.
94 NormalizeGoal(PathKind),
95}
96
97#[derive_where(Clone; I: Interner, Goal<I, P>: Clone)]
98#[derive_where(Copy; I: Interner, Goal<I, P>: Copy)]
99#[derive_where(Hash; I: Interner, Goal<I, P>: Hash)]
100#[derive_where(PartialEq; I: Interner, Goal<I, P>: PartialEq)]
101#[derive_where(Eq; I: Interner, Goal<I, P>: Eq)]
102#[derive_where(Debug; I: Interner, Goal<I, P>: fmt::Debug)]
103#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
104#[cfg_attr(
105 feature = "nightly",
106 derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
107)]
108pub struct QueryInput<I: Interner, P> {
109 pub goal: Goal<I, P>,
110 pub predefined_opaques_in_body: I::PredefinedOpaques,
111}
112
113/// Opaques that are defined in the inference context before a query is called.
114#[derive_where(Clone, Hash, PartialEq, Eq, Debug, Default; I: Interner)]
115#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
116#[cfg_attr(
117 feature = "nightly",
118 derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
119)]
120pub struct PredefinedOpaquesData<I: Interner> {
121 pub opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>,
122}
123
124/// Possible ways the given goal can be proven.
125#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
126pub enum CandidateSource<I: Interner> {
127 /// A user written impl.
128 ///
129 /// ## Examples
130 ///
131 /// ```rust
132 /// fn main() {
133 /// let x: Vec<u32> = Vec::new();
134 /// // This uses the impl from the standard library to prove `Vec<T>: Clone`.
135 /// let y = x.clone();
136 /// }
137 /// ```
138 Impl(I::DefId),
139 /// A builtin impl generated by the compiler. When adding a new special
140 /// trait, try to use actual impls whenever possible. Builtin impls should
141 /// only be used in cases where the impl cannot be manually be written.
142 ///
143 /// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
144 /// For a list of all traits with builtin impls, check out the
145 /// `EvalCtxt::assemble_builtin_impl_candidates` method.
146 BuiltinImpl(BuiltinImplSource),
147 /// An assumption from the environment.
148 ///
149 /// More precisely we've used the `n-th` assumption in the `param_env`.
150 ///
151 /// ## Examples
152 ///
153 /// ```rust
154 /// fn is_clone<T: Clone>(x: T) -> (T, T) {
155 /// // This uses the assumption `T: Clone` from the `where`-bounds
156 /// // to prove `T: Clone`.
157 /// (x.clone(), x)
158 /// }
159 /// ```
160 ParamEnv(usize),
161 /// If the self type is an alias type, e.g. an opaque type or a projection,
162 /// we know the bounds on that alias to hold even without knowing its concrete
163 /// underlying type.
164 ///
165 /// More precisely this candidate is using the `n-th` bound in the `item_bounds` of
166 /// the self type.
167 ///
168 /// ## Examples
169 ///
170 /// ```rust
171 /// trait Trait {
172 /// type Assoc: Clone;
173 /// }
174 ///
175 /// fn foo<T: Trait>(x: <T as Trait>::Assoc) {
176 /// // We prove `<T as Trait>::Assoc` by looking at the bounds on `Assoc` in
177 /// // in the trait definition.
178 /// let _y = x.clone();
179 /// }
180 /// ```
181 AliasBound,
182 /// A candidate that is registered only during coherence to represent some
183 /// yet-unknown impl that could be produced downstream without violating orphan
184 /// rules.
185 // FIXME: Merge this with the forced ambiguity candidates, so those don't use `Misc`.
186 CoherenceUnknowable,
187}
188
189#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
190#[cfg_attr(
191 feature = "nightly",
192 derive(HashStable_NoContext, Encodable_NoContext, Decodable_NoContext)
193)]
194pub enum BuiltinImplSource {
195 /// A built-in impl that is considered trivial, without any nested requirements. They
196 /// are preferred over where-clauses, and we want to track them explicitly.
197 Trivial,
198 /// Some built-in impl we don't need to differentiate. This should be used
199 /// unless more specific information is necessary.
200 Misc,
201 /// A built-in impl for trait objects. The index is only used in winnowing.
202 Object(usize),
203 /// A built-in implementation of `Upcast` for trait objects to other trait objects.
204 ///
205 /// The index is only used for winnowing.
206 TraitUpcasting(usize),
207}
208
209#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
210#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
211#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
212pub struct Response<I: Interner> {
213 pub certainty: Certainty,
214 pub var_values: CanonicalVarValues<I>,
215 /// Additional constraints returned by this query.
216 pub external_constraints: I::ExternalConstraints,
217}
218
219/// Additional constraints returned on success.
220#[derive_where(Clone, Hash, PartialEq, Eq, Debug, Default; I: Interner)]
221#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
222#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
223pub struct ExternalConstraintsData<I: Interner> {
224 pub region_constraints: Vec<ty::OutlivesPredicate<I, I::GenericArg>>,
225 pub opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>,
226 pub normalization_nested_goals: NestedNormalizationGoals<I>,
227}
228
229#[derive_where(Clone, Hash, PartialEq, Eq, Debug, Default; I: Interner)]
230#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
231#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
232pub struct NestedNormalizationGoals<I: Interner>(pub Vec<(GoalSource, Goal<I, I::Predicate>)>);
233
234impl<I: Interner> NestedNormalizationGoals<I> {
235 pub fn empty() -> Self {
236 NestedNormalizationGoals(vec![])
237 }
238
239 pub fn is_empty(&self) -> bool {
240 self.0.is_empty()
241 }
242}
243
244#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
245#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
246pub enum Certainty {
247 Yes,
248 Maybe(MaybeCause),
249}
250
251impl Certainty {
252 pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
253
254 /// Use this function to merge the certainty of multiple nested subgoals.
255 ///
256 /// Given an impl like `impl<T: Foo + Bar> Baz for T {}`, we have 2 nested
257 /// subgoals whenever we use the impl as a candidate: `T: Foo` and `T: Bar`.
258 /// If evaluating `T: Foo` results in ambiguity and `T: Bar` results in
259 /// success, we merge these two responses. This results in ambiguity.
260 ///
261 /// If we unify ambiguity with overflow, we return overflow. This doesn't matter
262 /// inside of the solver as we do not distinguish ambiguity from overflow. It does
263 /// however matter for diagnostics. If `T: Foo` resulted in overflow and `T: Bar`
264 /// in ambiguity without changing the inference state, we still want to tell the
265 /// user that `T: Baz` results in overflow.
266 pub fn unify_with(self, other: Certainty) -> Certainty {
267 match (self, other) {
268 (Certainty::Yes, Certainty::Yes) => Certainty::Yes,
269 (Certainty::Yes, Certainty::Maybe(_)) => other,
270 (Certainty::Maybe(_), Certainty::Yes) => self,
271 (Certainty::Maybe(a), Certainty::Maybe(b)) => Certainty::Maybe(a.unify_with(b)),
272 }
273 }
274
275 pub const fn overflow(suggest_increasing_limit: bool) -> Certainty {
276 Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit })
277 }
278}
279
280/// Why we failed to evaluate a goal.
281#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
282#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
283pub enum MaybeCause {
284 /// We failed due to ambiguity. This ambiguity can either
285 /// be a true ambiguity, i.e. there are multiple different answers,
286 /// or we hit a case where we just don't bother, e.g. `?x: Trait` goals.
287 Ambiguity,
288 /// We gave up due to an overflow, most often by hitting the recursion limit.
289 Overflow { suggest_increasing_limit: bool },
290}
291
292impl MaybeCause {
293 fn unify_with(self, other: MaybeCause) -> MaybeCause {
294 match (self, other) {
295 (MaybeCause::Ambiguity, MaybeCause::Ambiguity) => MaybeCause::Ambiguity,
296 (MaybeCause::Ambiguity, MaybeCause::Overflow { .. }) => other,
297 (MaybeCause::Overflow { .. }, MaybeCause::Ambiguity) => self,
298 (
299 MaybeCause::Overflow { suggest_increasing_limit: a },
300 MaybeCause::Overflow { suggest_increasing_limit: b },
301 ) => MaybeCause::Overflow { suggest_increasing_limit: a || b },
302 }
303 }
304}
305
306/// Indicates that a `impl Drop for Adt` is `const` or not.
307#[derive(Debug)]
308pub enum AdtDestructorKind {
309 NotConst,
310 Const,
311}