]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/infer/coercion.rs
Refactor the unification code and rejuvenate the unit test
[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 use middle::subst;
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::resolve::try_resolve_tvar_shallow;
75 use util::common::indenter;
76 use util::ppaux::Repr;
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.repr(self.get_ref().infcx.tcx),
95                b.repr(self.get_ref().infcx.tcx));
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(r_b, 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                     ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds }) => {
118                         let result = self.unpack_actual_value(a, |sty_a| {
119                             match *sty_a {
120                                 ty::ty_rptr(_, mt_a) => match ty::get(mt_a.ty).sty {
121                                     ty::ty_trait(..) => {
122                                         self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl)
123                                     }
124                                     _ => self.coerce_object(a, sty_a, b, def_id, substs,
125                                                             ty::RegionTraitStore(r_b, mt_b.mutbl),
126                                                             bounds)
127                                 },
128                                 _ => self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl)
129                             }
130                         });
131
132                         match result {
133                             Ok(t) => return Ok(t),
134                             Err(..) => {}
135                         }
136                     }
137
138                     _ => {
139                         return self.unpack_actual_value(a, |sty_a| {
140                             self.coerce_borrowed_pointer(a, sty_a, b, mt_b)
141                         });
142                     }
143                 };
144             }
145
146             ty::ty_uniq(t_b) => {
147                 match ty::get(t_b).sty {
148                     ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds }) => {
149                         let result = self.unpack_actual_value(a, |sty_a| {
150                             match *sty_a {
151                                 ty::ty_uniq(t_a) => match ty::get(t_a).sty {
152                                     ty::ty_trait(..) => {
153                                         Err(ty::terr_mismatch)
154                                     }
155                                     _ => self.coerce_object(a, sty_a, b, def_id, substs,
156                                                             ty::UniqTraitStore, bounds)
157                                 },
158                                 _ => Err(ty::terr_mismatch)
159                             }
160                         });
161
162                         match result {
163                             Ok(t) => return Ok(t),
164                             Err(..) => {}
165                         }
166                     }
167                     _ => {}
168                 }
169             }
170
171             ty::ty_closure(box ty::ClosureTy {
172                     store: ty::RegionTraitStore(..),
173                     ..
174                 }) => {
175                 return self.unpack_actual_value(a, |sty_a| {
176                     self.coerce_borrowed_fn(a, sty_a, b)
177                 });
178             }
179
180             ty::ty_ptr(mt_b) => {
181                 return self.unpack_actual_value(a, |sty_a| {
182                     self.coerce_unsafe_ptr(a, sty_a, b, mt_b)
183                 });
184             }
185
186             _ => {}
187         }
188
189         self.unpack_actual_value(a, |sty_a| {
190             match *sty_a {
191                 ty::ty_bare_fn(ref a_f) => {
192                     // Bare functions are coercible to any closure type.
193                     //
194                     // FIXME(#3320) this should go away and be
195                     // replaced with proper inference, got a patch
196                     // underway - ndm
197                     self.coerce_from_bare_fn(a, a_f, b)
198                 }
199                 _ => {
200                     // Otherwise, just use subtyping rules.
201                     self.subtype(a, b)
202                 }
203             }
204         })
205     }
206
207     pub fn subtype(&self, a: ty::t, b: ty::t) -> CoerceResult {
208         match Sub(self.get_ref().clone()).tys(a, b) {
209             Ok(_) => Ok(None),         // No coercion required.
210             Err(ref e) => Err(*e)
211         }
212     }
213
214     pub fn unpack_actual_value(&self, a: ty::t, f: |&ty::sty| -> CoerceResult)
215                                -> CoerceResult {
216         match resolve_type(self.get_ref().infcx, a, try_resolve_tvar_shallow) {
217             Ok(t) => {
218                 f(&ty::get(t).sty)
219             }
220             Err(e) => {
221                 self.get_ref().infcx.tcx.sess.span_bug(
222                     self.get_ref().trace.origin.span(),
223                     format!("failed to resolve even without \
224                           any force options: {:?}", e).as_slice());
225             }
226         }
227     }
228
229     pub fn coerce_borrowed_pointer(&self,
230                                    a: ty::t,
231                                    sty_a: &ty::sty,
232                                    b: ty::t,
233                                    mt_b: ty::mt)
234                                    -> CoerceResult {
235         debug!("coerce_borrowed_pointer(a={}, sty_a={:?}, b={}, mt_b={:?})",
236                a.repr(self.get_ref().infcx.tcx), sty_a,
237                b.repr(self.get_ref().infcx.tcx), mt_b);
238
239         // If we have a parameter of type `&M T_a` and the value
240         // provided is `expr`, we will be adding an implicit borrow,
241         // meaning that we convert `f(expr)` to `f(&M *expr)`.  Therefore,
242         // to type check, we will construct the type that `&M*expr` would
243         // yield.
244
245         let sub = Sub(self.get_ref().clone());
246         let coercion = Coercion(self.get_ref().trace.clone());
247         let r_borrow = self.get_ref().infcx.next_region_var(coercion);
248
249         let inner_ty = match *sty_a {
250             ty::ty_box(typ) | ty::ty_uniq(typ) => typ,
251             ty::ty_rptr(_, mt_a) => mt_a.ty,
252             _ => {
253                 return self.subtype(a, b);
254             }
255         };
256
257         let a_borrowed = ty::mk_rptr(self.get_ref().infcx.tcx,
258                                      r_borrow,
259                                      mt {ty: inner_ty, mutbl: mt_b.mutbl});
260         if_ok!(sub.tys(a_borrowed, b));
261         Ok(Some(AutoDerefRef(AutoDerefRef {
262             autoderefs: 1,
263             autoref: Some(AutoPtr(r_borrow, mt_b.mutbl))
264         })))
265     }
266
267     pub fn coerce_borrowed_string(&self,
268                                   a: ty::t,
269                                   sty_a: &ty::sty,
270                                   b: ty::t)
271                                   -> CoerceResult {
272         debug!("coerce_borrowed_string(a={}, sty_a={:?}, b={})",
273                a.repr(self.get_ref().infcx.tcx), sty_a,
274                b.repr(self.get_ref().infcx.tcx));
275
276         match *sty_a {
277             ty::ty_uniq(t) => match ty::get(t).sty {
278                 ty::ty_str => {}
279                 _ => return self.subtype(a, b),
280             },
281             _ => {
282                 return self.subtype(a, b);
283             }
284         };
285
286         let coercion = Coercion(self.get_ref().trace.clone());
287         let r_a = self.get_ref().infcx.next_region_var(coercion);
288         let a_borrowed = ty::mk_str_slice(self.get_ref().infcx.tcx, r_a, ast::MutImmutable);
289         if_ok!(self.subtype(a_borrowed, b));
290         Ok(Some(AutoDerefRef(AutoDerefRef {
291             autoderefs: 0,
292             autoref: Some(AutoBorrowVec(r_a, MutImmutable))
293         })))
294     }
295
296     pub fn coerce_borrowed_vector(&self,
297                                   a: ty::t,
298                                   sty_a: &ty::sty,
299                                   b: ty::t,
300                                   mutbl_b: ast::Mutability)
301                                   -> CoerceResult {
302         debug!("coerce_borrowed_vector(a={}, sty_a={:?}, b={})",
303                a.repr(self.get_ref().infcx.tcx), sty_a,
304                b.repr(self.get_ref().infcx.tcx));
305
306         let sub = Sub(self.get_ref().clone());
307         let coercion = Coercion(self.get_ref().trace.clone());
308         let r_borrow = self.get_ref().infcx.next_region_var(coercion);
309         let ty_inner = match *sty_a {
310             ty::ty_uniq(t) | ty::ty_ptr(ty::mt{ty: t, ..}) |
311             ty::ty_rptr(_, ty::mt{ty: t, ..}) => match ty::get(t).sty {
312                 ty::ty_vec(mt, None) => mt.ty,
313                 _ => {
314                     return self.subtype(a, b);
315                 }
316             },
317             ty::ty_vec(mt, _) => mt.ty,
318             _ => {
319                 return self.subtype(a, b);
320             }
321         };
322
323         let a_borrowed = ty::mk_slice(self.get_ref().infcx.tcx, r_borrow,
324                                       mt {ty: ty_inner, mutbl: mutbl_b});
325         if_ok!(sub.tys(a_borrowed, b));
326         Ok(Some(AutoDerefRef(AutoDerefRef {
327             autoderefs: 0,
328             autoref: Some(AutoBorrowVec(r_borrow, mutbl_b))
329         })))
330     }
331
332     fn coerce_borrowed_object(&self,
333                               a: ty::t,
334                               sty_a: &ty::sty,
335                               b: ty::t,
336                               b_mutbl: ast::Mutability) -> CoerceResult
337     {
338         debug!("coerce_borrowed_object(a={}, sty_a={:?}, b={})",
339                a.repr(self.get_ref().infcx.tcx), sty_a,
340                b.repr(self.get_ref().infcx.tcx));
341
342         let tcx = self.get_ref().infcx.tcx;
343         let coercion = Coercion(self.get_ref().trace.clone());
344         let r_a = self.get_ref().infcx.next_region_var(coercion);
345
346         let a_borrowed = match *sty_a {
347             ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty {
348                 ty::ty_trait(box ty::TyTrait {
349                         def_id,
350                         ref substs,
351                         bounds,
352                         ..
353                     }) => {
354                     let tr = ty::mk_trait(tcx, def_id, substs.clone(), bounds);
355                     ty::mk_rptr(tcx, r_a, ty::mt{ mutbl: b_mutbl, ty: tr })
356                 }
357                 _ => {
358                     return self.subtype(a, b);
359                 }
360             },
361             _ => {
362                 return self.subtype(a, b);
363             }
364         };
365
366         if_ok!(self.subtype(a_borrowed, b));
367         Ok(Some(AutoDerefRef(AutoDerefRef {
368             autoderefs: 0,
369             autoref: Some(AutoBorrowObj(r_a, b_mutbl))
370         })))
371     }
372
373     pub fn coerce_borrowed_fn(&self,
374                               a: ty::t,
375                               sty_a: &ty::sty,
376                               b: ty::t)
377                               -> CoerceResult {
378         debug!("coerce_borrowed_fn(a={}, sty_a={:?}, b={})",
379                a.repr(self.get_ref().infcx.tcx), sty_a,
380                b.repr(self.get_ref().infcx.tcx));
381
382         match *sty_a {
383             ty::ty_bare_fn(ref f) => {
384                 self.coerce_from_bare_fn(a, f, b)
385             }
386             _ => {
387                 self.subtype(a, b)
388             }
389         }
390     }
391
392     fn coerce_from_bare_fn(&self, a: ty::t, fn_ty_a: &ty::BareFnTy, b: ty::t)
393                            -> CoerceResult {
394         /*!
395          *
396          * Attempts to coerce from a bare Rust function (`extern
397          * "Rust" fn`) into a closure or a `proc`.
398          */
399
400         self.unpack_actual_value(b, |sty_b| {
401
402             debug!("coerce_from_bare_fn(a={}, b={})",
403                    a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
404
405             if fn_ty_a.abi != abi::Rust || fn_ty_a.fn_style != ast::NormalFn {
406                 return self.subtype(a, b);
407             }
408
409             let fn_ty_b = match *sty_b {
410                 ty::ty_closure(ref f) => (*f).clone(),
411                 _ => return self.subtype(a, b)
412             };
413
414             let adj = ty::AutoAddEnv(fn_ty_b.store);
415             let a_closure = ty::mk_closure(self.get_ref().infcx.tcx,
416                                            ty::ClosureTy {
417                                                 sig: fn_ty_a.sig.clone(),
418                                                 .. *fn_ty_b
419                                            });
420             if_ok!(self.subtype(a_closure, b));
421             Ok(Some(adj))
422         })
423     }
424
425     pub fn coerce_unsafe_ptr(&self,
426                              a: ty::t,
427                              sty_a: &ty::sty,
428                              b: ty::t,
429                              mt_b: ty::mt)
430                              -> CoerceResult {
431         debug!("coerce_unsafe_ptr(a={}, sty_a={:?}, b={})",
432                a.repr(self.get_ref().infcx.tcx), sty_a,
433                b.repr(self.get_ref().infcx.tcx));
434
435         let mt_a = match *sty_a {
436             ty::ty_rptr(_, mt) => mt,
437             _ => {
438                 return self.subtype(a, b);
439             }
440         };
441
442         // check that the types which they point at are compatible
443         let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, mt_a);
444         if_ok!(self.subtype(a_unsafe, b));
445
446         // although references and unsafe ptrs have the same
447         // representation, we still register an AutoDerefRef so that
448         // regionck knows that the region for `a` must be valid here
449         Ok(Some(AutoDerefRef(AutoDerefRef {
450             autoderefs: 1,
451             autoref: Some(ty::AutoUnsafe(mt_b.mutbl))
452         })))
453     }
454
455     pub fn coerce_object(&self,
456                          a: ty::t,
457                          sty_a: &ty::sty,
458                          b: ty::t,
459                          trait_def_id: ast::DefId,
460                          trait_substs: &subst::Substs,
461                          trait_store: ty::TraitStore,
462                          bounds: ty::BuiltinBounds) -> CoerceResult {
463
464         debug!("coerce_object(a={}, sty_a={:?}, b={})",
465                a.repr(self.get_ref().infcx.tcx), sty_a,
466                b.repr(self.get_ref().infcx.tcx));
467
468         Ok(Some(ty::AutoObject(trait_store, bounds,
469                                trait_def_id, trait_substs.clone())))
470     }
471 }