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