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