2012-03-06 05:52:13 -06:00
|
|
|
// Finds items that are externally reachable, to determine which items
|
|
|
|
// need to have their metadata (and possibly their AST) serialized.
|
|
|
|
// All items that can be referred to through an exported name are
|
|
|
|
// reachable, and when a reachable thing is inline or generic, it
|
|
|
|
// makes all other generics or inline functions that it references
|
|
|
|
// reachable as well.
|
|
|
|
|
2012-09-04 13:54:36 -05:00
|
|
|
use syntax::ast::*;
|
|
|
|
use syntax::{visit, ast_util, ast_map};
|
|
|
|
use syntax::ast_util::def_id_of_def;
|
|
|
|
use syntax::attr;
|
|
|
|
use syntax::print::pprust::expr_to_str;
|
2012-09-10 17:38:28 -05:00
|
|
|
use std::map::HashMap;
|
2012-09-04 13:54:36 -05:00
|
|
|
use driver::session::*;
|
2012-03-06 05:52:13 -06:00
|
|
|
|
|
|
|
export map, find_reachable;
|
|
|
|
|
2012-09-10 17:38:28 -05:00
|
|
|
type map = std::map::HashMap<node_id, ()>;
|
2012-03-06 05:52:13 -06:00
|
|
|
|
2012-09-20 15:08:45 -05:00
|
|
|
type ctx = {exp_map2: resolve::ExportMap2,
|
2012-03-20 06:28:46 -05:00
|
|
|
tcx: ty::ctxt,
|
|
|
|
method_map: typeck::method_map,
|
2012-03-06 05:52:13 -06:00
|
|
|
rmap: map};
|
|
|
|
|
2012-09-20 15:08:45 -05:00
|
|
|
fn find_reachable(crate_mod: _mod, exp_map2: resolve::ExportMap2,
|
2012-03-20 06:28:46 -05:00
|
|
|
tcx: ty::ctxt, method_map: typeck::method_map) -> map {
|
2012-09-19 17:13:04 -05:00
|
|
|
let rmap = std::map::HashMap();
|
2012-09-20 15:08:45 -05:00
|
|
|
let cx = {exp_map2: exp_map2, tcx: tcx,
|
|
|
|
method_map: method_map, rmap: rmap};
|
|
|
|
traverse_public_mod(cx, ast::crate_node_id, crate_mod);
|
2012-07-11 20:38:12 -05:00
|
|
|
traverse_all_resources_and_impls(cx, crate_mod);
|
2012-03-06 05:52:13 -06:00
|
|
|
rmap
|
|
|
|
}
|
|
|
|
|
2012-09-20 15:08:45 -05:00
|
|
|
fn traverse_exports(cx: ctx, mod_id: node_id) -> bool {
|
2012-03-15 08:47:03 -05:00
|
|
|
let mut found_export = false;
|
2012-09-20 15:08:45 -05:00
|
|
|
match cx.exp_map2.find(mod_id) {
|
|
|
|
Some(exp2s) => {
|
|
|
|
for exp2s.each |e2| {
|
2012-03-06 05:52:13 -06:00
|
|
|
found_export = true;
|
2012-09-20 15:08:45 -05:00
|
|
|
traverse_def_id(cx, e2.def_id)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
None => ()
|
2012-03-06 05:52:13 -06:00
|
|
|
}
|
2012-09-20 15:08:45 -05:00
|
|
|
return found_export;
|
2012-03-06 05:52:13 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fn traverse_def_id(cx: ctx, did: def_id) {
|
2012-08-01 19:30:05 -05:00
|
|
|
if did.crate != local_crate { return; }
|
2012-08-06 14:34:08 -05:00
|
|
|
let n = match cx.tcx.items.find(did.node) {
|
2012-08-20 14:23:37 -05:00
|
|
|
None => return, // This can happen for self, for example
|
|
|
|
Some(n) => n
|
2012-06-12 18:25:09 -05:00
|
|
|
};
|
2012-08-06 14:34:08 -05:00
|
|
|
match n {
|
2012-08-03 21:59:04 -05:00
|
|
|
ast_map::node_item(item, _) => traverse_public_item(cx, item),
|
|
|
|
ast_map::node_method(_, impl_id, _) => traverse_def_id(cx, impl_id),
|
|
|
|
ast_map::node_foreign_item(item, _, _) => {
|
|
|
|
cx.rmap.insert(item.id, ());
|
|
|
|
}
|
|
|
|
ast_map::node_variant(v, _, _) => { cx.rmap.insert(v.node.id, ()); }
|
|
|
|
_ => ()
|
2012-03-06 05:52:13 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-20 15:08:45 -05:00
|
|
|
fn traverse_public_mod(cx: ctx, mod_id: node_id, m: _mod) {
|
|
|
|
if !traverse_exports(cx, mod_id) {
|
2012-03-06 05:52:13 -06:00
|
|
|
// No exports, so every local item is exported
|
2012-09-18 23:41:37 -05:00
|
|
|
for vec::each(m.items) |item| {
|
|
|
|
traverse_public_item(cx, *item);
|
|
|
|
}
|
2012-03-06 05:52:13 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn traverse_public_item(cx: ctx, item: @item) {
|
2012-08-01 19:30:05 -05:00
|
|
|
if cx.rmap.contains_key(item.id) { return; }
|
2012-03-06 05:52:13 -06:00
|
|
|
cx.rmap.insert(item.id, ());
|
2012-08-06 14:34:08 -05:00
|
|
|
match item.node {
|
2012-09-20 15:08:45 -05:00
|
|
|
item_mod(m) => traverse_public_mod(cx, item.id, m),
|
2012-08-03 21:59:04 -05:00
|
|
|
item_foreign_mod(nm) => {
|
2012-09-20 15:08:45 -05:00
|
|
|
if !traverse_exports(cx, item.id) {
|
2012-09-18 23:41:37 -05:00
|
|
|
for vec::each(nm.items) |item| {
|
|
|
|
cx.rmap.insert(item.id, ());
|
|
|
|
}
|
2012-03-06 05:52:13 -06:00
|
|
|
}
|
|
|
|
}
|
2012-08-23 20:17:16 -05:00
|
|
|
item_fn(_, _, tps, blk) => {
|
2012-03-06 05:52:13 -06:00
|
|
|
if tps.len() > 0u ||
|
|
|
|
attr::find_inline_attr(item.attrs) != attr::ia_none {
|
|
|
|
traverse_inline_body(cx, blk);
|
|
|
|
}
|
|
|
|
}
|
2012-11-13 21:08:01 -06:00
|
|
|
item_impl(tps, _, _, ms) => {
|
|
|
|
for vec::each(ms) |m| {
|
|
|
|
if tps.len() > 0u || m.tps.len() > 0u ||
|
|
|
|
attr::find_inline_attr(m.attrs) != attr::ia_none {
|
|
|
|
cx.rmap.insert(m.id, ());
|
|
|
|
traverse_inline_body(cx, m.body);
|
2012-03-06 05:52:13 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-07 17:34:07 -05:00
|
|
|
item_class(struct_def, tps) => {
|
2012-09-21 21:37:57 -05:00
|
|
|
do option::iter(&struct_def.dtor) |dtor| {
|
2012-05-14 16:13:32 -05:00
|
|
|
cx.rmap.insert(dtor.node.id, ());
|
2012-07-16 21:16:19 -05:00
|
|
|
if tps.len() > 0u || attr::find_inline_attr(dtor.node.attrs)
|
|
|
|
!= attr::ia_none {
|
2012-06-12 18:25:09 -05:00
|
|
|
traverse_inline_body(cx, dtor.node.body);
|
|
|
|
}
|
2012-05-14 16:13:32 -05:00
|
|
|
}
|
2012-09-18 23:41:13 -05:00
|
|
|
for vec::each(struct_def.methods) |m| {
|
2012-08-15 17:53:58 -05:00
|
|
|
cx.rmap.insert(m.id, ());
|
|
|
|
if tps.len() > 0 ||
|
|
|
|
attr::find_inline_attr(m.attrs) != attr::ia_none {
|
|
|
|
traverse_inline_body(cx, m.body);
|
2012-03-20 07:19:33 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
item_ty(t, _) => {
|
2012-06-13 13:20:21 -05:00
|
|
|
traverse_ty(t, cx, mk_ty_visitor());
|
|
|
|
}
|
|
|
|
item_const(*) |
|
2012-08-03 21:59:04 -05:00
|
|
|
item_enum(*) | item_trait(*) => (),
|
|
|
|
item_mac(*) => fail ~"item macros unimplemented"
|
2012-03-06 05:52:13 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-13 13:20:21 -05:00
|
|
|
fn mk_ty_visitor() -> visit::vt<ctx> {
|
2012-08-28 17:54:45 -05:00
|
|
|
visit::mk_vt(@{visit_ty: traverse_ty, ..*visit::default_visitor()})
|
2012-06-13 13:20:21 -05:00
|
|
|
}
|
|
|
|
|
2012-10-15 16:56:42 -05:00
|
|
|
fn traverse_ty(ty: @Ty, cx: ctx, v: visit::vt<ctx>) {
|
2012-08-01 19:30:05 -05:00
|
|
|
if cx.rmap.contains_key(ty.id) { return; }
|
2012-06-13 13:20:21 -05:00
|
|
|
cx.rmap.insert(ty.id, ());
|
|
|
|
|
2012-08-06 14:34:08 -05:00
|
|
|
match ty.node {
|
2012-08-03 21:59:04 -05:00
|
|
|
ty_path(p, p_id) => {
|
2012-08-06 14:34:08 -05:00
|
|
|
match cx.tcx.def_map.find(p_id) {
|
2012-06-13 13:20:21 -05:00
|
|
|
// Kind of a hack to check this here, but I'm not sure what else
|
|
|
|
// to do
|
2012-08-20 14:23:37 -05:00
|
|
|
Some(def_prim_ty(_)) => { /* do nothing */ }
|
|
|
|
Some(d) => traverse_def_id(cx, def_id_of_def(d)),
|
|
|
|
None => { /* do nothing -- but should we fail here? */ }
|
2012-06-13 13:20:21 -05:00
|
|
|
}
|
2012-09-19 18:55:01 -05:00
|
|
|
for p.types.each |t| {
|
|
|
|
v.visit_ty(*t, cx, v);
|
|
|
|
}
|
2012-06-13 13:20:21 -05:00
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => visit::visit_ty(ty, cx, v)
|
2012-06-13 13:20:21 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-06 05:52:13 -06:00
|
|
|
fn traverse_inline_body(cx: ctx, body: blk) {
|
|
|
|
fn traverse_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
2012-08-06 14:34:08 -05:00
|
|
|
match e.node {
|
2012-08-03 21:59:04 -05:00
|
|
|
expr_path(_) => {
|
2012-08-06 14:34:08 -05:00
|
|
|
match cx.tcx.def_map.find(e.id) {
|
2012-08-20 14:23:37 -05:00
|
|
|
Some(d) => {
|
2012-06-12 18:25:09 -05:00
|
|
|
traverse_def_id(cx, def_id_of_def(d));
|
|
|
|
}
|
2012-08-20 14:23:37 -05:00
|
|
|
None => cx.tcx.sess.span_bug(e.span, fmt!("Unbound node \
|
2012-07-18 18:18:02 -05:00
|
|
|
id %? while traversing %s", e.id,
|
2012-08-22 19:24:52 -05:00
|
|
|
expr_to_str(e, cx.tcx.sess.intr())))
|
2012-06-12 18:25:09 -05:00
|
|
|
}
|
2012-03-06 05:52:13 -06:00
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
expr_field(_, _, _) => {
|
2012-08-06 14:34:08 -05:00
|
|
|
match cx.method_map.find(e.id) {
|
2012-08-20 14:23:37 -05:00
|
|
|
Some({origin: typeck::method_static(did), _}) => {
|
2012-06-07 12:51:21 -05:00
|
|
|
traverse_def_id(cx, did);
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => ()
|
2012-03-06 05:52:13 -06:00
|
|
|
}
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => ()
|
2012-03-06 05:52:13 -06:00
|
|
|
}
|
|
|
|
visit::visit_expr(e, cx, v);
|
|
|
|
}
|
2012-05-29 16:39:22 -05:00
|
|
|
// Don't ignore nested items: for example if a generic fn contains a
|
|
|
|
// generic impl (as in deque::create), we need to monomorphize the
|
|
|
|
// impl as well
|
|
|
|
fn traverse_item(i: @item, cx: ctx, _v: visit::vt<ctx>) {
|
|
|
|
traverse_public_item(cx, i);
|
|
|
|
}
|
|
|
|
visit::visit_block(body, cx, visit::mk_vt(@{
|
2012-03-06 05:52:13 -06:00
|
|
|
visit_expr: traverse_expr,
|
2012-09-04 15:29:32 -05:00
|
|
|
visit_item: traverse_item,
|
2012-08-28 17:54:45 -05:00
|
|
|
..*visit::default_visitor()
|
2012-03-06 05:52:13 -06:00
|
|
|
}));
|
|
|
|
}
|
2012-03-08 14:16:04 -06:00
|
|
|
|
2012-07-11 20:38:12 -05:00
|
|
|
fn traverse_all_resources_and_impls(cx: ctx, crate_mod: _mod) {
|
2012-03-08 14:16:04 -06:00
|
|
|
visit::visit_mod(crate_mod, ast_util::dummy_sp(), 0, cx, visit::mk_vt(@{
|
2012-06-30 18:19:07 -05:00
|
|
|
visit_expr: |_e, _cx, _v| { },
|
|
|
|
visit_item: |i, cx, v| {
|
2012-03-08 14:16:04 -06:00
|
|
|
visit::visit_item(i, cx, v);
|
2012-08-06 14:34:08 -05:00
|
|
|
match i.node {
|
2012-08-07 17:34:07 -05:00
|
|
|
item_class(struct_def, _) if struct_def.dtor.is_some() => {
|
2012-04-18 23:26:25 -05:00
|
|
|
traverse_public_item(cx, i);
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
item_impl(*) => {
|
2012-07-11 20:38:12 -05:00
|
|
|
traverse_public_item(cx, i);
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => ()
|
2012-03-08 14:16:04 -06:00
|
|
|
}
|
2012-09-04 15:29:32 -05:00
|
|
|
},
|
2012-08-28 17:54:45 -05:00
|
|
|
..*visit::default_visitor()
|
2012-03-08 14:16:04 -06:00
|
|
|
}));
|
|
|
|
}
|
2012-07-11 20:38:12 -05:00
|
|
|
|