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