(index<- )        ./librustc/middle/typeck/check/writeback.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  // Type resolution: the phase that finds all the types in the AST with
  12  // unresolved type variables and replaces "ty_var" types with their
  13  // substitutions.
  14  
  15  
  16  use middle::pat_util;
  17  use middle::ty;
  18  use middle::ty_fold::TypeFolder;
  19  use middle::typeck::astconv::AstConv;
  20  use middle::typeck::check::FnCtxt;
  21  use middle::typeck::infer::{force_all, resolve_all, resolve_region};
  22  use middle::typeck::infer::resolve_type;
  23  use middle::typeck::infer;
  24  use middle::typeck::{MethodCall, MethodCallee};
  25  use middle::typeck::{vtable_origin, vtable_static, vtable_param};
  26  use middle::typeck::write_substs_to_tcx;
  27  use middle::typeck::write_ty_to_tcx;
  28  use util::ppaux::Repr;
  29  
  30  use syntax::ast;
  31  use syntax::codemap::Span;
  32  use syntax::print::pprust::pat_to_str;
  33  use syntax::visit;
  34  use syntax::visit::Visitor;
  35  
  36  ///////////////////////////////////////////////////////////////////////////
  37  // Entry point functions
  38  
  39  pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) {
  40      assert_eq!(fcx.writeback_errors.get(), false);
  41      let mut wbcx = WritebackCx::new(fcx);
  42      wbcx.visit_expr(e, ());
  43      wbcx.visit_upvar_borrow_map();
  44  }
  45  
  46  pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
  47                                 decl: &ast::FnDecl,
  48                                 blk: &ast::Block) {
  49      assert_eq!(fcx.writeback_errors.get(), false);
  50      let mut wbcx = WritebackCx::new(fcx);
  51      wbcx.visit_block(blk, ());
  52      for arg in decl.inputs.iter() {
  53          wbcx.visit_pat(arg.pat, ());
  54  
  55          // Privacy needs the type for the whole pattern, not just each binding
  56          if !pat_util::pat_is_binding(&fcx.tcx().def_map, arg.pat) {
  57              wbcx.visit_node_id(ResolvingPattern(arg.pat.span),
  58                                 arg.pat.id);
  59          }
  60      }
  61      wbcx.visit_upvar_borrow_map();
  62  }
  63  
  64  ///////////////////////////////////////////////////////////////////////////
  65  // The Writerback context. This visitor walks the AST, checking the
  66  // fn-specific tables to find references to types or regions. It
  67  // resolves those regions to remove inference variables and writes the
  68  // final result back into the master tables in the tcx. Here and
  69  // there, it applies a few ad-hoc checks that were not convenient to
  70  // do elsewhere.
  71  
  72  struct WritebackCx<'cx> {
  73      fcx: &'cx FnCtxt<'cx>,
  74  }
  75  
  76  impl<'cx> WritebackCx<'cx> {
  77      fn new(fcx&'cx FnCtxt) -> WritebackCx<'cx> {
  78          WritebackCx { fcx: fcx }
  79      }
  80  
  81      fn tcx(&self) -> &'cx ty::ctxt {
  82          self.fcx.tcx()
  83      }
  84  }
  85  
  86  ///////////////////////////////////////////////////////////////////////////
  87  // Impl of Visitor for Resolver
  88  //
  89  // This is the master code which walks the AST. It delegates most of
  90  // the heavy lifting to the generic visit and resolve functions
  91  // below. In general, a function is made into a `visitor` if it must
  92  // traffic in node-ids or update tables in the type context etc.
  93  
  94  impl<'cx> Visitor<()> for WritebackCx<'cx> {
  95      fn visit_item(&mut self, _&ast::Item, _()) {
  96          // Ignore items
  97      }
  98  
  99      fn visit_stmt(&mut self, s&ast::Stmt, _()) {
 100          if self.fcx.writeback_errors.get() {
 101              return;
 102          }
 103  
 104          self.visit_node_id(ResolvingExpr(s.span), ty::stmt_node_id(s));
 105          visit::walk_stmt(self, s, ());
 106      }
 107  
 108      fn visit_expr(&mut self, e:&ast::Expr, _()) {
 109          if self.fcx.writeback_errors.get() {
 110              return;
 111          }
 112  
 113          self.visit_node_id(ResolvingExpr(e.span), e.id);
 114          self.visit_method_map_entry(ResolvingExpr(e.span),
 115                                      MethodCall::expr(e.id));
 116          self.visit_vtable_map_entry(ResolvingExpr(e.span),
 117                                      MethodCall::expr(e.id));
 118  
 119          match e.node {
 120              ast::ExprFnBlock(ref decl, _) | ast::ExprProc(ref decl, _) => {
 121                  for input in decl.inputs.iter() {
 122                      let _ = self.visit_node_id(ResolvingExpr(e.span),
 123                                                 input.id);
 124                  }
 125              }
 126              _ => {}
 127          }
 128  
 129          visit::walk_expr(self, e, ());
 130      }
 131  
 132      fn visit_block(&mut self, b&ast::Block, _()) {
 133          if self.fcx.writeback_errors.get() {
 134              return;
 135          }
 136  
 137          self.visit_node_id(ResolvingExpr(b.span), b.id);
 138          visit::walk_block(self, b, ());
 139      }
 140  
 141      fn visit_pat(&mut self, p&ast::Pat, _()) {
 142          if self.fcx.writeback_errors.get() {
 143              return;
 144          }
 145  
 146          self.visit_node_id(ResolvingPattern(p.span), p.id);
 147  
 148          debug!("Type for pattern binding {} (id {}) resolved to {}",
 149                 pat_to_str(p),
 150                 p.id,
 151                 ty::node_id_to_type(self.tcx(), p.id).repr(self.tcx()));
 152  
 153          visit::walk_pat(self, p, ());
 154      }
 155  
 156      fn visit_local(&mut self, l&ast::Local, _()) {
 157          if self.fcx.writeback_errors.get() {
 158              return;
 159          }
 160  
 161          let var_ty = self.fcx.local_ty(l.span, l.id);
 162          let var_ty = var_ty.resolve(self.fcx, ResolvingLocal(l.span));
 163          write_ty_to_tcx(self.tcx(), l.id, var_ty);
 164          visit::walk_local(self, l, ());
 165      }
 166  
 167      fn visit_ty(&mut self, _t&ast::Ty, _()) {
 168          // ignore
 169      }
 170  }
 171  
 172  impl<'cx> WritebackCx<'cx> {
 173      fn visit_upvar_borrow_map(&self) {
 174          if self.fcx.writeback_errors.get() {
 175              return;
 176          }
 177  
 178          for (upvar_id, upvar_borrow) in self.fcx.inh.upvar_borrow_map.borrow().iter() {
 179              let r = upvar_borrow.region;
 180              let r = r.resolve(self.fcx, ResolvingUpvar(*upvar_id));
 181              let new_upvar_borrow = ty::UpvarBorrow { kind: upvar_borrow.kind,
 182                                                       region: r };
 183              debug!("Upvar borrow for {} resolved to {}",
 184                     upvar_id.repr(self.tcx()),
 185                     new_upvar_borrow.repr(self.tcx()));
 186              self.fcx.tcx().upvar_borrow_map.borrow_mut().insert(
 187                  *upvar_id, new_upvar_borrow);
 188          }
 189      }
 190  
 191      fn visit_node_id(&self, reasonResolveReason, idast::NodeId) {
 192          // Resolve any borrowings for the node with id `id`
 193          self.visit_adjustments(reason, id);
 194  
 195          // Resolve the type of the node with id `id`
 196          let n_ty = self.fcx.node_ty(id);
 197          let n_ty = n_ty.resolve(self.fcx, reason);
 198          write_ty_to_tcx(self.tcx(), id, n_ty);
 199          debug!("Node {} has type {}", id, n_ty.repr(self.tcx()));
 200  
 201          // Resolve any substitutions
 202          self.fcx.opt_node_ty_substs(id, |node_substs| {
 203              let mut new_tps = Vec::new();
 204              for subst in node_substs.tps.iter() {
 205                  new_tps.push(subst.resolve(self.fcx, reason));
 206              }
 207              write_substs_to_tcx(self.tcx(), id, new_tps);
 208          });
 209      }
 210  
 211      fn visit_adjustments(&self, reasonResolveReason, idast::NodeId) {
 212          match self.fcx.inh.adjustments.borrow_mut().pop(&id) {
 213              None => {
 214                  debug!("No adjustments for node {}", id);
 215              }
 216  
 217              Some(adjustment) => {
 218                  let resolved_adjustment = match adjustment {
 219                      ty::AutoAddEnv(store) => {
 220                          // FIXME(eddyb) #2190 Allow only statically resolved
 221                          // bare functions to coerce to a closure to avoid
 222                          // constructing (slower) indirect call wrappers.
 223                          match self.tcx().def_map.borrow().find(&id) {
 224                              Some(&ast::DefFn(..)) |
 225                              Some(&ast::DefStaticMethod(..)) |
 226                              Some(&ast::DefVariant(..)) |
 227                              Some(&ast::DefStruct(_)) => {
 228                              }
 229                              _ => {
 230                                  self.tcx().sess.span_err(
 231                                      reason.span(self.fcx),
 232                                      "cannot coerce non-statically resolved bare fn")
 233                              }
 234                          }
 235  
 236                          ty::AutoAddEnv(store.resolve(self.fcx, reason))
 237                      }
 238  
 239                      ty::AutoDerefRef(adj) => {
 240                          for autoderef in range(0, adj.autoderefs) {
 241                              let method_call = MethodCall::autoderef(id, autoderef as u32);
 242                              self.visit_method_map_entry(reason, method_call);
 243                              self.visit_vtable_map_entry(reason, method_call);
 244                          }
 245  
 246                          ty::AutoDerefRef(ty::AutoDerefRef {
 247                              autoderefs: adj.autoderefs,
 248                              autoref: adj.autoref.resolve(self.fcx, reason),
 249                          })
 250                      }
 251  
 252                      adjustment => adjustment
 253                  };
 254                  debug!("Adjustments for node {}{:?}", id, resolved_adjustment);
 255                  self.tcx().adjustments.borrow_mut().insert(
 256                      id, resolved_adjustment);
 257              }
 258          }
 259      }
 260  
 261      fn visit_method_map_entry(&self,
 262                                reasonResolveReason,
 263                                method_callMethodCall) {
 264          // Resolve any method map entry
 265          match self.fcx.inh.method_map.borrow_mut().pop(&method_call) {
 266              Some(method) => {
 267                  debug!("writeback::resolve_method_map_entry(call={:?}, entry={})",
 268                         method_call,
 269                         method.repr(self.tcx()));
 270                  let mut new_method = MethodCallee {
 271                      origin: method.origin,
 272                      ty: method.ty.resolve(self.fcx, reason),
 273                      substs: method.substs.resolve(self.fcx, reason),
 274                  };
 275  
 276                  // Wack. For some reason I don't quite know, we always
 277                  // hard-code the self-ty and regions to these
 278                  // values. Changing this causes downstream errors I
 279                  // don't feel like investigating right now (in
 280                  // particular, self_ty is set to mk_err in some cases,
 281                  // probably for invocations on objects, and this
 282                  // causes encoding failures). -nmatsakis
 283                  new_method.substs.self_ty = None;
 284                  new_method.substs.regions = ty::ErasedRegions;
 285  
 286                  self.tcx().method_map.borrow_mut().insert(
 287                      method_call,
 288                      new_method);
 289              }
 290              None => {}
 291          }
 292      }
 293  
 294      fn visit_vtable_map_entry(&self,
 295                                reasonResolveReason,
 296                                vtable_keyMethodCall) {
 297          // Resolve any vtable map entry
 298          match self.fcx.inh.vtable_map.borrow_mut().pop(&vtable_key) {
 299              Some(origins) => {
 300                  let r_origins = origins.resolve(self.fcx, reason);
 301                  debug!("writeback::resolve_vtable_map_entry(\
 302                          vtable_key={}, vtables={:?})",
 303                         vtable_key, r_origins.repr(self.tcx()));
 304                  self.tcx().vtable_map.borrow_mut().insert(vtable_key, r_origins);
 305              }
 306              None => {}
 307          }
 308      }
 309  }
 310  
 311  ///////////////////////////////////////////////////////////////////////////
 312  // Resolution reason.
 313  
 314  enum ResolveReason {
 315      ResolvingExpr(Span),
 316      ResolvingLocal(Span),
 317      ResolvingPattern(Span),
 318      ResolvingUpvar(ty::UpvarId)
 319  }
 320  
 321  impl ResolveReason {
 322      fn span(&self, fcx&FnCtxt) -> Span {
 323          match *self {
 324              ResolvingExpr(s) => s,
 325              ResolvingLocal(s) => s,
 326              ResolvingPattern(s) => s,
 327              ResolvingUpvar(upvar_id) => {
 328                  ty::expr_span(fcx.tcx(), upvar_id.closure_expr_id)
 329              }
 330          }
 331      }
 332  }
 333  
 334  ///////////////////////////////////////////////////////////////////////////
 335  // Convenience methods for resolving different kinds of things.
 336  
 337  trait Resolve {
 338      fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> Self;
 339  }
 340  
 341  impl<T:Resolve> Resolve for Option<T> {
 342      fn resolve(&self, fcx&FnCtxt, reasonResolveReason) -> Option<T> {
 343          self.as_ref().map(|t| t.resolve(fcx, reason))
 344      }
 345  }
 346  
 347  impl<T:Resolve> Resolve for Vec<T> {
 348      fn resolve(&self, fcx&FnCtxt, reasonResolveReason) -> Vec<T> {
 349          self.iter().map(|t| t.resolve(fcx, reason)).collect()
 350      }
 351  }
 352  
 353  impl Resolve for ty::TraitStore {
 354      fn resolve(&self, fcx&FnCtxt, reasonResolveReason) -> ty::TraitStore {
 355          Resolver::new(fcx, reason).fold_trait_store(*self)
 356      }
 357  }
 358  
 359  impl Resolve for ty::t {
 360      fn resolve(&self, fcx&FnCtxt, reasonResolveReason) -> ty::t {
 361          Resolver::new(fcx, reason).fold_ty(*self)
 362      }
 363  }
 364  
 365  impl Resolve for ty::Region {
 366      fn resolve(&self, fcx&FnCtxt, reasonResolveReason) -> ty::Region {
 367          Resolver::new(fcx, reason).fold_region(*self)
 368      }
 369  }
 370  
 371  impl Resolve for ty::substs {
 372      fn resolve(&self, fcx&FnCtxt, reasonResolveReason) -> ty::substs {
 373          Resolver::new(fcx, reason).fold_substs(self)
 374      }
 375  }
 376  
 377  impl Resolve for ty::AutoRef {
 378      fn resolve(&self, fcx&FnCtxt, reasonResolveReason) -> ty::AutoRef {
 379          Resolver::new(fcx, reason).fold_autoref(self)
 380      }
 381  }
 382  
 383  impl Resolve for vtable_origin {
 384      fn resolve(&self, fcx&FnCtxt, reasonResolveReason) -> vtable_origin {
 385          match *self {
 386              vtable_static(def_id, ref tys, ref origins) => {
 387                  let r_tys = tys.resolve(fcx, reason);
 388                  let r_origins = origins.resolve(fcx, reason);
 389                  vtable_static(def_id, r_tys, r_origins)
 390              }
 391              vtable_param(n, b) => {
 392                  vtable_param(n, b)
 393              }
 394          }
 395      }
 396  }
 397  
 398  ///////////////////////////////////////////////////////////////////////////
 399  // The Resolver. This is the type folding engine that detects
 400  // unresolved types and so forth.
 401  
 402  struct Resolver<'cx> {
 403      fcx: &'cx FnCtxt<'cx>,
 404      reason: ResolveReason,
 405  }
 406  
 407  impl<'cx> Resolver<'cx> {
 408      fn new(fcx&'cx FnCtxt<'cx>,
 409             reasonResolveReason)
 410             -> Resolver<'cx>
 411      {
 412          Resolver { fcx: fcx, reason: reason }
 413      }
 414  
 415      fn report_error(&self, einfer::fixup_err) {
 416          self.fcx.writeback_errors.set(true);
 417          if !self.tcx().sess.has_errors() {
 418              match self.reason {
 419                  ResolvingExpr(span) => {
 420                      self.tcx().sess.span_err(
 421                          span,
 422                          format!("cannot determine a type for \
 423                                   this expression: {}",
 424                                  infer::fixup_err_to_str(e)))
 425                  }
 426  
 427                  ResolvingLocal(span) => {
 428                      self.tcx().sess.span_err(
 429                          span,
 430                          format!("cannot determine a type for \
 431                                   this local variable: {}",
 432                                  infer::fixup_err_to_str(e)))
 433                  }
 434  
 435                  ResolvingPattern(span) => {
 436                      self.tcx().sess.span_err(
 437                          span,
 438                          format!("cannot determine a type for \
 439                                   this pattern binding: {}",
 440                                  infer::fixup_err_to_str(e)))
 441                  }
 442  
 443                  ResolvingUpvar(upvar_id) => {
 444                      let span = self.reason.span(self.fcx);
 445                      self.tcx().sess.span_err(
 446                          span,
 447                          format!("cannot resolve lifetime for \
 448                                   captured variable `{}`: {}",
 449                                  ty::local_var_name_str(
 450                                      self.tcx(),
 451                                      upvar_id.var_id).get().to_str(),
 452                                  infer::fixup_err_to_str(e)));
 453                  }
 454              }
 455          }
 456      }
 457  }
 458  
 459  impl<'cx> TypeFolder for Resolver<'cx> {
 460      fn tcx<'a>(&'a self) -> &'a ty::ctxt {
 461          self.fcx.tcx()
 462      }
 463  
 464      fn fold_ty(&mut self, tty::t) -> ty::t {
 465          if !ty::type_needs_infer(t) {
 466              return t;
 467          }
 468  
 469          match resolve_type(self.fcx.infcx(), t, resolve_all | force_all) {
 470              Ok(t) => t,
 471              Err(e) => {
 472                  self.report_error(e);
 473                  ty::mk_err()
 474              }
 475          }
 476      }
 477  
 478      fn fold_region(&mut self, rty::Region) -> ty::Region {
 479          match resolve_region(self.fcx.infcx(), r, resolve_all | force_all) {
 480              Ok(r) => r,
 481              Err(e) => {
 482                  self.report_error(e);
 483                  ty::ReStatic
 484              }
 485          }
 486      }
 487  }


librustc/middle/typeck/check/writeback.rs:71:1-71:1 -struct- definition:
struct WritebackCx<'cx> {
    fcx: &'cx FnCtxt<'cx>,
}
references:- 5
77:     fn new(fcx: &'cx FnCtxt) -> WritebackCx<'cx> {
78:         WritebackCx { fcx: fcx }
79:     }
--
172: impl<'cx> WritebackCx<'cx> {
173:     fn visit_upvar_borrow_map(&self) {


librustc/middle/typeck/check/writeback.rs:313:1-313:1 -enum- definition:
enum ResolveReason {
    ResolvingExpr(Span),
    ResolvingLocal(Span),
references:- 16
359: impl Resolve for ty::t {
360:     fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::t {
361:         Resolver::new(fcx, reason).fold_ty(*self)
--
408:     fn new(fcx: &'cx FnCtxt<'cx>,
409:            reason: ResolveReason)
410:            -> Resolver<'cx>


librustc/middle/typeck/check/writeback.rs:336:1-336:1 -trait- definition:
trait Resolve {
    fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> Self;
}
references:- 11
359: impl Resolve for ty::t {
360:     fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::t {
--
365: impl Resolve for ty::Region {
366:     fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::Region {
--
383: impl Resolve for vtable_origin {
384:     fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> vtable_origin {


librustc/middle/typeck/check/writeback.rs:401:1-401:1 -struct- definition:
struct Resolver<'cx> {
    fcx: &'cx FnCtxt<'cx>,
    reason: ResolveReason,
references:- 4
411:     {
412:         Resolver { fcx: fcx, reason: reason }
413:     }
--
459: impl<'cx> TypeFolder for Resolver<'cx> {
460:     fn tcx<'a>(&'a self) -> &'a ty::ctxt {