diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 160cc23bd19..0530ffd30b4 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -17,7 +17,30 @@ use util::ppaux; use syntax::ast::*; use syntax::codemap; -use syntax::{oldvisit, ast_util, ast_map}; +use syntax::{ast_util, ast_map}; +use syntax::visit::Visitor; +use syntax::visit; + +struct CheckCrateVisitor { + sess: Session, + ast_map: ast_map::map, + def_map: resolve::DefMap, + method_map: typeck::method_map, + tcx: ty::ctxt, +} + +impl Visitor for CheckCrateVisitor { + fn visit_item(&mut self, i:@item, env:bool) { + check_item(self, self.sess, self.ast_map, self.def_map, i, env); + } + fn visit_pat(&mut self, p:@pat, env:bool) { + check_pat(self, p, env); + } + fn visit_expr(&mut self, ex:@expr, env:bool) { + check_expr(self, self.sess, self.def_map, self.method_map, + self.tcx, ex, env); + } +} pub fn check_crate(sess: Session, crate: &Crate, @@ -25,39 +48,40 @@ pub fn check_crate(sess: Session, def_map: resolve::DefMap, method_map: typeck::method_map, tcx: ty::ctxt) { - oldvisit::visit_crate(crate, (false, oldvisit::mk_vt(@oldvisit::Visitor { - visit_item: |a,b| check_item(sess, ast_map, def_map, a, b), - visit_pat: check_pat, - visit_expr: |a,b| - check_expr(sess, def_map, method_map, tcx, a, b), - .. *oldvisit::default_visitor() - }))); + let mut v = CheckCrateVisitor { + sess: sess, + ast_map: ast_map, + def_map: def_map, + method_map: method_map, + tcx: tcx, + }; + visit::walk_crate(&mut v, crate, false); sess.abort_if_errors(); } -pub fn check_item(sess: Session, +pub fn check_item(v: &mut CheckCrateVisitor, + sess: Session, ast_map: ast_map::map, def_map: resolve::DefMap, it: @item, - (_is_const, v): (bool, - oldvisit::vt)) { + _is_const: bool) { match it.node { item_static(_, _, ex) => { - (v.visit_expr)(ex, (true, v)); + v.visit_expr(ex, true); check_item_recursion(sess, ast_map, def_map, it); } item_enum(ref enum_definition, _) => { for var in (*enum_definition).variants.iter() { for ex in var.node.disr_expr.iter() { - (v.visit_expr)(*ex, (true, v)); + v.visit_expr(*ex, true); } } } - _ => oldvisit::visit_item(it, (false, v)) + _ => visit::walk_item(v, it, false) } } -pub fn check_pat(p: @pat, (_is_const, v): (bool, oldvisit::vt)) { +pub fn check_pat(v: &mut CheckCrateVisitor, p: @pat, _is_const: bool) { fn is_str(e: @expr) -> bool { match e.node { expr_vstore( @@ -72,22 +96,22 @@ pub fn check_pat(p: @pat, (_is_const, v): (bool, oldvisit::vt)) { } match p.node { // Let through plain ~-string literals here - pat_lit(a) => if !is_str(a) { (v.visit_expr)(a, (true, v)); }, + pat_lit(a) => if !is_str(a) { v.visit_expr(a, true); }, pat_range(a, b) => { - if !is_str(a) { (v.visit_expr)(a, (true, v)); } - if !is_str(b) { (v.visit_expr)(b, (true, v)); } + if !is_str(a) { v.visit_expr(a, true); } + if !is_str(b) { v.visit_expr(b, true); } } - _ => oldvisit::visit_pat(p, (false, v)) + _ => visit::walk_pat(v, p, false) } } -pub fn check_expr(sess: Session, +pub fn check_expr(v: &mut CheckCrateVisitor, + sess: Session, def_map: resolve::DefMap, method_map: typeck::method_map, tcx: ty::ctxt, e: @expr, - (is_const, v): (bool, - oldvisit::vt)) { + is_const: bool) { if is_const { match e.node { expr_unary(_, deref, _) => { } @@ -152,8 +176,8 @@ pub fn check_expr(sess: Session, } } } - expr_paren(e) => { check_expr(sess, def_map, method_map, - tcx, e, (is_const, v)); } + expr_paren(e) => { check_expr(v, sess, def_map, method_map, + tcx, e, is_const); } expr_vstore(_, expr_vstore_slice) | expr_vec(_, m_imm) | expr_addr_of(m_imm, _) | @@ -192,7 +216,7 @@ pub fn check_expr(sess: Session, } _ => () } - oldvisit::visit_expr(e, (is_const, v)); + visit::walk_expr(v, e, is_const); } #[deriving(Clone)] @@ -204,6 +228,8 @@ struct env { idstack: @mut ~[NodeId] } +struct CheckItemRecursionVisitor; + // Make sure a const item doesn't recursively refer to itself // FIXME: Should use the dependency graph when it's available (#1356) pub fn check_item_recursion(sess: Session, @@ -218,29 +244,27 @@ pub fn check_item_recursion(sess: Session, idstack: @mut ~[] }; - let visitor = oldvisit::mk_vt(@oldvisit::Visitor { - visit_item: visit_item, - visit_expr: visit_expr, - .. *oldvisit::default_visitor() - }); - (visitor.visit_item)(it, (env, visitor)); + let mut visitor = CheckItemRecursionVisitor; + visitor.visit_item(it, env); +} - fn visit_item(it: @item, (env, v): (env, oldvisit::vt)) { +impl Visitor for CheckItemRecursionVisitor { + fn visit_item(&mut self, it: @item, env: env) { if env.idstack.iter().any(|x| x == &(it.id)) { env.sess.span_fatal(env.root_it.span, "recursive constant"); } env.idstack.push(it.id); - oldvisit::visit_item(it, (env, v)); + visit::walk_item(self, it, env); env.idstack.pop(); } - fn visit_expr(e: @expr, (env, v): (env, oldvisit::vt)) { + fn visit_expr(&mut self, e: @expr, env: env) { match e.node { expr_path(*) => match env.def_map.find(&e.id) { Some(&def_static(def_id, _)) if ast_util::is_local(def_id) => match env.ast_map.get_copy(&def_id.node) { ast_map::node_item(it, _) => { - (v.visit_item)(it, (env, v)); + self.visit_item(it, env); } _ => fail!("const not bound to an item") }, @@ -248,6 +272,6 @@ pub fn check_item_recursion(sess: Session, }, _ => () } - oldvisit::visit_expr(e, (env, v)); + visit::walk_expr(self, e, env); } } diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs index cbd1d3cd9ad..35705dff6ef 100644 --- a/src/librustc/middle/check_loop.rs +++ b/src/librustc/middle/check_loop.rs @@ -12,7 +12,8 @@ use middle::ty; use syntax::ast::*; -use syntax::oldvisit; +use syntax::visit; +use syntax::visit::Visitor; #[deriving(Clone)] pub struct Context { @@ -20,50 +21,55 @@ pub struct Context { can_ret: bool } +struct CheckLoopVisitor { + tcx: ty::ctxt, +} + pub fn check_crate(tcx: ty::ctxt, crate: &Crate) { - oldvisit::visit_crate(crate, - (Context { in_loop: false, can_ret: true }, - oldvisit::mk_vt(@oldvisit::Visitor { - visit_item: |i, (_cx, v)| { - oldvisit::visit_item(i, (Context { + visit::walk_crate(&mut CheckLoopVisitor { tcx: tcx }, + crate, + Context { in_loop: false, can_ret: true }); +} + +impl Visitor for CheckLoopVisitor { + fn visit_item(&mut self, i:@item, _cx:Context) { + visit::walk_item(self, i, Context { in_loop: false, can_ret: true - }, v)); - }, - visit_expr: |e: @expr, (cx, v): (Context, oldvisit::vt)| { + }); + } + + fn visit_expr(&mut self, e:@expr, cx:Context) { + match e.node { expr_while(e, ref b) => { - (v.visit_expr)(e, (cx, v)); - (v.visit_block)(b, (Context { in_loop: true,.. cx }, v)); + self.visit_expr(e, cx); + self.visit_block(b, Context { in_loop: true,.. cx }); } expr_loop(ref b, _) => { - (v.visit_block)(b, (Context { in_loop: true,.. cx }, v)); + self.visit_block(b, Context { in_loop: true,.. cx }); } expr_fn_block(_, ref b) => { - (v.visit_block)(b, (Context { - in_loop: false, - can_ret: false - }, v)); + self.visit_block(b, Context { in_loop: false, can_ret: false }); } expr_break(_) => { if !cx.in_loop { - tcx.sess.span_err(e.span, "`break` outside of loop"); + self.tcx.sess.span_err(e.span, "`break` outside of loop"); } } expr_again(_) => { if !cx.in_loop { - tcx.sess.span_err(e.span, "`loop` outside of loop"); + self.tcx.sess.span_err(e.span, "`loop` outside of loop"); } } expr_ret(oe) => { if !cx.can_ret { - tcx.sess.span_err(e.span, "`return` in block function"); + self.tcx.sess.span_err(e.span, "`return` in block function"); } - oldvisit::visit_expr_opt(oe, (cx, v)); + visit::walk_expr_opt(self, oe, cx); } - _ => oldvisit::visit_expr(e, (cx, v)) + _ => visit::walk_expr(self, e, cx) } - }, - .. *oldvisit::default_visitor() - }))); + + } } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 9719460bbd3..3f321fcfcd2 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -25,7 +25,8 @@ use extra::sort; use syntax::ast::*; use syntax::ast_util::{unguarded_pat, walk_pat}; use syntax::codemap::{span, dummy_sp, spanned}; -use syntax::oldvisit; +use syntax::visit; +use syntax::visit::{Visitor,fn_kind}; pub struct MatchCheckCtxt { tcx: ty::ctxt, @@ -33,6 +34,22 @@ pub struct MatchCheckCtxt { moves_map: moves::MovesMap } +struct CheckMatchVisitor { + cx: @MatchCheckCtxt +} + +impl Visitor<()> for CheckMatchVisitor { + fn visit_expr(&mut self, ex:@expr, e:()) { + check_expr(self, self.cx, ex, e); + } + fn visit_local(&mut self, l:@Local, e:()) { + check_local(self, self.cx, l, e); + } + fn visit_fn(&mut self, fk:&fn_kind, fd:&fn_decl, b:&Block, s:span, n:NodeId, e:()) { + check_fn(self, self.cx, fk, fd, b, s, n, e); + } +} + pub fn check_crate(tcx: ty::ctxt, method_map: method_map, moves_map: moves::MovesMap, @@ -40,20 +57,18 @@ pub fn check_crate(tcx: ty::ctxt, let cx = @MatchCheckCtxt {tcx: tcx, method_map: method_map, moves_map: moves_map}; - oldvisit::visit_crate(crate, ((), oldvisit::mk_vt(@oldvisit::Visitor { - visit_expr: |a,b| check_expr(cx, a, b), - visit_local: |a,b| check_local(cx, a, b), - visit_fn: |kind, decl, body, sp, id, (e, v)| - check_fn(cx, kind, decl, body, sp, id, (e, v)), - .. *oldvisit::default_visitor::<()>() - }))); + let mut v = CheckMatchVisitor { cx: cx }; + + visit::walk_crate(&mut v, crate, ()); + tcx.sess.abort_if_errors(); } -pub fn check_expr(cx: @MatchCheckCtxt, +pub fn check_expr(v: &mut CheckMatchVisitor, + cx: @MatchCheckCtxt, ex: @expr, - (s, v): ((), oldvisit::vt<()>)) { - oldvisit::visit_expr(ex, (s, v)); + s: ()) { + visit::walk_expr(v, ex, s); match ex.node { expr_match(scrut, ref arms) => { // First, check legality of move bindings. @@ -787,10 +802,11 @@ pub fn default(cx: &MatchCheckCtxt, r: &[@pat]) -> Option<~[@pat]> { else { None } } -pub fn check_local(cx: &MatchCheckCtxt, +pub fn check_local(v: &mut CheckMatchVisitor, + cx: &MatchCheckCtxt, loc: @Local, - (s, v): ((), oldvisit::vt<()>)) { - oldvisit::visit_local(loc, (s, v)); + s: ()) { + visit::walk_local(v, loc, s); if is_refutable(cx, loc.pat) { cx.tcx.sess.span_err(loc.pat.span, "refutable pattern in local binding"); @@ -800,15 +816,15 @@ pub fn check_local(cx: &MatchCheckCtxt, check_legality_of_move_bindings(cx, false, [ loc.pat ]); } -pub fn check_fn(cx: &MatchCheckCtxt, - kind: &oldvisit::fn_kind, +pub fn check_fn(v: &mut CheckMatchVisitor, + cx: &MatchCheckCtxt, + kind: &visit::fn_kind, decl: &fn_decl, body: &Block, sp: span, id: NodeId, - (s, v): ((), - oldvisit::vt<()>)) { - oldvisit::visit_fn(kind, decl, body, sp, id, (s, v)); + s: ()) { + visit::walk_fn(v, kind, decl, body, sp, id, s); for input in decl.inputs.iter() { if is_refutable(cx, input.pat) { cx.tcx.sess.span_err(input.pat.span, diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 68e3dfd63be..2e8d0d351d9 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -14,7 +14,9 @@ use middle::astencode; use middle::ty; use middle; -use syntax::{ast, ast_map, ast_util, oldvisit}; +use syntax::{ast, ast_map, ast_util}; +use syntax::visit; +use syntax::visit::Visitor; use syntax::ast::*; use std::float; @@ -267,13 +269,18 @@ pub fn lookup_constness(tcx: ty::ctxt, e: &expr) -> constness { } } +struct ConstEvalVisitor { tcx: ty::ctxt } + +impl Visitor<()> for ConstEvalVisitor { + fn visit_expr_post(&mut self, e:@expr, _:()) { + classify(e, self.tcx); + } +} + pub fn process_crate(crate: &ast::Crate, tcx: ty::ctxt) { - let v = oldvisit::mk_simple_visitor(@oldvisit::SimpleVisitor { - visit_expr_post: |e| { classify(e, tcx); }, - .. *oldvisit::default_simple_visitor() - }); - oldvisit::visit_crate(crate, ((), v)); + let mut v = ConstEvalVisitor { tcx: tcx }; + visit::walk_crate(&mut v, crate, ()); tcx.sess.abort_if_errors(); } diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 651ce292d28..de0be2a0bc5 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -20,8 +20,10 @@ use syntax::ast::{deref, expr_call, expr_inline_asm, expr_method_call}; use syntax::ast::{expr_unary, unsafe_fn, expr_path}; use syntax::ast; use syntax::codemap::span; -use syntax::oldvisit::{fk_item_fn, fk_method}; -use syntax::oldvisit; +use syntax::visit::{fk_item_fn, fk_method}; +use syntax::visit; +use syntax::visit::{Visitor,fn_kind}; +use syntax::ast::{fn_decl,Block,NodeId,expr}; #[deriving(Eq)] enum UnsafeContext { @@ -45,6 +47,121 @@ fn type_is_unsafe_function(ty: ty::t) -> bool { } } +struct EffectCheckVisitor { + tcx: ty::ctxt, + context: @mut Context, +} + +impl EffectCheckVisitor { + fn require_unsafe(&mut self, span: span, description: &str) { + match self.context.unsafe_context { + SafeContext => { + // Report an error. + self.tcx.sess.span_err(span, + fmt!("%s requires unsafe function or block", + description)) + } + UnsafeBlock(block_id) => { + // OK, but record this. + debug!("effect: recording unsafe block as used: %?", block_id); + let _ = self.tcx.used_unsafe.insert(block_id); + } + UnsafeFn => {} + } + } +} + +impl Visitor<()> for EffectCheckVisitor { + fn visit_fn(&mut self, fn_kind:&fn_kind, fn_decl:&fn_decl, + block:&Block, span:span, node_id:NodeId, _:()) { + + let (is_item_fn, is_unsafe_fn) = match *fn_kind { + fk_item_fn(_, _, purity, _) => (true, purity == unsafe_fn), + fk_method(_, _, method) => (true, method.purity == unsafe_fn), + _ => (false, false), + }; + + let old_unsafe_context = self.context.unsafe_context; + if is_unsafe_fn { + self.context.unsafe_context = UnsafeFn + } else if is_item_fn { + self.context.unsafe_context = SafeContext + } + + visit::walk_fn(self, + fn_kind, + fn_decl, + block, + span, + node_id, + ()); + + self.context.unsafe_context = old_unsafe_context + } + + fn visit_block(&mut self, block:&Block, _:()) { + + let old_unsafe_context = self.context.unsafe_context; + if block.rules == ast::UnsafeBlock && + self.context.unsafe_context == SafeContext { + self.context.unsafe_context = UnsafeBlock(block.id) + } + + visit::walk_block(self, block, ()); + + self.context.unsafe_context = old_unsafe_context + } + + fn visit_expr(&mut self, expr:@expr, _:()) { + + match expr.node { + expr_method_call(callee_id, _, _, _, _, _) => { + let base_type = ty::node_id_to_type(self.tcx, callee_id); + debug!("effect: method call case, base type is %s", + ppaux::ty_to_str(self.tcx, base_type)); + if type_is_unsafe_function(base_type) { + self.require_unsafe(expr.span, + "invocation of unsafe method") + } + } + expr_call(base, _, _) => { + let base_type = ty::node_id_to_type(self.tcx, base.id); + debug!("effect: call case, base type is %s", + ppaux::ty_to_str(self.tcx, base_type)); + if type_is_unsafe_function(base_type) { + self.require_unsafe(expr.span, "call to unsafe function") + } + } + expr_unary(_, deref, base) => { + let base_type = ty::node_id_to_type(self.tcx, base.id); + debug!("effect: unary case, base type is %s", + ppaux::ty_to_str(self.tcx, base_type)); + match ty::get(base_type).sty { + ty_ptr(_) => { + self.require_unsafe(expr.span, + "dereference of unsafe pointer") + } + _ => {} + } + } + expr_inline_asm(*) => { + self.require_unsafe(expr.span, "use of inline assembly") + } + expr_path(*) => { + match ty::resolve_expr(self.tcx, expr) { + ast::def_static(_, true) => { + self.require_unsafe(expr.span, "use of mutable static") + } + _ => {} + } + } + _ => {} + } + + visit::walk_expr(self, expr, ()); + } +} + pub fn check_crate(tcx: ty::ctxt, method_map: method_map, crate: &ast::Crate) { @@ -53,112 +170,10 @@ pub fn check_crate(tcx: ty::ctxt, unsafe_context: SafeContext, }; - let require_unsafe: @fn(span: span, - description: &str) = |span, description| { - match context.unsafe_context { - SafeContext => { - // Report an error. - tcx.sess.span_err(span, - fmt!("%s requires unsafe function or block", - description)) - } - UnsafeBlock(block_id) => { - // OK, but record this. - debug!("effect: recording unsafe block as used: %?", block_id); - let _ = tcx.used_unsafe.insert(block_id); - } - UnsafeFn => {} - } + let mut visitor = EffectCheckVisitor { + tcx: tcx, + context: context, }; - let visitor = oldvisit::mk_vt(@oldvisit::Visitor { - visit_fn: |fn_kind, fn_decl, block, span, node_id, (_, visitor)| { - let (is_item_fn, is_unsafe_fn) = match *fn_kind { - fk_item_fn(_, _, purity, _) => (true, purity == unsafe_fn), - fk_method(_, _, method) => (true, method.purity == unsafe_fn), - _ => (false, false), - }; - - let old_unsafe_context = context.unsafe_context; - if is_unsafe_fn { - context.unsafe_context = UnsafeFn - } else if is_item_fn { - context.unsafe_context = SafeContext - } - - oldvisit::visit_fn(fn_kind, - fn_decl, - block, - span, - node_id, - ((), - visitor)); - - context.unsafe_context = old_unsafe_context - }, - - visit_block: |block, (_, visitor)| { - let old_unsafe_context = context.unsafe_context; - if block.rules == ast::UnsafeBlock && - context.unsafe_context == SafeContext { - context.unsafe_context = UnsafeBlock(block.id) - } - - oldvisit::visit_block(block, ((), visitor)); - - context.unsafe_context = old_unsafe_context - }, - - visit_expr: |expr, (_, visitor)| { - match expr.node { - expr_method_call(callee_id, _, _, _, _, _) => { - let base_type = ty::node_id_to_type(tcx, callee_id); - debug!("effect: method call case, base type is %s", - ppaux::ty_to_str(tcx, base_type)); - if type_is_unsafe_function(base_type) { - require_unsafe(expr.span, - "invocation of unsafe method") - } - } - expr_call(base, _, _) => { - let base_type = ty::node_id_to_type(tcx, base.id); - debug!("effect: call case, base type is %s", - ppaux::ty_to_str(tcx, base_type)); - if type_is_unsafe_function(base_type) { - require_unsafe(expr.span, "call to unsafe function") - } - } - expr_unary(_, deref, base) => { - let base_type = ty::node_id_to_type(tcx, base.id); - debug!("effect: unary case, base type is %s", - ppaux::ty_to_str(tcx, base_type)); - match ty::get(base_type).sty { - ty_ptr(_) => { - require_unsafe(expr.span, - "dereference of unsafe pointer") - } - _ => {} - } - } - expr_inline_asm(*) => { - require_unsafe(expr.span, "use of inline assembly") - } - expr_path(*) => { - match ty::resolve_expr(tcx, expr) { - ast::def_static(_, true) => { - require_unsafe(expr.span, "use of mutable static") - } - _ => {} - } - } - _ => {} - } - - oldvisit::visit_expr(expr, ((), visitor)) - }, - - .. *oldvisit::default_visitor() - }); - - oldvisit::visit_crate(crate, ((), visitor)) + visit::walk_crate(&mut visitor, crate, ()); } diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 54e7c79e97c..6a566f10f1e 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -34,54 +34,57 @@ use syntax::ast_util::{variant_visibility_to_privacy, visibility_to_privacy}; use syntax::attr; use syntax::codemap::span; use syntax::parse::token; -use syntax::oldvisit; +use syntax::visit; +use syntax::visit::Visitor; +use syntax::ast::{_mod,expr,item,Block,pat}; -pub fn check_crate<'mm>(tcx: ty::ctxt, - method_map: &'mm method_map, - crate: &ast::Crate) { - let privileged_items = @mut ~[]; +struct PrivacyVisitor { + tcx: ty::ctxt, + privileged_items: @mut ~[NodeId], +} +impl PrivacyVisitor { // Adds an item to its scope. - let add_privileged_item: @fn(@ast::item, &mut uint) = |item, count| { + fn add_privileged_item(&mut self, item: @ast::item, count: &mut uint) { match item.node { item_struct(*) | item_trait(*) | item_enum(*) | item_fn(*) => { - privileged_items.push(item.id); + self.privileged_items.push(item.id); *count += 1; } item_impl(_, _, _, ref methods) => { for method in methods.iter() { - privileged_items.push(method.id); + self.privileged_items.push(method.id); *count += 1; } - privileged_items.push(item.id); + self.privileged_items.push(item.id); *count += 1; } item_foreign_mod(ref foreign_mod) => { for foreign_item in foreign_mod.items.iter() { - privileged_items.push(foreign_item.id); + self.privileged_items.push(foreign_item.id); *count += 1; } } _ => {} } - }; + } // Adds items that are privileged to this scope. - let add_privileged_items: @fn(&[@ast::item]) -> uint = |items| { + fn add_privileged_items(&mut self, items: &[@ast::item]) -> uint { let mut count = 0; for &item in items.iter() { - add_privileged_item(item, &mut count); + self.add_privileged_item(item, &mut count); } count - }; + } // Checks that an enum variant is in scope - let check_variant: @fn(span: span, enum_id: ast::def_id) = - |span, enum_id| { - let variant_info = ty::enum_variants(tcx, enum_id)[0]; + fn check_variant(&mut self, span: span, enum_id: ast::def_id) { + let variant_info = ty::enum_variants(self.tcx, enum_id)[0]; let parental_privacy = if is_local(enum_id) { - let parent_vis = ast_map::node_item_query(tcx.items, enum_id.node, + let parent_vis = ast_map::node_item_query(self.tcx.items, + enum_id.node, |it| { it.vis }, ~"unbound enum parent when checking \ dereference of enum type"); @@ -99,15 +102,14 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, if variant_visibility_to_privacy(variant_info.vis, parental_privacy == Public) == Private { - tcx.sess.span_err(span, + self.tcx.sess.span_err(span, "can only dereference enums \ with a single, public variant"); } - }; + } // Returns true if a crate-local method is private and false otherwise. - let method_is_private: @fn(span: span, method_id: NodeId) -> bool = - |span, method_id| { + fn method_is_private(&mut self, span: span, method_id: NodeId) -> bool { let check = |vis: visibility, container_id: def_id| { let mut is_private = false; if vis == private { @@ -117,12 +119,12 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } else { // Look up the enclosing impl. if container_id.crate != LOCAL_CRATE { - tcx.sess.span_bug(span, + self.tcx.sess.span_bug(span, "local method isn't in local \ impl?!"); } - match tcx.items.find(&container_id.node) { + match self.tcx.items.find(&container_id.node) { Some(&node_item(item, _)) => { match item.node { item_impl(_, None, _, _) @@ -133,10 +135,10 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } Some(_) => { - tcx.sess.span_bug(span, "impl wasn't an item?!"); + self.tcx.sess.span_bug(span, "impl wasn't an item?!"); } None => { - tcx.sess.span_bug(span, "impl wasn't in AST map?!"); + self.tcx.sess.span_bug(span, "impl wasn't in AST map?!"); } } } @@ -144,7 +146,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, is_private }; - match tcx.items.find(&method_id) { + match self.tcx.items.find(&method_id) { Some(&node_method(method, impl_id, _)) => { check(method.vis, impl_id) } @@ -155,26 +157,25 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } Some(_) => { - tcx.sess.span_bug(span, + self.tcx.sess.span_bug(span, fmt!("method_is_private: method was a %s?!", ast_map::node_id_to_str( - tcx.items, + self.tcx.items, method_id, token::get_ident_interner()))); } None => { - tcx.sess.span_bug(span, "method not found in \ + self.tcx.sess.span_bug(span, "method not found in \ AST map?!"); } } - }; + } // Returns true if the given local item is private and false otherwise. - let local_item_is_private: @fn(span: span, item_id: NodeId) -> bool = - |span, item_id| { + fn local_item_is_private(&mut self, span: span, item_id: NodeId) -> bool { let mut f: &fn(NodeId) -> bool = |_| false; f = |item_id| { - match tcx.items.find(&item_id) { + match self.tcx.items.find(&item_id) { Some(&node_item(item, _)) => item.vis != public, Some(&node_foreign_item(*)) => false, Some(&node_method(method, impl_did, _)) => { @@ -186,104 +187,96 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } Some(&node_trait_method(_, trait_did, _)) => f(trait_did.node), Some(_) => { - tcx.sess.span_bug(span, + self.tcx.sess.span_bug(span, fmt!("local_item_is_private: item was \ a %s?!", ast_map::node_id_to_str( - tcx.items, + self.tcx.items, item_id, token::get_ident_interner()))); } None => { - tcx.sess.span_bug(span, "item not found in AST map?!"); + self.tcx.sess.span_bug(span, "item not found in AST map?!"); } } }; f(item_id) - }; + } // Checks that a private field is in scope. - let check_field: @fn(span: span, id: ast::def_id, ident: ast::ident) = - |span, id, ident| { - let fields = ty::lookup_struct_fields(tcx, id); + fn check_field(&mut self, span: span, id: ast::def_id, ident: ast::ident) { + let fields = ty::lookup_struct_fields(self.tcx, id); for field in fields.iter() { if field.ident != ident { loop; } if field.vis == private { - tcx.sess.span_err(span, fmt!("field `%s` is private", + self.tcx.sess.span_err(span, fmt!("field `%s` is private", token::ident_to_str(&ident))); } break; } - }; + } // Given the ID of a method, checks to ensure it's in scope. - let check_method_common: @fn(span: span, - method_id: def_id, - name: &ident) = - |span, method_id, name| { + fn check_method_common(&mut self, span: span, method_id: def_id, name: &ident) { // If the method is a default method, we need to use the def_id of // the default implementation. // Having to do this this is really unfortunate. - let method_id = ty::method(tcx, method_id).provided_source + let method_id = ty::method(self.tcx, method_id).provided_source .unwrap_or_default(method_id); if method_id.crate == LOCAL_CRATE { - let is_private = method_is_private(span, method_id.node); - let container_id = ty::method(tcx, method_id).container_id; + let is_private = self.method_is_private(span, method_id.node); + let container_id = ty::method(self.tcx, method_id).container_id; if is_private && (container_id.crate != LOCAL_CRATE || - !privileged_items.iter().any(|x| x == &(container_id.node))) { - tcx.sess.span_err(span, + !self.privileged_items.iter().any(|x| x == &(container_id.node))) { + self.tcx.sess.span_err(span, fmt!("method `%s` is private", token::ident_to_str(name))); } } else { let visibility = - csearch::get_item_visibility(tcx.sess.cstore, method_id); + csearch::get_item_visibility(self.tcx.sess.cstore, method_id); if visibility != public { - tcx.sess.span_err(span, + self.tcx.sess.span_err(span, fmt!("method `%s` is private", token::ident_to_str(name))); } } - }; + } // Checks that a private path is in scope. - let check_path: @fn(span: span, def: def, path: &Path) = - |span, def, path| { + fn check_path(&mut self, span: span, def: def, path: &Path) { debug!("checking path"); match def { def_static_method(method_id, _, _) => { debug!("found static method def, checking it"); - check_method_common(span, method_id, path.idents.last()) + self.check_method_common(span, method_id, path.idents.last()) } def_fn(def_id, _) => { if def_id.crate == LOCAL_CRATE { - if local_item_is_private(span, def_id.node) && - !privileged_items.iter().any(|x| x == &def_id.node) { - tcx.sess.span_err(span, + if self.local_item_is_private(span, def_id.node) && + !self.privileged_items.iter().any(|x| x == &def_id.node) { + self.tcx.sess.span_err(span, fmt!("function `%s` is private", token::ident_to_str(path.idents.last()))); } - } else if csearch::get_item_visibility(tcx.sess.cstore, + } else if csearch::get_item_visibility(self.tcx.sess.cstore, def_id) != public { - tcx.sess.span_err(span, + self.tcx.sess.span_err(span, fmt!("function `%s` is private", token::ident_to_str(path.idents.last()))); } } _ => {} } - }; + } // Checks that a private method is in scope. - let check_method: @fn(span: span, - origin: &method_origin, - ident: ast::ident) = - |span, origin, ident| { + fn check_method(&mut self, span: span, origin: &method_origin, ident: ast::ident) { match *origin { method_static(method_id) => { - check_method_common(span, method_id, &ident) + self.check_method_common(span, method_id, &ident) } method_param(method_param { trait_id: trait_id, @@ -292,19 +285,20 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, }) | method_trait(trait_id, method_num) => { if trait_id.crate == LOCAL_CRATE { - match tcx.items.find(&trait_id.node) { + match self.tcx.items.find(&trait_id.node) { Some(&node_item(item, _)) => { match item.node { item_trait(_, _, ref methods) => { if method_num >= (*methods).len() { - tcx.sess.span_bug(span, "method number out of range?!"); + self.tcx.sess.span_bug(span, + "method number out of range?!"); } match (*methods)[method_num] { provided(method) if method.vis == private && - !privileged_items.iter() + !self.privileged_items.iter() .any(|x| x == &(trait_id.node)) => { - tcx.sess.span_err(span, + self.tcx.sess.span_err(span, fmt!("method `%s` is private", token::ident_to_str(&method .ident))); @@ -316,15 +310,16 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } _ => { - tcx.sess.span_bug(span, "trait wasn't actually a trait?!"); + self.tcx.sess.span_bug(span, "trait wasn't actually a trait?!"); } } } Some(_) => { - tcx.sess.span_bug(span, "trait wasn't an item?!"); + self.tcx.sess.span_bug(span, "trait wasn't an item?!"); } None => { - tcx.sess.span_bug(span, "trait item wasn't found in the AST map?!"); + self.tcx.sess.span_bug(span, + "trait item wasn't found in the AST map?!"); } } } else { @@ -332,30 +327,35 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } } - }; + } +} - let visitor = oldvisit::mk_vt(@oldvisit::Visitor { - visit_mod: |the_module, span, node_id, (method_map, visitor)| { - let n_added = add_privileged_items(the_module.items); +impl<'self> Visitor<&'self method_map> for PrivacyVisitor { - oldvisit::visit_mod(the_module, - span, - node_id, - (method_map, visitor)); + fn visit_mod<'mm>(&mut self, the_module:&_mod, _:span, _:NodeId, + method_map:&'mm method_map) { + + let n_added = self.add_privileged_items(the_module.items); + + visit::walk_mod(self, the_module, method_map); do n_added.times { - ignore(privileged_items.pop()); + ignore(self.privileged_items.pop()); } - }, - visit_item: |item, (method_map, visitor)| { + } + + fn visit_item<'mm>(&mut self, item:@item, method_map:&'mm method_map) { + // Do not check privacy inside items with the resolve_unexported // attribute. This is used for the test runner. if !attr::contains_name(item.attrs, "!resolve_unexported") { - check_sane_privacy(tcx, item); - oldvisit::visit_item(item, (method_map, visitor)); + check_sane_privacy(self.tcx, item); + visit::walk_item(self, item, method_map); } - }, - visit_block: |block, (method_map, visitor)| { + } + + fn visit_block<'mm>(&mut self, block:&Block, method_map:&'mm method_map) { + // Gather up all the privileged items. let mut n_added = 0; for stmt in block.stmts.iter() { @@ -363,7 +363,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, stmt_decl(decl, _) => { match decl.node { decl_item(item) => { - add_privileged_item(item, &mut n_added); + self.add_privileged_item(item, &mut n_added); } _ => {} } @@ -372,15 +372,16 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } - oldvisit::visit_block(block, (method_map, visitor)); + visit::walk_block(self, block, method_map); do n_added.times { - ignore(privileged_items.pop()); + ignore(self.privileged_items.pop()); } - }, - visit_expr: |expr, - (method_map, visitor): - (&'mm method_map, oldvisit::vt<&'mm method_map>)| { + + } + + fn visit_expr<'mm>(&mut self, expr:@expr, method_map:&'mm method_map) { + match expr.node { expr_field(base, ident, _) => { // Method calls are now a special syntactic form, @@ -389,35 +390,35 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, // With type_autoderef, make sure we don't // allow pointers to violate privacy - match ty::get(ty::type_autoderef(tcx, ty::expr_ty(tcx, + match ty::get(ty::type_autoderef(self.tcx, ty::expr_ty(self.tcx, base))).sty { ty_struct(id, _) - if id.crate != LOCAL_CRATE || !privileged_items.iter() + if id.crate != LOCAL_CRATE || !self.privileged_items.iter() .any(|x| x == &(id.node)) => { debug!("(privacy checking) checking field access"); - check_field(expr.span, id, ident); + self.check_field(expr.span, id, ident); } _ => {} } } expr_method_call(_, base, ident, _, _, _) => { // Ditto - match ty::get(ty::type_autoderef(tcx, ty::expr_ty(tcx, + match ty::get(ty::type_autoderef(self.tcx, ty::expr_ty(self.tcx, base))).sty { ty_enum(id, _) | ty_struct(id, _) if id.crate != LOCAL_CRATE || - !privileged_items.iter().any(|x| x == &(id.node)) => { + !self.privileged_items.iter().any(|x| x == &(id.node)) => { match method_map.find(&expr.id) { None => { - tcx.sess.span_bug(expr.span, + self.tcx.sess.span_bug(expr.span, "method call not in \ method map"); } Some(ref entry) => { debug!("(privacy checking) checking \ impl method"); - check_method(expr.span, &entry.origin, ident); + self.check_method(expr.span, &entry.origin, ident); } } } @@ -425,35 +426,35 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } expr_path(ref path) => { - check_path(expr.span, tcx.def_map.get_copy(&expr.id), path); + self.check_path(expr.span, self.tcx.def_map.get_copy(&expr.id), path); } expr_struct(_, ref fields, _) => { - match ty::get(ty::expr_ty(tcx, expr)).sty { + match ty::get(ty::expr_ty(self.tcx, expr)).sty { ty_struct(id, _) => { if id.crate != LOCAL_CRATE || - !privileged_items.iter().any(|x| x == &(id.node)) { + !self.privileged_items.iter().any(|x| x == &(id.node)) { for field in (*fields).iter() { debug!("(privacy checking) checking \ field in struct literal"); - check_field(expr.span, id, field.ident); + self.check_field(expr.span, id, field.ident); } } } ty_enum(id, _) => { if id.crate != LOCAL_CRATE || - !privileged_items.iter().any(|x| x == &(id.node)) { - match tcx.def_map.get_copy(&expr.id) { + !self.privileged_items.iter().any(|x| x == &(id.node)) { + match self.tcx.def_map.get_copy(&expr.id) { def_variant(_, variant_id) => { for field in (*fields).iter() { debug!("(privacy checking) \ checking field in \ struct variant \ literal"); - check_field(expr.span, variant_id, field.ident); + self.check_field(expr.span, variant_id, field.ident); } } _ => { - tcx.sess.span_bug(expr.span, + self.tcx.sess.span_bug(expr.span, "resolve didn't \ map enum struct \ constructor to a \ @@ -463,7 +464,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } _ => { - tcx.sess.span_bug(expr.span, "struct expr \ + self.tcx.sess.span_bug(expr.span, "struct expr \ didn't have \ struct type?!"); } @@ -474,11 +475,11 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, // enum type t, then t's first variant is public or // privileged. (We can assume it has only one variant // since typeck already happened.) - match ty::get(ty::expr_ty(tcx, operand)).sty { + match ty::get(ty::expr_ty(self.tcx, operand)).sty { ty_enum(id, _) => { if id.crate != LOCAL_CRATE || - !privileged_items.iter().any(|x| x == &(id.node)) { - check_variant(expr.span, id); + !self.privileged_items.iter().any(|x| x == &(id.node)) { + self.check_variant(expr.span, id); } } _ => { /* No check needed */ } @@ -487,36 +488,39 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, _ => {} } - oldvisit::visit_expr(expr, (method_map, visitor)); - }, - visit_pat: |pattern, (method_map, visitor)| { + visit::walk_expr(self, expr, method_map); + + } + + fn visit_pat<'mm>(&mut self, pattern:@pat, method_map:&'mm method_map) { + match pattern.node { pat_struct(_, ref fields, _) => { - match ty::get(ty::pat_ty(tcx, pattern)).sty { + match ty::get(ty::pat_ty(self.tcx, pattern)).sty { ty_struct(id, _) => { if id.crate != LOCAL_CRATE || - !privileged_items.iter().any(|x| x == &(id.node)) { + !self.privileged_items.iter().any(|x| x == &(id.node)) { for field in fields.iter() { debug!("(privacy checking) checking \ struct pattern"); - check_field(pattern.span, id, field.ident); + self.check_field(pattern.span, id, field.ident); } } } ty_enum(enum_id, _) => { if enum_id.crate != LOCAL_CRATE || - !privileged_items.iter().any(|x| x == &enum_id.node) { - match tcx.def_map.find(&pattern.id) { + !self.privileged_items.iter().any(|x| x == &enum_id.node) { + match self.tcx.def_map.find(&pattern.id) { Some(&def_variant(_, variant_id)) => { for field in fields.iter() { debug!("(privacy checking) \ checking field in \ struct variant pattern"); - check_field(pattern.span, variant_id, field.ident); + self.check_field(pattern.span, variant_id, field.ident); } } _ => { - tcx.sess.span_bug(pattern.span, + self.tcx.sess.span_bug(pattern.span, "resolve didn't \ map enum struct \ pattern to a \ @@ -526,7 +530,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } _ => { - tcx.sess.span_bug(pattern.span, + self.tcx.sess.span_bug(pattern.span, "struct pattern didn't have \ struct type?!"); } @@ -535,11 +539,20 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, _ => {} } - oldvisit::visit_pat(pattern, (method_map, visitor)); - }, - .. *oldvisit::default_visitor() - }); - oldvisit::visit_crate(crate, (method_map, visitor)); + visit::walk_pat(self, pattern, method_map); + } +} + +pub fn check_crate<'mm>(tcx: ty::ctxt, + method_map: &'mm method_map, + crate: &ast::Crate) { + let privileged_items = @mut ~[]; + + let mut visitor = PrivacyVisitor { + tcx: tcx, + privileged_items: privileged_items, + }; + visit::walk_crate(&mut visitor, crate, method_map); } /// Validates all of the visibility qualifers placed on the item given. This diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 33a8960baee..b6a4ac49391 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -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, + worklist: @mut ~[NodeId], +} + +impl Visitor 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)| { 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, +} + +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(); diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 4da22be4428..ddd22a0add4 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -34,7 +34,10 @@ use syntax::codemap::span; use syntax::print::pprust; use syntax::parse::token; use syntax::parse::token::special_idents; -use syntax::{ast, oldvisit}; +use syntax::{ast, visit}; +use syntax::visit::{Visitor,fn_kind}; +use syntax::ast::{Block,item,fn_decl,NodeId,arm,pat,stmt,expr,Local}; +use syntax::ast::{Ty,TypeMethod,struct_field}; /** The region maps encode information about region relationships. @@ -323,8 +326,9 @@ fn parent_to_expr(cx: Context, child_id: ast::NodeId, sp: span) { } } -fn resolve_block(blk: &ast::Block, - (cx, visitor): (Context, oldvisit::vt)) { +fn resolve_block(visitor: &mut RegionResolutionVisitor, + blk: &ast::Block, + cx: Context) { // Record the parent of this block. parent_to_expr(cx, blk.id, blk.span); @@ -332,39 +336,43 @@ fn resolve_block(blk: &ast::Block, let new_cx = Context {var_parent: Some(blk.id), parent: Some(blk.id), ..cx}; - oldvisit::visit_block(blk, (new_cx, visitor)); + visit::walk_block(visitor, blk, new_cx); } -fn resolve_arm(arm: &ast::arm, - (cx, visitor): (Context, oldvisit::vt)) { - oldvisit::visit_arm(arm, (cx, visitor)); +fn resolve_arm(visitor: &mut RegionResolutionVisitor, + arm: &ast::arm, + cx: Context) { + visit::walk_arm(visitor, arm, cx); } -fn resolve_pat(pat: @ast::pat, - (cx, visitor): (Context, oldvisit::vt)) { +fn resolve_pat(visitor: &mut RegionResolutionVisitor, + pat: @ast::pat, + cx: Context) { assert_eq!(cx.var_parent, cx.parent); parent_to_expr(cx, pat.id, pat.span); - oldvisit::visit_pat(pat, (cx, visitor)); + visit::walk_pat(visitor, pat, cx); } -fn resolve_stmt(stmt: @ast::stmt, - (cx, visitor): (Context, oldvisit::vt)) { +fn resolve_stmt(visitor: &mut RegionResolutionVisitor, + stmt: @ast::stmt, + cx: Context) { match stmt.node { ast::stmt_decl(*) => { - oldvisit::visit_stmt(stmt, (cx, visitor)); + visit::walk_stmt(visitor, stmt, cx); } ast::stmt_expr(_, stmt_id) | ast::stmt_semi(_, stmt_id) => { parent_to_expr(cx, stmt_id, stmt.span); let expr_cx = Context {parent: Some(stmt_id), ..cx}; - oldvisit::visit_stmt(stmt, (expr_cx, visitor)); + visit::walk_stmt(visitor, stmt, expr_cx); } ast::stmt_mac(*) => cx.sess.bug("unexpanded macro") } } -fn resolve_expr(expr: @ast::expr, - (cx, visitor): (Context, oldvisit::vt)) { +fn resolve_expr(visitor: &mut RegionResolutionVisitor, + expr: @ast::expr, + cx: Context) { parent_to_expr(cx, expr.id, expr.span); let mut new_cx = cx; @@ -400,30 +408,32 @@ fn resolve_expr(expr: @ast::expr, }; - oldvisit::visit_expr(expr, (new_cx, visitor)); + visit::walk_expr(visitor, expr, new_cx); } -fn resolve_local(local: @ast::Local, - (cx, visitor): (Context, oldvisit::vt)) { +fn resolve_local(visitor: &mut RegionResolutionVisitor, + local: @ast::Local, + cx: Context) { assert_eq!(cx.var_parent, cx.parent); parent_to_expr(cx, local.id, local.span); - oldvisit::visit_local(local, (cx, visitor)); + visit::walk_local(visitor, local, cx); } -fn resolve_item(item: @ast::item, - (cx, visitor): (Context, oldvisit::vt)) { +fn resolve_item(visitor: &mut RegionResolutionVisitor, + item: @ast::item, + cx: Context) { // Items create a new outer block scope as far as we're concerned. let new_cx = Context {var_parent: None, parent: None, ..cx}; - oldvisit::visit_item(item, (new_cx, visitor)); + visit::walk_item(visitor, item, new_cx); } -fn resolve_fn(fk: &oldvisit::fn_kind, +fn resolve_fn(visitor: &mut RegionResolutionVisitor, + fk: &visit::fn_kind, decl: &ast::fn_decl, body: &ast::Block, sp: span, id: ast::NodeId, - (cx, visitor): (Context, - oldvisit::vt)) { + cx: Context) { debug!("region::resolve_fn(id=%?, \ span=%?, \ body.id=%?, \ @@ -438,26 +448,58 @@ fn resolve_fn(fk: &oldvisit::fn_kind, var_parent: Some(body.id), ..cx}; match *fk { - oldvisit::fk_method(_, _, method) => { + visit::fk_method(_, _, method) => { cx.region_maps.record_parent(method.self_id, body.id); } _ => {} } - oldvisit::visit_fn_decl(decl, (decl_cx, visitor)); + visit::walk_fn_decl(visitor, decl, decl_cx); // The body of the fn itself is either a root scope (top-level fn) // or it continues with the inherited scope (closures). let body_cx = match *fk { - oldvisit::fk_item_fn(*) | - oldvisit::fk_method(*) => { + visit::fk_item_fn(*) | + visit::fk_method(*) => { Context {parent: None, var_parent: None, ..cx} } - oldvisit::fk_anon(*) | - oldvisit::fk_fn_block(*) => { + visit::fk_anon(*) | + visit::fk_fn_block(*) => { cx } }; - (visitor.visit_block)(body, (body_cx, visitor)); + visitor.visit_block(body, body_cx); +} + +struct RegionResolutionVisitor; + +impl Visitor for RegionResolutionVisitor { + + fn visit_block(&mut self, b:&Block, cx:Context) { + resolve_block(self, b, cx); + } + + fn visit_item(&mut self, i:@item, cx:Context) { + resolve_item(self, i, cx); + } + + fn visit_fn(&mut self, fk:&fn_kind, fd:&fn_decl, b:&Block, s:span, n:NodeId, cx:Context) { + resolve_fn(self, fk, fd, b, s, n, cx); + } + fn visit_arm(&mut self, a:&arm, cx:Context) { + resolve_arm(self, a, cx); + } + fn visit_pat(&mut self, p:@pat, cx:Context) { + resolve_pat(self, p, cx); + } + fn visit_stmt(&mut self, s:@stmt, cx:Context) { + resolve_stmt(self, s, cx); + } + fn visit_expr(&mut self, ex:@expr, cx:Context) { + resolve_expr(self, ex, cx); + } + fn visit_local(&mut self, l:@Local, cx:Context) { + resolve_local(self, l, cx); + } } pub fn resolve_crate(sess: Session, @@ -474,18 +516,8 @@ pub fn resolve_crate(sess: Session, region_maps: region_maps, parent: None, var_parent: None}; - let visitor = oldvisit::mk_vt(@oldvisit::Visitor { - visit_block: resolve_block, - visit_item: resolve_item, - visit_fn: resolve_fn, - visit_arm: resolve_arm, - visit_pat: resolve_pat, - visit_stmt: resolve_stmt, - visit_expr: resolve_expr, - visit_local: resolve_local, - .. *oldvisit::default_visitor() - }); - oldvisit::visit_crate(crate, (cx, visitor)); + let mut visitor = RegionResolutionVisitor; + visit::walk_crate(&mut visitor, crate, cx); return region_maps; } @@ -700,46 +732,45 @@ impl DetermineRpCtxt { } } -fn determine_rp_in_item(item: @ast::item, - (cx, visitor): (@mut DetermineRpCtxt, - oldvisit::vt<@mut DetermineRpCtxt>)) { +fn determine_rp_in_item(visitor: &mut DetermineRpVisitor, + item: @ast::item, + cx: @mut DetermineRpCtxt) { do cx.with(item.id, true) { - oldvisit::visit_item(item, (cx, visitor)); + visit::walk_item(visitor, item, cx); } } -fn determine_rp_in_fn(fk: &oldvisit::fn_kind, +fn determine_rp_in_fn(visitor: &mut DetermineRpVisitor, + fk: &visit::fn_kind, decl: &ast::fn_decl, body: &ast::Block, _: span, _: ast::NodeId, - (cx, visitor): (@mut DetermineRpCtxt, - oldvisit::vt<@mut DetermineRpCtxt>)) { + cx: @mut DetermineRpCtxt) { do cx.with(cx.item_id, false) { do cx.with_ambient_variance(rv_contravariant) { for a in decl.inputs.iter() { - (visitor.visit_ty)(&a.ty, (cx, visitor)); + visitor.visit_ty(&a.ty, cx); } } - (visitor.visit_ty)(&decl.output, (cx, visitor)); - let generics = oldvisit::generics_of_fn(fk); - (visitor.visit_generics)(&generics, (cx, visitor)); - (visitor.visit_block)(body, (cx, visitor)); + visitor.visit_ty(&decl.output, cx); + let generics = visit::generics_of_fn(fk); + visitor.visit_generics(&generics, cx); + visitor.visit_block(body, cx); } } -fn determine_rp_in_ty_method(ty_m: &ast::TypeMethod, - (cx, visitor): - (@mut DetermineRpCtxt, - oldvisit::vt<@mut DetermineRpCtxt>)) { +fn determine_rp_in_ty_method(visitor: &mut DetermineRpVisitor, + ty_m: &ast::TypeMethod, + cx: @mut DetermineRpCtxt) { do cx.with(cx.item_id, false) { - oldvisit::visit_ty_method(ty_m, (cx, visitor)); + visit::walk_ty_method(visitor, ty_m, cx); } } -fn determine_rp_in_ty(ty: &ast::Ty, - (cx, visitor): (@mut DetermineRpCtxt, - oldvisit::vt<@mut DetermineRpCtxt>)) { +fn determine_rp_in_ty(visitor: &mut DetermineRpVisitor, + ty: &ast::Ty, + cx: @mut DetermineRpCtxt) { // we are only interested in types that will require an item to // be region-parameterized. if cx.item_id is zero, then this type // is not a member of a type defn nor is it a constitutent of an @@ -823,14 +854,14 @@ fn determine_rp_in_ty(ty: &ast::Ty, match ty.node { ast::ty_box(ref mt) | ast::ty_uniq(ref mt) | ast::ty_vec(ref mt) | ast::ty_rptr(_, ref mt) | ast::ty_ptr(ref mt) => { - visit_mt(mt, (cx, visitor)); + visit_mt(visitor, mt, cx); } ast::ty_path(ref path, _, _) => { // type parameters are---for now, anyway---always invariant do cx.with_ambient_variance(rv_invariant) { for tp in path.types.iter() { - (visitor.visit_ty)(tp, (cx, visitor)); + visitor.visit_ty(tp, cx); } } } @@ -843,37 +874,59 @@ fn determine_rp_in_ty(ty: &ast::Ty, // parameters are contravariant do cx.with_ambient_variance(rv_contravariant) { for a in decl.inputs.iter() { - (visitor.visit_ty)(&a.ty, (cx, visitor)); + visitor.visit_ty(&a.ty, cx); } } - (visitor.visit_ty)(&decl.output, (cx, visitor)); + visitor.visit_ty(&decl.output, cx); } } _ => { - oldvisit::visit_ty(ty, (cx, visitor)); + visit::walk_ty(visitor, ty, cx); } } - fn visit_mt(mt: &ast::mt, - (cx, visitor): (@mut DetermineRpCtxt, - oldvisit::vt<@mut DetermineRpCtxt>)) { + fn visit_mt(visitor: &mut DetermineRpVisitor, + mt: &ast::mt, + cx: @mut DetermineRpCtxt) { // mutability is invariant if mt.mutbl == ast::m_mutbl { do cx.with_ambient_variance(rv_invariant) { - (visitor.visit_ty)(mt.ty, (cx, visitor)); + visitor.visit_ty(mt.ty, cx); } } else { - (visitor.visit_ty)(mt.ty, (cx, visitor)); + visitor.visit_ty(mt.ty, cx); } } } -fn determine_rp_in_struct_field( - cm: @ast::struct_field, - (cx, visitor): (@mut DetermineRpCtxt, - oldvisit::vt<@mut DetermineRpCtxt>)) { - oldvisit::visit_struct_field(cm, (cx, visitor)); +fn determine_rp_in_struct_field(visitor: &mut DetermineRpVisitor, + cm: @ast::struct_field, + cx: @mut DetermineRpCtxt) { + visit::walk_struct_field(visitor, cm, cx); +} + +struct DetermineRpVisitor; + +impl Visitor<@mut DetermineRpCtxt> for DetermineRpVisitor { + + fn visit_fn(&mut self, fk:&fn_kind, fd:&fn_decl, + b:&Block, s:span, n:NodeId, e:@mut DetermineRpCtxt) { + determine_rp_in_fn(self, fk, fd, b, s, n, e); + } + fn visit_item(&mut self, i:@item, e:@mut DetermineRpCtxt) { + determine_rp_in_item(self, i, e); + } + fn visit_ty(&mut self, t:&Ty, e:@mut DetermineRpCtxt) { + determine_rp_in_ty(self, t, e); + } + fn visit_ty_method(&mut self, t:&TypeMethod, e:@mut DetermineRpCtxt) { + determine_rp_in_ty_method(self, t, e); + } + fn visit_struct_field(&mut self, s:@struct_field, e:@mut DetermineRpCtxt) { + determine_rp_in_struct_field(self, s, e); + } + } pub fn determine_rp_in_crate(sess: Session, @@ -894,15 +947,8 @@ pub fn determine_rp_in_crate(sess: Session, }; // Gather up the base set, worklist and dep_map - let visitor = oldvisit::mk_vt(@oldvisit::Visitor { - visit_fn: determine_rp_in_fn, - visit_item: determine_rp_in_item, - visit_ty: determine_rp_in_ty, - visit_ty_method: determine_rp_in_ty_method, - visit_struct_field: determine_rp_in_struct_field, - .. *oldvisit::default_visitor() - }); - oldvisit::visit_crate(crate, (cx, visitor)); + let mut visitor = DetermineRpVisitor; + visit::walk_crate(&mut visitor, crate, cx); // Propagate indirect dependencies //