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}