about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2012-03-06 13:57:07 +0100
committerMarijn Haverbeke <marijnh@gmail.com>2012-03-06 17:11:30 +0100
commit4e4bd585cd59caeb3a2fb107f1f5ba272149b3ee (patch)
tree2935b3fd86619bcbd189b6eb7e07067a161dfebd /src
parent19508c7d531910c309cd63e9ade2fe1be80ff71b (diff)
downloadrust-4e4bd585cd59caeb3a2fb107f1f5ba272149b3ee.tar.gz
rust-4e4bd585cd59caeb3a2fb107f1f5ba272149b3ee.zip
Track all exports in exp_map
This is needed because the reachability checker needs to be able to
follow exports.

Issue #1934
Diffstat (limited to 'src')
-rw-r--r--src/rustc/metadata/encoder.rs11
-rw-r--r--src/rustc/middle/ast_map.rs32
-rw-r--r--src/rustc/middle/resolve.rs194
-rw-r--r--src/rustc/middle/ty.rs3
-rw-r--r--src/rustdoc/reexport_pass.rs43
5 files changed, 151 insertions, 132 deletions
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<str>]) {
-    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<node_id, ast_node>;
 type ctx = {map: map, mutable path: path, mutable local_id: uint};
 type vt = visit::vt<ctx>;
 
+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<node_id, def>;
 type ext_map = hashmap<def_id, [ident]>;
-type exp_map = hashmap<str, @mutable [def]>;
 type impl_map = hashmap<node_id, iscopes>;
 type impl_cache = hashmap<def_id, option<@[@_impl]>>;
 
+type exp = {reexp: bool, id: def_id};
+type exp_map = hashmap<node_id, [exp]>;
+
 type env =
     {cstore: cstore::cstore,
      def_map: def_map,
      ast_map: ast_map::map,
      imports: hashmap<ast::node_id, import_state>,
-     exp_map: exp_map,
+     mutable exp_map: exp_map,
      mod_map: hashmap<ast::node_id, @indexed_mod>,
      block_map: hashmap<ast::node_id, [glob_imp_def]>,
      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<def>) {
-        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<def>) {
+        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<V:copy>(
 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));