]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/adjustment.rs
Rollup merge of #41249 - GuillaumeGomez:rustdoc-render, r=steveklabnik,frewsxcv
[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 ty::{self, Ty, TyCtxt, TypeAndMut};
12 use ty::LvaluePreference::{NoPreference};
13
14 use syntax::ast;
15 use syntax_pos::Span;
16
17 use hir;
18
19 #[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
20 pub struct Adjustment<'tcx> {
21     pub kind: Adjust<'tcx>,
22     pub target: Ty<'tcx>
23 }
24
25 #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
26 pub enum Adjust<'tcx> {
27     /// Go from ! to any type.
28     NeverToAny,
29
30     /// Go from a fn-item type to a fn-pointer type.
31     ReifyFnPointer,
32
33     /// Go from a safe fn pointer to an unsafe fn pointer.
34     UnsafeFnPointer,
35
36     /// Go from a non-capturing closure to an fn pointer.
37     ClosureFnPointer,
38
39     /// Go from a mut raw pointer to a const raw pointer.
40     MutToConstPointer,
41
42     /// Represents coercing a pointer to a different kind of pointer - where 'kind'
43     /// here means either or both of raw vs borrowed vs unique and fat vs thin.
44     ///
45     /// We transform pointers by following the following steps in order:
46     /// 1. Deref the pointer `self.autoderefs` times (may be 0).
47     /// 2. If `autoref` is `Some(_)`, then take the address and produce either a
48     ///    `&` or `*` pointer.
49     /// 3. If `unsize` is `Some(_)`, then apply the unsize transformation,
50     ///    which will do things like convert thin pointers to fat
51     ///    pointers, or convert structs containing thin pointers to
52     ///    structs containing fat pointers, or convert between fat
53     ///    pointers.  We don't store the details of how the transform is
54     ///    done (in fact, we don't know that, because it might depend on
55     ///    the precise type parameters). We just store the target
56     ///    type. Trans figures out what has to be done at monomorphization
57     ///    time based on the precise source/target type at hand.
58     ///
59     /// To make that more concrete, here are some common scenarios:
60     ///
61     /// 1. The simplest cases are where the pointer is not adjusted fat vs thin.
62     /// Here the pointer will be dereferenced N times (where a dereference can
63     /// happen to raw or borrowed pointers or any smart pointer which implements
64     /// Deref, including Box<_>). The number of dereferences is given by
65     /// `autoderefs`.  It can then be auto-referenced zero or one times, indicated
66     /// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
67     /// None.
68     ///
69     /// 2. A thin-to-fat coercon involves unsizing the underlying data. We start
70     /// with a thin pointer, deref a number of times, unsize the underlying data,
71     /// then autoref. The 'unsize' phase may change a fixed length array to a
72     /// dynamically sized one, a concrete object to a trait object, or statically
73     /// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is
74     /// represented by:
75     ///
76     /// ```
77     /// Adjust::DerefRef {
78     ///     autoderefs: 1,          // &[i32; 4] -> [i32; 4]
79     ///     autoref: Some(AutoBorrow::Ref), // [i32] -> &[i32]
80     ///     unsize: Some([i32]),    // [i32; 4] -> [i32]
81     /// }
82     /// ```
83     ///
84     /// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
85     /// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
86     /// The autoderef and -ref are the same as in the above example, but the type
87     /// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
88     /// the underlying conversions from `[i32; 4]` to `[i32]`.
89     ///
90     /// 3. Coercing a `Box<T>` to `Box<Trait>` is an interesting special case.  In
91     /// that case, we have the pointer we need coming in, so there are no
92     /// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
93     /// At some point, of course, `Box` should move out of the compiler, in which
94     /// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> ->
95     /// Box<[i32]> is represented by:
96     ///
97     /// ```
98     /// Adjust::DerefRef {
99     ///     autoderefs: 0,
100     ///     autoref: None,
101     ///     unsize: Some(Box<[i32]>),
102     /// }
103     /// ```
104     DerefRef {
105         /// Step 1. Apply a number of dereferences, producing an lvalue.
106         autoderefs: usize,
107
108         /// Step 2. Optionally produce a pointer/reference from the value.
109         autoref: Option<AutoBorrow<'tcx>>,
110
111         /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to
112         /// `&[T]`. Note that the source could be a thin or fat pointer.
113         unsize: bool,
114     }
115 }
116
117 impl<'tcx> Adjustment<'tcx> {
118     pub fn is_identity(&self) -> bool {
119         match self.kind {
120             Adjust::NeverToAny => self.target.is_never(),
121
122             Adjust::DerefRef { autoderefs: 0, autoref: None, unsize: false } => true,
123
124             Adjust::ReifyFnPointer |
125             Adjust::UnsafeFnPointer |
126             Adjust::ClosureFnPointer |
127             Adjust::MutToConstPointer |
128             Adjust::DerefRef {..} => false,
129         }
130     }
131 }
132
133 #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
134 pub enum AutoBorrow<'tcx> {
135     /// Convert from T to &T.
136     Ref(&'tcx ty::Region, hir::Mutability),
137
138     /// Convert from T to *T.
139     RawPtr(hir::Mutability),
140 }
141
142 /// Information for `CoerceUnsized` impls, storing information we
143 /// have computed about the coercion.
144 ///
145 /// This struct can be obtained via the `coerce_impl_info` query.
146 /// Demanding this struct also has the side-effect of reporting errors
147 /// for inappropriate impls.
148 #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
149 pub struct CoerceUnsizedInfo {
150     /// If this is a "custom coerce" impl, then what kind of custom
151     /// coercion is it? This applies to impls of `CoerceUnsized` for
152     /// structs, primarily, where we store a bit of info about which
153     /// fields need to be coerced.
154     pub custom_kind: Option<CustomCoerceUnsized>
155 }
156
157 #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
158 pub enum CustomCoerceUnsized {
159     /// Records the index of the field being coerced.
160     Struct(usize)
161 }
162
163 impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> {
164     pub fn adjust_for_autoderef<F>(&'tcx self,
165                                    tcx: TyCtxt<'a, 'gcx, 'tcx>,
166                                    expr_id: ast::NodeId,
167                                    expr_span: Span,
168                                    autoderef: u32, // how many autoderefs so far?
169                                    mut method_type: F)
170                                    -> Ty<'tcx> where
171         F: FnMut(ty::MethodCall) -> Option<Ty<'tcx>>,
172     {
173         let method_call = ty::MethodCall::autoderef(expr_id, autoderef);
174         let mut adjusted_ty = self;
175         if let Some(method_ty) = method_type(method_call) {
176             // Method calls always have all late-bound regions
177             // fully instantiated.
178             adjusted_ty = tcx.no_late_bound_regions(&method_ty.fn_ret()).unwrap();
179         }
180         match adjusted_ty.builtin_deref(true, NoPreference) {
181             Some(mt) => mt.ty,
182             None => {
183                 span_bug!(
184                     expr_span,
185                     "the {}th autoderef for {} failed: {}",
186                     autoderef,
187                     expr_id,
188                     adjusted_ty);
189             }
190         }
191     }
192
193     pub fn adjust_for_autoref(&'tcx self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
194                               autoref: Option<AutoBorrow<'tcx>>)
195                               -> Ty<'tcx> {
196         match autoref {
197             None => self,
198             Some(AutoBorrow::Ref(r, m)) => {
199                 tcx.mk_ref(r, TypeAndMut { ty: self, mutbl: m })
200             }
201             Some(AutoBorrow::RawPtr(m)) => {
202                 tcx.mk_ptr(TypeAndMut { ty: self, mutbl: m })
203             }
204         }
205     }
206 }