]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/traits/select.rs
Auto merge of #102795 - lukas-code:constify-is-aligned-via-align-offset, r=oli-obk
[rust.git] / compiler / rustc_middle / src / traits / select.rs
1 //! Candidate selection. See the [rustc dev guide] for more information on how this works.
2 //!
3 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection
4
5 use self::EvaluationResult::*;
6
7 use super::{SelectionError, SelectionResult};
8 use rustc_errors::ErrorGuaranteed;
9
10 use crate::ty;
11
12 use rustc_hir::def_id::DefId;
13 use rustc_query_system::cache::Cache;
14
15 pub type SelectionCache<'tcx> = Cache<
16     // This cache does not use `ParamEnvAnd` in its keys because `ParamEnv::and` can replace
17     // caller bounds with an empty list if the `TraitPredicate` looks global, which may happen
18     // after erasing lifetimes from the predicate.
19     (ty::ParamEnv<'tcx>, ty::TraitPredicate<'tcx>),
20     SelectionResult<'tcx, SelectionCandidate<'tcx>>,
21 >;
22
23 pub type EvaluationCache<'tcx> = Cache<
24     // See above: this cache does not use `ParamEnvAnd` in its keys due to sometimes incorrectly
25     // caching with the wrong `ParamEnv`.
26     (ty::ParamEnv<'tcx>, ty::PolyTraitPredicate<'tcx>),
27     EvaluationResult,
28 >;
29
30 /// The selection process begins by considering all impls, where
31 /// clauses, and so forth that might resolve an obligation. Sometimes
32 /// we'll be able to say definitively that (e.g.) an impl does not
33 /// apply to the obligation: perhaps it is defined for `usize` but the
34 /// obligation is for `i32`. In that case, we drop the impl out of the
35 /// list. But the other cases are considered *candidates*.
36 ///
37 /// For selection to succeed, there must be exactly one matching
38 /// candidate. If the obligation is fully known, this is guaranteed
39 /// by coherence. However, if the obligation contains type parameters
40 /// or variables, there may be multiple such impls.
41 ///
42 /// It is not a real problem if multiple matching impls exist because
43 /// of type variables - it just means the obligation isn't sufficiently
44 /// elaborated. In that case we report an ambiguity, and the caller can
45 /// try again after more type information has been gathered or report a
46 /// "type annotations needed" error.
47 ///
48 /// However, with type parameters, this can be a real problem - type
49 /// parameters don't unify with regular types, but they *can* unify
50 /// with variables from blanket impls, and (unless we know its bounds
51 /// will always be satisfied) picking the blanket impl will be wrong
52 /// for at least *some* substitutions. To make this concrete, if we have
53 ///
54 /// ```rust, ignore
55 /// trait AsDebug { type Out: fmt::Debug; fn debug(self) -> Self::Out; }
56 /// impl<T: fmt::Debug> AsDebug for T {
57 ///     type Out = T;
58 ///     fn debug(self) -> fmt::Debug { self }
59 /// }
60 /// fn foo<T: AsDebug>(t: T) { println!("{:?}", <T as AsDebug>::debug(t)); }
61 /// ```
62 ///
63 /// we can't just use the impl to resolve the `<T as AsDebug>` obligation
64 /// -- a type from another crate (that doesn't implement `fmt::Debug`) could
65 /// implement `AsDebug`.
66 ///
67 /// Because where-clauses match the type exactly, multiple clauses can
68 /// only match if there are unresolved variables, and we can mostly just
69 /// report this ambiguity in that case. This is still a problem - we can't
70 /// *do anything* with ambiguities that involve only regions. This is issue
71 /// #21974.
72 ///
73 /// If a single where-clause matches and there are no inference
74 /// variables left, then it definitely matches and we can just select
75 /// it.
76 ///
77 /// In fact, we even select the where-clause when the obligation contains
78 /// inference variables. The can lead to inference making "leaps of logic",
79 /// for example in this situation:
80 ///
81 /// ```rust, ignore
82 /// pub trait Foo<T> { fn foo(&self) -> T; }
83 /// impl<T> Foo<()> for T { fn foo(&self) { } }
84 /// impl Foo<bool> for bool { fn foo(&self) -> bool { *self } }
85 ///
86 /// pub fn foo<T>(t: T) where T: Foo<bool> {
87 ///     println!("{:?}", <T as Foo<_>>::foo(&t));
88 /// }
89 /// fn main() { foo(false); }
90 /// ```
91 ///
92 /// Here the obligation `<T as Foo<$0>>` can be matched by both the blanket
93 /// impl and the where-clause. We select the where-clause and unify `$0=bool`,
94 /// so the program prints "false". However, if the where-clause is omitted,
95 /// the blanket impl is selected, we unify `$0=()`, and the program prints
96 /// "()".
97 ///
98 /// Exactly the same issues apply to projection and object candidates, except
99 /// that we can have both a projection candidate and a where-clause candidate
100 /// for the same obligation. In that case either would do (except that
101 /// different "leaps of logic" would occur if inference variables are
102 /// present), and we just pick the where-clause. This is, for example,
103 /// required for associated types to work in default impls, as the bounds
104 /// are visible both as projection bounds and as where-clauses from the
105 /// parameter environment.
106 #[derive(PartialEq, Eq, Debug, Clone, TypeFoldable, TypeVisitable)]
107 pub enum SelectionCandidate<'tcx> {
108     BuiltinCandidate {
109         /// `false` if there are no *further* obligations.
110         has_nested: bool,
111     },
112
113     /// Implementation of transmutability trait.
114     TransmutabilityCandidate,
115
116     ParamCandidate(ty::PolyTraitPredicate<'tcx>),
117     ImplCandidate(DefId),
118     AutoImplCandidate,
119
120     /// This is a trait matching with a projected type as `Self`, and we found
121     /// an applicable bound in the trait definition. The `usize` is an index
122     /// into the list returned by `tcx.item_bounds`. The constness is the
123     /// constness of the bound in the trait.
124     ProjectionCandidate(usize, ty::BoundConstness),
125
126     /// Implementation of a `Fn`-family trait by one of the anonymous types
127     /// generated for an `||` expression.
128     ClosureCandidate,
129
130     /// Implementation of a `Generator` trait by one of the anonymous types
131     /// generated for a generator.
132     GeneratorCandidate,
133
134     /// Implementation of a `Fn`-family trait by one of the anonymous
135     /// types generated for a fn pointer type (e.g., `fn(int) -> int`)
136     FnPointerCandidate {
137         is_const: bool,
138     },
139
140     /// Builtin implementation of `DiscriminantKind`.
141     DiscriminantKindCandidate,
142
143     /// Builtin implementation of `Pointee`.
144     PointeeCandidate,
145
146     TraitAliasCandidate,
147
148     /// Matching `dyn Trait` with a supertrait of `Trait`. The index is the
149     /// position in the iterator returned by
150     /// `rustc_infer::traits::util::supertraits`.
151     ObjectCandidate(usize),
152
153     /// Perform trait upcasting coercion of `dyn Trait` to a supertrait of `Trait`.
154     /// The index is the position in the iterator returned by
155     /// `rustc_infer::traits::util::supertraits`.
156     TraitUpcastingUnsizeCandidate(usize),
157
158     BuiltinObjectCandidate,
159
160     BuiltinUnsizeCandidate,
161
162     /// Implementation of `const Destruct`, optionally from a custom `impl const Drop`.
163     ConstDestructCandidate(Option<DefId>),
164 }
165
166 /// The result of trait evaluation. The order is important
167 /// here as the evaluation of a list is the maximum of the
168 /// evaluations.
169 ///
170 /// The evaluation results are ordered:
171 ///     - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions`
172 ///       implies `EvaluatedToAmbig` implies `EvaluatedToUnknown`
173 ///     - `EvaluatedToErr` implies `EvaluatedToRecur`
174 ///     - the "union" of evaluation results is equal to their maximum -
175 ///     all the "potential success" candidates can potentially succeed,
176 ///     so they are noops when unioned with a definite error, and within
177 ///     the categories it's easy to see that the unions are correct.
178 #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, HashStable)]
179 pub enum EvaluationResult {
180     /// Evaluation successful.
181     EvaluatedToOk,
182     /// Evaluation successful, but there were unevaluated region obligations.
183     EvaluatedToOkModuloRegions,
184     /// Evaluation successful, but need to rerun because opaque types got
185     /// hidden types assigned without it being known whether the opaque types
186     /// are within their defining scope
187     EvaluatedToOkModuloOpaqueTypes,
188     /// Evaluation is known to be ambiguous -- it *might* hold for some
189     /// assignment of inference variables, but it might not.
190     ///
191     /// While this has the same meaning as `EvaluatedToUnknown` -- we can't
192     /// know whether this obligation holds or not -- it is the result we
193     /// would get with an empty stack, and therefore is cacheable.
194     EvaluatedToAmbig,
195     /// Evaluation failed because of recursion involving inference
196     /// variables. We are somewhat imprecise there, so we don't actually
197     /// know the real result.
198     ///
199     /// This can't be trivially cached for the same reason as `EvaluatedToRecur`.
200     EvaluatedToUnknown,
201     /// Evaluation failed because we encountered an obligation we are already
202     /// trying to prove on this branch.
203     ///
204     /// We know this branch can't be a part of a minimal proof-tree for
205     /// the "root" of our cycle, because then we could cut out the recursion
206     /// and maintain a valid proof tree. However, this does not mean
207     /// that all the obligations on this branch do not hold -- it's possible
208     /// that we entered this branch "speculatively", and that there
209     /// might be some other way to prove this obligation that does not
210     /// go through this cycle -- so we can't cache this as a failure.
211     ///
212     /// For example, suppose we have this:
213     ///
214     /// ```rust,ignore (pseudo-Rust)
215     /// pub trait Trait { fn xyz(); }
216     /// // This impl is "useless", but we can still have
217     /// // an `impl Trait for SomeUnsizedType` somewhere.
218     /// impl<T: Trait + Sized> Trait for T { fn xyz() {} }
219     ///
220     /// pub fn foo<T: Trait + ?Sized>() {
221     ///     <T as Trait>::xyz();
222     /// }
223     /// ```
224     ///
225     /// When checking `foo`, we have to prove `T: Trait`. This basically
226     /// translates into this:
227     ///
228     /// ```plain,ignore
229     /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait
230     /// ```
231     ///
232     /// When we try to prove it, we first go the first option, which
233     /// recurses. This shows us that the impl is "useless" -- it won't
234     /// tell us that `T: Trait` unless it already implemented `Trait`
235     /// by some other means. However, that does not prevent `T: Trait`
236     /// does not hold, because of the bound (which can indeed be satisfied
237     /// by `SomeUnsizedType` from another crate).
238     //
239     // FIXME: when an `EvaluatedToRecur` goes past its parent root, we
240     // ought to convert it to an `EvaluatedToErr`, because we know
241     // there definitely isn't a proof tree for that obligation. Not
242     // doing so is still sound -- there isn't any proof tree, so the
243     // branch still can't be a part of a minimal one -- but does not re-enable caching.
244     EvaluatedToRecur,
245     /// Evaluation failed.
246     EvaluatedToErr,
247 }
248
249 impl EvaluationResult {
250     /// Returns `true` if this evaluation result is known to apply, even
251     /// considering outlives constraints.
252     pub fn must_apply_considering_regions(self) -> bool {
253         self == EvaluatedToOk
254     }
255
256     /// Returns `true` if this evaluation result is known to apply, ignoring
257     /// outlives constraints.
258     pub fn must_apply_modulo_regions(self) -> bool {
259         self <= EvaluatedToOkModuloRegions
260     }
261
262     pub fn may_apply(self) -> bool {
263         match self {
264             EvaluatedToOkModuloOpaqueTypes
265             | EvaluatedToOk
266             | EvaluatedToOkModuloRegions
267             | EvaluatedToAmbig
268             | EvaluatedToUnknown => true,
269
270             EvaluatedToErr | EvaluatedToRecur => false,
271         }
272     }
273
274     pub fn is_stack_dependent(self) -> bool {
275         match self {
276             EvaluatedToUnknown | EvaluatedToRecur => true,
277
278             EvaluatedToOkModuloOpaqueTypes
279             | EvaluatedToOk
280             | EvaluatedToOkModuloRegions
281             | EvaluatedToAmbig
282             | EvaluatedToErr => false,
283         }
284     }
285 }
286
287 /// Indicates that trait evaluation caused overflow and in which pass.
288 #[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
289 pub enum OverflowError {
290     Error(ErrorGuaranteed),
291     Canonical,
292     ErrorReporting,
293 }
294
295 impl From<ErrorGuaranteed> for OverflowError {
296     fn from(e: ErrorGuaranteed) -> OverflowError {
297         OverflowError::Error(e)
298     }
299 }
300
301 TrivialTypeTraversalAndLiftImpls! {
302     OverflowError,
303 }
304
305 impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
306     fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
307         match overflow_error {
308             OverflowError::Error(e) => SelectionError::Overflow(OverflowError::Error(e)),
309             OverflowError::Canonical => SelectionError::Overflow(OverflowError::Canonical),
310             OverflowError::ErrorReporting => SelectionError::ErrorReporting,
311         }
312     }
313 }