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::{
9 GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
10};
11
12use crate::lang_items::SolverTraitLangItem;
13use crate::search_graph::PathKind;
14use crate::{self as ty, Canonical, CanonicalVarValues, Interner, Upcast};
15
16pub type CanonicalInput<I, T = <I as Interner>::Predicate> =
17 ty::CanonicalQueryInput<I, QueryInput<I, T>>;
18pub type CanonicalResponse<I> = Canonical<I, Response<I>>;
19/// The result of evaluating a canonical query.
20///
21/// FIXME: We use a different type than the existing canonical queries. This is because
22/// we need to add a `Certainty` for `overflow` and may want to restructure this code without
23/// having to worry about changes to currently used code. Once we've made progress on this
24/// solver, merge the two responses again.
25pub type QueryResult<I> = Result<CanonicalResponse<I>, NoSolution>;
26
27#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
28#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
29pub struct NoSolution;
30
31/// A goal is a statement, i.e. `predicate`, we want to prove
32/// given some assumptions, i.e. `param_env`.
33///
34/// Most of the time the `param_env` contains the `where`-bounds of the function
35/// we're currently typechecking while the `predicate` is some trait bound.
36#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, P)]
37#[derive_where(Copy; I: Interner, P: Copy)]
38#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
39#[cfg_attr(
40 feature = "nightly",
41 derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
42)]
43pub struct Goal<I: Interner, P> {
44 pub param_env: I::ParamEnv,
45 pub predicate: P,
46}
47
48impl<I: Interner, P: Eq> Eq for Goal<I, P> {}
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 /// 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, GenericTypeVisitable, 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/// Which trait candidates should be preferred over other candidates? By default, prefer where
113/// bounds over alias bounds. For marker traits, prefer alias bounds over where bounds.
114#[derive(Clone, Copy, Debug)]
115pub enum CandidatePreferenceMode {
116 /// Prefers where bounds over alias bounds
117 Default,
118 /// Prefers alias bounds over where bounds
119 Marker,
120}
121
122impl CandidatePreferenceMode {
123 /// Given `trait_def_id`, which candidate preference mode should be used?
124 pub fn compute<I: Interner>(cx: I, trait_id: I::TraitId) -> CandidatePreferenceMode {
125 let is_sizedness_or_auto_or_default_goal = cx.is_sizedness_trait(trait_id)
126 || cx.trait_is_auto(trait_id)
127 || cx.is_default_trait(trait_id);
128 if is_sizedness_or_auto_or_default_goal {
129 CandidatePreferenceMode::Marker
130 } else {
131 CandidatePreferenceMode::Default
132 }
133 }
134}
135
136/// Possible ways the given goal can be proven.
137#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
138pub enum CandidateSource<I: Interner> {
139 /// A user written impl.
140 ///
141 /// ## Examples
142 ///
143 /// ```rust
144 /// fn main() {
145 /// let x: Vec<u32> = Vec::new();
146 /// // This uses the impl from the standard library to prove `Vec<T>: Clone`.
147 /// let y = x.clone();
148 /// }
149 /// ```
150 Impl(I::ImplId),
151 /// A builtin impl generated by the compiler. When adding a new special
152 /// trait, try to use actual impls whenever possible. Builtin impls should
153 /// only be used in cases where the impl cannot be manually be written.
154 ///
155 /// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
156 /// For a list of all traits with builtin impls, check out the
157 /// `EvalCtxt::assemble_builtin_impl_candidates` method.
158 BuiltinImpl(BuiltinImplSource),
159 /// An assumption from the environment. Stores a [`ParamEnvSource`], since we
160 /// prefer non-global param-env candidates in candidate assembly.
161 ///
162 /// ## Examples
163 ///
164 /// ```rust
165 /// fn is_clone<T: Clone>(x: T) -> (T, T) {
166 /// // This uses the assumption `T: Clone` from the `where`-bounds
167 /// // to prove `T: Clone`.
168 /// (x.clone(), x)
169 /// }
170 /// ```
171 ParamEnv(ParamEnvSource),
172 /// If the self type is an alias type, e.g. an opaque type or a projection,
173 /// we know the bounds on that alias to hold even without knowing its concrete
174 /// underlying type.
175 ///
176 /// More precisely this candidate is using the `n-th` bound in the `item_bounds` of
177 /// the self type.
178 ///
179 /// ## Examples
180 ///
181 /// ```rust
182 /// trait Trait {
183 /// type Assoc: Clone;
184 /// }
185 ///
186 /// fn foo<T: Trait>(x: <T as Trait>::Assoc) {
187 /// // We prove `<T as Trait>::Assoc` by looking at the bounds on `Assoc` in
188 /// // in the trait definition.
189 /// let _y = x.clone();
190 /// }
191 /// ```
192 AliasBound(AliasBoundKind),
193 /// A candidate that is registered only during coherence to represent some
194 /// yet-unknown impl that could be produced downstream without violating orphan
195 /// rules.
196 // FIXME: Merge this with the forced ambiguity candidates, so those don't use `Misc`.
197 CoherenceUnknowable,
198}
199
200impl<I: Interner> Eq for CandidateSource<I> {}
201
202#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
203pub enum ParamEnvSource {
204 /// Preferred eagerly.
205 NonGlobal,
206 // Not considered unless there are non-global param-env candidates too.
207 Global,
208}
209
210#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
211#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
212pub enum AliasBoundKind {
213 /// Alias bound from the self type of a projection
214 SelfBounds,
215 // Alias bound having recursed on the self type of a projection
216 NonSelfBounds,
217}
218
219#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
220#[cfg_attr(
221 feature = "nightly",
222 derive(HashStable_NoContext, Encodable_NoContext, Decodable_NoContext)
223)]
224pub enum BuiltinImplSource {
225 /// A built-in impl that is considered trivial, without any nested requirements. They
226 /// are preferred over where-clauses, and we want to track them explicitly.
227 Trivial,
228 /// Some built-in impl we don't need to differentiate. This should be used
229 /// unless more specific information is necessary.
230 Misc,
231 /// A built-in impl for trait objects. The index is only used in winnowing.
232 Object(usize),
233 /// A built-in implementation of `Upcast` for trait objects to other trait objects.
234 ///
235 /// The index is only used for winnowing.
236 TraitUpcasting(usize),
237}
238
239#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
240#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
241#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
242pub struct Response<I: Interner> {
243 pub certainty: Certainty,
244 pub var_values: CanonicalVarValues<I>,
245 /// Additional constraints returned by this query.
246 pub external_constraints: I::ExternalConstraints,
247}
248
249impl<I: Interner> Eq for Response<I> {}
250
251/// Additional constraints returned on success.
252#[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)]
253#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
254#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
255pub struct ExternalConstraintsData<I: Interner> {
256 pub region_constraints: Vec<ty::OutlivesPredicate<I, I::GenericArg>>,
257 pub opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>,
258 pub normalization_nested_goals: NestedNormalizationGoals<I>,
259}
260
261impl<I: Interner> Eq for ExternalConstraintsData<I> {}
262
263impl<I: Interner> ExternalConstraintsData<I> {
264 pub fn is_empty(&self) -> bool {
265 self.region_constraints.is_empty()
266 && self.opaque_types.is_empty()
267 && self.normalization_nested_goals.is_empty()
268 }
269}
270
271#[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)]
272#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
273#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
274pub struct NestedNormalizationGoals<I: Interner>(pub Vec<(GoalSource, Goal<I, I::Predicate>)>);
275
276impl<I: Interner> Eq for NestedNormalizationGoals<I> {}
277
278impl<I: Interner> NestedNormalizationGoals<I> {
279 pub fn empty() -> Self {
280 NestedNormalizationGoals(vec![])
281 }
282
283 pub fn is_empty(&self) -> bool {
284 self.0.is_empty()
285 }
286}
287
288#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
289#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
290pub enum Certainty {
291 Yes,
292 Maybe { cause: MaybeCause, opaque_types_jank: OpaqueTypesJank },
293}
294
295/// Supporting not-yet-defined opaque types in HIR typeck is somewhat
296/// challenging. Ideally we'd normalize them to a new inference variable
297/// and just defer type inference which relies on the opaque until we've
298/// constrained the hidden type.
299///
300/// This doesn't work for method and function calls as we need to guide type
301/// inference for the function arguments. We treat not-yet-defined opaque types
302/// as if they were rigid instead in these places.
303///
304/// When we encounter a `?hidden_type_of_opaque: Trait<?var>` goal, we use the
305/// item bounds and blanket impls to guide inference by constraining other type
306/// variables, see `EvalCtxt::try_assemble_bounds_via_registered_opaques`. We
307/// always keep the certainty as `Maybe` so that we properly prove these goals
308/// once the hidden type has been constrained.
309///
310/// If we fail to prove the trait goal via item bounds or blanket impls, the
311/// goal would have errored if the opaque type were rigid. In this case, we
312/// set `OpaqueTypesJank::ErrorIfRigidSelfTy` in the [Certainty].
313///
314/// Places in HIR typeck where we want to treat not-yet-defined opaque types as if
315/// they were kind of rigid then use `fn root_goal_may_hold_opaque_types_jank` which
316/// returns `false` if the goal doesn't hold or if `OpaqueTypesJank::ErrorIfRigidSelfTy`
317/// is set (i.e. proving it required relies on some `?hidden_ty: NotInItemBounds` goal).
318///
319/// This is subtly different from actually treating not-yet-defined opaque types as
320/// rigid, e.g. it allows constraining opaque types if they are not the self-type of
321/// a goal. It is good enough for now and only matters for very rare type inference
322/// edge cases. We can improve this later on if necessary.
323#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
324#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
325pub enum OpaqueTypesJank {
326 AllGood,
327 ErrorIfRigidSelfTy,
328}
329impl OpaqueTypesJank {
330 fn and(self, other: OpaqueTypesJank) -> OpaqueTypesJank {
331 match (self, other) {
332 (OpaqueTypesJank::AllGood, OpaqueTypesJank::AllGood) => OpaqueTypesJank::AllGood,
333 (OpaqueTypesJank::ErrorIfRigidSelfTy, _) | (_, OpaqueTypesJank::ErrorIfRigidSelfTy) => {
334 OpaqueTypesJank::ErrorIfRigidSelfTy
335 }
336 }
337 }
338
339 pub fn or(self, other: OpaqueTypesJank) -> OpaqueTypesJank {
340 match (self, other) {
341 (OpaqueTypesJank::ErrorIfRigidSelfTy, OpaqueTypesJank::ErrorIfRigidSelfTy) => {
342 OpaqueTypesJank::ErrorIfRigidSelfTy
343 }
344 (OpaqueTypesJank::AllGood, _) | (_, OpaqueTypesJank::AllGood) => {
345 OpaqueTypesJank::AllGood
346 }
347 }
348 }
349}
350
351impl Certainty {
352 pub const AMBIGUOUS: Certainty = Certainty::Maybe {
353 cause: MaybeCause::Ambiguity,
354 opaque_types_jank: OpaqueTypesJank::AllGood,
355 };
356
357 /// Use this function to merge the certainty of multiple nested subgoals.
358 ///
359 /// Given an impl like `impl<T: Foo + Bar> Baz for T {}`, we have 2 nested
360 /// subgoals whenever we use the impl as a candidate: `T: Foo` and `T: Bar`.
361 /// If evaluating `T: Foo` results in ambiguity and `T: Bar` results in
362 /// success, we merge these two responses. This results in ambiguity.
363 ///
364 /// If we unify ambiguity with overflow, we return overflow. This doesn't matter
365 /// inside of the solver as we do not distinguish ambiguity from overflow. It does
366 /// however matter for diagnostics. If `T: Foo` resulted in overflow and `T: Bar`
367 /// in ambiguity without changing the inference state, we still want to tell the
368 /// user that `T: Baz` results in overflow.
369 pub fn and(self, other: Certainty) -> Certainty {
370 match (self, other) {
371 (Certainty::Yes, Certainty::Yes) => Certainty::Yes,
372 (Certainty::Yes, Certainty::Maybe { .. }) => other,
373 (Certainty::Maybe { .. }, Certainty::Yes) => self,
374 (
375 Certainty::Maybe { cause: a_cause, opaque_types_jank: a_jank },
376 Certainty::Maybe { cause: b_cause, opaque_types_jank: b_jank },
377 ) => Certainty::Maybe {
378 cause: a_cause.and(b_cause),
379 opaque_types_jank: a_jank.and(b_jank),
380 },
381 }
382 }
383
384 pub const fn overflow(suggest_increasing_limit: bool) -> Certainty {
385 Certainty::Maybe {
386 cause: MaybeCause::Overflow { suggest_increasing_limit, keep_constraints: false },
387 opaque_types_jank: OpaqueTypesJank::AllGood,
388 }
389 }
390}
391
392/// Why we failed to evaluate a goal.
393#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
394#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
395pub enum MaybeCause {
396 /// We failed due to ambiguity. This ambiguity can either
397 /// be a true ambiguity, i.e. there are multiple different answers,
398 /// or we hit a case where we just don't bother, e.g. `?x: Trait` goals.
399 Ambiguity,
400 /// We gave up due to an overflow, most often by hitting the recursion limit.
401 Overflow { suggest_increasing_limit: bool, keep_constraints: bool },
402}
403
404impl MaybeCause {
405 fn and(self, other: MaybeCause) -> MaybeCause {
406 match (self, other) {
407 (MaybeCause::Ambiguity, MaybeCause::Ambiguity) => MaybeCause::Ambiguity,
408 (MaybeCause::Ambiguity, MaybeCause::Overflow { .. }) => other,
409 (MaybeCause::Overflow { .. }, MaybeCause::Ambiguity) => self,
410 (
411 MaybeCause::Overflow {
412 suggest_increasing_limit: limit_a,
413 keep_constraints: keep_a,
414 },
415 MaybeCause::Overflow {
416 suggest_increasing_limit: limit_b,
417 keep_constraints: keep_b,
418 },
419 ) => MaybeCause::Overflow {
420 suggest_increasing_limit: limit_a && limit_b,
421 keep_constraints: keep_a && keep_b,
422 },
423 }
424 }
425
426 pub fn or(self, other: MaybeCause) -> MaybeCause {
427 match (self, other) {
428 (MaybeCause::Ambiguity, MaybeCause::Ambiguity) => MaybeCause::Ambiguity,
429
430 // When combining ambiguity + overflow, we can keep constraints.
431 (
432 MaybeCause::Ambiguity,
433 MaybeCause::Overflow { suggest_increasing_limit, keep_constraints: _ },
434 ) => MaybeCause::Overflow { suggest_increasing_limit, keep_constraints: true },
435 (
436 MaybeCause::Overflow { suggest_increasing_limit, keep_constraints: _ },
437 MaybeCause::Ambiguity,
438 ) => MaybeCause::Overflow { suggest_increasing_limit, keep_constraints: true },
439
440 (
441 MaybeCause::Overflow {
442 suggest_increasing_limit: limit_a,
443 keep_constraints: keep_a,
444 },
445 MaybeCause::Overflow {
446 suggest_increasing_limit: limit_b,
447 keep_constraints: keep_b,
448 },
449 ) => MaybeCause::Overflow {
450 suggest_increasing_limit: limit_a || limit_b,
451 keep_constraints: keep_a || keep_b,
452 },
453 }
454 }
455}
456
457/// Indicates that a `impl Drop for Adt` is `const` or not.
458#[derive(Debug)]
459pub enum AdtDestructorKind {
460 NotConst,
461 Const,
462}
463
464/// Which sizedness trait - `Sized`, `MetaSized`? `PointeeSized` is omitted as it is removed during
465/// lowering.
466#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
467#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
468pub enum SizedTraitKind {
469 /// `Sized` trait
470 Sized,
471 /// `MetaSized` trait
472 MetaSized,
473}
474
475impl SizedTraitKind {
476 /// Returns `DefId` of corresponding language item.
477 pub fn require_lang_item<I: Interner>(self, cx: I) -> I::TraitId {
478 cx.require_trait_lang_item(match self {
479 SizedTraitKind::Sized => SolverTraitLangItem::Sized,
480 SizedTraitKind::MetaSized => SolverTraitLangItem::MetaSized,
481 })
482 }
483}