rustc_middle/ty/
adjustment.rs

1use rustc_abi::FieldIdx;
2use rustc_hir as hir;
3use rustc_hir::def_id::DefId;
4use rustc_hir::lang_items::LangItem;
5use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
6use rustc_span::Span;
7
8use crate::ty::{Ty, TyCtxt};
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
11pub enum PointerCoercion {
12    /// Go from a fn-item type to a fn pointer or an unsafe fn pointer.
13    /// It cannot convert an unsafe fn-item to a safe fn pointer.
14    ReifyFnPointer(hir::Safety),
15
16    /// Go from a safe fn pointer to an unsafe fn pointer.
17    UnsafeFnPointer,
18
19    /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
20    /// It cannot convert a closure that requires unsafe.
21    ClosureFnPointer(hir::Safety),
22
23    /// Go from a mut raw pointer to a const raw pointer.
24    MutToConstPointer,
25
26    /// Go from `*const [T; N]` to `*const T`
27    ArrayToPointer,
28
29    /// Unsize a pointer/reference value, e.g., `&[T; n]` to
30    /// `&[T]`. Note that the source could be a thin or wide pointer.
31    /// This will do things like convert thin pointers to wide
32    /// pointers, or convert structs containing thin pointers to
33    /// structs containing wide pointers, or convert between wide
34    /// pointers. We don't store the details of how the transform is
35    /// done (in fact, we don't know that, because it might depend on
36    /// the precise type parameters). We just store the target
37    /// type. Codegen backends and miri figure out what has to be done
38    /// based on the precise source/target type at hand.
39    Unsize,
40}
41
42/// Represents coercing a value to a different type of value.
43///
44/// We transform values by following a number of `Adjust` steps in order.
45/// See the documentation on variants of `Adjust` for more details.
46///
47/// Here are some common scenarios:
48///
49/// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
50///    Here the pointer will be dereferenced N times (where a dereference can
51///    happen to raw or borrowed pointers or any smart pointer which implements
52///    `Deref`, including `Box<_>`). The types of dereferences is given by
53///    `autoderefs`. It can then be auto-referenced zero or one times, indicated
54///    by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
55///    `false`.
56///
57/// 2. A thin-to-fat coercion involves unsizing the underlying data. We start
58///    with a thin pointer, deref a number of times, unsize the underlying data,
59///    then autoref. The 'unsize' phase may change a fixed length array to a
60///    dynamically sized one, a concrete object to a trait object, or statically
61///    sized struct to a dynamically sized one. E.g., `&[i32; 4]` -> `&[i32]` is
62///    represented by:
63///
64///    ```ignore (illustrative)
65///    Deref(None) -> [i32; 4],
66///    Borrow(AutoBorrow::Ref) -> &[i32; 4],
67///    Unsize -> &[i32],
68///    ```
69///
70///    Note that for a struct, the 'deep' unsizing of the struct is not recorded.
71///    E.g., `struct Foo<T> { x: T }` we can coerce `&Foo<[i32; 4]>` to `&Foo<[i32]>`
72///    The autoderef and -ref are the same as in the above example, but the type
73///    stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
74///    the underlying conversions from `[i32; 4]` to `[i32]`.
75///
76/// 3. Coercing a `Box<T>` to `Box<dyn Trait>` is an interesting special case. In
77///    that case, we have the pointer we need coming in, so there are no
78///    autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
79///    At some point, of course, `Box` should move out of the compiler, in which
80///    case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` ->
81///    `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`.
82#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
83pub struct Adjustment<'tcx> {
84    pub kind: Adjust,
85    pub target: Ty<'tcx>,
86}
87
88impl<'tcx> Adjustment<'tcx> {
89    pub fn is_region_borrow(&self) -> bool {
90        matches!(self.kind, Adjust::Borrow(AutoBorrow::Ref(..)))
91    }
92}
93
94#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
95pub enum Adjust {
96    /// Go from ! to any type.
97    NeverToAny,
98
99    /// Dereference once, producing a place.
100    Deref(Option<OverloadedDeref>),
101
102    /// Take the address and produce either a `&` or `*` pointer.
103    Borrow(AutoBorrow),
104
105    Pointer(PointerCoercion),
106
107    /// Take a pinned reference and reborrow as a `Pin<&mut T>` or `Pin<&T>`.
108    ReborrowPin(hir::Mutability),
109}
110
111/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
112/// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`.
113/// The target type is `U` in both cases, with the region and mutability
114/// being those shared by both the receiver and the returned reference.
115#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
116#[derive(TypeFoldable, TypeVisitable)]
117pub struct OverloadedDeref {
118    pub mutbl: hir::Mutability,
119    /// The `Span` associated with the field access or method call
120    /// that triggered this overloaded deref.
121    pub span: Span,
122}
123
124impl OverloadedDeref {
125    /// Get the [`DefId`] of the method call for the given `Deref`/`DerefMut` trait
126    /// for this overloaded deref's mutability.
127    pub fn method_call<'tcx>(&self, tcx: TyCtxt<'tcx>) -> DefId {
128        let trait_def_id = match self.mutbl {
129            hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, self.span),
130            hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, self.span),
131        };
132        tcx.associated_items(trait_def_id)
133            .in_definition_order()
134            .find(|item| item.is_fn())
135            .unwrap()
136            .def_id
137    }
138}
139
140/// At least for initial deployment, we want to limit two-phase borrows to
141/// only a few specific cases. Right now, those are mostly "things that desugar"
142/// into method calls:
143/// - using `x.some_method()` syntax, where some_method takes `&mut self`,
144/// - using `Foo::some_method(&mut x, ...)` syntax,
145/// - binary assignment operators (`+=`, `-=`, `*=`, etc.).
146/// Anything else should be rejected until generalized two-phase borrow support
147/// is implemented. Right now, dataflow can't handle the general case where there
148/// is more than one use of a mutable borrow, and we don't want to accept too much
149/// new code via two-phase borrows, so we try to limit where we create two-phase
150/// capable mutable borrows.
151/// See #49434 for tracking.
152#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
153pub enum AllowTwoPhase {
154    Yes,
155    No,
156}
157
158#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
159pub enum AutoBorrowMutability {
160    Mut { allow_two_phase_borrow: AllowTwoPhase },
161    Not,
162}
163
164impl AutoBorrowMutability {
165    /// Creates an `AutoBorrowMutability` from a mutability and allowance of two phase borrows.
166    ///
167    /// Note that when `mutbl.is_not()`, `allow_two_phase_borrow` is ignored
168    pub fn new(mutbl: hir::Mutability, allow_two_phase_borrow: AllowTwoPhase) -> Self {
169        match mutbl {
170            hir::Mutability::Not => Self::Not,
171            hir::Mutability::Mut => Self::Mut { allow_two_phase_borrow },
172        }
173    }
174}
175
176impl From<AutoBorrowMutability> for hir::Mutability {
177    fn from(m: AutoBorrowMutability) -> Self {
178        match m {
179            AutoBorrowMutability::Mut { .. } => hir::Mutability::Mut,
180            AutoBorrowMutability::Not => hir::Mutability::Not,
181        }
182    }
183}
184
185#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
186#[derive(TypeFoldable, TypeVisitable)]
187pub enum AutoBorrow {
188    /// Converts from T to &T.
189    Ref(AutoBorrowMutability),
190
191    /// Converts from T to *T.
192    RawPtr(hir::Mutability),
193}
194
195/// Information for `CoerceUnsized` impls, storing information we
196/// have computed about the coercion.
197///
198/// This struct can be obtained via the `coerce_impl_info` query.
199/// Demanding this struct also has the side-effect of reporting errors
200/// for inappropriate impls.
201#[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, HashStable)]
202pub struct CoerceUnsizedInfo {
203    /// If this is a "custom coerce" impl, then what kind of custom
204    /// coercion is it? This applies to impls of `CoerceUnsized` for
205    /// structs, primarily, where we store a bit of info about which
206    /// fields need to be coerced.
207    pub custom_kind: Option<CustomCoerceUnsized>,
208}
209
210#[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, HashStable)]
211pub enum CustomCoerceUnsized {
212    /// Records the index of the field being coerced.
213    Struct(FieldIdx),
214}
215
216/// Represents an implicit coercion applied to the scrutinee of a match before testing a pattern
217/// against it. Currently, this is used only for implicit dereferences.
218#[derive(Clone, Copy, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
219pub struct PatAdjustment<'tcx> {
220    pub kind: PatAdjust,
221    /// The type of the scrutinee before the adjustment is applied, or the "adjusted type" of the
222    /// pattern.
223    pub source: Ty<'tcx>,
224}
225
226/// Represents implicit coercions of patterns' types, rather than values' types.
227#[derive(Clone, Copy, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
228#[derive(TypeFoldable, TypeVisitable)]
229pub enum PatAdjust {
230    /// An implicit dereference before matching, such as when matching the pattern `0` against a
231    /// scrutinee of type `&u8` or `&mut u8`.
232    BuiltinDeref,
233    /// An implicit call to `Deref(Mut)::deref(_mut)` before matching, such as when matching the
234    /// pattern `[..]` against a scrutinee of type `Vec<T>`.
235    OverloadedDeref,
236    /// An implicit dereference before matching a `&pin` reference (under feature `pin_ergonomics`),
237    /// which will be lowered as a builtin deref of the private field `__pointer` in `Pin`
238    PinDeref,
239}