rustc_type_ir/solve/
mod.rs

1pub mod inspect;
2
3use std::hash::Hash;
4
5use derive_where::derive_where;
6#[cfg(feature = "nightly")]
7use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
8use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
9
10use crate::lang_items::SolverTraitLangItem;
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, Hash, PartialEq, Debug; I: Interner, P)]
35#[derive_where(Copy; I: Interner, P: Copy)]
36#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
37#[cfg_attr(
38    feature = "nightly",
39    derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
40)]
41pub struct Goal<I: Interner, P> {
42    pub param_env: I::ParamEnv,
43    pub predicate: P,
44}
45
46impl<I: Interner, P: Eq> Eq for Goal<I, P> {}
47
48impl<I: Interner, P> Goal<I, P> {
49    pub fn new(cx: I, param_env: I::ParamEnv, predicate: impl Upcast<I, P>) -> Goal<I, P> {
50        Goal { param_env, predicate: predicate.upcast(cx) }
51    }
52
53    /// Updates the goal to one with a different `predicate` but the same `param_env`.
54    pub fn with<Q>(self, cx: I, predicate: impl Upcast<I, Q>) -> Goal<I, Q> {
55        Goal { param_env: self.param_env, predicate: predicate.upcast(cx) }
56    }
57}
58
59/// Why a specific goal has to be proven.
60///
61/// This is necessary as we treat nested goals different depending on
62/// their source. This is used to decide whether a cycle is coinductive.
63/// See the documentation of `EvalCtxt::step_kind_for_source` for more details
64/// about this.
65///
66/// It is also used by proof tree visitors, e.g. for diagnostics purposes.
67#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
68#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
69pub enum GoalSource {
70    Misc,
71    /// A nested goal required to prove that types are equal/subtypes.
72    /// This is always an unproductive step.
73    ///
74    /// This is also used for all `NormalizesTo` goals as we they are used
75    /// to relate types in `AliasRelate`.
76    TypeRelating,
77    /// We're proving a where-bound of an impl.
78    ImplWhereBound,
79    /// Const conditions that need to hold for `[const]` alias bounds to hold.
80    AliasBoundConstCondition,
81    /// Instantiating a higher-ranked goal and re-proving it.
82    InstantiateHigherRanked,
83    /// Predicate required for an alias projection to be well-formed.
84    /// This is used in three places:
85    /// 1. projecting to an opaque whose hidden type is already registered in
86    ///    the opaque type storage,
87    /// 2. for rigid projections's trait goal,
88    /// 3. for GAT where clauses.
89    AliasWellFormed,
90    /// In case normalizing aliases in nested goals cycles, eagerly normalizing these
91    /// aliases in the context of the parent may incorrectly change the cycle kind.
92    /// Normalizing aliases in goals therefore tracks the original path kind for this
93    /// nested goal. See the comment of the `ReplaceAliasWithInfer` visitor for more
94    /// details.
95    NormalizeGoal(PathKind),
96}
97
98#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, Goal<I, P>)]
99#[derive_where(Copy; I: Interner, Goal<I, P>: Copy)]
100#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
101#[cfg_attr(
102    feature = "nightly",
103    derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
104)]
105pub struct QueryInput<I: Interner, P> {
106    pub goal: Goal<I, P>,
107    pub predefined_opaques_in_body: I::PredefinedOpaques,
108}
109
110impl<I: Interner, P: Eq> Eq for QueryInput<I, P> {}
111
112/// Opaques that are defined in the inference context before a query is called.
113#[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)]
114#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
115#[cfg_attr(
116    feature = "nightly",
117    derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
118)]
119pub struct PredefinedOpaquesData<I: Interner> {
120    pub opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>,
121}
122
123impl<I: Interner> Eq for PredefinedOpaquesData<I> {}
124
125/// Possible ways the given goal can be proven.
126#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
127pub enum CandidateSource<I: Interner> {
128    /// A user written impl.
129    ///
130    /// ## Examples
131    ///
132    /// ```rust
133    /// fn main() {
134    ///     let x: Vec<u32> = Vec::new();
135    ///     // This uses the impl from the standard library to prove `Vec<T>: Clone`.
136    ///     let y = x.clone();
137    /// }
138    /// ```
139    Impl(I::ImplId),
140    /// A builtin impl generated by the compiler. When adding a new special
141    /// trait, try to use actual impls whenever possible. Builtin impls should
142    /// only be used in cases where the impl cannot be manually be written.
143    ///
144    /// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
145    /// For a list of all traits with builtin impls, check out the
146    /// `EvalCtxt::assemble_builtin_impl_candidates` method.
147    BuiltinImpl(BuiltinImplSource),
148    /// An assumption from the environment. Stores a [`ParamEnvSource`], since we
149    /// prefer non-global param-env candidates in candidate assembly.
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(ParamEnvSource),
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
189impl<I: Interner> Eq for CandidateSource<I> {}
190
191#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
192pub enum ParamEnvSource {
193    /// Preferred eagerly.
194    NonGlobal,
195    // Not considered unless there are non-global param-env candidates too.
196    Global,
197}
198
199#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
200#[cfg_attr(
201    feature = "nightly",
202    derive(HashStable_NoContext, Encodable_NoContext, Decodable_NoContext)
203)]
204pub enum BuiltinImplSource {
205    /// A built-in impl that is considered trivial, without any nested requirements. They
206    /// are preferred over where-clauses, and we want to track them explicitly.
207    Trivial,
208    /// Some built-in impl we don't need to differentiate. This should be used
209    /// unless more specific information is necessary.
210    Misc,
211    /// A built-in impl for trait objects. The index is only used in winnowing.
212    Object(usize),
213    /// A built-in implementation of `Upcast` for trait objects to other trait objects.
214    ///
215    /// The index is only used for winnowing.
216    TraitUpcasting(usize),
217}
218
219#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
220#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
221#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
222pub struct Response<I: Interner> {
223    pub certainty: Certainty,
224    pub var_values: CanonicalVarValues<I>,
225    /// Additional constraints returned by this query.
226    pub external_constraints: I::ExternalConstraints,
227}
228
229impl<I: Interner> Eq for Response<I> {}
230
231/// Additional constraints returned on success.
232#[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)]
233#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
234#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
235pub struct ExternalConstraintsData<I: Interner> {
236    pub region_constraints: Vec<ty::OutlivesPredicate<I, I::GenericArg>>,
237    pub opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>,
238    pub normalization_nested_goals: NestedNormalizationGoals<I>,
239}
240
241impl<I: Interner> Eq for ExternalConstraintsData<I> {}
242
243impl<I: Interner> ExternalConstraintsData<I> {
244    pub fn is_empty(&self) -> bool {
245        self.region_constraints.is_empty()
246            && self.opaque_types.is_empty()
247            && self.normalization_nested_goals.is_empty()
248    }
249}
250
251#[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)]
252#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
253#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
254pub struct NestedNormalizationGoals<I: Interner>(pub Vec<(GoalSource, Goal<I, I::Predicate>)>);
255
256impl<I: Interner> Eq for NestedNormalizationGoals<I> {}
257
258impl<I: Interner> NestedNormalizationGoals<I> {
259    pub fn empty() -> Self {
260        NestedNormalizationGoals(vec![])
261    }
262
263    pub fn is_empty(&self) -> bool {
264        self.0.is_empty()
265    }
266}
267
268#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
269#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
270pub enum Certainty {
271    Yes,
272    Maybe(MaybeCause),
273}
274
275impl Certainty {
276    pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
277
278    /// Use this function to merge the certainty of multiple nested subgoals.
279    ///
280    /// Given an impl like `impl<T: Foo + Bar> Baz for T {}`, we have 2 nested
281    /// subgoals whenever we use the impl as a candidate: `T: Foo` and `T: Bar`.
282    /// If evaluating `T: Foo` results in ambiguity and `T: Bar` results in
283    /// success, we merge these two responses. This results in ambiguity.
284    ///
285    /// If we unify ambiguity with overflow, we return overflow. This doesn't matter
286    /// inside of the solver as we do not distinguish ambiguity from overflow. It does
287    /// however matter for diagnostics. If `T: Foo` resulted in overflow and `T: Bar`
288    /// in ambiguity without changing the inference state, we still want to tell the
289    /// user that `T: Baz` results in overflow.
290    pub fn and(self, other: Certainty) -> Certainty {
291        match (self, other) {
292            (Certainty::Yes, Certainty::Yes) => Certainty::Yes,
293            (Certainty::Yes, Certainty::Maybe(_)) => other,
294            (Certainty::Maybe(_), Certainty::Yes) => self,
295            (Certainty::Maybe(a), Certainty::Maybe(b)) => Certainty::Maybe(a.and(b)),
296        }
297    }
298
299    pub const fn overflow(suggest_increasing_limit: bool) -> Certainty {
300        Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit, keep_constraints: false })
301    }
302}
303
304/// Why we failed to evaluate a goal.
305#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
306#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
307pub enum MaybeCause {
308    /// We failed due to ambiguity. This ambiguity can either
309    /// be a true ambiguity, i.e. there are multiple different answers,
310    /// or we hit a case where we just don't bother, e.g. `?x: Trait` goals.
311    Ambiguity,
312    /// We gave up due to an overflow, most often by hitting the recursion limit.
313    Overflow { suggest_increasing_limit: bool, keep_constraints: bool },
314}
315
316impl MaybeCause {
317    fn and(self, other: MaybeCause) -> MaybeCause {
318        match (self, other) {
319            (MaybeCause::Ambiguity, MaybeCause::Ambiguity) => MaybeCause::Ambiguity,
320            (MaybeCause::Ambiguity, MaybeCause::Overflow { .. }) => other,
321            (MaybeCause::Overflow { .. }, MaybeCause::Ambiguity) => self,
322            (
323                MaybeCause::Overflow {
324                    suggest_increasing_limit: limit_a,
325                    keep_constraints: keep_a,
326                },
327                MaybeCause::Overflow {
328                    suggest_increasing_limit: limit_b,
329                    keep_constraints: keep_b,
330                },
331            ) => MaybeCause::Overflow {
332                suggest_increasing_limit: limit_a && limit_b,
333                keep_constraints: keep_a && keep_b,
334            },
335        }
336    }
337
338    pub fn or(self, other: MaybeCause) -> MaybeCause {
339        match (self, other) {
340            (MaybeCause::Ambiguity, MaybeCause::Ambiguity) => MaybeCause::Ambiguity,
341
342            // When combining ambiguity + overflow, we can keep constraints.
343            (
344                MaybeCause::Ambiguity,
345                MaybeCause::Overflow { suggest_increasing_limit, keep_constraints: _ },
346            ) => MaybeCause::Overflow { suggest_increasing_limit, keep_constraints: true },
347            (
348                MaybeCause::Overflow { suggest_increasing_limit, keep_constraints: _ },
349                MaybeCause::Ambiguity,
350            ) => MaybeCause::Overflow { suggest_increasing_limit, keep_constraints: true },
351
352            (
353                MaybeCause::Overflow {
354                    suggest_increasing_limit: limit_a,
355                    keep_constraints: keep_a,
356                },
357                MaybeCause::Overflow {
358                    suggest_increasing_limit: limit_b,
359                    keep_constraints: keep_b,
360                },
361            ) => MaybeCause::Overflow {
362                suggest_increasing_limit: limit_a || limit_b,
363                keep_constraints: keep_a || keep_b,
364            },
365        }
366    }
367}
368
369/// Indicates that a `impl Drop for Adt` is `const` or not.
370#[derive(Debug)]
371pub enum AdtDestructorKind {
372    NotConst,
373    Const,
374}
375
376/// Which sizedness trait - `Sized`, `MetaSized`? `PointeeSized` is omitted as it is removed during
377/// lowering.
378#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
379#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
380pub enum SizedTraitKind {
381    /// `Sized` trait
382    Sized,
383    /// `MetaSized` trait
384    MetaSized,
385}
386
387impl SizedTraitKind {
388    /// Returns `DefId` of corresponding language item.
389    pub fn require_lang_item<I: Interner>(self, cx: I) -> I::TraitId {
390        cx.require_trait_lang_item(match self {
391            SizedTraitKind::Sized => SolverTraitLangItem::Sized,
392            SizedTraitKind::MetaSized => SolverTraitLangItem::MetaSized,
393        })
394    }
395}