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