]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/infer/coercion.rs
Ignore tests broken by failing on ICE
[rust.git] / src / librustc / middle / typeck / infer / coercion.rs
1 // Copyright 2012 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 /*!
12
13 # Type Coercion
14
15 Under certain circumstances we will coerce from one type to another,
16 for example by auto-borrowing.  This occurs in situations where the
17 compiler has a firm 'expected type' that was supplied from the user,
18 and where the actual type is similar to that expected type in purpose
19 but not in representation (so actual subtyping is inappropriate).
20
21 ## Reborrowing
22
23 Note that if we are expecting a reference, we will *reborrow*
24 even if the argument provided was already a reference.  This is
25 useful for freezing mut/const things (that is, when the expected is &T
26 but you have &const T or &mut T) and also for avoiding the linearity
27 of mut things (when the expected is &mut T and you have &mut T).  See
28 the various `src/test/run-pass/coerce-reborrow-*.rs` tests for
29 examples of where this is useful.
30
31 ## Subtle note
32
33 When deciding what type coercions to consider, we do not attempt to
34 resolve any type variables we may encounter.  This is because `b`
35 represents the expected type "as the user wrote it", meaning that if
36 the user defined a generic function like
37
38    fn foo<A>(a: A, b: A) { ... }
39
40 and then we wrote `foo(&1, @2)`, we will not auto-borrow
41 either argument.  In older code we went to some lengths to
42 resolve the `b` variable, which could mean that we'd
43 auto-borrow later arguments but not earlier ones, which
44 seems very confusing.
45
46 ## Subtler note
47
48 However, right now, if the user manually specifies the
49 values for the type variables, as so:
50
51    foo::<&int>(@1, @2)
52
53 then we *will* auto-borrow, because we can't distinguish this from a
54 function that declared `&int`.  This is inconsistent but it's easiest
55 at the moment. The right thing to do, I think, is to consider the
56 *unsubstituted* type when deciding whether to auto-borrow, but the
57 *substituted* type when considering the bounds and so forth. But most
58 of our methods don't give access to the unsubstituted type, and
59 rightly so because they'd be error-prone.  So maybe the thing to do is
60 to actually determine the kind of coercions that should occur
61 separately and pass them in.  Or maybe it's ok as is.  Anyway, it's
62 sort of a minor point so I've opted to leave it for later---after all
63 we may want to adjust precisely when coercions occur.
64
65 */
66
67
68 use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowObj, AutoDerefRef};
69 use middle::ty::{mt};
70 use middle::ty;
71 use middle::typeck::infer::{CoerceResult, resolve_type, Coercion};
72 use middle::typeck::infer::combine::{CombineFields, Combine};
73 use middle::typeck::infer::sub::Sub;
74 use middle::typeck::infer::to_str::InferStr;
75 use middle::typeck::infer::resolve::try_resolve_tvar_shallow;
76 use util::common::indenter;
77
78 use syntax::abi;
79 use syntax::ast::MutImmutable;
80 use syntax::ast;
81
82 // Note: Coerce is not actually a combiner, in that it does not
83 // conform to the same interface, though it performs a similar
84 // function.
85 pub struct Coerce<'f>(pub CombineFields<'f>);
86
87 impl<'f> Coerce<'f> {
88     pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f> {
89         let Coerce(ref v) = *self; v
90     }
91
92     pub fn tys(&self, a: ty::t, b: ty::t) -> CoerceResult {
93         debug!("Coerce.tys({} => {})",
94                a.inf_str(self.get_ref().infcx),
95                b.inf_str(self.get_ref().infcx));
96         let _indent = indenter();
97
98         // Examine the supertype and consider auto-borrowing.
99         //
100         // Note: does not attempt to resolve type variables we encounter.
101         // See above for details.
102         match ty::get(b).sty {
103             ty::ty_rptr(_, mt_b) => {
104                 match ty::get(mt_b.ty).sty {
105                     ty::ty_vec(mt_b, None) => {
106                         return self.unpack_actual_value(a, |sty_a| {
107                             self.coerce_borrowed_vector(a, sty_a, b, mt_b.mutbl)
108                         });
109                     }
110                     ty::ty_vec(_, _) => {},
111                     ty::ty_str => {
112                         return self.unpack_actual_value(a, |sty_a| {
113                             self.coerce_borrowed_string(a, sty_a, b)
114                         });
115                     }
116                     _ => {
117                         return self.unpack_actual_value(a, |sty_a| {
118                             self.coerce_borrowed_pointer(a, sty_a, b, mt_b)
119                         });
120                     }
121                 };
122             }
123
124             ty::ty_closure(~ty::ClosureTy {store: ty::RegionTraitStore(..), ..}) => {
125                 return self.unpack_actual_value(a, |sty_a| {
126                     self.coerce_borrowed_fn(a, sty_a, b)
127                 });
128             }
129
130             ty::ty_ptr(mt_b) => {
131                 return self.unpack_actual_value(a, |sty_a| {
132                     self.coerce_unsafe_ptr(a, sty_a, b, mt_b)
133                 });
134             }
135
136             ty::ty_trait(~ty::TyTrait {
137                 def_id, ref substs, store: ty::UniqTraitStore, bounds
138             }) => {
139                 let result = self.unpack_actual_value(a, |sty_a| {
140                     match *sty_a {
141                         ty::ty_uniq(..) => {
142                             self.coerce_object(a, sty_a, b, def_id, substs,
143                                                ty::UniqTraitStore, bounds)
144                         }
145                         _ => Err(ty::terr_mismatch)
146                     }
147                 });
148
149                 match result {
150                     Ok(t) => return Ok(t),
151                     Err(..) => {}
152                 }
153             }
154
155             ty::ty_trait(~ty::TyTrait {
156                 def_id, ref substs, store: ty::RegionTraitStore(region, m), bounds
157             }) => {
158                 let result = self.unpack_actual_value(a, |sty_a| {
159                     match *sty_a {
160                         ty::ty_rptr(..) => {
161                             self.coerce_object(a, sty_a, b, def_id, substs,
162                                                ty::RegionTraitStore(region, m), bounds)
163                         }
164                         _ => self.coerce_borrowed_object(a, sty_a, b, m)
165                     }
166                 });
167
168                 match result {
169                     Ok(t) => return Ok(t),
170                     Err(..) => {}
171                 }
172             }
173
174             _ => {}
175         }
176
177         self.unpack_actual_value(a, |sty_a| {
178             match *sty_a {
179                 ty::ty_bare_fn(ref a_f) => {
180                     // Bare functions are coercable to any closure type.
181                     //
182                     // FIXME(#3320) this should go away and be
183                     // replaced with proper inference, got a patch
184                     // underway - ndm
185                     self.coerce_from_bare_fn(a, a_f, b)
186                 }
187                 _ => {
188                     // Otherwise, just use subtyping rules.
189                     self.subtype(a, b)
190                 }
191             }
192         })
193     }
194
195     pub fn subtype(&self, a: ty::t, b: ty::t) -> CoerceResult {
196         match Sub(self.get_ref().clone()).tys(a, b) {
197             Ok(_) => Ok(None),         // No coercion required.
198             Err(ref e) => Err(*e)
199         }
200     }
201
202     pub fn unpack_actual_value(&self, a: ty::t, f: |&ty::sty| -> CoerceResult)
203                                -> CoerceResult {
204         match resolve_type(self.get_ref().infcx, a, try_resolve_tvar_shallow) {
205             Ok(t) => {
206                 f(&ty::get(t).sty)
207             }
208             Err(e) => {
209                 self.get_ref().infcx.tcx.sess.span_bug(
210                     self.get_ref().trace.origin.span(),
211                     format!("failed to resolve even without \
212                           any force options: {:?}", e));
213             }
214         }
215     }
216
217     pub fn coerce_borrowed_pointer(&self,
218                                    a: ty::t,
219                                    sty_a: &ty::sty,
220                                    b: ty::t,
221                                    mt_b: ty::mt)
222                                    -> CoerceResult {
223         debug!("coerce_borrowed_pointer(a={}, sty_a={:?}, b={}, mt_b={:?})",
224                a.inf_str(self.get_ref().infcx), sty_a,
225                b.inf_str(self.get_ref().infcx), mt_b);
226
227         // If we have a parameter of type `&M T_a` and the value
228         // provided is `expr`, we will be adding an implicit borrow,
229         // meaning that we convert `f(expr)` to `f(&M *expr)`.  Therefore,
230         // to type check, we will construct the type that `&M*expr` would
231         // yield.
232
233         let sub = Sub(self.get_ref().clone());
234         let coercion = Coercion(self.get_ref().trace.clone());
235         let r_borrow = self.get_ref().infcx.next_region_var(coercion);
236
237         let inner_ty = match *sty_a {
238             ty::ty_box(typ) | ty::ty_uniq(typ) => typ,
239             ty::ty_rptr(_, mt_a) => mt_a.ty,
240             _ => {
241                 return self.subtype(a, b);
242             }
243         };
244
245         let a_borrowed = ty::mk_rptr(self.get_ref().infcx.tcx,
246                                      r_borrow,
247                                      mt {ty: inner_ty, mutbl: mt_b.mutbl});
248         if_ok!(sub.tys(a_borrowed, b));
249         Ok(Some(AutoDerefRef(AutoDerefRef {
250             autoderefs: 1,
251             autoref: Some(AutoPtr(r_borrow, mt_b.mutbl))
252         })))
253     }
254
255     pub fn coerce_borrowed_string(&self,
256                                   a: ty::t,
257                                   sty_a: &ty::sty,
258                                   b: ty::t)
259                                   -> CoerceResult {
260         debug!("coerce_borrowed_string(a={}, sty_a={:?}, b={})",
261                a.inf_str(self.get_ref().infcx), sty_a,
262                b.inf_str(self.get_ref().infcx));
263
264         match *sty_a {
265             ty::ty_uniq(t) => match ty::get(t).sty {
266                 ty::ty_str => {}
267                 _ => return self.subtype(a, b),
268             },
269             _ => {
270                 return self.subtype(a, b);
271             }
272         };
273
274         let coercion = Coercion(self.get_ref().trace.clone());
275         let r_a = self.get_ref().infcx.next_region_var(coercion);
276         let a_borrowed = ty::mk_str_slice(self.get_ref().infcx.tcx, r_a, ast::MutImmutable);
277         if_ok!(self.subtype(a_borrowed, b));
278         Ok(Some(AutoDerefRef(AutoDerefRef {
279             autoderefs: 0,
280             autoref: Some(AutoBorrowVec(r_a, MutImmutable))
281         })))
282     }
283
284     pub fn coerce_borrowed_vector(&self,
285                                   a: ty::t,
286                                   sty_a: &ty::sty,
287                                   b: ty::t,
288                                   mutbl_b: ast::Mutability)
289                                   -> CoerceResult {
290         debug!("coerce_borrowed_vector(a={}, sty_a={:?}, b={})",
291                a.inf_str(self.get_ref().infcx), sty_a,
292                b.inf_str(self.get_ref().infcx));
293
294         let sub = Sub(self.get_ref().clone());
295         let coercion = Coercion(self.get_ref().trace.clone());
296         let r_borrow = self.get_ref().infcx.next_region_var(coercion);
297         let ty_inner = match *sty_a {
298             ty::ty_uniq(t) | ty::ty_ptr(ty::mt{ty: t, ..}) |
299             ty::ty_rptr(_, ty::mt{ty: t, ..}) => match ty::get(t).sty {
300                 ty::ty_vec(mt, None) => mt.ty,
301                 _ => {
302                     return self.subtype(a, b);
303                 }
304             },
305             ty::ty_vec(mt, _) => mt.ty,
306             _ => {
307                 return self.subtype(a, b);
308             }
309         };
310
311         let a_borrowed = ty::mk_slice(self.get_ref().infcx.tcx, r_borrow,
312                                       mt {ty: ty_inner, mutbl: mutbl_b});
313         if_ok!(sub.tys(a_borrowed, b));
314         Ok(Some(AutoDerefRef(AutoDerefRef {
315             autoderefs: 0,
316             autoref: Some(AutoBorrowVec(r_borrow, mutbl_b))
317         })))
318     }
319
320     fn coerce_borrowed_object(&self,
321                               a: ty::t,
322                               sty_a: &ty::sty,
323                               b: ty::t,
324                               b_mutbl: ast::Mutability) -> CoerceResult
325     {
326         debug!("coerce_borrowed_object(a={}, sty_a={:?}, b={})",
327                a.inf_str(self.get_ref().infcx), sty_a,
328                b.inf_str(self.get_ref().infcx));
329
330         let tcx = self.get_ref().infcx.tcx;
331         let coercion = Coercion(self.get_ref().trace.clone());
332         let r_a = self.get_ref().infcx.next_region_var(coercion);
333
334         let a_borrowed = match *sty_a {
335             ty::ty_trait(~ty::TyTrait { def_id, ref substs, bounds, .. }) => {
336                 ty::mk_trait(tcx, def_id, substs.clone(),
337                              ty::RegionTraitStore(r_a, b_mutbl), bounds)
338             }
339             _ => {
340                 return self.subtype(a, b);
341             }
342         };
343
344         if_ok!(self.subtype(a_borrowed, b));
345         Ok(Some(AutoDerefRef(AutoDerefRef {
346             autoderefs: 0,
347             autoref: Some(AutoBorrowObj(r_a, b_mutbl))
348         })))
349     }
350
351     pub fn coerce_borrowed_fn(&self,
352                               a: ty::t,
353                               sty_a: &ty::sty,
354                               b: ty::t)
355                               -> CoerceResult {
356         debug!("coerce_borrowed_fn(a={}, sty_a={:?}, b={})",
357                a.inf_str(self.get_ref().infcx), sty_a,
358                b.inf_str(self.get_ref().infcx));
359
360         match *sty_a {
361             ty::ty_bare_fn(ref f) => {
362                 self.coerce_from_bare_fn(a, f, b)
363             }
364             _ => {
365                 self.subtype(a, b)
366             }
367         }
368     }
369
370     fn coerce_from_bare_fn(&self, a: ty::t, fn_ty_a: &ty::BareFnTy, b: ty::t)
371                            -> CoerceResult {
372         /*!
373          *
374          * Attempts to coerce from a bare Rust function (`extern
375          * "Rust" fn`) into a closure or a `proc`.
376          */
377
378         self.unpack_actual_value(b, |sty_b| {
379
380             debug!("coerce_from_bare_fn(a={}, b={})",
381                    a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
382
383             if fn_ty_a.abi != abi::Rust || fn_ty_a.fn_style != ast::NormalFn {
384                 return self.subtype(a, b);
385             }
386
387             let fn_ty_b = match *sty_b {
388                 ty::ty_closure(ref f) => (*f).clone(),
389                 _ => return self.subtype(a, b)
390             };
391
392             let adj = ty::AutoAddEnv(fn_ty_b.store);
393             let a_closure = ty::mk_closure(self.get_ref().infcx.tcx,
394                                            ty::ClosureTy {
395                                                 sig: fn_ty_a.sig.clone(),
396                                                 .. *fn_ty_b
397                                            });
398             if_ok!(self.subtype(a_closure, b));
399             Ok(Some(adj))
400         })
401     }
402
403     pub fn coerce_unsafe_ptr(&self,
404                              a: ty::t,
405                              sty_a: &ty::sty,
406                              b: ty::t,
407                              mt_b: ty::mt)
408                              -> CoerceResult {
409         debug!("coerce_unsafe_ptr(a={}, sty_a={:?}, b={})",
410                a.inf_str(self.get_ref().infcx), sty_a,
411                b.inf_str(self.get_ref().infcx));
412
413         let mt_a = match *sty_a {
414             ty::ty_rptr(_, mt) => mt,
415             _ => {
416                 return self.subtype(a, b);
417             }
418         };
419
420         // check that the types which they point at are compatible
421         let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, mt_a);
422         if_ok!(self.subtype(a_unsafe, b));
423
424         // although references and unsafe ptrs have the same
425         // representation, we still register an AutoDerefRef so that
426         // regionck knows that the region for `a` must be valid here
427         Ok(Some(AutoDerefRef(AutoDerefRef {
428             autoderefs: 1,
429             autoref: Some(ty::AutoUnsafe(mt_b.mutbl))
430         })))
431     }
432
433     pub fn coerce_object(&self,
434                          a: ty::t,
435                          sty_a: &ty::sty,
436                          b: ty::t,
437                          trait_def_id: ast::DefId,
438                          trait_substs: &ty::substs,
439                          trait_store: ty::TraitStore,
440                          bounds: ty::BuiltinBounds) -> CoerceResult {
441
442         debug!("coerce_object(a={}, sty_a={:?}, b={})",
443                a.inf_str(self.get_ref().infcx), sty_a,
444                b.inf_str(self.get_ref().infcx));
445
446         Ok(Some(ty::AutoObject(trait_store, bounds,
447                                trait_def_id, trait_substs.clone())))
448     }
449 }