]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/infer/coercion.rs
doc: remove incomplete sentence
[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::{mod, Ty};
71 use util::ppaux;
72 use util::ppaux::Repr;
73
74 use syntax::abi;
75 use syntax::ast;
76
77 // Note: Coerce is not actually a combiner, in that it does not
78 // conform to the same interface, though it performs a similar
79 // function.
80 pub struct Coerce<'f, 'tcx: 'f>(pub CombineFields<'f, 'tcx>);
81
82 impl<'f, 'tcx> Coerce<'f, 'tcx> {
83     pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f, 'tcx> {
84         let Coerce(ref v) = *self; v
85     }
86
87     fn tcx(&self) -> &ty::ctxt<'tcx> {
88         self.get_ref().infcx.tcx
89     }
90
91     pub fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
92         debug!("Coerce.tys({} => {})",
93                a.repr(self.tcx()),
94                b.repr(self.tcx()));
95
96         // Consider coercing the subtype to a DST
97         let unsize = self.unpack_actual_value(a, |a| {
98             self.coerce_unsized(a, b)
99         });
100         if unsize.is_ok() {
101             return unsize;
102         }
103
104         // Examine the supertype and consider auto-borrowing.
105         //
106         // Note: does not attempt to resolve type variables we encounter.
107         // See above for details.
108         match b.sty {
109             ty::ty_ptr(mt_b) => {
110                 match mt_b.ty.sty {
111                     ty::ty_str => {
112                         return self.unpack_actual_value(a, |a| {
113                             self.coerce_unsafe_ptr(a, b, ast::MutImmutable)
114                         });
115                     }
116
117                     ty::ty_trait(..) => {
118                         let result = self.unpack_actual_value(a, |a| {
119                             self.coerce_unsafe_object(a, b, mt_b.mutbl)
120                         });
121
122                         match result {
123                             Ok(t) => return Ok(t),
124                             Err(..) => {}
125                         }
126                     }
127
128                     _ => {
129                         return self.unpack_actual_value(a, |a| {
130                             self.coerce_unsafe_ptr(a, b, mt_b.mutbl)
131                         });
132                     }
133                 };
134             }
135
136             ty::ty_rptr(_, mt_b) => {
137                 match mt_b.ty.sty {
138                     ty::ty_str => {
139                         return self.unpack_actual_value(a, |a| {
140                             self.coerce_borrowed_pointer(a, b, ast::MutImmutable)
141                         });
142                     }
143
144                     ty::ty_trait(..) => {
145                         let result = self.unpack_actual_value(a, |a| {
146                             self.coerce_borrowed_object(a, b, mt_b.mutbl)
147                         });
148
149                         match result {
150                             Ok(t) => return Ok(t),
151                             Err(..) => {}
152                         }
153                     }
154
155                     _ => {
156                         return self.unpack_actual_value(a, |a| {
157                             self.coerce_borrowed_pointer(a, b, mt_b.mutbl)
158                         });
159                     }
160                 };
161             }
162
163             ty::ty_closure(box ty::ClosureTy {
164                     store: ty::RegionTraitStore(..),
165                     ..
166                 }) => {
167                 return self.unpack_actual_value(a, |a| {
168                     self.coerce_borrowed_fn(a, b)
169                 });
170             }
171
172             _ => {}
173         }
174
175         self.unpack_actual_value(a, |a| {
176             match a.sty {
177                 ty::ty_bare_fn(Some(a_def_id), a_f) => {
178                     // Function items are coercible to any closure
179                     // type; function pointers are not (that would
180                     // require double indirection).
181                     self.coerce_from_fn_item(a, a_def_id, a_f, b)
182                 }
183                 _ => {
184                     // Otherwise, just use subtyping rules.
185                     self.subtype(a, b)
186                 }
187             }
188         })
189     }
190
191     pub fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
192         match Sub(self.get_ref().clone()).tys(a, b) {
193             Ok(_) => Ok(None),         // No coercion required.
194             Err(ref e) => Err(*e)
195         }
196     }
197
198     pub fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where
199         F: FnOnce(Ty<'tcx>) -> T,
200     {
201         f(self.get_ref().infcx.shallow_resolve(a))
202     }
203
204     // ~T -> &T or &mut T -> &T (including where T = [U] or str)
205     pub fn coerce_borrowed_pointer(&self,
206                                    a: Ty<'tcx>,
207                                    b: Ty<'tcx>,
208                                    mutbl_b: ast::Mutability)
209                                    -> CoerceResult<'tcx> {
210         debug!("coerce_borrowed_pointer(a={}, b={})",
211                a.repr(self.tcx()),
212                b.repr(self.tcx()));
213
214         // If we have a parameter of type `&M T_a` and the value
215         // provided is `expr`, we will be adding an implicit borrow,
216         // meaning that we convert `f(expr)` to `f(&M *expr)`.  Therefore,
217         // to type check, we will construct the type that `&M*expr` would
218         // yield.
219
220         let sub = Sub(self.get_ref().clone());
221         let coercion = Coercion(self.get_ref().trace.clone());
222         let r_borrow = self.get_ref().infcx.next_region_var(coercion);
223
224         let inner_ty = match a.sty {
225             ty::ty_uniq(_) => return Err(ty::terr_mismatch),
226             ty::ty_rptr(_, mt_a) => mt_a.ty,
227             _ => {
228                 return self.subtype(a, b);
229             }
230         };
231
232         let a_borrowed = ty::mk_rptr(self.tcx(),
233                                      self.tcx().mk_region(r_borrow),
234                                      mt {ty: inner_ty, mutbl: mutbl_b});
235         try!(sub.tys(a_borrowed, b));
236
237         Ok(Some(AdjustDerefRef(AutoDerefRef {
238             autoderefs: 1,
239             autoref: Some(AutoPtr(r_borrow, mutbl_b, None))
240         })))
241     }
242
243
244     // &[T, ..n] or &mut [T, ..n] -> &[T]
245     // or &mut [T, ..n] -> &mut [T]
246     // or &Concrete -> &Trait, etc.
247     fn coerce_unsized(&self,
248                       a: Ty<'tcx>,
249                       b: Ty<'tcx>)
250                       -> CoerceResult<'tcx> {
251         debug!("coerce_unsized(a={}, b={})",
252                a.repr(self.tcx()),
253                b.repr(self.tcx()));
254
255         // Note, we want to avoid unnecessary unsizing. We don't want to coerce to
256         // a DST unless we have to. This currently comes out in the wash since
257         // we can't unify [T] with U. But to properly support DST, we need to allow
258         // that, at which point we will need extra checks on b here.
259
260         let sub = Sub(self.get_ref().clone());
261
262         match (&a.sty, &b.sty) {
263             (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => {
264                 self.unpack_actual_value(t_a, |a| {
265                     match self.unsize_ty(t_a, a, mt_b.ty) {
266                         Some((ty, kind)) => {
267                             if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
268                                 return Err(ty::terr_mutability);
269                             }
270
271                             let coercion = Coercion(self.get_ref().trace.clone());
272                             let r_borrow = self.get_ref().infcx.next_region_var(coercion);
273                             let ty = ty::mk_rptr(self.tcx(),
274                                                  self.tcx().mk_region(r_borrow),
275                                                  ty::mt{ty: ty, mutbl: mt_b.mutbl});
276                             try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
277                             debug!("Success, coerced with AutoDerefRef(1, \
278                                     AutoPtr(AutoUnsize({})))", kind);
279                             Ok(Some(AdjustDerefRef(AutoDerefRef {
280                                 autoderefs: 1,
281                                 autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl,
282                                                           Some(box AutoUnsize(kind))))
283                             })))
284                         }
285                         _ => Err(ty::terr_mismatch)
286                     }
287                 })
288             }
289             (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => {
290                 self.unpack_actual_value(t_a, |a| {
291                     match self.unsize_ty(t_a, a, mt_b.ty) {
292                         Some((ty, kind)) => {
293                             if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
294                                 return Err(ty::terr_mutability);
295                             }
296
297                             let ty = ty::mk_ptr(self.tcx(),
298                                                  ty::mt{ty: ty, mutbl: mt_b.mutbl});
299                             try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
300                             debug!("Success, coerced with AutoDerefRef(1, \
301                                     AutoPtr(AutoUnsize({})))", kind);
302                             Ok(Some(AdjustDerefRef(AutoDerefRef {
303                                 autoderefs: 1,
304                                 autoref: Some(ty::AutoUnsafe(mt_b.mutbl,
305                                                              Some(box AutoUnsize(kind))))
306                             })))
307                         }
308                         _ => Err(ty::terr_mismatch)
309                     }
310                 })
311             }
312             (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => {
313                 self.unpack_actual_value(t_a, |a| {
314                     match self.unsize_ty(t_a, a, t_b) {
315                         Some((ty, kind)) => {
316                             let ty = ty::mk_uniq(self.tcx(), ty);
317                             try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
318                             debug!("Success, coerced with AutoDerefRef(1, \
319                                     AutoUnsizeUniq({}))", kind);
320                             Ok(Some(AdjustDerefRef(AutoDerefRef {
321                                 autoderefs: 1,
322                                 autoref: Some(ty::AutoUnsizeUniq(kind))
323                             })))
324                         }
325                         _ => Err(ty::terr_mismatch)
326                     }
327                 })
328             }
329             _ => Err(ty::terr_mismatch)
330         }
331     }
332
333     // Takes a type and returns an unsized version along with the adjustment
334     // performed to unsize it.
335     // E.g., `[T, ..n]` -> `([T], UnsizeLength(n))`
336     fn unsize_ty(&self,
337                  ty_a: Ty<'tcx>,
338                  a: Ty<'tcx>,
339                  ty_b: Ty<'tcx>)
340                  -> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)> {
341         debug!("unsize_ty(a={}, ty_b={})", a, ty_b.repr(self.tcx()));
342
343         let tcx = self.tcx();
344
345         self.unpack_actual_value(ty_b, |b|
346             match (&a.sty, &b.sty) {
347                 (&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => {
348                     let ty = ty::mk_vec(tcx, t_a, None);
349                     Some((ty, ty::UnsizeLength(len)))
350                 }
351                 (&ty::ty_trait(..), &ty::ty_trait(..)) => {
352                     None
353                 }
354                 (_, &ty::ty_trait(box ty::TyTrait { ref principal, ref bounds })) => {
355                     // FIXME what is the purpose of `ty`?
356                     let ty = ty::mk_trait(tcx, principal.clone(), bounds.clone());
357                     Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: principal.clone(),
358                                                              bounds: bounds.clone() },
359                                                ty_a)))
360                 }
361                 (&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b))
362                   if did_a == did_b => {
363                     debug!("unsizing a struct");
364                     // Try unsizing each type param in turn to see if we end up with ty_b.
365                     let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace);
366                     let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
367                     assert!(ty_substs_a.len() == ty_substs_b.len());
368
369                     let sub = Sub(self.get_ref().clone());
370
371                     let mut result = None;
372                     let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
373                     for (i, (tp_a, tp_b)) in tps {
374                         if self.get_ref().infcx.try(|_| sub.tys(*tp_a, *tp_b)).is_ok() {
375                             continue;
376                         }
377                         match
378                             self.unpack_actual_value(
379                                 *tp_a,
380                                 |tp| self.unsize_ty(*tp_a, tp, *tp_b))
381                         {
382                             Some((new_tp, k)) => {
383                                 // Check that the whole types match.
384                                 let mut new_substs = substs_a.clone();
385                                 new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
386                                 let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs));
387                                 if self.get_ref().infcx.try(|_| sub.tys(ty, ty_b)).is_err() {
388                                     debug!("Unsized type parameter '{}', but still \
389                                             could not match types {} and {}",
390                                            ppaux::ty_to_string(tcx, *tp_a),
391                                            ppaux::ty_to_string(tcx, ty),
392                                            ppaux::ty_to_string(tcx, ty_b));
393                                     // We can only unsize a single type parameter, so
394                                     // if we unsize one and it doesn't give us the
395                                     // type we want, then we won't succeed later.
396                                     break;
397                                 }
398
399                                 result = Some((ty, ty::UnsizeStruct(box k, i)));
400                                 break;
401                             }
402                             None => {}
403                         }
404                     }
405                     result
406                 }
407                 _ => None
408             }
409         )
410     }
411
412     fn coerce_borrowed_object(&self,
413                               a: Ty<'tcx>,
414                               b: Ty<'tcx>,
415                               b_mutbl: ast::Mutability) -> CoerceResult<'tcx>
416     {
417         let tcx = self.tcx();
418
419         debug!("coerce_borrowed_object(a={}, b={}, b_mutbl={})",
420                a.repr(tcx),
421                b.repr(tcx), b_mutbl);
422
423         let coercion = Coercion(self.get_ref().trace.clone());
424         let r_a = self.get_ref().infcx.next_region_var(coercion);
425
426         self.coerce_object(a, b, b_mutbl,
427                            |tr| ty::mk_rptr(tcx, tcx.mk_region(r_a),
428                                             ty::mt{ mutbl: b_mutbl, ty: tr }),
429                            || AutoPtr(r_a, b_mutbl, None))
430     }
431
432     fn coerce_unsafe_object(&self,
433                             a: Ty<'tcx>,
434                             b: Ty<'tcx>,
435                             b_mutbl: ast::Mutability) -> CoerceResult<'tcx>
436     {
437         let tcx = self.tcx();
438
439         debug!("coerce_unsafe_object(a={}, b={}, b_mutbl={})",
440                a.repr(tcx),
441                b.repr(tcx), b_mutbl);
442
443         self.coerce_object(a, b, b_mutbl,
444                            |tr| ty::mk_ptr(tcx, ty::mt{ mutbl: b_mutbl, ty: tr }),
445                            || AutoUnsafe(b_mutbl, None))
446     }
447
448     fn coerce_object<F, G>(&self,
449                            a: Ty<'tcx>,
450                            b: Ty<'tcx>,
451                            b_mutbl: ast::Mutability,
452                            mk_ty: F,
453                            mk_adjust: G) -> CoerceResult<'tcx> where
454         F: FnOnce(Ty<'tcx>) -> Ty<'tcx>,
455         G: FnOnce() -> ty::AutoRef<'tcx>,
456     {
457         let tcx = self.tcx();
458
459         match a.sty {
460             ty::ty_rptr(_, ty::mt{ty, mutbl}) => match ty.sty {
461                 ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => {
462                     debug!("mutbl={} b_mutbl={}", mutbl, b_mutbl);
463                     let tr = ty::mk_trait(tcx, principal.clone(), bounds.clone());
464                     try!(self.subtype(mk_ty(tr), b));
465                     Ok(Some(AdjustDerefRef(AutoDerefRef {
466                         autoderefs: 1,
467                         autoref: Some(mk_adjust())
468                     })))
469                 }
470                 _ => {
471                     self.subtype(a, b)
472                 }
473             },
474             _ => {
475                 self.subtype(a, b)
476             }
477         }
478     }
479
480     pub fn coerce_borrowed_fn(&self,
481                               a: Ty<'tcx>,
482                               b: Ty<'tcx>)
483                               -> CoerceResult<'tcx> {
484         debug!("coerce_borrowed_fn(a={}, b={})",
485                a.repr(self.tcx()),
486                b.repr(self.tcx()));
487
488         match a.sty {
489             ty::ty_bare_fn(Some(a_def_id), f) => {
490                 self.coerce_from_fn_item(a, a_def_id, f, b)
491             }
492             _ => {
493                 self.subtype(a, b)
494             }
495         }
496     }
497
498     fn coerce_from_fn_item(&self,
499                            a: Ty<'tcx>,
500                            fn_def_id_a: ast::DefId,
501                            fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
502                            b: Ty<'tcx>)
503                            -> CoerceResult<'tcx> {
504         /*!
505          * Attempts to coerce from the type of a Rust function item
506          * into a closure or a `proc`.
507          */
508
509         self.unpack_actual_value(b, |b| {
510             debug!("coerce_from_fn_item(a={}, b={})",
511                    a.repr(self.tcx()), b.repr(self.tcx()));
512
513             match b.sty {
514                 ty::ty_closure(ref f) => {
515                     if fn_ty_a.abi != abi::Rust || fn_ty_a.unsafety != ast::Unsafety::Normal {
516                         return self.subtype(a, b);
517                     }
518
519                     let fn_ty_b = (*f).clone();
520                     let adj = ty::AdjustAddEnv(fn_def_id_a, fn_ty_b.store);
521                     let a_closure = ty::mk_closure(self.tcx(),
522                                                    ty::ClosureTy {
523                                                        sig: fn_ty_a.sig.clone(),
524                                                        .. *fn_ty_b
525                                                    });
526                     try!(self.subtype(a_closure, b));
527                     Ok(Some(adj))
528                 }
529                 ty::ty_bare_fn(None, _) => {
530                     let a_fn_pointer = ty::mk_bare_fn(self.tcx(), None, fn_ty_a);
531                     try!(self.subtype(a_fn_pointer, b));
532                     Ok(Some(ty::AdjustReifyFnPointer(fn_def_id_a)))
533                 }
534                 _ => {
535                     return self.subtype(a, b)
536                 }
537             }
538         })
539     }
540
541     pub fn coerce_unsafe_ptr(&self,
542                              a: Ty<'tcx>,
543                              b: Ty<'tcx>,
544                              mutbl_b: ast::Mutability)
545                              -> CoerceResult<'tcx> {
546         debug!("coerce_unsafe_ptr(a={}, b={})",
547                a.repr(self.tcx()),
548                b.repr(self.tcx()));
549
550         let mt_a = match a.sty {
551             ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => mt,
552             _ => {
553                 return self.subtype(a, b);
554             }
555         };
556
557         // Check that the types which they point at are compatible.
558         let a_unsafe = ty::mk_ptr(self.tcx(), ty::mt{ mutbl: mutbl_b, ty: mt_a.ty });
559         try!(self.subtype(a_unsafe, b));
560         if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) {
561             return Err(ty::terr_mutability);
562         }
563
564         // Although references and unsafe ptrs have the same
565         // representation, we still register an AutoDerefRef so that
566         // regionck knows that the region for `a` must be valid here.
567         Ok(Some(AdjustDerefRef(AutoDerefRef {
568             autoderefs: 1,
569             autoref: Some(ty::AutoUnsafe(mutbl_b, None))
570         })))
571     }
572 }
573
574 fn can_coerce_mutbls(from_mutbl: ast::Mutability,
575                      to_mutbl: ast::Mutability)
576                      -> bool {
577     match (from_mutbl, to_mutbl) {
578         (ast::MutMutable, ast::MutMutable) => true,
579         (ast::MutImmutable, ast::MutImmutable) => true,
580         (ast::MutMutable, ast::MutImmutable) => true,
581         (ast::MutImmutable, ast::MutMutable) => false,
582     }
583 }