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::to_str::InferStr;
75 use middle::typeck::infer::resolve::try_resolve_tvar_shallow;
76 use util::common::indenter;
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.inf_str(self.get_ref().infcx),
95 b.inf_str(self.get_ref().infcx));
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(_, 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 return self.unpack_actual_value(a, |sty_a| {
118 self.coerce_borrowed_pointer(a, sty_a, b, mt_b)
124 ty::ty_closure(~ty::ClosureTy {store: ty::RegionTraitStore(..), ..}) => {
125 return self.unpack_actual_value(a, |sty_a| {
126 self.coerce_borrowed_fn(a, sty_a, b)
130 ty::ty_ptr(mt_b) => {
131 return self.unpack_actual_value(a, |sty_a| {
132 self.coerce_unsafe_ptr(a, sty_a, b, mt_b)
136 ty::ty_trait(~ty::TyTrait {
137 def_id, ref substs, store: ty::UniqTraitStore, bounds
139 let result = self.unpack_actual_value(a, |sty_a| {
142 self.coerce_object(a, sty_a, b, def_id, substs,
143 ty::UniqTraitStore, bounds)
145 _ => Err(ty::terr_mismatch)
150 Ok(t) => return Ok(t),
155 ty::ty_trait(~ty::TyTrait {
156 def_id, ref substs, store: ty::RegionTraitStore(region, m), bounds
158 let result = self.unpack_actual_value(a, |sty_a| {
161 self.coerce_object(a, sty_a, b, def_id, substs,
162 ty::RegionTraitStore(region, m), bounds)
164 _ => self.coerce_borrowed_object(a, sty_a, b, m)
169 Ok(t) => return Ok(t),
177 self.unpack_actual_value(a, |sty_a| {
179 ty::ty_bare_fn(ref a_f) => {
180 // Bare functions are coercable to any closure type.
182 // FIXME(#3320) this should go away and be
183 // replaced with proper inference, got a patch
185 self.coerce_from_bare_fn(a, a_f, b)
188 // Otherwise, just use subtyping rules.
195 pub fn subtype(&self, a: ty::t, b: ty::t) -> CoerceResult {
196 match Sub(self.get_ref().clone()).tys(a, b) {
197 Ok(_) => Ok(None), // No coercion required.
198 Err(ref e) => Err(*e)
202 pub fn unpack_actual_value(&self, a: ty::t, f: |&ty::sty| -> CoerceResult)
204 match resolve_type(self.get_ref().infcx, a, try_resolve_tvar_shallow) {
209 self.get_ref().infcx.tcx.sess.span_bug(
210 self.get_ref().trace.origin.span(),
211 format!("failed to resolve even without \
212 any force options: {:?}", e));
217 pub fn coerce_borrowed_pointer(&self,
223 debug!("coerce_borrowed_pointer(a={}, sty_a={:?}, b={}, mt_b={:?})",
224 a.inf_str(self.get_ref().infcx), sty_a,
225 b.inf_str(self.get_ref().infcx), mt_b);
227 // If we have a parameter of type `&M T_a` and the value
228 // provided is `expr`, we will be adding an implicit borrow,
229 // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore,
230 // to type check, we will construct the type that `&M*expr` would
233 let sub = Sub(self.get_ref().clone());
234 let coercion = Coercion(self.get_ref().trace.clone());
235 let r_borrow = self.get_ref().infcx.next_region_var(coercion);
237 let inner_ty = match *sty_a {
238 ty::ty_box(typ) | ty::ty_uniq(typ) => typ,
239 ty::ty_rptr(_, mt_a) => mt_a.ty,
241 return self.subtype(a, b);
245 let a_borrowed = ty::mk_rptr(self.get_ref().infcx.tcx,
247 mt {ty: inner_ty, mutbl: mt_b.mutbl});
248 if_ok!(sub.tys(a_borrowed, b));
249 Ok(Some(AutoDerefRef(AutoDerefRef {
251 autoref: Some(AutoPtr(r_borrow, mt_b.mutbl))
255 pub fn coerce_borrowed_string(&self,
260 debug!("coerce_borrowed_string(a={}, sty_a={:?}, b={})",
261 a.inf_str(self.get_ref().infcx), sty_a,
262 b.inf_str(self.get_ref().infcx));
265 ty::ty_uniq(t) => match ty::get(t).sty {
267 _ => return self.subtype(a, b),
270 return self.subtype(a, b);
274 let coercion = Coercion(self.get_ref().trace.clone());
275 let r_a = self.get_ref().infcx.next_region_var(coercion);
276 let a_borrowed = ty::mk_str_slice(self.get_ref().infcx.tcx, r_a, ast::MutImmutable);
277 if_ok!(self.subtype(a_borrowed, b));
278 Ok(Some(AutoDerefRef(AutoDerefRef {
280 autoref: Some(AutoBorrowVec(r_a, MutImmutable))
284 pub fn coerce_borrowed_vector(&self,
288 mutbl_b: ast::Mutability)
290 debug!("coerce_borrowed_vector(a={}, sty_a={:?}, b={})",
291 a.inf_str(self.get_ref().infcx), sty_a,
292 b.inf_str(self.get_ref().infcx));
294 let sub = Sub(self.get_ref().clone());
295 let coercion = Coercion(self.get_ref().trace.clone());
296 let r_borrow = self.get_ref().infcx.next_region_var(coercion);
297 let ty_inner = match *sty_a {
298 ty::ty_uniq(t) | ty::ty_ptr(ty::mt{ty: t, ..}) |
299 ty::ty_rptr(_, ty::mt{ty: t, ..}) => match ty::get(t).sty {
300 ty::ty_vec(mt, None) => mt.ty,
302 return self.subtype(a, b);
305 ty::ty_vec(mt, _) => mt.ty,
307 return self.subtype(a, b);
311 let a_borrowed = ty::mk_slice(self.get_ref().infcx.tcx, r_borrow,
312 mt {ty: ty_inner, mutbl: mutbl_b});
313 if_ok!(sub.tys(a_borrowed, b));
314 Ok(Some(AutoDerefRef(AutoDerefRef {
316 autoref: Some(AutoBorrowVec(r_borrow, mutbl_b))
320 fn coerce_borrowed_object(&self,
324 b_mutbl: ast::Mutability) -> CoerceResult
326 debug!("coerce_borrowed_object(a={}, sty_a={:?}, b={})",
327 a.inf_str(self.get_ref().infcx), sty_a,
328 b.inf_str(self.get_ref().infcx));
330 let tcx = self.get_ref().infcx.tcx;
331 let coercion = Coercion(self.get_ref().trace.clone());
332 let r_a = self.get_ref().infcx.next_region_var(coercion);
334 let a_borrowed = match *sty_a {
335 ty::ty_trait(~ty::TyTrait { def_id, ref substs, bounds, .. }) => {
336 ty::mk_trait(tcx, def_id, substs.clone(),
337 ty::RegionTraitStore(r_a, b_mutbl), bounds)
340 return self.subtype(a, b);
344 if_ok!(self.subtype(a_borrowed, b));
345 Ok(Some(AutoDerefRef(AutoDerefRef {
347 autoref: Some(AutoBorrowObj(r_a, b_mutbl))
351 pub fn coerce_borrowed_fn(&self,
356 debug!("coerce_borrowed_fn(a={}, sty_a={:?}, b={})",
357 a.inf_str(self.get_ref().infcx), sty_a,
358 b.inf_str(self.get_ref().infcx));
361 ty::ty_bare_fn(ref f) => {
362 self.coerce_from_bare_fn(a, f, b)
370 fn coerce_from_bare_fn(&self, a: ty::t, fn_ty_a: &ty::BareFnTy, b: ty::t)
374 * Attempts to coerce from a bare Rust function (`extern
375 * "Rust" fn`) into a closure or a `proc`.
378 self.unpack_actual_value(b, |sty_b| {
380 debug!("coerce_from_bare_fn(a={}, b={})",
381 a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
383 if fn_ty_a.abi != abi::Rust || fn_ty_a.fn_style != ast::NormalFn {
384 return self.subtype(a, b);
387 let fn_ty_b = match *sty_b {
388 ty::ty_closure(ref f) => (*f).clone(),
389 _ => return self.subtype(a, b)
392 let adj = ty::AutoAddEnv(fn_ty_b.store);
393 let a_closure = ty::mk_closure(self.get_ref().infcx.tcx,
395 sig: fn_ty_a.sig.clone(),
398 if_ok!(self.subtype(a_closure, b));
403 pub fn coerce_unsafe_ptr(&self,
409 debug!("coerce_unsafe_ptr(a={}, sty_a={:?}, b={})",
410 a.inf_str(self.get_ref().infcx), sty_a,
411 b.inf_str(self.get_ref().infcx));
413 let mt_a = match *sty_a {
414 ty::ty_rptr(_, mt) => mt,
416 return self.subtype(a, b);
420 // check that the types which they point at are compatible
421 let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, mt_a);
422 if_ok!(self.subtype(a_unsafe, b));
424 // although references and unsafe ptrs have the same
425 // representation, we still register an AutoDerefRef so that
426 // regionck knows that the region for `a` must be valid here
427 Ok(Some(AutoDerefRef(AutoDerefRef {
429 autoref: Some(ty::AutoUnsafe(mt_b.mutbl))
433 pub fn coerce_object(&self,
437 trait_def_id: ast::DefId,
438 trait_substs: &ty::substs,
439 trait_store: ty::TraitStore,
440 bounds: ty::BuiltinBounds) -> CoerceResult {
442 debug!("coerce_object(a={}, sty_a={:?}, b={})",
443 a.inf_str(self.get_ref().infcx), sty_a,
444 b.inf_str(self.get_ref().infcx));
446 Ok(Some(ty::AutoObject(trait_store, bounds,
447 trait_def_id, trait_substs.clone())))