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.
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).
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.
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
36 //! fn foo<A>(a: A, b: A) { ... }
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.
46 //! However, right now, if the user manually specifies the
47 //! values for the type variables, as so:
49 //! foo::<&int>(@1, @2)
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.
64 use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe};
66 use middle::ty::{mod, Ty};
67 use middle::typeck::infer::{CoerceResult, resolve_type, Coercion};
68 use middle::typeck::infer::combine::{CombineFields, Combine};
69 use middle::typeck::infer::sub::Sub;
70 use middle::typeck::infer::resolve::try_resolve_tvar_shallow;
72 use util::ppaux::Repr;
77 // Note: Coerce is not actually a combiner, in that it does not
78 // conform to the same interface, though it performs a similar
80 pub struct Coerce<'f, 'tcx: 'f>(pub CombineFields<'f, 'tcx>);
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
87 pub fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
88 debug!("Coerce.tys({} => {})",
89 a.repr(self.get_ref().infcx.tcx),
90 b.repr(self.get_ref().infcx.tcx));
92 // Consider coercing the subtype to a DST
93 let unsize = self.unpack_actual_value(a, |sty_a| {
94 self.coerce_unsized(a, sty_a, b)
100 // Examine the supertype and consider auto-borrowing.
102 // Note: does not attempt to resolve type variables we encounter.
103 // See above for details.
105 ty::ty_ptr(mt_b) => {
108 return self.unpack_actual_value(a, |sty_a| {
109 self.coerce_unsafe_ptr(a, sty_a, b, ast::MutImmutable)
113 ty::ty_trait(..) => {
114 let result = self.unpack_actual_value(a, |sty_a| {
115 self.coerce_unsafe_object(a, sty_a, b, mt_b.mutbl)
119 Ok(t) => return Ok(t),
125 return self.unpack_actual_value(a, |sty_a| {
126 self.coerce_unsafe_ptr(a, sty_a, b, mt_b.mutbl)
132 ty::ty_rptr(_, mt_b) => {
135 return self.unpack_actual_value(a, |sty_a| {
136 self.coerce_borrowed_pointer(a, sty_a, b, ast::MutImmutable)
140 ty::ty_trait(..) => {
141 let result = self.unpack_actual_value(a, |sty_a| {
142 self.coerce_borrowed_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_borrowed_pointer(a, sty_a, b, mt_b.mutbl)
159 ty::ty_closure(box ty::ClosureTy {
160 store: ty::RegionTraitStore(..),
163 return self.unpack_actual_value(a, |sty_a| {
164 self.coerce_borrowed_fn(a, sty_a, b)
171 self.unpack_actual_value(a, |sty_a| {
173 ty::ty_bare_fn(ref a_f) => {
174 // Bare functions are coercible to any closure type.
176 // FIXME(#3320) this should go away and be
177 // replaced with proper inference, got a patch
179 self.coerce_from_bare_fn(a, a_f, b)
182 // Otherwise, just use subtyping rules.
189 pub fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
190 match Sub(self.get_ref().clone()).tys(a, b) {
191 Ok(_) => Ok(None), // No coercion required.
192 Err(ref e) => Err(*e)
196 pub fn unpack_actual_value<T>(&self, a: Ty<'tcx>, f: |&ty::sty<'tcx>| -> T)
198 match resolve_type(self.get_ref().infcx, None,
199 a, try_resolve_tvar_shallow) {
204 self.get_ref().infcx.tcx.sess.span_bug(
205 self.get_ref().trace.origin.span(),
206 format!("failed to resolve even without \
207 any force options: {}", e).as_slice());
212 // ~T -> &T or &mut T -> &T (including where T = [U] or str)
213 pub fn coerce_borrowed_pointer(&self,
215 sty_a: &ty::sty<'tcx>,
217 mutbl_b: ast::Mutability)
218 -> CoerceResult<'tcx> {
219 debug!("coerce_borrowed_pointer(a={}, sty_a={}, b={})",
220 a.repr(self.get_ref().infcx.tcx), sty_a,
221 b.repr(self.get_ref().infcx.tcx));
223 // If we have a parameter of type `&M T_a` and the value
224 // provided is `expr`, we will be adding an implicit borrow,
225 // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore,
226 // to type check, we will construct the type that `&M*expr` would
229 let sub = Sub(self.get_ref().clone());
230 let coercion = Coercion(self.get_ref().trace.clone());
231 let r_borrow = self.get_ref().infcx.next_region_var(coercion);
233 let inner_ty = match *sty_a {
234 ty::ty_uniq(_) => return Err(ty::terr_mismatch),
235 ty::ty_rptr(_, mt_a) => mt_a.ty,
237 return self.subtype(a, b);
241 let a_borrowed = ty::mk_rptr(self.get_ref().infcx.tcx,
243 mt {ty: inner_ty, mutbl: mutbl_b});
244 try!(sub.tys(a_borrowed, b));
246 Ok(Some(AdjustDerefRef(AutoDerefRef {
248 autoref: Some(AutoPtr(r_borrow, mutbl_b, None))
253 // &[T, ..n] or &mut [T, ..n] -> &[T]
254 // or &mut [T, ..n] -> &mut [T]
255 // or &Concrete -> &Trait, etc.
256 fn coerce_unsized(&self,
258 sty_a: &ty::sty<'tcx>,
260 -> CoerceResult<'tcx> {
261 debug!("coerce_unsized(a={}, sty_a={}, b={})",
262 a.repr(self.get_ref().infcx.tcx), sty_a,
263 b.repr(self.get_ref().infcx.tcx));
265 // Note, we want to avoid unnecessary unsizing. We don't want to coerce to
266 // a DST unless we have to. This currently comes out in the wash since
267 // we can't unify [T] with U. But to properly support DST, we need to allow
268 // that, at which point we will need extra checks on b here.
270 let sub = Sub(self.get_ref().clone());
273 match (sty_a, sty_b) {
274 (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => {
275 self.unpack_actual_value(t_a, |sty_a| {
276 match self.unsize_ty(t_a, sty_a, mt_b.ty) {
277 Some((ty, kind)) => {
278 if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
279 return Err(ty::terr_mutability);
282 let coercion = Coercion(self.get_ref().trace.clone());
283 let r_borrow = self.get_ref().infcx.next_region_var(coercion);
284 let ty = ty::mk_rptr(self.get_ref().infcx.tcx,
286 ty::mt{ty: ty, mutbl: mt_b.mutbl});
287 try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
288 debug!("Success, coerced with AutoDerefRef(1, \
289 AutoPtr(AutoUnsize({})))", kind);
290 Ok(Some(AdjustDerefRef(AutoDerefRef {
292 autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl,
293 Some(box AutoUnsize(kind))))
296 _ => Err(ty::terr_mismatch)
300 (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => {
301 self.unpack_actual_value(t_a, |sty_a| {
302 match self.unsize_ty(t_a, sty_a, mt_b.ty) {
303 Some((ty, kind)) => {
304 if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
305 return Err(ty::terr_mutability);
308 let ty = ty::mk_ptr(self.get_ref().infcx.tcx,
309 ty::mt{ty: ty, mutbl: mt_b.mutbl});
310 try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
311 debug!("Success, coerced with AutoDerefRef(1, \
312 AutoPtr(AutoUnsize({})))", kind);
313 Ok(Some(AdjustDerefRef(AutoDerefRef {
315 autoref: Some(ty::AutoUnsafe(mt_b.mutbl,
316 Some(box AutoUnsize(kind))))
319 _ => Err(ty::terr_mismatch)
323 (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => {
324 self.unpack_actual_value(t_a, |sty_a| {
325 match self.unsize_ty(t_a, sty_a, t_b) {
326 Some((ty, kind)) => {
327 let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty);
328 try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
329 debug!("Success, coerced with AutoDerefRef(1, \
330 AutoUnsizeUniq({}))", kind);
331 Ok(Some(AdjustDerefRef(AutoDerefRef {
333 autoref: Some(ty::AutoUnsizeUniq(kind))
336 _ => Err(ty::terr_mismatch)
340 _ => Err(ty::terr_mismatch)
344 // Takes a type and returns an unsized version along with the adjustment
345 // performed to unsize it.
346 // E.g., `[T, ..n]` -> `([T], UnsizeLength(n))`
349 sty_a: &ty::sty<'tcx>,
351 -> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)> {
352 debug!("unsize_ty(sty_a={}, ty_b={})", sty_a, ty_b.repr(self.get_ref().infcx.tcx));
354 let tcx = self.get_ref().infcx.tcx;
356 self.unpack_actual_value(ty_b, |sty_b|
357 match (sty_a, sty_b) {
358 (&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => {
359 let ty = ty::mk_vec(tcx, t_a, None);
360 Some((ty, ty::UnsizeLength(len)))
362 (&ty::ty_trait(..), &ty::ty_trait(..)) => {
365 (_, &ty::ty_trait(box ty::TyTrait { ref principal, bounds })) => {
366 // FIXME what is the purpose of `ty`?
367 let ty = ty::mk_trait(tcx, (*principal).clone(), bounds);
368 Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: (*principal).clone(),
372 (&ty::ty_struct(did_a, ref substs_a), &ty::ty_struct(did_b, ref substs_b))
373 if did_a == did_b => {
374 debug!("unsizing a struct");
375 // Try unsizing each type param in turn to see if we end up with ty_b.
376 let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace);
377 let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
378 assert!(ty_substs_a.len() == ty_substs_b.len());
380 let sub = Sub(self.get_ref().clone());
382 let mut result = None;
383 let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
384 for (i, (tp_a, tp_b)) in tps {
385 if self.get_ref().infcx.try(|| sub.tys(*tp_a, *tp_b)).is_ok() {
389 self.unpack_actual_value(
391 |tp| self.unsize_ty(*tp_a, tp, *tp_b))
393 Some((new_tp, k)) => {
394 // Check that the whole types match.
395 let mut new_substs = substs_a.clone();
396 new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
397 let ty = ty::mk_struct(tcx, did_a, new_substs);
398 if self.get_ref().infcx.try(|| sub.tys(ty, ty_b)).is_err() {
399 debug!("Unsized type parameter '{}', but still \
400 could not match types {} and {}",
401 ppaux::ty_to_string(tcx, *tp_a),
402 ppaux::ty_to_string(tcx, ty),
403 ppaux::ty_to_string(tcx, ty_b));
404 // We can only unsize a single type parameter, so
405 // if we unsize one and it doesn't give us the
406 // type we want, then we won't succeed later.
410 result = Some((ty, ty::UnsizeStruct(box k, i)));
423 fn coerce_borrowed_object(&self,
425 sty_a: &ty::sty<'tcx>,
427 b_mutbl: ast::Mutability) -> CoerceResult<'tcx>
429 let tcx = self.get_ref().infcx.tcx;
431 debug!("coerce_borrowed_object(a={}, sty_a={}, b={}, b_mutbl={})",
433 b.repr(tcx), b_mutbl);
435 let coercion = Coercion(self.get_ref().trace.clone());
436 let r_a = self.get_ref().infcx.next_region_var(coercion);
438 self.coerce_object(a, sty_a, b, b_mutbl,
439 |tr| ty::mk_rptr(tcx, r_a, ty::mt{ mutbl: b_mutbl, ty: tr }),
440 || AutoPtr(r_a, b_mutbl, None))
443 fn coerce_unsafe_object(&self,
445 sty_a: &ty::sty<'tcx>,
447 b_mutbl: ast::Mutability) -> CoerceResult<'tcx>
449 let tcx = self.get_ref().infcx.tcx;
451 debug!("coerce_unsafe_object(a={}, sty_a={}, b={}, b_mutbl={})",
453 b.repr(tcx), b_mutbl);
455 self.coerce_object(a, sty_a, b, b_mutbl,
456 |tr| ty::mk_ptr(tcx, ty::mt{ mutbl: b_mutbl, ty: tr }),
457 || AutoUnsafe(b_mutbl, None))
460 fn coerce_object(&self,
462 sty_a: &ty::sty<'tcx>,
464 b_mutbl: ast::Mutability,
465 mk_ty: |Ty<'tcx>| -> Ty<'tcx>,
466 mk_adjust: || -> ty::AutoRef<'tcx>) -> CoerceResult<'tcx>
468 let tcx = self.get_ref().infcx.tcx;
471 ty::ty_rptr(_, ty::mt{ty, mutbl}) => match ty.sty {
472 ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => {
473 debug!("mutbl={} b_mutbl={}", mutbl, b_mutbl);
474 // FIXME what is purpose of this type `tr`?
475 let tr = ty::mk_trait(tcx, (*principal).clone(), bounds);
476 try!(self.subtype(mk_ty(tr), b));
477 Ok(Some(AdjustDerefRef(AutoDerefRef {
479 autoref: Some(mk_adjust())
492 pub fn coerce_borrowed_fn(&self,
494 sty_a: &ty::sty<'tcx>,
496 -> CoerceResult<'tcx> {
497 debug!("coerce_borrowed_fn(a={}, sty_a={}, b={})",
498 a.repr(self.get_ref().infcx.tcx), sty_a,
499 b.repr(self.get_ref().infcx.tcx));
502 ty::ty_bare_fn(ref f) => {
503 self.coerce_from_bare_fn(a, f, b)
511 /// Attempts to coerce from a bare Rust function (`extern "Rust" fn`) into a closure or a
513 fn coerce_from_bare_fn(&self, a: Ty<'tcx>, fn_ty_a: &ty::BareFnTy<'tcx>, b: Ty<'tcx>)
514 -> CoerceResult<'tcx> {
515 self.unpack_actual_value(b, |sty_b| {
517 debug!("coerce_from_bare_fn(a={}, b={})",
518 a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
520 if fn_ty_a.abi != abi::Rust || fn_ty_a.fn_style != ast::NormalFn {
521 return self.subtype(a, b);
524 let fn_ty_b = match *sty_b {
525 ty::ty_closure(ref f) => (*f).clone(),
526 _ => return self.subtype(a, b)
529 let adj = ty::AdjustAddEnv(fn_ty_b.store);
530 let a_closure = ty::mk_closure(self.get_ref().infcx.tcx,
532 sig: fn_ty_a.sig.clone(),
535 try!(self.subtype(a_closure, b));
540 pub fn coerce_unsafe_ptr(&self,
542 sty_a: &ty::sty<'tcx>,
544 mutbl_b: ast::Mutability)
545 -> CoerceResult<'tcx> {
546 debug!("coerce_unsafe_ptr(a={}, sty_a={}, b={})",
547 a.repr(self.get_ref().infcx.tcx), sty_a,
548 b.repr(self.get_ref().infcx.tcx));
550 let mt_a = match *sty_a {
551 ty::ty_rptr(_, mt) => mt,
553 return self.subtype(a, b);
557 // Check that the types which they point at are compatible.
558 // Note that we don't adjust the mutability here. We cannot change
559 // the mutability and the kind of pointer in a single coercion.
560 let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, mt_a);
561 try!(self.subtype(a_unsafe, b));
563 // Although references and unsafe ptrs have the same
564 // representation, we still register an AutoDerefRef so that
565 // regionck knows that the region for `a` must be valid here.
566 Ok(Some(AdjustDerefRef(AutoDerefRef {
568 autoref: Some(ty::AutoUnsafe(mutbl_b, None))
573 fn can_coerce_mutbls(from_mutbl: ast::Mutability,
574 to_mutbl: ast::Mutability)
576 match (from_mutbl, to_mutbl) {
577 (ast::MutMutable, ast::MutMutable) => true,
578 (ast::MutImmutable, ast::MutImmutable) => true,
579 (ast::MutMutable, ast::MutImmutable) => true,
580 (ast::MutImmutable, ast::MutMutable) => false,