]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/infer/coercion.rs
rollup merge of #21438: taralx/kill-racycell
[rust.git] / src / librustc / middle / 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 //! # Type Coercion
12 //!
13 //! Under certain circumstances we will coerce from one type to another,
14 //! for example by auto-borrowing.  This occurs in situations where the
15 //! compiler has a firm 'expected type' that was supplied from the user,
16 //! and where the actual type is similar to that expected type in purpose
17 //! but not in representation (so actual subtyping is inappropriate).
18 //!
19 //! ## Reborrowing
20 //!
21 //! Note that if we are expecting a reference, we will *reborrow*
22 //! even if the argument provided was already a reference.  This is
23 //! useful for freezing mut/const things (that is, when the expected is &T
24 //! but you have &const T or &mut T) and also for avoiding the linearity
25 //! of mut things (when the expected is &mut T and you have &mut T).  See
26 //! the various `src/test/run-pass/coerce-reborrow-*.rs` tests for
27 //! examples of where this is useful.
28 //!
29 //! ## Subtle note
30 //!
31 //! When deciding what type coercions to consider, we do not attempt to
32 //! resolve any type variables we may encounter.  This is because `b`
33 //! represents the expected type "as the user wrote it", meaning that if
34 //! the user defined a generic function like
35 //!
36 //!    fn foo<A>(a: A, b: A) { ... }
37 //!
38 //! and then we wrote `foo(&1, @2)`, we will not auto-borrow
39 //! either argument.  In older code we went to some lengths to
40 //! resolve the `b` variable, which could mean that we'd
41 //! auto-borrow later arguments but not earlier ones, which
42 //! seems very confusing.
43 //!
44 //! ## Subtler note
45 //!
46 //! However, right now, if the user manually specifies the
47 //! values for the type variables, as so:
48 //!
49 //!    foo::<&int>(@1, @2)
50 //!
51 //! then we *will* auto-borrow, because we can't distinguish this from a
52 //! function that declared `&int`.  This is inconsistent but it's easiest
53 //! at the moment. The right thing to do, I think, is to consider the
54 //! *unsubstituted* type when deciding whether to auto-borrow, but the
55 //! *substituted* type when considering the bounds and so forth. But most
56 //! of our methods don't give access to the unsubstituted type, and
57 //! rightly so because they'd be error-prone.  So maybe the thing to do is
58 //! to actually determine the kind of coercions that should occur
59 //! separately and pass them in.  Or maybe it's ok as is.  Anyway, it's
60 //! sort of a minor point so I've opted to leave it for later---after all
61 //! we may want to adjust precisely when coercions occur.
62
63 use super::{CoerceResult, Coercion};
64 use super::combine::{CombineFields, Combine};
65 use super::sub::Sub;
66
67 use middle::subst;
68 use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe};
69 use middle::ty::{mt};
70 use middle::ty::{self, Ty};
71 use util::ppaux;
72 use util::ppaux::Repr;
73
74 use syntax::ast;
75
76 // Note: Coerce is not actually a combiner, in that it does not
77 // conform to the same interface, though it performs a similar
78 // function.
79 pub struct Coerce<'f, 'tcx: 'f>(pub CombineFields<'f, 'tcx>);
80
81 impl<'f, 'tcx> Coerce<'f, 'tcx> {
82     pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f, 'tcx> {
83         let Coerce(ref v) = *self; v
84     }
85
86     fn tcx(&self) -> &ty::ctxt<'tcx> {
87         self.get_ref().infcx.tcx
88     }
89
90     pub fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
91         debug!("Coerce.tys({} => {})",
92                a.repr(self.tcx()),
93                b.repr(self.tcx()));
94
95         // Consider coercing the subtype to a DST
96         let unsize = self.unpack_actual_value(a, |a| {
97             self.coerce_unsized(a, b)
98         });
99         if unsize.is_ok() {
100             return unsize;
101         }
102
103         // Examine the supertype and consider auto-borrowing.
104         //
105         // Note: does not attempt to resolve type variables we encounter.
106         // See above for details.
107         match b.sty {
108             ty::ty_ptr(mt_b) => {
109                 match mt_b.ty.sty {
110                     ty::ty_str => {
111                         return self.unpack_actual_value(a, |a| {
112                             self.coerce_unsafe_ptr(a, b, ast::MutImmutable)
113                         });
114                     }
115
116                     ty::ty_trait(..) => {
117                         let result = self.unpack_actual_value(a, |a| {
118                             self.coerce_unsafe_object(a, b, mt_b.mutbl)
119                         });
120
121                         match result {
122                             Ok(t) => return Ok(t),
123                             Err(..) => {}
124                         }
125                     }
126
127                     _ => {
128                         return self.unpack_actual_value(a, |a| {
129                             self.coerce_unsafe_ptr(a, b, mt_b.mutbl)
130                         });
131                     }
132                 };
133             }
134
135             ty::ty_rptr(_, mt_b) => {
136                 match mt_b.ty.sty {
137                     ty::ty_str => {
138                         return self.unpack_actual_value(a, |a| {
139                             self.coerce_borrowed_pointer(a, b, ast::MutImmutable)
140                         });
141                     }
142
143                     ty::ty_trait(..) => {
144                         let result = self.unpack_actual_value(a, |a| {
145                             self.coerce_borrowed_object(a, b, mt_b.mutbl)
146                         });
147
148                         match result {
149                             Ok(t) => return Ok(t),
150                             Err(..) => {}
151                         }
152                     }
153
154                     _ => {
155                         return self.unpack_actual_value(a, |a| {
156                             self.coerce_borrowed_pointer(a, b, mt_b.mutbl)
157                         });
158                     }
159                 };
160             }
161
162             _ => {}
163         }
164
165         self.unpack_actual_value(a, |a| {
166             match a.sty {
167                 ty::ty_bare_fn(Some(a_def_id), a_f) => {
168                     // Function items are coercible to any closure
169                     // type; function pointers are not (that would
170                     // require double indirection).
171                     self.coerce_from_fn_item(a, a_def_id, a_f, b)
172                 }
173                 _ => {
174                     // Otherwise, just use subtyping rules.
175                     self.subtype(a, b)
176                 }
177             }
178         })
179     }
180
181     pub fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
182         match Sub(self.get_ref().clone()).tys(a, b) {
183             Ok(_) => Ok(None),         // No coercion required.
184             Err(ref e) => Err(*e)
185         }
186     }
187
188     pub fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where
189         F: FnOnce(Ty<'tcx>) -> T,
190     {
191         f(self.get_ref().infcx.shallow_resolve(a))
192     }
193
194     // ~T -> &T or &mut T -> &T (including where T = [U] or str)
195     pub fn coerce_borrowed_pointer(&self,
196                                    a: Ty<'tcx>,
197                                    b: Ty<'tcx>,
198                                    mutbl_b: ast::Mutability)
199                                    -> CoerceResult<'tcx> {
200         debug!("coerce_borrowed_pointer(a={}, b={})",
201                a.repr(self.tcx()),
202                b.repr(self.tcx()));
203
204         // If we have a parameter of type `&M T_a` and the value
205         // provided is `expr`, we will be adding an implicit borrow,
206         // meaning that we convert `f(expr)` to `f(&M *expr)`.  Therefore,
207         // to type check, we will construct the type that `&M*expr` would
208         // yield.
209
210         let sub = Sub(self.get_ref().clone());
211         let coercion = Coercion(self.get_ref().trace.clone());
212         let r_borrow = self.get_ref().infcx.next_region_var(coercion);
213
214         let inner_ty = match a.sty {
215             ty::ty_uniq(_) => return Err(ty::terr_mismatch),
216             ty::ty_rptr(_, mt_a) => {
217                 if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) {
218                     return Err(ty::terr_mutability);
219                 }
220                 mt_a.ty
221             }
222             _ => {
223                 return self.subtype(a, b);
224             }
225         };
226
227         let a_borrowed = ty::mk_rptr(self.tcx(),
228                                      self.tcx().mk_region(r_borrow),
229                                      mt {ty: inner_ty, mutbl: mutbl_b});
230         try!(sub.tys(a_borrowed, b));
231
232         Ok(Some(AdjustDerefRef(AutoDerefRef {
233             autoderefs: 1,
234             autoref: Some(AutoPtr(r_borrow, mutbl_b, None))
235         })))
236     }
237
238
239     // &[T, ..n] or &mut [T, ..n] -> &[T]
240     // or &mut [T, ..n] -> &mut [T]
241     // or &Concrete -> &Trait, etc.
242     fn coerce_unsized(&self,
243                       a: Ty<'tcx>,
244                       b: Ty<'tcx>)
245                       -> CoerceResult<'tcx> {
246         debug!("coerce_unsized(a={}, b={})",
247                a.repr(self.tcx()),
248                b.repr(self.tcx()));
249
250         // Note, we want to avoid unnecessary unsizing. We don't want to coerce to
251         // a DST unless we have to. This currently comes out in the wash since
252         // we can't unify [T] with U. But to properly support DST, we need to allow
253         // that, at which point we will need extra checks on b here.
254
255         let sub = Sub(self.get_ref().clone());
256
257         match (&a.sty, &b.sty) {
258             (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => {
259                 self.unpack_actual_value(t_a, |a| {
260                     match self.unsize_ty(t_a, a, mt_b.ty) {
261                         Some((ty, kind)) => {
262                             if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
263                                 return Err(ty::terr_mutability);
264                             }
265
266                             let coercion = Coercion(self.get_ref().trace.clone());
267                             let r_borrow = self.get_ref().infcx.next_region_var(coercion);
268                             let ty = ty::mk_rptr(self.tcx(),
269                                                  self.tcx().mk_region(r_borrow),
270                                                  ty::mt{ty: ty, mutbl: mt_b.mutbl});
271                             try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
272                             debug!("Success, coerced with AutoDerefRef(1, \
273                                     AutoPtr(AutoUnsize({:?})))", kind);
274                             Ok(Some(AdjustDerefRef(AutoDerefRef {
275                                 autoderefs: 1,
276                                 autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl,
277                                                           Some(box AutoUnsize(kind))))
278                             })))
279                         }
280                         _ => Err(ty::terr_mismatch)
281                     }
282                 })
283             }
284             (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => {
285                 self.unpack_actual_value(t_a, |a| {
286                     match self.unsize_ty(t_a, a, mt_b.ty) {
287                         Some((ty, kind)) => {
288                             if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
289                                 return Err(ty::terr_mutability);
290                             }
291
292                             let ty = ty::mk_ptr(self.tcx(),
293                                                  ty::mt{ty: ty, mutbl: mt_b.mutbl});
294                             try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
295                             debug!("Success, coerced with AutoDerefRef(1, \
296                                     AutoPtr(AutoUnsize({:?})))", kind);
297                             Ok(Some(AdjustDerefRef(AutoDerefRef {
298                                 autoderefs: 1,
299                                 autoref: Some(ty::AutoUnsafe(mt_b.mutbl,
300                                                              Some(box AutoUnsize(kind))))
301                             })))
302                         }
303                         _ => Err(ty::terr_mismatch)
304                     }
305                 })
306             }
307             (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => {
308                 self.unpack_actual_value(t_a, |a| {
309                     match self.unsize_ty(t_a, a, t_b) {
310                         Some((ty, kind)) => {
311                             let ty = ty::mk_uniq(self.tcx(), ty);
312                             try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
313                             debug!("Success, coerced with AutoDerefRef(1, \
314                                     AutoUnsizeUniq({:?}))", kind);
315                             Ok(Some(AdjustDerefRef(AutoDerefRef {
316                                 autoderefs: 1,
317                                 autoref: Some(ty::AutoUnsizeUniq(kind))
318                             })))
319                         }
320                         _ => Err(ty::terr_mismatch)
321                     }
322                 })
323             }
324             _ => Err(ty::terr_mismatch)
325         }
326     }
327
328     // Takes a type and returns an unsized version along with the adjustment
329     // performed to unsize it.
330     // E.g., `[T, ..n]` -> `([T], UnsizeLength(n))`
331     fn unsize_ty(&self,
332                  ty_a: Ty<'tcx>,
333                  a: Ty<'tcx>,
334                  ty_b: Ty<'tcx>)
335                  -> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)> {
336         debug!("unsize_ty(a={:?}, ty_b={})", a, ty_b.repr(self.tcx()));
337
338         let tcx = self.tcx();
339
340         self.unpack_actual_value(ty_b, |b|
341             match (&a.sty, &b.sty) {
342                 (&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => {
343                     let ty = ty::mk_vec(tcx, t_a, None);
344                     Some((ty, ty::UnsizeLength(len)))
345                 }
346                 (&ty::ty_trait(..), &ty::ty_trait(..)) => {
347                     None
348                 }
349                 (_, &ty::ty_trait(box ty::TyTrait { ref principal, ref bounds })) => {
350                     // FIXME what is the purpose of `ty`?
351                     let ty = ty::mk_trait(tcx, principal.clone(), bounds.clone());
352                     Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: principal.clone(),
353                                                              bounds: bounds.clone() },
354                                                ty_a)))
355                 }
356                 (&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b))
357                   if did_a == did_b => {
358                     debug!("unsizing a struct");
359                     // Try unsizing each type param in turn to see if we end up with ty_b.
360                     let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace);
361                     let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
362                     assert!(ty_substs_a.len() == ty_substs_b.len());
363
364                     let sub = Sub(self.get_ref().clone());
365
366                     let mut result = None;
367                     let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
368                     for (i, (tp_a, tp_b)) in tps {
369                         if self.get_ref().infcx.try(|_| sub.tys(*tp_a, *tp_b)).is_ok() {
370                             continue;
371                         }
372                         match
373                             self.unpack_actual_value(
374                                 *tp_a,
375                                 |tp| self.unsize_ty(*tp_a, tp, *tp_b))
376                         {
377                             Some((new_tp, k)) => {
378                                 // Check that the whole types match.
379                                 let mut new_substs = substs_a.clone();
380                                 new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
381                                 let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs));
382                                 if self.get_ref().infcx.try(|_| sub.tys(ty, ty_b)).is_err() {
383                                     debug!("Unsized type parameter '{}', but still \
384                                             could not match types {} and {}",
385                                            ppaux::ty_to_string(tcx, *tp_a),
386                                            ppaux::ty_to_string(tcx, ty),
387                                            ppaux::ty_to_string(tcx, ty_b));
388                                     // We can only unsize a single type parameter, so
389                                     // if we unsize one and it doesn't give us the
390                                     // type we want, then we won't succeed later.
391                                     break;
392                                 }
393
394                                 result = Some((ty, ty::UnsizeStruct(box k, i)));
395                                 break;
396                             }
397                             None => {}
398                         }
399                     }
400                     result
401                 }
402                 _ => None
403             }
404         )
405     }
406
407     fn coerce_borrowed_object(&self,
408                               a: Ty<'tcx>,
409                               b: Ty<'tcx>,
410                               b_mutbl: ast::Mutability) -> CoerceResult<'tcx>
411     {
412         let tcx = self.tcx();
413
414         debug!("coerce_borrowed_object(a={}, b={}, b_mutbl={:?})",
415                a.repr(tcx),
416                b.repr(tcx), b_mutbl);
417
418         let coercion = Coercion(self.get_ref().trace.clone());
419         let r_a = self.get_ref().infcx.next_region_var(coercion);
420
421         self.coerce_object(a, b, b_mutbl,
422                            |tr| ty::mk_rptr(tcx, tcx.mk_region(r_a),
423                                             ty::mt{ mutbl: b_mutbl, ty: tr }),
424                            || AutoPtr(r_a, b_mutbl, None))
425     }
426
427     fn coerce_unsafe_object(&self,
428                             a: Ty<'tcx>,
429                             b: Ty<'tcx>,
430                             b_mutbl: ast::Mutability) -> CoerceResult<'tcx>
431     {
432         let tcx = self.tcx();
433
434         debug!("coerce_unsafe_object(a={}, b={}, b_mutbl={:?})",
435                a.repr(tcx),
436                b.repr(tcx), b_mutbl);
437
438         self.coerce_object(a, b, b_mutbl,
439                            |tr| ty::mk_ptr(tcx, ty::mt{ mutbl: b_mutbl, ty: tr }),
440                            || AutoUnsafe(b_mutbl, None))
441     }
442
443     fn coerce_object<F, G>(&self,
444                            a: Ty<'tcx>,
445                            b: Ty<'tcx>,
446                            b_mutbl: ast::Mutability,
447                            mk_ty: F,
448                            mk_adjust: G) -> CoerceResult<'tcx> where
449         F: FnOnce(Ty<'tcx>) -> Ty<'tcx>,
450         G: FnOnce() -> ty::AutoRef<'tcx>,
451     {
452         let tcx = self.tcx();
453
454         match a.sty {
455             ty::ty_rptr(_, ty::mt{ty, mutbl}) => match ty.sty {
456                 ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => {
457                     debug!("mutbl={:?} b_mutbl={:?}", mutbl, b_mutbl);
458                     let tr = ty::mk_trait(tcx, principal.clone(), bounds.clone());
459                     try!(self.subtype(mk_ty(tr), b));
460                     Ok(Some(AdjustDerefRef(AutoDerefRef {
461                         autoderefs: 1,
462                         autoref: Some(mk_adjust())
463                     })))
464                 }
465                 _ => {
466                     self.subtype(a, b)
467                 }
468             },
469             _ => {
470                 self.subtype(a, b)
471             }
472         }
473     }
474
475     pub fn coerce_borrowed_fn(&self,
476                               a: Ty<'tcx>,
477                               b: Ty<'tcx>)
478                               -> CoerceResult<'tcx> {
479         debug!("coerce_borrowed_fn(a={}, b={})",
480                a.repr(self.tcx()),
481                b.repr(self.tcx()));
482
483         match a.sty {
484             ty::ty_bare_fn(Some(a_def_id), f) => {
485                 self.coerce_from_fn_item(a, a_def_id, f, b)
486             }
487             _ => {
488                 self.subtype(a, b)
489             }
490         }
491     }
492
493     fn coerce_from_fn_item(&self,
494                            a: Ty<'tcx>,
495                            fn_def_id_a: ast::DefId,
496                            fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
497                            b: Ty<'tcx>)
498                            -> CoerceResult<'tcx> {
499         /*!
500          * Attempts to coerce from the type of a Rust function item
501          * into a closure or a `proc`.
502          */
503
504         self.unpack_actual_value(b, |b| {
505             debug!("coerce_from_fn_item(a={}, b={})",
506                    a.repr(self.tcx()), b.repr(self.tcx()));
507
508             match b.sty {
509                 ty::ty_bare_fn(None, _) => {
510                     let a_fn_pointer = ty::mk_bare_fn(self.tcx(), None, fn_ty_a);
511                     try!(self.subtype(a_fn_pointer, b));
512                     Ok(Some(ty::AdjustReifyFnPointer(fn_def_id_a)))
513                 }
514                 _ => {
515                     return self.subtype(a, b)
516                 }
517             }
518         })
519     }
520
521     pub fn coerce_unsafe_ptr(&self,
522                              a: Ty<'tcx>,
523                              b: Ty<'tcx>,
524                              mutbl_b: ast::Mutability)
525                              -> CoerceResult<'tcx> {
526         debug!("coerce_unsafe_ptr(a={}, b={})",
527                a.repr(self.tcx()),
528                b.repr(self.tcx()));
529
530         let mt_a = match a.sty {
531             ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => mt,
532             _ => {
533                 return self.subtype(a, b);
534             }
535         };
536
537         // Check that the types which they point at are compatible.
538         let a_unsafe = ty::mk_ptr(self.tcx(), ty::mt{ mutbl: mutbl_b, ty: mt_a.ty });
539         try!(self.subtype(a_unsafe, b));
540         if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) {
541             return Err(ty::terr_mutability);
542         }
543
544         // Although references and unsafe ptrs have the same
545         // representation, we still register an AutoDerefRef so that
546         // regionck knows that the region for `a` must be valid here.
547         Ok(Some(AdjustDerefRef(AutoDerefRef {
548             autoderefs: 1,
549             autoref: Some(ty::AutoUnsafe(mutbl_b, None))
550         })))
551     }
552 }
553
554 fn can_coerce_mutbls(from_mutbl: ast::Mutability,
555                      to_mutbl: ast::Mutability)
556                      -> bool {
557     match (from_mutbl, to_mutbl) {
558         (ast::MutMutable, ast::MutMutable) => true,
559         (ast::MutImmutable, ast::MutImmutable) => true,
560         (ast::MutMutable, ast::MutImmutable) => true,
561         (ast::MutImmutable, ast::MutMutable) => false,
562     }
563 }