Use lambdas in the freevars pass.
This commit is contained in:
parent
ae3312002a
commit
95680474e2
1 changed files with 50 additions and 64 deletions
|
|
@ -26,8 +26,8 @@ export def_lookup;
|
|||
// Throughout the compiler, variables are generally dealt with using the
|
||||
// node_ids of the reference sites and not the def_id of the definition
|
||||
// site. Thus we store a set are the definitions along with a vec of one
|
||||
// referencing node_id per free variable. The set is useful for testing
|
||||
// membership, the list of referencing sites is what you want for most
|
||||
// "canonical" referencing node_id per free variable. The set is useful for
|
||||
// testing membership, the list of referencing sites is what you want for most
|
||||
// other things.
|
||||
type freevar_set = hashset[ast::node_id];
|
||||
type freevar_info = {defs: freevar_set, refs: @ast::node_id[]};
|
||||
|
|
@ -41,67 +41,61 @@ type freevar_map = hashmap[ast::node_id, freevar_info];
|
|||
fn collect_freevars(def_map: &resolve::def_map, sess: &session::session,
|
||||
walker: &fn(&visit::vt[()]) ,
|
||||
initial_decls: ast::node_id[]) -> freevar_info {
|
||||
type env =
|
||||
@{mutable refs: ast::node_id[],
|
||||
decls: hashset[ast::node_id],
|
||||
def_map: resolve::def_map,
|
||||
sess: session::session};
|
||||
let decls = new_int_hash();
|
||||
for decl: ast::node_id in initial_decls { set_add(decls, decl); }
|
||||
let refs = @mutable ~[];
|
||||
|
||||
fn walk_fn(e: env, f: &ast::_fn, tps: &ast::ty_param[], sp: &span,
|
||||
i: &ast::fn_ident, nid: ast::node_id) {
|
||||
for a: ast::arg in f.decl.inputs { e.decls.insert(a.id, ()); }
|
||||
}
|
||||
fn walk_expr(e: env, expr: &@ast::expr) {
|
||||
let walk_fn = lambda(f: &ast::_fn, tps: &ast::ty_param[], sp: &span,
|
||||
i: &ast::fn_ident, nid: ast::node_id) {
|
||||
for a: ast::arg in f.decl.inputs { set_add(decls, a.id); }
|
||||
};
|
||||
let walk_expr = lambda(expr: &@ast::expr) {
|
||||
alt expr.node {
|
||||
ast::expr_path(path) {
|
||||
if !e.def_map.contains_key(expr.id) {
|
||||
e.sess.span_fatal(expr.span,
|
||||
"internal error in collect_freevars");
|
||||
if !def_map.contains_key(expr.id) {
|
||||
sess.span_fatal(expr.span,
|
||||
"internal error in collect_freevars");
|
||||
}
|
||||
alt e.def_map.get(expr.id) {
|
||||
ast::def_arg(did) { e.refs += ~[expr.id]; }
|
||||
ast::def_local(did) { e.refs += ~[expr.id]; }
|
||||
ast::def_binding(did) { e.refs += ~[expr.id]; }
|
||||
alt def_map.get(expr.id) {
|
||||
ast::def_arg(did) { *refs += ~[expr.id]; }
|
||||
ast::def_local(did) { *refs += ~[expr.id]; }
|
||||
ast::def_binding(did) { *refs += ~[expr.id]; }
|
||||
_ {/* no-op */ }
|
||||
}
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
}
|
||||
fn walk_local(e: env, local: &@ast::local) {
|
||||
};
|
||||
let walk_local = lambda(local: &@ast::local) {
|
||||
for each b: @ast::pat in ast::pat_bindings(local.node.pat) {
|
||||
set_add(e.decls, b.id);
|
||||
set_add(decls, b.id);
|
||||
}
|
||||
}
|
||||
fn walk_pat(e: env, p: &@ast::pat) {
|
||||
alt p.node { ast::pat_bind(_) { set_add(e.decls, p.id); } _ { } }
|
||||
}
|
||||
let decls: hashset[ast::node_id] = new_int_hash();
|
||||
for decl: ast::node_id in initial_decls { set_add(decls, decl); }
|
||||
};
|
||||
let walk_pat = lambda(p: &@ast::pat) {
|
||||
alt p.node { ast::pat_bind(_) { set_add(decls, p.id); } _ { } }
|
||||
};
|
||||
|
||||
let e: env =
|
||||
@{mutable refs: ~[], decls: decls, def_map: def_map, sess: sess};
|
||||
walker(visit::mk_simple_visitor
|
||||
(@{visit_local: bind walk_local(e, _),
|
||||
visit_pat: bind walk_pat(e, _),
|
||||
visit_expr: bind walk_expr(e, _),
|
||||
visit_fn: bind walk_fn(e, _, _, _, _, _)
|
||||
(@{visit_local: walk_local,
|
||||
visit_pat: walk_pat,
|
||||
visit_expr: walk_expr,
|
||||
visit_fn: walk_fn
|
||||
with *visit::default_simple_visitor()}));
|
||||
|
||||
// Calculate (refs - decls). This is the set of captured upvars.
|
||||
// We build a vec of the node ids of the uses and a set of the
|
||||
// node ids of the definitions.
|
||||
let refs = ~[];
|
||||
let canonical_refs = ~[];
|
||||
let defs = new_int_hash();
|
||||
for ref_id_: ast::node_id in e.refs {
|
||||
for ref_id_: ast::node_id in *refs {
|
||||
let ref_id = ref_id_;
|
||||
let def_id = ast::def_id_of_def(def_map.get(ref_id)).node;
|
||||
if !decls.contains_key(def_id) && !defs.contains_key(def_id) {
|
||||
refs += ~[ref_id];
|
||||
canonical_refs += ~[ref_id];
|
||||
set_add(defs, def_id);
|
||||
}
|
||||
}
|
||||
ret {defs: defs, refs: @refs};
|
||||
ret {defs: defs, refs: @canonical_refs};
|
||||
}
|
||||
|
||||
// Build a map from every function and for-each body to a set of the
|
||||
|
|
@ -111,46 +105,38 @@ fn collect_freevars(def_map: &resolve::def_map, sess: &session::session,
|
|||
// one pass. This could be improved upon if it turns out to matter.
|
||||
fn annotate_freevars(sess: &session::session, def_map: &resolve::def_map,
|
||||
crate: &@ast::crate) -> freevar_map {
|
||||
type env =
|
||||
{freevars: freevar_map,
|
||||
def_map: resolve::def_map,
|
||||
sess: session::session};
|
||||
let freevars = new_int_hash();
|
||||
|
||||
fn walk_fn(e: env, f: &ast::_fn, tps: &ast::ty_param[], sp: &span,
|
||||
i: &ast::fn_ident, nid: ast::node_id) {
|
||||
fn start_walk(f: &ast::_fn, tps: &ast::ty_param[], sp: &span,
|
||||
i: &ast::fn_ident, nid: ast::node_id,
|
||||
v: &visit::vt[()]) {
|
||||
let walk_fn = lambda(f: &ast::_fn, tps: &ast::ty_param[], sp: &span,
|
||||
i: &ast::fn_ident, nid: ast::node_id) {
|
||||
let start_walk = lambda(v: &visit::vt[()]) {
|
||||
v.visit_fn(f, tps, sp, i, nid, (), v);
|
||||
}
|
||||
let walker = bind start_walk(f, tps, sp, i, nid, _);
|
||||
let vars = collect_freevars(e.def_map, e.sess, walker, ~[]);
|
||||
e.freevars.insert(nid, vars);
|
||||
}
|
||||
fn walk_expr(e: env, expr: &@ast::expr) {
|
||||
};
|
||||
let vars = collect_freevars(def_map, sess, start_walk, ~[]);
|
||||
freevars.insert(nid, vars);
|
||||
};
|
||||
let walk_expr = lambda(expr: &@ast::expr) {
|
||||
alt expr.node {
|
||||
ast::expr_for_each(local, _, body) {
|
||||
fn start_walk(b: &ast::blk, v: &visit::vt[()]) {
|
||||
v.visit_block(b, (), v);
|
||||
}
|
||||
let start_walk = lambda(v: &visit::vt[()]) {
|
||||
v.visit_block(body, (), v);
|
||||
};
|
||||
let bound = ast::pat_binding_ids(local.node.pat);
|
||||
let vars =
|
||||
collect_freevars(e.def_map, e.sess, bind start_walk(body, _),
|
||||
bound);
|
||||
e.freevars.insert(body.node.id, vars);
|
||||
collect_freevars(def_map, sess, start_walk, bound);
|
||||
freevars.insert(body.node.id, vars);
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let e: env = {freevars: new_int_hash(), def_map: def_map, sess: sess};
|
||||
let visitor =
|
||||
visit::mk_simple_visitor(@{visit_fn: bind walk_fn(e, _, _, _, _, _),
|
||||
visit_expr: bind walk_expr(e, _)
|
||||
visit::mk_simple_visitor(@{visit_fn: walk_fn,
|
||||
visit_expr: walk_expr
|
||||
with *visit::default_simple_visitor()});
|
||||
visit::visit_crate(*crate, (), visitor);
|
||||
|
||||
ret e.freevars;
|
||||
ret freevars;
|
||||
}
|
||||
|
||||
fn get_freevar_info(tcx: &ty::ctxt, fid: ast::node_id) -> freevar_info {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue