]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/traits/select.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / traits / select.rs
CommitLineData
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
5use self::EvaluationResult::*;
6
74b04a01 7use super::{SelectionError, SelectionResult};
5e7ed085 8use rustc_errors::ErrorGuaranteed;
0bf4aa26 9
3dfed10e 10use crate::ty;
9fa01778 11
74b04a01 12use rustc_hir::def_id::DefId;
3dfed10e 13use rustc_query_system::cache::Cache;
1a4d82fc 14
3dfed10e 15pub 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
23pub 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 107pub 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 179pub 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 249impl 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 289pub enum OverflowError {
5e7ed085 290 Error(ErrorGuaranteed),
c295e0f8
XL
291 Canonical,
292 ErrorReporting,
293}
83c7162d 294
5e7ed085
FG
295impl From<ErrorGuaranteed> for OverflowError {
296 fn from(e: ErrorGuaranteed) -> OverflowError {
297 OverflowError::Error(e)
298 }
299}
300
064997fb 301TrivialTypeTraversalAndLiftImpls! {
5e7ed085
FG
302 OverflowError,
303}
304
83c7162d 305impl<'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}