]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/coercion.rs
remove unused mut qualifiers
[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, NoPreference, PreferMutLvalue, UnresolvedTypeAction};
64
65 use middle::infer::{self, cres, Coercion, TypeTrace};
66 use middle::infer::combine::Combine;
67 use middle::infer::sub::Sub;
68 use middle::subst;
69 use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe};
70 use middle::ty::{self, mt, Ty};
71 use util::common::indent;
72 use util::ppaux;
73 use util::ppaux::Repr;
74
75 use syntax::ast;
76
77 struct Coerce<'a, 'tcx: 'a> {
78     fcx: &'a FnCtxt<'a, 'tcx>,
79     trace: TypeTrace<'tcx>
80 }
81
82 type CoerceResult<'tcx> = cres<'tcx, Option<ty::AutoAdjustment<'tcx>>>;
83
84 impl<'f, 'tcx> Coerce<'f, 'tcx> {
85     fn tcx(&self) -> &ty::ctxt<'tcx> {
86         self.fcx.tcx()
87     }
88
89     fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
90         let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone()));
91         try!(sub.tys(a, b));
92         Ok(None) // No coercion required.
93     }
94
95     fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where
96         F: FnOnce(Ty<'tcx>) -> T,
97     {
98         f(self.fcx.infcx().shallow_resolve(a))
99     }
100
101     fn coerce(&self,
102               expr_a: &ast::Expr,
103               a: Ty<'tcx>,
104               b: Ty<'tcx>)
105               -> CoerceResult<'tcx> {
106         debug!("Coerce.tys({} => {})",
107                a.repr(self.tcx()),
108                b.repr(self.tcx()));
109
110         // Consider coercing the subtype to a DST
111         let unsize = self.unpack_actual_value(a, |a| {
112             self.coerce_unsized(a, b)
113         });
114         if unsize.is_ok() {
115             return unsize;
116         }
117
118         // Examine the supertype and consider auto-borrowing.
119         //
120         // Note: does not attempt to resolve type variables we encounter.
121         // See above for details.
122         match b.sty {
123             ty::ty_ptr(mt_b) => {
124                 return self.unpack_actual_value(a, |a| {
125                     self.coerce_unsafe_ptr(a, b, mt_b.mutbl)
126                 });
127             }
128
129             ty::ty_rptr(_, mt_b) => {
130                 return self.unpack_actual_value(a, |a| {
131                     self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl)
132                 });
133             }
134
135             _ => {}
136         }
137
138         self.unpack_actual_value(a, |a| {
139             match a.sty {
140                 ty::ty_bare_fn(Some(a_def_id), a_f) => {
141                     // Function items are coercible to any closure
142                     // type; function pointers are not (that would
143                     // require double indirection).
144                     self.coerce_from_fn_item(a, a_def_id, a_f, b)
145                 }
146                 _ => {
147                     // Otherwise, just use subtyping rules.
148                     self.subtype(a, b)
149                 }
150             }
151         })
152     }
153
154     /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
155     /// To match `A` with `B`, autoderef will be performed,
156     /// calling `deref`/`deref_mut` where necessary.
157     fn coerce_borrowed_pointer(&self,
158                                expr_a: &ast::Expr,
159                                a: Ty<'tcx>,
160                                b: Ty<'tcx>,
161                                mutbl_b: ast::Mutability)
162                                -> CoerceResult<'tcx> {
163         debug!("coerce_borrowed_pointer(a={}, b={})",
164                a.repr(self.tcx()),
165                b.repr(self.tcx()));
166
167         // If we have a parameter of type `&M T_a` and the value
168         // provided is `expr`, we will be adding an implicit borrow,
169         // meaning that we convert `f(expr)` to `f(&M *expr)`.  Therefore,
170         // to type check, we will construct the type that `&M*expr` would
171         // yield.
172
173         match a.sty {
174             ty::ty_rptr(_, mt_a) => {
175                 if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) {
176                     return Err(ty::terr_mutability);
177                 }
178             }
179             _ => return self.subtype(a, b)
180         }
181
182         let coercion = Coercion(self.trace.clone());
183         let r_borrow = self.fcx.infcx().next_region_var(coercion);
184         let autoref = Some(AutoPtr(r_borrow, mutbl_b, None));
185
186         let r_borrow = self.tcx().mk_region(r_borrow);
187         let lvalue_pref = match mutbl_b {
188             ast::MutMutable => PreferMutLvalue,
189             ast::MutImmutable => NoPreference
190         };
191         let mut first_error = None;
192         let (_, autoderefs, success) = autoderef(self.fcx,
193                                                  expr_a.span,
194                                                  a,
195                                                  Some(expr_a),
196                                                  UnresolvedTypeAction::Ignore,
197                                                  lvalue_pref,
198                                                  |inner_ty, autoderef| {
199             if autoderef == 0 {
200                 // Don't let this pass, otherwise it would cause
201                 // &T to autoref to &&T.
202                 return None;
203             }
204             let ty = ty::mk_rptr(self.tcx(), r_borrow,
205                                  mt {ty: inner_ty, mutbl: mutbl_b});
206             if let Err(err) = self.fcx.infcx().try(|_| self.subtype(ty, b)) {
207                 if first_error.is_none() {
208                     first_error = Some(err);
209                 }
210                 None
211             } else {
212                 Some(())
213             }
214         });
215
216         match success {
217             Some(_) => {
218                 Ok(Some(AdjustDerefRef(AutoDerefRef {
219                     autoderefs: autoderefs,
220                     autoref: autoref
221                 })))
222             }
223             None => {
224                 // Return original error as if overloaded deref was never
225                 // attempted, to avoid irrelevant/confusing error messages.
226                 Err(first_error.expect("coerce_borrowed_pointer failed with no error?"))
227             }
228         }
229     }
230
231
232     // &[T, ..n] or &mut [T, ..n] -> &[T]
233     // or &mut [T, ..n] -> &mut [T]
234     // or &Concrete -> &Trait, etc.
235     fn coerce_unsized(&self,
236                       a: Ty<'tcx>,
237                       b: Ty<'tcx>)
238                       -> CoerceResult<'tcx> {
239         debug!("coerce_unsized(a={}, b={})",
240                a.repr(self.tcx()),
241                b.repr(self.tcx()));
242
243         // Note, we want to avoid unnecessary unsizing. We don't want to coerce to
244         // a DST unless we have to. This currently comes out in the wash since
245         // we can't unify [T] with U. But to properly support DST, we need to allow
246         // that, at which point we will need extra checks on b here.
247
248         match (&a.sty, &b.sty) {
249             (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => {
250                 self.unpack_actual_value(t_a, |a| {
251                     match self.unsize_ty(t_a, a, mt_b.ty) {
252                         Some((ty, kind)) => {
253                             if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
254                                 return Err(ty::terr_mutability);
255                             }
256
257                             let coercion = Coercion(self.trace.clone());
258                             let r_borrow = self.fcx.infcx().next_region_var(coercion);
259                             let ty = ty::mk_rptr(self.tcx(),
260                                                  self.tcx().mk_region(r_borrow),
261                                                  ty::mt{ty: ty, mutbl: mt_b.mutbl});
262                             try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
263                             debug!("Success, coerced with AutoDerefRef(1, \
264                                     AutoPtr(AutoUnsize({:?})))", kind);
265                             Ok(Some(AdjustDerefRef(AutoDerefRef {
266                                 autoderefs: 1,
267                                 autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl,
268                                                           Some(box AutoUnsize(kind))))
269                             })))
270                         }
271                         _ => Err(ty::terr_mismatch)
272                     }
273                 })
274             }
275             (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => {
276                 self.unpack_actual_value(t_a, |a| {
277                     match self.unsize_ty(t_a, a, mt_b.ty) {
278                         Some((ty, kind)) => {
279                             if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
280                                 return Err(ty::terr_mutability);
281                             }
282
283                             let ty = ty::mk_ptr(self.tcx(),
284                                                  ty::mt{ty: ty, mutbl: mt_b.mutbl});
285                             try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
286                             debug!("Success, coerced with AutoDerefRef(1, \
287                                     AutoPtr(AutoUnsize({:?})))", kind);
288                             Ok(Some(AdjustDerefRef(AutoDerefRef {
289                                 autoderefs: 1,
290                                 autoref: Some(ty::AutoUnsafe(mt_b.mutbl,
291                                                              Some(box AutoUnsize(kind))))
292                             })))
293                         }
294                         _ => Err(ty::terr_mismatch)
295                     }
296                 })
297             }
298             (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => {
299                 self.unpack_actual_value(t_a, |a| {
300                     match self.unsize_ty(t_a, a, t_b) {
301                         Some((ty, kind)) => {
302                             let ty = ty::mk_uniq(self.tcx(), ty);
303                             try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
304                             debug!("Success, coerced with AutoDerefRef(1, \
305                                     AutoUnsizeUniq({:?}))", kind);
306                             Ok(Some(AdjustDerefRef(AutoDerefRef {
307                                 autoderefs: 1,
308                                 autoref: Some(ty::AutoUnsizeUniq(kind))
309                             })))
310                         }
311                         _ => Err(ty::terr_mismatch)
312                     }
313                 })
314             }
315             _ => Err(ty::terr_mismatch)
316         }
317     }
318
319     // Takes a type and returns an unsized version along with the adjustment
320     // performed to unsize it.
321     // E.g., `[T, ..n]` -> `([T], UnsizeLength(n))`
322     fn unsize_ty(&self,
323                  ty_a: Ty<'tcx>,
324                  a: Ty<'tcx>,
325                  ty_b: Ty<'tcx>)
326                  -> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)> {
327         debug!("unsize_ty(a={:?}, ty_b={})", a, ty_b.repr(self.tcx()));
328
329         let tcx = self.tcx();
330
331         self.unpack_actual_value(ty_b, |b|
332             match (&a.sty, &b.sty) {
333                 (&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => {
334                     let ty = ty::mk_vec(tcx, t_a, None);
335                     Some((ty, ty::UnsizeLength(len)))
336                 }
337                 (&ty::ty_trait(..), &ty::ty_trait(..)) => {
338                     None
339                 }
340                 (_, &ty::ty_trait(box ty::TyTrait { ref principal, ref bounds })) => {
341                     // FIXME what is the purpose of `ty`?
342                     let ty = ty::mk_trait(tcx, principal.clone(), bounds.clone());
343                     Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: principal.clone(),
344                                                              bounds: bounds.clone() },
345                                                ty_a)))
346                 }
347                 (&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b))
348                   if did_a == did_b => {
349                     debug!("unsizing a struct");
350                     // Try unsizing each type param in turn to see if we end up with ty_b.
351                     let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace);
352                     let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
353                     assert!(ty_substs_a.len() == ty_substs_b.len());
354
355                     let mut result = None;
356                     let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
357                     for (i, (tp_a, tp_b)) in tps {
358                         if self.fcx.infcx().try(|_| self.subtype(*tp_a, *tp_b)).is_ok() {
359                             continue;
360                         }
361                         match
362                             self.unpack_actual_value(
363                                 *tp_a,
364                                 |tp| self.unsize_ty(*tp_a, tp, *tp_b))
365                         {
366                             Some((new_tp, k)) => {
367                                 // Check that the whole types match.
368                                 let mut new_substs = substs_a.clone();
369                                 new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
370                                 let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs));
371                                 if self.fcx.infcx().try(|_| self.subtype(ty, ty_b)).is_err() {
372                                     debug!("Unsized type parameter '{}', but still \
373                                             could not match types {} and {}",
374                                            ppaux::ty_to_string(tcx, *tp_a),
375                                            ppaux::ty_to_string(tcx, ty),
376                                            ppaux::ty_to_string(tcx, ty_b));
377                                     // We can only unsize a single type parameter, so
378                                     // if we unsize one and it doesn't give us the
379                                     // type we want, then we won't succeed later.
380                                     break;
381                                 }
382
383                                 result = Some((ty, ty::UnsizeStruct(box k, i)));
384                                 break;
385                             }
386                             None => {}
387                         }
388                     }
389                     result
390                 }
391                 _ => None
392             }
393         )
394     }
395
396     fn coerce_from_fn_item(&self,
397                            a: Ty<'tcx>,
398                            fn_def_id_a: ast::DefId,
399                            fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
400                            b: Ty<'tcx>)
401                            -> CoerceResult<'tcx> {
402         /*!
403          * Attempts to coerce from the type of a Rust function item
404          * into a closure or a `proc`.
405          */
406
407         self.unpack_actual_value(b, |b| {
408             debug!("coerce_from_fn_item(a={}, b={})",
409                    a.repr(self.tcx()), b.repr(self.tcx()));
410
411             match b.sty {
412                 ty::ty_bare_fn(None, _) => {
413                     let a_fn_pointer = ty::mk_bare_fn(self.tcx(), None, fn_ty_a);
414                     try!(self.subtype(a_fn_pointer, b));
415                     Ok(Some(ty::AdjustReifyFnPointer(fn_def_id_a)))
416                 }
417                 _ => {
418                     return self.subtype(a, b)
419                 }
420             }
421         })
422     }
423
424     fn coerce_unsafe_ptr(&self,
425                          a: Ty<'tcx>,
426                          b: Ty<'tcx>,
427                          mutbl_b: ast::Mutability)
428                          -> CoerceResult<'tcx> {
429         debug!("coerce_unsafe_ptr(a={}, b={})",
430                a.repr(self.tcx()),
431                b.repr(self.tcx()));
432
433         let mt_a = match a.sty {
434             ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => mt,
435             _ => {
436                 return self.subtype(a, b);
437             }
438         };
439
440         // Check that the types which they point at are compatible.
441         let a_unsafe = ty::mk_ptr(self.tcx(), ty::mt{ mutbl: mutbl_b, ty: mt_a.ty });
442         try!(self.subtype(a_unsafe, b));
443         if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) {
444             return Err(ty::terr_mutability);
445         }
446
447         // Although references and unsafe ptrs have the same
448         // representation, we still register an AutoDerefRef so that
449         // regionck knows that the region for `a` must be valid here.
450         Ok(Some(AdjustDerefRef(AutoDerefRef {
451             autoderefs: 1,
452             autoref: Some(ty::AutoUnsafe(mutbl_b, None))
453         })))
454     }
455 }
456
457 pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
458                              expr: &ast::Expr,
459                              a: Ty<'tcx>,
460                              b: Ty<'tcx>)
461                              -> cres<'tcx, ()> {
462     debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx()));
463     let adjustment = try!(indent(|| {
464         fcx.infcx().commit_if_ok(|| {
465             let origin = infer::ExprAssignable(expr.span);
466             Coerce {
467                 fcx: fcx,
468                 trace: infer::TypeTrace::types(origin, false, a, b)
469             }.coerce(expr, a, b)
470         })
471     }));
472     if let Some(adjustment) = adjustment {
473         fcx.write_adjustment(expr.id, expr.span, adjustment);
474     }
475     Ok(())
476 }
477
478 fn can_coerce_mutbls(from_mutbl: ast::Mutability,
479                      to_mutbl: ast::Mutability)
480                      -> bool {
481     match (from_mutbl, to_mutbl) {
482         (ast::MutMutable, ast::MutMutable) => true,
483         (ast::MutImmutable, ast::MutImmutable) => true,
484         (ast::MutMutable, ast::MutImmutable) => true,
485         (ast::MutImmutable, ast::MutMutable) => false,
486     }
487 }