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, AutoBorrowVec, AutoBorrowObj, AutoDerefRef};
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;
76 use util::ppaux::Repr;
79 use syntax::ast::MutImmutable;
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>(pub CombineFields<'f>);
88 pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f> {
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 // Examine the supertype and consider auto-borrowing.
100 // Note: does not attempt to resolve type variables we encounter.
101 // See above for details.
102 match ty::get(b).sty {
103 ty::ty_rptr(r_b, mt_b) => {
104 match ty::get(mt_b.ty).sty {
105 ty::ty_vec(mt_b, None) => {
106 return self.unpack_actual_value(a, |sty_a| {
107 self.coerce_borrowed_vector(a, sty_a, b, mt_b.mutbl)
110 ty::ty_vec(_, _) => {},
112 return self.unpack_actual_value(a, |sty_a| {
113 self.coerce_borrowed_string(a, sty_a, b)
117 ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds }) => {
118 let result = self.unpack_actual_value(a, |sty_a| {
120 ty::ty_rptr(_, mt_a) => match ty::get(mt_a.ty).sty {
121 ty::ty_trait(..) => {
122 self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl)
124 _ => self.coerce_object(a, sty_a, b, def_id, substs,
125 ty::RegionTraitStore(r_b, mt_b.mutbl),
128 _ => self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl)
133 Ok(t) => return Ok(t),
139 return self.unpack_actual_value(a, |sty_a| {
140 self.coerce_borrowed_pointer(a, sty_a, b, mt_b)
146 ty::ty_uniq(t_b) => {
147 match ty::get(t_b).sty {
148 ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds }) => {
149 let result = self.unpack_actual_value(a, |sty_a| {
151 ty::ty_uniq(t_a) => match ty::get(t_a).sty {
152 ty::ty_trait(..) => {
153 Err(ty::terr_mismatch)
155 _ => self.coerce_object(a, sty_a, b, def_id, substs,
156 ty::UniqTraitStore, bounds)
158 _ => Err(ty::terr_mismatch)
163 Ok(t) => return Ok(t),
171 ty::ty_closure(box ty::ClosureTy {
172 store: ty::RegionTraitStore(..),
175 return self.unpack_actual_value(a, |sty_a| {
176 self.coerce_borrowed_fn(a, sty_a, b)
180 ty::ty_ptr(mt_b) => {
181 return self.unpack_actual_value(a, |sty_a| {
182 self.coerce_unsafe_ptr(a, sty_a, b, mt_b)
189 self.unpack_actual_value(a, |sty_a| {
191 ty::ty_bare_fn(ref a_f) => {
192 // Bare functions are coercible to any closure type.
194 // FIXME(#3320) this should go away and be
195 // replaced with proper inference, got a patch
197 self.coerce_from_bare_fn(a, a_f, b)
200 // Otherwise, just use subtyping rules.
207 pub fn subtype(&self, a: ty::t, b: ty::t) -> CoerceResult {
208 match Sub(self.get_ref().clone()).tys(a, b) {
209 Ok(_) => Ok(None), // No coercion required.
210 Err(ref e) => Err(*e)
214 pub fn unpack_actual_value(&self, a: ty::t, f: |&ty::sty| -> CoerceResult)
216 match resolve_type(self.get_ref().infcx, a, try_resolve_tvar_shallow) {
221 self.get_ref().infcx.tcx.sess.span_bug(
222 self.get_ref().trace.origin.span(),
223 format!("failed to resolve even without \
224 any force options: {:?}", e).as_slice());
229 pub fn coerce_borrowed_pointer(&self,
235 debug!("coerce_borrowed_pointer(a={}, sty_a={:?}, b={}, mt_b={:?})",
236 a.repr(self.get_ref().infcx.tcx), sty_a,
237 b.repr(self.get_ref().infcx.tcx), mt_b);
239 // If we have a parameter of type `&M T_a` and the value
240 // provided is `expr`, we will be adding an implicit borrow,
241 // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore,
242 // to type check, we will construct the type that `&M*expr` would
245 let sub = Sub(self.get_ref().clone());
246 let coercion = Coercion(self.get_ref().trace.clone());
247 let r_borrow = self.get_ref().infcx.next_region_var(coercion);
249 let inner_ty = match *sty_a {
250 ty::ty_box(typ) | ty::ty_uniq(typ) => typ,
251 ty::ty_rptr(_, mt_a) => mt_a.ty,
253 return self.subtype(a, b);
257 let a_borrowed = ty::mk_rptr(self.get_ref().infcx.tcx,
259 mt {ty: inner_ty, mutbl: mt_b.mutbl});
260 if_ok!(sub.tys(a_borrowed, b));
261 Ok(Some(AutoDerefRef(AutoDerefRef {
263 autoref: Some(AutoPtr(r_borrow, mt_b.mutbl))
267 pub fn coerce_borrowed_string(&self,
272 debug!("coerce_borrowed_string(a={}, sty_a={:?}, b={})",
273 a.repr(self.get_ref().infcx.tcx), sty_a,
274 b.repr(self.get_ref().infcx.tcx));
277 ty::ty_uniq(t) => match ty::get(t).sty {
279 _ => return self.subtype(a, b),
282 return self.subtype(a, b);
286 let coercion = Coercion(self.get_ref().trace.clone());
287 let r_a = self.get_ref().infcx.next_region_var(coercion);
288 let a_borrowed = ty::mk_str_slice(self.get_ref().infcx.tcx, r_a, ast::MutImmutable);
289 if_ok!(self.subtype(a_borrowed, b));
290 Ok(Some(AutoDerefRef(AutoDerefRef {
292 autoref: Some(AutoBorrowVec(r_a, MutImmutable))
296 pub fn coerce_borrowed_vector(&self,
300 mutbl_b: ast::Mutability)
302 debug!("coerce_borrowed_vector(a={}, sty_a={:?}, b={})",
303 a.repr(self.get_ref().infcx.tcx), sty_a,
304 b.repr(self.get_ref().infcx.tcx));
306 let sub = Sub(self.get_ref().clone());
307 let coercion = Coercion(self.get_ref().trace.clone());
308 let r_borrow = self.get_ref().infcx.next_region_var(coercion);
309 let ty_inner = match *sty_a {
310 ty::ty_uniq(t) | ty::ty_ptr(ty::mt{ty: t, ..}) |
311 ty::ty_rptr(_, ty::mt{ty: t, ..}) => match ty::get(t).sty {
312 ty::ty_vec(mt, None) => mt.ty,
314 return self.subtype(a, b);
317 ty::ty_vec(mt, _) => mt.ty,
319 return self.subtype(a, b);
323 let a_borrowed = ty::mk_slice(self.get_ref().infcx.tcx, r_borrow,
324 mt {ty: ty_inner, mutbl: mutbl_b});
325 if_ok!(sub.tys(a_borrowed, b));
326 Ok(Some(AutoDerefRef(AutoDerefRef {
328 autoref: Some(AutoBorrowVec(r_borrow, mutbl_b))
332 fn coerce_borrowed_object(&self,
336 b_mutbl: ast::Mutability) -> CoerceResult
338 debug!("coerce_borrowed_object(a={}, sty_a={:?}, b={})",
339 a.repr(self.get_ref().infcx.tcx), sty_a,
340 b.repr(self.get_ref().infcx.tcx));
342 let tcx = self.get_ref().infcx.tcx;
343 let coercion = Coercion(self.get_ref().trace.clone());
344 let r_a = self.get_ref().infcx.next_region_var(coercion);
346 let a_borrowed = match *sty_a {
347 ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty {
348 ty::ty_trait(box ty::TyTrait {
354 let tr = ty::mk_trait(tcx, def_id, substs.clone(), bounds);
355 ty::mk_rptr(tcx, r_a, ty::mt{ mutbl: b_mutbl, ty: tr })
358 return self.subtype(a, b);
362 return self.subtype(a, b);
366 if_ok!(self.subtype(a_borrowed, b));
367 Ok(Some(AutoDerefRef(AutoDerefRef {
369 autoref: Some(AutoBorrowObj(r_a, b_mutbl))
373 pub fn coerce_borrowed_fn(&self,
378 debug!("coerce_borrowed_fn(a={}, sty_a={:?}, b={})",
379 a.repr(self.get_ref().infcx.tcx), sty_a,
380 b.repr(self.get_ref().infcx.tcx));
383 ty::ty_bare_fn(ref f) => {
384 self.coerce_from_bare_fn(a, f, b)
392 fn coerce_from_bare_fn(&self, a: ty::t, fn_ty_a: &ty::BareFnTy, b: ty::t)
396 * Attempts to coerce from a bare Rust function (`extern
397 * "Rust" fn`) into a closure or a `proc`.
400 self.unpack_actual_value(b, |sty_b| {
402 debug!("coerce_from_bare_fn(a={}, b={})",
403 a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
405 if fn_ty_a.abi != abi::Rust || fn_ty_a.fn_style != ast::NormalFn {
406 return self.subtype(a, b);
409 let fn_ty_b = match *sty_b {
410 ty::ty_closure(ref f) => (*f).clone(),
411 _ => return self.subtype(a, b)
414 let adj = ty::AutoAddEnv(fn_ty_b.store);
415 let a_closure = ty::mk_closure(self.get_ref().infcx.tcx,
417 sig: fn_ty_a.sig.clone(),
420 if_ok!(self.subtype(a_closure, b));
425 pub fn coerce_unsafe_ptr(&self,
431 debug!("coerce_unsafe_ptr(a={}, sty_a={:?}, b={})",
432 a.repr(self.get_ref().infcx.tcx), sty_a,
433 b.repr(self.get_ref().infcx.tcx));
435 let mt_a = match *sty_a {
436 ty::ty_rptr(_, mt) => mt,
438 return self.subtype(a, b);
442 // check that the types which they point at are compatible
443 let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, mt_a);
444 if_ok!(self.subtype(a_unsafe, b));
446 // although references and unsafe ptrs have the same
447 // representation, we still register an AutoDerefRef so that
448 // regionck knows that the region for `a` must be valid here
449 Ok(Some(AutoDerefRef(AutoDerefRef {
451 autoref: Some(ty::AutoUnsafe(mt_b.mutbl))
455 pub fn coerce_object(&self,
459 trait_def_id: ast::DefId,
460 trait_substs: &subst::Substs,
461 trait_store: ty::TraitStore,
462 bounds: ty::BuiltinBounds) -> CoerceResult {
464 debug!("coerce_object(a={}, sty_a={:?}, b={})",
465 a.repr(self.get_ref().infcx.tcx), sty_a,
466 b.repr(self.get_ref().infcx.tcx));
468 Ok(Some(ty::AutoObject(trait_store, bounds,
469 trait_def_id, trait_substs.clone())))