port reachable.rs from oldvisit to <V:Visitor> trait.

This commit is contained in:
Felix S. Klock II 2013-08-13 13:53:13 +02:00
parent 18be88f64a
commit 69e822dcb3

View file

@ -24,8 +24,8 @@ use syntax::ast_map;
use syntax::ast_util::def_id_of_def;
use syntax::attr;
use syntax::parse::token;
use syntax::oldvisit::Visitor;
use syntax::oldvisit;
use syntax::visit::Visitor;
use syntax::visit;
// Returns true if the given set of attributes contains the `#[inline]`
// attribute.
@ -94,40 +94,29 @@ struct ReachableContext {
worklist: @mut ~[NodeId],
}
impl ReachableContext {
// Creates a new reachability computation context.
fn new(tcx: ty::ctxt, method_map: typeck::method_map)
-> ReachableContext {
ReachableContext {
tcx: tcx,
method_map: method_map,
reachable_symbols: @mut HashSet::new(),
worklist: @mut ~[],
}
}
struct ReachableVisitor {
reachable_symbols: @mut HashSet<NodeId>,
worklist: @mut ~[NodeId],
}
impl Visitor<PrivacyContext> for ReachableVisitor {
fn visit_item(&mut self, item:@item, privacy_context:PrivacyContext) {
// Step 1: Mark all public symbols, and add all public symbols that might
// be inlined to a worklist.
fn mark_public_symbols(&self, crate: @Crate) {
let reachable_symbols = self.reachable_symbols;
let worklist = self.worklist;
let visitor = oldvisit::mk_vt(@Visitor {
visit_item: |item, (privacy_context, visitor):
(PrivacyContext, oldvisit::vt<PrivacyContext>)| {
match item.node {
item_fn(*) => {
if privacy_context == PublicContext {
reachable_symbols.insert(item.id);
self.reachable_symbols.insert(item.id);
}
if item_might_be_inlined(item) {
worklist.push(item.id)
self.worklist.push(item.id)
}
}
item_struct(ref struct_def, _) => {
match struct_def.ctor_id {
Some(ctor_id) if
privacy_context == PublicContext => {
reachable_symbols.insert(ctor_id);
self.reachable_symbols.insert(ctor_id);
}
Some(_) | None => {}
}
@ -135,7 +124,7 @@ impl ReachableContext {
item_enum(ref enum_def, _) => {
if privacy_context == PublicContext {
for variant in enum_def.variants.iter() {
reachable_symbols.insert(variant.node.id);
self.reachable_symbols.insert(variant.node.id);
}
}
}
@ -155,7 +144,7 @@ impl ReachableContext {
// Mark all public methods as reachable.
for &method in methods.iter() {
if should_be_considered_public(method) {
reachable_symbols.insert(method.id);
self.reachable_symbols.insert(method.id);
}
}
@ -164,7 +153,7 @@ impl ReachableContext {
// symbols to the worklist.
for &method in methods.iter() {
if should_be_considered_public(method) {
worklist.push(method.id)
self.worklist.push(method.id)
}
}
} else {
@ -176,7 +165,7 @@ impl ReachableContext {
if generics_require_inlining(generics) ||
attributes_specify_inlining(*attrs) ||
should_be_considered_public(*method) {
worklist.push(method.id)
self.worklist.push(method.id)
}
}
}
@ -187,8 +176,8 @@ impl ReachableContext {
for trait_method in trait_methods.iter() {
match *trait_method {
provided(method) => {
reachable_symbols.insert(method.id);
worklist.push(method.id)
self.reachable_symbols.insert(method.id);
self.worklist.push(method.id)
}
required(_) => {}
}
@ -199,15 +188,97 @@ impl ReachableContext {
}
if item.vis == public && privacy_context == PublicContext {
oldvisit::visit_item(item, (PublicContext, visitor))
visit::walk_item(self, item, PublicContext)
} else {
oldvisit::visit_item(item, (PrivateContext, visitor))
visit::walk_item(self, item, PrivateContext)
}
},
.. *oldvisit::default_visitor()
});
}
oldvisit::visit_crate(crate, (PublicContext, visitor))
}
struct MarkSymbolVisitor {
worklist: @mut ~[NodeId],
method_map: typeck::method_map,
tcx: ty::ctxt,
reachable_symbols: @mut HashSet<NodeId>,
}
impl Visitor<()> for MarkSymbolVisitor {
fn visit_expr(&mut self, expr:@expr, _:()) {
match expr.node {
expr_path(_) => {
let def = match self.tcx.def_map.find(&expr.id) {
Some(&def) => def,
None => {
self.tcx.sess.span_bug(expr.span,
"def ID not in def map?!")
}
};
let def_id = def_id_of_def(def);
if ReachableContext::
def_id_represents_local_inlined_item(self.tcx,
def_id) {
self.worklist.push(def_id.node)
}
self.reachable_symbols.insert(def_id.node);
}
expr_method_call(*) => {
match self.method_map.find(&expr.id) {
Some(&typeck::method_map_entry {
origin: typeck::method_static(def_id),
_
}) => {
if ReachableContext::
def_id_represents_local_inlined_item(
self.tcx,
def_id) {
self.worklist.push(def_id.node)
}
self.reachable_symbols.insert(def_id.node);
}
Some(_) => {}
None => {
self.tcx.sess.span_bug(expr.span,
"method call expression \
not in method map?!")
}
}
}
_ => {}
}
visit::walk_expr(self, expr, ())
}
}
impl ReachableContext {
// Creates a new reachability computation context.
fn new(tcx: ty::ctxt, method_map: typeck::method_map)
-> ReachableContext {
ReachableContext {
tcx: tcx,
method_map: method_map,
reachable_symbols: @mut HashSet::new(),
worklist: @mut ~[],
}
}
// Step 1: Mark all public symbols, and add all public symbols that might
// be inlined to a worklist.
fn mark_public_symbols(&self, crate: @Crate) {
let reachable_symbols = self.reachable_symbols;
let worklist = self.worklist;
let mut visitor = ReachableVisitor {
reachable_symbols: reachable_symbols,
worklist: worklist,
};
visit::walk_crate(&mut visitor, crate, PublicContext);
}
// Returns true if the given def ID represents a local item that is
@ -269,63 +340,21 @@ impl ReachableContext {
}
// Helper function to set up a visitor for `propagate()` below.
fn init_visitor(&self) -> oldvisit::vt<()> {
fn init_visitor(&self) -> MarkSymbolVisitor {
let (worklist, method_map) = (self.worklist, self.method_map);
let (tcx, reachable_symbols) = (self.tcx, self.reachable_symbols);
oldvisit::mk_vt(@oldvisit::Visitor {
visit_expr: |expr, (_, visitor)| {
match expr.node {
expr_path(_) => {
let def = match tcx.def_map.find(&expr.id) {
Some(&def) => def,
None => {
tcx.sess.span_bug(expr.span,
"def ID not in def map?!")
}
};
let def_id = def_id_of_def(def);
if ReachableContext::
def_id_represents_local_inlined_item(tcx,
def_id) {
worklist.push(def_id.node)
}
reachable_symbols.insert(def_id.node);
}
expr_method_call(*) => {
match method_map.find(&expr.id) {
Some(&typeck::method_map_entry {
origin: typeck::method_static(def_id),
_
}) => {
if ReachableContext::
def_id_represents_local_inlined_item(
tcx,
def_id) {
worklist.push(def_id.node)
}
reachable_symbols.insert(def_id.node);
}
Some(_) => {}
None => {
tcx.sess.span_bug(expr.span,
"method call expression \
not in method map?!")
}
}
}
_ => {}
}
oldvisit::visit_expr(expr, ((), visitor))
},
..*oldvisit::default_visitor()
})
MarkSymbolVisitor {
worklist: worklist,
method_map: method_map,
tcx: tcx,
reachable_symbols: reachable_symbols,
}
}
// Step 2: Mark all symbols that the symbols on the worklist touch.
fn propagate(&self) {
let visitor = self.init_visitor();
let mut visitor = self.init_visitor();
let mut scanned = HashSet::new();
while self.worklist.len() > 0 {
let search_item = self.worklist.pop();
@ -342,7 +371,7 @@ impl ReachableContext {
Some(&ast_map::node_item(item, _)) => {
match item.node {
item_fn(_, _, _, _, ref search_block) => {
oldvisit::visit_block(search_block, ((), visitor))
visit::walk_block(&mut visitor, search_block, ())
}
_ => {
self.tcx.sess.span_bug(item.span,
@ -359,12 +388,12 @@ impl ReachableContext {
worklist?!")
}
provided(ref method) => {
oldvisit::visit_block(&method.body, ((), visitor))
visit::walk_block(&mut visitor, &method.body, ())
}
}
}
Some(&ast_map::node_method(ref method, _, _)) => {
oldvisit::visit_block(&method.body, ((), visitor))
visit::walk_block(&mut visitor, &method.body, ())
}
Some(_) => {
let ident_interner = token::get_ident_interner();