]>
Commit | Line | Data |
---|---|---|
ba9703b0 | 1 | //! Candidate selection. See the [rustc dev guide] for more information on how this works. |
0531ce1d | 2 | //! |
ba9703b0 | 3 | //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection |
1a4d82fc | 4 | |
1a4d82fc JJ |
5 | use self::EvaluationResult::*; |
6 | ||
74b04a01 | 7 | use super::{SelectionError, SelectionResult}; |
5e7ed085 | 8 | use rustc_errors::ErrorGuaranteed; |
0bf4aa26 | 9 | |
3dfed10e | 10 | use crate::ty; |
9fa01778 | 11 | |
74b04a01 | 12 | use rustc_hir::def_id::DefId; |
3dfed10e | 13 | use rustc_query_system::cache::Cache; |
1a4d82fc | 14 | |
3dfed10e | 15 | pub type SelectionCache<'tcx> = Cache< |
5e7ed085 FG |
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>), | |
3dfed10e XL |
20 | SelectionResult<'tcx, SelectionCandidate<'tcx>>, |
21 | >; | |
1a4d82fc | 22 | |
5e7ed085 FG |
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 | >; | |
74b04a01 | 29 | |
1a4d82fc | 30 | /// The selection process begins by considering all impls, where |
9fa01778 | 31 | /// clauses, and so forth that might resolve an obligation. Sometimes |
1a4d82fc | 32 | /// we'll be able to say definitively that (e.g.) an impl does not |
c34b1796 | 33 | /// apply to the obligation: perhaps it is defined for `usize` but the |
f9f354fc | 34 | /// obligation is for `i32`. In that case, we drop the impl out of the |
9fa01778 | 35 | /// list. But the other cases are considered *candidates*. |
1a4d82fc | 36 | /// |
d9579d0f AL |
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. | |
1a4d82fc | 41 | /// |
d9579d0f AL |
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 | |
e74abb32 | 46 | /// "type annotations needed" error. |
d9579d0f AL |
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 | /// | |
f9f354fc XL |
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 | /// ``` | |
d9579d0f | 62 | /// |
60c5eb7d XL |
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`. | |
d9579d0f AL |
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 | /// | |
f9f354fc XL |
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 } } | |
d9579d0f | 85 | /// |
f9f354fc XL |
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 | /// ``` | |
d9579d0f | 91 | /// |
60c5eb7d XL |
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`, | |
d9579d0f | 94 | /// so the program prints "false". However, if the where-clause is omitted, |
60c5eb7d | 95 | /// the blanket impl is selected, we unify `$0=()`, and the program prints |
d9579d0f AL |
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 | |
e9174d1e | 102 | /// present), and we just pick the where-clause. This is, for example, |
d9579d0f AL |
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. | |
064997fb | 106 | #[derive(PartialEq, Eq, Debug, Clone, TypeFoldable, TypeVisitable)] |
74b04a01 | 107 | pub enum SelectionCandidate<'tcx> { |
0bf4aa26 | 108 | BuiltinCandidate { |
60c5eb7d | 109 | /// `false` if there are no *further* obligations. |
0bf4aa26 XL |
110 | has_nested: bool, |
111 | }, | |
064997fb FG |
112 | |
113 | /// Implementation of transmutability trait. | |
114 | TransmutabilityCandidate, | |
115 | ||
a2a8927a | 116 | ParamCandidate(ty::PolyTraitPredicate<'tcx>), |
e9174d1e | 117 | ImplCandidate(DefId), |
2b03887a | 118 | AutoImplCandidate, |
1a4d82fc | 119 | |
29967ef6 XL |
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 | |
2b03887a FG |
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), | |
1a4d82fc | 125 | |
a7813a04 | 126 | /// Implementation of a `Fn`-family trait by one of the anonymous types |
94222f64 | 127 | /// generated for an `||` expression. |
ea8adc8c XL |
128 | ClosureCandidate, |
129 | ||
130 | /// Implementation of a `Generator` trait by one of the anonymous types | |
131 | /// generated for a generator. | |
132 | GeneratorCandidate, | |
1a4d82fc JJ |
133 | |
134 | /// Implementation of a `Fn`-family trait by one of the anonymous | |
60c5eb7d | 135 | /// types generated for a fn pointer type (e.g., `fn(int) -> int`) |
c295e0f8 XL |
136 | FnPointerCandidate { |
137 | is_const: bool, | |
138 | }, | |
1a4d82fc | 139 | |
f9f354fc XL |
140 | /// Builtin implementation of `DiscriminantKind`. |
141 | DiscriminantKindCandidate, | |
142 | ||
6a06907d XL |
143 | /// Builtin implementation of `Pointee`. |
144 | PointeeCandidate, | |
145 | ||
2b03887a | 146 | TraitAliasCandidate, |
a1dfa0c6 | 147 | |
29967ef6 XL |
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), | |
1a4d82fc | 152 | |
94222f64 XL |
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 | ||
c34b1796 AL |
158 | BuiltinObjectCandidate, |
159 | ||
d9579d0f | 160 | BuiltinUnsizeCandidate, |
c295e0f8 | 161 | |
5e7ed085 FG |
162 | /// Implementation of `const Destruct`, optionally from a custom `impl const Drop`. |
163 | ConstDestructCandidate(Option<DefId>), | |
1a4d82fc JJ |
164 | } |
165 | ||
92a42be0 SL |
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. | |
3b2f2976 XL |
169 | /// |
170 | /// The evaluation results are ordered: | |
0731742a XL |
171 | /// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions` |
172 | /// implies `EvaluatedToAmbig` implies `EvaluatedToUnknown` | |
3b2f2976 XL |
173 | /// - `EvaluatedToErr` implies `EvaluatedToRecur` |
174 | /// - the "union" of evaluation results is equal to their maximum - | |
175 | /// all the "potential success" candidates can potentially succeed, | |
9fa01778 | 176 | /// so they are noops when unioned with a definite error, and within |
3b2f2976 | 177 | /// the categories it's easy to see that the unions are correct. |
60c5eb7d | 178 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, HashStable)] |
83c7162d | 179 | pub enum EvaluationResult { |
60c5eb7d | 180 | /// Evaluation successful. |
1a4d82fc | 181 | EvaluatedToOk, |
60c5eb7d | 182 | /// Evaluation successful, but there were unevaluated region obligations. |
0731742a | 183 | EvaluatedToOkModuloRegions, |
04454e1e FG |
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, | |
60c5eb7d | 188 | /// Evaluation is known to be ambiguous -- it *might* hold for some |
3b2f2976 XL |
189 | /// assignment of inference variables, but it might not. |
190 | /// | |
60c5eb7d XL |
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 | |
3b2f2976 | 193 | /// would get with an empty stack, and therefore is cacheable. |
1a4d82fc | 194 | EvaluatedToAmbig, |
3b2f2976 XL |
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 | |
60c5eb7d | 207 | /// that all the obligations on this branch do not hold -- it's possible |
3b2f2976 XL |
208 | /// that we entered this branch "speculatively", and that there |
209 | /// might be some other way to prove this obligation that does not | |
60c5eb7d | 210 | /// go through this cycle -- so we can't cache this as a failure. |
3b2f2976 XL |
211 | /// |
212 | /// For example, suppose we have this: | |
213 | /// | |
214 | /// ```rust,ignore (pseudo-Rust) | |
60c5eb7d XL |
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() {} } | |
3b2f2976 | 219 | /// |
60c5eb7d XL |
220 | /// pub fn foo<T: Trait + ?Sized>() { |
221 | /// <T as Trait>::xyz(); | |
222 | /// } | |
3b2f2976 XL |
223 | /// ``` |
224 | /// | |
225 | /// When checking `foo`, we have to prove `T: Trait`. This basically | |
226 | /// translates into this: | |
227 | /// | |
83c7162d | 228 | /// ```plain,ignore |
60c5eb7d | 229 | /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait |
83c7162d | 230 | /// ``` |
3b2f2976 XL |
231 | /// |
232 | /// When we try to prove it, we first go the first option, which | |
9fa01778 | 233 | /// recurses. This shows us that the impl is "useless" -- it won't |
3b2f2976 XL |
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). | |
9fa01778 XL |
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. | |
3b2f2976 | 244 | EvaluatedToRecur, |
9fa01778 | 245 | /// Evaluation failed. |
92a42be0 SL |
246 | EvaluatedToErr, |
247 | } | |
248 | ||
3b2f2976 | 249 | impl EvaluationResult { |
9fa01778 | 250 | /// Returns `true` if this evaluation result is known to apply, even |
0731742a XL |
251 | /// considering outlives constraints. |
252 | pub fn must_apply_considering_regions(self) -> bool { | |
253 | self == EvaluatedToOk | |
254 | } | |
255 | ||
9fa01778 | 256 | /// Returns `true` if this evaluation result is known to apply, ignoring |
0731742a XL |
257 | /// outlives constraints. |
258 | pub fn must_apply_modulo_regions(self) -> bool { | |
259 | self <= EvaluatedToOkModuloRegions | |
260 | } | |
261 | ||
83c7162d | 262 | pub fn may_apply(self) -> bool { |
3b2f2976 | 263 | match self { |
04454e1e FG |
264 | EvaluatedToOkModuloOpaqueTypes |
265 | | EvaluatedToOk | |
266 | | EvaluatedToOkModuloRegions | |
267 | | EvaluatedToAmbig | |
268 | | EvaluatedToUnknown => true, | |
3b2f2976 | 269 | |
0bf4aa26 | 270 | EvaluatedToErr | EvaluatedToRecur => false, |
3b2f2976 XL |
271 | } |
272 | } | |
273 | ||
74b04a01 | 274 | pub fn is_stack_dependent(self) -> bool { |
3b2f2976 | 275 | match self { |
0bf4aa26 | 276 | EvaluatedToUnknown | EvaluatedToRecur => true, |
3b2f2976 | 277 | |
04454e1e FG |
278 | EvaluatedToOkModuloOpaqueTypes |
279 | | EvaluatedToOk | |
280 | | EvaluatedToOkModuloRegions | |
281 | | EvaluatedToAmbig | |
282 | | EvaluatedToErr => false, | |
3b2f2976 XL |
283 | } |
284 | } | |
285 | } | |
286 | ||
c295e0f8 | 287 | /// Indicates that trait evaluation caused overflow and in which pass. |
60c5eb7d | 288 | #[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)] |
c295e0f8 | 289 | pub enum OverflowError { |
5e7ed085 | 290 | Error(ErrorGuaranteed), |
c295e0f8 XL |
291 | Canonical, |
292 | ErrorReporting, | |
293 | } | |
83c7162d | 294 | |
5e7ed085 FG |
295 | impl From<ErrorGuaranteed> for OverflowError { |
296 | fn from(e: ErrorGuaranteed) -> OverflowError { | |
297 | OverflowError::Error(e) | |
298 | } | |
299 | } | |
300 | ||
064997fb | 301 | TrivialTypeTraversalAndLiftImpls! { |
5e7ed085 FG |
302 | OverflowError, |
303 | } | |
304 | ||
83c7162d | 305 | impl<'tcx> From<OverflowError> for SelectionError<'tcx> { |
c295e0f8 XL |
306 | fn from(overflow_error: OverflowError) -> SelectionError<'tcx> { |
307 | match overflow_error { | |
5e7ed085 FG |
308 | OverflowError::Error(e) => SelectionError::Overflow(OverflowError::Error(e)), |
309 | OverflowError::Canonical => SelectionError::Overflow(OverflowError::Canonical), | |
c295e0f8 XL |
310 | OverflowError::ErrorReporting => SelectionError::ErrorReporting, |
311 | } | |
83c7162d XL |
312 | } |
313 | } |