]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
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 | pub use self::AutoAdjustment::*; | |
12 | pub use self::AutoRef::*; | |
13 | ||
9cc50fc6 | 14 | use middle::ty::{self, Ty, TypeAndMut, TypeFoldable}; |
e9174d1e SL |
15 | use middle::ty::LvaluePreference::{NoPreference}; |
16 | ||
17 | use syntax::ast; | |
18 | use syntax::codemap::Span; | |
19 | ||
20 | use rustc_front::hir; | |
21 | ||
22 | #[derive(Copy, Clone)] | |
23 | pub enum AutoAdjustment<'tcx> { | |
7453a54e SL |
24 | AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type |
25 | AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer | |
26 | AdjustMutToConstPointer, // go from a mut raw pointer to a const raw pointer | |
e9174d1e SL |
27 | AdjustDerefRef(AutoDerefRef<'tcx>), |
28 | } | |
29 | ||
30 | /// Represents coercing a pointer to a different kind of pointer - where 'kind' | |
31 | /// here means either or both of raw vs borrowed vs unique and fat vs thin. | |
32 | /// | |
33 | /// We transform pointers by following the following steps in order: | |
34 | /// 1. Deref the pointer `self.autoderefs` times (may be 0). | |
35 | /// 2. If `autoref` is `Some(_)`, then take the address and produce either a | |
36 | /// `&` or `*` pointer. | |
37 | /// 3. If `unsize` is `Some(_)`, then apply the unsize transformation, | |
38 | /// which will do things like convert thin pointers to fat | |
39 | /// pointers, or convert structs containing thin pointers to | |
40 | /// structs containing fat pointers, or convert between fat | |
41 | /// pointers. We don't store the details of how the transform is | |
42 | /// done (in fact, we don't know that, because it might depend on | |
43 | /// the precise type parameters). We just store the target | |
44 | /// type. Trans figures out what has to be done at monomorphization | |
45 | /// time based on the precise source/target type at hand. | |
46 | /// | |
47 | /// To make that more concrete, here are some common scenarios: | |
48 | /// | |
49 | /// 1. The simplest cases are where the pointer is not adjusted fat vs thin. | |
50 | /// Here the pointer will be dereferenced N times (where a dereference can | |
b039eaaf | 51 | /// happen to raw or borrowed pointers or any smart pointer which implements |
e9174d1e SL |
52 | /// Deref, including Box<_>). The number of dereferences is given by |
53 | /// `autoderefs`. It can then be auto-referenced zero or one times, indicated | |
54 | /// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is | |
55 | /// None. | |
56 | /// | |
57 | /// 2. A thin-to-fat coercon involves unsizing the underlying data. We start | |
58 | /// with a thin pointer, deref a number of times, unsize the underlying data, | |
59 | /// then autoref. The 'unsize' phase may change a fixed length array to a | |
60 | /// dynamically sized one, a concrete object to a trait object, or statically | |
61 | /// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is | |
62 | /// represented by: | |
63 | /// | |
64 | /// ``` | |
65 | /// AutoDerefRef { | |
66 | /// autoderefs: 1, // &[i32; 4] -> [i32; 4] | |
67 | /// autoref: Some(AutoPtr), // [i32] -> &[i32] | |
68 | /// unsize: Some([i32]), // [i32; 4] -> [i32] | |
69 | /// } | |
70 | /// ``` | |
71 | /// | |
72 | /// Note that for a struct, the 'deep' unsizing of the struct is not recorded. | |
73 | /// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> | |
74 | /// The autoderef and -ref are the same as in the above example, but the type | |
75 | /// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about | |
76 | /// the underlying conversions from `[i32; 4]` to `[i32]`. | |
77 | /// | |
78 | /// 3. Coercing a `Box<T>` to `Box<Trait>` is an interesting special case. In | |
79 | /// that case, we have the pointer we need coming in, so there are no | |
80 | /// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. | |
81 | /// At some point, of course, `Box` should move out of the compiler, in which | |
82 | /// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> | |
83 | /// Box<[i32]> is represented by: | |
84 | /// | |
85 | /// ``` | |
86 | /// AutoDerefRef { | |
87 | /// autoderefs: 0, | |
88 | /// autoref: None, | |
89 | /// unsize: Some(Box<[i32]>), | |
90 | /// } | |
91 | /// ``` | |
92 | #[derive(Copy, Clone)] | |
93 | pub struct AutoDerefRef<'tcx> { | |
94 | /// Step 1. Apply a number of dereferences, producing an lvalue. | |
95 | pub autoderefs: usize, | |
96 | ||
97 | /// Step 2. Optionally produce a pointer/reference from the value. | |
98 | pub autoref: Option<AutoRef<'tcx>>, | |
99 | ||
100 | /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to | |
101 | /// `&[T]`. The stored type is the target pointer type. Note that | |
102 | /// the source could be a thin or fat pointer. | |
103 | pub unsize: Option<Ty<'tcx>>, | |
104 | } | |
105 | ||
106 | impl<'tcx> AutoAdjustment<'tcx> { | |
107 | pub fn is_identity(&self) -> bool { | |
108 | match *self { | |
109 | AdjustReifyFnPointer | | |
7453a54e SL |
110 | AdjustUnsafeFnPointer | |
111 | AdjustMutToConstPointer => false, | |
e9174d1e SL |
112 | AdjustDerefRef(ref r) => r.is_identity(), |
113 | } | |
114 | } | |
115 | } | |
116 | impl<'tcx> AutoDerefRef<'tcx> { | |
117 | pub fn is_identity(&self) -> bool { | |
118 | self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none() | |
119 | } | |
120 | } | |
121 | ||
122 | ||
123 | #[derive(Copy, Clone, PartialEq, Debug)] | |
124 | pub enum AutoRef<'tcx> { | |
125 | /// Convert from T to &T. | |
126 | AutoPtr(&'tcx ty::Region, hir::Mutability), | |
127 | ||
128 | /// Convert from T to *T. | |
129 | /// Value to thin pointer. | |
130 | AutoUnsafe(hir::Mutability), | |
131 | } | |
132 | ||
133 | #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] | |
134 | pub enum CustomCoerceUnsized { | |
135 | /// Records the index of the field being coerced. | |
136 | Struct(usize) | |
137 | } | |
138 | ||
139 | impl<'tcx> ty::TyS<'tcx> { | |
140 | /// See `expr_ty_adjusted` | |
141 | pub fn adjust<F>(&'tcx self, cx: &ty::ctxt<'tcx>, | |
142 | span: Span, | |
143 | expr_id: ast::NodeId, | |
144 | adjustment: Option<&AutoAdjustment<'tcx>>, | |
145 | mut method_type: F) | |
146 | -> Ty<'tcx> where | |
147 | F: FnMut(ty::MethodCall) -> Option<Ty<'tcx>>, | |
148 | { | |
149 | if let ty::TyError = self.sty { | |
150 | return self; | |
151 | } | |
152 | ||
153 | return match adjustment { | |
154 | Some(adjustment) => { | |
155 | match *adjustment { | |
7453a54e | 156 | AdjustReifyFnPointer => { |
e9174d1e SL |
157 | match self.sty { |
158 | ty::TyBareFn(Some(_), b) => { | |
159 | cx.mk_fn(None, b) | |
160 | } | |
161 | _ => { | |
162 | cx.sess.bug( | |
163 | &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ | |
164 | {:?}", self)); | |
165 | } | |
166 | } | |
167 | } | |
168 | ||
7453a54e | 169 | AdjustUnsafeFnPointer => { |
e9174d1e SL |
170 | match self.sty { |
171 | ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b), | |
172 | ref b => { | |
173 | cx.sess.bug( | |
7453a54e | 174 | &format!("AdjustUnsafeFnPointer adjustment on non-fn-ptr: \ |
e9174d1e SL |
175 | {:?}", |
176 | b)); | |
177 | } | |
178 | } | |
7453a54e SL |
179 | } |
180 | ||
181 | AdjustMutToConstPointer => { | |
182 | match self.sty { | |
183 | ty::TyRawPtr(mt) => cx.mk_ptr(ty::TypeAndMut { | |
184 | ty: mt.ty, | |
185 | mutbl: hir::MutImmutable | |
186 | }), | |
187 | ref b => { | |
188 | cx.sess.bug( | |
189 | &format!("AdjustMutToConstPointer on non-raw-ptr: \ | |
190 | {:?}", | |
191 | b)); | |
192 | } | |
193 | } | |
194 | } | |
e9174d1e SL |
195 | |
196 | AdjustDerefRef(ref adj) => { | |
197 | let mut adjusted_ty = self; | |
198 | ||
199 | if !adjusted_ty.references_error() { | |
200 | for i in 0..adj.autoderefs { | |
201 | adjusted_ty = | |
202 | adjusted_ty.adjust_for_autoderef(cx, | |
203 | expr_id, | |
204 | span, | |
205 | i as u32, | |
206 | &mut method_type); | |
207 | } | |
208 | } | |
209 | ||
210 | if let Some(target) = adj.unsize { | |
211 | target | |
212 | } else { | |
213 | adjusted_ty.adjust_for_autoref(cx, adj.autoref) | |
214 | } | |
215 | } | |
216 | } | |
217 | } | |
218 | None => self | |
219 | }; | |
220 | } | |
221 | ||
222 | pub fn adjust_for_autoderef<F>(&'tcx self, | |
223 | cx: &ty::ctxt<'tcx>, | |
224 | expr_id: ast::NodeId, | |
225 | expr_span: Span, | |
226 | autoderef: u32, // how many autoderefs so far? | |
227 | mut method_type: F) | |
228 | -> Ty<'tcx> where | |
229 | F: FnMut(ty::MethodCall) -> Option<Ty<'tcx>>, | |
230 | { | |
231 | let method_call = ty::MethodCall::autoderef(expr_id, autoderef); | |
232 | let mut adjusted_ty = self; | |
233 | if let Some(method_ty) = method_type(method_call) { | |
234 | // Method calls always have all late-bound regions | |
235 | // fully instantiated. | |
236 | let fn_ret = cx.no_late_bound_regions(&method_ty.fn_ret()).unwrap(); | |
237 | adjusted_ty = fn_ret.unwrap(); | |
238 | } | |
239 | match adjusted_ty.builtin_deref(true, NoPreference) { | |
240 | Some(mt) => mt.ty, | |
241 | None => { | |
242 | cx.sess.span_bug( | |
243 | expr_span, | |
244 | &format!("the {}th autoderef failed: {}", | |
245 | autoderef, | |
246 | adjusted_ty) | |
247 | ); | |
248 | } | |
249 | } | |
250 | } | |
251 | ||
252 | pub fn adjust_for_autoref(&'tcx self, cx: &ty::ctxt<'tcx>, | |
253 | autoref: Option<AutoRef<'tcx>>) | |
254 | -> Ty<'tcx> { | |
255 | match autoref { | |
256 | None => self, | |
257 | Some(AutoPtr(r, m)) => { | |
258 | cx.mk_ref(r, TypeAndMut { ty: self, mutbl: m }) | |
259 | } | |
260 | Some(AutoUnsafe(m)) => { | |
261 | cx.mk_ptr(TypeAndMut { ty: self, mutbl: m }) | |
262 | } | |
263 | } | |
264 | } | |
265 | } |