Change resolve to use walk instead of fold

Possibly, at some point, we should add a state-passing variant of
walk, or a wrapper that makes it easier to thread state. (See the
repetetive pop_state_for_* functions in this commit.)
This commit is contained in:
Marijn Haverbeke 2011-05-13 10:51:36 +02:00
parent 7082bf4478
commit 89490e416b
2 changed files with 167 additions and 107 deletions

View file

@ -92,10 +92,8 @@ fn compile_input(session::session sess,
crate = time(time_passes, "external crate reading",
bind creader::read_crates(sess, crate));
auto res = time(time_passes, "resolution",
bind resolve::resolve_crate(sess, crate));
crate = res._0;
auto def_map = res._1;
auto def_map = time(time_passes, "resolution",
bind resolve::resolve_crate(sess, crate));
time[()](time_passes, "capture checking",
bind capture::check_for_captures(sess, crate, def_map));

View file

@ -93,8 +93,7 @@ tag namespace {
ns_type;
}
fn resolve_crate(session sess, @ast::crate crate)
-> tup(@ast::crate, def_map) {
fn resolve_crate(session sess, @ast::crate crate) -> def_map {
auto e = @rec(def_map = new_uint_hash[def](),
imports = new_int_hash[import_state](),
mod_map = new_int_hash[@indexed_mod](),
@ -104,7 +103,8 @@ fn resolve_crate(session sess, @ast::crate crate)
sess = sess);
map_crate(e, *crate);
resolve_imports(*e);
ret tup(resolve_names(e, *crate), e.def_map);
resolve_names(e, *crate);
ret e.def_map;
}
// Locate all modules and imports and index them, so that the next passes can
@ -115,7 +115,7 @@ fn map_crate(&@env e, &ast::crate c) {
auto v = rec(visit_crate_pre = bind push_env_for_crate(cell, _),
visit_crate_post = bind pop_env_for_crate(cell, _),
visit_view_item_pre = bind visit_view_item(e, cell, _),
visit_item_pre = bind push_env_for_item_map_mod(e, cell, _),
visit_item_pre = bind visit_item(e, cell, _),
visit_item_post = bind pop_env_for_item(cell, _)
with walk::default_visitor());
// Register the top-level mod
@ -123,16 +123,16 @@ fn map_crate(&@env e, &ast::crate c) {
index=index_mod(c.node.module)));
walk::walk_crate(v, c);
// Helpers for this pass.
fn push_env_for_crate(@mutable list[scope] sc, &ast::crate c) {
*sc = cons[scope](scope_crate(@c), @*sc);
fn visit_view_item(@env e, @mutable list[scope] sc, &@ast::view_item i) {
alt (i.node) {
case (ast::view_item_import(_, ?ids, ?defid)) {
e.imports.insert(defid._1, todo(i, *sc));
}
case (_) {}
}
}
fn pop_env_for_crate(@mutable list[scope] sc, &ast::crate c) {
*sc = std::list::cdr(*sc);
}
fn push_env_for_item_map_mod(@env e, @mutable list[scope] sc,
&@ast::item i) {
*sc = cons[scope](scope_item(i), @*sc);
fn visit_item(@env e, @mutable list[scope] sc, &@ast::item i) {
push_env_for_item(sc, i);
alt (i.node) {
case (ast::item_mod(_, ?md, ?defid)) {
auto index = index_mod(md);
@ -145,17 +145,6 @@ fn map_crate(&@env e, &ast::crate c) {
case (_) {}
}
}
fn pop_env_for_item(@mutable list[scope] sc, &@ast::item i) {
*sc = std::list::cdr(*sc);
}
fn visit_view_item(@env e, @mutable list[scope] sc, &@ast::view_item i) {
alt (i.node) {
case (ast::view_item_import(_, ?ids, ?defid)) {
e.imports.insert(defid._1, todo(i, *sc));
}
case (_) {}
}
}
}
fn resolve_imports(&env e) {
@ -169,67 +158,150 @@ fn resolve_imports(&env e) {
}
}
// FIXME this should use walk (will need to add walk_arm)
fn resolve_names(&@env e, &ast::crate c) -> @ast::crate {
auto fld = @rec(fold_pat_tag = bind fold_pat_tag(e,_,_,_,_,_),
fold_expr_path = bind fold_expr_path(e,_,_,_,_),
fold_ty_path = bind fold_ty_path(e,_,_,_,_),
update_env_for_crate = bind update_env_for_crate(_,_),
update_env_for_item = bind update_env_for_item(_,_),
update_env_for_native_item =
bind update_env_for_native_item(_,_),
update_env_for_block = bind update_env_for_block(_,_),
update_env_for_arm = bind update_env_for_arm(_,_),
update_env_for_expr = bind update_env_for_expr(_,_)
with *fold::new_identity_fold[list[scope]]());
ret fold::fold_crate(nil[scope], fld, @c);
fn resolve_names(&@env e, &ast::crate c) {
auto cell = @mutable nil[scope];
auto v = rec(visit_crate_pre = bind push_env_for_crate(cell, _),
visit_crate_post = bind pop_env_for_crate(cell, _),
visit_item_pre = bind push_env_for_item(cell, _),
visit_item_post = bind pop_env_for_item(cell, _),
visit_method_pre = bind push_env_for_method(cell, _),
visit_method_post = bind pop_env_for_method(cell, _),
visit_native_item_pre = bind push_env_for_n_item(cell, _),
visit_native_item_post = bind pop_env_for_n_item(cell, _),
visit_block_pre = bind push_env_for_block(cell, _),
visit_block_post = bind pop_env_for_block(cell, _),
visit_arm_pre = bind walk_arm(e, cell, _),
visit_arm_post = bind pop_env_for_arm(cell, _),
visit_expr_pre = bind walk_expr(e, cell, _),
visit_expr_post = bind pop_env_for_expr(cell, _),
visit_ty_pre = bind walk_ty(e, cell, _)
with walk::default_visitor());
walk::walk_crate(v, c);
// Helpers for this pass
fn update_env_for_crate(&list[scope] sc, &@ast::crate c) -> list[scope] {
ret cons[scope](scope_crate(c), @sc);
}
fn update_env_for_item(&list[scope] sc, &@ast::item i) -> list[scope] {
ret cons[scope](scope_item(i), @sc);
}
fn update_env_for_native_item(&list[scope] sc, &@ast::native_item i)
-> list[scope] {
ret cons[scope](scope_native_item(i), @sc);
}
fn update_env_for_block(&list[scope] sc, &ast::block b) -> list[scope] {
ret cons[scope](scope_block(b), @sc);
}
fn update_env_for_expr(&list[scope] sc, &@ast::expr x) -> list[scope] {
alt (x.node) {
case (ast::expr_for(?d, _, _, _)) {
ret cons[scope](scope_loop(d), @sc);
fn walk_expr(@env e, @mutable list[scope] sc, &@ast::expr exp) {
push_env_for_expr(sc, exp);
alt (exp.node) {
case (ast::expr_path(?p, ?a)) {
auto df = lookup_path_strict(*e, *sc, exp.span, p.node.idents,
ns_value);
e.def_map.insert(ast::ann_tag(a), df);
}
case (ast::expr_for_each(?d, _, _, _)) {
ret cons[scope](scope_loop(d), @sc);
}
case (_) { ret sc; }
case (_) {}
}
}
fn update_env_for_arm(&list[scope] sc, &ast::arm p) -> list[scope] {
ret cons[scope](scope_arm(p), @sc);
fn walk_ty(@env e, @mutable list[scope] sc, &@ast::ty t) {
alt (t.node) {
case (ast::ty_path(?p, ?a)) {
auto new_def = lookup_path_strict(*e, *sc, t.span,
p.node.idents, ns_type);
e.def_map.insert(ast::ann_tag(a), new_def);
}
case (_) {}
}
}
fn walk_arm(@env e, @mutable list[scope] sc, &ast::arm a) {
walk_pat(*e, *sc, a.pat);
push_env_for_arm(sc, a);
}
fn walk_pat(&env e, &list[scope] sc, &@ast::pat pat) {
alt (pat.node) {
case (ast::pat_tag(?p, ?children, ?a)) {
auto fnd = lookup_path_strict(e, sc, p.span, p.node.idents,
ns_value);
alt (fnd) {
case (ast::def_variant(?did, ?vid)) {
e.def_map.insert(ast::ann_tag(a), fnd);
}
case (_) {
e.sess.span_err(p.span, "not a tag variant: " +
_str::connect(p.node.idents, "::"));
fail;
}
}
for (@ast::pat child in children) {
walk_pat(e, sc, child);
}
}
case (_) {}
}
}
}
fn lookup_import(&env e, def_id defid, namespace ns) -> option::t[def] {
alt (e.imports.get(defid._1)) {
case (todo(?item, ?sc)) {
resolve_import(e, item, sc);
ret lookup_import(e, defid, ns);
// Helpers for tracking scope during a walk
fn push_env_for_crate(@mutable list[scope] sc, &ast::crate c) {
*sc = cons[scope](scope_crate(@c), @*sc);
}
fn pop_env_for_crate(@mutable list[scope] sc, &ast::crate c) {
*sc = std::list::cdr(*sc);
}
fn push_env_for_item(@mutable list[scope] sc, &@ast::item i) {
*sc = cons[scope](scope_item(i), @*sc);
}
fn pop_env_for_item(@mutable list[scope] sc, &@ast::item i) {
*sc = std::list::cdr(*sc);
}
fn push_env_for_method(@mutable list[scope] sc, &@ast::method m) {
let vec[ast::ty_param] tp = vec();
let @ast::item i = @rec(node=ast::item_fn(m.node.ident,
m.node.meth,
tp,
m.node.id,
m.node.ann),
span=m.span);
*sc = cons[scope](scope_item(i), @*sc);
}
fn pop_env_for_method(@mutable list[scope] sc, &@ast::method m) {
*sc = std::list::cdr(*sc);
}
fn push_env_for_n_item(@mutable list[scope] sc, &@ast::native_item i) {
*sc = cons[scope](scope_native_item(i), @*sc);
}
fn pop_env_for_n_item(@mutable list[scope] sc, &@ast::native_item i) {
*sc = std::list::cdr(*sc);
}
fn push_env_for_block(@mutable list[scope] sc, &ast::block b) {
*sc = cons[scope](scope_block(b), @*sc);
}
fn pop_env_for_block(@mutable list[scope] sc, &ast::block b) {
*sc = std::list::cdr(*sc);
}
fn push_env_for_expr(@mutable list[scope] sc, &@ast::expr x) {
alt (x.node) {
case (ast::expr_for(?d, _, _, _)) {
*sc = cons[scope](scope_loop(d), @*sc);
}
case (resolving(?sp)) {
e.sess.span_err(sp, "cyclic import");
}
case (resolved(?val, ?typ)) {
ret alt (ns) { case (ns_value) { val }
case (ns_type) { typ } };
case (ast::expr_for_each(?d, _, _, _)) {
*sc = cons[scope](scope_loop(d), @*sc);
}
case (_) {}
}
}
fn pop_env_for_expr(@mutable list[scope] sc, &@ast::expr x) {
alt (x.node) {
case (ast::expr_for(?d, _, _, _)) {
*sc = std::list::cdr(*sc);
}
case (ast::expr_for_each(?d, _, _, _)) {
*sc = std::list::cdr(*sc);
}
case (_) {}
}
}
fn push_env_for_arm(@mutable list[scope] sc, &ast::arm p) {
*sc = cons[scope](scope_arm(p), @*sc);
}
fn pop_env_for_arm(@mutable list[scope] sc, &ast::arm p) {
*sc = std::list::cdr(*sc);
}
// Import resolution
fn resolve_import(&env e, &@ast::view_item it, &list[scope] sc) {
auto defid; auto ids;
@ -277,35 +349,7 @@ fn resolve_import(&env e, &@ast::view_item it, &list[scope] sc) {
}
}
fn fold_expr_path(@env e, &list[scope] sc, &span sp, &ast::path p, &ann a)
-> @ast::expr {
auto df = lookup_path_strict(*e, sc, sp, p.node.idents, ns_value);
e.def_map.insert(ast::ann_tag(a), df);
ret @fold::respan(sp, ast::expr_path(p, a));
}
fn fold_pat_tag(@env e, &list[scope] sc, &span sp, &ast::path p,
&vec[@ast::pat] args, &ann a) -> @ast::pat {
alt (lookup_path_strict(*e, sc, sp, p.node.idents, ns_value)) {
case (ast::def_variant(?did, ?vid)) {
e.def_map.insert(ast::ann_tag(a), ast::def_variant(did, vid));
ret @fold::respan[ast::pat_](sp, ast::pat_tag(p, args, a));
}
case (_) {
e.sess.span_err(sp, "not a tag variant: " +
_str::connect(p.node.idents, "::"));
fail;
}
}
}
fn fold_ty_path(@env e, &list[scope] sc, &span sp, &ast::path p,
&ast::ann a) -> @ast::ty {
auto new_def = lookup_path_strict(*e, sc, sp, p.node.idents, ns_type);
e.def_map.insert(ast::ann_tag(a), new_def);
ret @fold::respan[ast::ty_](sp, ast::ty_path(p, a));
}
// Utilities
fn is_module(def d) -> bool {
alt (d) {
@ -326,6 +370,8 @@ fn unresolved(&env e, &span sp, ident id, str kind) {
e.sess.span_err(sp, "unresolved " + kind + ": " + id);
}
// Lookup helpers
fn lookup_path_strict(&env e, &list[scope] sc, &span sp, vec[ident] idents,
namespace ns) -> def {
auto n_idents = _vec::len(idents);
@ -628,6 +674,22 @@ fn found_view_item(&env e, @ast::view_item vi, namespace ns)
}
}
fn lookup_import(&env e, def_id defid, namespace ns) -> option::t[def] {
alt (e.imports.get(defid._1)) {
case (todo(?item, ?sc)) {
resolve_import(e, item, sc);
ret lookup_import(e, defid, ns);
}
case (resolving(?sp)) {
e.sess.span_err(sp, "cyclic import");
}
case (resolved(?val, ?typ)) {
ret alt (ns) { case (ns_value) { val }
case (ns_type) { typ } };
}
}
}
fn lookup_in_regular_mod(&env e, def_id defid, ident id, namespace ns, dir dr)
-> option::t[def] {
auto info = e.mod_map.get(defid._1);