]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/coercion.rs
move traits structural impls to traits::structural_impls
[rust.git] / src / librustc_typeck / check / coercion.rs
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 //! # Type Coercion
12 //!
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).
18 //!
19 //! ## Reborrowing
20 //!
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.
28 //!
29 //! ## Subtle note
30 //!
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
35 //!
36 //!    fn foo<A>(a: A, b: A) { ... }
37 //!
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.
43 //!
44 //! ## Subtler note
45 //!
46 //! However, right now, if the user manually specifies the
47 //! values for the type variables, as so:
48 //!
49 //!    foo::<&int>(@1, @2)
50 //!
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.
62
63 use check::{autoderef, FnCtxt, UnresolvedTypeAction};
64
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::{AutoDerefRef, AdjustDerefRef};
69 use middle::ty::{self, LvaluePreference, TypeAndMut, Ty};
70 use middle::ty::error::TypeError;
71 use middle::ty::relate::RelateResult;
72 use util::common::indent;
73
74 use std::cell::RefCell;
75 use std::collections::VecDeque;
76 use rustc_front::hir;
77
78 struct Coerce<'a, 'tcx: 'a> {
79     fcx: &'a FnCtxt<'a, 'tcx>,
80     origin: infer::TypeOrigin,
81     unsizing_obligations: RefCell<Vec<traits::PredicateObligation<'tcx>>>,
82 }
83
84 type CoerceResult<'tcx> = RelateResult<'tcx, Option<ty::AutoAdjustment<'tcx>>>;
85
86 impl<'f, 'tcx> Coerce<'f, 'tcx> {
87     fn tcx(&self) -> &ty::ctxt<'tcx> {
88         self.fcx.tcx()
89     }
90
91     fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
92         try!(self.fcx.infcx().sub_types(false, self.origin.clone(), a, b));
93         Ok(None) // No coercion required.
94     }
95
96     fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where
97         F: FnOnce(Ty<'tcx>) -> T,
98     {
99         f(self.fcx.infcx().shallow_resolve(a))
100     }
101
102     fn coerce(&self,
103               expr_a: &hir::Expr,
104               a: Ty<'tcx>,
105               b: Ty<'tcx>)
106               -> CoerceResult<'tcx> {
107         debug!("Coerce.tys({:?} => {:?})",
108                a,
109                b);
110
111         // Consider coercing the subtype to a DST
112         let unsize = self.unpack_actual_value(a, |a| {
113             self.coerce_unsized(a, b)
114         });
115         if unsize.is_ok() {
116             return unsize;
117         }
118
119         // Examine the supertype and consider auto-borrowing.
120         //
121         // Note: does not attempt to resolve type variables we encounter.
122         // See above for details.
123         match b.sty {
124             ty::TyRawPtr(mt_b) => {
125                 return self.unpack_actual_value(a, |a| {
126                     self.coerce_unsafe_ptr(a, b, mt_b.mutbl)
127                 });
128             }
129
130             ty::TyRef(_, mt_b) => {
131                 return self.unpack_actual_value(a, |a| {
132                     self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl)
133                 });
134             }
135
136             _ => {}
137         }
138
139         self.unpack_actual_value(a, |a| {
140             match a.sty {
141                 ty::TyBareFn(Some(_), a_f) => {
142                     // Function items are coercible to any closure
143                     // type; function pointers are not (that would
144                     // require double indirection).
145                     self.coerce_from_fn_item(a, a_f, b)
146                 }
147                 ty::TyBareFn(None, a_f) => {
148                     // We permit coercion of fn pointers to drop the
149                     // unsafe qualifier.
150                     self.coerce_from_fn_pointer(a, a_f, b)
151                 }
152                 _ => {
153                     // Otherwise, just use subtyping rules.
154                     self.subtype(a, b)
155                 }
156             }
157         })
158     }
159
160     /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
161     /// To match `A` with `B`, autoderef will be performed,
162     /// calling `deref`/`deref_mut` where necessary.
163     fn coerce_borrowed_pointer(&self,
164                                expr_a: &hir::Expr,
165                                a: Ty<'tcx>,
166                                b: Ty<'tcx>,
167                                mutbl_b: hir::Mutability)
168                                -> CoerceResult<'tcx> {
169         debug!("coerce_borrowed_pointer(a={:?}, b={:?})",
170                a,
171                b);
172
173         // If we have a parameter of type `&M T_a` and the value
174         // provided is `expr`, we will be adding an implicit borrow,
175         // meaning that we convert `f(expr)` to `f(&M *expr)`.  Therefore,
176         // to type check, we will construct the type that `&M*expr` would
177         // yield.
178
179         match a.sty {
180             ty::TyRef(_, mt_a) => {
181                 try!(coerce_mutbls(mt_a.mutbl, mutbl_b));
182             }
183             _ => return self.subtype(a, b)
184         }
185
186         let coercion = Coercion(self.origin.span());
187         let r_borrow = self.fcx.infcx().next_region_var(coercion);
188         let r_borrow = self.tcx().mk_region(r_borrow);
189         let autoref = Some(ty::AutoPtr(r_borrow, mutbl_b));
190
191         let lvalue_pref = LvaluePreference::from_mutbl(mutbl_b);
192         let mut first_error = None;
193         let (_, autoderefs, success) = autoderef(self.fcx,
194                                                  expr_a.span,
195                                                  a,
196                                                  Some(expr_a),
197                                                  UnresolvedTypeAction::Ignore,
198                                                  lvalue_pref,
199                                                  |inner_ty, autoderef| {
200             if autoderef == 0 {
201                 // Don't let this pass, otherwise it would cause
202                 // &T to autoref to &&T.
203                 return None;
204             }
205             let ty = self.tcx().mk_ref(r_borrow,
206                                         TypeAndMut {ty: inner_ty, mutbl: mutbl_b});
207             if let Err(err) = self.subtype(ty, b) {
208                 if first_error.is_none() {
209                     first_error = Some(err);
210                 }
211                 None
212             } else {
213                 Some(())
214             }
215         });
216
217         match success {
218             Some(_) => {
219                 Ok(Some(AdjustDerefRef(AutoDerefRef {
220                     autoderefs: autoderefs,
221                     autoref: autoref,
222                     unsize: None
223                 })))
224             }
225             None => {
226                 // Return original error as if overloaded deref was never
227                 // attempted, to avoid irrelevant/confusing error messages.
228                 Err(first_error.expect("coerce_borrowed_pointer failed with no error?"))
229             }
230         }
231     }
232
233
234     // &[T; n] or &mut [T; n] -> &[T]
235     // or &mut [T; n] -> &mut [T]
236     // or &Concrete -> &Trait, etc.
237     fn coerce_unsized(&self,
238                       source: Ty<'tcx>,
239                       target: Ty<'tcx>)
240                       -> CoerceResult<'tcx> {
241         debug!("coerce_unsized(source={:?}, target={:?})",
242                source,
243                target);
244
245         let traits = (self.tcx().lang_items.unsize_trait(),
246                       self.tcx().lang_items.coerce_unsized_trait());
247         let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits {
248             (u, cu)
249         } else {
250             debug!("Missing Unsize or CoerceUnsized traits");
251             return Err(TypeError::Mismatch);
252         };
253
254         // Note, we want to avoid unnecessary unsizing. We don't want to coerce to
255         // a DST unless we have to. This currently comes out in the wash since
256         // we can't unify [T] with U. But to properly support DST, we need to allow
257         // that, at which point we will need extra checks on the target here.
258
259         // Handle reborrows before selecting `Source: CoerceUnsized<Target>`.
260         let (source, reborrow) = match (&source.sty, &target.sty) {
261             (&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => {
262                 try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
263
264                 let coercion = Coercion(self.origin.span());
265                 let r_borrow = self.fcx.infcx().next_region_var(coercion);
266                 let region = self.tcx().mk_region(r_borrow);
267                 (mt_a.ty, Some(ty::AutoPtr(region, mt_b.mutbl)))
268             }
269             (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
270                 try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
271                 (mt_a.ty, Some(ty::AutoUnsafe(mt_b.mutbl)))
272             }
273             _ => (source, None)
274         };
275         let source = source.adjust_for_autoref(self.tcx(), reborrow);
276
277         let mut selcx = traits::SelectionContext::new(self.fcx.infcx());
278
279         // Use a FIFO queue for this custom fulfillment procedure.
280         let mut queue = VecDeque::new();
281         let mut leftover_predicates = vec![];
282
283         // Create an obligation for `Source: CoerceUnsized<Target>`.
284         let cause = ObligationCause::misc(self.origin.span(), self.fcx.body_id);
285         queue.push_back(predicate_for_trait_def(self.tcx(),
286                                                 cause,
287                                                 coerce_unsized_did,
288                                                 0,
289                                                 source,
290                                                 vec![target]));
291
292         // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
293         // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
294         // inference might unify those two inner type variables later.
295         let traits = [coerce_unsized_did, unsize_did];
296         while let Some(obligation) = queue.pop_front() {
297             debug!("coerce_unsized resolve step: {:?}", obligation);
298             let trait_ref =  match obligation.predicate {
299                 ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
300                     tr.clone()
301                 }
302                 _ => {
303                     leftover_predicates.push(obligation);
304                     continue;
305                 }
306             };
307             match selcx.select(&obligation.with(trait_ref)) {
308                 // Uncertain or unimplemented.
309                 Ok(None) | Err(traits::Unimplemented) => {
310                     debug!("coerce_unsized: early return - can't prove obligation");
311                     return Err(TypeError::Mismatch);
312                 }
313
314                 // Object safety violations or miscellaneous.
315                 Err(err) => {
316                     report_selection_error(self.fcx.infcx(), &obligation, &err);
317                     // Treat this like an obligation and follow through
318                     // with the unsizing - the lack of a coercion should
319                     // be silent, as it causes a type mismatch later.
320                 }
321
322                 Ok(Some(vtable)) => {
323                     for obligation in vtable.nested_obligations() {
324                         queue.push_back(obligation);
325                     }
326                 }
327             }
328         }
329
330         let mut obligations = self.unsizing_obligations.borrow_mut();
331         assert!(obligations.is_empty());
332         *obligations = leftover_predicates;
333
334         let adjustment = AutoDerefRef {
335             autoderefs: if reborrow.is_some() { 1 } else { 0 },
336             autoref: reborrow,
337             unsize: Some(target)
338         };
339         debug!("Success, coerced with {:?}", adjustment);
340         Ok(Some(AdjustDerefRef(adjustment)))
341     }
342
343     fn coerce_from_fn_pointer(&self,
344                            a: Ty<'tcx>,
345                            fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
346                            b: Ty<'tcx>)
347                            -> CoerceResult<'tcx>
348     {
349         /*!
350          * Attempts to coerce from the type of a Rust function item
351          * into a closure or a `proc`.
352          */
353
354         self.unpack_actual_value(b, |b| {
355             debug!("coerce_from_fn_pointer(a={:?}, b={:?})",
356                    a, b);
357
358             if let ty::TyBareFn(None, fn_ty_b) = b.sty {
359                 match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
360                     (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
361                         let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a);
362                         try!(self.subtype(unsafe_a, b));
363                         return Ok(Some(ty::AdjustUnsafeFnPointer));
364                     }
365                     _ => {}
366                 }
367             }
368             self.subtype(a, b)
369         })
370     }
371
372     fn coerce_from_fn_item(&self,
373                            a: Ty<'tcx>,
374                            fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
375                            b: Ty<'tcx>)
376                            -> CoerceResult<'tcx> {
377         /*!
378          * Attempts to coerce from the type of a Rust function item
379          * into a closure or a `proc`.
380          */
381
382         self.unpack_actual_value(b, |b| {
383             debug!("coerce_from_fn_item(a={:?}, b={:?})",
384                    a, b);
385
386             match b.sty {
387                 ty::TyBareFn(None, _) => {
388                     let a_fn_pointer = self.tcx().mk_fn(None, fn_ty_a);
389                     try!(self.subtype(a_fn_pointer, b));
390                     Ok(Some(ty::AdjustReifyFnPointer))
391                 }
392                 _ => self.subtype(a, b)
393             }
394         })
395     }
396
397     fn coerce_unsafe_ptr(&self,
398                          a: Ty<'tcx>,
399                          b: Ty<'tcx>,
400                          mutbl_b: hir::Mutability)
401                          -> CoerceResult<'tcx> {
402         debug!("coerce_unsafe_ptr(a={:?}, b={:?})",
403                a,
404                b);
405
406         let (is_ref, mt_a) = match a.sty {
407             ty::TyRef(_, mt) => (true, mt),
408             ty::TyRawPtr(mt) => (false, mt),
409             _ => {
410                 return self.subtype(a, b);
411             }
412         };
413
414         // Check that the types which they point at are compatible.
415         let a_unsafe = self.tcx().mk_ptr(ty::TypeAndMut{ mutbl: mutbl_b, ty: mt_a.ty });
416         try!(self.subtype(a_unsafe, b));
417         try!(coerce_mutbls(mt_a.mutbl, mutbl_b));
418
419         // Although references and unsafe ptrs have the same
420         // representation, we still register an AutoDerefRef so that
421         // regionck knows that the region for `a` must be valid here.
422         if is_ref {
423             Ok(Some(AdjustDerefRef(AutoDerefRef {
424                 autoderefs: 1,
425                 autoref: Some(ty::AutoUnsafe(mutbl_b)),
426                 unsize: None
427             })))
428         } else {
429             Ok(None)
430         }
431     }
432 }
433
434 pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
435                              expr: &hir::Expr,
436                              a: Ty<'tcx>,
437                              b: Ty<'tcx>)
438                              -> RelateResult<'tcx, ()> {
439     debug!("mk_assignty({:?} -> {:?})", a, b);
440     let mut unsizing_obligations = vec![];
441     let adjustment = try!(indent(|| {
442         fcx.infcx().commit_if_ok(|_| {
443             let coerce = Coerce {
444                 fcx: fcx,
445                 origin: infer::ExprAssignable(expr.span),
446                 unsizing_obligations: RefCell::new(vec![])
447             };
448             let adjustment = try!(coerce.coerce(expr, a, b));
449             unsizing_obligations = coerce.unsizing_obligations.into_inner();
450             Ok(adjustment)
451         })
452     }));
453
454     if let Some(AdjustDerefRef(auto)) = adjustment {
455         if auto.unsize.is_some() {
456             for obligation in unsizing_obligations {
457                 fcx.register_predicate(obligation);
458             }
459         }
460     }
461
462     if let Some(adjustment) = adjustment {
463         debug!("Success, coerced with {:?}", adjustment);
464         fcx.write_adjustment(expr.id, adjustment);
465     }
466     Ok(())
467 }
468
469 fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
470                        to_mutbl: hir::Mutability)
471                        -> CoerceResult<'tcx> {
472     match (from_mutbl, to_mutbl) {
473         (hir::MutMutable, hir::MutMutable) |
474         (hir::MutImmutable, hir::MutImmutable) |
475         (hir::MutMutable, hir::MutImmutable) => Ok(None),
476         (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability)
477     }
478 }