]>
Commit | Line | Data |
---|---|---|
9fa01778 XL |
1 | use crate::hir; |
2 | use crate::hir::def_id::DefId; | |
3 | use crate::ty::{self, Ty, TyCtxt}; | |
532ac7d7 XL |
4 | use crate::ty::subst::SubstsRef; |
5 | use rustc_macros::HashStable; | |
7cac9316 | 6 | |
e9174d1e | 7 | |
48663c56 XL |
8 | #[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] |
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]>`. | |
60c5eb7d | 79 | #[derive(Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] |
c30ab7b3 SL |
80 | pub struct Adjustment<'tcx> { |
81 | pub kind: Adjust<'tcx>, | |
7cac9316 | 82 | pub target: Ty<'tcx>, |
e9174d1e SL |
83 | } |
84 | ||
60c5eb7d | 85 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] |
c30ab7b3 SL |
86 | pub enum Adjust<'tcx> { |
87 | /// Go from ! to any type. | |
88 | NeverToAny, | |
89 | ||
2c00a5a8 | 90 | /// Dereference once, producing a place. |
7cac9316 XL |
91 | Deref(Option<OverloadedDeref<'tcx>>), |
92 | ||
93 | /// Take the address and produce either a `&` or `*` pointer. | |
94 | Borrow(AutoBorrow<'tcx>), | |
95 | ||
48663c56 | 96 | Pointer(PointerCast), |
e9174d1e SL |
97 | } |
98 | ||
7cac9316 XL |
99 | /// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` |
100 | /// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`. | |
101 | /// The target type is `U` in both cases, with the region and mutability | |
102 | /// being those shared by both the receiver and the returned reference. | |
60c5eb7d | 103 | #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] |
7cac9316 XL |
104 | pub struct OverloadedDeref<'tcx> { |
105 | pub region: ty::Region<'tcx>, | |
106 | pub mutbl: hir::Mutability, | |
107 | } | |
c30ab7b3 | 108 | |
dc9dc135 XL |
109 | impl<'tcx> OverloadedDeref<'tcx> { |
110 | pub fn method_call(&self, tcx: TyCtxt<'tcx>, source: Ty<'tcx>) -> (DefId, SubstsRef<'tcx>) { | |
7cac9316 | 111 | let trait_def_id = match self.mutbl { |
60c5eb7d XL |
112 | hir::Mutability::Immutable => tcx.lang_items().deref_trait(), |
113 | hir::Mutability::Mutable => tcx.lang_items().deref_mut_trait() | |
7cac9316 XL |
114 | }; |
115 | let method_def_id = tcx.associated_items(trait_def_id.unwrap()) | |
dc9dc135 | 116 | .find(|m| m.kind == ty::AssocKind::Method).unwrap().def_id; |
7cac9316 | 117 | (method_def_id, tcx.mk_substs_trait(source, &[])) |
e9174d1e SL |
118 | } |
119 | } | |
e9174d1e | 120 | |
83c7162d | 121 | /// At least for initial deployment, we want to limit two-phase borrows to |
9fa01778 XL |
122 | /// only a few specific cases. Right now, those are mostly "things that desugar" |
123 | /// into method calls: | |
124 | /// - using `x.some_method()` syntax, where some_method takes `&mut self`, | |
125 | /// - using `Foo::some_method(&mut x, ...)` syntax, | |
126 | /// - binary assignment operators (`+=`, `-=`, `*=`, etc.). | |
127 | /// Anything else should be rejected until generalized two-phase borrow support | |
83c7162d XL |
128 | /// is implemented. Right now, dataflow can't handle the general case where there |
129 | /// is more than one use of a mutable borrow, and we don't want to accept too much | |
130 | /// new code via two-phase borrows, so we try to limit where we create two-phase | |
131 | /// capable mutable borrows. | |
132 | /// See #49434 for tracking. | |
532ac7d7 | 133 | #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable)] |
83c7162d XL |
134 | pub enum AllowTwoPhase { |
135 | Yes, | |
136 | No | |
137 | } | |
138 | ||
532ac7d7 | 139 | #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable)] |
2c00a5a8 | 140 | pub enum AutoBorrowMutability { |
83c7162d | 141 | Mutable { allow_two_phase_borrow: AllowTwoPhase }, |
2c00a5a8 XL |
142 | Immutable, |
143 | } | |
144 | ||
145 | impl From<AutoBorrowMutability> for hir::Mutability { | |
146 | fn from(m: AutoBorrowMutability) -> Self { | |
147 | match m { | |
60c5eb7d XL |
148 | AutoBorrowMutability::Mutable { .. } => hir::Mutability::Mutable, |
149 | AutoBorrowMutability::Immutable => hir::Mutability::Immutable, | |
2c00a5a8 XL |
150 | } |
151 | } | |
152 | } | |
153 | ||
60c5eb7d | 154 | #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] |
c30ab7b3 | 155 | pub enum AutoBorrow<'tcx> { |
9fa01778 | 156 | /// Converts from T to &T. |
2c00a5a8 | 157 | Ref(ty::Region<'tcx>, AutoBorrowMutability), |
e9174d1e | 158 | |
9fa01778 | 159 | /// Converts from T to *T. |
c30ab7b3 | 160 | RawPtr(hir::Mutability), |
e9174d1e SL |
161 | } |
162 | ||
cc61c64b XL |
163 | /// Information for `CoerceUnsized` impls, storing information we |
164 | /// have computed about the coercion. | |
165 | /// | |
166 | /// This struct can be obtained via the `coerce_impl_info` query. | |
167 | /// Demanding this struct also has the side-effect of reporting errors | |
168 | /// for inappropriate impls. | |
532ac7d7 | 169 | #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, HashStable)] |
cc61c64b XL |
170 | pub struct CoerceUnsizedInfo { |
171 | /// If this is a "custom coerce" impl, then what kind of custom | |
172 | /// coercion is it? This applies to impls of `CoerceUnsized` for | |
173 | /// structs, primarily, where we store a bit of info about which | |
174 | /// fields need to be coerced. | |
175 | pub custom_kind: Option<CustomCoerceUnsized> | |
176 | } | |
177 | ||
532ac7d7 | 178 | #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, HashStable)] |
e9174d1e SL |
179 | pub enum CustomCoerceUnsized { |
180 | /// Records the index of the field being coerced. | |
181 | Struct(usize) | |
182 | } |