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