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, depth: int) {
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, s: Span, nid: ast::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, fid: ast::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_id: ast::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:- 7librustc/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:- 2974: 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:- 297: 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:- 4librustc/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:- 426: 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:- 4109: 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:- 2113: 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,