Fix bugs: make sure glob imports show up in the right module,

and make sure that circular glob imports don't diverge.
This commit is contained in:
Paul Stansifer 2011-05-25 10:10:30 -07:00 committed by Graydon Hoare
parent 3375b8fba2
commit 54ca8565c9
6 changed files with 178 additions and 70 deletions

View File

@ -12,6 +12,7 @@ import util::common::new_str_hash;
import util::common::span;
import middle::tstate::ann::ts_ann;
import std::map::hashmap;
import std::list;
import std::list::list;
import std::list::nil;
import std::list::cons;
@ -168,40 +169,43 @@ fn map_crate(&@env e, &ast::crate c) {
}
// Next, assemble the links for globbed imports.
let @indexed_mod cur_mod = e.mod_map.get(-1);
cell = @mutable nil[scope];
auto link_globs =
auto link_globs =
rec(visit_crate_pre = bind push_env_for_crate(cell, _),
visit_crate_post = bind pop_env_for_crate(cell, _),
visit_view_item_pre = bind link_glob(e, cell, cur_mod, _),
visit_item_pre = bind enter_i(e, cell, cur_mod, _),
visit_view_item_pre = bind link_glob(e, cell, _),
visit_item_pre = bind push_env_for_item(cell, _),
visit_item_post = bind pop_env_for_item(cell, _)
with walk::default_visitor());
walk::walk_crate(link_globs, c);
fn enter_i(@env e, @mutable list[scope] sc, @indexed_mod cur_mod,
&@ast::item i) {
push_env_for_item(sc,i);
alt(i.node) {
case (ast::item_mod(_, _, ?defid)) {
cur_mod = e.mod_map.get(defid._1);
fn link_glob(@env e, @mutable list[scope] sc, &@ast::view_item vi) {
fn find_mod(@env e, list[scope] sc) -> @indexed_mod {
alt (sc) {
case (cons[scope](scope_item(?i), ?tl)) {
alt(i.node) {
case (ast::item_mod(_, _, ?defid)) {
ret e.mod_map.get(defid._1);
}
case (ast::item_native_mod(_, _, ?defid)) {
ret e.mod_map.get(defid._1);
}
case (_) {
be find_mod(e, *tl);
}
}
}
case (_) {
ret e.mod_map.get(-1); //top-level
}
}
case (ast::item_native_mod(_, _, ?defid)) {
cur_mod = e.mod_map.get(defid._1);
}
case (_) {}
}
}
fn link_glob(@env e, @mutable list[scope] sc, @indexed_mod cur_mod,
&@ast::view_item vi) {
alt (vi.node) {
//if it really is a glob import, that is
case (ast::view_item_import_glob(?path, _)) {
cur_mod.glob_imports +=
[follow_import(*e, *sc, path, vi.span)];
find_mod(e, *sc).glob_imports
+= [follow_import(*e, *sc, path, vi.span)];
}
case (_) {}
}
@ -518,10 +522,13 @@ fn lookup_in_scope(&env e, list[scope] sc, &span sp, &ident id, namespace ns)
-> option::t[def] {
fn in_scope(&env e, &span sp, &ident id, &scope s, namespace ns)
-> option::t[def] {
//not recursing through globs
let list[def] no_m = nil[def];
alt (s) {
case (scope_crate(?c)) {
auto defid = tup(ast::local_crate, -1);
ret lookup_in_local_mod(e, defid, sp, id, ns, inside);
ret lookup_in_local_mod(e, defid, no_m, sp, id, ns, inside);
}
case (scope_item(?it)) {
alt (it.node) {
@ -537,10 +544,12 @@ fn lookup_in_scope(&env e, list[scope] sc, &span sp, &ident id, namespace ns)
}
}
case (ast::item_mod(_, _, ?defid)) {
ret lookup_in_local_mod(e, defid, sp, id, ns, inside);
ret lookup_in_local_mod(e, defid, no_m, sp,
id, ns, inside);
}
case (ast::item_native_mod(_, ?m, ?defid)) {
ret lookup_in_local_native_mod(e, defid, sp, id, ns);
ret lookup_in_local_native_mod(e, defid, no_m,
sp, id, ns);
}
case (ast::item_ty(_, _, ?ty_params, _, _)) {
if (ns == ns_type) {
@ -768,26 +777,44 @@ fn lookup_in_mod_strict(&env e, def m, &span sp, &ident id,
fn lookup_in_mod(&env e, def m, &span sp, &ident id, namespace ns, dir dr)
-> option::t[def] {
auto defid = ast::def_id_of_def(m);
if (defid._0 != ast::local_crate) { // examining a mod. in an ext. crate
auto cached = e.ext_cache.find(tup(defid,id,ns));
if (!option::is_none(cached)) { ret cached; }
auto path = [id];
if (defid._1 != -1) {
path = e.ext_map.get(defid) + path;
}
auto fnd = lookup_external(e, defid._0, path, ns);
if (!option::is_none(fnd)) {
e.ext_cache.insert(tup(defid,id,ns), option::get(fnd));
}
ret fnd;
}
be lookup_in_mod_recursively(e, cons[def](m, @nil[def]), sp, id, ns, dr);
}
// this list is simply the stack of glob imports we have passed through
// (preventing cyclic glob imports from diverging)
fn lookup_in_mod_recursively(&env e, list[def] m, &span sp, &ident id,
namespace ns, dir dr) -> option::t[def] {
alt (m) {
case (ast::def_mod(?defid)) {
ret lookup_in_local_mod(e, defid, sp, id, ns, dr);
case (cons[def](?mod_def, ?tl)) {
if (list::has(*tl, mod_def)) {
ret none[def]; // import glob cycle detected; we're done
}
auto defid = ast::def_id_of_def(mod_def);
if (defid._0 != ast::local_crate) {
// examining a module in an external crate
auto cached = e.ext_cache.find(tup(defid,id,ns));
if (!option::is_none(cached)) { ret cached; }
auto path = [id];
if (defid._1 != -1) {
path = e.ext_map.get(defid) + path;
}
auto fnd = lookup_external(e, defid._0, path, ns);
if (!option::is_none(fnd)) {
e.ext_cache.insert(tup(defid,id,ns), option::get(fnd));
}
ret fnd;
}
alt (mod_def) {
case (ast::def_mod(?defid)) {
ret lookup_in_local_mod(e, defid, m, sp, id, ns, dr);
}
case (ast::def_native_mod(?defid)) {
ret lookup_in_local_native_mod(e, defid, m, sp, id, ns);
}
}
}
case (ast::def_native_mod(?defid)) {
ret lookup_in_local_native_mod(e, defid, sp, id, ns);
case (_) {
e.sess.bug("lookup_in_mod_recursively needs a module"); fail;
}
}
}
@ -825,8 +852,14 @@ fn lookup_import(&env e, def_id defid, namespace ns) -> option::t[def] {
fail;
}
fn lookup_in_local_mod(&env e, def_id defid, &span sp, &ident id,
namespace ns, dir dr) -> option::t[def] {
fn lookup_in_local_native_mod(&env e, def_id defid, list[def] m, &span sp,
&ident id, namespace ns) -> option::t[def] {
ret lookup_in_local_mod(e, defid, m, sp, id, ns, inside);
}
fn lookup_in_local_mod(&env e, def_id defid, list[def] m, &span sp,
&ident id, namespace ns, dir dr) -> option::t[def] {
auto info = e.mod_map.get(defid._1);
if (dr == outside && !ast::is_exported(id, option::get(info.m))) {
// if we're in a native mod, then dr==inside, so info.m is some _mod
@ -848,26 +881,24 @@ fn lookup_in_local_mod(&env e, def_id defid, &span sp, &ident id,
}
}
// not local or explicitly imported; try globs:
ret lookup_glob_in_mod(e, info, sp, id, ns, dr);
ret lookup_glob_in_mod(e, info, m, sp, id, ns, dr);
}
fn lookup_glob_in_mod(&env e, @indexed_mod info, &span sp, &ident id,
namespace ns, dir dr) -> option::t[def] {
fn l_i_m(&env e, &def d, &span sp, &ident id, namespace ns, dir dr)
-> option::t[def] {
ret lookup_in_mod(e, d, sp, id, ns, dr);
fn lookup_glob_in_mod(&env e, @indexed_mod info, list[def] m, &span sp,
&ident id, namespace ns, dir dr) -> option::t[def] {
fn l_i_m_r(&env e, list[def] prev_ms, &def m, &span sp, &ident id,
namespace ns, dir dr) -> option::t[def] {
be lookup_in_mod_recursively(e, cons[def](m, @prev_ms),
sp, id, ns, dr);
}
auto matches = vec::filter_map
(bind l_i_m(e, _, sp, id, ns, dr), info.glob_imports);
auto matches = vec::filter_map[def, def]
(bind l_i_m_r(e, m, _, sp, id, ns, dr),
info.glob_imports);
if (vec::len(matches) == 0u) {
ret none[def];
} else if (vec::len(matches) == 1u){
ret some[def](matches.(0));
} else {
for (def d in matches) {
e.sess.span_note(sp, "'" + id + "' is defined at " +
util::common::istr(ast::def_id_of_def(d)._1));
}
e.sess.span_err(sp, "'" + id + "' is glob-imported from" +
" multiple different modules.");
fail;
@ -914,10 +945,6 @@ fn lookup_in_mie(&env e, &mod_index_entry mie, namespace ns)
ret none[def];
}
fn lookup_in_local_native_mod(&env e, def_id defid, &span sp, &ident id,
namespace ns) -> option::t[def] {
ret lookup_in_local_mod(e, defid, sp, id, ns, inside);
}
// Module indexing
@ -945,9 +972,8 @@ fn index_mod(&ast::_mod md) -> mod_index {
case(ast::view_item_import(?def_ident,_,_)) {
add_to_index(index, def_ident, mie_view_item(it));
}
case(ast::view_item_import_glob(?path,_)) {
//globbed imports have to be resolved lazily.
}
//globbed imports have to be resolved lazily.
case(ast::view_item_import_glob(_,_)) {}
case(ast::view_item_export(_)) {}
}
}
@ -995,6 +1021,7 @@ fn index_nmod(&ast::native_mod md) -> mod_index {
case(ast::view_item_import(?def_ident,_,_)) {
add_to_index(index, def_ident, mie_view_item(it));
}
case(ast::view_item_import_glob(_,_)) {}
case(ast::view_item_export(_)) {}
}
}

View File

@ -1,5 +1,12 @@
// error-pattern: unresolved name
import module_of_many_things::*;
mod module_of_many_things {
export f1, f2, f4;
export f1;
export f2;
export f4;
fn f1() {
log "f1";
}
@ -14,11 +21,10 @@ mod module_of_many_things {
}
}
import module_of_many_things::*;
fn main() {
f1();
f2();
f3();
f999(); // 'export' currently doesn't work?
f4();
}

View File

@ -0,0 +1,29 @@
// error-pattern: unresolved name
mod circ1 {
import circ1::*;
fn f1() {
log "f1";
}
fn common() -> uint {
ret 0u;
}
}
mod circ2 {
import circ2::*;
fn f2() {
log "f2";
}
fn common() -> uint {
ret 1u;
}
}
mod test {
import circ1::*;
fn test() {
f1066();
}
}

View File

@ -31,7 +31,6 @@ mod dug {
fn also_redstone() {
log "Whatever.";
}
fn f1() {}
}
}
}

View File

@ -1,4 +1,4 @@
import a1:b1::word_traveler;
import a1::b1::word_traveler;
mod a1 { //
mod b1 { //

View File

@ -0,0 +1,47 @@
import test1::*;
import test2::*;
mod circ1 {
import circ1::*;
fn f1() {
log "f1";
}
fn common() -> uint {
ret 0u;
}
}
mod circ2 {
import circ2::*;
fn f2() {
log "f2";
}
fn common() -> uint {
ret 1u;
}
}
mod test1 {
import circ1::*;
fn test1() {
f1();
f2();
assert(common() == 0u);
}
}
mod test2 {
import circ2::*;
fn test2() {
f1();
f2();
assert(common() == 1u);
}
}
fn main() {
test1();
test2();
}