]> git.lizzy.rs Git - rust.git/blob - src/librustc_middle/ty/adjustment.rs
Rollup merge of #75837 - GuillaumeGomez:fix-font-color-help-button, r=Cldfire
[rust.git] / src / librustc_middle / ty / adjustment.rs
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
8 #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, 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
23     /// Go from `*const [T; N]` to `*const T`
24     ArrayToPointer,
25
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
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.
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
50 ///    `autoderefs`. It can then be auto-referenced zero or one times, indicated
51 ///    by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
52 ///    `false`.
53 ///
54 /// 2. A thin-to-fat coercion involves unsizing the underlying data. We start
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:
60 ///
61 ///    ```
62 ///    Deref(None) -> [i32; 4],
63 ///    Borrow(AutoBorrow::Ref) -> &[i32; 4],
64 ///    Unsize -> &[i32],
65 ///    ```
66 ///
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]`.
72 ///
73 /// 3. Coercing a `Box<T>` to `Box<dyn Trait>` is an interesting special case. In
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]>`.
79 #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
80 pub struct Adjustment<'tcx> {
81     pub kind: Adjust<'tcx>,
82     pub target: Ty<'tcx>,
83 }
84
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
94 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
95 pub enum Adjust<'tcx> {
96     /// Go from ! to any type.
97     NeverToAny,
98
99     /// Dereference once, producing a place.
100     Deref(Option<OverloadedDeref<'tcx>>),
101
102     /// Take the address and produce either a `&` or `*` pointer.
103     Borrow(AutoBorrow<'tcx>),
104
105     Pointer(PointerCast),
106 }
107
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.
112 #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
113 pub struct OverloadedDeref<'tcx> {
114     pub region: ty::Region<'tcx>,
115     pub mutbl: hir::Mutability,
116 }
117
118 impl<'tcx> OverloadedDeref<'tcx> {
119     pub fn method_call(&self, tcx: TyCtxt<'tcx>, source: Ty<'tcx>) -> (DefId, SubstsRef<'tcx>) {
120         let trait_def_id = match self.mutbl {
121             hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, None),
122             hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, None),
123         };
124         let method_def_id = tcx
125             .associated_items(trait_def_id)
126             .in_definition_order()
127             .find(|m| m.kind == ty::AssocKind::Fn)
128             .unwrap()
129             .def_id;
130         (method_def_id, tcx.mk_substs_trait(source, &[]))
131     }
132 }
133
134 /// At least for initial deployment, we want to limit two-phase borrows to
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
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.
146 #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
147 pub enum AllowTwoPhase {
148     Yes,
149     No,
150 }
151
152 #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
153 pub enum AutoBorrowMutability {
154     Mut { allow_two_phase_borrow: AllowTwoPhase },
155     Not,
156 }
157
158 impl From<AutoBorrowMutability> for hir::Mutability {
159     fn from(m: AutoBorrowMutability) -> Self {
160         match m {
161             AutoBorrowMutability::Mut { .. } => hir::Mutability::Mut,
162             AutoBorrowMutability::Not => hir::Mutability::Not,
163         }
164     }
165 }
166
167 #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
168 pub enum AutoBorrow<'tcx> {
169     /// Converts from T to &T.
170     Ref(ty::Region<'tcx>, AutoBorrowMutability),
171
172     /// Converts from T to *T.
173     RawPtr(hir::Mutability),
174 }
175
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.
182 #[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, HashStable)]
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.
188     pub custom_kind: Option<CustomCoerceUnsized>,
189 }
190
191 #[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, HashStable)]
192 pub enum CustomCoerceUnsized {
193     /// Records the index of the field being coerced.
194     Struct(usize),
195 }