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