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.
63 use super::{CoerceResult, Coercion};
64 use super::combine::{CombineFields, Combine};
68 use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe};
70 use middle::ty::{self, Ty};
72 use util::ppaux::Repr;
76 // Note: Coerce is not actually a combiner, in that it does not
77 // conform to the same interface, though it performs a similar
79 pub struct Coerce<'f, 'tcx: 'f>(pub CombineFields<'f, 'tcx>);
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
86 fn tcx(&self) -> &ty::ctxt<'tcx> {
87 self.get_ref().infcx.tcx
90 pub fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
91 debug!("Coerce.tys({} => {})",
95 // Consider coercing the subtype to a DST
96 let unsize = self.unpack_actual_value(a, |a| {
97 self.coerce_unsized(a, b)
103 // Examine the supertype and consider auto-borrowing.
105 // Note: does not attempt to resolve type variables we encounter.
106 // See above for details.
108 ty::ty_ptr(mt_b) => {
111 return self.unpack_actual_value(a, |a| {
112 self.coerce_unsafe_ptr(a, b, ast::MutImmutable)
116 ty::ty_trait(..) => {
117 let result = self.unpack_actual_value(a, |a| {
118 self.coerce_unsafe_object(a, b, mt_b.mutbl)
122 Ok(t) => return Ok(t),
128 return self.unpack_actual_value(a, |a| {
129 self.coerce_unsafe_ptr(a, b, mt_b.mutbl)
135 ty::ty_rptr(_, mt_b) => {
138 return self.unpack_actual_value(a, |a| {
139 self.coerce_borrowed_pointer(a, b, ast::MutImmutable)
143 ty::ty_trait(..) => {
144 let result = self.unpack_actual_value(a, |a| {
145 self.coerce_borrowed_object(a, b, mt_b.mutbl)
149 Ok(t) => return Ok(t),
155 return self.unpack_actual_value(a, |a| {
156 self.coerce_borrowed_pointer(a, b, mt_b.mutbl)
165 self.unpack_actual_value(a, |a| {
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)
174 // Otherwise, just use subtyping rules.
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)
188 pub fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where
189 F: FnOnce(Ty<'tcx>) -> T,
191 f(self.get_ref().infcx.shallow_resolve(a))
194 // ~T -> &T or &mut T -> &T (including where T = [U] or str)
195 pub fn coerce_borrowed_pointer(&self,
198 mutbl_b: ast::Mutability)
199 -> CoerceResult<'tcx> {
200 debug!("coerce_borrowed_pointer(a={}, b={})",
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
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);
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);
223 return self.subtype(a, b);
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));
232 Ok(Some(AdjustDerefRef(AutoDerefRef {
234 autoref: Some(AutoPtr(r_borrow, mutbl_b, None))
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,
245 -> CoerceResult<'tcx> {
246 debug!("coerce_unsized(a={}, b={})",
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.
255 let sub = Sub(self.get_ref().clone());
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);
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 {
276 autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl,
277 Some(box AutoUnsize(kind))))
280 _ => Err(ty::terr_mismatch)
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);
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 {
299 autoref: Some(ty::AutoUnsafe(mt_b.mutbl,
300 Some(box AutoUnsize(kind))))
303 _ => Err(ty::terr_mismatch)
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 {
317 autoref: Some(ty::AutoUnsizeUniq(kind))
320 _ => Err(ty::terr_mismatch)
324 _ => Err(ty::terr_mismatch)
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))`
335 -> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)> {
336 debug!("unsize_ty(a={:?}, ty_b={})", a, ty_b.repr(self.tcx()));
338 let tcx = self.tcx();
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)))
346 (&ty::ty_trait(..), &ty::ty_trait(..)) => {
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() },
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());
364 let sub = Sub(self.get_ref().clone());
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() {
373 self.unpack_actual_value(
375 |tp| self.unsize_ty(*tp_a, tp, *tp_b))
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.
394 result = Some((ty, ty::UnsizeStruct(box k, i)));
407 fn coerce_borrowed_object(&self,
410 b_mutbl: ast::Mutability) -> CoerceResult<'tcx>
412 let tcx = self.tcx();
414 debug!("coerce_borrowed_object(a={}, b={}, b_mutbl={:?})",
416 b.repr(tcx), b_mutbl);
418 let coercion = Coercion(self.get_ref().trace.clone());
419 let r_a = self.get_ref().infcx.next_region_var(coercion);
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))
427 fn coerce_unsafe_object(&self,
430 b_mutbl: ast::Mutability) -> CoerceResult<'tcx>
432 let tcx = self.tcx();
434 debug!("coerce_unsafe_object(a={}, b={}, b_mutbl={:?})",
436 b.repr(tcx), b_mutbl);
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))
443 fn coerce_object<F, G>(&self,
446 b_mutbl: ast::Mutability,
448 mk_adjust: G) -> CoerceResult<'tcx> where
449 F: FnOnce(Ty<'tcx>) -> Ty<'tcx>,
450 G: FnOnce() -> ty::AutoRef<'tcx>,
452 let tcx = self.tcx();
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 {
462 autoref: Some(mk_adjust())
475 pub fn coerce_borrowed_fn(&self,
478 -> CoerceResult<'tcx> {
479 debug!("coerce_borrowed_fn(a={}, b={})",
484 ty::ty_bare_fn(Some(a_def_id), f) => {
485 self.coerce_from_fn_item(a, a_def_id, f, b)
493 fn coerce_from_fn_item(&self,
495 fn_def_id_a: ast::DefId,
496 fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
498 -> CoerceResult<'tcx> {
500 * Attempts to coerce from the type of a Rust function item
501 * into a closure or a `proc`.
504 self.unpack_actual_value(b, |b| {
505 debug!("coerce_from_fn_item(a={}, b={})",
506 a.repr(self.tcx()), b.repr(self.tcx()));
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)))
515 return self.subtype(a, b)
521 pub fn coerce_unsafe_ptr(&self,
524 mutbl_b: ast::Mutability)
525 -> CoerceResult<'tcx> {
526 debug!("coerce_unsafe_ptr(a={}, b={})",
530 let mt_a = match a.sty {
531 ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => mt,
533 return self.subtype(a, b);
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);
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 {
549 autoref: Some(ty::AutoUnsafe(mutbl_b, None))
554 fn can_coerce_mutbls(from_mutbl: ast::Mutability,
555 to_mutbl: ast::Mutability)
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,