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