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.
4 //
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.
10
11 /*!
12
13 # Type Coercion
14
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).
20
21 ## Reborrowing
22
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.
30
31 ## Subtle note
32
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
37
38 fn foo<A>(a: A, b: A) { ... }
39
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
44 seems very confusing.
45
46 ## Subtler note
47
48 However, right now, if the user manually specifies the
49 values for the type variables, as so:
50
51 foo::<&int>(@1, @2)
52
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.
64
65 */
66
67
68 use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowObj, AutoDerefRef};
69 use middle::ty::{mt};
70 use middle::ty;
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;
77
78 use syntax::abi;
79 use syntax::ast::MutImmutable;
80 use syntax::ast;
81
82 // Note: Coerce is not actually a combiner, in that it does not
83 // conform to the same interface, though it performs a similar
84 // function.
85 pub struct Coerce<'f>(pub CombineFields<'f>);
86
87 impl<'f> Coerce<'f> {
88 pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f> {
89 let Coerce(ref v) = *self; v
90 }
91
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();
97
98 // Examine the supertype and consider auto-borrowing.
99 //
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)
108 });
109 }
110 ty::ty_vec(_, _) => {},
111 ty::ty_str => {
112 return self.unpack_actual_value(a, |sty_a| {
113 self.coerce_borrowed_string(a, sty_a, b)
114 });
115 }
116 _ => {
117 return self.unpack_actual_value(a, |sty_a| {
118 self.coerce_borrowed_pointer(a, sty_a, b, mt_b)
119 });
120 }
121 };
122 }
123
124 ty::ty_closure(box ty::ClosureTy {
125 store: ty::RegionTraitStore(..),
126 ..
127 }) => {
128 return self.unpack_actual_value(a, |sty_a| {
129 self.coerce_borrowed_fn(a, sty_a, b)
130 });
131 }
132
133 ty::ty_ptr(mt_b) => {
134 return self.unpack_actual_value(a, |sty_a| {
135 self.coerce_unsafe_ptr(a, sty_a, b, mt_b)
136 });
137 }
138
139 ty::ty_trait(box ty::TyTrait {
140 def_id, ref substs, store: ty::UniqTraitStore, bounds
141 }) => {
142 let result = self.unpack_actual_value(a, |sty_a| {
143 match *sty_a {
144 ty::ty_uniq(..) => {
145 self.coerce_object(a, sty_a, b, def_id, substs,
146 ty::UniqTraitStore, bounds)
147 }
148 _ => Err(ty::terr_mismatch)
149 }
150 });
151
152 match result {
153 Ok(t) => return Ok(t),
154 Err(..) => {}
155 }
156 }
157
158 ty::ty_trait(box ty::TyTrait {
159 def_id, ref substs, store: ty::RegionTraitStore(region, m), bounds
160 }) => {
161 let result = self.unpack_actual_value(a, |sty_a| {
162 match *sty_a {
163 ty::ty_rptr(..) => {
164 self.coerce_object(a, sty_a, b, def_id, substs,
165 ty::RegionTraitStore(region, m), bounds)
166 }
167 _ => self.coerce_borrowed_object(a, sty_a, b, m)
168 }
169 });
170
171 match result {
172 Ok(t) => return Ok(t),
173 Err(..) => {}
174 }
175 }
176
177 _ => {}
178 }
179
180 self.unpack_actual_value(a, |sty_a| {
181 match *sty_a {
182 ty::ty_bare_fn(ref a_f) => {
183 // Bare functions are coercable to any closure type.
184 //
185 // FIXME(#3320) this should go away and be
186 // replaced with proper inference, got a patch
187 // underway - ndm
188 self.coerce_from_bare_fn(a, a_f, b)
189 }
190 _ => {
191 // Otherwise, just use subtyping rules.
192 self.subtype(a, b)
193 }
194 }
195 })
196 }
197
198 pub fn subtype(&self, a: ty::t, b: ty::t) -> CoerceResult {
199 match Sub(self.get_ref().clone()).tys(a, b) {
200 Ok(_) => Ok(None), // No coercion required.
201 Err(ref e) => Err(*e)
202 }
203 }
204
205 pub fn unpack_actual_value(&self, a: ty::t, f: |&ty::sty| -> CoerceResult)
206 -> CoerceResult {
207 match resolve_type(self.get_ref().infcx, a, try_resolve_tvar_shallow) {
208 Ok(t) => {
209 f(&ty::get(t).sty)
210 }
211 Err(e) => {
212 self.get_ref().infcx.tcx.sess.span_bug(
213 self.get_ref().trace.origin.span(),
214 format!("failed to resolve even without \
215 any force options: {:?}", e));
216 }
217 }
218 }
219
220 pub fn coerce_borrowed_pointer(&self,
221 a: ty::t,
222 sty_a: &ty::sty,
223 b: ty::t,
224 mt_b: ty::mt)
225 -> CoerceResult {
226 debug!("coerce_borrowed_pointer(a={}, sty_a={:?}, b={}, mt_b={:?})",
227 a.inf_str(self.get_ref().infcx), sty_a,
228 b.inf_str(self.get_ref().infcx), mt_b);
229
230 // If we have a parameter of type `&M T_a` and the value
231 // provided is `expr`, we will be adding an implicit borrow,
232 // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore,
233 // to type check, we will construct the type that `&M*expr` would
234 // yield.
235
236 let sub = Sub(self.get_ref().clone());
237 let coercion = Coercion(self.get_ref().trace.clone());
238 let r_borrow = self.get_ref().infcx.next_region_var(coercion);
239
240 let inner_ty = match *sty_a {
241 ty::ty_box(typ) | ty::ty_uniq(typ) => typ,
242 ty::ty_rptr(_, mt_a) => mt_a.ty,
243 _ => {
244 return self.subtype(a, b);
245 }
246 };
247
248 let a_borrowed = ty::mk_rptr(self.get_ref().infcx.tcx,
249 r_borrow,
250 mt {ty: inner_ty, mutbl: mt_b.mutbl});
251 if_ok!(sub.tys(a_borrowed, b));
252 Ok(Some(AutoDerefRef(AutoDerefRef {
253 autoderefs: 1,
254 autoref: Some(AutoPtr(r_borrow, mt_b.mutbl))
255 })))
256 }
257
258 pub fn coerce_borrowed_string(&self,
259 a: ty::t,
260 sty_a: &ty::sty,
261 b: ty::t)
262 -> CoerceResult {
263 debug!("coerce_borrowed_string(a={}, sty_a={:?}, b={})",
264 a.inf_str(self.get_ref().infcx), sty_a,
265 b.inf_str(self.get_ref().infcx));
266
267 match *sty_a {
268 ty::ty_uniq(t) => match ty::get(t).sty {
269 ty::ty_str => {}
270 _ => return self.subtype(a, b),
271 },
272 _ => {
273 return self.subtype(a, b);
274 }
275 };
276
277 let coercion = Coercion(self.get_ref().trace.clone());
278 let r_a = self.get_ref().infcx.next_region_var(coercion);
279 let a_borrowed = ty::mk_str_slice(self.get_ref().infcx.tcx, r_a, ast::MutImmutable);
280 if_ok!(self.subtype(a_borrowed, b));
281 Ok(Some(AutoDerefRef(AutoDerefRef {
282 autoderefs: 0,
283 autoref: Some(AutoBorrowVec(r_a, MutImmutable))
284 })))
285 }
286
287 pub fn coerce_borrowed_vector(&self,
288 a: ty::t,
289 sty_a: &ty::sty,
290 b: ty::t,
291 mutbl_b: ast::Mutability)
292 -> CoerceResult {
293 debug!("coerce_borrowed_vector(a={}, sty_a={:?}, b={})",
294 a.inf_str(self.get_ref().infcx), sty_a,
295 b.inf_str(self.get_ref().infcx));
296
297 let sub = Sub(self.get_ref().clone());
298 let coercion = Coercion(self.get_ref().trace.clone());
299 let r_borrow = self.get_ref().infcx.next_region_var(coercion);
300 let ty_inner = match *sty_a {
301 ty::ty_uniq(t) | ty::ty_ptr(ty::mt{ty: t, ..}) |
302 ty::ty_rptr(_, ty::mt{ty: t, ..}) => match ty::get(t).sty {
303 ty::ty_vec(mt, None) => mt.ty,
304 _ => {
305 return self.subtype(a, b);
306 }
307 },
308 ty::ty_vec(mt, _) => mt.ty,
309 _ => {
310 return self.subtype(a, b);
311 }
312 };
313
314 let a_borrowed = ty::mk_slice(self.get_ref().infcx.tcx, r_borrow,
315 mt {ty: ty_inner, mutbl: mutbl_b});
316 if_ok!(sub.tys(a_borrowed, b));
317 Ok(Some(AutoDerefRef(AutoDerefRef {
318 autoderefs: 0,
319 autoref: Some(AutoBorrowVec(r_borrow, mutbl_b))
320 })))
321 }
322
323 fn coerce_borrowed_object(&self,
324 a: ty::t,
325 sty_a: &ty::sty,
326 b: ty::t,
327 b_mutbl: ast::Mutability) -> CoerceResult
328 {
329 debug!("coerce_borrowed_object(a={}, sty_a={:?}, b={})",
330 a.inf_str(self.get_ref().infcx), sty_a,
331 b.inf_str(self.get_ref().infcx));
332
333 let tcx = self.get_ref().infcx.tcx;
334 let coercion = Coercion(self.get_ref().trace.clone());
335 let r_a = self.get_ref().infcx.next_region_var(coercion);
336
337 let a_borrowed = match *sty_a {
338 ty::ty_trait(box ty::TyTrait {
339 def_id,
340 ref substs,
341 bounds,
342 ..
343 }) => {
344 ty::mk_trait(tcx, def_id, substs.clone(),
345 ty::RegionTraitStore(r_a, b_mutbl), bounds)
346 }
347 _ => {
348 return self.subtype(a, b);
349 }
350 };
351
352 if_ok!(self.subtype(a_borrowed, b));
353 Ok(Some(AutoDerefRef(AutoDerefRef {
354 autoderefs: 0,
355 autoref: Some(AutoBorrowObj(r_a, b_mutbl))
356 })))
357 }
358
359 pub fn coerce_borrowed_fn(&self,
360 a: ty::t,
361 sty_a: &ty::sty,
362 b: ty::t)
363 -> CoerceResult {
364 debug!("coerce_borrowed_fn(a={}, sty_a={:?}, b={})",
365 a.inf_str(self.get_ref().infcx), sty_a,
366 b.inf_str(self.get_ref().infcx));
367
368 match *sty_a {
369 ty::ty_bare_fn(ref f) => {
370 self.coerce_from_bare_fn(a, f, b)
371 }
372 _ => {
373 self.subtype(a, b)
374 }
375 }
376 }
377
378 fn coerce_from_bare_fn(&self, a: ty::t, fn_ty_a: &ty::BareFnTy, b: ty::t)
379 -> CoerceResult {
380 /*!
381 *
382 * Attempts to coerce from a bare Rust function (`extern
383 * "Rust" fn`) into a closure or a `proc`.
384 */
385
386 self.unpack_actual_value(b, |sty_b| {
387
388 debug!("coerce_from_bare_fn(a={}, b={})",
389 a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
390
391 if fn_ty_a.abi != abi::Rust || fn_ty_a.fn_style != ast::NormalFn {
392 return self.subtype(a, b);
393 }
394
395 let fn_ty_b = match *sty_b {
396 ty::ty_closure(ref f) => (*f).clone(),
397 _ => return self.subtype(a, b)
398 };
399
400 let adj = ty::AutoAddEnv(fn_ty_b.store);
401 let a_closure = ty::mk_closure(self.get_ref().infcx.tcx,
402 ty::ClosureTy {
403 sig: fn_ty_a.sig.clone(),
404 .. *fn_ty_b
405 });
406 if_ok!(self.subtype(a_closure, b));
407 Ok(Some(adj))
408 })
409 }
410
411 pub fn coerce_unsafe_ptr(&self,
412 a: ty::t,
413 sty_a: &ty::sty,
414 b: ty::t,
415 mt_b: ty::mt)
416 -> CoerceResult {
417 debug!("coerce_unsafe_ptr(a={}, sty_a={:?}, b={})",
418 a.inf_str(self.get_ref().infcx), sty_a,
419 b.inf_str(self.get_ref().infcx));
420
421 let mt_a = match *sty_a {
422 ty::ty_rptr(_, mt) => mt,
423 _ => {
424 return self.subtype(a, b);
425 }
426 };
427
428 // check that the types which they point at are compatible
429 let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, mt_a);
430 if_ok!(self.subtype(a_unsafe, b));
431
432 // although references and unsafe ptrs have the same
433 // representation, we still register an AutoDerefRef so that
434 // regionck knows that the region for `a` must be valid here
435 Ok(Some(AutoDerefRef(AutoDerefRef {
436 autoderefs: 1,
437 autoref: Some(ty::AutoUnsafe(mt_b.mutbl))
438 })))
439 }
440
441 pub fn coerce_object(&self,
442 a: ty::t,
443 sty_a: &ty::sty,
444 b: ty::t,
445 trait_def_id: ast::DefId,
446 trait_substs: &ty::substs,
447 trait_store: ty::TraitStore,
448 bounds: ty::BuiltinBounds) -> CoerceResult {
449
450 debug!("coerce_object(a={}, sty_a={:?}, b={})",
451 a.inf_str(self.get_ref().infcx), sty_a,
452 b.inf_str(self.get_ref().infcx));
453
454 Ok(Some(ty::AutoObject(trait_store, bounds,
455 trait_def_id, trait_substs.clone())))
456 }
457 }