(index<- )        ./librustc/middle/freevars.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-2014 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  // A pass that annotates for each loops and functions with the free
  12  // variables that they contain.
  13  
  14  #![allow(non_camel_case_types)]
  15  
  16  use middle::resolve;
  17  use middle::ty;
  18  use util::nodemap::{NodeMap, NodeSet};
  19  
  20  use syntax::codemap::Span;
  21  use syntax::{ast, ast_util};
  22  use syntax::visit;
  23  use syntax::visit::Visitor;
  24  
  25  #[deriving(Show)]
  26  pub enum CaptureMode {
  27      /// Copy/move the value from this llvm ValueRef into the environment.
  28      CaptureByValue,
  29  
  30      /// Access by reference (used for stack closures).
  31      CaptureByRef
  32  }
  33  
  34  // A vector of defs representing the free variables referred to in a function.
  35  // (The def_upvar will already have been stripped).
  36  #[deriving(Encodable, Decodable)]
  37  pub struct freevar_entry {
  38      pub def: ast::Def, //< The variable being accessed free.
  39      pub span: Span     //< First span where it is accessed (there can be multiple)
  40  }
  41  pub type freevar_map = NodeMap<Vec<freevar_entry>>;
  42  
  43  struct CollectFreevarsVisitor<'a> {
  44      seen: NodeSet,
  45      refs: Vec<freevar_entry>,
  46      def_map: &'a resolve::DefMap,
  47  }
  48  
  49  impl<'a> Visitor<int> for CollectFreevarsVisitor<'a> {
  50      fn visit_item(&mut self, _&ast::Item, _int) {
  51          // ignore_item
  52      }
  53  
  54      fn visit_expr(&mut self, expr&ast::Expr, depthint) {
  55          match expr.node {
  56              ast::ExprFnBlock(..) | ast::ExprProc(..) => {
  57                  visit::walk_expr(self, expr, depth + 1)
  58              }
  59              ast::ExprPath(..) => {
  60                  let mut i = 0;
  61                  match self.def_map.borrow().find(&expr.id) {
  62                      None => fail!("path not found"),
  63                      Some(&df) => {
  64                          let mut def = df;
  65                          while i < depth {
  66                              match def {
  67                                  ast::DefUpvar(_, inner, _, _) => { def = *inner; }
  68                                  _ => break
  69                              }
  70                              i += 1;
  71                          }
  72                          if i == depth { // Made it to end of loop
  73                              let dnum = ast_util::def_id_of_def(def).node;
  74                              if !self.seen.contains(&dnum) {
  75                                  self.refs.push(freevar_entry {
  76                                      def: def,
  77                                      span: expr.span,
  78                                  });
  79                                  self.seen.insert(dnum);
  80                              }
  81                          }
  82                      }
  83                  }
  84              }
  85              _ => visit::walk_expr(self, expr, depth)
  86          }
  87      }
  88  
  89  
  90  }
  91  
  92  // Searches through part of the AST for all references to locals or
  93  // upvars in this frame and returns the list of definition IDs thus found.
  94  // Since we want to be able to collect upvars in some arbitrary piece
  95  // of the AST, we take a walker function that we invoke with a visitor
  96  // in order to start the search.
  97  fn collect_freevars(def_map: &resolve::DefMap, blk: &ast::Block) -> Vec<freevar_entry> {
  98      let mut v = CollectFreevarsVisitor {
  99          seen: NodeSet::new(),
 100          refs: Vec::new(),
 101          def_map: def_map,
 102      };
 103  
 104      v.visit_block(blk, 1);
 105      v.refs
 106  }
 107  
 108  struct AnnotateFreevarsVisitor<'a> {
 109      def_map: &'a resolve::DefMap,
 110      freevars: freevar_map,
 111  }
 112  
 113  impl<'a> Visitor<()> for AnnotateFreevarsVisitor<'a> {
 114      fn visit_fn(&mut self, fk&visit::FnKind, fd&ast::FnDecl,
 115                  blk&ast::Block, sSpan, nidast::NodeId, _()) {
 116          let vars = collect_freevars(self.def_map, blk);
 117          self.freevars.insert(nid, vars);
 118          visit::walk_fn(self, fk, fd, blk, s, nid, ());
 119      }
 120  }
 121  
 122  // Build a map from every function and for-each body to a set of the
 123  // freevars contained in it. The implementation is not particularly
 124  // efficient as it fully recomputes the free variables at every
 125  // node of interest rather than building up the free variables in
 126  // one pass. This could be improved upon if it turns out to matter.
 127  pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate) ->
 128     freevar_map {
 129      let mut visitor = AnnotateFreevarsVisitor {
 130          def_map: def_map,
 131          freevars: NodeMap::new(),
 132      };
 133      visit::walk_crate(&mut visitor, krate, ());
 134  
 135      visitor.freevars
 136  }
 137  
 138  pub fn with_freevars<T>(tcx: &ty::ctxt, fidast::NodeId, f: |&[freevar_entry]-> T) -> T {
 139      match tcx.freevars.borrow().find(&fid) {
 140          None => fail!("with_freevars: {} has no freevars", fid),
 141          Some(d) => f(d.as_slice())
 142      }
 143  }
 144  
 145  pub fn get_capture_mode(tcx: &ty::ctxt,
 146                          closure_expr_idast::NodeId)
 147                          -> CaptureMode
 148  {
 149      let fn_ty = ty::node_id_to_type(tcx, closure_expr_id);
 150      match ty::ty_closure_store(fn_ty) {
 151          ty::RegionTraitStore(..) => CaptureByRef,
 152          ty::UniqTraitStore => CaptureByValue
 153      }
 154  }


librustc/middle/freevars.rs:137:1-137:1 -fn- definition:
pub fn with_freevars<T>(tcx: &ty::ctxt, fid: ast::NodeId, f: |&[freevar_entry]| -> T) -> T {
    match tcx.freevars.borrow().find(&fid) {
        None => fail!("with_freevars: {} has no freevars", fid),
references:- 7
librustc/middle/expr_use_visitor.rs:
794:         let tcx = self.typer.tcx();
795:         freevars::with_freevars(tcx, closure_expr.id, |freevars| {
796:             match freevars::get_capture_mode(self.tcx(), closure_expr.id) {
librustc/middle/trans/closure.rs:
363:     let freevars: Vec<freevars::freevar_entry> =
364:         freevars::with_freevars(
365:             tcx, id,
librustc/middle/typeck/check/regionck.rs:
641:             }) => {
642:             freevars::with_freevars(tcx, expr.id, |freevars| {
643:                 propagate_upupvar_borrow_kind(rcx, expr, freevars);
librustc/middle/borrowck/check_loans.rs:
719:         let freevar_mode = freevars::get_capture_mode(self.tcx(), closure_id);
720:         freevars::with_freevars(self.tcx(), closure_id, |freevars| {
721:             for freevar in freevars.iter() {
librustc/middle/liveness.rs:
476:         let fv_mode = freevars::get_capture_mode(ir.tcx, expr.id);
477:         freevars::with_freevars(ir.tcx, expr.id, |freevars| {
478:             for fv in freevars.iter() {
librustc/middle/kind.rs:
230:     with_appropriate_checker(cx, fn_id, |chk| {
231:         freevars::with_freevars(cx.tcx, fn_id, |freevars| {
232:             for fv in freevars.iter() {
librustc/middle/typeck/check/regionck.rs:
613:                 store: ty::RegionTraitStore(region, _), ..}) => {
614:             freevars::with_freevars(tcx, expr.id, |freevars| {
615:                 if freevars.is_empty() {


librustc/middle/freevars.rs:36:34-36:34 -struct- definition:
pub struct freevar_entry {
    pub def: ast::Def, //< The variable being accessed free.
    pub span: Span     //< First span where it is accessed (there can be multiple)
references:- 29
74:                             if !self.seen.contains(&dnum) {
75:                                 self.refs.push(freevar_entry {
76:                                     def: def,
librustc/middle/astencode.rs:
535:     fn tr(&self, xcx: &ExtendedDecodeContext) -> freevar_entry {
536:         freevar_entry {
537:             def: self.def.tr(xcx),
librustc/middle/freevars.rs:
40: }
41: pub type freevar_map = NodeMap<Vec<freevar_entry>>;
--
44:     seen: NodeSet,
45:     refs: Vec<freevar_entry>,
46:     def_map: &'a resolve::DefMap,
--
96: // in order to start the search.
97: fn collect_freevars(def_map: &resolve::DefMap, blk: &ast::Block) -> Vec<freevar_entry> {
98:     let mut v = CollectFreevarsVisitor {
--
138: pub fn with_freevars<T>(tcx: &ty::ctxt, fid: ast::NodeId, f: |&[freevar_entry]| -> T) -> T {
139:     match tcx.freevars.borrow().find(&fid) {
librustc/middle/astencode.rs:
522:     fn read_freevar_entry(&mut self, xcx: &ExtendedDecodeContext)
523:                           -> freevar_entry;
524: }
--
527:     fn read_freevar_entry(&mut self, xcx: &ExtendedDecodeContext)
528:                           -> freevar_entry {
529:         let fv: freevar_entry = Decodable::decode(self).unwrap();
--
534: impl tr for freevar_entry {
535:     fn tr(&self, xcx: &ExtendedDecodeContext) -> freevar_entry {
536:         freevar_entry {
librustc/middle/expr_use_visitor.rs:
808:                             closure_expr: &ast::Expr,
809:                             freevars: &[freevars::freevar_entry]) {
810:         for freevar in freevars.iter() {
--
833:                               closure_expr: &ast::Expr,
834:                               freevars: &[freevars::freevar_entry]) {
835:         for freevar in freevars.iter() {
librustc/middle/trans/closure.rs:
229:                      freevar_mode: freevars::CaptureMode,
230:                      freevars: &Vec<freevars::freevar_entry>,
231:                      store: ty::TraitStore)
--
253:                         cdata_ty: ty::t,
254:                         freevars: &Vec<freevars::freevar_entry>,
255:                         store: ty::TraitStore)
--
362:     let freevar_mode = freevars::get_capture_mode(tcx, id);
363:     let freevars: Vec<freevars::freevar_entry> =
364:         freevars::with_freevars(
librustc/middle/typeck/check/regionck.rs:
651:                                 expr: &ast::Expr,
652:                                 freevars: &[freevars::freevar_entry]) {
653:         /*!
librustc/middle/borrowck/check_loans.rs:
737:                                  closure_id: ast::NodeId,
738:                                  freevar: &freevars::freevar_entry,
739:                                  move_path: &LoanPath) {
librustc/middle/kind.rs:
192:     fn check_for_bare(cx: &Context, fv: &freevar_entry) {
193:         cx.tcx.sess.span_err(
librustc/middle/typeck/check/regionck.rs:
697:                                      expr: &ast::Expr,
698:                                      freevars: &[freevars::freevar_entry]) {
699:         let tcx = rcx.fcx.ccx.tcx;


librustc/middle/freevars.rs:42:1-42:1 -struct- definition:
struct CollectFreevarsVisitor<'a> {
    seen: NodeSet,
    refs: Vec<freevar_entry>,
references:- 2
97: fn collect_freevars(def_map: &resolve::DefMap, blk: &ast::Block) -> Vec<freevar_entry> {
98:     let mut v = CollectFreevarsVisitor {
99:         seen: NodeSet::new(),


librustc/middle/freevars.rs:144:1-144:1 -fn- definition:
pub fn get_capture_mode(tcx: &ty::ctxt,
                        closure_expr_id: ast::NodeId)
                        -> CaptureMode
references:- 4
librustc/middle/expr_use_visitor.rs:
795:         freevars::with_freevars(tcx, closure_expr.id, |freevars| {
796:             match freevars::get_capture_mode(self.tcx(), closure_expr.id) {
797:                 freevars::CaptureByRef => {
librustc/middle/trans/closure.rs:
362:     let freevar_mode = freevars::get_capture_mode(tcx, id);
363:     let freevars: Vec<freevars::freevar_entry> =
librustc/middle/borrowck/check_loans.rs:
718:                                 span: Span) {
719:         let freevar_mode = freevars::get_capture_mode(self.tcx(), closure_id);
720:         freevars::with_freevars(self.tcx(), closure_id, |freevars| {
librustc/middle/liveness.rs:
475:         let mut call_caps = Vec::new();
476:         let fv_mode = freevars::get_capture_mode(ir.tcx, expr.id);
477:         freevars::with_freevars(ir.tcx, expr.id, |freevars| {


librustc/middle/freevars.rs:25:18-25:18 -enum- definition:
pub enum CaptureMode {
    /// Copy/move the value from this llvm ValueRef into the environment.
    CaptureByValue,
references:- 4
26: pub enum CaptureMode {
librustc/middle/trans/closure.rs:
101: pub struct EnvValue {
102:     action: freevars::CaptureMode,
103:     datum: Datum<Lvalue>
--
228: fn build_closure<'a>(bcx0: &'a Block<'a>,
229:                      freevar_mode: freevars::CaptureMode,
230:                      freevars: &Vec<freevars::freevar_entry>,
librustc/middle/freevars.rs:
146:                         closure_expr_id: ast::NodeId)
147:                         -> CaptureMode
148: {


librustc/middle/freevars.rs:40:2-40:2 -NK_AS_STR_TODO- definition:
}
pub type freevar_map = NodeMap<Vec<freevar_entry>>;
struct CollectFreevarsVisitor<'a> {
references:- 4
109:     def_map: &'a resolve::DefMap,
110:     freevars: freevar_map,
111: }
librustc/middle/ty.rs:
277:     pub intrinsic_defs: RefCell<DefIdMap<t>>,
278:     pub freevars: RefCell<freevars::freevar_map>,
279:     pub tcache: type_cache,
--
1075:                map: ast_map::Map,
1076:                freevars: freevars::freevar_map,
1077:                region_maps: middle::region::RegionMaps,
librustc/middle/freevars.rs:
127: pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate) ->
128:    freevar_map {
129:     let mut visitor = AnnotateFreevarsVisitor {


librustc/middle/freevars.rs:107:1-107:1 -struct- definition:
struct AnnotateFreevarsVisitor<'a> {
    def_map: &'a resolve::DefMap,
    freevars: freevar_map,
references:- 2
113: impl<'a> Visitor<()> for AnnotateFreevarsVisitor<'a> {
114:     fn visit_fn(&mut self, fk: &visit::FnKind, fd: &ast::FnDecl,
--
128:    freevar_map {
129:     let mut visitor = AnnotateFreevarsVisitor {
130:         def_map: def_map,