diff --git a/src/comp/middle/freevars.rs b/src/comp/middle/freevars.rs new file mode 100644 index 00000000000..bf2a8f7e2c9 --- /dev/null +++ b/src/comp/middle/freevars.rs @@ -0,0 +1,91 @@ +// A pass that annotates for each loops with the free variables that +// they contain. + +import std::map; +import std::map::*; +import syntax::ast; +import syntax::walk; +import driver::session; +import middle::ty; +import syntax::codemap::span; + + + +// 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. +fn collect_upvars(&ty::ctxt tcx, &fn (&walk::ast_visitor) walker, + ast::node_id[] initial_decls) -> ast::node_id[] { + type env = + @rec(mutable ast::node_id[] refs, + hashmap[ast::node_id, ()] decls, + resolve::def_map def_map, + session::session sess); + + fn walk_fn(env e, &ast::_fn f, &ast::ty_param[] tps, &span sp, + &ast::fn_ident i, ast::node_id nid) { + for (ast::arg a in f.decl.inputs) { e.decls.insert(a.id, ()); } + } + fn walk_expr(env e, &@ast::expr expr) { + alt (expr.node) { + case (ast::expr_path(?path)) { + if (! e.def_map.contains_key(expr.id)) { + e.sess.span_fatal(expr.span, + "internal error in collect_upvars"); + } + alt (e.def_map.get(expr.id)) { + case (ast::def_arg(?did)) { e.refs += ~[did._1]; } + case (ast::def_local(?did)) { e.refs += ~[did._1]; } + case (ast::def_binding(?did)) { e.refs += ~[did._1]; } + case (_) { /* no-op */ } + } + } + case (_) { } + } + } + fn walk_local(env e, &@ast::local local) { + e.decls.insert(local.node.id, ()); + } + fn walk_pat(env e, &@ast::pat p) { + alt (p.node) { + case (ast::pat_bind(_)) { + e.decls.insert(p.id, ()); + } + case (_) {} + } + } + let hashmap[ast::node_id, ()] decls = new_int_hash[()](); + for (ast::node_id decl in initial_decls) { decls.insert(decl, ()); } + + let env e = + @rec(mutable refs=~[], + decls=decls, + def_map=tcx.def_map, + sess=tcx.sess); + auto visitor = + @rec(visit_fn_pre=bind walk_fn(e, _, _, _, _, _), + visit_local_pre=bind walk_local(e, _), + visit_expr_pre=bind walk_expr(e, _), + visit_pat_pre=bind walk_pat(e, _) + with walk::default_visitor()); + walker(*visitor); + // Calculate (refs - decls). This is the set of captured upvars. + + let ast::node_id[] result = ~[]; + for (ast::node_id ref_id_ in e.refs) { + auto ref_id = ref_id_; + if (!decls.contains_key(ref_id)) { result += ~[ref_id]; } + } + ret result; +} + +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 0fba8ccd2b1..710b91a18a9 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -27,6 +27,7 @@ import syntax::walk; import driver::session; import middle::ty; +import middle::freevars; import back::link; import back::x86; import back::abi; @@ -4107,76 +4108,6 @@ fn inner(&@block_ctxt cx, @ast::local local, ValueRef curr, ty::t t, // Iterator translation -// 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. -fn collect_upvars(&@block_ctxt cx, &fn (&walk::ast_visitor) walker, - ast::node_id[] initial_decls) -> ast::node_id[] { - type env = - @rec(mutable ast::node_id[] refs, - hashmap[ast::node_id, ()] decls, - resolve::def_map def_map, - session::session sess); - - fn walk_fn(env e, &ast::_fn f, &ast::ty_param[] tps, &span sp, - &ast::fn_ident i, ast::node_id nid) { - for (ast::arg a in f.decl.inputs) { e.decls.insert(a.id, ()); } - } - fn walk_expr(env e, &@ast::expr expr) { - alt (expr.node) { - case (ast::expr_path(?path)) { - if (! e.def_map.contains_key(expr.id)) { - e.sess.span_fatal(expr.span, - "internal error in collect_upvars"); - } - alt (e.def_map.get(expr.id)) { - case (ast::def_arg(?did)) { e.refs += ~[did._1]; } - case (ast::def_local(?did)) { e.refs += ~[did._1]; } - case (ast::def_binding(?did)) { e.refs += ~[did._1]; } - case (_) { /* no-op */ } - } - } - case (_) { } - } - } - fn walk_local(env e, &@ast::local local) { - e.decls.insert(local.node.id, ()); - } - fn walk_pat(env e, &@ast::pat p) { - alt (p.node) { - case (ast::pat_bind(_)) { - e.decls.insert(p.id, ()); - } - case (_) {} - } - } - let hashmap[ast::node_id, ()] decls = new_int_hash[()](); - for (ast::node_id decl in initial_decls) { decls.insert(decl, ()); } - - let env e = - @rec(mutable refs=~[], - decls=decls, - def_map=cx.fcx.lcx.ccx.tcx.def_map, - sess=cx.fcx.lcx.ccx.tcx.sess); - auto visitor = - @rec(visit_fn_pre=bind walk_fn(e, _, _, _, _, _), - visit_local_pre=bind walk_local(e, _), - visit_expr_pre=bind walk_expr(e, _), - visit_pat_pre=bind walk_pat(e, _) - with walk::default_visitor()); - walker(*visitor); - // Calculate (refs - decls). This is the set of captured upvars. - - let ast::node_id[] result = ~[]; - for (ast::node_id ref_id_ in e.refs) { - auto ref_id = ref_id_; - if (!decls.contains_key(ref_id)) { result += ~[ref_id]; } - } - ret result; -} - // Finds the ValueRef associated with a variable in a function // context. It checks locals, upvars, and args. fn find_variable(&@fn_ctxt fcx, ast::node_id nid) -> ValueRef { @@ -4353,8 +4284,9 @@ fn trans_for_each(&@block_ctxt cx, &@ast::local local, &@ast::expr seq, // FIXME: possibly support alias-mode here? auto decl_ty = node_id_type(lcx.ccx, local.node.id); auto decl_id = local.node.id; - auto upvars = collect_upvars(cx, bind walk::walk_block(_, body), - ~[decl_id]); + auto upvars = freevars::collect_upvars(cx.fcx.lcx.ccx.tcx, + bind walk::walk_block(_, body), + ~[decl_id]); auto environment_data = build_environment(cx, upvars); auto llenvptr = environment_data._0; diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index 10e9cb80193..1970aa66cd2 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -26,6 +26,7 @@ mod middle { mod resolve; mod typeck; mod alias; + mod freevars; mod tstate { mod ck;