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 check::{autoderef, FnCtxt, UnresolvedTypeAction};
65 use middle::infer::{self, Coercion};
66 use middle::traits::{self, ObligationCause};
67 use middle::traits::{predicate_for_trait_def, report_selection_error};
68 use middle::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef};
69 use middle::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer};
70 use middle::ty::adjustment::{AdjustUnsafeFnPointer};
71 use middle::ty::{self, LvaluePreference, TypeAndMut, Ty};
72 use middle::ty::error::TypeError;
73 use middle::ty::relate::RelateResult;
74 use util::common::indent;
76 use std::cell::RefCell;
77 use std::collections::VecDeque;
80 struct Coerce<'a, 'tcx: 'a> {
81 fcx: &'a FnCtxt<'a, 'tcx>,
82 origin: infer::TypeOrigin,
83 unsizing_obligations: RefCell<Vec<traits::PredicateObligation<'tcx>>>,
86 type CoerceResult<'tcx> = RelateResult<'tcx, Option<AutoAdjustment<'tcx>>>;
88 impl<'f, 'tcx> Coerce<'f, 'tcx> {
89 fn tcx(&self) -> &ty::ctxt<'tcx> {
93 fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
94 try!(self.fcx.infcx().sub_types(false, self.origin.clone(), a, b));
95 Ok(None) // No coercion required.
98 fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where
99 F: FnOnce(Ty<'tcx>) -> T,
101 f(self.fcx.infcx().shallow_resolve(a))
108 -> CoerceResult<'tcx> {
109 debug!("Coerce.tys({:?} => {:?})",
113 // Consider coercing the subtype to a DST
114 let unsize = self.unpack_actual_value(a, |a| {
115 self.coerce_unsized(a, b)
121 // Examine the supertype and consider auto-borrowing.
123 // Note: does not attempt to resolve type variables we encounter.
124 // See above for details.
126 ty::TyRawPtr(mt_b) => {
127 return self.unpack_actual_value(a, |a| {
128 self.coerce_unsafe_ptr(a, b, mt_b.mutbl)
132 ty::TyRef(_, mt_b) => {
133 return self.unpack_actual_value(a, |a| {
134 self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl)
141 self.unpack_actual_value(a, |a| {
143 ty::TyBareFn(Some(_), a_f) => {
144 // Function items are coercible to any closure
145 // type; function pointers are not (that would
146 // require double indirection).
147 self.coerce_from_fn_item(a, a_f, b)
149 ty::TyBareFn(None, a_f) => {
150 // We permit coercion of fn pointers to drop the
152 self.coerce_from_fn_pointer(a, a_f, b)
155 // Otherwise, just use subtyping rules.
162 /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
163 /// To match `A` with `B`, autoderef will be performed,
164 /// calling `deref`/`deref_mut` where necessary.
165 fn coerce_borrowed_pointer(&self,
169 mutbl_b: hir::Mutability)
170 -> CoerceResult<'tcx> {
171 debug!("coerce_borrowed_pointer(a={:?}, b={:?})",
175 // If we have a parameter of type `&M T_a` and the value
176 // provided is `expr`, we will be adding an implicit borrow,
177 // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore,
178 // to type check, we will construct the type that `&M*expr` would
182 ty::TyRef(_, mt_a) => {
183 try!(coerce_mutbls(mt_a.mutbl, mutbl_b));
185 _ => return self.subtype(a, b)
188 let coercion = Coercion(self.origin.span());
189 let r_borrow = self.fcx.infcx().next_region_var(coercion);
190 let r_borrow = self.tcx().mk_region(r_borrow);
191 let autoref = Some(AutoPtr(r_borrow, mutbl_b));
193 let lvalue_pref = LvaluePreference::from_mutbl(mutbl_b);
194 let mut first_error = None;
195 let (_, autoderefs, success) = autoderef(self.fcx,
199 UnresolvedTypeAction::Ignore,
201 |inner_ty, autoderef| {
203 // Don't let this pass, otherwise it would cause
204 // &T to autoref to &&T.
207 let ty = self.tcx().mk_ref(r_borrow,
208 TypeAndMut {ty: inner_ty, mutbl: mutbl_b});
209 if let Err(err) = self.subtype(ty, b) {
210 if first_error.is_none() {
211 first_error = Some(err);
221 Ok(Some(AdjustDerefRef(AutoDerefRef {
222 autoderefs: autoderefs,
228 // Return original error as if overloaded deref was never
229 // attempted, to avoid irrelevant/confusing error messages.
230 Err(first_error.expect("coerce_borrowed_pointer failed with no error?"))
236 // &[T; n] or &mut [T; n] -> &[T]
237 // or &mut [T; n] -> &mut [T]
238 // or &Concrete -> &Trait, etc.
239 fn coerce_unsized(&self,
242 -> CoerceResult<'tcx> {
243 debug!("coerce_unsized(source={:?}, target={:?})",
247 let traits = (self.tcx().lang_items.unsize_trait(),
248 self.tcx().lang_items.coerce_unsized_trait());
249 let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits {
252 debug!("Missing Unsize or CoerceUnsized traits");
253 return Err(TypeError::Mismatch);
256 // Note, we want to avoid unnecessary unsizing. We don't want to coerce to
257 // a DST unless we have to. This currently comes out in the wash since
258 // we can't unify [T] with U. But to properly support DST, we need to allow
259 // that, at which point we will need extra checks on the target here.
261 // Handle reborrows before selecting `Source: CoerceUnsized<Target>`.
262 let (source, reborrow) = match (&source.sty, &target.sty) {
263 (&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => {
264 try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
266 let coercion = Coercion(self.origin.span());
267 let r_borrow = self.fcx.infcx().next_region_var(coercion);
268 let region = self.tcx().mk_region(r_borrow);
269 (mt_a.ty, Some(AutoPtr(region, mt_b.mutbl)))
271 (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
272 try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
273 (mt_a.ty, Some(AutoUnsafe(mt_b.mutbl)))
277 let source = source.adjust_for_autoref(self.tcx(), reborrow);
279 let mut selcx = traits::SelectionContext::new(self.fcx.infcx());
281 // Use a FIFO queue for this custom fulfillment procedure.
282 let mut queue = VecDeque::new();
283 let mut leftover_predicates = vec![];
285 // Create an obligation for `Source: CoerceUnsized<Target>`.
286 let cause = ObligationCause::misc(self.origin.span(), self.fcx.body_id);
287 queue.push_back(predicate_for_trait_def(self.tcx(),
294 // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
295 // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
296 // inference might unify those two inner type variables later.
297 let traits = [coerce_unsized_did, unsize_did];
298 while let Some(obligation) = queue.pop_front() {
299 debug!("coerce_unsized resolve step: {:?}", obligation);
300 let trait_ref = match obligation.predicate {
301 ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
305 leftover_predicates.push(obligation);
309 match selcx.select(&obligation.with(trait_ref)) {
310 // Uncertain or unimplemented.
311 Ok(None) | Err(traits::Unimplemented) => {
312 debug!("coerce_unsized: early return - can't prove obligation");
313 return Err(TypeError::Mismatch);
316 // Object safety violations or miscellaneous.
318 report_selection_error(self.fcx.infcx(), &obligation, &err);
319 // Treat this like an obligation and follow through
320 // with the unsizing - the lack of a coercion should
321 // be silent, as it causes a type mismatch later.
324 Ok(Some(vtable)) => {
325 for obligation in vtable.nested_obligations() {
326 queue.push_back(obligation);
332 let mut obligations = self.unsizing_obligations.borrow_mut();
333 assert!(obligations.is_empty());
334 *obligations = leftover_predicates;
336 let adjustment = AutoDerefRef {
337 autoderefs: if reborrow.is_some() { 1 } else { 0 },
341 debug!("Success, coerced with {:?}", adjustment);
342 Ok(Some(AdjustDerefRef(adjustment)))
345 fn coerce_from_fn_pointer(&self,
347 fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
349 -> CoerceResult<'tcx>
352 * Attempts to coerce from the type of a Rust function item
353 * into a closure or a `proc`.
356 self.unpack_actual_value(b, |b| {
357 debug!("coerce_from_fn_pointer(a={:?}, b={:?})",
360 if let ty::TyBareFn(None, fn_ty_b) = b.sty {
361 match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
362 (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
363 let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a);
364 try!(self.subtype(unsafe_a, b));
365 return Ok(Some(AdjustUnsafeFnPointer));
374 fn coerce_from_fn_item(&self,
376 fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
378 -> CoerceResult<'tcx> {
380 * Attempts to coerce from the type of a Rust function item
381 * into a closure or a `proc`.
384 self.unpack_actual_value(b, |b| {
385 debug!("coerce_from_fn_item(a={:?}, b={:?})",
389 ty::TyBareFn(None, _) => {
390 let a_fn_pointer = self.tcx().mk_fn(None, fn_ty_a);
391 try!(self.subtype(a_fn_pointer, b));
392 Ok(Some(AdjustReifyFnPointer))
394 _ => self.subtype(a, b)
399 fn coerce_unsafe_ptr(&self,
402 mutbl_b: hir::Mutability)
403 -> CoerceResult<'tcx> {
404 debug!("coerce_unsafe_ptr(a={:?}, b={:?})",
408 let (is_ref, mt_a) = match a.sty {
409 ty::TyRef(_, mt) => (true, mt),
410 ty::TyRawPtr(mt) => (false, mt),
412 return self.subtype(a, b);
416 // Check that the types which they point at are compatible.
417 let a_unsafe = self.tcx().mk_ptr(ty::TypeAndMut{ mutbl: mutbl_b, ty: mt_a.ty });
418 try!(self.subtype(a_unsafe, b));
419 try!(coerce_mutbls(mt_a.mutbl, mutbl_b));
421 // Although references and unsafe ptrs have the same
422 // representation, we still register an AutoDerefRef so that
423 // regionck knows that the region for `a` must be valid here.
425 Ok(Some(AdjustDerefRef(AutoDerefRef {
427 autoref: Some(AutoUnsafe(mutbl_b)),
436 pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
440 -> RelateResult<'tcx, ()> {
441 debug!("mk_assignty({:?} -> {:?})", a, b);
442 let mut unsizing_obligations = vec![];
443 let adjustment = try!(indent(|| {
444 fcx.infcx().commit_if_ok(|_| {
445 let coerce = Coerce {
447 origin: infer::ExprAssignable(expr.span),
448 unsizing_obligations: RefCell::new(vec![])
450 let adjustment = try!(coerce.coerce(expr, a, b));
451 unsizing_obligations = coerce.unsizing_obligations.into_inner();
456 if let Some(AdjustDerefRef(auto)) = adjustment {
457 if auto.unsize.is_some() {
458 for obligation in unsizing_obligations {
459 fcx.register_predicate(obligation);
464 if let Some(adjustment) = adjustment {
465 debug!("Success, coerced with {:?}", adjustment);
466 fcx.write_adjustment(expr.id, adjustment);
471 fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
472 to_mutbl: hir::Mutability)
473 -> CoerceResult<'tcx> {
474 match (from_mutbl, to_mutbl) {
475 (hir::MutMutable, hir::MutMutable) |
476 (hir::MutImmutable, hir::MutImmutable) |
477 (hir::MutMutable, hir::MutImmutable) => Ok(None),
478 (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability)