about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-08-02 22:05:03 -0700
committerbors <bors@rust-lang.org>2013-08-02 22:05:03 -0700
commit2a7be1c9e4d5a50dab4f3f95c8f1d843a7d6f084 (patch)
treeb7612d4ec3135ab61b5a02f68259943e88b87936 /src/libsyntax
parentefd6eafeb4f734ef7883afadb4e50099430c76f2 (diff)
parent9457ebee550d8f77ffc9b895acddae8946ee631e (diff)
downloadrust-2a7be1c9e4d5a50dab4f3f95c8f1d843a7d6f084.tar.gz
rust-2a7be1c9e4d5a50dab4f3f95c8f1d843a7d6f084.zip
auto merge of #8235 : pcwalton/rust/unsafe-extern-fns, r=pcwalton
r? @brson
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/ast_map.rs477
-rw-r--r--src/libsyntax/ast_util.rs419
-rw-r--r--src/libsyntax/ext/expand.rs180
-rw-r--r--src/libsyntax/fold.rs3
-rw-r--r--src/libsyntax/oldvisit.rs775
-rw-r--r--src/libsyntax/parse/obsolete.rs8
-rw-r--r--src/libsyntax/parse/parser.rs11
-rw-r--r--src/libsyntax/print/pprust.rs4
-rw-r--r--src/libsyntax/syntax.rs1
-rw-r--r--src/libsyntax/visit.rs1136
11 files changed, 2090 insertions, 926 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index d6bee4fe19f..11f2c7005bc 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1077,7 +1077,7 @@ pub struct foreign_item {
 
 #[deriving(Eq, Encodable, Decodable,IterBytes)]
 pub enum foreign_item_ {
-    foreign_item_fn(fn_decl, purity, Generics),
+    foreign_item_fn(fn_decl, Generics),
     foreign_item_static(Ty, /* is_mutbl */ bool),
 }
 
diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs
index bee0f113aa7..9c0f2d34a6c 100644
--- a/src/libsyntax/ast_map.rs
+++ b/src/libsyntax/ast_map.rs
@@ -13,12 +13,14 @@ use ast::*;
 use ast;
 use ast_util::{inlined_item_utils, stmt_id};
 use ast_util;
+use codemap::span;
 use codemap;
 use diagnostic::span_handler;
 use parse::token::ident_interner;
+use parse::token::special_idents;
 use print::pprust;
+use visit::{Visitor, fn_kind};
 use visit;
-use syntax::parse::token::special_idents;
 
 use std::hashmap::HashMap;
 use std::vec;
@@ -86,22 +88,282 @@ pub struct Ctx {
     diag: @span_handler,
 }
 
-pub type vt = visit::vt<@mut Ctx>;
+impl Ctx {
+    fn extend(@mut self, elt: ident) -> @path {
+        @vec::append(self.path.clone(), [path_name(elt)])
+    }
+
+    fn map_method(@mut self,
+                  impl_did: def_id,
+                  impl_path: @path,
+                  m: @method,
+                  is_provided: bool) {
+        let entry = if is_provided {
+            node_trait_method(@provided(m), impl_did, impl_path)
+        } else {
+            node_method(m, impl_did, impl_path)
+        };
+        self.map.insert(m.id, entry);
+        self.map.insert(m.self_id, node_local(special_idents::self_));
+    }
+
+    fn map_struct_def(@mut self,
+                      struct_def: @ast::struct_def,
+                      parent_node: ast_node,
+                      ident: ast::ident) {
+        let p = self.extend(ident);
+
+        // If this is a tuple-like struct, register the constructor.
+        match struct_def.ctor_id {
+            None => {}
+            Some(ctor_id) => {
+                match parent_node {
+                    node_item(item, _) => {
+                        self.map.insert(ctor_id,
+                                        node_struct_ctor(struct_def,
+                                                         item,
+                                                         p));
+                    }
+                    _ => fail!("struct def parent wasn't an item")
+                }
+            }
+        }
+    }
+
+    fn map_expr(@mut self, ex: @expr) {
+        self.map.insert(ex.id, node_expr(ex));
+
+        // Expressions which are or might be calls:
+        {
+            let r = ex.get_callee_id();
+            foreach callee_id in r.iter() {
+                self.map.insert(*callee_id, node_callee_scope(ex));
+            }
+        }
+
+        visit::visit_expr(self as @Visitor<()>, ex, ());
+    }
 
-pub fn extend(cx: @mut Ctx, elt: ident) -> @path {
-    @(vec::append(cx.path.clone(), [path_name(elt)]))
+    fn map_fn(@mut self,
+              fk: &visit::fn_kind,
+              decl: &fn_decl,
+              body: &Block,
+              sp: codemap::span,
+              id: NodeId) {
+        foreach a in decl.inputs.iter() {
+            self.map.insert(a.id, node_arg);
+        }
+        visit::visit_fn(self as @Visitor<()>, fk, decl, body, sp, id, ());
+    }
+
+    fn map_stmt(@mut self, stmt: @stmt) {
+        self.map.insert(stmt_id(stmt), node_stmt(stmt));
+        visit::visit_stmt(self as @Visitor<()>, stmt, ());
+    }
+
+    fn map_block(@mut self, b: &Block) {
+        // clone is FIXME #2543
+        self.map.insert(b.id, node_block((*b).clone()));
+        visit::visit_block(self as @Visitor<()>, b, ());
+    }
+
+    fn map_pat(@mut self, pat: @pat) {
+        match pat.node {
+            pat_ident(_, ref path, _) => {
+                // Note: this is at least *potentially* a pattern...
+                self.map.insert(pat.id,
+                                node_local(ast_util::path_to_ident(path)));
+            }
+            _ => ()
+        }
+
+        visit::visit_pat(self as @Visitor<()>, pat, ());
+    }
 }
 
-pub fn mk_ast_map_visitor() -> vt {
-    return visit::mk_vt(@visit::Visitor {
-        visit_item: map_item,
-        visit_expr: map_expr,
-        visit_stmt: map_stmt,
-        visit_fn: map_fn,
-        visit_block: map_block,
-        visit_pat: map_pat,
-        .. *visit::default_visitor()
-    });
+impl Visitor<()> for Ctx {
+    fn visit_item(@mut self, i: @item, _: ()) {
+        // clone is FIXME #2543
+        let item_path = @self.path.clone();
+        self.map.insert(i.id, node_item(i, item_path));
+        match i.node {
+            item_impl(_, _, _, ref ms) => {
+                let impl_did = ast_util::local_def(i.id);
+                foreach m in ms.iter() {
+                    self.map_method(impl_did, self.extend(i.ident), *m, false)
+                }
+            }
+            item_enum(ref enum_definition, _) => {
+                foreach v in (*enum_definition).variants.iter() {
+                    // FIXME #2543: bad clone
+                    self.map.insert(v.node.id,
+                                    node_variant((*v).clone(),
+                                                 i,
+                                                 self.extend(i.ident)));
+                }
+            }
+            item_foreign_mod(ref nm) => {
+                foreach nitem in nm.items.iter() {
+                    // Compute the visibility for this native item.
+                    let visibility = match nitem.vis {
+                        public => public,
+                        private => private,
+                        inherited => i.vis
+                    };
+
+                    self.map.insert(nitem.id,
+                                    node_foreign_item(*nitem,
+                                                      nm.abis,
+                                                      visibility,
+                                                      // FIXME (#2543)
+                                                      if nm.sort ==
+                                                            ast::named {
+                                                        self.extend(i.ident)
+                                                      } else {
+                                                        // Anonymous extern
+                                                        // mods go in the
+                                                        // parent scope.
+                                                        @self.path.clone()
+                                                      }));
+                }
+            }
+            item_struct(struct_def, _) => {
+                self.map_struct_def(struct_def,
+                                    node_item(i, item_path),
+                                    i.ident)
+            }
+            item_trait(_, ref traits, ref methods) => {
+                foreach p in traits.iter() {
+                    self.map.insert(p.ref_id, node_item(i, item_path));
+                }
+                foreach tm in methods.iter() {
+                    let id = ast_util::trait_method_to_ty_method(tm).id;
+                    let d_id = ast_util::local_def(i.id);
+                    self.map.insert(id,
+                                    node_trait_method(@(*tm).clone(),
+                                                      d_id,
+                                                      item_path));
+                }
+            }
+            _ => {}
+        }
+
+        match i.node {
+            item_mod(_) | item_foreign_mod(_) => {
+                self.path.push(path_mod(i.ident));
+            }
+            _ => self.path.push(path_name(i.ident))
+        }
+        visit::visit_item(self as @Visitor<()>, i, ());
+        self.path.pop();
+    }
+
+    fn visit_pat(@mut self, pat: @pat, _: ()) {
+        self.map_pat(pat);
+        visit::visit_pat(self as @Visitor<()>, pat, ())
+    }
+
+    fn visit_expr(@mut self, expr: @expr, _: ()) {
+        self.map_expr(expr)
+    }
+
+    fn visit_stmt(@mut self, stmt: @stmt, _: ()) {
+        self.map_stmt(stmt)
+    }
+
+    fn visit_fn(@mut self,
+                function_kind: &fn_kind,
+                function_declaration: &fn_decl,
+                block: &Block,
+                span: span,
+                node_id: NodeId,
+                _: ()) {
+        self.map_fn(function_kind, function_declaration, block, span, node_id)
+    }
+
+    fn visit_block(@mut self, block: &Block, _: ()) {
+        self.map_block(block)
+    }
+
+    // XXX: Methods below can become default methods.
+
+    fn visit_mod(@mut self, module: &_mod, _: span, _: NodeId, _: ()) {
+        visit::visit_mod(self as @Visitor<()>, module, ())
+    }
+
+    fn visit_view_item(@mut self, view_item: &view_item, _: ()) {
+        visit::visit_view_item(self as @Visitor<()>, view_item, ())
+    }
+
+    fn visit_foreign_item(@mut self, foreign_item: @foreign_item, _: ()) {
+        visit::visit_foreign_item(self as @Visitor<()>, foreign_item, ())
+    }
+
+    fn visit_local(@mut self, local: @Local, _: ()) {
+        visit::visit_local(self as @Visitor<()>, local, ())
+    }
+
+    fn visit_arm(@mut self, arm: &arm, _: ()) {
+        visit::visit_arm(self as @Visitor<()>, arm, ())
+    }
+
+    fn visit_decl(@mut self, decl: @decl, _: ()) {
+        visit::visit_decl(self as @Visitor<()>, decl, ())
+    }
+
+    fn visit_expr_post(@mut self, _: @expr, _: ()) {
+        // Empty!
+    }
+
+    fn visit_ty(@mut self, typ: &Ty, _: ()) {
+        visit::visit_ty(self as @Visitor<()>, typ, ())
+    }
+
+    fn visit_generics(@mut self, generics: &Generics, _: ()) {
+        visit::visit_generics(self as @Visitor<()>, generics, ())
+    }
+
+    fn visit_fn(@mut self,
+                function_kind: &fn_kind,
+                function_declaration: &fn_decl,
+                block: &Block,
+                span: span,
+                node_id: NodeId,
+                _: ()) {
+        visit::visit_fn(self as @Visitor<()>,
+                        function_kind,
+                        function_declaration,
+                        block,
+                        span,
+                        node_id,
+                        ())
+    }
+
+    fn visit_ty_method(@mut self, ty_method: &TypeMethod, _: ()) {
+        visit::visit_ty_method(self as @Visitor<()>, ty_method, ())
+    }
+
+    fn visit_trait_method(@mut self, trait_method: &trait_method, _: ()) {
+        visit::visit_trait_method(self as @Visitor<()>, trait_method, ())
+    }
+
+    fn visit_struct_def(@mut self,
+                        struct_def: @struct_def,
+                        ident: ident,
+                        generics: &Generics,
+                        node_id: NodeId,
+                        _: ()) {
+        visit::visit_struct_def(self as @Visitor<()>,
+                                struct_def,
+                                ident,
+                                generics,
+                                node_id,
+                                ())
+    }
+
+    fn visit_struct_field(@mut self, struct_field: @struct_field, _: ()) {
+        visit::visit_struct_field(self as @Visitor<()>, struct_field, ())
+    }
 }
 
 pub fn map_crate(diag: @span_handler, c: &Crate) -> map {
@@ -110,7 +372,7 @@ pub fn map_crate(diag: @span_handler, c: &Crate) -> map {
         path: ~[],
         diag: diag,
     };
-    visit::visit_crate(c, (cx, mk_ast_map_visitor()));
+    visit::visit_crate(cx as @Visitor<()>, c, ());
     cx.map
 }
 
@@ -123,194 +385,31 @@ pub fn map_decoded_item(diag: @span_handler,
                         ii: &inlined_item) {
     // I believe it is ok for the local IDs of inlined items from other crates
     // to overlap with the local ids from this crate, so just generate the ids
-    // starting from 0.  (In particular, I think these ids are only used in
-    // alias analysis, which we will not be running on the inlined items, and
-    // even if we did I think it only needs an ordering between local
-    // variables that are simultaneously in scope).
+    // starting from 0.
     let cx = @mut Ctx {
         map: map,
         path: path.clone(),
         diag: diag,
     };
-    let v = mk_ast_map_visitor();
 
     // methods get added to the AST map when their impl is visited.  Since we
     // don't decode and instantiate the impl, but just the method, we have to
     // add it to the table now:
     match *ii {
-      ii_item(*) => { /* fallthrough */ }
-      ii_foreign(i) => {
-        cx.map.insert(i.id, node_foreign_item(i,
-                                              AbiSet::Intrinsic(),
-                                              i.vis,    // Wrong but OK
-                                              @path));
-      }
-      ii_method(impl_did, is_provided, m) => {
-        map_method(impl_did, @path, m, is_provided, cx);
-      }
-    }
-
-    // visit the item / method contents and add those to the map:
-    ii.accept(cx, v);
-}
-
-pub fn map_fn(
-    fk: &visit::fn_kind,
-    decl: &fn_decl,
-    body: &Block,
-    sp: codemap::span,
-    id: NodeId,
-    (cx,v): (@mut Ctx,
-             visit::vt<@mut Ctx>)
-) {
-    foreach a in decl.inputs.iter() {
-        cx.map.insert(a.id, node_arg);
-    }
-    visit::visit_fn(fk, decl, body, sp, id, (cx, v));
-}
-
-pub fn map_block(b: &Block, (cx,v): (@mut Ctx, visit::vt<@mut Ctx>)) {
-    cx.map.insert(b.id, node_block(/* FIXME (#2543) */ (*b).clone()));
-    visit::visit_block(b, (cx, v));
-}
-
-pub fn map_pat(pat: @pat, (cx,v): (@mut Ctx, visit::vt<@mut Ctx>)) {
-    match pat.node {
-        pat_ident(_, ref path, _) => {
-            // Note: this is at least *potentially* a pattern...
-            cx.map.insert(pat.id, node_local(ast_util::path_to_ident(path)));
+        ii_item(*) => {} // fallthrough
+        ii_foreign(i) => {
+            cx.map.insert(i.id, node_foreign_item(i,
+                                                  AbiSet::Intrinsic(),
+                                                  i.vis,    // Wrong but OK
+                                                  @path));
         }
-        _ => ()
-    }
-
-    visit::visit_pat(pat, (cx, v));
-}
-
-pub fn map_method(impl_did: def_id, impl_path: @path,
-                  m: @method, is_provided: bool, cx: @mut Ctx) {
-    let entry = if is_provided {
-        node_trait_method(@provided(m), impl_did, impl_path)
-    } else { node_method(m, impl_did, impl_path) };
-    cx.map.insert(m.id, entry);
-    cx.map.insert(m.self_id, node_local(special_idents::self_));
-}
-
-pub fn map_item(i: @item, (cx, v): (@mut Ctx, visit::vt<@mut Ctx>)) {
-    let item_path = @/* FIXME (#2543) */ cx.path.clone();
-    cx.map.insert(i.id, node_item(i, item_path));
-    match i.node {
-        item_impl(_, _, _, ref ms) => {
-            let impl_did = ast_util::local_def(i.id);
-            foreach m in ms.iter() {
-                map_method(impl_did, extend(cx, i.ident), *m, false, cx);
-            }
-        }
-        item_enum(ref enum_definition, _) => {
-            foreach v in (*enum_definition).variants.iter() {
-                cx.map.insert(v.node.id, node_variant(
-                    /* FIXME (#2543) */ (*v).clone(),
-                    i,
-                    extend(cx, i.ident)));
-            }
-        }
-        item_foreign_mod(ref nm) => {
-            foreach nitem in nm.items.iter() {
-                // Compute the visibility for this native item.
-                let visibility = match nitem.vis {
-                    public => public,
-                    private => private,
-                    inherited => i.vis
-                };
-
-                cx.map.insert(nitem.id,
-                    node_foreign_item(
-                        *nitem,
-                        nm.abis,
-                        visibility,
-                        // FIXME (#2543)
-                        if nm.sort == ast::named {
-                            extend(cx, i.ident)
-                        } else {
-                            // Anonymous extern mods go in the parent scope
-                            @cx.path.clone()
-                        }
-                    )
-                );
-            }
-        }
-        item_struct(struct_def, _) => {
-            map_struct_def(
-                struct_def,
-                node_item(i, item_path),
-                i.ident,
-                (cx,
-                 v)
-            );
-        }
-        item_trait(_, ref traits, ref methods) => {
-            foreach p in traits.iter() {
-                cx.map.insert(p.ref_id, node_item(i, item_path));
-            }
-            foreach tm in methods.iter() {
-                let id = ast_util::trait_method_to_ty_method(tm).id;
-                let d_id = ast_util::local_def(i.id);
-                cx.map.insert(
-                    id,
-                    node_trait_method(@(*tm).clone(), d_id, item_path)
-                );
-            }
+        ii_method(impl_did, is_provided, m) => {
+            cx.map_method(impl_did, @path, m, is_provided);
         }
-        _ => ()
     }
 
-    match i.node {
-        item_mod(_) | item_foreign_mod(_) => {
-            cx.path.push(path_mod(i.ident));
-        }
-        _ => cx.path.push(path_name(i.ident))
-    }
-    visit::visit_item(i, (cx, v));
-    cx.path.pop();
-}
-
-pub fn map_struct_def(
-    struct_def: @ast::struct_def,
-    parent_node: ast_node,
-    ident: ast::ident,
-    (cx, _v): (@mut Ctx,
-               visit::vt<@mut Ctx>)
-) {
-    let p = extend(cx, ident);
-    // If this is a tuple-like struct, register the constructor.
-    match struct_def.ctor_id {
-        None => {}
-        Some(ctor_id) => {
-            match parent_node {
-                node_item(item, _) => {
-                    cx.map.insert(ctor_id,
-                                  node_struct_ctor(struct_def, item, p));
-                }
-                _ => fail!("struct def parent wasn't an item")
-            }
-        }
-    }
-}
-
-pub fn map_expr(ex: @expr, (cx,v): (@mut Ctx, visit::vt<@mut Ctx>)) {
-    cx.map.insert(ex.id, node_expr(ex));
-    // Expressions which are or might be calls:
-    {
-        let r = ex.get_callee_id();
-        foreach callee_id in r.iter() {
-            cx.map.insert(*callee_id, node_callee_scope(ex));
-        }
-    }
-    visit::visit_expr(ex, (cx, v));
-}
-
-pub fn map_stmt(stmt: @stmt, (cx,v): (@mut Ctx, visit::vt<@mut Ctx>)) {
-    cx.map.insert(stmt_id(stmt), node_stmt(stmt));
-    visit::visit_stmt(stmt, (cx, v));
+    // visit the item / method contents and add those to the map:
+    ii.accept((), cx as @Visitor<()>);
 }
 
 pub fn node_id_to_str(map: map, id: NodeId, itr: @ident_interner) -> ~str {
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index b8a2ea1b57d..45238c30d73 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -14,6 +14,7 @@ use ast_util;
 use codemap::{span, dummy_sp};
 use opt_vec;
 use parse::token;
+use visit::{SimpleVisitor, SimpleVisitorVisitor, Visitor};
 use visit;
 
 use std::hashmap::HashMap;
@@ -297,7 +298,7 @@ pub fn struct_field_visibility(field: ast::struct_field) -> visibility {
 pub trait inlined_item_utils {
     fn ident(&self) -> ident;
     fn id(&self) -> ast::NodeId;
-    fn accept<E: Clone>(&self, e: E, v: visit::vt<E>);
+    fn accept<E: Clone>(&self, e: E, v: @Visitor<E>);
 }
 
 impl inlined_item_utils for inlined_item {
@@ -317,11 +318,11 @@ impl inlined_item_utils for inlined_item {
         }
     }
 
-    fn accept<E: Clone>(&self, e: E, v: visit::vt<E>) {
+    fn accept<E: Clone>(&self, e: E, v: @Visitor<E>) {
         match *self {
-            ii_item(i) => (v.visit_item)(i, (e, v)),
-            ii_foreign(i) => (v.visit_foreign_item)(i, (e, v)),
-            ii_method(_, _, m) => visit::visit_method_helper(m, (e, v)),
+            ii_item(i) => v.visit_item(i, e),
+            ii_foreign(i) => v.visit_foreign_item(i, e),
+            ii_method(_, _, m) => visit::visit_method_helper(v, m, e),
         }
     }
 }
@@ -339,8 +340,8 @@ pub fn is_self(d: ast::def) -> bool {
 /// Maps a binary operator to its precedence
 pub fn operator_prec(op: ast::binop) -> uint {
   match op {
-      mul | div | rem   => 12u,
-      // 'as' sits between here with 11
+      // 'as' sits here with 12
+      mul | div | rem   => 11u,
       add | subtract    => 10u,
       shl | shr         =>  9u,
       bitand            =>  8u,
@@ -355,7 +356,7 @@ pub fn operator_prec(op: ast::binop) -> uint {
 
 /// Precedence of the `as` operator, which is a binary operator
 /// not appearing in the prior table.
-pub static as_prec: uint = 11u;
+pub static as_prec: uint = 12u;
 
 pub fn empty_generics() -> Generics {
     Generics {lifetimes: opt_vec::Empty,
@@ -389,134 +390,238 @@ impl id_range {
     }
 }
 
-pub fn id_visitor<T: Clone>(vfn: @fn(NodeId, T)) -> visit::vt<T> {
-    let visit_generics: @fn(&Generics, T) = |generics, t| {
-        foreach p in generics.ty_params.iter() {
-            vfn(p.id, t.clone());
+struct IdVisitor {
+    visit_callback: @fn(NodeId),
+    pass_through_items: bool,
+    visited_outermost: bool,
+}
+
+impl IdVisitor {
+    fn visit_generics_helper(@mut self, generics: &Generics) {
+        foreach type_parameter in generics.ty_params.iter() {
+            (self.visit_callback)(type_parameter.id)
         }
-        foreach p in generics.lifetimes.iter() {
-            vfn(p.id, t.clone());
+        foreach lifetime in generics.lifetimes.iter() {
+            (self.visit_callback)(lifetime.id)
         }
-    };
-    visit::mk_vt(@visit::Visitor {
-        visit_mod: |m, sp, id, (t, vt): (T, visit::vt<T>)| {
-            vfn(id, t.clone());
-            visit::visit_mod(m, sp, id, (t, vt));
-        },
+    }
+}
 
-        visit_view_item: |vi, (t, vt)| {
-            match vi.node {
-              view_item_extern_mod(_, _, id) => vfn(id, t.clone()),
-              view_item_use(ref vps) => {
-                  foreach vp in vps.iter() {
-                      match vp.node {
-                          view_path_simple(_, _, id) => vfn(id, t.clone()),
-                          view_path_glob(_, id) => vfn(id, t.clone()),
-                          view_path_list(_, ref paths, id) => {
-                              vfn(id, t.clone());
-                              foreach p in paths.iter() {
-                                  vfn(p.node.id, t.clone());
-                              }
-                          }
-                      }
-                  }
-              }
+impl Visitor<()> for IdVisitor {
+    fn visit_mod(@mut self,
+                 module: &_mod,
+                 span: span,
+                 node_id: NodeId,
+                 env: ()) {
+        (self.visit_callback)(node_id);
+        visit::visit_mod(self as @Visitor<()>, module, env)
+    }
+
+    fn visit_view_item(@mut self, view_item: &view_item, env: ()) {
+        match view_item.node {
+            view_item_extern_mod(_, _, node_id) => {
+                (self.visit_callback)(node_id)
             }
-            visit::visit_view_item(vi, (t, vt));
-        },
+            view_item_use(ref view_paths) => {
+                foreach view_path in view_paths.iter() {
+                    match view_path.node {
+                        view_path_simple(_, _, node_id) |
+                        view_path_glob(_, node_id) => {
+                            (self.visit_callback)(node_id)
+                        }
+                        view_path_list(_, ref paths, node_id) => {
+                            (self.visit_callback)(node_id);
+                            foreach path in paths.iter() {
+                                (self.visit_callback)(path.node.id)
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        visit::visit_view_item(self as @Visitor<()>, view_item, env)
+    }
 
-        visit_foreign_item: |ni, (t, vt)| {
-            vfn(ni.id, t.clone());
-            visit::visit_foreign_item(ni, (t, vt));
-        },
+    fn visit_foreign_item(@mut self, foreign_item: @foreign_item, env: ()) {
+        (self.visit_callback)(foreign_item.id);
+        visit::visit_foreign_item(self as @Visitor<()>, foreign_item, env)
+    }
 
-        visit_item: |i, (t, vt)| {
-            vfn(i.id, t.clone());
-            match i.node {
-              item_enum(ref enum_definition, _) =>
-                foreach v in (*enum_definition).variants.iter() {
-                    vfn(v.node.id, t.clone());
-                },
-              _ => ()
+    fn visit_item(@mut self, item: @item, env: ()) {
+        if !self.pass_through_items {
+            if self.visited_outermost {
+                return
+            } else {
+                self.visited_outermost = true
             }
-            visit::visit_item(i, (t, vt));
-        },
-
-        visit_local: |l, (t, vt)| {
-            vfn(l.id, t.clone());
-            visit::visit_local(l, (t, vt));
-        },
-        visit_block: |b, (t, vt)| {
-            vfn(b.id, t.clone());
-            visit::visit_block(b, (t, vt));
-        },
-        visit_stmt: |s, (t, vt)| {
-            vfn(ast_util::stmt_id(s), t.clone());
-            visit::visit_stmt(s, (t, vt));
-        },
-        visit_pat: |p, (t, vt)| {
-            vfn(p.id, t.clone());
-            visit::visit_pat(p, (t, vt));
-        },
+        }
 
-        visit_expr: |e, (t, vt)| {
-            {
-                let r = e.get_callee_id();
-                foreach callee_id in r.iter() {
-                    vfn(*callee_id, t.clone());
+        (self.visit_callback)(item.id);
+        match item.node {
+            item_enum(ref enum_definition, _) => {
+                foreach variant in enum_definition.variants.iter() {
+                    (self.visit_callback)(variant.node.id)
                 }
             }
-            vfn(e.id, t.clone());
-            visit::visit_expr(e, (t, vt));
-        },
+            _ => {}
+        }
+
+        visit::visit_item(self as @Visitor<()>, item, env);
+
+        self.visited_outermost = false
+    }
+
+    fn visit_local(@mut self, local: @Local, env: ()) {
+        (self.visit_callback)(local.id);
+        visit::visit_local(self as @Visitor<()>, local, env)
+    }
+
+    fn visit_block(@mut self, block: &Block, env: ()) {
+        (self.visit_callback)(block.id);
+        visit::visit_block(self as @Visitor<()>, block, env)
+    }
+
+    fn visit_stmt(@mut self, statement: @stmt, env: ()) {
+        (self.visit_callback)(ast_util::stmt_id(statement));
+        visit::visit_stmt(self as @Visitor<()>, statement, env)
+    }
+
+    // XXX: Default
+    fn visit_arm(@mut self, arm: &arm, env: ()) {
+        visit::visit_arm(self as @Visitor<()>, arm, env)
+    }
 
-        visit_ty: |ty, (t, vt)| {
-            vfn(ty.id, t.clone());
-            match ty.node {
-              ty_path(_, _, id) => vfn(id, t.clone()),
-              _ => { /* fall through */ }
+    fn visit_pat(@mut self, pattern: @pat, env: ()) {
+        (self.visit_callback)(pattern.id);
+        visit::visit_pat(self as @Visitor<()>, pattern, env)
+    }
+
+    // XXX: Default
+    fn visit_decl(@mut self, declaration: @decl, env: ()) {
+        visit::visit_decl(self as @Visitor<()>, declaration, env)
+    }
+
+    fn visit_expr(@mut self, expression: @expr, env: ()) {
+        {
+            let optional_callee_id = expression.get_callee_id();
+            foreach callee_id in optional_callee_id.iter() {
+                (self.visit_callback)(*callee_id)
             }
-            visit::visit_ty(ty, (t, vt));
-        },
+        }
+        (self.visit_callback)(expression.id);
+        visit::visit_expr(self as @Visitor<()>, expression, env)
+    }
 
-        visit_generics: |generics, (t, vt)| {
-            visit_generics(generics, t.clone());
-            visit::visit_generics(generics, (t, vt));
-        },
+    // XXX: Default
+    fn visit_expr_post(@mut self, _: @expr, _: ()) {
+        // Empty!
+    }
 
-        visit_fn: |fk, d, a, b, id, (t, vt)| {
-            vfn(id, t.clone());
+    fn visit_ty(@mut self, typ: &Ty, env: ()) {
+        (self.visit_callback)(typ.id);
+        match typ.node {
+            ty_path(_, _, id) => (self.visit_callback)(id),
+            _ => {}
+        }
+        visit::visit_ty(self as @Visitor<()>, typ, env)
+    }
 
-            match *fk {
-                visit::fk_item_fn(_, generics, _, _) => {
-                    visit_generics(generics, t.clone());
-                }
-                visit::fk_method(_, generics, m) => {
-                    vfn(m.self_id, t.clone());
-                    visit_generics(generics, t.clone());
-                }
-                visit::fk_anon(_) |
-                visit::fk_fn_block => {
-                }
+    fn visit_generics(@mut self, generics: &Generics, env: ()) {
+        self.visit_generics_helper(generics);
+        visit::visit_generics(self as @Visitor<()>, generics, env)
+    }
+
+    fn visit_fn(@mut self,
+                function_kind: &visit::fn_kind,
+                function_declaration: &fn_decl,
+                block: &Block,
+                span: span,
+                node_id: NodeId,
+                env: ()) {
+        if !self.pass_through_items {
+            match *function_kind {
+                visit::fk_method(*) if self.visited_outermost => return,
+                visit::fk_method(*) => self.visited_outermost = true,
+                _ => {}
             }
+        }
+
+        (self.visit_callback)(node_id);
 
-            foreach arg in d.inputs.iter() {
-                vfn(arg.id, t.clone())
+        match *function_kind {
+            visit::fk_item_fn(_, generics, _, _) => {
+                self.visit_generics_helper(generics)
             }
-            visit::visit_fn(fk, d, a, b, id, (t.clone(), vt));
-        },
+            visit::fk_method(_, generics, method) => {
+                (self.visit_callback)(method.self_id);
+                self.visit_generics_helper(generics)
+            }
+            visit::fk_anon(_) | visit::fk_fn_block => {}
+        }
 
-        visit_struct_field: |f, (t, vt)| {
-            vfn(f.node.id, t.clone());
-            visit::visit_struct_field(f, (t, vt));
-        },
+        foreach argument in function_declaration.inputs.iter() {
+            (self.visit_callback)(argument.id)
+        }
 
-        .. *visit::default_visitor()
-    })
+        visit::visit_fn(self as @Visitor<()>,
+                        function_kind,
+                        function_declaration,
+                        block,
+                        span,
+                        node_id,
+                        env);
+
+        if !self.pass_through_items {
+            match *function_kind {
+                visit::fk_method(*) => self.visited_outermost = false,
+                _ => {}
+            }
+        }
+    }
+
+    // XXX: Default
+    fn visit_ty_method(@mut self, type_method: &TypeMethod, env: ()) {
+        visit::visit_ty_method(self as @Visitor<()>, type_method, env)
+    }
+
+    // XXX: Default
+    fn visit_trait_method(@mut self, trait_method: &trait_method, env: ()) {
+        visit::visit_trait_method(self as @Visitor<()>, trait_method, env)
+    }
+
+    // XXX: Default
+    fn visit_struct_def(@mut self,
+                        struct_definition: @struct_def,
+                        identifier: ident,
+                        generics: &Generics,
+                        node_id: NodeId,
+                        env: ()) {
+        visit::visit_struct_def(self as @Visitor<()>,
+                                struct_definition,
+                                identifier,
+                                generics,
+                                node_id,
+                                env)
+    }
+
+    fn visit_struct_field(@mut self, struct_field: @struct_field, env: ()) {
+        (self.visit_callback)(struct_field.node.id);
+        visit::visit_struct_field(self as @Visitor<()>, struct_field, env)
+    }
+}
+
+pub fn id_visitor(vfn: @fn(NodeId), pass_through_items: bool)
+                  -> @Visitor<()> {
+    let visitor = @IdVisitor {
+        visit_callback: vfn,
+        pass_through_items: pass_through_items,
+        visited_outermost: false,
+    };
+    visitor as @Visitor<()>
 }
 
 pub fn visit_ids_for_inlined_item(item: &inlined_item, vfn: @fn(NodeId)) {
-    item.accept((), id_visitor(|id, ()| vfn(id)));
+    item.accept((), id_visitor(|id| vfn(id), true));
 }
 
 pub fn compute_id_range(visit_ids_fn: &fn(@fn(NodeId))) -> id_range {
@@ -570,13 +675,91 @@ pub trait EachViewItem {
     pub fn each_view_item(&self, f: @fn(&ast::view_item) -> bool) -> bool;
 }
 
+struct EachViewItemData {
+    callback: @fn(&ast::view_item) -> bool,
+}
+
+impl SimpleVisitor for EachViewItemData {
+    fn visit_mod(@mut self, _: &_mod, _: span, _: NodeId) {
+        // XXX: Default method.
+    }
+    fn visit_view_item(@mut self, view_item: &view_item) {
+        let _ = (self.callback)(view_item);
+    }
+    fn visit_foreign_item(@mut self, _: @foreign_item) {
+        // XXX: Default method.
+    }
+    fn visit_item(@mut self, _: @item) {
+        // XXX: Default method.
+    }
+    fn visit_local(@mut self, _: @Local) {
+        // XXX: Default method.
+    }
+    fn visit_block(@mut self, _: &Block) {
+        // XXX: Default method.
+    }
+    fn visit_stmt(@mut self, _: @stmt) {
+        // XXX: Default method.
+    }
+    fn visit_arm(@mut self, _: &arm) {
+        // XXX: Default method.
+    }
+    fn visit_pat(@mut self, _: @pat) {
+        // XXX: Default method.
+    }
+    fn visit_decl(@mut self, _: @decl) {
+        // XXX: Default method.
+    }
+    fn visit_expr(@mut self, _: @expr) {
+        // XXX: Default method.
+    }
+    fn visit_expr_post(@mut self, _: @expr) {
+        // XXX: Default method.
+    }
+    fn visit_ty(@mut self, _: &Ty) {
+        // XXX: Default method.
+    }
+    fn visit_generics(@mut self, _: &Generics) {
+        // XXX: Default method.
+    }
+    fn visit_fn(@mut self,
+                _: &visit::fn_kind,
+                _: &fn_decl,
+                _: &Block,
+                _: span,
+                _: NodeId) {
+        // XXX: Default method.
+    }
+    fn visit_ty_method(@mut self, _: &TypeMethod) {
+        // XXX: Default method.
+    }
+    fn visit_trait_method(@mut self, _: &trait_method) {
+        // XXX: Default method.
+    }
+    fn visit_struct_def(@mut self,
+                        _: @struct_def,
+                        _: ident,
+                        _: &Generics,
+                        _: NodeId) {
+        // XXX: Default method.
+    }
+    fn visit_struct_field(@mut self, _: @struct_field) {
+        // XXX: Default method.
+    }
+    fn visit_struct_method(@mut self, _: @method) {
+        // XXX: Default method.
+    }
+}
+
 impl EachViewItem for ast::Crate {
     fn each_view_item(&self, f: @fn(&ast::view_item) -> bool) -> bool {
-        let broke = @mut false;
-        let vtor: visit::vt<()> = visit::mk_simple_visitor(@visit::SimpleVisitor {
-            visit_view_item: |vi| { *broke = f(vi); }, ..*visit::default_simple_visitor()
-        });
-        visit::visit_crate(self, ((), vtor));
+        let data = @mut EachViewItemData {
+            callback: f,
+        };
+        let visitor = @mut SimpleVisitorVisitor {
+            simple_visitor: data as @SimpleVisitor,
+        };
+        visit::visit_crate(visitor as @Visitor<()>, self, ());
         true
     }
 }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index dc096a145cc..0ec367653c0 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{Block, Crate, expr_, expr_mac, mac_invoc_tt};
+use ast::{Block, Crate, NodeId, expr_, expr_mac, ident, mac_invoc_tt};
 use ast::{item_mac, stmt_, stmt_mac, stmt_expr, stmt_semi};
 use ast::{illegal_ctxt};
 use ast;
@@ -516,35 +516,153 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
 
 }
 
-// return a visitor that extracts the pat_ident paths
-// from a given pattern and puts them in a mutable
-// array (passed in to the traversal)
-pub fn new_name_finder() -> @Visitor<@mut ~[ast::ident]> {
-    let default_visitor = visit::default_visitor();
-    @Visitor{
-        visit_pat : |p:@ast::pat,
-                     (ident_accum, v): (@mut ~[ast::ident], visit::vt<@mut ~[ast::ident]>)| {
-            match *p {
-                // we found a pat_ident!
-                ast::pat{id:_, node: ast::pat_ident(_,ref path,ref inner), span:_} => {
-                    match path {
-                        // a path of length one:
-                        &ast::Path{global: false,idents: [id], span:_,rp:_,types:_} =>
-                        ident_accum.push(id),
-                        // I believe these must be enums...
-                        _ => ()
-                    }
-                    // visit optional subpattern of pat_ident:
-                    foreach subpat in inner.iter() {
-                        (v.visit_pat)(*subpat, (ident_accum, v))
-                    }
+#[deriving(Clone)]
+struct NewNameFinderContext {
+    ident_accumulator: @mut ~[ast::ident],
+}
+
+impl Visitor<()> for NewNameFinderContext {
+    fn visit_pat(@mut self, pattern: @ast::pat, _: ()) {
+        match *pattern {
+            // we found a pat_ident!
+            ast::pat {
+                id: _,
+                node: ast::pat_ident(_, ref path, ref inner),
+                span: _
+            } => {
+                match path {
+                    // a path of length one:
+                    &ast::Path {
+                        global: false,
+                        idents: [id],
+                        span: _,
+                        rp: _,
+                        types: _
+                    } => self.ident_accumulator.push(id),
+                    // I believe these must be enums...
+                    _ => ()
+                }
+                // visit optional subpattern of pat_ident:
+                foreach subpat in inner.iter() {
+                    self.visit_pat(*subpat, ())
                 }
-                // use the default traversal for non-pat_idents
-                _ => visit::visit_pat(p,(ident_accum,v))
             }
-        },
-        .. *default_visitor
+            // use the default traversal for non-pat_idents
+            _ => visit::visit_pat(self as @Visitor<()>, pattern, ())
+        }
+    }
+
+    // XXX: Methods below can become default methods.
+
+    fn visit_mod(@mut self, module: &ast::_mod, _: span, _: NodeId, _: ()) {
+        visit::visit_mod(self as @Visitor<()>, module, ())
+    }
+
+    fn visit_view_item(@mut self, view_item: &ast::view_item, _: ()) {
+        visit::visit_view_item(self as @Visitor<()>, view_item, ())
+    }
+
+    fn visit_item(@mut self, item: @ast::item, _: ()) {
+        visit::visit_item(self as @Visitor<()>, item, ())
+    }
+
+    fn visit_foreign_item(@mut self,
+                          foreign_item: @ast::foreign_item,
+                          _: ()) {
+        visit::visit_foreign_item(self as @Visitor<()>, foreign_item, ())
+    }
+
+    fn visit_local(@mut self, local: @ast::Local, _: ()) {
+        visit::visit_local(self as @Visitor<()>, local, ())
+    }
+
+    fn visit_block(@mut self, block: &ast::Block, _: ()) {
+        visit::visit_block(self as @Visitor<()>, block, ())
+    }
+
+    fn visit_stmt(@mut self, stmt: @ast::stmt, _: ()) {
+        visit::visit_stmt(self as @Visitor<()>, stmt, ())
+    }
+
+    fn visit_arm(@mut self, arm: &ast::arm, _: ()) {
+        visit::visit_arm(self as @Visitor<()>, arm, ())
     }
+
+    fn visit_decl(@mut self, decl: @ast::decl, _: ()) {
+        visit::visit_decl(self as @Visitor<()>, decl, ())
+    }
+
+    fn visit_expr(@mut self, expr: @ast::expr, _: ()) {
+        visit::visit_expr(self as @Visitor<()>, expr, ())
+    }
+
+    fn visit_expr_post(@mut self, _: @ast::expr, _: ()) {
+        // Empty!
+    }
+
+    fn visit_ty(@mut self, typ: &ast::Ty, _: ()) {
+        visit::visit_ty(self as @Visitor<()>, typ, ())
+    }
+
+    fn visit_generics(@mut self, generics: &ast::Generics, _: ()) {
+        visit::visit_generics(self as @Visitor<()>, generics, ())
+    }
+
+    fn visit_fn(@mut self,
+                function_kind: &visit::fn_kind,
+                function_declaration: &ast::fn_decl,
+                block: &ast::Block,
+                span: span,
+                node_id: NodeId,
+                _: ()) {
+        visit::visit_fn(self as @Visitor<()>,
+                        function_kind,
+                        function_declaration,
+                        block,
+                        span,
+                        node_id,
+                        ())
+    }
+
+    fn visit_ty_method(@mut self, ty_method: &ast::TypeMethod, _: ()) {
+        visit::visit_ty_method(self as @Visitor<()>, ty_method, ())
+    }
+
+    fn visit_trait_method(@mut self,
+                          trait_method: &ast::trait_method,
+                          _: ()) {
+        visit::visit_trait_method(self as @Visitor<()>, trait_method, ())
+    }
+
+    fn visit_struct_def(@mut self,
+                        struct_def: @ast::struct_def,
+                        ident: ident,
+                        generics: &ast::Generics,
+                        node_id: NodeId,
+                        _: ()) {
+        visit::visit_struct_def(self as @Visitor<()>,
+                                struct_def,
+                                ident,
+                                generics,
+                                node_id,
+                                ())
+    }
+
+    fn visit_struct_field(@mut self,
+                          struct_field: @ast::struct_field,
+                          _: ()) {
+        visit::visit_struct_field(self as @Visitor<()>, struct_field, ())
+    }
+}
+
+// return a visitor that extracts the pat_ident paths
+// from a given pattern and puts them in a mutable
+// array (passed in to the traversal)
+pub fn new_name_finder(idents: @mut ~[ast::ident]) -> @Visitor<()> {
+    let context = @mut NewNameFinderContext {
+        ident_accumulator: idents,
+    };
+    context as @Visitor<()>
 }
 
 pub fn expand_block(extsbox: @mut SyntaxEnv,
@@ -955,7 +1073,7 @@ mod test {
     use parse::token::{intern, get_ident_interner};
     use print::pprust;
     use util::parser_testing::{string_to_item, string_to_pat, strs_to_idents};
-    use visit::{mk_vt};
+    use oldvisit::{mk_vt};
 
     // make sure that fail! is present
     #[test] fn fail_exists_test () {
@@ -1079,9 +1197,9 @@ mod test {
     #[test]
     fn pat_idents(){
         let pat = string_to_pat(@"(a,Foo{x:c @ (b,9),y:Bar(4,d)})");
-        let pat_idents = new_name_finder();
         let idents = @mut ~[];
-        ((*pat_idents).visit_pat)(pat, (idents, mk_vt(pat_idents)));
-        assert_eq!(idents,@mut strs_to_idents(~["a","c","b","d"]));
+        let pat_idents = new_name_finder(idents);
+        pat_idents.visit_pat(pat, ());
+        assert_eq!(idents, @mut strs_to_idents(~["a","c","b","d"]));
     }
 }
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index f0b00f5681c..9bda1189a8e 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -223,7 +223,7 @@ fn noop_fold_foreign_item(ni: @foreign_item, fld: @ast_fold)
         attrs: ni.attrs.map(|x| fold_attribute(*x)),
         node:
             match ni.node {
-                foreign_item_fn(ref fdec, purity, ref generics) => {
+                foreign_item_fn(ref fdec, ref generics) => {
                     foreign_item_fn(
                         ast::fn_decl {
                             inputs: fdec.inputs.map(|a|
@@ -231,7 +231,6 @@ fn noop_fold_foreign_item(ni: @foreign_item, fld: @ast_fold)
                             output: fld.fold_ty(&fdec.output),
                             cf: fdec.cf,
                         },
-                        purity,
                         fold_generics(generics, fld))
                 }
                 foreign_item_static(ref t, m) => {
diff --git a/src/libsyntax/oldvisit.rs b/src/libsyntax/oldvisit.rs
new file mode 100644
index 00000000000..a39dc38a856
--- /dev/null
+++ b/src/libsyntax/oldvisit.rs
@@ -0,0 +1,775 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use abi::AbiSet;
+use ast::*;
+use ast;
+use codemap::span;
+use parse;
+use opt_vec;
+use opt_vec::OptVec;
+
+// Context-passing AST walker. Each overridden visit method has full control
+// over what happens with its node, it can do its own traversal of the node's
+// children (potentially passing in different contexts to each), call
+// visit::visit_* to apply the default traversal algorithm (again, it can
+// override the context), or prevent deeper traversal by doing nothing.
+//
+// Note: it is an important invariant that the default visitor walks the body
+// of a function in "execution order" (more concretely, reverse post-order
+// with respect to the CFG implied by the AST), meaning that if AST node A may
+// execute before AST node B, then A is visited first.  The borrow checker in
+// particular relies on this property.
+
+// Our typesystem doesn't do circular types, so the visitor record can not
+// hold functions that take visitors. A vt enum is used to break the cycle.
+pub enum vt<E> { mk_vt(visitor<E>), }
+
+pub enum fn_kind<'self> {
+    // fn foo() or extern "Abi" fn foo()
+    fk_item_fn(ident, &'self Generics, purity, AbiSet),
+
+    // fn foo(&self)
+    fk_method(ident, &'self Generics, &'self method),
+
+    // @fn(x, y) { ... }
+    fk_anon(ast::Sigil),
+
+    // |x, y| ...
+    fk_fn_block,
+}
+
+pub fn name_of_fn(fk: &fn_kind) -> ident {
+    match *fk {
+      fk_item_fn(name, _, _, _) | fk_method(name, _, _) => {
+          name
+      }
+      fk_anon(*) | fk_fn_block(*) => parse::token::special_idents::anon,
+    }
+}
+
+pub fn generics_of_fn(fk: &fn_kind) -> Generics {
+    match *fk {
+        fk_item_fn(_, generics, _, _) |
+        fk_method(_, generics, _) => {
+            (*generics).clone()
+        }
+        fk_anon(*) | fk_fn_block(*) => {
+            Generics {
+                lifetimes: opt_vec::Empty,
+                ty_params: opt_vec::Empty,
+            }
+        }
+    }
+}
+
+pub struct Visitor<E> {
+    visit_mod: @fn(&_mod, span, NodeId, (E, vt<E>)),
+    visit_view_item: @fn(&view_item, (E, vt<E>)),
+    visit_foreign_item: @fn(@foreign_item, (E, vt<E>)),
+    visit_item: @fn(@item, (E, vt<E>)),
+    visit_local: @fn(@Local, (E, vt<E>)),
+    visit_block: @fn(&Block, (E, vt<E>)),
+    visit_stmt: @fn(@stmt, (E, vt<E>)),
+    visit_arm: @fn(&arm, (E, vt<E>)),
+    visit_pat: @fn(@pat, (E, vt<E>)),
+    visit_decl: @fn(@decl, (E, vt<E>)),
+    visit_expr: @fn(@expr, (E, vt<E>)),
+    visit_expr_post: @fn(@expr, (E, vt<E>)),
+    visit_ty: @fn(&Ty, (E, vt<E>)),
+    visit_generics: @fn(&Generics, (E, vt<E>)),
+    visit_fn: @fn(&fn_kind, &fn_decl, &Block, span, NodeId, (E, vt<E>)),
+    visit_ty_method: @fn(&TypeMethod, (E, vt<E>)),
+    visit_trait_method: @fn(&trait_method, (E, vt<E>)),
+    visit_struct_def: @fn(@struct_def, ident, &Generics, NodeId, (E, vt<E>)),
+    visit_struct_field: @fn(@struct_field, (E, vt<E>)),
+}
+
+pub type visitor<E> = @Visitor<E>;
+
+pub fn default_visitor<E:Clone>() -> visitor<E> {
+    return @Visitor {
+        visit_mod: |a,b,c,d|visit_mod::<E>(a, b, c, d),
+        visit_view_item: |a,b|visit_view_item::<E>(a, b),
+        visit_foreign_item: |a,b|visit_foreign_item::<E>(a, b),
+        visit_item: |a,b|visit_item::<E>(a, b),
+        visit_local: |a,b|visit_local::<E>(a, b),
+        visit_block: |a,b|visit_block::<E>(a, b),
+        visit_stmt: |a,b|visit_stmt::<E>(a, b),
+        visit_arm: |a,b|visit_arm::<E>(a, b),
+        visit_pat: |a,b|visit_pat::<E>(a, b),
+        visit_decl: |a,b|visit_decl::<E>(a, b),
+        visit_expr: |a,b|visit_expr::<E>(a, b),
+        visit_expr_post: |_a,_b| (),
+        visit_ty: |a,b|skip_ty::<E>(a, b),
+        visit_generics: |a,b|visit_generics::<E>(a, b),
+        visit_fn: |a,b,c,d,e,f|visit_fn::<E>(a, b, c, d, e, f),
+        visit_ty_method: |a,b|visit_ty_method::<E>(a, b),
+        visit_trait_method: |a,b|visit_trait_method::<E>(a, b),
+        visit_struct_def: |a,b,c,d,e|visit_struct_def::<E>(a, b, c, d, e),
+        visit_struct_field: |a,b|visit_struct_field::<E>(a, b),
+    };
+}
+
+pub fn visit_crate<E:Clone>(c: &Crate, (e, v): (E, vt<E>)) {
+    (v.visit_mod)(&c.module, c.span, CRATE_NODE_ID, (e, v));
+}
+
+pub fn visit_mod<E:Clone>(m: &_mod,
+                          _sp: span,
+                          _id: NodeId,
+                          (e, v): (E, vt<E>)) {
+    for m.view_items.iter().advance |vi| {
+        (v.visit_view_item)(vi, (e.clone(), v));
+    }
+    for m.items.iter().advance |i| {
+        (v.visit_item)(*i, (e.clone(), v));
+    }
+}
+
+pub fn visit_view_item<E>(_vi: &view_item, (_e, _v): (E, vt<E>)) { }
+
+pub fn visit_local<E:Clone>(loc: &Local, (e, v): (E, vt<E>)) {
+    (v.visit_pat)(loc.pat, (e.clone(), v));
+    (v.visit_ty)(&loc.ty, (e.clone(), v));
+    match loc.init {
+      None => (),
+      Some(ex) => (v.visit_expr)(ex, (e, v))
+    }
+}
+
+fn visit_trait_ref<E:Clone>(tref: &ast::trait_ref, (e, v): (E, vt<E>)) {
+    visit_path(&tref.path, (e, v));
+}
+
+pub fn visit_item<E:Clone>(i: &item, (e, v): (E, vt<E>)) {
+    match i.node {
+        item_static(ref t, _, ex) => {
+            (v.visit_ty)(t, (e.clone(), v));
+            (v.visit_expr)(ex, (e.clone(), v));
+        }
+        item_fn(ref decl, purity, abi, ref generics, ref body) => {
+            (v.visit_fn)(
+                &fk_item_fn(
+                    i.ident,
+                    generics,
+                    purity,
+                    abi
+                ),
+                decl,
+                body,
+                i.span,
+                i.id,
+                (e,
+                 v)
+            );
+        }
+        item_mod(ref m) => (v.visit_mod)(m, i.span, i.id, (e, v)),
+        item_foreign_mod(ref nm) => {
+            for nm.view_items.iter().advance |vi| {
+                (v.visit_view_item)(vi, (e.clone(), v));
+            }
+            for nm.items.iter().advance |ni| {
+                (v.visit_foreign_item)(*ni, (e.clone(), v));
+            }
+        }
+        item_ty(ref t, ref tps) => {
+            (v.visit_ty)(t, (e.clone(), v));
+            (v.visit_generics)(tps, (e, v));
+        }
+        item_enum(ref enum_definition, ref tps) => {
+            (v.visit_generics)(tps, (e.clone(), v));
+            visit_enum_def(
+                enum_definition,
+                tps,
+                (e, v)
+            );
+        }
+        item_impl(ref tps, ref traits, ref ty, ref methods) => {
+            (v.visit_generics)(tps, (e.clone(), v));
+            for traits.iter().advance |p| {
+                visit_trait_ref(p, (e.clone(), v));
+            }
+            (v.visit_ty)(ty, (e.clone(), v));
+            for methods.iter().advance |m| {
+                visit_method_helper(*m, (e.clone(), v))
+            }
+        }
+        item_struct(struct_def, ref generics) => {
+            (v.visit_generics)(generics, (e.clone(), v));
+            (v.visit_struct_def)(struct_def, i.ident, generics, i.id, (e, v));
+        }
+        item_trait(ref generics, ref traits, ref methods) => {
+            (v.visit_generics)(generics, (e.clone(), v));
+            for traits.iter().advance |p| {
+                visit_path(&p.path, (e.clone(), v));
+            }
+            for methods.iter().advance |m| {
+                (v.visit_trait_method)(m, (e.clone(), v));
+            }
+        }
+        item_mac(ref m) => visit_mac(m, (e, v))
+    }
+}
+
+pub fn visit_enum_def<E:Clone>(enum_definition: &ast::enum_def,
+                               tps: &Generics,
+                               (e, v): (E, vt<E>)) {
+    for enum_definition.variants.iter().advance |vr| {
+        match vr.node.kind {
+            tuple_variant_kind(ref variant_args) => {
+                for variant_args.iter().advance |va| {
+                    (v.visit_ty)(&va.ty, (e.clone(), v));
+                }
+            }
+            struct_variant_kind(struct_def) => {
+                (v.visit_struct_def)(struct_def, vr.node.name, tps,
+                                     vr.node.id, (e.clone(), v));
+            }
+        }
+        // Visit the disr expr if it exists
+        for vr.node.disr_expr.iter().advance |ex| {
+            (v.visit_expr)(*ex, (e.clone(), v))
+        }
+    }
+}
+
+pub fn skip_ty<E>(_t: &Ty, (_e,_v): (E, vt<E>)) {}
+
+pub fn visit_ty<E:Clone>(t: &Ty, (e, v): (E, vt<E>)) {
+    match t.node {
+        ty_box(ref mt) | ty_uniq(ref mt) |
+        ty_vec(ref mt) | ty_ptr(ref mt) | ty_rptr(_, ref mt) => {
+            (v.visit_ty)(mt.ty, (e, v));
+        },
+        ty_tup(ref ts) => {
+            for ts.iter().advance |tt| {
+                (v.visit_ty)(tt, (e.clone(), v));
+            }
+        },
+        ty_closure(ref f) => {
+            for f.decl.inputs.iter().advance |a| {
+                (v.visit_ty)(&a.ty, (e.clone(), v));
+            }
+            (v.visit_ty)(&f.decl.output, (e.clone(), v));
+            do f.bounds.map |bounds| {
+                visit_ty_param_bounds(bounds, (e.clone(), v));
+            };
+        },
+        ty_bare_fn(ref f) => {
+            for f.decl.inputs.iter().advance |a| {
+                (v.visit_ty)(&a.ty, (e.clone(), v));
+            }
+            (v.visit_ty)(&f.decl.output, (e, v));
+        },
+        ty_path(ref p, ref bounds, _) => {
+            visit_path(p, (e.clone(), v));
+            do bounds.map |bounds| {
+                visit_ty_param_bounds(bounds, (e.clone(), v));
+            };
+        },
+        ty_fixed_length_vec(ref mt, ex) => {
+            (v.visit_ty)(mt.ty, (e.clone(), v));
+            (v.visit_expr)(ex, (e.clone(), v));
+        },
+        ty_nil | ty_bot | ty_mac(_) | ty_infer => ()
+    }
+}
+
+pub fn visit_path<E:Clone>(p: &Path, (e, v): (E, vt<E>)) {
+    for p.types.iter().advance |tp| { (v.visit_ty)(tp, (e.clone(), v)); }
+}
+
+pub fn visit_pat<E:Clone>(p: &pat, (e, v): (E, vt<E>)) {
+    match p.node {
+        pat_enum(ref path, ref children) => {
+            visit_path(path, (e.clone(), v));
+            for children.iter().advance |children| {
+                for children.iter().advance |child| {
+                    (v.visit_pat)(*child, (e.clone(), v));
+                }
+            }
+        }
+        pat_struct(ref path, ref fields, _) => {
+            visit_path(path, (e.clone(), v));
+            for fields.iter().advance |f| {
+                (v.visit_pat)(f.pat, (e.clone(), v));
+            }
+        }
+        pat_tup(ref elts) => {
+            for elts.iter().advance |elt| {
+                (v.visit_pat)(*elt, (e.clone(), v))
+            }
+        },
+        pat_box(inner) | pat_uniq(inner) | pat_region(inner) => {
+            (v.visit_pat)(inner, (e, v))
+        },
+        pat_ident(_, ref path, ref inner) => {
+            visit_path(path, (e.clone(), v));
+            for inner.iter().advance |subpat| {
+                (v.visit_pat)(*subpat, (e.clone(), v))
+            }
+        }
+        pat_lit(ex) => (v.visit_expr)(ex, (e, v)),
+        pat_range(e1, e2) => {
+            (v.visit_expr)(e1, (e.clone(), v));
+            (v.visit_expr)(e2, (e, v));
+        }
+        pat_wild => (),
+        pat_vec(ref before, ref slice, ref after) => {
+            for before.iter().advance |elt| {
+                (v.visit_pat)(*elt, (e.clone(), v));
+            }
+            for slice.iter().advance |elt| {
+                (v.visit_pat)(*elt, (e.clone(), v));
+            }
+            for after.iter().advance |tail| {
+                (v.visit_pat)(*tail, (e.clone(), v));
+            }
+        }
+    }
+}
+
+pub fn visit_foreign_item<E:Clone>(ni: &foreign_item, (e, v): (E, vt<E>)) {
+    match ni.node {
+        foreign_item_fn(ref fd, ref generics) => {
+            visit_fn_decl(fd, (e.clone(), v));
+            (v.visit_generics)(generics, (e, v));
+        }
+        foreign_item_static(ref t, _) => {
+            (v.visit_ty)(t, (e, v));
+        }
+    }
+}
+
+pub fn visit_ty_param_bounds<E:Clone>(bounds: &OptVec<TyParamBound>,
+                                      (e, v): (E, vt<E>)) {
+    for bounds.iter().advance |bound| {
+        match *bound {
+            TraitTyParamBound(ref ty) => visit_trait_ref(ty, (e.clone(), v)),
+            RegionTyParamBound => {}
+        }
+    }
+}
+
+pub fn visit_generics<E:Clone>(generics: &Generics, (e, v): (E, vt<E>)) {
+    for generics.ty_params.iter().advance |tp| {
+        visit_ty_param_bounds(&tp.bounds, (e.clone(), v));
+    }
+}
+
+pub fn visit_fn_decl<E:Clone>(fd: &fn_decl, (e, v): (E, vt<E>)) {
+    for fd.inputs.iter().advance |a| {
+        (v.visit_pat)(a.pat, (e.clone(), v));
+        (v.visit_ty)(&a.ty, (e.clone(), v));
+    }
+    (v.visit_ty)(&fd.output, (e, v));
+}
+
+// Note: there is no visit_method() method in the visitor, instead override
+// visit_fn() and check for fk_method().  I named this visit_method_helper()
+// because it is not a default impl of any method, though I doubt that really
+// clarifies anything. - Niko
+pub fn visit_method_helper<E:Clone>(m: &method, (e, v): (E, vt<E>)) {
+    (v.visit_fn)(&fk_method(m.ident, &m.generics, m),
+                 &m.decl,
+                 &m.body,
+                 m.span,
+                 m.id,
+                 (e, v));
+}
+
+pub fn visit_fn<E:Clone>(fk: &fn_kind,
+                         decl: &fn_decl,
+                         body: &Block,
+                         _sp: span,
+                         _id: NodeId,
+                         (e, v): (E, vt<E>)) {
+    visit_fn_decl(decl, (e.clone(), v));
+    let generics = generics_of_fn(fk);
+    (v.visit_generics)(&generics, (e.clone(), v));
+    (v.visit_block)(body, (e, v));
+}
+
+pub fn visit_ty_method<E:Clone>(m: &TypeMethod, (e, v): (E, vt<E>)) {
+    for m.decl.inputs.iter().advance |a| {
+        (v.visit_ty)(&a.ty, (e.clone(), v));
+    }
+    (v.visit_generics)(&m.generics, (e.clone(), v));
+    (v.visit_ty)(&m.decl.output, (e, v));
+}
+
+pub fn visit_trait_method<E:Clone>(m: &trait_method, (e, v): (E, vt<E>)) {
+    match *m {
+      required(ref ty_m) => (v.visit_ty_method)(ty_m, (e, v)),
+      provided(m) => visit_method_helper(m, (e, v))
+    }
+}
+
+pub fn visit_struct_def<E:Clone>(
+    sd: @struct_def,
+    _nm: ast::ident,
+    _generics: &Generics,
+    _id: NodeId,
+    (e, v): (E, vt<E>)
+) {
+    for sd.fields.iter().advance |f| {
+        (v.visit_struct_field)(*f, (e.clone(), v));
+    }
+}
+
+pub fn visit_struct_field<E:Clone>(sf: &struct_field, (e, v): (E, vt<E>)) {
+    (v.visit_ty)(&sf.node.ty, (e, v));
+}
+
+pub fn visit_block<E:Clone>(b: &Block, (e, v): (E, vt<E>)) {
+    for b.view_items.iter().advance |vi| {
+        (v.visit_view_item)(vi, (e.clone(), v));
+    }
+    for b.stmts.iter().advance |s| {
+        (v.visit_stmt)(*s, (e.clone(), v));
+    }
+    visit_expr_opt(b.expr, (e, v));
+}
+
+pub fn visit_stmt<E>(s: &stmt, (e, v): (E, vt<E>)) {
+    match s.node {
+      stmt_decl(d, _) => (v.visit_decl)(d, (e, v)),
+      stmt_expr(ex, _) => (v.visit_expr)(ex, (e, v)),
+      stmt_semi(ex, _) => (v.visit_expr)(ex, (e, v)),
+      stmt_mac(ref mac, _) => visit_mac(mac, (e, v))
+    }
+}
+
+pub fn visit_decl<E:Clone>(d: &decl, (e, v): (E, vt<E>)) {
+    match d.node {
+        decl_local(ref loc) => (v.visit_local)(*loc, (e, v)),
+        decl_item(it) => (v.visit_item)(it, (e, v))
+    }
+}
+
+pub fn visit_expr_opt<E>(eo: Option<@expr>, (e, v): (E, vt<E>)) {
+    match eo { None => (), Some(ex) => (v.visit_expr)(ex, (e, v)) }
+}
+
+pub fn visit_exprs<E:Clone>(exprs: &[@expr], (e, v): (E, vt<E>)) {
+    for exprs.iter().advance |ex| { (v.visit_expr)(*ex, (e.clone(), v)); }
+}
+
+pub fn visit_mac<E>(_m: &mac, (_e, _v): (E, vt<E>)) {
+    /* no user-serviceable parts inside */
+}
+
+pub fn visit_expr<E:Clone>(ex: @expr, (e, v): (E, vt<E>)) {
+    match ex.node {
+        expr_vstore(x, _) => (v.visit_expr)(x, (e.clone(), v)),
+        expr_vec(ref es, _) => visit_exprs(*es, (e.clone(), v)),
+        expr_repeat(element, count, _) => {
+            (v.visit_expr)(element, (e.clone(), v));
+            (v.visit_expr)(count, (e.clone(), v));
+        }
+        expr_struct(ref p, ref flds, base) => {
+            visit_path(p, (e.clone(), v));
+            for flds.iter().advance |f| {
+                (v.visit_expr)(f.expr, (e.clone(), v));
+            }
+            visit_expr_opt(base, (e.clone(), v));
+        }
+        expr_tup(ref elts) => {
+            for elts.iter().advance |el| { (v.visit_expr)(*el, (e.clone(), v)) }
+        }
+        expr_call(callee, ref args, _) => {
+            visit_exprs(*args, (e.clone(), v));
+            (v.visit_expr)(callee, (e.clone(), v));
+        }
+        expr_method_call(_, callee, _, ref tys, ref args, _) => {
+            visit_exprs(*args, (e.clone(), v));
+            for tys.iter().advance |tp| {
+                (v.visit_ty)(tp, (e.clone(), v));
+            }
+            (v.visit_expr)(callee, (e.clone(), v));
+        }
+        expr_binary(_, _, a, b) => {
+            (v.visit_expr)(a, (e.clone(), v));
+            (v.visit_expr)(b, (e.clone(), v));
+        }
+        expr_addr_of(_, x) | expr_unary(_, _, x) |
+        expr_loop_body(x) | expr_do_body(x) => (v.visit_expr)(x, (e.clone(), v)),
+        expr_lit(_) => (),
+        expr_cast(x, ref t) => {
+            (v.visit_expr)(x, (e.clone(), v));
+            (v.visit_ty)(t, (e.clone(), v));
+        }
+        expr_if(x, ref b, eo) => {
+            (v.visit_expr)(x, (e.clone(), v));
+            (v.visit_block)(b, (e.clone(), v));
+            visit_expr_opt(eo, (e.clone(), v));
+        }
+        expr_while(x, ref b) => {
+            (v.visit_expr)(x, (e.clone(), v));
+            (v.visit_block)(b, (e.clone(), v));
+        }
+        expr_for_loop(pattern, subexpression, ref block) => {
+            (v.visit_pat)(pattern, (e.clone(), v));
+            (v.visit_expr)(subexpression, (e.clone(), v));
+            (v.visit_block)(block, (e.clone(), v))
+        }
+        expr_loop(ref b, _) => (v.visit_block)(b, (e.clone(), v)),
+        expr_match(x, ref arms) => {
+            (v.visit_expr)(x, (e.clone(), v));
+            for arms.iter().advance |a| { (v.visit_arm)(a, (e.clone(), v)); }
+        }
+        expr_fn_block(ref decl, ref body) => {
+            (v.visit_fn)(
+                &fk_fn_block,
+                decl,
+                body,
+                ex.span,
+                ex.id,
+                (e.clone(), v)
+            );
+        }
+        expr_block(ref b) => (v.visit_block)(b, (e.clone(), v)),
+        expr_assign(a, b) => {
+            (v.visit_expr)(b, (e.clone(), v));
+            (v.visit_expr)(a, (e.clone(), v));
+        }
+        expr_assign_op(_, _, a, b) => {
+            (v.visit_expr)(b, (e.clone(), v));
+            (v.visit_expr)(a, (e.clone(), v));
+        }
+        expr_field(x, _, ref tys) => {
+            (v.visit_expr)(x, (e.clone(), v));
+            for tys.iter().advance |tp| {
+                (v.visit_ty)(tp, (e.clone(), v));
+            }
+        }
+        expr_index(_, a, b) => {
+            (v.visit_expr)(a, (e.clone(), v));
+            (v.visit_expr)(b, (e.clone(), v));
+        }
+        expr_path(ref p) => visit_path(p, (e.clone(), v)),
+        expr_self => (),
+        expr_break(_) => (),
+        expr_again(_) => (),
+        expr_ret(eo) => visit_expr_opt(eo, (e.clone(), v)),
+        expr_log(lv, x) => {
+            (v.visit_expr)(lv, (e.clone(), v));
+            (v.visit_expr)(x, (e.clone(), v));
+        }
+        expr_mac(ref mac) => visit_mac(mac, (e.clone(), v)),
+        expr_paren(x) => (v.visit_expr)(x, (e.clone(), v)),
+        expr_inline_asm(ref a) => {
+            for a.inputs.iter().advance |&(_, input)| {
+                (v.visit_expr)(input, (e.clone(), v));
+            }
+            for a.outputs.iter().advance |&(_, out)| {
+                (v.visit_expr)(out, (e.clone(), v));
+            }
+        }
+    }
+    (v.visit_expr_post)(ex, (e, v));
+}
+
+pub fn visit_arm<E:Clone>(a: &arm, (e, v): (E, vt<E>)) {
+    for a.pats.iter().advance |p| { (v.visit_pat)(*p, (e.clone(), v)); }
+    visit_expr_opt(a.guard, (e.clone(), v));
+    (v.visit_block)(&a.body, (e.clone(), v));
+}
+
+// Simpler, non-context passing interface. Always walks the whole tree, simply
+// calls the given functions on the nodes.
+
+pub struct SimpleVisitor {
+    visit_mod: @fn(&_mod, span, NodeId),
+    visit_view_item: @fn(&view_item),
+    visit_foreign_item: @fn(@foreign_item),
+    visit_item: @fn(@item),
+    visit_local: @fn(@Local),
+    visit_block: @fn(&Block),
+    visit_stmt: @fn(@stmt),
+    visit_arm: @fn(&arm),
+    visit_pat: @fn(@pat),
+    visit_decl: @fn(@decl),
+    visit_expr: @fn(@expr),
+    visit_expr_post: @fn(@expr),
+    visit_ty: @fn(&Ty),
+    visit_generics: @fn(&Generics),
+    visit_fn: @fn(&fn_kind, &fn_decl, &Block, span, NodeId),
+    visit_ty_method: @fn(&TypeMethod),
+    visit_trait_method: @fn(&trait_method),
+    visit_struct_def: @fn(@struct_def, ident, &Generics, NodeId),
+    visit_struct_field: @fn(@struct_field),
+    visit_struct_method: @fn(@method)
+}
+
+pub type simple_visitor = @SimpleVisitor;
+
+pub fn simple_ignore_ty(_t: &Ty) {}
+
+pub fn default_simple_visitor() -> @SimpleVisitor {
+    @SimpleVisitor {
+        visit_mod: |_m, _sp, _id| { },
+        visit_view_item: |_vi| { },
+        visit_foreign_item: |_ni| { },
+        visit_item: |_i| { },
+        visit_local: |_l| { },
+        visit_block: |_b| { },
+        visit_stmt: |_s| { },
+        visit_arm: |_a| { },
+        visit_pat: |_p| { },
+        visit_decl: |_d| { },
+        visit_expr: |_e| { },
+        visit_expr_post: |_e| { },
+        visit_ty: simple_ignore_ty,
+        visit_generics: |_| {},
+        visit_fn: |_, _, _, _, _| {},
+        visit_ty_method: |_| {},
+        visit_trait_method: |_| {},
+        visit_struct_def: |_, _, _, _| {},
+        visit_struct_field: |_| {},
+        visit_struct_method: |_| {},
+    }
+}
+
+pub fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
+    fn v_mod(
+        f: @fn(&_mod, span, NodeId),
+        m: &_mod,
+        sp: span,
+        id: NodeId,
+        (e, v): ((), vt<()>)
+    ) {
+        f(m, sp, id);
+        visit_mod(m, sp, id, (e, v));
+    }
+    fn v_view_item(f: @fn(&view_item), vi: &view_item, (e, v): ((), vt<()>)) {
+        f(vi);
+        visit_view_item(vi, (e, v));
+    }
+    fn v_foreign_item(f: @fn(@foreign_item), ni: @foreign_item, (e, v): ((), vt<()>)) {
+        f(ni);
+        visit_foreign_item(ni, (e, v));
+    }
+    fn v_item(f: @fn(@item), i: @item, (e, v): ((), vt<()>)) {
+        f(i);
+        visit_item(i, (e, v));
+    }
+    fn v_local(f: @fn(@Local), l: @Local, (e, v): ((), vt<()>)) {
+        f(l);
+        visit_local(l, (e, v));
+    }
+    fn v_block(f: @fn(&ast::Block), bl: &ast::Block, (e, v): ((), vt<()>)) {
+        f(bl);
+        visit_block(bl, (e, v));
+    }
+    fn v_stmt(f: @fn(@stmt), st: @stmt, (e, v): ((), vt<()>)) {
+        f(st);
+        visit_stmt(st, (e, v));
+    }
+    fn v_arm(f: @fn(&arm), a: &arm, (e, v): ((), vt<()>)) {
+        f(a);
+        visit_arm(a, (e, v));
+    }
+    fn v_pat(f: @fn(@pat), p: @pat, (e, v): ((), vt<()>)) {
+        f(p);
+        visit_pat(p, (e, v));
+    }
+    fn v_decl(f: @fn(@decl), d: @decl, (e, v): ((), vt<()>)) {
+        f(d);
+        visit_decl(d, (e, v));
+    }
+    fn v_expr(f: @fn(@expr), ex: @expr, (e, v): ((), vt<()>)) {
+        f(ex);
+        visit_expr(ex, (e, v));
+    }
+    fn v_expr_post(f: @fn(@expr), ex: @expr, (_e, _v): ((), vt<()>)) {
+        f(ex);
+    }
+    fn v_ty(f: @fn(&Ty), ty: &Ty, (e, v): ((), vt<()>)) {
+        f(ty);
+        visit_ty(ty, (e, v));
+    }
+    fn v_ty_method(f: @fn(&TypeMethod), ty: &TypeMethod, (e, v): ((), vt<()>)) {
+        f(ty);
+        visit_ty_method(ty, (e, v));
+    }
+    fn v_trait_method(f: @fn(&trait_method),
+                      m: &trait_method,
+                      (e, v): ((), vt<()>)) {
+        f(m);
+        visit_trait_method(m, (e, v));
+    }
+    fn v_struct_def(
+        f: @fn(@struct_def, ident, &Generics, NodeId),
+        sd: @struct_def,
+        nm: ident,
+        generics: &Generics,
+        id: NodeId,
+        (e, v): ((), vt<()>)
+    ) {
+        f(sd, nm, generics, id);
+        visit_struct_def(sd, nm, generics, id, (e, v));
+    }
+    fn v_generics(
+        f: @fn(&Generics),
+        ps: &Generics,
+        (e, v): ((), vt<()>)
+    ) {
+        f(ps);
+        visit_generics(ps, (e, v));
+    }
+    fn v_fn(
+        f: @fn(&fn_kind, &fn_decl, &Block, span, NodeId),
+        fk: &fn_kind,
+        decl: &fn_decl,
+        body: &Block,
+        sp: span,
+        id: NodeId,
+        (e, v): ((), vt<()>)
+    ) {
+        f(fk, decl, body, sp, id);
+        visit_fn(fk, decl, body, sp, id, (e, v));
+    }
+    let visit_ty: @fn(&Ty, ((), vt<()>)) =
+        |a,b| v_ty(v.visit_ty, a, b);
+    fn v_struct_field(f: @fn(@struct_field), sf: @struct_field, (e, v): ((), vt<()>)) {
+        f(sf);
+        visit_struct_field(sf, (e, v));
+    }
+    return mk_vt(@Visitor {
+        visit_mod: |a,b,c,d|v_mod(v.visit_mod, a, b, c, d),
+        visit_view_item: |a,b| v_view_item(v.visit_view_item, a, b),
+        visit_foreign_item:
+            |a,b|v_foreign_item(v.visit_foreign_item, a, b),
+        visit_item: |a,b|v_item(v.visit_item, a, b),
+        visit_local: |a,b|v_local(v.visit_local, a, b),
+        visit_block: |a,b|v_block(v.visit_block, a, b),
+        visit_stmt: |a,b|v_stmt(v.visit_stmt, a, b),
+        visit_arm: |a,b|v_arm(v.visit_arm, a, b),
+        visit_pat: |a,b|v_pat(v.visit_pat, a, b),
+        visit_decl: |a,b|v_decl(v.visit_decl, a, b),
+        visit_expr: |a,b|v_expr(v.visit_expr, a, b),
+        visit_expr_post: |a,b| v_expr_post(v.visit_expr_post, a, b),
+        visit_ty: visit_ty,
+        visit_generics: |a,b|
+            v_generics(v.visit_generics, a, b),
+        visit_fn: |a,b,c,d,e,f|
+            v_fn(v.visit_fn, a, b, c, d, e, f),
+        visit_ty_method: |a,b|
+            v_ty_method(v.visit_ty_method, a, b),
+        visit_trait_method: |a,b|
+            v_trait_method(v.visit_trait_method, a, b),
+        visit_struct_def: |a,b,c,d,e|
+            v_struct_def(v.visit_struct_def, a, b, c, d, e),
+        visit_struct_field: |a,b|
+            v_struct_field(v.visit_struct_field, a, b),
+    });
+}
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
index 3472b9f1d67..ec956f61863 100644
--- a/src/libsyntax/parse/obsolete.rs
+++ b/src/libsyntax/parse/obsolete.rs
@@ -63,6 +63,7 @@ pub enum ObsoleteSyntax {
     ObsoleteMultipleLocalDecl,
     ObsoleteMutWithMultipleBindings,
     ObsoleteExternVisibility,
+    ObsoleteUnsafeExternFn,
 }
 
 impl to_bytes::IterBytes for ObsoleteSyntax {
@@ -246,7 +247,12 @@ impl ParserObsoleteMethods for Parser {
                 "`pub extern` or `priv extern`",
                 "place the `pub` or `priv` on the individual external items \
                  instead"
-            )
+            ),
+            ObsoleteUnsafeExternFn => (
+                "unsafe external function",
+                "external functions are always unsafe; remove the `unsafe` \
+                 keyword"
+            ),
         };
 
         self.report(sp, kind, kind_str, desc);
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 1d61c5be83d..386f027d6e1 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -84,7 +84,8 @@ use parse::obsolete::{ObsoletePurity, ObsoleteStaticMethod};
 use parse::obsolete::{ObsoleteConstItem, ObsoleteFixedLengthVectorType};
 use parse::obsolete::{ObsoleteNamedExternModule, ObsoleteMultipleLocalDecl};
 use parse::obsolete::{ObsoleteMutWithMultipleBindings};
-use parse::obsolete::{ObsoleteExternVisibility, ParserObsoleteMethods};
+use parse::obsolete::{ObsoleteExternVisibility, ObsoleteUnsafeExternFn};
+use parse::obsolete::{ParserObsoleteMethods};
 use parse::token::{can_begin_expr, get_ident_interner, ident_to_str, is_ident};
 use parse::token::{is_ident_or_path};
 use parse::token::{is_plain_ident, INTERPOLATED, keywords, special_idents};
@@ -4066,14 +4067,20 @@ impl Parser {
     fn parse_item_foreign_fn(&self,  attrs: ~[Attribute]) -> @foreign_item {
         let lo = self.span.lo;
         let vis = self.parse_visibility();
+
+        // Parse obsolete purity.
         let purity = self.parse_fn_purity();
+        if purity != impure_fn {
+            self.obsolete(*self.last_span, ObsoleteUnsafeExternFn);
+        }
+
         let (ident, generics) = self.parse_fn_header();
         let decl = self.parse_fn_decl();
         let hi = self.span.hi;
         self.expect(&token::SEMI);
         @ast::foreign_item { ident: ident,
                              attrs: attrs,
-                             node: foreign_item_fn(decl, purity, generics),
+                             node: foreign_item_fn(decl, generics),
                              id: self.get_id(),
                              span: mk_sp(lo, hi),
                              vis: vis }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index d24dd86fda1..7d885837a60 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -454,8 +454,8 @@ pub fn print_foreign_item(s: @ps, item: &ast::foreign_item) {
     maybe_print_comment(s, item.span.lo);
     print_outer_attributes(s, item.attrs);
     match item.node {
-      ast::foreign_item_fn(ref decl, purity, ref generics) => {
-        print_fn(s, decl, Some(purity), AbiSet::Rust(), item.ident, generics, None,
+      ast::foreign_item_fn(ref decl, ref generics) => {
+        print_fn(s, decl, None, AbiSet::Rust(), item.ident, generics, None,
                  item.vis);
         end(s); // end head-ibox
         word(s.s, ";");
diff --git a/src/libsyntax/syntax.rs b/src/libsyntax/syntax.rs
index 4d604faa6e1..e0f5aa848a2 100644
--- a/src/libsyntax/syntax.rs
+++ b/src/libsyntax/syntax.rs
@@ -43,6 +43,7 @@ pub mod ast_util;
 pub mod ast_map;
 pub mod visit;
 pub mod fold;
+pub mod oldvisit;
 
 
 pub mod parse;
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index d988f96d3d4..6f228a9a43b 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -28,10 +28,6 @@ use opt_vec::OptVec;
 // execute before AST node B, then A is visited first.  The borrow checker in
 // particular relies on this property.
 
-// Our typesystem doesn't do circular types, so the visitor record can not
-// hold functions that take visitors. A vt enum is used to break the cycle.
-pub enum vt<E> { mk_vt(visitor<E>), }
-
 pub enum fn_kind<'self> {
     // fn foo() or extern "Abi" fn foo()
     fk_item_fn(ident, &'self Generics, purity, AbiSet),
@@ -70,702 +66,682 @@ pub fn generics_of_fn(fk: &fn_kind) -> Generics {
     }
 }
 
-pub struct Visitor<E> {
-    visit_mod: @fn(&_mod, span, NodeId, (E, vt<E>)),
-    visit_view_item: @fn(&view_item, (E, vt<E>)),
-    visit_foreign_item: @fn(@foreign_item, (E, vt<E>)),
-    visit_item: @fn(@item, (E, vt<E>)),
-    visit_local: @fn(@Local, (E, vt<E>)),
-    visit_block: @fn(&Block, (E, vt<E>)),
-    visit_stmt: @fn(@stmt, (E, vt<E>)),
-    visit_arm: @fn(&arm, (E, vt<E>)),
-    visit_pat: @fn(@pat, (E, vt<E>)),
-    visit_decl: @fn(@decl, (E, vt<E>)),
-    visit_expr: @fn(@expr, (E, vt<E>)),
-    visit_expr_post: @fn(@expr, (E, vt<E>)),
-    visit_ty: @fn(&Ty, (E, vt<E>)),
-    visit_generics: @fn(&Generics, (E, vt<E>)),
-    visit_fn: @fn(&fn_kind, &fn_decl, &Block, span, NodeId, (E, vt<E>)),
-    visit_ty_method: @fn(&TypeMethod, (E, vt<E>)),
-    visit_trait_method: @fn(&trait_method, (E, vt<E>)),
-    visit_struct_def: @fn(@struct_def, ident, &Generics, NodeId, (E, vt<E>)),
-    visit_struct_field: @fn(@struct_field, (E, vt<E>)),
-}
-
-pub type visitor<E> = @Visitor<E>;
-
-pub fn default_visitor<E:Clone>() -> visitor<E> {
-    return @Visitor {
-        visit_mod: |a,b,c,d|visit_mod::<E>(a, b, c, d),
-        visit_view_item: |a,b|visit_view_item::<E>(a, b),
-        visit_foreign_item: |a,b|visit_foreign_item::<E>(a, b),
-        visit_item: |a,b|visit_item::<E>(a, b),
-        visit_local: |a,b|visit_local::<E>(a, b),
-        visit_block: |a,b|visit_block::<E>(a, b),
-        visit_stmt: |a,b|visit_stmt::<E>(a, b),
-        visit_arm: |a,b|visit_arm::<E>(a, b),
-        visit_pat: |a,b|visit_pat::<E>(a, b),
-        visit_decl: |a,b|visit_decl::<E>(a, b),
-        visit_expr: |a,b|visit_expr::<E>(a, b),
-        visit_expr_post: |_a,_b| (),
-        visit_ty: |a,b|skip_ty::<E>(a, b),
-        visit_generics: |a,b|visit_generics::<E>(a, b),
-        visit_fn: |a,b,c,d,e,f|visit_fn::<E>(a, b, c, d, e, f),
-        visit_ty_method: |a,b|visit_ty_method::<E>(a, b),
-        visit_trait_method: |a,b|visit_trait_method::<E>(a, b),
-        visit_struct_def: |a,b,c,d,e|visit_struct_def::<E>(a, b, c, d, e),
-        visit_struct_field: |a,b|visit_struct_field::<E>(a, b),
-    };
-}
-
-pub fn visit_crate<E:Clone>(c: &Crate, (e, v): (E, vt<E>)) {
-    (v.visit_mod)(&c.module, c.span, CRATE_NODE_ID, (e, v));
-}
-
-pub fn visit_mod<E:Clone>(m: &_mod,
-                          _sp: span,
-                          _id: NodeId,
-                          (e, v): (E, vt<E>)) {
-    foreach vi in m.view_items.iter() {
-        (v.visit_view_item)(vi, (e.clone(), v));
-    }
-    foreach i in m.items.iter() {
-        (v.visit_item)(*i, (e.clone(), v));
-    }
-}
-
-pub fn visit_view_item<E>(_vi: &view_item, (_e, _v): (E, vt<E>)) { }
-
-pub fn visit_local<E:Clone>(loc: &Local, (e, v): (E, vt<E>)) {
-    (v.visit_pat)(loc.pat, (e.clone(), v));
-    (v.visit_ty)(&loc.ty, (e.clone(), v));
-    match loc.init {
-      None => (),
-      Some(ex) => (v.visit_expr)(ex, (e, v))
-    }
-}
-
-fn visit_trait_ref<E:Clone>(tref: &ast::trait_ref, (e, v): (E, vt<E>)) {
-    visit_path(&tref.path, (e, v));
-}
-
-pub fn visit_item<E:Clone>(i: &item, (e, v): (E, vt<E>)) {
-    match i.node {
-        item_static(ref t, _, ex) => {
-            (v.visit_ty)(t, (e.clone(), v));
-            (v.visit_expr)(ex, (e.clone(), v));
-        }
-        item_fn(ref decl, purity, abi, ref generics, ref body) => {
-            (v.visit_fn)(
-                &fk_item_fn(
-                    i.ident,
-                    generics,
-                    purity,
-                    abi
-                ),
-                decl,
-                body,
-                i.span,
-                i.id,
-                (e,
-                 v)
-            );
-        }
-        item_mod(ref m) => (v.visit_mod)(m, i.span, i.id, (e, v)),
-        item_foreign_mod(ref nm) => {
-            foreach vi in nm.view_items.iter() {
-                (v.visit_view_item)(vi, (e.clone(), v));
+pub trait Visitor<E> {
+    fn visit_mod(@mut self, &_mod, span, NodeId, E);
+    fn visit_view_item(@mut self, &view_item, E);
+    fn visit_foreign_item(@mut self, @foreign_item, E);
+    fn visit_item(@mut self, @item, E);
+    fn visit_local(@mut self, @Local, E);
+    fn visit_block(@mut self, &Block, E);
+    fn visit_stmt(@mut self, @stmt, E);
+    fn visit_arm(@mut self, &arm, E);
+    fn visit_pat(@mut self, @pat, E);
+    fn visit_decl(@mut self, @decl, E);
+    fn visit_expr(@mut self, @expr, E);
+    fn visit_expr_post(@mut self, @expr, E);
+    fn visit_ty(@mut self, &Ty, E);
+    fn visit_generics(@mut self, &Generics, E);
+    fn visit_fn(@mut self, &fn_kind, &fn_decl, &Block, span, NodeId, E);
+    fn visit_ty_method(@mut self, &TypeMethod, E);
+    fn visit_trait_method(@mut self, &trait_method, E);
+    fn visit_struct_def(@mut self, @struct_def, ident, &Generics, NodeId, E);
+    fn visit_struct_field(@mut self, @struct_field, E);
+}
+
+pub fn visit_crate<E:Clone>(visitor: @Visitor<E>, crate: &Crate, env: E) {
+    visitor.visit_mod(&crate.module, crate.span, CRATE_NODE_ID, env)
+}
+
+pub fn visit_mod<E:Clone>(visitor: @Visitor<E>, module: &_mod, env: E) {
+    foreach view_item in module.view_items.iter() {
+        visitor.visit_view_item(view_item, env.clone())
+    }
+    foreach item in module.items.iter() {
+        visitor.visit_item(*item, env.clone())
+    }
+}
+
+pub fn visit_view_item<E:Clone>(_: @Visitor<E>, _: &view_item, _: E) {
+    // Empty!
+}
+
+pub fn visit_local<E:Clone>(visitor: @Visitor<E>, local: &Local, env: E) {
+    visitor.visit_pat(local.pat, env.clone());
+    visitor.visit_ty(&local.ty, env.clone());
+    match local.init {
+        None => {}
+        Some(initializer) => visitor.visit_expr(initializer, env),
+    }
+}
+
+fn visit_trait_ref<E:Clone>(visitor: @Visitor<E>,
+                            trait_ref: &ast::trait_ref,
+                            env: E) {
+    visit_path(visitor, &trait_ref.path, env)
+}
+
+pub fn visit_item<E:Clone>(visitor: @Visitor<E>, item: &item, env: E) {
+    match item.node {
+        item_static(ref typ, _, expr) => {
+            visitor.visit_ty(typ, env.clone());
+            visitor.visit_expr(expr, env);
+        }
+        item_fn(ref declaration, purity, abi, ref generics, ref body) => {
+            visitor.visit_fn(&fk_item_fn(item.ident, generics, purity, abi),
+                             declaration,
+                             body,
+                             item.span,
+                             item.id,
+                             env)
+        }
+        item_mod(ref module) => {
+            visitor.visit_mod(module, item.span, item.id, env)
+        }
+        item_foreign_mod(ref foreign_module) => {
+            foreach view_item in foreign_module.view_items.iter() {
+                visitor.visit_view_item(view_item, env.clone())
             }
-            foreach ni in nm.items.iter() {
-                (v.visit_foreign_item)(*ni, (e.clone(), v));
+            foreach foreign_item in foreign_module.items.iter() {
+                visitor.visit_foreign_item(*foreign_item, env.clone())
             }
         }
-        item_ty(ref t, ref tps) => {
-            (v.visit_ty)(t, (e.clone(), v));
-            (v.visit_generics)(tps, (e, v));
-        }
-        item_enum(ref enum_definition, ref tps) => {
-            (v.visit_generics)(tps, (e.clone(), v));
-            visit_enum_def(
-                enum_definition,
-                tps,
-                (e, v)
-            );
-        }
-        item_impl(ref tps, ref traits, ref ty, ref methods) => {
-            (v.visit_generics)(tps, (e.clone(), v));
-            foreach p in traits.iter() {
-                visit_trait_ref(p, (e.clone(), v));
+        item_ty(ref typ, ref type_parameters) => {
+            visitor.visit_ty(typ, env.clone());
+            visitor.visit_generics(type_parameters, env)
+        }
+        item_enum(ref enum_definition, ref type_parameters) => {
+            visitor.visit_generics(type_parameters, env.clone());
+            visit_enum_def(visitor, enum_definition, type_parameters, env)
+        }
+        item_impl(ref type_parameters,
+                  ref trait_references,
+                  ref typ,
+                  ref methods) => {
+            visitor.visit_generics(type_parameters, env.clone());
+            foreach trait_reference in trait_references.iter() {
+                visit_trait_ref(visitor, trait_reference, env.clone())
             }
-            (v.visit_ty)(ty, (e.clone(), v));
-            foreach m in methods.iter() {
-                visit_method_helper(*m, (e.clone(), v))
+            visitor.visit_ty(typ, env.clone());
+            foreach method in methods.iter() {
+                visit_method_helper(visitor, *method, env.clone())
             }
         }
-        item_struct(struct_def, ref generics) => {
-            (v.visit_generics)(generics, (e.clone(), v));
-            (v.visit_struct_def)(struct_def, i.ident, generics, i.id, (e, v));
-        }
-        item_trait(ref generics, ref traits, ref methods) => {
-            (v.visit_generics)(generics, (e.clone(), v));
-            foreach p in traits.iter() {
-                visit_path(&p.path, (e.clone(), v));
+        item_struct(struct_definition, ref generics) => {
+            visitor.visit_generics(generics, env.clone());
+            visitor.visit_struct_def(struct_definition,
+                                     item.ident,
+                                     generics,
+                                     item.id,
+                                     env)
+        }
+        item_trait(ref generics, ref trait_paths, ref methods) => {
+            visitor.visit_generics(generics, env.clone());
+            foreach trait_path in trait_paths.iter() {
+                visit_path(visitor, &trait_path.path, env.clone())
             }
-            foreach m in methods.iter() {
-                (v.visit_trait_method)(m, (e.clone(), v));
+            foreach method in methods.iter() {
+                visitor.visit_trait_method(method, env.clone())
             }
         }
-        item_mac(ref m) => visit_mac(m, (e, v))
+        item_mac(ref macro) => visit_mac(visitor, macro, env),
     }
 }
 
-pub fn visit_enum_def<E:Clone>(enum_definition: &ast::enum_def,
-                               tps: &Generics,
-                               (e, v): (E, vt<E>)) {
-    foreach vr in enum_definition.variants.iter() {
-        match vr.node.kind {
-            tuple_variant_kind(ref variant_args) => {
-                foreach va in variant_args.iter() {
-                    (v.visit_ty)(&va.ty, (e.clone(), v));
+pub fn visit_enum_def<E:Clone>(visitor: @Visitor<E>,
+                               enum_definition: &ast::enum_def,
+                               generics: &Generics,
+                               env: E) {
+    foreach variant in enum_definition.variants.iter() {
+        match variant.node.kind {
+            tuple_variant_kind(ref variant_arguments) => {
+                foreach variant_argument in variant_arguments.iter() {
+                    visitor.visit_ty(&variant_argument.ty, env.clone())
                 }
             }
-            struct_variant_kind(struct_def) => {
-                (v.visit_struct_def)(struct_def, vr.node.name, tps,
-                                     vr.node.id, (e.clone(), v));
+            struct_variant_kind(struct_definition) => {
+                visitor.visit_struct_def(struct_definition,
+                                         variant.node.name,
+                                         generics,
+                                         variant.node.id,
+                                         env.clone())
             }
         }
-        // Visit the disr expr if it exists
-        foreach ex in vr.node.disr_expr.iter() {
-            (v.visit_expr)(*ex, (e.clone(), v))
-        }
     }
 }
 
-pub fn skip_ty<E>(_t: &Ty, (_e,_v): (E, vt<E>)) {}
+pub fn skip_ty<E>(_: @Visitor<E>, _: &Ty, _: E) {
+    // Empty!
+}
 
-pub fn visit_ty<E:Clone>(t: &Ty, (e, v): (E, vt<E>)) {
-    match t.node {
-        ty_box(ref mt) | ty_uniq(ref mt) |
-        ty_vec(ref mt) | ty_ptr(ref mt) | ty_rptr(_, ref mt) => {
-            (v.visit_ty)(mt.ty, (e, v));
-        },
-        ty_tup(ref ts) => {
-            foreach tt in ts.iter() {
-                (v.visit_ty)(tt, (e.clone(), v));
+pub fn visit_ty<E:Clone>(visitor: @Visitor<E>, typ: &Ty, env: E) {
+    match typ.node {
+        ty_box(ref mutable_type) | ty_uniq(ref mutable_type) |
+        ty_vec(ref mutable_type) | ty_ptr(ref mutable_type) |
+        ty_rptr(_, ref mutable_type) => {
+            visitor.visit_ty(mutable_type.ty, env)
+        }
+        ty_tup(ref tuple_element_types) => {
+            foreach tuple_element_type in tuple_element_types.iter() {
+                visitor.visit_ty(tuple_element_type, env.clone())
             }
-        },
-        ty_closure(ref f) => {
-            foreach a in f.decl.inputs.iter() {
-                (v.visit_ty)(&a.ty, (e.clone(), v));
+        }
+        ty_closure(ref function_declaration) => {
+             foreach argument in function_declaration.decl.inputs.iter() {
+                visitor.visit_ty(&argument.ty, env.clone())
+             }
+             visitor.visit_ty(&function_declaration.decl.output, env.clone());
+             foreach bounds in function_declaration.bounds.iter() {
+                visit_ty_param_bounds(visitor, bounds, env.clone())
+             }
+        }
+        ty_bare_fn(ref function_declaration) => {
+            foreach argument in function_declaration.decl.inputs.iter() {
+                visitor.visit_ty(&argument.ty, env.clone())
             }
-            (v.visit_ty)(&f.decl.output, (e.clone(), v));
-            do f.bounds.map |bounds| {
-                visit_ty_param_bounds(bounds, (e.clone(), v));
-            };
-        },
-        ty_bare_fn(ref f) => {
-            foreach a in f.decl.inputs.iter() {
-                (v.visit_ty)(&a.ty, (e.clone(), v));
+            visitor.visit_ty(&function_declaration.decl.output, env.clone())
+        }
+        ty_path(ref path, ref bounds, _) => {
+            visit_path(visitor, path, env.clone());
+            foreach bounds in bounds.iter() {
+                visit_ty_param_bounds(visitor, bounds, env.clone())
             }
-            (v.visit_ty)(&f.decl.output, (e, v));
-        },
-        ty_path(ref p, ref bounds, _) => {
-            visit_path(p, (e.clone(), v));
-            do bounds.map |bounds| {
-                visit_ty_param_bounds(bounds, (e.clone(), v));
-            };
-        },
-        ty_fixed_length_vec(ref mt, ex) => {
-            (v.visit_ty)(mt.ty, (e.clone(), v));
-            (v.visit_expr)(ex, (e.clone(), v));
-        },
+        }
+        ty_fixed_length_vec(ref mutable_type, expression) => {
+            visitor.visit_ty(mutable_type.ty, env.clone());
+            visitor.visit_expr(expression, env)
+        }
         ty_nil | ty_bot | ty_mac(_) | ty_infer => ()
     }
 }
 
-pub fn visit_path<E:Clone>(p: &Path, (e, v): (E, vt<E>)) {
-    foreach tp in p.types.iter() { (v.visit_ty)(tp, (e.clone(), v)); }
+pub fn visit_path<E:Clone>(visitor: @Visitor<E>, path: &Path, env: E) {
+    foreach typ in path.types.iter() {
+        visitor.visit_ty(typ, env.clone())
+    }
 }
 
-pub fn visit_pat<E:Clone>(p: &pat, (e, v): (E, vt<E>)) {
-    match p.node {
+pub fn visit_pat<E:Clone>(visitor: @Visitor<E>, pattern: &pat, env: E) {
+    match pattern.node {
         pat_enum(ref path, ref children) => {
-            visit_path(path, (e.clone(), v));
+            visit_path(visitor, path, env.clone());
             foreach children in children.iter() {
                 foreach child in children.iter() {
-                    (v.visit_pat)(*child, (e.clone(), v));
+                    visitor.visit_pat(*child, env.clone())
                 }
             }
         }
         pat_struct(ref path, ref fields, _) => {
-            visit_path(path, (e.clone(), v));
-            foreach f in fields.iter() {
-                (v.visit_pat)(f.pat, (e.clone(), v));
+            visit_path(visitor, path, env.clone());
+            foreach field in fields.iter() {
+                visitor.visit_pat(field.pat, env.clone())
             }
         }
-        pat_tup(ref elts) => {
-            foreach elt in elts.iter() {
-                (v.visit_pat)(*elt, (e.clone(), v))
+        pat_tup(ref tuple_elements) => {
+            foreach tuple_element in tuple_elements.iter() {
+                visitor.visit_pat(*tuple_element, env.clone())
             }
-        },
-        pat_box(inner) | pat_uniq(inner) | pat_region(inner) => {
-            (v.visit_pat)(inner, (e, v))
-        },
-        pat_ident(_, ref path, ref inner) => {
-            visit_path(path, (e.clone(), v));
-            foreach subpat in inner.iter() {
-                (v.visit_pat)(*subpat, (e.clone(), v))
+        }
+        pat_box(subpattern) |
+        pat_uniq(subpattern) |
+        pat_region(subpattern) => {
+            visitor.visit_pat(subpattern, env)
+        }
+        pat_ident(_, ref path, ref optional_subpattern) => {
+            visit_path(visitor, path, env.clone());
+            match *optional_subpattern {
+                None => {}
+                Some(subpattern) => visitor.visit_pat(subpattern, env),
             }
         }
-        pat_lit(ex) => (v.visit_expr)(ex, (e, v)),
-        pat_range(e1, e2) => {
-            (v.visit_expr)(e1, (e.clone(), v));
-            (v.visit_expr)(e2, (e, v));
+        pat_lit(expression) => visitor.visit_expr(expression, env),
+        pat_range(lower_bound, upper_bound) => {
+            visitor.visit_expr(lower_bound, env.clone());
+            visitor.visit_expr(upper_bound, env)
         }
         pat_wild => (),
-        pat_vec(ref before, ref slice, ref after) => {
-            foreach elt in before.iter() {
-                (v.visit_pat)(*elt, (e.clone(), v));
+        pat_vec(ref prepattern, ref slice_pattern, ref postpatterns) => {
+            foreach prepattern in prepattern.iter() {
+                visitor.visit_pat(*prepattern, env.clone())
             }
-            foreach elt in slice.iter() {
-                (v.visit_pat)(*elt, (e.clone(), v));
+            foreach slice_pattern in slice_pattern.iter() {
+                visitor.visit_pat(*slice_pattern, env.clone())
             }
-            foreach tail in after.iter() {
-                (v.visit_pat)(*tail, (e.clone(), v));
+            foreach postpattern in postpatterns.iter() {
+                visitor.visit_pat(*postpattern, env.clone())
             }
         }
     }
 }
 
-pub fn visit_foreign_item<E:Clone>(ni: &foreign_item, (e, v): (E, vt<E>)) {
-    match ni.node {
-        foreign_item_fn(ref fd, _, ref generics) => {
-            visit_fn_decl(fd, (e.clone(), v));
-            (v.visit_generics)(generics, (e, v));
-        }
-        foreign_item_static(ref t, _) => {
-            (v.visit_ty)(t, (e, v));
+pub fn visit_foreign_item<E:Clone>(visitor: @Visitor<E>,
+                                   foreign_item: &foreign_item,
+                                   env: E) {
+    match foreign_item.node {
+        foreign_item_fn(ref function_declaration, ref generics) => {
+            visit_fn_decl(visitor, function_declaration, env.clone());
+            visitor.visit_generics(generics, env)
         }
+        foreign_item_static(ref typ, _) => visitor.visit_ty(typ, env),
     }
 }
 
-pub fn visit_ty_param_bounds<E:Clone>(bounds: &OptVec<TyParamBound>,
-                                      (e, v): (E, vt<E>)) {
+pub fn visit_ty_param_bounds<E:Clone>(visitor: @Visitor<E>,
+                                      bounds: &OptVec<TyParamBound>,
+                                      env: E) {
     foreach bound in bounds.iter() {
         match *bound {
-            TraitTyParamBound(ref ty) => visit_trait_ref(ty, (e.clone(), v)),
+            TraitTyParamBound(ref typ) => {
+                visit_trait_ref(visitor, typ, env.clone())
+            }
             RegionTyParamBound => {}
         }
     }
 }
 
-pub fn visit_generics<E:Clone>(generics: &Generics, (e, v): (E, vt<E>)) {
-    foreach tp in generics.ty_params.iter() {
-        visit_ty_param_bounds(&tp.bounds, (e.clone(), v));
+pub fn visit_generics<E:Clone>(visitor: @Visitor<E>,
+                               generics: &Generics,
+                               env: E) {
+    foreach type_parameter in generics.ty_params.iter() {
+        visit_ty_param_bounds(visitor, &type_parameter.bounds, env.clone())
     }
 }
 
-pub fn visit_fn_decl<E:Clone>(fd: &fn_decl, (e, v): (E, vt<E>)) {
-    foreach a in fd.inputs.iter() {
-        (v.visit_pat)(a.pat, (e.clone(), v));
-        (v.visit_ty)(&a.ty, (e.clone(), v));
+pub fn visit_fn_decl<E:Clone>(visitor: @Visitor<E>,
+                              function_declaration: &fn_decl,
+                              env: E) {
+    foreach argument in function_declaration.inputs.iter() {
+        visitor.visit_pat(argument.pat, env.clone());
+        visitor.visit_ty(&argument.ty, env.clone())
     }
-    (v.visit_ty)(&fd.output, (e, v));
+    visitor.visit_ty(&function_declaration.output, env)
 }
 
 // Note: there is no visit_method() method in the visitor, instead override
 // visit_fn() and check for fk_method().  I named this visit_method_helper()
 // because it is not a default impl of any method, though I doubt that really
 // clarifies anything. - Niko
-pub fn visit_method_helper<E:Clone>(m: &method, (e, v): (E, vt<E>)) {
-    (v.visit_fn)(&fk_method(m.ident, &m.generics, m),
-                 &m.decl,
-                 &m.body,
-                 m.span,
-                 m.id,
-                 (e, v));
+pub fn visit_method_helper<E:Clone>(visitor: @Visitor<E>,
+                                    method: &method,
+                                    env: E) {
+    visitor.visit_fn(&fk_method(method.ident, &method.generics, method),
+                     &method.decl,
+                     &method.body,
+                     method.span,
+                     method.id,
+                     env)
 }
 
-pub fn visit_fn<E:Clone>(fk: &fn_kind, decl: &fn_decl, body: &Block, _sp: span,
-                         _id: NodeId, (e, v): (E, vt<E>)) {
-    visit_fn_decl(decl, (e.clone(), v));
-    let generics = generics_of_fn(fk);
-    (v.visit_generics)(&generics, (e.clone(), v));
-    (v.visit_block)(body, (e, v));
+pub fn visit_fn<E:Clone>(visitor: @Visitor<E>,
+                         function_kind: &fn_kind,
+                         function_declaration: &fn_decl,
+                         function_body: &Block,
+                         _: span,
+                         _: NodeId,
+                         env: E) {
+    visit_fn_decl(visitor, function_declaration, env.clone());
+    let generics = generics_of_fn(function_kind);
+    visitor.visit_generics(&generics, env.clone());
+    visitor.visit_block(function_body, env)
 }
 
-pub fn visit_ty_method<E:Clone>(m: &TypeMethod, (e, v): (E, vt<E>)) {
-    foreach a in m.decl.inputs.iter() {
-        (v.visit_ty)(&a.ty, (e.clone(), v));
+pub fn visit_ty_method<E:Clone>(visitor: @Visitor<E>,
+                                method_type: &TypeMethod,
+                                env: E) {
+    foreach argument_type in method_type.decl.inputs.iter() {
+        visitor.visit_ty(&argument_type.ty, env.clone())
     }
-    (v.visit_generics)(&m.generics, (e.clone(), v));
-    (v.visit_ty)(&m.decl.output, (e, v));
+    visitor.visit_generics(&method_type.generics, env.clone());
+    visitor.visit_ty(&method_type.decl.output, env.clone())
 }
 
-pub fn visit_trait_method<E:Clone>(m: &trait_method, (e, v): (E, vt<E>)) {
-    match *m {
-      required(ref ty_m) => (v.visit_ty_method)(ty_m, (e, v)),
-      provided(m) => visit_method_helper(m, (e, v))
+pub fn visit_trait_method<E:Clone>(visitor: @Visitor<E>,
+                                   trait_method: &trait_method,
+                                   env: E) {
+    match *trait_method {
+        required(ref method_type) => {
+            visitor.visit_ty_method(method_type, env)
+        }
+        provided(method) => visit_method_helper(visitor, method, env),
     }
 }
 
-pub fn visit_struct_def<E:Clone>(
-    sd: @struct_def,
-    _nm: ast::ident,
-    _generics: &Generics,
-    _id: NodeId,
-    (e, v): (E, vt<E>)
-) {
-    foreach f in sd.fields.iter() {
-        (v.visit_struct_field)(*f, (e.clone(), v));
+pub fn visit_struct_def<E:Clone>(visitor: @Visitor<E>,
+                                 struct_definition: @struct_def,
+                                 _: ast::ident,
+                                 _: &Generics,
+                                 _: NodeId,
+                                 env: E) {
+    foreach field in struct_definition.fields.iter() {
+        visitor.visit_struct_field(*field, env.clone())
     }
 }
 
-pub fn visit_struct_field<E:Clone>(sf: &struct_field, (e, v): (E, vt<E>)) {
-    (v.visit_ty)(&sf.node.ty, (e, v));
+pub fn visit_struct_field<E:Clone>(visitor: @Visitor<E>,
+                                   struct_field: &struct_field,
+                                   env: E) {
+    visitor.visit_ty(&struct_field.node.ty, env)
 }
 
-pub fn visit_block<E:Clone>(b: &Block, (e, v): (E, vt<E>)) {
-    foreach vi in b.view_items.iter() {
-        (v.visit_view_item)(vi, (e.clone(), v));
+pub fn visit_block<E:Clone>(visitor: @Visitor<E>, block: &Block, env: E) {
+    foreach view_item in block.view_items.iter() {
+        visitor.visit_view_item(view_item, env.clone())
     }
-    foreach s in b.stmts.iter() {
-        (v.visit_stmt)(*s, (e.clone(), v));
+    foreach statement in block.stmts.iter() {
+        visitor.visit_stmt(*statement, env.clone())
     }
-    visit_expr_opt(b.expr, (e, v));
+    visit_expr_opt(visitor, block.expr, env)
 }
 
-pub fn visit_stmt<E>(s: &stmt, (e, v): (E, vt<E>)) {
-    match s.node {
-      stmt_decl(d, _) => (v.visit_decl)(d, (e, v)),
-      stmt_expr(ex, _) => (v.visit_expr)(ex, (e, v)),
-      stmt_semi(ex, _) => (v.visit_expr)(ex, (e, v)),
-      stmt_mac(ref mac, _) => visit_mac(mac, (e, v))
+pub fn visit_stmt<E>(visitor: @Visitor<E>, statement: &stmt, env: E) {
+    match statement.node {
+        stmt_decl(declaration, _) => visitor.visit_decl(declaration, env),
+        stmt_expr(expression, _) | stmt_semi(expression, _) => {
+            visitor.visit_expr(expression, env)
+        }
+        stmt_mac(ref macro, _) => visit_mac(visitor, macro, env),
     }
 }
 
-pub fn visit_decl<E:Clone>(d: &decl, (e, v): (E, vt<E>)) {
-    match d.node {
-        decl_local(ref loc) => (v.visit_local)(*loc, (e, v)),
-        decl_item(it) => (v.visit_item)(it, (e, v))
+pub fn visit_decl<E:Clone>(visitor: @Visitor<E>, declaration: &decl, env: E) {
+    match declaration.node {
+        decl_local(ref local) => visitor.visit_local(*local, env),
+        decl_item(item) => visitor.visit_item(item, env),
     }
 }
 
-pub fn visit_expr_opt<E>(eo: Option<@expr>, (e, v): (E, vt<E>)) {
-    match eo { None => (), Some(ex) => (v.visit_expr)(ex, (e, v)) }
+pub fn visit_expr_opt<E>(visitor: @Visitor<E>,
+                         optional_expression: Option<@expr>,
+                         env: E) {
+    match optional_expression {
+        None => {}
+        Some(expression) => visitor.visit_expr(expression, env),
+    }
 }
 
-pub fn visit_exprs<E:Clone>(exprs: &[@expr], (e, v): (E, vt<E>)) {
-    foreach ex in exprs.iter() { (v.visit_expr)(*ex, (e.clone(), v)); }
+pub fn visit_exprs<E:Clone>(visitor: @Visitor<E>,
+                            expressions: &[@expr],
+                            env: E) {
+    foreach expression in expressions.iter() {
+        visitor.visit_expr(*expression, env.clone())
+    }
 }
 
-pub fn visit_mac<E>(_m: &mac, (_e, _v): (E, vt<E>)) {
-    /* no user-serviceable parts inside */
+pub fn visit_mac<E>(_: @Visitor<E>, _: &mac, _: E) {
+    // Empty!
 }
 
-pub fn visit_expr<E:Clone>(ex: @expr, (e, v): (E, vt<E>)) {
-    match ex.node {
-        expr_vstore(x, _) => (v.visit_expr)(x, (e.clone(), v)),
-        expr_vec(ref es, _) => visit_exprs(*es, (e.clone(), v)),
+pub fn visit_expr<E:Clone>(visitor: @Visitor<E>, expression: @expr, env: E) {
+    match expression.node {
+        expr_vstore(subexpression, _) => {
+            visitor.visit_expr(subexpression, env.clone())
+        }
+        expr_vec(ref subexpressions, _) => {
+            visit_exprs(visitor, *subexpressions, env.clone())
+        }
         expr_repeat(element, count, _) => {
-            (v.visit_expr)(element, (e.clone(), v));
-            (v.visit_expr)(count, (e.clone(), v));
+            visitor.visit_expr(element, env.clone());
+            visitor.visit_expr(count, env.clone())
         }
-        expr_struct(ref p, ref flds, base) => {
-            visit_path(p, (e.clone(), v));
-            foreach f in flds.iter() {
-                (v.visit_expr)(f.expr, (e.clone(), v));
+        expr_struct(ref path, ref fields, optional_base) => {
+            visit_path(visitor, path, env.clone());
+            foreach field in fields.iter() {
+                visitor.visit_expr(field.expr, env.clone())
             }
-            visit_expr_opt(base, (e.clone(), v));
+            visit_expr_opt(visitor, optional_base, env.clone())
         }
-        expr_tup(ref elts) => {
-            foreach el in elts.iter() { (v.visit_expr)(*el, (e.clone(), v)) }
+        expr_tup(ref subexpressions) => {
+            foreach subexpression in subexpressions.iter() {
+                visitor.visit_expr(*subexpression, env.clone())
+            }
         }
-        expr_call(callee, ref args, _) => {
-            visit_exprs(*args, (e.clone(), v));
-            (v.visit_expr)(callee, (e.clone(), v));
+        expr_call(callee_expression, ref arguments, _) => {
+            foreach argument in arguments.iter() {
+                visitor.visit_expr(*argument, env.clone())
+            }
+            visitor.visit_expr(callee_expression, env.clone())
         }
-        expr_method_call(_, callee, _, ref tys, ref args, _) => {
-            visit_exprs(*args, (e.clone(), v));
-            foreach tp in tys.iter() {
-                (v.visit_ty)(tp, (e.clone(), v));
+        expr_method_call(_, callee, _, ref types, ref arguments, _) => {
+            visit_exprs(visitor, *arguments, env.clone());
+            foreach typ in types.iter() {
+                visitor.visit_ty(typ, env.clone())
+            }
+            visitor.visit_expr(callee, env.clone())
+        }
+        expr_binary(_, _, left_expression, right_expression) => {
+            visitor.visit_expr(left_expression, env.clone());
+            visitor.visit_expr(right_expression, env.clone())
+        }
+        expr_addr_of(_, subexpression) |
+        expr_unary(_, _, subexpression) |
+        expr_loop_body(subexpression) |
+        expr_do_body(subexpression) => {
+            visitor.visit_expr(subexpression, env.clone())
+        }
+        expr_lit(_) => {}
+        expr_cast(subexpression, ref typ) => {
+            visitor.visit_expr(subexpression, env.clone());
+            visitor.visit_ty(typ, env.clone())
+        }
+        expr_if(head_expression, ref if_block, optional_else) => {
+            visitor.visit_expr(head_expression, env.clone());
+            visitor.visit_block(if_block, env.clone());
+            visit_expr_opt(visitor, optional_else, env.clone())
+        }
+        expr_while(subexpression, ref block) => {
+            visitor.visit_expr(subexpression, env.clone());
+            visitor.visit_block(block, env.clone())
+        }
+        expr_for_loop(pattern, subexpression, ref block) => {
+            visitor.visit_pat(pattern, env.clone());
+            visitor.visit_expr(subexpression, env.clone());
+            visitor.visit_block(block, env.clone())
+        }
+        expr_loop(ref block, _) => visitor.visit_block(block, env.clone()),
+        expr_match(subexpression, ref arms) => {
+            visitor.visit_expr(subexpression, env.clone());
+            foreach arm in arms.iter() {
+                visitor.visit_arm(arm, env.clone())
             }
-            (v.visit_expr)(callee, (e.clone(), v));
-        }
-        expr_binary(_, _, a, b) => {
-            (v.visit_expr)(a, (e.clone(), v));
-            (v.visit_expr)(b, (e.clone(), v));
-        }
-        expr_addr_of(_, x) | expr_unary(_, _, x) |
-        expr_loop_body(x) | expr_do_body(x) => (v.visit_expr)(x, (e.clone(), v)),
-        expr_lit(_) => (),
-        expr_cast(x, ref t) => {
-            (v.visit_expr)(x, (e.clone(), v));
-            (v.visit_ty)(t, (e.clone(), v));
-        }
-        expr_if(x, ref b, eo) => {
-            (v.visit_expr)(x, (e.clone(), v));
-            (v.visit_block)(b, (e.clone(), v));
-            visit_expr_opt(eo, (e.clone(), v));
-        }
-        expr_while(x, ref b) => {
-            (v.visit_expr)(x, (e.clone(), v));
-            (v.visit_block)(b, (e.clone(), v));
-        }
-        expr_for_loop(pat, iter, ref b) => {
-            (v.visit_pat)(pat, (e.clone(), v));
-            (v.visit_expr)(iter, (e.clone(), v));
-            (v.visit_block)(b, (e.clone(), v));
-        }
-        expr_loop(ref b, _) => (v.visit_block)(b, (e.clone(), v)),
-        expr_match(x, ref arms) => {
-            (v.visit_expr)(x, (e.clone(), v));
-            foreach a in arms.iter() { (v.visit_arm)(a, (e.clone(), v)); }
-        }
-        expr_fn_block(ref decl, ref body) => {
-            (v.visit_fn)(
-                &fk_fn_block,
-                decl,
-                body,
-                ex.span,
-                ex.id,
-                (e.clone(), v)
-            );
-        }
-        expr_block(ref b) => (v.visit_block)(b, (e.clone(), v)),
-        expr_assign(a, b) => {
-            (v.visit_expr)(b, (e.clone(), v));
-            (v.visit_expr)(a, (e.clone(), v));
-        }
-        expr_assign_op(_, _, a, b) => {
-            (v.visit_expr)(b, (e.clone(), v));
-            (v.visit_expr)(a, (e.clone(), v));
-        }
-        expr_field(x, _, ref tys) => {
-            (v.visit_expr)(x, (e.clone(), v));
-            foreach tp in tys.iter() {
-                (v.visit_ty)(tp, (e.clone(), v));
+        }
+        expr_fn_block(ref function_declaration, ref body) => {
+            visitor.visit_fn(&fk_fn_block,
+                             function_declaration,
+                             body,
+                             expression.span,
+                             expression.id,
+                             env.clone())
+        }
+        expr_block(ref block) => visitor.visit_block(block, env.clone()),
+        expr_assign(left_hand_expression, right_hand_expression) => {
+            visitor.visit_expr(right_hand_expression, env.clone());
+            visitor.visit_expr(left_hand_expression, env.clone())
+        }
+        expr_assign_op(_, _, left_expression, right_expression) => {
+            visitor.visit_expr(right_expression, env.clone());
+            visitor.visit_expr(left_expression, env.clone())
+        }
+        expr_field(subexpression, _, ref types) => {
+            visitor.visit_expr(subexpression, env.clone());
+            foreach typ in types.iter() {
+                visitor.visit_ty(typ, env.clone())
             }
         }
-        expr_index(_, a, b) => {
-            (v.visit_expr)(a, (e.clone(), v));
-            (v.visit_expr)(b, (e.clone(), v));
-        }
-        expr_path(ref p) => visit_path(p, (e.clone(), v)),
-        expr_self => (),
-        expr_break(_) => (),
-        expr_again(_) => (),
-        expr_ret(eo) => visit_expr_opt(eo, (e.clone(), v)),
-        expr_log(lv, x) => {
-            (v.visit_expr)(lv, (e.clone(), v));
-            (v.visit_expr)(x, (e.clone(), v));
-        }
-        expr_mac(ref mac) => visit_mac(mac, (e.clone(), v)),
-        expr_paren(x) => (v.visit_expr)(x, (e.clone(), v)),
-        expr_inline_asm(ref a) => {
-            foreach &(_, input) in a.inputs.iter() {
-                (v.visit_expr)(input, (e.clone(), v));
+        expr_index(_, main_expression, index_expression) => {
+            visitor.visit_expr(main_expression, env.clone());
+            visitor.visit_expr(index_expression, env.clone())
+        }
+        expr_path(ref path) => visit_path(visitor, path, env.clone()),
+        expr_self | expr_break(_) | expr_again(_) => {}
+        expr_ret(optional_expression) => {
+            visit_expr_opt(visitor, optional_expression, env.clone())
+        }
+        expr_log(level, subexpression) => {
+            visitor.visit_expr(level, env.clone());
+            visitor.visit_expr(subexpression, env.clone());
+        }
+        expr_mac(ref macro) => visit_mac(visitor, macro, env.clone()),
+        expr_paren(subexpression) => {
+            visitor.visit_expr(subexpression, env.clone())
+        }
+        expr_inline_asm(ref assembler) => {
+            foreach &(_, input) in assembler.inputs.iter() {
+                visitor.visit_expr(input, env.clone())
             }
-            foreach &(_, out) in a.outputs.iter() {
-                (v.visit_expr)(out, (e.clone(), v));
+            foreach &(_, output) in assembler.outputs.iter() {
+                visitor.visit_expr(output, env.clone())
             }
         }
     }
-    (v.visit_expr_post)(ex, (e, v));
+
+    visitor.visit_expr_post(expression, env.clone())
 }
 
-pub fn visit_arm<E:Clone>(a: &arm, (e, v): (E, vt<E>)) {
-    foreach p in a.pats.iter() { (v.visit_pat)(*p, (e.clone(), v)); }
-    visit_expr_opt(a.guard, (e.clone(), v));
-    (v.visit_block)(&a.body, (e.clone(), v));
+pub fn visit_arm<E:Clone>(visitor: @Visitor<E>, arm: &arm, env: E) {
+    foreach pattern in arm.pats.iter() {
+        visitor.visit_pat(*pattern, env.clone())
+    }
+    visit_expr_opt(visitor, arm.guard, env.clone());
+    visitor.visit_block(&arm.body, env)
 }
 
 // Simpler, non-context passing interface. Always walks the whole tree, simply
 // calls the given functions on the nodes.
 
-pub struct SimpleVisitor {
-    visit_mod: @fn(&_mod, span, NodeId),
-    visit_view_item: @fn(&view_item),
-    visit_foreign_item: @fn(@foreign_item),
-    visit_item: @fn(@item),
-    visit_local: @fn(@Local),
-    visit_block: @fn(&Block),
-    visit_stmt: @fn(@stmt),
-    visit_arm: @fn(&arm),
-    visit_pat: @fn(@pat),
-    visit_decl: @fn(@decl),
-    visit_expr: @fn(@expr),
-    visit_expr_post: @fn(@expr),
-    visit_ty: @fn(&Ty),
-    visit_generics: @fn(&Generics),
-    visit_fn: @fn(&fn_kind, &fn_decl, &Block, span, NodeId),
-    visit_ty_method: @fn(&TypeMethod),
-    visit_trait_method: @fn(&trait_method),
-    visit_struct_def: @fn(@struct_def, ident, &Generics, NodeId),
-    visit_struct_field: @fn(@struct_field),
-    visit_struct_method: @fn(@method)
-}
-
-pub type simple_visitor = @SimpleVisitor;
-
-pub fn simple_ignore_ty(_t: &Ty) {}
-
-pub fn default_simple_visitor() -> @SimpleVisitor {
-    @SimpleVisitor {
-        visit_mod: |_m, _sp, _id| { },
-        visit_view_item: |_vi| { },
-        visit_foreign_item: |_ni| { },
-        visit_item: |_i| { },
-        visit_local: |_l| { },
-        visit_block: |_b| { },
-        visit_stmt: |_s| { },
-        visit_arm: |_a| { },
-        visit_pat: |_p| { },
-        visit_decl: |_d| { },
-        visit_expr: |_e| { },
-        visit_expr_post: |_e| { },
-        visit_ty: simple_ignore_ty,
-        visit_generics: |_| {},
-        visit_fn: |_, _, _, _, _| {},
-        visit_ty_method: |_| {},
-        visit_trait_method: |_| {},
-        visit_struct_def: |_, _, _, _| {},
-        visit_struct_field: |_| {},
-        visit_struct_method: |_| {},
-    }
-}
-
-pub fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
-    fn v_mod(
-        f: @fn(&_mod, span, NodeId),
-        m: &_mod,
-        sp: span,
-        id: NodeId,
-        (e, v): ((), vt<()>)
-    ) {
-        f(m, sp, id);
-        visit_mod(m, sp, id, (e, v));
-    }
-    fn v_view_item(f: @fn(&view_item), vi: &view_item, (e, v): ((), vt<()>)) {
-        f(vi);
-        visit_view_item(vi, (e, v));
-    }
-    fn v_foreign_item(f: @fn(@foreign_item), ni: @foreign_item, (e, v): ((), vt<()>)) {
-        f(ni);
-        visit_foreign_item(ni, (e, v));
-    }
-    fn v_item(f: @fn(@item), i: @item, (e, v): ((), vt<()>)) {
-        f(i);
-        visit_item(i, (e, v));
-    }
-    fn v_local(f: @fn(@Local), l: @Local, (e, v): ((), vt<()>)) {
-        f(l);
-        visit_local(l, (e, v));
-    }
-    fn v_block(f: @fn(&ast::Block), bl: &ast::Block, (e, v): ((), vt<()>)) {
-        f(bl);
-        visit_block(bl, (e, v));
-    }
-    fn v_stmt(f: @fn(@stmt), st: @stmt, (e, v): ((), vt<()>)) {
-        f(st);
-        visit_stmt(st, (e, v));
-    }
-    fn v_arm(f: @fn(&arm), a: &arm, (e, v): ((), vt<()>)) {
-        f(a);
-        visit_arm(a, (e, v));
-    }
-    fn v_pat(f: @fn(@pat), p: @pat, (e, v): ((), vt<()>)) {
-        f(p);
-        visit_pat(p, (e, v));
-    }
-    fn v_decl(f: @fn(@decl), d: @decl, (e, v): ((), vt<()>)) {
-        f(d);
-        visit_decl(d, (e, v));
-    }
-    fn v_expr(f: @fn(@expr), ex: @expr, (e, v): ((), vt<()>)) {
-        f(ex);
-        visit_expr(ex, (e, v));
-    }
-    fn v_expr_post(f: @fn(@expr), ex: @expr, (_e, _v): ((), vt<()>)) {
-        f(ex);
-    }
-    fn v_ty(f: @fn(&Ty), ty: &Ty, (e, v): ((), vt<()>)) {
-        f(ty);
-        visit_ty(ty, (e, v));
-    }
-    fn v_ty_method(f: @fn(&TypeMethod), ty: &TypeMethod, (e, v): ((), vt<()>)) {
-        f(ty);
-        visit_ty_method(ty, (e, v));
-    }
-    fn v_trait_method(f: @fn(&trait_method),
-                      m: &trait_method,
-                      (e, v): ((), vt<()>)) {
-        f(m);
-        visit_trait_method(m, (e, v));
-    }
-    fn v_struct_def(
-        f: @fn(@struct_def, ident, &Generics, NodeId),
-        sd: @struct_def,
-        nm: ident,
-        generics: &Generics,
-        id: NodeId,
-        (e, v): ((), vt<()>)
-    ) {
-        f(sd, nm, generics, id);
-        visit_struct_def(sd, nm, generics, id, (e, v));
-    }
-    fn v_generics(
-        f: @fn(&Generics),
-        ps: &Generics,
-        (e, v): ((), vt<()>)
-    ) {
-        f(ps);
-        visit_generics(ps, (e, v));
-    }
-    fn v_fn(
-        f: @fn(&fn_kind, &fn_decl, &Block, span, NodeId),
-        fk: &fn_kind,
-        decl: &fn_decl,
-        body: &Block,
-        sp: span,
-        id: NodeId,
-        (e, v): ((), vt<()>)
-    ) {
-        f(fk, decl, body, sp, id);
-        visit_fn(fk, decl, body, sp, id, (e, v));
-    }
-    let visit_ty: @fn(&Ty, ((), vt<()>)) =
-        |a,b| v_ty(v.visit_ty, a, b);
-    fn v_struct_field(f: @fn(@struct_field), sf: @struct_field, (e, v): ((), vt<()>)) {
-        f(sf);
-        visit_struct_field(sf, (e, v));
-    }
-    return mk_vt(@Visitor {
-        visit_mod: |a,b,c,d|v_mod(v.visit_mod, a, b, c, d),
-        visit_view_item: |a,b| v_view_item(v.visit_view_item, a, b),
-        visit_foreign_item:
-            |a,b|v_foreign_item(v.visit_foreign_item, a, b),
-        visit_item: |a,b|v_item(v.visit_item, a, b),
-        visit_local: |a,b|v_local(v.visit_local, a, b),
-        visit_block: |a,b|v_block(v.visit_block, a, b),
-        visit_stmt: |a,b|v_stmt(v.visit_stmt, a, b),
-        visit_arm: |a,b|v_arm(v.visit_arm, a, b),
-        visit_pat: |a,b|v_pat(v.visit_pat, a, b),
-        visit_decl: |a,b|v_decl(v.visit_decl, a, b),
-        visit_expr: |a,b|v_expr(v.visit_expr, a, b),
-        visit_expr_post: |a,b| v_expr_post(v.visit_expr_post, a, b),
-        visit_ty: visit_ty,
-        visit_generics: |a,b|
-            v_generics(v.visit_generics, a, b),
-        visit_fn: |a,b,c,d,e,f|
-            v_fn(v.visit_fn, a, b, c, d, e, f),
-        visit_ty_method: |a,b|
-            v_ty_method(v.visit_ty_method, a, b),
-        visit_trait_method: |a,b|
-            v_trait_method(v.visit_trait_method, a, b),
-        visit_struct_def: |a,b,c,d,e|
-            v_struct_def(v.visit_struct_def, a, b, c, d, e),
-        visit_struct_field: |a,b|
-            v_struct_field(v.visit_struct_field, a, b),
-    });
+pub trait SimpleVisitor {
+    fn visit_mod(@mut self, &_mod, span, NodeId);
+    fn visit_view_item(@mut self, &view_item);
+    fn visit_foreign_item(@mut self, @foreign_item);
+    fn visit_item(@mut self, @item);
+    fn visit_local(@mut self, @Local);
+    fn visit_block(@mut self, &Block);
+    fn visit_stmt(@mut self, @stmt);
+    fn visit_arm(@mut self, &arm);
+    fn visit_pat(@mut self, @pat);
+    fn visit_decl(@mut self, @decl);
+    fn visit_expr(@mut self, @expr);
+    fn visit_expr_post(@mut self, @expr);
+    fn visit_ty(@mut self, &Ty);
+    fn visit_generics(@mut self, &Generics);
+    fn visit_fn(@mut self, &fn_kind, &fn_decl, &Block, span, NodeId);
+    fn visit_ty_method(@mut self, &TypeMethod);
+    fn visit_trait_method(@mut self, &trait_method);
+    fn visit_struct_def(@mut self, @struct_def, ident, &Generics, NodeId);
+    fn visit_struct_field(@mut self, @struct_field);
+    fn visit_struct_method(@mut self, @method);
+}
+
+pub struct SimpleVisitorVisitor {
+    simple_visitor: @SimpleVisitor,
+}
+
+impl Visitor<()> for SimpleVisitorVisitor {
+    fn visit_mod(@mut self,
+                 module: &_mod,
+                 span: span,
+                 node_id: NodeId,
+                 env: ()) {
+        self.simple_visitor.visit_mod(module, span, node_id);
+        visit_mod(self as @Visitor<()>, module, env)
+    }
+    fn visit_view_item(@mut self, view_item: &view_item, env: ()) {
+        self.simple_visitor.visit_view_item(view_item);
+        visit_view_item(self as @Visitor<()>, view_item, env)
+    }
+    fn visit_foreign_item(@mut self, foreign_item: @foreign_item, env: ()) {
+        self.simple_visitor.visit_foreign_item(foreign_item);
+        visit_foreign_item(self as @Visitor<()>, foreign_item, env)
+    }
+    fn visit_item(@mut self, item: @item, env: ()) {
+        self.simple_visitor.visit_item(item);
+        visit_item(self as @Visitor<()>, item, env)
+    }
+    fn visit_local(@mut self, local: @Local, env: ()) {
+        self.simple_visitor.visit_local(local);
+        visit_local(self as @Visitor<()>, local, env)
+    }
+    fn visit_block(@mut self, block: &Block, env: ()) {
+        self.simple_visitor.visit_block(block);
+        visit_block(self as @Visitor<()>, block, env)
+    }
+    fn visit_stmt(@mut self, statement: @stmt, env: ()) {
+        self.simple_visitor.visit_stmt(statement);
+        visit_stmt(self as @Visitor<()>, statement, env)
+    }
+    fn visit_arm(@mut self, arm: &arm, env: ()) {
+        self.simple_visitor.visit_arm(arm);
+        visit_arm(self as @Visitor<()>, arm, env)
+    }
+    fn visit_pat(@mut self, pattern: @pat, env: ()) {
+        self.simple_visitor.visit_pat(pattern);
+        visit_pat(self as @Visitor<()>, pattern, env)
+    }
+    fn visit_decl(@mut self, declaration: @decl, env: ()) {
+        self.simple_visitor.visit_decl(declaration);
+        visit_decl(self as @Visitor<()>, declaration, env)
+    }
+    fn visit_expr(@mut self, expression: @expr, env: ()) {
+        self.simple_visitor.visit_expr(expression);
+        visit_expr(self as @Visitor<()>, expression, env)
+    }
+    fn visit_expr_post(@mut self, expression: @expr, _: ()) {
+        self.simple_visitor.visit_expr_post(expression)
+    }
+    fn visit_ty(@mut self, typ: &Ty, env: ()) {
+        self.simple_visitor.visit_ty(typ);
+        visit_ty(self as @Visitor<()>, typ, env)
+    }
+    fn visit_generics(@mut self, generics: &Generics, env: ()) {
+        self.simple_visitor.visit_generics(generics);
+        visit_generics(self as @Visitor<()>, generics, env)
+    }
+    fn visit_fn(@mut self,
+                function_kind: &fn_kind,
+                function_declaration: &fn_decl,
+                block: &Block,
+                span: span,
+                node_id: NodeId,
+                env: ()) {
+        self.simple_visitor.visit_fn(function_kind,
+                                     function_declaration,
+                                     block,
+                                     span,
+                                     node_id);
+        visit_fn(self as @Visitor<()>,
+                 function_kind,
+                 function_declaration,
+                 block,
+                 span,
+                 node_id,
+                 env)
+    }
+    fn visit_ty_method(@mut self, method_type: &TypeMethod, env: ()) {
+        self.simple_visitor.visit_ty_method(method_type);
+        visit_ty_method(self as @Visitor<()>, method_type, env)
+    }
+    fn visit_trait_method(@mut self, trait_method: &trait_method, env: ()) {
+        self.simple_visitor.visit_trait_method(trait_method);
+        visit_trait_method(self as @Visitor<()>, trait_method, env)
+    }
+    fn visit_struct_def(@mut self,
+                        struct_definition: @struct_def,
+                        identifier: ident,
+                        generics: &Generics,
+                        node_id: NodeId,
+                        env: ()) {
+        self.simple_visitor.visit_struct_def(struct_definition,
+                                             identifier,
+                                             generics,
+                                             node_id);
+        visit_struct_def(self as @Visitor<()>,
+                         struct_definition,
+                         identifier,
+                         generics,
+                         node_id,
+                         env)
+    }
+    fn visit_struct_field(@mut self, struct_field: @struct_field, env: ()) {
+        self.simple_visitor.visit_struct_field(struct_field);
+        visit_struct_field(self as @Visitor<()>, struct_field, env)
+    }
 }
+