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.
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.
11 // A pass that annotates for each loops and functions with the free
12 // variables that they contain.
14 #![allow(non_camel_case_types)]
19 use util::nodemap::{NodeMap, NodeSet};
22 use syntax::codemap::Span;
23 use syntax::visit::Visitor;
26 struct CollectFreevarsVisitor<'a, 'b:'a> {
29 cx: &'a mut AnnotateFreevarsVisitor<'b>,
33 impl<'a, 'b, 'v> Visitor<'v> for CollectFreevarsVisitor<'a, 'b> {
34 fn visit_item(&mut self, _: &ast::Item) {
38 fn visit_expr(&mut self, expr: &ast::Expr) {
40 ast::ExprProc(..) => {
41 self.cx.capture_mode_map.insert(expr.id, ast::CaptureByValue);
43 visit::walk_expr(self, expr);
46 ast::ExprFnBlock(_, _, _) => {
47 // NOTE(stage0): After snapshot, change to:
49 //self.cx.capture_mode_map.insert(expr.id, capture_clause);
50 self.cx.capture_mode_map.insert(expr.id, ast::CaptureByRef);
52 visit::walk_expr(self, expr);
55 ast::ExprUnboxedFn(capture_clause, _, _, _) => {
56 self.cx.capture_mode_map.insert(expr.id, capture_clause);
58 visit::walk_expr(self, expr);
61 ast::ExprPath(..) => {
62 let def = *self.cx.def_map.borrow().find(&expr.id)
63 .expect("path not found");
64 let dnum = def.def_id().node;
65 if self.seen.contains(&dnum) {
69 def::DefUpvar(_, _, depth, _, _) => {
70 if depth < self.depth {
74 for _ in range(0, depth - self.depth) {
76 def::DefUpvar(_, inner, _, _, _) => { def = *inner; }
84 self.cx.freevars.find_or_insert(self.node_id, vec![]).push(ty::Freevar {
88 self.seen.insert(dnum);
90 _ => visit::walk_expr(self, expr)
95 struct AnnotateFreevarsVisitor<'a> {
96 def_map: &'a resolve::DefMap,
97 freevars: ty::FreevarMap,
98 capture_mode_map: ty::CaptureModeMap,
101 impl<'a, 'v> Visitor<'v> for AnnotateFreevarsVisitor<'a> {
102 fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
103 blk: &'v ast::Block, s: Span, nid: ast::NodeId) {
104 CollectFreevarsVisitor {
106 seen: NodeSet::new(),
110 visit::walk_fn(self, fk, fd, blk, s);
114 // Build a map from every function and for-each body to a set of the
115 // freevars contained in it. The implementation is not particularly
116 // efficient as it fully recomputes the free variables at every
117 // node of interest rather than building up the free variables in
118 // one pass. This could be improved upon if it turns out to matter.
119 pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate)
120 -> (ty::FreevarMap, ty::CaptureModeMap) {
121 let mut visitor = AnnotateFreevarsVisitor {
123 freevars: NodeMap::new(),
124 capture_mode_map: NodeMap::new(),
126 visit::walk_crate(&mut visitor, krate);
127 (visitor.freevars, visitor.capture_mode_map)