rustc_middle/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
5use rustc_errors::ErrorGuaranteed;
6use rustc_hir::def_id::DefId;
7use rustc_macros::{HashStable, TypeVisitable};
8use rustc_query_system::cache::Cache;
9use rustc_type_ir::solve::AliasBoundKind;
10
11use self::EvaluationResult::*;
12use super::{SelectionError, SelectionResult};
13use crate::ty;
14
15pub type SelectionCache<'tcx, ENV> =
16    Cache<(ENV, ty::TraitPredicate<'tcx>), SelectionResult<'tcx, SelectionCandidate<'tcx>>>;
17
18pub type EvaluationCache<'tcx, ENV> = Cache<(ENV, ty::PolyTraitPredicate<'tcx>), EvaluationResult>;
19
20/// The selection process begins by considering all impls, where
21/// clauses, and so forth that might resolve an obligation. Sometimes
22/// we'll be able to say definitively that (e.g.) an impl does not
23/// apply to the obligation: perhaps it is defined for `usize` but the
24/// obligation is for `i32`. In that case, we drop the impl out of the
25/// list. But the other cases are considered *candidates*.
26///
27/// For selection to succeed, there must be exactly one matching
28/// candidate. If the obligation is fully known, this is guaranteed
29/// by coherence. However, if the obligation contains type parameters
30/// or variables, there may be multiple such impls.
31///
32/// It is not a real problem if multiple matching impls exist because
33/// of type variables - it just means the obligation isn't sufficiently
34/// elaborated. In that case we report an ambiguity, and the caller can
35/// try again after more type information has been gathered or report a
36/// "type annotations needed" error.
37///
38/// However, with type parameters, this can be a real problem - type
39/// parameters don't unify with regular types, but they *can* unify
40/// with variables from blanket impls, and (unless we know its bounds
41/// will always be satisfied) picking the blanket impl will be wrong
42/// for at least *some* generic parameters. To make this concrete, if
43/// we have
44///
45/// ```rust, ignore
46/// trait AsDebug { type Out: fmt::Debug; fn debug(self) -> Self::Out; }
47/// impl<T: fmt::Debug> AsDebug for T {
48///     type Out = T;
49///     fn debug(self) -> fmt::Debug { self }
50/// }
51/// fn foo<T: AsDebug>(t: T) { println!("{:?}", <T as AsDebug>::debug(t)); }
52/// ```
53///
54/// we can't just use the impl to resolve the `<T as AsDebug>` obligation
55/// -- a type from another crate (that doesn't implement `fmt::Debug`) could
56/// implement `AsDebug`.
57///
58/// Because where-clauses match the type exactly, multiple clauses can
59/// only match if there are unresolved variables, and we can mostly just
60/// report this ambiguity in that case. This is still a problem - we can't
61/// *do anything* with ambiguities that involve only regions. This is issue
62/// #21974.
63///
64/// If a single where-clause matches and there are no inference
65/// variables left, then it definitely matches and we can just select
66/// it.
67///
68/// In fact, we even select the where-clause when the obligation contains
69/// inference variables. The can lead to inference making "leaps of logic",
70/// for example in this situation:
71///
72/// ```rust, ignore
73/// pub trait Foo<T> { fn foo(&self) -> T; }
74/// impl<T> Foo<()> for T { fn foo(&self) { } }
75/// impl Foo<bool> for bool { fn foo(&self) -> bool { *self } }
76///
77/// pub fn foo<T>(t: T) where T: Foo<bool> {
78///     println!("{:?}", <T as Foo<_>>::foo(&t));
79/// }
80/// fn main() { foo(false); }
81/// ```
82///
83/// Here the obligation `<T as Foo<$0>>` can be matched by both the blanket
84/// impl and the where-clause. We select the where-clause and unify `$0=bool`,
85/// so the program prints "false". However, if the where-clause is omitted,
86/// the blanket impl is selected, we unify `$0=()`, and the program prints
87/// "()".
88///
89/// Exactly the same issues apply to projection and object candidates, except
90/// that we can have both a projection candidate and a where-clause candidate
91/// for the same obligation. In that case either would do (except that
92/// different "leaps of logic" would occur if inference variables are
93/// present), and we just pick the where-clause. This is, for example,
94/// required for associated types to work in default impls, as the bounds
95/// are visible both as projection bounds and as where-clauses from the
96/// parameter environment.
97#[derive(PartialEq, Eq, Debug, Clone, TypeVisitable)]
98pub enum SelectionCandidate<'tcx> {
99    /// A built-in implementation for the `Sized` trait. This is preferred
100    /// over all other candidates.
101    SizedCandidate,
102
103    /// A builtin implementation for some specific traits, used in cases
104    /// where we cannot rely an ordinary library implementations.
105    ///
106    /// The most notable examples are `Copy` and `Clone`. This is also
107    /// used for the `DiscriminantKind` and `Pointee` trait, both of which have
108    /// an associated type.
109    BuiltinCandidate,
110
111    /// Implementation of transmutability trait.
112    TransmutabilityCandidate,
113
114    ParamCandidate(ty::PolyTraitPredicate<'tcx>),
115    ImplCandidate(DefId),
116    AutoImplCandidate,
117
118    /// This is a trait matching with a projected type as `Self`, and we found
119    /// an applicable bound in the trait definition. The `usize` is an index
120    /// into the list returned by `tcx.item_bounds` and the `AliasBoundKind`
121    /// is whether this is candidate from recursion on the self type of a
122    /// projection.
123    ProjectionCandidate {
124        idx: usize,
125        kind: AliasBoundKind,
126    },
127
128    /// Implementation of a `Fn`-family trait by one of the anonymous types
129    /// generated for an `||` expression.
130    ClosureCandidate {
131        is_const: bool,
132    },
133
134    /// Implementation of an `AsyncFn`-family trait by one of the anonymous types
135    /// generated for an `async ||` expression.
136    AsyncClosureCandidate,
137
138    /// Implementation of the `AsyncFnKindHelper` helper trait, which
139    /// is used internally to delay computation for async closures until after
140    /// upvar analysis is performed in HIR typeck.
141    AsyncFnKindHelperCandidate,
142
143    /// Implementation of a `Coroutine` trait by one of the anonymous types
144    /// generated for a coroutine.
145    CoroutineCandidate,
146
147    /// Implementation of a `Future` trait by one of the coroutine types
148    /// generated for an async construct.
149    FutureCandidate,
150
151    /// Implementation of an `Iterator` trait by one of the coroutine types
152    /// generated for a `gen` construct.
153    IteratorCandidate,
154
155    /// Implementation of an `AsyncIterator` trait by one of the coroutine types
156    /// generated for a `async gen` construct.
157    AsyncIteratorCandidate,
158
159    /// Implementation of a `Fn`-family trait by one of the anonymous
160    /// types generated for a fn pointer type (e.g., `fn(int) -> int`)
161    FnPointerCandidate,
162
163    /// Builtin impl of the `PointerLike` trait.
164    PointerLikeCandidate,
165
166    TraitAliasCandidate,
167
168    /// Matching `dyn Trait` with a supertrait of `Trait`. The index is the
169    /// position in the iterator returned by
170    /// `rustc_infer::traits::util::supertraits`.
171    ObjectCandidate(usize),
172
173    /// Perform trait upcasting coercion of `dyn Trait` to a supertrait of `Trait`.
174    /// The index is the position in the iterator returned by
175    /// `rustc_infer::traits::util::supertraits`.
176    TraitUpcastingUnsizeCandidate(usize),
177
178    BuiltinObjectCandidate,
179
180    BuiltinUnsizeCandidate,
181
182    BikeshedGuaranteedNoDropCandidate,
183}
184
185/// The result of trait evaluation. The order is important
186/// here as the evaluation of a list is the maximum of the
187/// evaluations.
188///
189/// The evaluation results are ordered:
190///     - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions`
191///       implies `EvaluatedToAmbig` implies `EvaluatedToAmbigStackDependent`
192///     - the "union" of evaluation results is equal to their maximum -
193///     all the "potential success" candidates can potentially succeed,
194///     so they are noops when unioned with a definite error, and within
195///     the categories it's easy to see that the unions are correct.
196#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, HashStable)]
197pub enum EvaluationResult {
198    /// Evaluation successful.
199    EvaluatedToOk,
200    /// Evaluation successful, but there were unevaluated region obligations.
201    EvaluatedToOkModuloRegions,
202    /// Evaluation successful, but need to rerun because opaque types got
203    /// hidden types assigned without it being known whether the opaque types
204    /// are within their defining scope
205    EvaluatedToOkModuloOpaqueTypes,
206    /// Evaluation is known to be ambiguous -- it *might* hold for some
207    /// assignment of inference variables, but it might not.
208    ///
209    /// While this has the same meaning as `EvaluatedToAmbigStackDependent` -- we can't
210    /// know whether this obligation holds or not -- it is the result we
211    /// would get with an empty stack, and therefore is cacheable.
212    EvaluatedToAmbig,
213    /// Evaluation failed because of recursion involving inference
214    /// variables. We are somewhat imprecise there, so we don't actually
215    /// know the real result.
216    ///
217    /// This can't be trivially cached because the result depends on the
218    /// stack results.
219    EvaluatedToAmbigStackDependent,
220    /// Evaluation failed.
221    EvaluatedToErr,
222}
223
224impl EvaluationResult {
225    /// Returns `true` if this evaluation result is known to apply, even
226    /// considering outlives constraints.
227    pub fn must_apply_considering_regions(self) -> bool {
228        self == EvaluatedToOk
229    }
230
231    /// Returns `true` if this evaluation result is known to apply, ignoring
232    /// outlives constraints.
233    pub fn must_apply_modulo_regions(self) -> bool {
234        self <= EvaluatedToOkModuloRegions
235    }
236
237    pub fn may_apply(self) -> bool {
238        match self {
239            EvaluatedToOkModuloOpaqueTypes
240            | EvaluatedToOk
241            | EvaluatedToOkModuloRegions
242            | EvaluatedToAmbig
243            | EvaluatedToAmbigStackDependent => true,
244
245            EvaluatedToErr => false,
246        }
247    }
248
249    pub fn is_stack_dependent(self) -> bool {
250        match self {
251            EvaluatedToAmbigStackDependent => true,
252
253            EvaluatedToOkModuloOpaqueTypes
254            | EvaluatedToOk
255            | EvaluatedToOkModuloRegions
256            | EvaluatedToAmbig
257            | EvaluatedToErr => false,
258        }
259    }
260}
261
262/// Indicates that trait evaluation caused overflow and in which pass.
263#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
264pub enum OverflowError {
265    Error(ErrorGuaranteed),
266    Canonical,
267}
268
269impl From<ErrorGuaranteed> for OverflowError {
270    fn from(e: ErrorGuaranteed) -> OverflowError {
271        OverflowError::Error(e)
272    }
273}
274
275impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
276    fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
277        match overflow_error {
278            OverflowError::Error(e) => SelectionError::Overflow(OverflowError::Error(e)),
279            OverflowError::Canonical => SelectionError::Overflow(OverflowError::Canonical),
280        }
281    }
282}