2014-02-10 08:36:31 -06:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 18:48:01 -06:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2011-07-18 21:14:01 -05:00
|
|
|
// A pass that annotates for each loops and functions with the free
|
|
|
|
// variables that they contain.
|
2011-07-18 19:26:37 -05:00
|
|
|
|
2014-02-10 08:36:31 -06:00
|
|
|
#[allow(non_camel_case_types)];
|
2013-05-17 17:28:44 -05:00
|
|
|
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::resolve;
|
|
|
|
use middle::ty;
|
|
|
|
|
2014-02-19 21:29:58 -06:00
|
|
|
use collections::HashMap;
|
2013-08-31 11:13:04 -05:00
|
|
|
use syntax::codemap::Span;
|
2013-08-13 06:37:54 -05:00
|
|
|
use syntax::{ast, ast_util};
|
|
|
|
use syntax::visit;
|
|
|
|
use syntax::visit::Visitor;
|
2011-07-18 19:26:37 -05:00
|
|
|
|
2011-09-01 07:35:00 -05:00
|
|
|
// A vector of defs representing the free variables referred to in a function.
|
|
|
|
// (The def_upvar will already have been stripped).
|
2013-05-15 17:55:57 -05:00
|
|
|
#[deriving(Encodable, Decodable)]
|
2013-01-30 15:44:24 -06:00
|
|
|
pub struct freevar_entry {
|
2013-09-01 20:45:37 -05:00
|
|
|
def: ast::Def, //< The variable being accessed free.
|
2013-08-31 11:13:04 -05:00
|
|
|
span: Span //< First span where it is accessed (there can be multiple)
|
2013-01-16 21:24:10 -06:00
|
|
|
}
|
2013-01-30 15:44:24 -06:00
|
|
|
pub type freevar_info = @~[@freevar_entry];
|
2013-12-20 22:29:03 -06:00
|
|
|
pub type freevar_map = HashMap<ast::NodeId, freevar_info>;
|
2011-07-18 19:26:37 -05:00
|
|
|
|
2013-08-13 06:37:54 -05:00
|
|
|
struct CollectFreevarsVisitor {
|
2013-12-20 22:24:18 -06:00
|
|
|
seen: HashMap<ast::NodeId, ()>,
|
|
|
|
refs: ~[@freevar_entry],
|
2013-08-13 06:37:54 -05:00
|
|
|
def_map: resolve::DefMap,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Visitor<int> for CollectFreevarsVisitor {
|
2011-07-18 19:26:37 -05:00
|
|
|
|
2014-01-09 07:05:33 -06:00
|
|
|
fn visit_item(&mut self, _: &ast::Item, _: int) {
|
2013-08-13 06:37:54 -05:00
|
|
|
// ignore_item
|
|
|
|
}
|
|
|
|
|
2014-01-06 06:00:46 -06:00
|
|
|
fn visit_expr(&mut self, expr: &ast::Expr, depth: int) {
|
|
|
|
match expr.node {
|
|
|
|
ast::ExprFnBlock(..) | ast::ExprProc(..) => {
|
2013-08-13 06:37:54 -05:00
|
|
|
visit::walk_expr(self, expr, depth + 1)
|
2014-01-06 06:00:46 -06:00
|
|
|
}
|
2014-01-27 06:18:36 -06:00
|
|
|
ast::ExprPath(..) => {
|
2014-01-06 06:00:46 -06:00
|
|
|
let mut i = 0;
|
|
|
|
let def_map = self.def_map.borrow();
|
|
|
|
match def_map.get().find(&expr.id) {
|
2013-10-21 15:08:31 -05:00
|
|
|
None => fail!("path not found"),
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&df) => {
|
2014-01-06 06:00:46 -06:00
|
|
|
let mut def = df;
|
|
|
|
while i < depth {
|
|
|
|
match def {
|
|
|
|
ast::DefUpvar(_, inner, _, _) => { def = *inner; }
|
|
|
|
_ => break
|
|
|
|
}
|
|
|
|
i += 1;
|
2012-01-05 13:33:22 -06:00
|
|
|
}
|
2014-01-06 06:00:46 -06:00
|
|
|
if i == depth { // Made it to end of loop
|
|
|
|
let dnum = ast_util::def_id_of_def(def).node;
|
|
|
|
if !self.seen.contains_key(&dnum) {
|
|
|
|
self.refs.push(@freevar_entry {
|
|
|
|
def: def,
|
|
|
|
span: expr.span,
|
|
|
|
});
|
|
|
|
self.seen.insert(dnum, ());
|
|
|
|
}
|
2012-01-05 13:33:22 -06:00
|
|
|
}
|
2011-09-02 17:34:58 -05:00
|
|
|
}
|
2014-01-06 06:00:46 -06:00
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
}
|
2014-01-06 06:00:46 -06:00
|
|
|
_ => visit::walk_expr(self, expr, depth)
|
|
|
|
}
|
2013-08-13 06:37:54 -05:00
|
|
|
}
|
2011-09-01 07:35:00 -05:00
|
|
|
|
2013-08-13 06:37:54 -05:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Searches through part of the AST for all references to locals or
|
|
|
|
// upvars in this frame and returns the list of definition IDs thus found.
|
|
|
|
// Since we want to be able to collect upvars in some arbitrary piece
|
|
|
|
// of the AST, we take a walker function that we invoke with a visitor
|
|
|
|
// in order to start the search.
|
2014-01-06 06:00:46 -06:00
|
|
|
fn collect_freevars(def_map: resolve::DefMap, blk: &ast::Block) -> freevar_info {
|
2013-12-20 22:24:18 -06:00
|
|
|
let seen = HashMap::new();
|
|
|
|
let refs = ~[];
|
2013-08-13 06:37:54 -05:00
|
|
|
|
|
|
|
let mut v = CollectFreevarsVisitor {
|
|
|
|
seen: seen,
|
|
|
|
refs: refs,
|
|
|
|
def_map: def_map,
|
|
|
|
};
|
|
|
|
|
|
|
|
v.visit_block(blk, 1);
|
2013-12-20 22:24:18 -06:00
|
|
|
let CollectFreevarsVisitor {
|
|
|
|
refs,
|
|
|
|
..
|
|
|
|
} = v;
|
|
|
|
return @refs;
|
2011-07-18 19:26:37 -05:00
|
|
|
}
|
|
|
|
|
2013-08-13 06:37:54 -05:00
|
|
|
struct AnnotateFreevarsVisitor {
|
|
|
|
def_map: resolve::DefMap,
|
|
|
|
freevars: freevar_map,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Visitor<()> for AnnotateFreevarsVisitor {
|
2014-01-09 07:05:33 -06:00
|
|
|
fn visit_fn(&mut self, fk: &visit::FnKind, fd: &ast::FnDecl,
|
2014-01-06 06:00:46 -06:00
|
|
|
blk: &ast::Block, s: Span, nid: ast::NodeId, _: ()) {
|
2013-08-13 06:37:54 -05:00
|
|
|
let vars = collect_freevars(self.def_map, blk);
|
|
|
|
self.freevars.insert(nid, vars);
|
|
|
|
visit::walk_fn(self, fk, fd, blk, s, nid, ());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-18 21:14:01 -05:00
|
|
|
// Build a map from every function and for-each body to a set of the
|
|
|
|
// freevars contained in it. The implementation is not particularly
|
|
|
|
// efficient as it fully recomputes the free variables at every
|
|
|
|
// node of interest rather than building up the free variables in
|
|
|
|
// one pass. This could be improved upon if it turns out to matter.
|
2014-02-05 15:15:24 -06:00
|
|
|
pub fn annotate_freevars(def_map: resolve::DefMap, krate: &ast::Crate) ->
|
2011-09-02 17:34:58 -05:00
|
|
|
freevar_map {
|
2013-08-13 06:37:54 -05:00
|
|
|
let mut visitor = AnnotateFreevarsVisitor {
|
|
|
|
def_map: def_map,
|
2013-12-20 22:29:03 -06:00
|
|
|
freevars: HashMap::new(),
|
2011-12-20 13:03:21 -06:00
|
|
|
};
|
2014-02-05 15:15:24 -06:00
|
|
|
visit::walk_crate(&mut visitor, krate, ());
|
2011-07-18 21:14:01 -05:00
|
|
|
|
2013-12-20 22:29:03 -06:00
|
|
|
let AnnotateFreevarsVisitor {
|
|
|
|
freevars,
|
|
|
|
..
|
|
|
|
} = visitor;
|
|
|
|
freevars
|
2011-07-18 21:14:01 -05:00
|
|
|
}
|
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
pub fn get_freevars(tcx: ty::ctxt, fid: ast::NodeId) -> freevar_info {
|
2013-12-20 22:29:03 -06:00
|
|
|
let freevars = tcx.freevars.borrow();
|
|
|
|
match freevars.get().find(&fid) {
|
|
|
|
None => fail!("get_freevars: {} has no freevars", fid),
|
|
|
|
Some(&d) => return d
|
2011-07-21 16:49:58 -05:00
|
|
|
}
|
|
|
|
}
|
2013-01-10 12:59:58 -06:00
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
pub fn has_freevars(tcx: ty::ctxt, fid: ast::NodeId) -> bool {
|
2013-06-08 20:38:47 -05:00
|
|
|
!get_freevars(tcx, fid).is_empty()
|
2011-07-21 16:49:58 -05:00
|
|
|
}
|