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.
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.
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).
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.
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
38 fn foo<A>(a: A, b: A) { ... }
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
48 However, right now, if the user manually specifies the
49 values for the type variables, as so:
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.
68 use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe};
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;
77 use util::ppaux::Repr;
82 // Note: Coerce is not actually a combiner, in that it does not
83 // conform to the same interface, though it performs a similar
85 pub struct Coerce<'f, 'tcx: 'f>(pub CombineFields<'f, 'tcx>);
87 impl<'f, 'tcx> Coerce<'f, 'tcx> {
88 pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f, 'tcx> {
89 let Coerce(ref v) = *self; v
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();
98 // Special case: if the subtype is a sized array literal (`[T, ..n]`),
99 // then it would get auto-borrowed to `&[T, ..n]` and then DST-ified
100 // to `&[T]`. Doing it all at once makes the target code a bit more
101 // efficient and spares us from having to handle multiple coercions.
102 match ty::get(b).sty {
103 ty::ty_ptr(mt_b) | ty::ty_rptr(_, mt_b) => {
104 match ty::get(mt_b.ty).sty {
105 ty::ty_vec(_, None) => {
106 let unsize_and_ref = self.unpack_actual_value(a, |sty_a| {
107 self.coerce_unsized_with_borrow(a, sty_a, b, mt_b.mutbl)
109 if unsize_and_ref.is_ok() {
110 return unsize_and_ref;
119 // Consider coercing the subtype to a DST
120 let unsize = self.unpack_actual_value(a, |sty_a| {
121 self.coerce_unsized(a, sty_a, b)
127 // Examine the supertype and consider auto-borrowing.
129 // Note: does not attempt to resolve type variables we encounter.
130 // See above for details.
131 match ty::get(b).sty {
132 ty::ty_ptr(mt_b) => {
133 match ty::get(mt_b.ty).sty {
135 return self.unpack_actual_value(a, |sty_a| {
136 self.coerce_unsafe_ptr(a, sty_a, b, ast::MutImmutable)
140 ty::ty_trait(..) => {
141 let result = self.unpack_actual_value(a, |sty_a| {
142 self.coerce_unsafe_object(a, sty_a, b, mt_b.mutbl)
146 Ok(t) => return Ok(t),
152 return self.unpack_actual_value(a, |sty_a| {
153 self.coerce_unsafe_ptr(a, sty_a, b, mt_b.mutbl)
159 ty::ty_rptr(_, mt_b) => {
160 match ty::get(mt_b.ty).sty {
162 return self.unpack_actual_value(a, |sty_a| {
163 self.coerce_borrowed_pointer(a, sty_a, b, ast::MutImmutable)
167 ty::ty_trait(..) => {
168 let result = self.unpack_actual_value(a, |sty_a| {
169 self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl)
173 Ok(t) => return Ok(t),
179 return self.unpack_actual_value(a, |sty_a| {
180 self.coerce_borrowed_pointer(a, sty_a, b, mt_b.mutbl)
186 ty::ty_closure(box ty::ClosureTy {
187 store: ty::RegionTraitStore(..),
190 return self.unpack_actual_value(a, |sty_a| {
191 self.coerce_borrowed_fn(a, sty_a, b)
198 self.unpack_actual_value(a, |sty_a| {
200 ty::ty_bare_fn(ref a_f) => {
201 // Bare functions are coercible to any closure type.
203 // FIXME(#3320) this should go away and be
204 // replaced with proper inference, got a patch
206 self.coerce_from_bare_fn(a, a_f, b)
209 // Otherwise, just use subtyping rules.
216 pub fn subtype(&self, a: ty::t, b: ty::t) -> CoerceResult {
217 match Sub(self.get_ref().clone()).tys(a, b) {
218 Ok(_) => Ok(None), // No coercion required.
219 Err(ref e) => Err(*e)
223 pub fn unpack_actual_value<T>(&self, a: ty::t, f: |&ty::sty| -> T)
225 match resolve_type(self.get_ref().infcx, None,
226 a, try_resolve_tvar_shallow) {
231 self.get_ref().infcx.tcx.sess.span_bug(
232 self.get_ref().trace.origin.span(),
233 format!("failed to resolve even without \
234 any force options: {:?}", e).as_slice());
239 // ~T -> &T or &mut T -> &T (including where T = [U] or str)
240 pub fn coerce_borrowed_pointer(&self,
244 mutbl_b: ast::Mutability)
246 debug!("coerce_borrowed_pointer(a={}, sty_a={:?}, b={})",
247 a.repr(self.get_ref().infcx.tcx), sty_a,
248 b.repr(self.get_ref().infcx.tcx));
250 // If we have a parameter of type `&M T_a` and the value
251 // provided is `expr`, we will be adding an implicit borrow,
252 // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore,
253 // to type check, we will construct the type that `&M*expr` would
256 let sub = Sub(self.get_ref().clone());
257 let coercion = Coercion(self.get_ref().trace.clone());
258 let r_borrow = self.get_ref().infcx.next_region_var(coercion);
260 let inner_ty = match *sty_a {
261 ty::ty_box(_) | ty::ty_uniq(_) => return Err(ty::terr_mismatch),
262 ty::ty_rptr(_, mt_a) => mt_a.ty,
264 return self.subtype(a, b);
268 let a_borrowed = ty::mk_rptr(self.get_ref().infcx.tcx,
270 mt {ty: inner_ty, mutbl: mutbl_b});
271 try!(sub.tys(a_borrowed, b));
273 Ok(Some(AdjustDerefRef(AutoDerefRef {
275 autoref: Some(AutoPtr(r_borrow, mutbl_b, None))
279 // [T, ..n] -> &[T] or &mut [T]
280 fn coerce_unsized_with_borrow(&self,
284 mutbl_b: ast::Mutability)
286 debug!("coerce_unsized_with_borrow(a={}, sty_a={:?}, b={})",
287 a.repr(self.get_ref().infcx.tcx), sty_a,
288 b.repr(self.get_ref().infcx.tcx));
291 ty::ty_vec(t_a, Some(len)) => {
292 let sub = Sub(self.get_ref().clone());
293 let coercion = Coercion(self.get_ref().trace.clone());
294 let r_borrow = self.get_ref().infcx.next_region_var(coercion);
295 let unsized_ty = ty::mk_slice(self.get_ref().infcx.tcx, r_borrow,
296 mt {ty: t_a, mutbl: mutbl_b});
297 try!(self.get_ref().infcx.try(|| sub.tys(unsized_ty, b)));
298 Ok(Some(AdjustDerefRef(AutoDerefRef {
300 autoref: Some(ty::AutoPtr(r_borrow,
302 Some(box AutoUnsize(ty::UnsizeLength(len)))))
305 _ => Err(ty::terr_mismatch)
309 // &[T, ..n] or &mut [T, ..n] -> &[T]
310 // or &mut [T, ..n] -> &mut [T]
311 // or &Concrete -> &Trait, etc.
312 fn coerce_unsized(&self,
317 debug!("coerce_unsized(a={}, sty_a={:?}, b={})",
318 a.repr(self.get_ref().infcx.tcx), sty_a,
319 b.repr(self.get_ref().infcx.tcx));
321 // Note, we want to avoid unnecessary unsizing. We don't want to coerce to
322 // a DST unless we have to. This currently comes out in the wash since
323 // we can't unify [T] with U. But to properly support DST, we need to allow
324 // that, at which point we will need extra checks on b here.
326 let sub = Sub(self.get_ref().clone());
328 let sty_b = &ty::get(b).sty;
329 match (sty_a, sty_b) {
330 (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => {
331 self.unpack_actual_value(t_a, |sty_a| {
332 match self.unsize_ty(t_a, sty_a, mt_b.ty) {
333 Some((ty, kind)) => {
334 if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
335 return Err(ty::terr_mutability);
338 let coercion = Coercion(self.get_ref().trace.clone());
339 let r_borrow = self.get_ref().infcx.next_region_var(coercion);
340 let ty = ty::mk_rptr(self.get_ref().infcx.tcx,
342 ty::mt{ty: ty, mutbl: mt_b.mutbl});
343 try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
344 debug!("Success, coerced with AutoDerefRef(1, \
345 AutoPtr(AutoUnsize({:?})))", kind);
346 Ok(Some(AdjustDerefRef(AutoDerefRef {
348 autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl,
349 Some(box AutoUnsize(kind))))
352 _ => Err(ty::terr_mismatch)
356 (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => {
357 self.unpack_actual_value(t_a, |sty_a| {
358 match self.unsize_ty(t_a, sty_a, mt_b.ty) {
359 Some((ty, kind)) => {
360 if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
361 return Err(ty::terr_mutability);
364 let ty = ty::mk_ptr(self.get_ref().infcx.tcx,
365 ty::mt{ty: ty, mutbl: mt_b.mutbl});
366 try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
367 debug!("Success, coerced with AutoDerefRef(1, \
368 AutoPtr(AutoUnsize({:?})))", kind);
369 Ok(Some(AdjustDerefRef(AutoDerefRef {
371 autoref: Some(ty::AutoUnsafe(mt_b.mutbl,
372 Some(box AutoUnsize(kind))))
375 _ => Err(ty::terr_mismatch)
379 (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => {
380 self.unpack_actual_value(t_a, |sty_a| {
381 match self.unsize_ty(t_a, sty_a, t_b) {
382 Some((ty, kind)) => {
383 let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty);
384 try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
385 debug!("Success, coerced with AutoDerefRef(1, \
386 AutoUnsizeUniq({:?}))", kind);
387 Ok(Some(AdjustDerefRef(AutoDerefRef {
389 autoref: Some(ty::AutoUnsizeUniq(kind))
392 _ => Err(ty::terr_mismatch)
396 _ => Err(ty::terr_mismatch)
400 // Takes a type and returns an unsized version along with the adjustment
401 // performed to unsize it.
402 // E.g., `[T, ..n]` -> `([T], UnsizeLength(n))`
407 -> Option<(ty::t, ty::UnsizeKind)> {
408 debug!("unsize_ty(sty_a={:?}, ty_b={})", sty_a, ty_b.repr(self.get_ref().infcx.tcx));
410 let tcx = self.get_ref().infcx.tcx;
412 self.unpack_actual_value(ty_b, |sty_b|
413 match (sty_a, sty_b) {
414 (&ty::ty_vec(t_a, Some(len)), _) => {
415 let ty = ty::mk_vec(tcx, t_a, None);
416 Some((ty, ty::UnsizeLength(len)))
418 (&ty::ty_trait(..), &ty::ty_trait(..)) => None,
419 (_, &ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds })) => {
420 let ty = ty::mk_trait(tcx,
424 Some((ty, ty::UnsizeVtable(ty::TyTrait { def_id: def_id,
426 substs: substs.clone() },
429 (&ty::ty_struct(did_a, ref substs_a), &ty::ty_struct(did_b, ref substs_b))
430 if did_a == did_b => {
431 debug!("unsizing a struct");
432 // Try unsizing each type param in turn to see if we end up with ty_b.
433 let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace);
434 let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
435 assert!(ty_substs_a.len() == ty_substs_b.len());
437 let sub = Sub(self.get_ref().clone());
439 let mut result = None;
440 let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
441 for (i, (tp_a, tp_b)) in tps {
442 if self.get_ref().infcx.try(|| sub.tys(*tp_a, *tp_b)).is_ok() {
446 self.unpack_actual_value(
448 |tp| self.unsize_ty(*tp_a, tp, *tp_b))
450 Some((new_tp, k)) => {
451 // Check that the whole types match.
452 let mut new_substs = substs_a.clone();
453 new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
454 let ty = ty::mk_struct(tcx, did_a, new_substs);
455 if self.get_ref().infcx.try(|| sub.tys(ty, ty_b)).is_err() {
456 debug!("Unsized type parameter '{}', but still \
457 could not match types {} and {}",
458 ppaux::ty_to_string(tcx, *tp_a),
459 ppaux::ty_to_string(tcx, ty),
460 ppaux::ty_to_string(tcx, ty_b));
461 // We can only unsize a single type parameter, so
462 // if we unsize one and it doesn't give us the
463 // type we want, then we won't succeed later.
467 result = Some((ty, ty::UnsizeStruct(box k, i)));
480 fn coerce_borrowed_object(&self,
484 b_mutbl: ast::Mutability) -> CoerceResult
486 let tcx = self.get_ref().infcx.tcx;
488 debug!("coerce_borrowed_object(a={}, sty_a={:?}, b={}, b_mutbl={})",
490 b.repr(tcx), b_mutbl);
492 let coercion = Coercion(self.get_ref().trace.clone());
493 let r_a = self.get_ref().infcx.next_region_var(coercion);
495 self.coerce_object(a, sty_a, b, b_mutbl,
496 |tr| ty::mk_rptr(tcx, r_a, ty::mt{ mutbl: b_mutbl, ty: tr }),
497 || AutoPtr(r_a, b_mutbl, None))
500 fn coerce_unsafe_object(&self,
504 b_mutbl: ast::Mutability) -> CoerceResult
506 let tcx = self.get_ref().infcx.tcx;
508 debug!("coerce_unsafe_object(a={}, sty_a={:?}, b={}, b_mutbl={})",
510 b.repr(tcx), b_mutbl);
512 self.coerce_object(a, sty_a, b, b_mutbl,
513 |tr| ty::mk_ptr(tcx, ty::mt{ mutbl: b_mutbl, ty: tr }),
514 || AutoUnsafe(b_mutbl, None))
517 fn coerce_object(&self,
521 b_mutbl: ast::Mutability,
522 mk_ty: |ty::t| -> ty::t,
523 mk_adjust: || -> ty::AutoRef) -> CoerceResult
525 let tcx = self.get_ref().infcx.tcx;
528 ty::ty_rptr(_, ty::mt{ty, mutbl}) => match ty::get(ty).sty {
529 ty::ty_trait(box ty::TyTrait {
536 debug!("mutbl={} b_mutbl={}", mutbl, b_mutbl);
538 let tr = ty::mk_trait(tcx, def_id, substs.clone(), bounds);
539 try!(self.subtype(mk_ty(tr), b));
540 Ok(Some(AdjustDerefRef(AutoDerefRef {
542 autoref: Some(mk_adjust())
555 pub fn coerce_borrowed_fn(&self,
560 debug!("coerce_borrowed_fn(a={}, sty_a={:?}, b={})",
561 a.repr(self.get_ref().infcx.tcx), sty_a,
562 b.repr(self.get_ref().infcx.tcx));
565 ty::ty_bare_fn(ref f) => {
566 self.coerce_from_bare_fn(a, f, b)
574 fn coerce_from_bare_fn(&self, a: ty::t, fn_ty_a: &ty::BareFnTy, b: ty::t)
578 * Attempts to coerce from a bare Rust function (`extern
579 * "Rust" fn`) into a closure or a `proc`.
582 self.unpack_actual_value(b, |sty_b| {
584 debug!("coerce_from_bare_fn(a={}, b={})",
585 a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
587 if fn_ty_a.abi != abi::Rust || fn_ty_a.fn_style != ast::NormalFn {
588 return self.subtype(a, b);
591 let fn_ty_b = match *sty_b {
592 ty::ty_closure(ref f) => (*f).clone(),
593 _ => return self.subtype(a, b)
596 let adj = ty::AdjustAddEnv(fn_ty_b.store);
597 let a_closure = ty::mk_closure(self.get_ref().infcx.tcx,
599 sig: fn_ty_a.sig.clone(),
602 try!(self.subtype(a_closure, b));
607 pub fn coerce_unsafe_ptr(&self,
611 mutbl_b: ast::Mutability)
613 debug!("coerce_unsafe_ptr(a={}, sty_a={:?}, b={})",
614 a.repr(self.get_ref().infcx.tcx), sty_a,
615 b.repr(self.get_ref().infcx.tcx));
617 let mt_a = match *sty_a {
618 ty::ty_rptr(_, mt) => mt,
620 return self.subtype(a, b);
624 // Check that the types which they point at are compatible.
625 // Note that we don't adjust the mutability here. We cannot change
626 // the mutability and the kind of pointer in a single coercion.
627 let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, mt_a);
628 try!(self.subtype(a_unsafe, b));
630 // Although references and unsafe ptrs have the same
631 // representation, we still register an AutoDerefRef so that
632 // regionck knows that the region for `a` must be valid here.
633 Ok(Some(AdjustDerefRef(AutoDerefRef {
635 autoref: Some(ty::AutoUnsafe(mutbl_b, None))
640 fn can_coerce_mutbls(from_mutbl: ast::Mutability,
641 to_mutbl: ast::Mutability)
643 match (from_mutbl, to_mutbl) {
644 (ast::MutMutable, ast::MutMutable) => true,
645 (ast::MutImmutable, ast::MutImmutable) => true,
646 (ast::MutMutable, ast::MutImmutable) => true,
647 (ast::MutImmutable, ast::MutMutable) => false,