diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index cee46b2b054..8ae7b6e3592 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -159,12 +159,17 @@ fn encode_item_paths(ebml_w: ebml::writer, ecx: @encode_ctxt, crate: @crate) fn encode_reexport_paths(ebml_w: ebml::writer, ecx: @encode_ctxt, &index: [entry]) { - ecx.ccx.exp_map.items {|path, defs| - for def in *defs { + let tcx = ecx.ccx.tcx; + ecx.ccx.exp_map.items {|exp_id, defs| + for def in defs { + if !def.reexp { cont; } + let path = alt check tcx.items.get(exp_id) { + ast_map::node_export(_, path) { ast_map::path_to_str(*path) } + }; index += [{val: path, pos: ebml_w.writer.tell()}]; ebml_w.start_tag(tag_paths_data_item); encode_name(ebml_w, path); - encode_def_id(ebml_w, ast_util::def_id_of_def(def)); + encode_def_id(ebml_w, def.id); ebml_w.end_tag(); } } diff --git a/src/rustc/middle/ast_map.rs b/src/rustc/middle/ast_map.rs index b950ac03e49..3ff8a96f287 100644 --- a/src/rustc/middle/ast_map.rs +++ b/src/rustc/middle/ast_map.rs @@ -27,6 +27,7 @@ enum ast_node { node_method(@method, def_id /* impl did */, @path /* path to the impl */), node_variant(variant, def_id, @path), node_expr(@expr), + node_export(@view_path, @path), // Locals are numbered, because the alias analysis needs to know in which // order they are introduced. node_arg(arg, uint), @@ -38,6 +39,10 @@ type map = std::map::map; type ctx = {map: map, mutable path: path, mutable local_id: uint}; type vt = visit::vt; +fn extend(cx: ctx, elt: str) -> @path { + @(cx.path + [path_name(elt)]) +} + fn mk_ast_map_visitor() -> vt { ret visit::mk_vt(@{ visit_item: map_item, @@ -45,7 +50,8 @@ fn mk_ast_map_visitor() -> vt { visit_expr: map_expr, visit_fn: map_fn, visit_local: map_local, - visit_arm: map_arm + visit_arm: map_arm, + visit_view_item: map_view_item with *visit::default_visitor() }); } @@ -140,20 +146,38 @@ fn map_item(i: @item, cx: ctx, v: vt) { item_enum(vs, _) { for v in vs { cx.map.insert(v.node.id, node_variant( - v, ast_util::local_def(i.id), - @(cx.path + [path_name(i.ident)]))); + v, ast_util::local_def(i.id), extend(cx, i.ident))); } } _ { } } alt i.node { - item_mod(_) | item_native_mod(_) { cx.path += [path_mod(i.ident)]; } + item_mod(_) | item_native_mod(_) { + cx.path += [path_mod(i.ident)]; + } _ { cx.path += [path_name(i.ident)]; } } visit::visit_item(i, cx, v); vec::pop(cx.path); } +fn map_view_item(vi: @view_item, cx: ctx, _v: vt) { + alt vi.node { + view_item_export(vps) { + for vp in vps { + let (id, name) = alt vp.node { + view_path_simple(nm, _, id) { (id, nm) } + view_path_glob(pth, id) | view_path_list(pth, _, id) { + (id, vec::last_total(*pth)) + } + }; + cx.map.insert(id, node_export(vp, extend(cx, name))); + } + } + _ {} + } +} + fn map_native_item(i: @native_item, cx: ctx, v: vt) { cx.map.insert(i.id, node_native_item(i, @cx.path)); visit::visit_native_item(i, cx, v); diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs index b48622fb1b9..af71d57dded 100644 --- a/src/rustc/middle/resolve.rs +++ b/src/rustc/middle/resolve.rs @@ -8,7 +8,7 @@ import front::attr; import metadata::{csearch, cstore}; import driver::session::session; import util::common::*; -import std::map::{new_int_hash, new_str_hash}; +import std::map::{new_int_hash, new_str_hash, mk_hashmap}; import syntax::codemap::span; import syntax::visit; import visit::vt; @@ -117,16 +117,18 @@ type indexed_mod = { type def_map = hashmap; type ext_map = hashmap; -type exp_map = hashmap; type impl_map = hashmap; type impl_cache = hashmap>; +type exp = {reexp: bool, id: def_id}; +type exp_map = hashmap; + type env = {cstore: cstore::cstore, def_map: def_map, ast_map: ast_map::map, imports: hashmap, - exp_map: exp_map, + mutable exp_map: exp_map, mod_map: hashmap, block_map: hashmap, ext_map: ext_map, @@ -188,7 +190,7 @@ fn create_env(sess: session, amap: ast_map::map) -> @env { def_map: new_int_hash(), ast_map: amap, imports: new_int_hash(), - exp_map: new_str_hash(), + mutable exp_map: new_int_hash(), mod_map: new_int_hash(), block_map: new_int_hash(), ext_map: new_def_hash(), @@ -2005,63 +2007,59 @@ fn check_exports(e: @env) { - fn lookup_glob_any(e: @env, info: @indexed_mod, sp: span, path: str, - ident: ident) -> bool { - let lookup = - bind lookup_glob_in_mod(*e, info, sp, ident, _, inside); - let (m, v, t) = (lookup(ns_module), - lookup(ns_val(value_or_enum)), - lookup(ns_type)); - let full_path = path + ident; - maybe_add_reexport(e, full_path, m); - maybe_add_reexport(e, full_path, v); - maybe_add_reexport(e, full_path, t); + fn lookup_glob_any(e: @env, info: @indexed_mod, sp: span, + ident: ident, export_id: node_id) -> bool { + let m = lookup_glob_in_mod(*e, info, sp, ident, ns_module, inside); + let v = lookup_glob_in_mod(*e, info, sp, ident, ns_val(value_or_enum), + inside); + let t = lookup_glob_in_mod(*e, info, sp, ident, ns_type, inside); + maybe_add_reexport(e, export_id, m); + maybe_add_reexport(e, export_id, v); + maybe_add_reexport(e, export_id, t); is_some(m) || is_some(v) || is_some(t) } - fn maybe_add_reexport(e: @env, path: str, def: option) { - alt def { - some(def) { - alt e.exp_map.find(path) { - some(v) { - // If there are multiple reexports of the same def - // using the same path, then we only need one copy - if !vec::contains(*v, def) { - *v += [def]; - } - } - none { e.exp_map.insert(path, @mutable [def]); } - } - } - _ {} + + fn maybe_add_reexport(e: @env, export_id: node_id, def: option) { + option::may(def) {|def| + add_export(e, export_id, def_id_of_def(def), true); } } + fn add_export(e: @env, export_id: node_id, target_id: def_id, + reexp: bool) { + let found = alt e.exp_map.find(export_id) { + some(f) { f } none { [] } + }; + e.exp_map.insert(export_id, found + [{reexp: reexp, id: target_id}]); + } fn check_export(e: @env, ident: str, _mod: @indexed_mod, - vi: @view_item) { + export_id: node_id, vi: @view_item) { let found_something = false; - let full_path = _mod.path + ident; if _mod.index.contains_key(ident) { found_something = true; let xs = _mod.index.get(ident); list::iter(xs) {|x| alt x { mie_import_ident(id, _) { - alt e.imports.get(id) { + alt check e.imports.get(id) { resolved(v, t, m, _, rid, _) { - maybe_add_reexport(e, full_path, v); - maybe_add_reexport(e, full_path, t); - maybe_add_reexport(e, full_path, m); + maybe_add_reexport(e, export_id, v); + maybe_add_reexport(e, export_id, t); + maybe_add_reexport(e, export_id, m); } - _ { } } } + mie_item(@{id, _}) | mie_native_item(@{id, _}) | + mie_enum_variant(_, _, id, _) { + add_export(e, export_id, local_def(id), false); + } _ { } } } } - found_something |= lookup_glob_any(e, _mod, vi.span, - _mod.path, ident); + found_something |= lookup_glob_any(e, _mod, vi.span, ident, + export_id); if !found_something { e.sess.span_warn(vi.span, #fmt("exported item %s is not defined", ident)); @@ -2071,64 +2069,54 @@ fn check_exports(e: @env) { fn check_enum_ok(e: @env, sp:span, id: ident, _mod: @indexed_mod) -> node_id { alt _mod.index.find(id) { - none { e.sess.span_fatal(sp, #fmt("undefined id %s \ - in an export", id)); } - some(ms) { - let maybe_id = list::find(ms) {|m| - alt m { - mie_item(an_item) { - alt an_item.node { - item_enum(_,_) { /* OK */ some(an_item.id) } - _ { none } - } - } - _ { none } - } - }; - alt maybe_id { - some(an_id) { ret an_id; } - _ { e.sess.span_fatal(sp, #fmt("%s does not refer \ - to an enumeration", id)); } - } - } - } + none { + e.sess.span_fatal(sp, #fmt("undefined id %s in an export", id)); + } + some(ms) { + let maybe_id = list::find(ms) {|m| + alt m { + mie_item(@{node: item_enum(_, _), id, _}) { some(id) } + _ { none } + } + }; + alt maybe_id { + some(an_id) { an_id } + _ { e.sess.span_fatal(sp, #fmt("%s does not refer \ + to an enumeration", id)); } + } + } + } } - fn check_export_enum_list(e: @env, _mod: @indexed_mod, + fn check_export_enum_list(e: @env, export_id: node_id, _mod: @indexed_mod, span: codemap::span, id: ast::ident, ids: [ast::path_list_ident]) { - if vec::len(ids) == 0u { - let _ = check_enum_ok(e, span, id, _mod); - } else { - let parent_id = check_enum_ok(e, span, id, _mod); - for variant_id in ids { - alt _mod.index.find(variant_id.node.name) { - some(ms) { - list::iter(ms) {|m| - alt m { - mie_enum_variant(_, _, actual_parent_id, _) { - if actual_parent_id != parent_id { - let msg = #fmt("variant %s \ - doesn't belong to enum %s", - variant_id.node.name, - id); - e.sess.span_err(span, msg); - } - } - _ { - e.sess.span_err(span, - #fmt("%s is not a variant", - variant_id.node.name)); - } + let parent_id = check_enum_ok(e, span, id, _mod); + add_export(e, export_id, local_def(parent_id), false); + for variant_id in ids { + let found = false; + alt _mod.index.find(variant_id.node.name) { + some(ms) { + list::iter(ms) {|m| + alt m { + mie_enum_variant(_, _, actual_parent_id, _) { + found = true; + if actual_parent_id != parent_id { + e.sess.span_err( + span, #fmt("variant %s doesn't belong to \ + enum %s", + variant_id.node.name, id)); } + } + _ {} } - } - _ { - e.sess.span_err(span, - #fmt("%s is not a variant", - variant_id.node.name)); - } } + } + _ {} + } + if !found { + e.sess.span_err(span, #fmt("%s is not a variant", + variant_id.node.name)); } } } @@ -2141,17 +2129,17 @@ fn check_exports(e: @env) { for vi in m.view_items { iter_export_paths(*vi) { |vp| alt vp.node { - ast::view_path_simple(ident, _, _) { - check_export(e, ident, _mod, vi); + ast::view_path_simple(ident, _, id) { + check_export(e, ident, _mod, id, vi); } - ast::view_path_list(path, ids, _) { + ast::view_path_list(path, ids, node_id) { let id = if vec::len(*path) == 1u { path[0] } else { - e.sess.span_fatal(vp.span, - #fmt("bad export name-list")) + e.sess.span_fatal(vp.span, "bad export name-list") }; - check_export_enum_list(e, _mod, vp.span, id, ids); + check_export_enum_list(e, node_id, _mod, vp.span, id, + ids); } ast::view_path_glob(_, node_id) { glob_is_re_exported.insert(node_id, ()); @@ -2162,18 +2150,14 @@ fn check_exports(e: @env) { // Now follow the export-glob links and fill in the // globbed_exports and exp_map lists. for glob in _mod.glob_imports { - alt check glob.path.node { - ast::view_path_glob(path, node_id) { - if ! glob_is_re_exported.contains_key(node_id) { - cont; - } - } - } + let id = alt check glob.path.node { + ast::view_path_glob(_, node_id) { node_id } + }; + if ! glob_is_re_exported.contains_key(id) { cont; } iter_mod(*e, glob.def, glob.path.span, outside) {|ident, def| - let full_path = _mod.path + ident; _mod.globbed_exports += [ident]; - maybe_add_reexport(e, full_path, some(def)); + maybe_add_reexport(e, id, some(def)); } } } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index f841b9e0ed3..b940b55d642 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -2216,7 +2216,8 @@ fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path { } ast_map::node_expr(_) | ast_map::node_arg(_, _) | - ast_map::node_local(_) | ast_map::node_res_ctor(_) { + ast_map::node_local(_) | ast_map::node_res_ctor(_) | + ast_map::node_export(_, _) { cx.sess.bug(#fmt["cannot find item_path for node %?", node]); } } diff --git a/src/rustdoc/reexport_pass.rs b/src/rustdoc/reexport_pass.rs index d5e61692719..ddbbf3d96d4 100644 --- a/src/rustdoc/reexport_pass.rs +++ b/src/rustdoc/reexport_pass.rs @@ -4,6 +4,7 @@ import std::map; import rustc::syntax::ast; import rustc::syntax::ast_util; import rustc::util::common; +import rustc::middle::ast_map; export mk_pass; @@ -75,10 +76,11 @@ fn from_str_assoc_list( fn build_reexport_def_set(srv: astsrv::srv) -> def_set { let assoc_list = astsrv::exec(srv) {|ctxt| let def_set = common::new_def_hash(); - ctxt.exp_map.items {|_path, defs| - for def in *defs { - let def_id = ast_util::def_id_of_def(def); - def_set.insert(def_id, ()); + ctxt.exp_map.items {|_id, defs| + for def in defs { + if def.reexp { + def_set.insert(def.id, ()); + } } } to_assoc_list(def_set) @@ -154,29 +156,32 @@ fn build_reexport_path_map(srv: astsrv::srv, -def_map: def_map) -> path_map { let def_map = from_def_assoc_list(def_assoc_list); let path_map = map::new_str_hash(); - ctxt.exp_map.items {|path, defs| - - let path = str::split_str(path, "::"); - let modpath = str::connect(vec::init(path), "::"); - let name = option::get(vec::last(path)); + ctxt.exp_map.items {|exp_id, defs| + let path = alt check ctxt.ast_map.get(exp_id) { + ast_map::node_export(_, path) { path } + }; + let name = alt check vec::last_total(*path) { + ast_map::path_name(nm) { nm } + }; + let modpath = ast_map::path_to_str(vec::init(*path)); let reexportdocs = []; - for def in *defs { - let def_id = ast_util::def_id_of_def(def); - alt def_map.find(def_id) { + for def in defs { + if !def.reexp { cont; } + alt def_map.find(def.id) { some(itemtag) { reexportdocs += [(name, itemtag)]; } - none { } + _ {} } } - if vec::is_not_empty(reexportdocs) { - let prevdocs = alt path_map.find(modpath) { - some(docs) { docs } - none { [] } - }; - let reexportdocs = prevdocs + reexportdocs; + if reexportdocs.len() > 0u { + option::may(path_map.find(modpath)) {|docs| + reexportdocs = docs + vec::filter(reexportdocs, {|x| + !vec::contains(docs, x) + }); + } path_map.insert(modpath, reexportdocs); #debug("path_map entry: %? - %?", modpath, (name, reexportdocs));