2012-12-03 16:48:01 -08:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// 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.
|
|
|
|
|
2013-01-07 14:16:52 -08:00
|
|
|
|
2011-07-18 19:14:01 -07:00
|
|
|
// A pass that annotates for each loops and functions with the free
|
|
|
|
// variables that they contain.
|
2011-07-18 17:26:37 -07:00
|
|
|
|
2013-03-22 22:26:41 -04:00
|
|
|
use core::prelude::*;
|
|
|
|
|
2012-12-23 17:41:37 -05:00
|
|
|
use middle::resolve;
|
|
|
|
use middle::ty;
|
|
|
|
|
2013-04-03 08:45:14 -04:00
|
|
|
use core::hashmap::LinearMap;
|
2012-09-04 11:54:36 -07:00
|
|
|
use syntax::codemap::span;
|
2012-12-23 17:41:37 -05:00
|
|
|
use syntax::{ast, ast_util, visit};
|
2011-07-18 17:26:37 -07:00
|
|
|
|
2011-09-01 14:35:00 +02:00
|
|
|
// A vector of defs representing the free variables referred to in a function.
|
|
|
|
// (The def_upvar will already have been stripped).
|
2012-12-17 19:31:04 -08:00
|
|
|
#[auto_encode]
|
|
|
|
#[auto_decode]
|
2013-01-30 13:44:24 -08:00
|
|
|
pub struct freevar_entry {
|
2011-12-16 16:07:54 -08:00
|
|
|
def: ast::def, //< The variable being accessed free.
|
|
|
|
span: span //< First span where it is accessed (there can be multiple)
|
2013-01-16 19:24:10 -08:00
|
|
|
}
|
2013-01-30 13:44:24 -08:00
|
|
|
pub type freevar_info = @~[@freevar_entry];
|
2013-03-22 22:26:41 -04:00
|
|
|
pub type freevar_map = @mut LinearMap<ast::node_id, freevar_info>;
|
2011-07-18 17:26:37 -07: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.
|
2013-02-17 22:20:36 -08:00
|
|
|
fn collect_freevars(def_map: resolve::DefMap, blk: &ast::blk)
|
2011-12-20 11:03:21 -08:00
|
|
|
-> freevar_info {
|
2013-03-22 22:26:41 -04:00
|
|
|
let seen = @mut LinearMap::new();
|
2012-06-29 16:26:56 -07:00
|
|
|
let refs = @mut ~[];
|
2011-07-18 17:26:37 -07:00
|
|
|
|
2011-10-06 12:26:12 +02:00
|
|
|
fn ignore_item(_i: @ast::item, &&_depth: int, _v: visit::vt<int>) { }
|
2011-09-01 14:35:00 +02:00
|
|
|
|
2013-03-01 12:11:07 -08:00
|
|
|
let walk_expr: @fn(expr: @ast::expr, &&depth: int, v: visit::vt<int>) =
|
|
|
|
|expr, depth, v| {
|
2012-08-06 12:34:08 -07:00
|
|
|
match expr.node {
|
2013-03-01 16:59:46 -08:00
|
|
|
ast::expr_fn_block(*) => visit::visit_expr(expr, depth + 1, v),
|
2012-08-26 09:58:45 -07:00
|
|
|
ast::expr_path(*) => {
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut i = 0;
|
2013-02-05 19:41:45 -08:00
|
|
|
match def_map.find(&expr.id) {
|
2013-02-11 19:26:38 -08:00
|
|
|
None => fail!(~"path not found"),
|
2013-03-22 22:26:41 -04:00
|
|
|
Some(&df) => {
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut def = df;
|
2012-01-05 11:33:22 -08:00
|
|
|
while i < depth {
|
2013-03-20 01:17:42 -04:00
|
|
|
match def {
|
2012-08-20 16:53:33 -07:00
|
|
|
ast::def_upvar(_, inner, _, _) => { def = *inner; }
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => break
|
2012-01-05 11:33:22 -08:00
|
|
|
}
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
if i == depth { // Made it to end of loop
|
|
|
|
let dnum = ast_util::def_id_of_def(def).node;
|
2013-02-08 17:08:02 -05:00
|
|
|
if !seen.contains_key(&dnum) {
|
2013-01-16 19:24:10 -08:00
|
|
|
refs.push(@freevar_entry {
|
|
|
|
def: def,
|
|
|
|
span: expr.span,
|
|
|
|
});
|
2012-06-28 15:00:03 -07:00
|
|
|
seen.insert(dnum, ());
|
2012-01-05 11:33:22 -08:00
|
|
|
}
|
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
}
|
2012-01-05 11:33:22 -08:00
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => visit::visit_expr(expr, depth, v)
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
};
|
2011-09-01 14:35:00 +02:00
|
|
|
|
2013-01-08 14:00:45 -08:00
|
|
|
let v = visit::mk_vt(@visit::Visitor {visit_item: ignore_item,
|
|
|
|
visit_expr: walk_expr,
|
|
|
|
.. *visit::default_visitor()});
|
2012-11-29 17:51:16 -08:00
|
|
|
(v.visit_block)(blk, 1, v);
|
2013-01-07 14:16:52 -08:00
|
|
|
return @/*bad*/copy *refs;
|
2011-07-18 17:26:37 -07:00
|
|
|
}
|
|
|
|
|
2011-07-18 19:14:01 -07: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.
|
2013-01-30 13:44:24 -08:00
|
|
|
pub fn annotate_freevars(def_map: resolve::DefMap, crate: @ast::crate) ->
|
2011-09-02 15:34:58 -07:00
|
|
|
freevar_map {
|
2013-03-22 22:26:41 -04:00
|
|
|
let freevars = @mut LinearMap::new();
|
2011-07-18 19:14:01 -07:00
|
|
|
|
2013-03-01 12:11:07 -08:00
|
|
|
let walk_fn: @fn(&visit::fn_kind,
|
|
|
|
&ast::fn_decl,
|
|
|
|
&ast::blk,
|
|
|
|
span,
|
|
|
|
ast::node_id) = |_, _, blk, _, nid| {
|
2011-12-20 11:03:21 -08:00
|
|
|
let vars = collect_freevars(def_map, blk);
|
|
|
|
freevars.insert(nid, vars);
|
|
|
|
};
|
2011-07-18 19:14:01 -07:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
let visitor =
|
2013-01-08 14:00:45 -08:00
|
|
|
visit::mk_simple_visitor(@visit::SimpleVisitor {
|
|
|
|
visit_fn: walk_fn,
|
|
|
|
.. *visit::default_simple_visitor()});
|
2011-07-26 16:47:13 +02:00
|
|
|
visit::visit_crate(*crate, (), visitor);
|
2011-07-18 19:14:01 -07:00
|
|
|
|
2012-08-01 17:30:05 -07:00
|
|
|
return freevars;
|
2011-07-18 19:14:01 -07:00
|
|
|
}
|
|
|
|
|
2013-01-30 13:44:24 -08:00
|
|
|
pub fn get_freevars(tcx: ty::ctxt, fid: ast::node_id) -> freevar_info {
|
2013-02-05 19:41:45 -08:00
|
|
|
match tcx.freevars.find(&fid) {
|
2013-02-26 16:36:59 +01:00
|
|
|
None => fail!(~"get_freevars: "+int::to_str(fid)+~" has no freevars"),
|
2013-03-22 22:26:41 -04:00
|
|
|
Some(&d) => return d
|
2011-07-21 14:49:58 -07:00
|
|
|
}
|
|
|
|
}
|
2013-01-10 10:59:58 -08:00
|
|
|
|
2013-01-30 13:44:24 -08:00
|
|
|
pub fn has_freevars(tcx: ty::ctxt, fid: ast::node_id) -> bool {
|
2012-08-01 17:30:05 -07:00
|
|
|
return vec::len(*get_freevars(tcx, fid)) != 0u;
|
2011-07-21 14:49:58 -07:00
|
|
|
}
|
|
|
|
|
2011-07-18 17:26:37 -07:00
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// End:
|