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