]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/freevars.rs
rustc: move type definitions from middle::freevars to middle::ty.
[rust.git] / src / librustc / middle / freevars.rs
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::def;
17 use middle::resolve;
18 use middle::ty;
19 use util::nodemap::{NodeMap, NodeSet};
20
21 use syntax::ast;
22 use syntax::codemap::Span;
23 use syntax::visit::Visitor;
24 use syntax::visit;
25
26 struct CollectFreevarsVisitor<'a, 'b:'a> {
27     node_id: ast::NodeId,
28     seen: NodeSet,
29     cx: &'a mut AnnotateFreevarsVisitor<'b>,
30     depth: u32
31 }
32
33 impl<'a, 'b, 'v> Visitor<'v> for CollectFreevarsVisitor<'a, 'b> {
34     fn visit_item(&mut self, _: &ast::Item) {
35         // ignore_item
36     }
37
38     fn visit_expr(&mut self, expr: &ast::Expr) {
39         match expr.node {
40             ast::ExprProc(..) => {
41                 self.cx.capture_mode_map.insert(expr.id, ast::CaptureByValue);
42                 self.depth += 1;
43                 visit::walk_expr(self, expr);
44                 self.depth -= 1;
45             }
46             ast::ExprFnBlock(_, _, _) => {
47                 // NOTE(stage0): After snapshot, change to:
48                 //
49                 //self.cx.capture_mode_map.insert(expr.id, capture_clause);
50                 self.cx.capture_mode_map.insert(expr.id, ast::CaptureByRef);
51                 self.depth += 1;
52                 visit::walk_expr(self, expr);
53                 self.depth -= 1;
54             }
55             ast::ExprUnboxedFn(capture_clause, _, _, _) => {
56                 self.cx.capture_mode_map.insert(expr.id, capture_clause);
57                 self.depth += 1;
58                 visit::walk_expr(self, expr);
59                 self.depth -= 1;
60             }
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) {
66                     return;
67                 }
68                 let def = match def {
69                     def::DefUpvar(_, _, depth, _, _) => {
70                         if depth < self.depth {
71                             return;
72                         }
73                         let mut def = def;
74                         for _ in range(0, depth - self.depth) {
75                             match def {
76                                 def::DefUpvar(_, inner, _, _, _) => { def = *inner; }
77                                 _ => unreachable!()
78                             }
79                         }
80                         def
81                     },
82                     _ => return
83                 };
84                 self.cx.freevars.find_or_insert(self.node_id, vec![]).push(ty::Freevar {
85                     def: def,
86                     span: expr.span,
87                 });
88                 self.seen.insert(dnum);
89             }
90             _ => visit::walk_expr(self, expr)
91         }
92     }
93 }
94
95 struct AnnotateFreevarsVisitor<'a> {
96     def_map: &'a resolve::DefMap,
97     freevars: ty::FreevarMap,
98     capture_mode_map: ty::CaptureModeMap,
99 }
100
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 {
105             node_id: nid,
106             seen: NodeSet::new(),
107             cx: self,
108             depth: 0
109         }.visit_block(blk);
110         visit::walk_fn(self, fk, fd, blk, s);
111     }
112 }
113
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 {
122         def_map: def_map,
123         freevars: NodeMap::new(),
124         capture_mode_map: NodeMap::new(),
125     };
126     visit::walk_crate(&mut visitor, krate);
127     (visitor.freevars, visitor.capture_mode_map)
128 }