(index<- )        ./librustc/middle/typeck/infer/coercion.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   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, aty::t, bty::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, aty::t, bty::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, aty::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                                     aty::t,
 222                                     sty_a&ty::sty,
 223                                     bty::t,
 224                                     mt_bty::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                                    aty::t,
 260                                    sty_a&ty::sty,
 261                                    bty::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                                    aty::t,
 289                                    sty_a&ty::sty,
 290                                    bty::t,
 291                                    mutbl_bast::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                                aty::t,
 325                                sty_a&ty::sty,
 326                                bty::t,
 327                                b_mutblast::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                                aty::t,
 361                                sty_a&ty::sty,
 362                                bty::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, aty::t, fn_ty_a&ty::BareFnTy, bty::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                               aty::t,
 413                               sty_a&ty::sty,
 414                               bty::t,
 415                               mt_bty::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                           aty::t,
 443                           sty_a&ty::sty,
 444                           bty::t,
 445                           trait_def_idast::DefId,
 446                           trait_substs&ty::substs,
 447                           trait_storety::TraitStore,
 448                           boundsty::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  }