]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/ty/adjustment.rs
drive-by: Fix path spans
[rust.git] / compiler / rustc_middle / src / ty / adjustment.rs
1 use crate::ty::{self, Ty, TyCtxt};
2 use rustc_hir as hir;
3 use rustc_hir::lang_items::LangItem;
4 use rustc_macros::HashStable;
5 use rustc_span::Span;
6
7 #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
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
22     /// Go from `*const [T; N]` to `*const T`
23     ArrayToPointer,
24
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
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.
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
48 ///    `Deref`, including `Box<_>`). The types of dereferences is given by
49 ///    `autoderefs`. It can then be auto-referenced zero or one times, indicated
50 ///    by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
51 ///    `false`.
52 ///
53 /// 2. A thin-to-fat coercion involves unsizing the underlying data. We start
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
57 ///    sized struct to a dynamically sized one. E.g., `&[i32; 4]` -> `&[i32]` is
58 ///    represented by:
59 ///
60 ///    ```ignore (illustrative)
61 ///    Deref(None) -> [i32; 4],
62 ///    Borrow(AutoBorrow::Ref) -> &[i32; 4],
63 ///    Unsize -> &[i32],
64 ///    ```
65 ///
66 ///    Note that for a struct, the 'deep' unsizing of the struct is not recorded.
67 ///    E.g., `struct Foo<T> { x: T }` we can coerce `&Foo<[i32; 4]>` to `&Foo<[i32]>`
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]`.
71 ///
72 /// 3. Coercing a `Box<T>` to `Box<dyn Trait>` is an interesting special case. In
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
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]>`.
78 #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
79 pub struct Adjustment<'tcx> {
80     pub kind: Adjust<'tcx>,
81     pub target: Ty<'tcx>,
82 }
83
84 impl<'tcx> Adjustment<'tcx> {
85     pub fn is_region_borrow(&self) -> bool {
86         matches!(self.kind, Adjust::Borrow(AutoBorrow::Ref(..)))
87     }
88 }
89
90 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
91 pub enum Adjust<'tcx> {
92     /// Go from ! to any type.
93     NeverToAny,
94
95     /// Dereference once, producing a place.
96     Deref(Option<OverloadedDeref<'tcx>>),
97
98     /// Take the address and produce either a `&` or `*` pointer.
99     Borrow(AutoBorrow<'tcx>),
100
101     Pointer(PointerCast),
102
103     /// Cast into a dyn* object.
104     DynStar,
105 }
106
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.
111 #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
112 #[derive(TypeFoldable, TypeVisitable, Lift)]
113 pub struct OverloadedDeref<'tcx> {
114     pub region: ty::Region<'tcx>,
115     pub mutbl: hir::Mutability,
116     /// The `Span` associated with the field access or method call
117     /// that triggered this overloaded deref.
118     pub span: Span,
119 }
120
121 impl<'tcx> OverloadedDeref<'tcx> {
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> {
124         let trait_def_id = match self.mutbl {
125             hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, None),
126             hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, None),
127         };
128         let method_def_id = tcx
129             .associated_items(trait_def_id)
130             .in_definition_order()
131             .find(|m| m.kind == ty::AssocKind::Fn)
132             .unwrap()
133             .def_id;
134         tcx.mk_fn_def(method_def_id, tcx.mk_substs_trait(source, []))
135     }
136 }
137
138 /// At least for initial deployment, we want to limit two-phase borrows to
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
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.
150 #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
151 pub enum AllowTwoPhase {
152     Yes,
153     No,
154 }
155
156 #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
157 pub enum AutoBorrowMutability {
158     Mut { allow_two_phase_borrow: AllowTwoPhase },
159     Not,
160 }
161
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
174 impl From<AutoBorrowMutability> for hir::Mutability {
175     fn from(m: AutoBorrowMutability) -> Self {
176         match m {
177             AutoBorrowMutability::Mut { .. } => hir::Mutability::Mut,
178             AutoBorrowMutability::Not => hir::Mutability::Not,
179         }
180     }
181 }
182
183 #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
184 #[derive(TypeFoldable, TypeVisitable, Lift)]
185 pub enum AutoBorrow<'tcx> {
186     /// Converts from T to &T.
187     Ref(ty::Region<'tcx>, AutoBorrowMutability),
188
189     /// Converts from T to *T.
190     RawPtr(hir::Mutability),
191 }
192
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.
199 #[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, HashStable)]
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.
205     pub custom_kind: Option<CustomCoerceUnsized>,
206 }
207
208 #[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, HashStable)]
209 pub enum CustomCoerceUnsized {
210     /// Records the index of the field being coerced.
211     Struct(usize),
212 }