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