about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-09-23 19:20:58 -0700
committerbors <bors@rust-lang.org>2013-09-23 19:20:58 -0700
commitd062de8aa48083439237cb338b38c25306bf6c94 (patch)
tree1ced905a1f2255a3f5207ed6c70fbe5e80cf4b41 /src/libsyntax
parent348d8446739f9633897a3d728d265ee6ac59c8fb (diff)
parent3b1d3e5bf8e2f288147fd879b37bc5e6f8c5528f (diff)
downloadrust-d062de8aa48083439237cb338b38c25306bf6c94.tar.gz
rust-d062de8aa48083439237cb338b38c25306bf6c94.zip
auto merge of #9310 : pcwalton/rust/at-fn, r=pcwalton
r? @brson
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast_util.rs93
-rw-r--r--src/libsyntax/diagnostic.rs79
-rw-r--r--src/libsyntax/ext/base.rs239
-rw-r--r--src/libsyntax/ext/build.rs30
-rw-r--r--src/libsyntax/ext/expand.rs489
-rw-r--r--src/libsyntax/ext/fmt.rs2
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs141
-rw-r--r--src/libsyntax/fold.rs1455
-rw-r--r--src/libsyntax/parse/mod.rs2
-rw-r--r--src/libsyntax/print/pprust.rs58
10 files changed, 1390 insertions, 1198 deletions
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index f0f86911f50..ac88fc835d5 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -12,7 +12,6 @@ use ast::*;
 use ast;
 use ast_util;
 use codemap::{Span, dummy_sp};
-use fold;
 use opt_vec;
 use parse::token;
 use visit::Visitor;
@@ -371,21 +370,6 @@ pub fn empty_generics() -> Generics {
               ty_params: opt_vec::Empty}
 }
 
-///////////////////////////////////////////////////////////////////////////
-// Assigning node ids
-
-fn node_id_assigner(next_id: @fn() -> ast::NodeId) -> @fold::ast_fold {
-    let precursor = @fold::AstFoldFns {
-        new_id: |old_id| {
-            assert_eq!(old_id, ast::DUMMY_NODE_ID);
-            next_id()
-        },
-        ..*fold::default_ast_fold()
-    };
-
-    fold::make_fold(precursor)
-}
-
 // ______________________________________________________________________
 // Enumerating the IDs which appear in an AST
 
@@ -413,18 +397,22 @@ impl id_range {
     }
 }
 
-pub fn id_visitor(vfn: @fn(NodeId), pass_through_items: bool)
+pub fn id_visitor(operation: @IdVisitingOperation, pass_through_items: bool)
                   -> @mut Visitor<()> {
     let visitor = @mut IdVisitor {
-        visit_callback: vfn,
+        operation: operation,
         pass_through_items: pass_through_items,
         visited_outermost: false,
     };
     visitor as @mut Visitor<()>
 }
 
+pub trait IdVisitingOperation {
+    fn visit_id(&self, node_id: NodeId);
+}
+
 pub struct IdVisitor {
-    visit_callback: @fn(NodeId),
+    operation: @IdVisitingOperation,
     pass_through_items: bool,
     visited_outermost: bool,
 }
@@ -432,10 +420,10 @@ pub struct IdVisitor {
 impl IdVisitor {
     fn visit_generics_helper(&self, generics: &Generics) {
         for type_parameter in generics.ty_params.iter() {
-            (self.visit_callback)(type_parameter.id)
+            self.operation.visit_id(type_parameter.id)
         }
         for lifetime in generics.lifetimes.iter() {
-            (self.visit_callback)(lifetime.id)
+            self.operation.visit_id(lifetime.id)
         }
     }
 }
@@ -446,26 +434,26 @@ impl Visitor<()> for IdVisitor {
                  _: Span,
                  node_id: NodeId,
                  env: ()) {
-        (self.visit_callback)(node_id);
+        self.operation.visit_id(node_id);
         visit::walk_mod(self, 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)
+                self.operation.visit_id(node_id)
             }
             view_item_use(ref view_paths) => {
                 for 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)
+                            self.operation.visit_id(node_id)
                         }
                         view_path_list(_, ref paths, node_id) => {
-                            (self.visit_callback)(node_id);
+                            self.operation.visit_id(node_id);
                             for path in paths.iter() {
-                                (self.visit_callback)(path.node.id)
+                                self.operation.visit_id(path.node.id)
                             }
                         }
                     }
@@ -476,7 +464,7 @@ impl Visitor<()> for IdVisitor {
     }
 
     fn visit_foreign_item(&mut self, foreign_item: @foreign_item, env: ()) {
-        (self.visit_callback)(foreign_item.id);
+        self.operation.visit_id(foreign_item.id);
         visit::walk_foreign_item(self, foreign_item, env)
     }
 
@@ -489,11 +477,11 @@ impl Visitor<()> for IdVisitor {
             }
         }
 
-        (self.visit_callback)(item.id);
+        self.operation.visit_id(item.id);
         match item.node {
             item_enum(ref enum_definition, _) => {
                 for variant in enum_definition.variants.iter() {
-                    (self.visit_callback)(variant.node.id)
+                    self.operation.visit_id(variant.node.id)
                 }
             }
             _ => {}
@@ -505,22 +493,22 @@ impl Visitor<()> for IdVisitor {
     }
 
     fn visit_local(&mut self, local: @Local, env: ()) {
-        (self.visit_callback)(local.id);
+        self.operation.visit_id(local.id);
         visit::walk_local(self, local, env)
     }
 
     fn visit_block(&mut self, block: &Block, env: ()) {
-        (self.visit_callback)(block.id);
+        self.operation.visit_id(block.id);
         visit::walk_block(self, block, env)
     }
 
     fn visit_stmt(&mut self, statement: @Stmt, env: ()) {
-        (self.visit_callback)(ast_util::stmt_id(statement));
+        self.operation.visit_id(ast_util::stmt_id(statement));
         visit::walk_stmt(self, statement, env)
     }
 
     fn visit_pat(&mut self, pattern: @Pat, env: ()) {
-        (self.visit_callback)(pattern.id);
+        self.operation.visit_id(pattern.id);
         visit::walk_pat(self, pattern, env)
     }
 
@@ -529,17 +517,17 @@ impl Visitor<()> for IdVisitor {
         {
             let optional_callee_id = expression.get_callee_id();
             for callee_id in optional_callee_id.iter() {
-                (self.visit_callback)(*callee_id)
+                self.operation.visit_id(*callee_id)
             }
         }
-        (self.visit_callback)(expression.id);
+        self.operation.visit_id(expression.id);
         visit::walk_expr(self, expression, env)
     }
 
     fn visit_ty(&mut self, typ: &Ty, env: ()) {
-        (self.visit_callback)(typ.id);
+        self.operation.visit_id(typ.id);
         match typ.node {
-            ty_path(_, _, id) => (self.visit_callback)(id),
+            ty_path(_, _, id) => self.operation.visit_id(id),
             _ => {}
         }
         visit::walk_ty(self, typ, env)
@@ -565,21 +553,21 @@ impl Visitor<()> for IdVisitor {
             }
         }
 
-        (self.visit_callback)(node_id);
+        self.operation.visit_id(node_id);
 
         match *function_kind {
             visit::fk_item_fn(_, generics, _, _) => {
                 self.visit_generics_helper(generics)
             }
             visit::fk_method(_, generics, method) => {
-                (self.visit_callback)(method.self_id);
+                self.operation.visit_id(method.self_id);
                 self.visit_generics_helper(generics)
             }
             visit::fk_anon(_) | visit::fk_fn_block => {}
         }
 
         for argument in function_declaration.inputs.iter() {
-            (self.visit_callback)(argument.id)
+            self.operation.visit_id(argument.id)
         }
 
         visit::walk_fn(self,
@@ -599,25 +587,36 @@ impl Visitor<()> for IdVisitor {
     }
 
     fn visit_struct_field(&mut self, struct_field: @struct_field, env: ()) {
-        (self.visit_callback)(struct_field.node.id);
+        self.operation.visit_id(struct_field.node.id);
         visit::walk_struct_field(self, struct_field, env)
     }
 }
 
-pub fn visit_ids_for_inlined_item(item: &inlined_item, vfn: @fn(NodeId)) {
+pub fn visit_ids_for_inlined_item(item: &inlined_item,
+                                  operation: @IdVisitingOperation) {
     let mut id_visitor = IdVisitor {
-        visit_callback: vfn,
+        operation: operation,
         pass_through_items: true,
         visited_outermost: false,
     };
     item.accept((), &mut id_visitor);
 }
 
-pub fn compute_id_range(visit_ids_fn: &fn(@fn(NodeId))) -> id_range {
-    let result = @mut id_range::max();
-    do visit_ids_fn |id| {
-        result.add(id);
+struct IdRangeComputingVisitor {
+    result: @mut id_range,
+}
+
+impl IdVisitingOperation for IdRangeComputingVisitor {
+    fn visit_id(&self, id: NodeId) {
+        self.result.add(id)
     }
+}
+
+pub fn compute_id_range(visit_ids_fn: &fn(@IdVisitingOperation)) -> id_range {
+    let result = @mut id_range::max();
+    visit_ids_fn(@IdRangeComputingVisitor {
+        result: result,
+    } as @IdVisitingOperation);
     *result
 }
 
diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs
index 5e9714ca5b2..aa06e1bee41 100644
--- a/src/libsyntax/diagnostic.rs
+++ b/src/libsyntax/diagnostic.rs
@@ -15,9 +15,12 @@ use std::io;
 use std::local_data;
 use extra::term;
 
-pub type Emitter = @fn(cmsp: Option<(@codemap::CodeMap, Span)>,
-                       msg: &str,
-                       lvl: level);
+pub trait Emitter {
+    fn emit(&self,
+            cmsp: Option<(@codemap::CodeMap, Span)>,
+            msg: &str,
+            lvl: level);
+}
 
 // a handler deals with errors; certain errors
 // (fatal, bug, unimpl) may cause immediate exit,
@@ -55,7 +58,7 @@ pub trait span_handler {
 
 struct HandlerT {
     err_count: uint,
-    emit: Emitter,
+    emit: @Emitter,
 }
 
 struct CodemapT {
@@ -91,11 +94,11 @@ impl span_handler for CodemapT {
 
 impl handler for HandlerT {
     fn fatal(@mut self, msg: &str) -> ! {
-        (self.emit)(None, msg, fatal);
+        self.emit.emit(None, msg, fatal);
         fail!();
     }
     fn err(@mut self, msg: &str) {
-        (self.emit)(None, msg, error);
+        self.emit.emit(None, msg, error);
         self.bump_err_count();
     }
     fn bump_err_count(@mut self) {
@@ -120,10 +123,10 @@ impl handler for HandlerT {
         self.fatal(s);
     }
     fn warn(@mut self, msg: &str) {
-        (self.emit)(None, msg, warning);
+        self.emit.emit(None, msg, warning);
     }
     fn note(@mut self, msg: &str) {
-        (self.emit)(None, msg, note);
+        self.emit.emit(None, msg, note);
     }
     fn bug(@mut self, msg: &str) -> ! {
         self.fatal(ice_msg(msg));
@@ -135,7 +138,7 @@ impl handler for HandlerT {
             cmsp: Option<(@codemap::CodeMap, Span)>,
             msg: &str,
             lvl: level) {
-        (self.emit)(cmsp, msg, lvl);
+        self.emit.emit(cmsp, msg, lvl);
     }
 }
 
@@ -145,19 +148,22 @@ pub fn ice_msg(msg: &str) -> ~str {
 
 pub fn mk_span_handler(handler: @mut handler, cm: @codemap::CodeMap)
                     -> @mut span_handler {
-    @mut CodemapT { handler: handler, cm: cm } as @mut span_handler
+    @mut CodemapT {
+        handler: handler,
+        cm: cm,
+    } as @mut span_handler
 }
 
-pub fn mk_handler(emitter: Option<Emitter>) -> @mut handler {
-    let emit: Emitter = match emitter {
+pub fn mk_handler(emitter: Option<@Emitter>) -> @mut handler {
+    let emit: @Emitter = match emitter {
         Some(e) => e,
-        None => {
-            let emit: Emitter = |cmsp, msg, t| emit(cmsp, msg, t);
-            emit
-        }
+        None => @DefaultEmitter as @Emitter
     };
 
-    @mut HandlerT { err_count: 0, emit: emit } as @mut handler
+    @mut HandlerT {
+        err_count: 0,
+        emit: emit,
+    } as @mut handler
 }
 
 #[deriving(Eq)]
@@ -230,31 +236,30 @@ fn print_diagnostic(topic: &str, lvl: level, msg: &str) {
     print_maybe_styled(fmt!("%s\n", msg), term::attr::Bold);
 }
 
-pub fn collect(messages: @mut ~[~str])
-            -> @fn(Option<(@codemap::CodeMap, Span)>, &str, level) {
-    let f: @fn(Option<(@codemap::CodeMap, Span)>, &str, level) =
-        |_o, msg: &str, _l| { messages.push(msg.to_str()); };
-    f
-}
+pub struct DefaultEmitter;
 
-pub fn emit(cmsp: Option<(@codemap::CodeMap, Span)>, msg: &str, lvl: level) {
-    match cmsp {
-      Some((cm, sp)) => {
-        let sp = cm.adjust_span(sp);
-        let ss = cm.span_to_str(sp);
-        let lines = cm.span_to_lines(sp);
-        print_diagnostic(ss, lvl, msg);
-        highlight_lines(cm, sp, lvl, lines);
-        print_macro_backtrace(cm, sp);
-      }
-      None => {
-        print_diagnostic("", lvl, msg);
-      }
+impl Emitter for DefaultEmitter {
+    fn emit(&self,
+            cmsp: Option<(@codemap::CodeMap, Span)>,
+            msg: &str,
+            lvl: level) {
+        match cmsp {
+            Some((cm, sp)) => {
+                let sp = cm.adjust_span(sp);
+                let ss = cm.span_to_str(sp);
+                let lines = cm.span_to_lines(sp);
+                print_diagnostic(ss, lvl, msg);
+                highlight_lines(cm, sp, lvl, lines);
+                print_macro_backtrace(cm, sp);
+            }
+            None => print_diagnostic("", lvl, msg),
+        }
     }
 }
 
 fn highlight_lines(cm: @codemap::CodeMap,
-                   sp: Span, lvl: level,
+                   sp: Span,
+                   lvl: level,
                    lines: @codemap::FileLines) {
     let fm = lines.file;
 
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 2bcfafc3bb4..48eb9a350f1 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -33,62 +33,120 @@ pub struct MacroDef {
     ext: SyntaxExtension
 }
 
-// No context arg for an Item Decorator macro, simply because
-// adding it would require adding a ctxt field to all items.
-// we could do this if it turns out to be useful.
-
-pub type ItemDecoratorFun = @fn(@ExtCtxt,
-                             Span,
-                             @ast::MetaItem,
-                             ~[@ast::item])
-                          -> ~[@ast::item];
-
-pub type SyntaxExpanderTTFun = @fn(@ExtCtxt,
-                                   Span,
-                                   &[ast::token_tree],
-                                   ast::SyntaxContext)
-                                -> MacResult;
-
-pub type SyntaxExpanderTTItemFun = @fn(@ExtCtxt,
-                                       Span,
-                                       ast::Ident,
-                                       ~[ast::token_tree],
-                                       ast::SyntaxContext)
-                                    -> MacResult;
-
-// oog... in order to make the presentation of builtin_normal_tt_no_ctxt
-// and builtin_ident_tt_no_ctxt palatable, we need one-off types for
-// functions that don't consume a ctxt:
-
-pub type SyntaxExpanderTTFunNoCtxt = @fn(@ExtCtxt,
-                                   Span,
-                                   &[ast::token_tree])
-                                -> MacResult;
-
-pub type SyntaxExpanderTTItemFunNoCtxt = @fn(@ExtCtxt,
-                                       Span,
-                                       ast::Ident,
-                                       ~[ast::token_tree])
-                                    -> MacResult;
+pub type ItemDecorator = extern "Rust" fn(@ExtCtxt,
+                                          Span,
+                                          @ast::MetaItem,
+                                          ~[@ast::item])
+                                          -> ~[@ast::item];
+
+pub struct SyntaxExpanderTT {
+    expander: SyntaxExpanderTTExpander,
+    span: Option<Span>
+}
+
+pub trait SyntaxExpanderTTTrait {
+    fn expand(&self,
+              ecx: @ExtCtxt,
+              span: Span,
+              token_tree: &[ast::token_tree],
+              context: ast::SyntaxContext)
+              -> MacResult;
+}
+
+pub type SyntaxExpanderTTFunNoCtxt =
+    extern "Rust" fn(ecx: @ExtCtxt,
+                     span: codemap::Span,
+                     token_tree: &[ast::token_tree])
+                     -> MacResult;
+
+enum SyntaxExpanderTTExpander {
+    SyntaxExpanderTTExpanderWithoutContext(SyntaxExpanderTTFunNoCtxt),
+}
+
+impl SyntaxExpanderTTTrait for SyntaxExpanderTT {
+    fn expand(&self,
+              ecx: @ExtCtxt,
+              span: Span,
+              token_tree: &[ast::token_tree],
+              _: ast::SyntaxContext)
+              -> MacResult {
+        match self.expander {
+            SyntaxExpanderTTExpanderWithoutContext(f) => {
+                f(ecx, span, token_tree)
+            }
+        }
+    }
+}
 
+enum SyntaxExpanderTTItemExpander {
+    SyntaxExpanderTTItemExpanderWithContext(SyntaxExpanderTTItemFun),
+    SyntaxExpanderTTItemExpanderWithoutContext(SyntaxExpanderTTItemFunNoCtxt),
+}
 
+pub struct SyntaxExpanderTTItem {
+    expander: SyntaxExpanderTTItemExpander,
+    span: Option<Span>
+}
+
+pub trait SyntaxExpanderTTItemTrait {
+    fn expand(&self,
+              cx: @ExtCtxt,
+              sp: Span,
+              ident: ast::Ident,
+              token_tree: ~[ast::token_tree],
+              context: ast::SyntaxContext)
+              -> MacResult;
+}
+
+impl SyntaxExpanderTTItemTrait for SyntaxExpanderTTItem {
+    fn expand(&self,
+              cx: @ExtCtxt,
+              sp: Span,
+              ident: ast::Ident,
+              token_tree: ~[ast::token_tree],
+              context: ast::SyntaxContext)
+              -> MacResult {
+        match self.expander {
+            SyntaxExpanderTTItemExpanderWithContext(fun) => {
+                fun(cx, sp, ident, token_tree, context)
+            }
+            SyntaxExpanderTTItemExpanderWithoutContext(fun) => {
+                fun(cx, sp, ident, token_tree)
+            }
+        }
+    }
+}
+
+pub type SyntaxExpanderTTItemFun = extern "Rust" fn(@ExtCtxt,
+                                                    Span,
+                                                    ast::Ident,
+                                                    ~[ast::token_tree],
+                                                    ast::SyntaxContext)
+                                                    -> MacResult;
+
+pub type SyntaxExpanderTTItemFunNoCtxt =
+    extern "Rust" fn(@ExtCtxt, Span, ast::Ident, ~[ast::token_tree])
+                     -> MacResult;
+
+pub trait AnyMacro {
+    fn make_expr(&self) -> @ast::Expr;
+    fn make_item(&self) -> Option<@ast::item>;
+    fn make_stmt(&self) -> @ast::Stmt;
+}
 
 pub enum MacResult {
     MRExpr(@ast::Expr),
     MRItem(@ast::item),
-    MRAny(@fn() -> @ast::Expr,
-          @fn() -> Option<@ast::item>,
-          @fn() -> @ast::Stmt),
-    MRDef(MacroDef)
+    MRAny(@AnyMacro),
+    MRDef(MacroDef),
 }
 
 pub enum SyntaxExtension {
-
     // #[auto_encode] and such
-    ItemDecorator(ItemDecoratorFun),
+    ItemDecorator(ItemDecorator),
 
     // Token-tree expanders
-    NormalTT(SyntaxExpanderTTFun, Option<Span>),
+    NormalTT(@SyntaxExpanderTTTrait, Option<Span>),
 
     // An IdentTT is a macro that has an
     // identifier in between the name of the
@@ -98,7 +156,7 @@ pub enum SyntaxExtension {
 
     // perhaps macro_rules! will lose its odd special identifier argument,
     // and this can go away also
-    IdentTT(SyntaxExpanderTTItemFun, Option<Span>),
+    IdentTT(@SyntaxExpanderTTItemTrait, Option<Span>),
 }
 
 
@@ -133,16 +191,22 @@ type RenameList = ~[(ast::Ident,Name)];
 // AST nodes into full ASTs
 pub fn syntax_expander_table() -> SyntaxEnv {
     // utility function to simplify creating NormalTT syntax extensions
-    // that ignore their contexts
-    fn builtin_normal_tt_no_ctxt(f: SyntaxExpanderTTFunNoCtxt) -> @Transformer {
-        let wrapped_expander : SyntaxExpanderTTFun = |a,b,c,_d|{f(a,b,c)};
-        @SE(NormalTT(wrapped_expander, None))
+    fn builtin_normal_tt_no_ctxt(f: SyntaxExpanderTTFunNoCtxt)
+                                 -> @Transformer {
+        @SE(NormalTT(@SyntaxExpanderTT{
+            expander: SyntaxExpanderTTExpanderWithoutContext(f),
+            span: None,
+        } as @SyntaxExpanderTTTrait,
+        None))
     }
     // utility function to simplify creating IdentTT syntax extensions
     // that ignore their contexts
     fn builtin_item_tt_no_ctxt(f: SyntaxExpanderTTItemFunNoCtxt) -> @Transformer {
-        let wrapped_expander : SyntaxExpanderTTItemFun = |a,b,c,d,_e|{f(a,b,c,d)};
-        @SE(IdentTT(wrapped_expander, None))
+        @SE(IdentTT(@SyntaxExpanderTTItem {
+            expander: SyntaxExpanderTTItemExpanderWithoutContext(f),
+            span: None,
+        } as @SyntaxExpanderTTItemTrait,
+        None))
     }
     let mut syntax_expanders = HashMap::new();
     // NB identifier starts with space, and can't conflict with legal idents
@@ -152,11 +216,18 @@ pub fn syntax_expander_table() -> SyntaxEnv {
                                 pending_renames : @mut ~[]
                             }));
     syntax_expanders.insert(intern(&"macro_rules"),
-                            @SE(IdentTT(ext::tt::macro_rules::add_new_extension, None)));
+                            @SE(IdentTT(@SyntaxExpanderTTItem {
+                                expander: SyntaxExpanderTTItemExpanderWithContext(
+                                    ext::tt::macro_rules::add_new_extension),
+                                span: None,
+                            } as @SyntaxExpanderTTItemTrait,
+                            None)));
     syntax_expanders.insert(intern(&"fmt"),
-                            builtin_normal_tt_no_ctxt(ext::fmt::expand_syntax_ext));
+                            builtin_normal_tt_no_ctxt(
+                                ext::fmt::expand_syntax_ext));
     syntax_expanders.insert(intern(&"format_args"),
-                            builtin_normal_tt_no_ctxt(ext::format::expand_args));
+                            builtin_normal_tt_no_ctxt(
+                                ext::format::expand_args));
     syntax_expanders.insert(
         intern(&"auto_encode"),
         @SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
@@ -164,67 +235,77 @@ pub fn syntax_expander_table() -> SyntaxEnv {
         intern(&"auto_decode"),
         @SE(ItemDecorator(ext::auto_encode::expand_auto_decode)));
     syntax_expanders.insert(intern(&"env"),
-                            builtin_normal_tt_no_ctxt(ext::env::expand_env));
+                            builtin_normal_tt_no_ctxt(
+                                    ext::env::expand_env));
     syntax_expanders.insert(intern(&"option_env"),
-                            builtin_normal_tt_no_ctxt(ext::env::expand_option_env));
+                            builtin_normal_tt_no_ctxt(
+                                    ext::env::expand_option_env));
     syntax_expanders.insert(intern("bytes"),
-                            builtin_normal_tt_no_ctxt(ext::bytes::expand_syntax_ext));
+                            builtin_normal_tt_no_ctxt(
+                                    ext::bytes::expand_syntax_ext));
     syntax_expanders.insert(intern("concat_idents"),
                             builtin_normal_tt_no_ctxt(
-                                ext::concat_idents::expand_syntax_ext));
+                                    ext::concat_idents::expand_syntax_ext));
     syntax_expanders.insert(intern(&"log_syntax"),
                             builtin_normal_tt_no_ctxt(
-                                ext::log_syntax::expand_syntax_ext));
+                                    ext::log_syntax::expand_syntax_ext));
     syntax_expanders.insert(intern(&"deriving"),
                             @SE(ItemDecorator(
                                 ext::deriving::expand_meta_deriving)));
 
     // Quasi-quoting expanders
     syntax_expanders.insert(intern(&"quote_tokens"),
-                            builtin_normal_tt_no_ctxt(
-                                ext::quote::expand_quote_tokens));
+                       builtin_normal_tt_no_ctxt(
+                            ext::quote::expand_quote_tokens));
     syntax_expanders.insert(intern(&"quote_expr"),
-                            builtin_normal_tt_no_ctxt(ext::quote::expand_quote_expr));
+                       builtin_normal_tt_no_ctxt(
+                            ext::quote::expand_quote_expr));
     syntax_expanders.insert(intern(&"quote_ty"),
-                            builtin_normal_tt_no_ctxt(ext::quote::expand_quote_ty));
+                       builtin_normal_tt_no_ctxt(
+                            ext::quote::expand_quote_ty));
     syntax_expanders.insert(intern(&"quote_item"),
-                            builtin_normal_tt_no_ctxt(ext::quote::expand_quote_item));
+                       builtin_normal_tt_no_ctxt(
+                            ext::quote::expand_quote_item));
     syntax_expanders.insert(intern(&"quote_pat"),
-                            builtin_normal_tt_no_ctxt(ext::quote::expand_quote_pat));
+                       builtin_normal_tt_no_ctxt(
+                            ext::quote::expand_quote_pat));
     syntax_expanders.insert(intern(&"quote_stmt"),
-                            builtin_normal_tt_no_ctxt(ext::quote::expand_quote_stmt));
+                       builtin_normal_tt_no_ctxt(
+                            ext::quote::expand_quote_stmt));
 
     syntax_expanders.insert(intern(&"line"),
                             builtin_normal_tt_no_ctxt(
-                                ext::source_util::expand_line));
+                                    ext::source_util::expand_line));
     syntax_expanders.insert(intern(&"col"),
                             builtin_normal_tt_no_ctxt(
-                                ext::source_util::expand_col));
+                                    ext::source_util::expand_col));
     syntax_expanders.insert(intern(&"file"),
                             builtin_normal_tt_no_ctxt(
-                                ext::source_util::expand_file));
+                                    ext::source_util::expand_file));
     syntax_expanders.insert(intern(&"stringify"),
                             builtin_normal_tt_no_ctxt(
-                                ext::source_util::expand_stringify));
+                                    ext::source_util::expand_stringify));
     syntax_expanders.insert(intern(&"include"),
                             builtin_normal_tt_no_ctxt(
-                                ext::source_util::expand_include));
+                                    ext::source_util::expand_include));
     syntax_expanders.insert(intern(&"include_str"),
                             builtin_normal_tt_no_ctxt(
-                                ext::source_util::expand_include_str));
+                                    ext::source_util::expand_include_str));
     syntax_expanders.insert(intern(&"include_bin"),
                             builtin_normal_tt_no_ctxt(
-                                ext::source_util::expand_include_bin));
+                                    ext::source_util::expand_include_bin));
     syntax_expanders.insert(intern(&"module_path"),
                             builtin_normal_tt_no_ctxt(
-                                ext::source_util::expand_mod));
+                                    ext::source_util::expand_mod));
     syntax_expanders.insert(intern(&"asm"),
-                            builtin_normal_tt_no_ctxt(ext::asm::expand_asm));
+                            builtin_normal_tt_no_ctxt(
+                                    ext::asm::expand_asm));
     syntax_expanders.insert(intern(&"cfg"),
-                            builtin_normal_tt_no_ctxt(ext::cfg::expand_cfg));
-    syntax_expanders.insert(
-        intern(&"trace_macros"),
-        builtin_normal_tt_no_ctxt(ext::trace_macros::expand_trace_macros));
+                            builtin_normal_tt_no_ctxt(
+                                    ext::cfg::expand_cfg));
+    syntax_expanders.insert(intern(&"trace_macros"),
+                            builtin_normal_tt_no_ctxt(
+                                    ext::trace_macros::expand_trace_macros));
     MapChain::new(~syntax_expanders)
 }
 
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 889c2a5976e..ba2342d7827 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -15,6 +15,7 @@ use ast_util;
 use codemap::{Span, respan, dummy_sp};
 use ext::base::ExtCtxt;
 use ext::quote::rt::*;
+use fold;
 use opt_vec;
 use opt_vec::OptVec;
 
@@ -862,3 +863,32 @@ impl AstBuilder for @ExtCtxt {
                                 ast::view_path_glob(self.path(sp, path), ast::DUMMY_NODE_ID))])
     }
 }
+
+struct Duplicator {
+    cx: @ExtCtxt,
+}
+
+impl fold::ast_fold for Duplicator {
+    fn new_id(&self, _: NodeId) -> NodeId {
+        ast::DUMMY_NODE_ID
+    }
+}
+
+pub trait Duplicate {
+    //
+    // Duplication functions
+    //
+    // These functions just duplicate AST nodes.
+    //
+
+    fn duplicate(&self, cx: @ExtCtxt) -> Self;
+}
+
+impl Duplicate for @ast::Expr {
+    fn duplicate(&self, cx: @ExtCtxt) -> @ast::Expr {
+        let folder = @Duplicator {
+            cx: cx,
+        } as @fold::ast_fold;
+        folder.fold_expr(*self)
+    }
+}
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 82d452bc734..004a889fb4d 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -10,7 +10,7 @@
 
 use ast::{Block, Crate, DeclLocal, Expr_, ExprMac, SyntaxContext};
 use ast::{Local, Ident, mac_invoc_tt};
-use ast::{item_mac, Mrk, Stmt_, StmtDecl, StmtMac, StmtExpr, StmtSemi};
+use ast::{item_mac, Mrk, Stmt, StmtDecl, StmtMac, StmtExpr, StmtSemi};
 use ast::{token_tree};
 use ast;
 use ast_util::{mtwt_outer_mark, new_rename, new_mark};
@@ -21,6 +21,7 @@ use codemap;
 use codemap::{Span, Spanned, ExpnInfo, NameAndSpan};
 use ext::base::*;
 use fold::*;
+use opt_vec;
 use parse;
 use parse::{parse_item_from_source_str};
 use parse::token;
@@ -32,12 +33,10 @@ use std::vec;
 
 pub fn expand_expr(extsbox: @mut SyntaxEnv,
                    cx: @ExtCtxt,
-                   e: &Expr_,
-                   span: Span,
-                   fld: @ast_fold,
-                   orig: @fn(&Expr_, Span, @ast_fold) -> (Expr_, Span))
-                -> (Expr_, Span) {
-    match *e {
+                   e: @ast::Expr,
+                   fld: &MacroExpander)
+                   -> @ast::Expr {
+    match e.node {
         // expr_mac should really be expr_ext or something; it's the
         // entry-point for all syntax extensions.
         ExprMac(ref mac) => {
@@ -66,7 +65,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
                         }
                         Some(@SE(NormalTT(expandfun, exp_span))) => {
                             cx.bt_push(ExpnInfo {
-                                call_site: span,
+                                call_site: e.span,
                                 callee: NameAndSpan {
                                     name: extnamestr,
                                     span: exp_span,
@@ -84,10 +83,12 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
                             let mac_span = original_span(cx);
 
                             let expanded =
-                                match expandfun(cx, mac_span.call_site,
-                                                marked_before, marked_ctxt) {
+                                match expandfun.expand(cx,
+                                                       mac_span.call_site,
+                                                       marked_before,
+                                                       marked_ctxt) {
                                     MRExpr(e) => e,
-                                    MRAny(expr_maker,_,_) => expr_maker(),
+                                    MRAny(any_macro) => any_macro.make_expr(),
                                     _ => {
                                         cx.span_fatal(
                                             pth.span,
@@ -101,12 +102,19 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
                             // mark after:
                             let marked_after = mark_expr(expanded,fm);
 
-                            //keep going, outside-in
+                            // Keep going, outside-in.
+                            //
+                            // XXX(pcwalton): Is it necessary to clone the
+                            // node here?
                             let fully_expanded =
                                 fld.fold_expr(marked_after).node.clone();
                             cx.bt_pop();
 
-                            (fully_expanded, span)
+                            @ast::Expr {
+                                id: ast::DUMMY_NODE_ID,
+                                node: fully_expanded,
+                                span: e.span,
+                            }
                         }
                         _ => {
                             cx.span_fatal(
@@ -125,8 +133,48 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
         ast::ExprForLoop(src_pat, src_expr, ref src_loop_block, opt_ident) => {
             // Expand any interior macros etc.
             // NB: we don't fold pats yet. Curious.
-            let src_expr = fld.fold_expr(src_expr);
-            let src_loop_block = fld.fold_block(src_loop_block);
+            let src_expr = fld.fold_expr(src_expr).clone();
+            let src_loop_block = fld.fold_block(src_loop_block).clone();
+
+            let span = e.span;
+
+            pub fn mk_expr(_: @ExtCtxt, span: Span, node: Expr_)
+                           -> @ast::Expr {
+                @ast::Expr {
+                    id: ast::DUMMY_NODE_ID,
+                    node: node,
+                    span: span,
+                }
+            }
+
+            fn mk_block(_: @ExtCtxt,
+                        stmts: &[@ast::Stmt],
+                        expr: Option<@ast::Expr>,
+                        span: Span)
+                        -> ast::Block {
+                ast::Block {
+                    view_items: ~[],
+                    stmts: stmts.to_owned(),
+                    expr: expr,
+                    id: ast::DUMMY_NODE_ID,
+                    rules: ast::DefaultBlock,
+                    span: span,
+                }
+            }
+
+            fn mk_simple_path(ident: ast::Ident, span: Span) -> ast::Path {
+                ast::Path {
+                    span: span,
+                    global: false,
+                    segments: ~[
+                        ast::PathSegment {
+                            identifier: ident,
+                            lifetime: None,
+                            types: opt_vec::Empty,
+                        }
+                    ],
+                }
+            }
 
             // to:
             //
@@ -182,10 +230,14 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
                                  ~[iter_decl_stmt],
                                  Some(loop_expr));
 
-            (ast::ExprBlock(block), span)
+            @ast::Expr {
+                id: ast::DUMMY_NODE_ID,
+                node: ast::ExprBlock(block),
+                span: span,
+            }
         }
 
-        _ => orig(e, span, fld)
+        _ => noop_fold_expr(e, fld)
     }
 }
 
@@ -201,12 +253,10 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
 pub fn expand_mod_items(extsbox: @mut SyntaxEnv,
                         cx: @ExtCtxt,
                         module_: &ast::_mod,
-                        fld: @ast_fold,
-                        orig: @fn(&ast::_mod, @ast_fold) -> ast::_mod)
-                     -> ast::_mod {
-
+                        fld: &MacroExpander)
+                        -> ast::_mod {
     // Fold the contents first:
-    let module_ = orig(module_, fld);
+    let module_ = noop_fold_mod(module_, fld);
 
     // For each item, look through the attributes.  If any of them are
     // decorated with "item decorators", then use that function to transform
@@ -233,7 +283,10 @@ pub fn expand_mod_items(extsbox: @mut SyntaxEnv,
         }
     };
 
-    ast::_mod { items: new_items, ..module_ }
+    ast::_mod {
+        items: new_items,
+        ..module_
+    }
 }
 
 // eval $e with a new exts frame:
@@ -256,19 +309,20 @@ static special_block_name : &'static str = " block";
 pub fn expand_item(extsbox: @mut SyntaxEnv,
                    cx: @ExtCtxt,
                    it: @ast::item,
-                   fld: @ast_fold,
-                   orig: @fn(@ast::item, @ast_fold) -> Option<@ast::item>)
-                -> Option<@ast::item> {
+                   fld: &MacroExpander)
+                   -> Option<@ast::item> {
     match it.node {
         ast::item_mac(*) => expand_item_mac(extsbox, cx, it, fld),
         ast::item_mod(_) | ast::item_foreign_mod(_) => {
             cx.mod_push(it.ident);
             let macro_escape = contains_macro_escape(it.attrs);
-            let result = with_exts_frame!(extsbox,macro_escape,orig(it,fld));
+            let result = with_exts_frame!(extsbox,
+                                          macro_escape,
+                                          noop_fold_item(it, fld));
             cx.mod_pop();
             result
         },
-        _ => orig(it,fld)
+        _ => noop_fold_item(it, fld)
     }
 }
 
@@ -280,11 +334,15 @@ pub fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool {
 // Support for item-position macro invocations, exactly the same
 // logic as for expression-position macro invocations.
 pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
-                       cx: @ExtCtxt, it: @ast::item,
-                       fld: @ast_fold)
-                    -> Option<@ast::item> {
+                       cx: @ExtCtxt,
+                       it: @ast::item,
+                       fld: &MacroExpander)
+                       -> Option<@ast::item> {
     let (pth, tts, ctxt) = match it.node {
-        item_mac(codemap::Spanned { node: mac_invoc_tt(ref pth, ref tts, ctxt), _}) => {
+        item_mac(codemap::Spanned {
+            node: mac_invoc_tt(ref pth, ref tts, ctxt),
+            _
+        }) => {
             (pth, (*tts).clone(), ctxt)
         }
         _ => cx.span_bug(it.span, "invalid item macro invocation")
@@ -314,7 +372,7 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
             // mark before expansion:
             let marked_before = mark_tts(tts,fm);
             let marked_ctxt = new_mark(fm,ctxt);
-            expander(cx, it.span, marked_before, marked_ctxt)
+            expander.expand(cx, it.span, marked_before, marked_ctxt)
         }
         Some(@SE(IdentTT(expander, span))) => {
             if it.ident.name == parse::token::special_idents::invalid.name {
@@ -332,7 +390,7 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
             // mark before expansion:
             let marked_tts = mark_tts(tts,fm);
             let marked_ctxt = new_mark(fm,ctxt);
-            expander(cx, it.span, it.ident, marked_tts, marked_ctxt)
+            expander.expand(cx, it.span, it.ident, marked_tts, marked_ctxt)
         }
         _ => cx.span_fatal(
             it.span, fmt!("%s! is not legal in item position", extnamestr))
@@ -346,10 +404,10 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
         MRExpr(_) => {
             cx.span_fatal(pth.span, fmt!("expr macro in item position: %s", extnamestr))
         }
-        MRAny(_, item_maker, _) => {
-            item_maker()
-                .and_then(|i| mark_item(i,fm))
-                .and_then(|i| fld.fold_item(i))
+        MRAny(any_macro) => {
+            any_macro.make_item()
+                     .and_then(|i| mark_item(i,fm))
+                     .and_then(|i| fld.fold_item(i))
         }
         MRDef(ref mdef) => {
             // yikes... no idea how to apply the mark to this. I'm afraid
@@ -382,15 +440,12 @@ fn insert_macro(exts: SyntaxEnv, name: ast::Name, transformer: @Transformer) {
 // expand a stmt
 pub fn expand_stmt(extsbox: @mut SyntaxEnv,
                    cx: @ExtCtxt,
-                   s: &Stmt_,
-                   sp: Span,
-                   fld: @ast_fold,
-                   orig: @fn(&Stmt_, Span, @ast_fold)
-                             -> (Option<Stmt_>, Span))
-                -> (Option<Stmt_>, Span) {
+                   s: &Stmt,
+                   fld: &MacroExpander)
+                   -> Option<@Stmt> {
     // why the copying here and not in expand_expr?
     // looks like classic changed-in-only-one-place
-    let (pth, tts, semi, ctxt) = match *s {
+    let (pth, tts, semi, ctxt) = match s.node {
         StmtMac(ref mac, semi) => {
             match mac.node {
                 mac_invoc_tt(ref pth, ref tts, ctxt) => {
@@ -398,24 +453,26 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
                 }
             }
         }
-        _ => return expand_non_macro_stmt(*extsbox,s,sp,fld,orig)
+        _ => return expand_non_macro_stmt(*extsbox, s, fld)
     };
     if (pth.segments.len() > 1u) {
-        cx.span_fatal(
-            pth.span,
-            fmt!("expected macro name without module \
-                  separators"));
+        cx.span_fatal(pth.span,
+                      "expected macro name without module separators");
     }
     let extname = &pth.segments[0].identifier;
     let extnamestr = ident_to_str(extname);
-    let (fully_expanded, sp) = match (*extsbox).find(&extname.name) {
-        None =>
-            cx.span_fatal(pth.span, fmt!("macro undefined: '%s'", extnamestr)),
+    let fully_expanded: @ast::Stmt = match (*extsbox).find(&extname.name) {
+        None => {
+            cx.span_fatal(pth.span, fmt!("macro undefined: '%s'", extnamestr))
+        }
 
         Some(@SE(NormalTT(expandfun, exp_span))) => {
             cx.bt_push(ExpnInfo {
-                call_site: sp,
-                callee: NameAndSpan { name: extnamestr, span: exp_span }
+                call_site: s.span,
+                callee: NameAndSpan {
+                    name: extnamestr,
+                    span: exp_span,
+                }
             });
             let fm = fresh_mark();
             // mark before expansion:
@@ -426,24 +483,32 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
             // not the current mac.span.
             let mac_span = original_span(cx);
 
-            let expanded = match expandfun(cx, mac_span.call_site,
-                                           marked_tts, marked_ctxt) {
-                MRExpr(e) =>
-                    @codemap::Spanned { node: StmtExpr(e, ast::DUMMY_NODE_ID),
-                                        span: e.span},
-                MRAny(_,_,stmt_mkr) => stmt_mkr(),
+            let expanded = match expandfun.expand(cx,
+                                                  mac_span.call_site,
+                                                  marked_tts,
+                                                  marked_ctxt) {
+                MRExpr(e) => {
+                    @codemap::Spanned {
+                        node: StmtExpr(e, ast::DUMMY_NODE_ID),
+                        span: e.span,
+                    }
+                }
+                MRAny(any_macro) => any_macro.make_stmt(),
                 _ => cx.span_fatal(
                     pth.span,
                     fmt!("non-stmt macro in stmt pos: %s", extnamestr))
             };
             let marked_after = mark_stmt(expanded,fm);
 
-            //keep going, outside-in
+            // Keep going, outside-in.
             let fully_expanded = match fld.fold_stmt(marked_after) {
                 Some(stmt) => {
                     let fully_expanded = &stmt.node;
                     cx.bt_pop();
-                    (*fully_expanded).clone()
+                    @Spanned {
+                        span: stmt.span,
+                        node: (*fully_expanded).clone(),
+                    }
                 }
                 None => {
                     cx.span_fatal(pth.span,
@@ -451,7 +516,7 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
                 }
             };
 
-            (fully_expanded, sp)
+            fully_expanded
         }
 
         _ => {
@@ -460,24 +525,28 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
         }
     };
 
-    (match fully_expanded {
-        StmtExpr(e, stmt_id) if semi => Some(StmtSemi(e, stmt_id)),
-        _ => { Some(fully_expanded) } /* might already have a semi */
-    }, sp)
-
+    match fully_expanded.node {
+        StmtExpr(e, stmt_id) if semi => {
+            Some(@Spanned {
+                span: fully_expanded.span,
+                node: StmtSemi(e, stmt_id),
+            })
+        }
+        _ => Some(fully_expanded), /* might already have a semi */
+    }
 }
 
 // expand a non-macro stmt. this is essentially the fallthrough for
 // expand_stmt, above.
-fn expand_non_macro_stmt (exts: SyntaxEnv,
-                          s: &Stmt_,
-                          sp: Span,
-                          fld: @ast_fold,
-                          orig: @fn(&Stmt_, Span, @ast_fold) -> (Option<Stmt_>, Span))
-    -> (Option<Stmt_>,Span) {
+fn expand_non_macro_stmt(exts: SyntaxEnv, s: &Stmt, fld: &MacroExpander)
+                         -> Option<@Stmt> {
     // is it a let?
-    match *s {
-        StmtDecl(@Spanned{node: DeclLocal(ref local), span: stmt_span}, node_id) => {
+    match s.node {
+        StmtDecl(@Spanned {
+            node: DeclLocal(ref local),
+            span: stmt_span
+        },
+        node_id) => {
             let block_info = get_block_info(exts);
             let pending_renames = block_info.pending_renames;
 
@@ -515,19 +584,24 @@ fn expand_non_macro_stmt (exts: SyntaxEnv,
             // also, don't forget to expand the init:
             let new_init_opt = init.map(|e| fld.fold_expr(*e));
             let rewritten_local =
-                @Local{is_mutbl:is_mutbl,
-                       ty:ty,
-                       pat:rewritten_pat,
-                       init:new_init_opt,
-                       id:id,
-                       span:span};
-            (Some(StmtDecl(@Spanned{node:DeclLocal(rewritten_local),
-                                     span: stmt_span},node_id)),
-             sp)
+                @Local {
+                    is_mutbl: is_mutbl,
+                    ty: ty,
+                    pat: rewritten_pat,
+                    init: new_init_opt,
+                    id: id,
+                    span: span,
+                };
+            Some(@Spanned {
+                node: StmtDecl(@Spanned {
+                        node: DeclLocal(rewritten_local),
+                        span: stmt_span
+                    },
+                    node_id),
+                span: span
+            })
         },
-        _ => {
-            orig(s, sp, fld)
-        }
+        _ => noop_fold_stmt(s, fld),
     }
 }
 
@@ -628,18 +702,18 @@ pub fn new_path_finder(paths: @mut ~[ast::Path]) -> @mut Visitor<()> {
 
 // expand a block. pushes a new exts_frame, then calls expand_block_elts
 pub fn expand_block(extsbox: @mut SyntaxEnv,
-                    _cx: @ExtCtxt,
+                    _: @ExtCtxt,
                     blk: &Block,
-                    fld: @ast_fold,
-                    _orig: @fn(&Block, @ast_fold) -> Block)
-                 -> Block {
+                    fld: &MacroExpander)
+                    -> Block {
     // see note below about treatment of exts table
     with_exts_frame!(extsbox,false,
                      expand_block_elts(*extsbox, blk, fld))
 }
 
 // expand the elements of a block.
-pub fn expand_block_elts(exts: SyntaxEnv, b: &Block, fld: @ast_fold) -> Block {
+pub fn expand_block_elts(exts: SyntaxEnv, b: &Block, fld: &MacroExpander)
+                         -> Block {
     let block_info = get_block_info(exts);
     let pending_renames = block_info.pending_renames;
     let rename_fld = renames_to_fold(pending_renames);
@@ -680,9 +754,47 @@ fn get_block_info(exts : SyntaxEnv) -> BlockInfo {
     }
 }
 
+struct IdentRenamer {
+    renames: @mut ~[(ast::Ident,ast::Name)],
+}
+
+impl ast_fold for IdentRenamer {
+    fn fold_ident(&self, id: ast::Ident) -> ast::Ident {
+        let new_ctxt = self.renames.iter().fold(id.ctxt, |ctxt, &(from, to)| {
+            new_rename(from, to, ctxt)
+        });
+        ast::Ident {
+            name: id.name,
+            ctxt: new_ctxt,
+        }
+    }
+}
+
+// given a mutable list of renames, return a tree-folder that applies those
+// renames.
+pub fn renames_to_fold(renames: @mut ~[(ast::Ident,ast::Name)]) -> @ast_fold {
+    @IdentRenamer {
+        renames: renames,
+    } as @ast_fold
+}
+
+// perform a bunch of renames
+fn apply_pending_renames(folder : @ast_fold, stmt : ast::Stmt) -> @ast::Stmt {
+    match folder.fold_stmt(&stmt) {
+        Some(s) => s,
+        None => fail!(fmt!("renaming of stmt produced None"))
+    }
+}
+
+
+
 pub fn new_span(cx: @ExtCtxt, sp: Span) -> Span {
     /* this discards information in the case of macro-defining macros */
-    return Span {lo: sp.lo, hi: sp.hi, expn_info: cx.backtrace()};
+    Span {
+        lo: sp.lo,
+        hi: sp.hi,
+        expn_info: cx.backtrace(),
+    }
 }
 
 // FIXME (#2247): this is a moderately bad kludge to inject some macros into
@@ -1025,10 +1137,28 @@ pub fn std_macros() -> @str {
 }";
 }
 
+struct Injector {
+    sm: @ast::item,
+}
+
+impl ast_fold for Injector {
+    fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
+        // Just inject the standard macros at the start of the first module
+        // in the crate: that is, at the start of the crate file itself.
+        let items = vec::append(~[ self.sm ], module.items);
+        ast::_mod {
+            items: items,
+            ..(*module).clone() // FIXME #2543: Bad copy.
+        }
+    }
+}
+
 // add a bunch of macros as though they were placed at the head of the
 // program (ick). This should run before cfg stripping.
 pub fn inject_std_macros(parse_sess: @mut parse::ParseSess,
-                         cfg: ast::CrateConfig, c: &Crate) -> @Crate {
+                         cfg: ast::CrateConfig,
+                         c: @Crate)
+                         -> @Crate {
     let sm = match parse_item_from_source_str(@"<std-macros>",
                                               std_macros(),
                                               cfg.clone(),
@@ -1038,48 +1168,80 @@ pub fn inject_std_macros(parse_sess: @mut parse::ParseSess,
         None => fail!("expected core macros to parse correctly")
     };
 
-    let injecter = @AstFoldFns {
-        fold_mod: |modd, _| {
-            // just inject the std macros at the start of the first
-            // module in the crate (i.e the crate file itself.)
-            let items = vec::append(~[sm], modd.items);
-            ast::_mod {
-                items: items,
-                // FIXME #2543: Bad copy.
-                .. (*modd).clone()
-            }
-        },
-        .. *default_ast_fold()
-    };
-    @make_fold(injecter).fold_crate(c)
+    let injector = @Injector {
+        sm: sm,
+    } as @ast_fold;
+    @injector.fold_crate(c)
+}
+
+struct NoOpFolder {
+    contents: (),
+}
+
+impl ast_fold for NoOpFolder {}
+
+struct MacroExpander {
+    extsbox: @mut SyntaxEnv,
+    cx: @ExtCtxt,
+}
+
+impl ast_fold for MacroExpander {
+    fn fold_expr(&self, expr: @ast::Expr) -> @ast::Expr {
+        expand_expr(self.extsbox,
+                    self.cx,
+                    expr,
+                    self)
+    }
+
+    fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
+        expand_mod_items(self.extsbox,
+                         self.cx,
+                         module,
+                         self)
+    }
+
+    fn fold_item(&self, item: @ast::item) -> Option<@ast::item> {
+        expand_item(self.extsbox,
+                    self.cx,
+                    item,
+                    self)
+    }
+
+    fn fold_stmt(&self, stmt: &ast::Stmt) -> Option<@ast::Stmt> {
+        expand_stmt(self.extsbox,
+                    self.cx,
+                    stmt,
+                    self)
+    }
+
+    fn fold_block(&self, block: &ast::Block) -> ast::Block {
+        expand_block(self.extsbox,
+                     self.cx,
+                     block,
+                     self)
+    }
+
+    fn new_span(&self, span: Span) -> Span {
+        new_span(self.cx, span)
+    }
 }
 
 pub fn expand_crate(parse_sess: @mut parse::ParseSess,
-                    cfg: ast::CrateConfig, c: &Crate) -> @Crate {
+                    cfg: ast::CrateConfig,
+                    c: &Crate) -> @Crate {
     // adding *another* layer of indirection here so that the block
     // visitor can swap out one exts table for another for the duration
     // of the block.  The cleaner alternative would be to thread the
     // exts table through the fold, but that would require updating
     // every method/element of AstFoldFns in fold.rs.
-    let extsbox = @mut syntax_expander_table();
-    let afp = default_ast_fold();
+    let extsbox = syntax_expander_table();
     let cx = ExtCtxt::new(parse_sess, cfg.clone());
-    let f_pre = @AstFoldFns {
-        fold_expr: |expr,span,recur|
-            expand_expr(extsbox, cx, expr, span, recur, afp.fold_expr),
-        fold_mod: |modd,recur|
-            expand_mod_items(extsbox, cx, modd, recur, afp.fold_mod),
-        fold_item: |item,recur|
-            expand_item(extsbox, cx, item, recur, afp.fold_item),
-        fold_stmt: |stmt,span,recur|
-            expand_stmt(extsbox, cx, stmt, span, recur, afp.fold_stmt),
-        fold_block: |blk,recur|
-            expand_block(extsbox, cx, blk, recur, afp.fold_block),
-        new_span: |a| new_span(cx, a),
-        .. *afp};
-    let f = make_fold(f_pre);
-
-    let ret = @f.fold_crate(c);
+    let expander = @MacroExpander {
+        extsbox: @mut extsbox,
+        cx: cx,
+    } as @ast_fold;
+
+    let ret = @expander.fold_crate(c);
     parse_sess.span_diagnostic.handler().abort_if_errors();
     return ret;
 }
@@ -1145,53 +1307,56 @@ impl CtxtFn for Repainter {
     }
 }
 
-// given a function from ctxts to ctxts, produce
-// an ast_fold that applies that function to all ctxts:
-pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(cf: @T) -> @AstFoldFns {
-    let afp = default_ast_fold();
-    let fi : @fn(ast::Ident, @ast_fold) -> ast::Ident =
-        |ast::Ident{name, ctxt}, _| {
-        ast::Ident{name:name,ctxt:cf.f(ctxt)}
-    };
-    let fm : @fn(&ast::mac_, Span, @ast_fold) -> (ast::mac_,Span) =
-        |m, sp, fld| {
-        match *m {
-            mac_invoc_tt(ref path, ref tts, ctxt) =>
-            (mac_invoc_tt(fld.fold_path(path),
-                          fold_tts(*tts,fld),
-                          cf.f(ctxt)),
-            sp)
-        }
+pub struct ContextWrapper {
+    context_function: @CtxtFn,
+}
 
-    };
-    @AstFoldFns{
-        fold_ident : fi,
-        fold_mac : fm,
-        .. *afp
+impl ast_fold for ContextWrapper {
+    fn fold_ident(&self, id: ast::Ident) -> ast::Ident {
+        let ast::Ident {
+            name,
+            ctxt
+        } = id;
+        ast::Ident {
+            name: name,
+            ctxt: self.context_function.f(ctxt),
+        }
+    }
+    fn fold_mac(&self, m: &ast::mac) -> ast::mac {
+        let macro = match m.node {
+            mac_invoc_tt(ref path, ref tts, ctxt) => {
+                mac_invoc_tt(self.fold_path(path),
+                             fold_tts(*tts, self),
+                             self.context_function.f(ctxt))
+            }
+        };
+        Spanned {
+            node: macro,
+            span: m.span,
+        }
     }
 }
 
-
-
-// given a mutable list of renames, return a tree-folder that applies those
-// renames.
-// FIXME #4536: currently pub to allow testing
-pub fn renames_to_fold(renames : @mut ~[(ast::Ident,ast::Name)]) -> @AstFoldFns {
-    fun_to_ctxt_folder(@MultiRenamer{renames : renames})
+// given a function from ctxts to ctxts, produce
+// an ast_fold that applies that function to all ctxts:
+pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(cf: @T) -> @ContextWrapper {
+    @ContextWrapper {
+        context_function: cf as @CtxtFn,
+    }
 }
 
 // just a convenience:
-pub fn new_mark_folder(m : Mrk) -> @AstFoldFns {
+pub fn new_mark_folder(m: Mrk) -> @ContextWrapper {
     fun_to_ctxt_folder(@Marker{mark:m})
 }
 
-pub fn new_rename_folder(from : ast::Ident, to : ast::Name) -> @AstFoldFns {
+pub fn new_rename_folder(from: ast::Ident, to: ast::Name) -> @ContextWrapper {
     fun_to_ctxt_folder(@Renamer{from:from,to:to})
 }
 
 // apply a given mark to the given token trees. Used prior to expansion of a macro.
 fn mark_tts(tts : &[token_tree], m : Mrk) -> ~[token_tree] {
-    fold_tts(tts,new_mark_folder(m) as @ast_fold)
+    fold_tts(tts,new_mark_folder(m))
 }
 
 // apply a given mark to the given expr. Used following the expansion of a macro.
@@ -1359,7 +1524,7 @@ mod test {
         let ident_str = @"x";
         let tts = string_to_tts(ident_str);
         let fm = fresh_mark();
-        let marked_once = fold::fold_tts(tts,new_mark_folder(fm) as @fold::ast_fold);
+        let marked_once = fold::fold_tts(tts,new_mark_folder(fm));
         assert_eq!(marked_once.len(),1);
         let marked_once_ctxt =
             match marked_once[0] {
diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs
index 9adb02ecc98..d48fa03c0ef 100644
--- a/src/libsyntax/ext/fmt.rs
+++ b/src/libsyntax/ext/fmt.rs
@@ -38,7 +38,7 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree])
     fn parse_fmt_err_(cx: @ExtCtxt, sp: Span, msg: &str) -> ! {
         cx.span_fatal(sp, msg);
     }
-    let parse_fmt_err: @fn(&str) -> ! = |s| parse_fmt_err_(cx, fmtspan, s);
+    let parse_fmt_err: &fn(&str) -> ! = |s| parse_fmt_err_(cx, fmtspan, s);
     let pieces = parse_fmt_string(fmt, parse_fmt_err);
     MRExpr(pieces_to_expr(cx, sp, pieces, args))
 }
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 74de8eaa09e..3fd394b3652 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -12,9 +12,9 @@ use ast::{Ident, matcher_, matcher, match_tok, match_nonterminal, match_seq};
 use ast::{tt_delim};
 use ast;
 use codemap::{Span, Spanned, dummy_sp};
-use ext::base::{ExtCtxt, MacResult, MRAny, MRDef, MacroDef, NormalTT};
+use ext::base::{AnyMacro, ExtCtxt, MacResult, MRAny, MRDef, MacroDef};
+use ext::base::{NormalTT, SyntaxExpanderTTTrait};
 use ext::base;
-use ext::expand;
 use ext::tt::macro_parser::{error};
 use ext::tt::macro_parser::{named_match, matched_seq, matched_nonterminal};
 use ext::tt::macro_parser::{parse, parse_or_else, success, failure};
@@ -24,6 +24,112 @@ use parse::token::{get_ident_interner, special_idents, gensym_ident, ident_to_st
 use parse::token::{FAT_ARROW, SEMI, nt_matchers, nt_tt};
 use print;
 
+struct ParserAnyMacro {
+    parser: @Parser,
+}
+
+impl AnyMacro for ParserAnyMacro {
+    fn make_expr(&self) -> @ast::Expr {
+        self.parser.parse_expr()
+    }
+    fn make_item(&self) -> Option<@ast::item> {
+        self.parser.parse_item(~[])     // no attrs
+    }
+    fn make_stmt(&self) -> @ast::Stmt {
+        self.parser.parse_stmt(~[])     // no attrs
+    }
+}
+
+struct MacroRulesSyntaxExpanderTTFun {
+    name: Ident,
+    lhses: @~[@named_match],
+    rhses: @~[@named_match],
+}
+
+impl SyntaxExpanderTTTrait for MacroRulesSyntaxExpanderTTFun {
+    fn expand(&self,
+              cx: @ExtCtxt,
+              sp: Span,
+              arg: &[ast::token_tree],
+              _: ast::SyntaxContext)
+              -> MacResult {
+        generic_extension(cx, sp, self.name, arg, *self.lhses, *self.rhses)
+    }
+}
+
+// Given `lhses` and `rhses`, this is the new macro we create
+fn generic_extension(cx: @ExtCtxt,
+                     sp: Span,
+                     name: Ident,
+                     arg: &[ast::token_tree],
+                     lhses: &[@named_match],
+                     rhses: &[@named_match])
+                     -> MacResult {
+    if cx.trace_macros() {
+        printfln!("%s! { %s }",
+                  cx.str_of(name),
+                  print::pprust::tt_to_str(
+                      &ast::tt_delim(@mut arg.to_owned()),
+                      get_ident_interner()));
+    }
+
+    // Which arm's failure should we report? (the one furthest along)
+    let mut best_fail_spot = dummy_sp();
+    let mut best_fail_msg = ~"internal error: ran no matchers";
+
+    let s_d = cx.parse_sess().span_diagnostic;
+
+    for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers
+        match *lhs {
+          @matched_nonterminal(nt_matchers(ref mtcs)) => {
+            // `none` is because we're not interpolating
+            let arg_rdr = new_tt_reader(
+                s_d,
+                None,
+                arg.to_owned()
+            ) as @mut reader;
+            match parse(cx.parse_sess(), cx.cfg(), arg_rdr, *mtcs) {
+              success(named_matches) => {
+                let rhs = match rhses[i] {
+                    // okay, what's your transcriber?
+                    @matched_nonterminal(nt_tt(@ref tt)) => {
+                        match (*tt) {
+                            // cut off delimiters; don't parse 'em
+                            tt_delim(ref tts) => {
+                                (*tts).slice(1u,(*tts).len()-1u).to_owned()
+                            }
+                            _ => cx.span_fatal(
+                                sp, "macro rhs must be delimited")
+                        }
+                    },
+                    _ => cx.span_bug(sp, "bad thing in rhs")
+                };
+                // rhs has holes ( `$id` and `$(...)` that need filled)
+                let trncbr = new_tt_reader(s_d, Some(named_matches),
+                                           rhs);
+                let p = @Parser(cx.parse_sess(),
+                                cx.cfg(),
+                                trncbr as @mut reader);
+
+                // Let the context choose how to interpret the result.
+                // Weird, but useful for X-macros.
+                return MRAny(@ParserAnyMacro {
+                    parser: p,
+                } as @AnyMacro)
+              }
+              failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo {
+                best_fail_spot = sp;
+                best_fail_msg = (*msg).clone();
+              },
+              error(sp, ref msg) => cx.span_fatal(sp, (*msg))
+            }
+          }
+          _ => cx.bug("non-matcher found in parsed lhses")
+        }
+    }
+    cx.span_fatal(best_fail_spot, best_fail_msg);
+}
+
 // this procedure performs the expansion of the
 // macro_rules! macro. It parses the RHS and adds
 // an extension to the current context.
@@ -31,10 +137,8 @@ pub fn add_new_extension(cx: @ExtCtxt,
                          sp: Span,
                          name: Ident,
                          arg: ~[ast::token_tree],
-                         stx_ctxt: ast::SyntaxContext)
-                      -> base::MacResult {
-    let arg = expand::mtwt_cancel_outer_mark(arg,stx_ctxt);
-    // Wrap a matcher_ in a spanned to produce a matcher.
+                         _: ast::SyntaxContext)
+                         -> base::MacResult {
     // these spans won't matter, anyways
     fn ms(m: matcher_) -> matcher {
         Spanned {
@@ -82,11 +186,13 @@ pub fn add_new_extension(cx: @ExtCtxt,
     };
 
     // Given `lhses` and `rhses`, this is the new macro we create
-    fn generic_extension(cx: @ExtCtxt, sp: Span, name: Ident,
+    fn generic_extension(cx: @ExtCtxt,
+                         sp: Span,
+                         name: Ident,
                          arg: &[ast::token_tree],
-                         lhses: &[@named_match], rhses: &[@named_match])
-    -> MacResult {
-
+                         lhses: &[@named_match],
+                         rhses: &[@named_match])
+                         -> MacResult {
         if cx.trace_macros() {
             printfln!("%s! { %s }",
                       cx.str_of(name),
@@ -135,9 +241,9 @@ pub fn add_new_extension(cx: @ExtCtxt,
 
                     // Let the context choose how to interpret the result.
                     // Weird, but useful for X-macros.
-                    return MRAny(|| p.parse_expr(),
-                                  || p.parse_item(~[/* no attrs*/]),
-                                  || p.parse_stmt(~[/* no attrs*/]));
+                    return MRAny(@ParserAnyMacro {
+                        parser: p
+                    } as @AnyMacro);
                   }
                   failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo {
                     best_fail_spot = sp;
@@ -152,10 +258,13 @@ pub fn add_new_extension(cx: @ExtCtxt,
         cx.span_fatal(best_fail_spot, best_fail_msg);
     }
 
-    let exp: @fn(@ExtCtxt, Span, &[ast::token_tree], ctxt: ast::SyntaxContext) -> MacResult =
-        |cx, sp, arg, _ctxt| generic_extension(cx, sp, name, arg, *lhses, *rhses);
+    let exp = @MacroRulesSyntaxExpanderTTFun {
+        name: name,
+        lhses: lhses,
+        rhses: rhses,
+    } as @SyntaxExpanderTTTrait;
 
-    return MRDef(MacroDef{
+    return MRDef(MacroDef {
         name: ident_to_str(&name),
         ext: NormalTT(exp, Some(sp))
     });
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 5472c61a155..a25f267c458 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -14,227 +14,434 @@ use codemap::{Span, Spanned};
 use parse::token;
 use opt_vec::OptVec;
 
-// this file defines an ast_fold trait for objects that can perform
-// a "fold" on Rust ASTs. It also contains a structure that implements
-// that trait, and a "default_fold" whose fields contain closures
-// that perform "default traversals", visiting all of the sub-elements
-// and re-assembling the result. The "fun_to_ident_folder" in the
-// test module provides a simple example of creating a very simple
-// fold that only looks at identifiers.
-
+// We may eventually want to be able to fold over type parameters, too.
 pub trait ast_fold {
-    fn fold_crate(@self, &Crate) -> Crate;
-    fn fold_view_item(@self, &view_item) -> view_item;
-    fn fold_foreign_item(@self, @foreign_item) -> @foreign_item;
-    fn fold_item(@self, @item) -> Option<@item>;
-    fn fold_struct_field(@self, @struct_field) -> @struct_field;
-    fn fold_item_underscore(@self, &item_) -> item_;
-    fn fold_type_method(@self, m: &TypeMethod) -> TypeMethod;
-    fn fold_method(@self, @method) -> @method;
-    fn fold_block(@self, &Block) -> Block;
-    fn fold_stmt(@self, &Stmt) -> Option<@Stmt>;
-    fn fold_arm(@self, &Arm) -> Arm;
-    fn fold_pat(@self, @Pat) -> @Pat;
-    fn fold_decl(@self, @Decl) -> Option<@Decl>;
-    fn fold_expr(@self, @Expr) -> @Expr;
-    fn fold_ty(@self, &Ty) -> Ty;
-    fn fold_mod(@self, &_mod) -> _mod;
-    fn fold_foreign_mod(@self, &foreign_mod) -> foreign_mod;
-    fn fold_variant(@self, &variant) -> variant;
-    fn fold_ident(@self, Ident) -> Ident;
-    fn fold_path(@self, &Path) -> Path;
-    fn fold_local(@self, @Local) -> @Local;
-    fn fold_mac(@self, &mac) -> mac;
-    fn map_exprs(@self, @fn(@Expr) -> @Expr, &[@Expr]) -> ~[@Expr];
-    fn new_id(@self, NodeId) -> NodeId;
-    fn new_span(@self, Span) -> Span;
-
-    // New style, using default methods:
-
-    fn fold_variant_arg(@self, va: &variant_arg) -> variant_arg {
-        variant_arg {
-            ty: self.fold_ty(&va.ty),
-            id: self.new_id(va.id)
-        }
-    }
-
-    fn fold_spanned<T>(@self, s: &Spanned<T>, f: &fn(&T) -> T) -> Spanned<T> {
-        Spanned {
-            node: f(&s.node),
-            span: self.new_span(s.span)
-        }
+    fn fold_crate(&self, c: &Crate) -> Crate {
+        noop_fold_crate(c, self)
     }
 
-    fn fold_view_path(@self, vp: &view_path) -> view_path {
-        self.fold_spanned(vp, |v| self.fold_view_path_(v))
+    fn fold_meta_items(&self, meta_items: &[@MetaItem]) -> ~[@MetaItem] {
+        meta_items.map(|x| fold_meta_item_(*x, self))
     }
 
-    fn fold_view_paths(@self, vps: &[@view_path]) -> ~[@view_path] {
-        vps.map(|vp| @self.fold_view_path(*vp))
+    fn fold_view_paths(&self, view_paths: &[@view_path]) -> ~[@view_path] {
+        view_paths.map(|view_path| {
+            let inner_view_path = match view_path.node {
+                view_path_simple(ref ident, ref path, node_id) => {
+                    view_path_simple(ident.clone(),
+                                     self.fold_path(path),
+                                     self.new_id(node_id))
+                }
+                view_path_glob(ref path, node_id) => {
+                    view_path_glob(self.fold_path(path), self.new_id(node_id))
+                }
+                view_path_list(ref path, ref path_list_idents, node_id) => {
+                    view_path_list(self.fold_path(path),
+                                   path_list_idents.map(|path_list_ident| {
+                                    let id = self.new_id(path_list_ident.node
+                                                                        .id);
+                                    Spanned {
+                                        node: path_list_ident_ {
+                                            name: path_list_ident.node
+                                                                 .name
+                                                                 .clone(),
+                                            id: id,
+                                        },
+                                        span: self.new_span(
+                                            path_list_ident.span)
+                                   }
+                                  }),
+                                  self.new_id(node_id))
+                }
+            };
+            @Spanned {
+                node: inner_view_path,
+                span: self.new_span(view_path.span),
+            }
+        })
     }
 
-    fn fold_view_path_(@self, vp: &view_path_) -> view_path_ {
-        match *vp {
-            view_path_simple(ident, ref path, node_id) => {
-                view_path_simple(self.fold_ident(ident),
-                                 self.fold_path(path),
-                                 self.new_id(node_id))
-            }
-            view_path_glob(ref path, node_id) => {
-                view_path_glob(self.fold_path(path),
-                               self.new_id(node_id))
+    fn fold_view_item(&self, vi: &view_item) -> view_item {
+        let inner_view_item = match vi.node {
+            view_item_extern_mod(ref ident,
+                                 string,
+                                 ref meta_items,
+                                 node_id) => {
+                view_item_extern_mod(ident.clone(),
+                                     string,
+                                     self.fold_meta_items(*meta_items),
+                                     self.new_id(node_id))
             }
-            view_path_list(ref path, ref idents, node_id) => {
-                view_path_list(self.fold_path(path),
-                               self.fold_path_list_idents(*idents),
-                               self.new_id(node_id))
+            view_item_use(ref view_paths) => {
+                view_item_use(self.fold_view_paths(*view_paths))
             }
+        };
+        view_item {
+            node: inner_view_item,
+            attrs: vi.attrs.map(|a| fold_attribute_(*a, self)),
+            vis: vi.vis,
+            span: self.new_span(vi.span),
+        }
+    }
+
+    fn fold_foreign_item(&self, ni: @foreign_item) -> @foreign_item {
+        let fold_attribute = |x| fold_attribute_(x, self);
+
+        @ast::foreign_item {
+            ident: self.fold_ident(ni.ident),
+            attrs: ni.attrs.map(|x| fold_attribute(*x)),
+            node:
+                match ni.node {
+                    foreign_item_fn(ref fdec, ref generics) => {
+                        foreign_item_fn(
+                            ast::fn_decl {
+                                inputs: fdec.inputs.map(|a| fold_arg_(a,
+                                                                      self)),
+                                output: self.fold_ty(&fdec.output),
+                                cf: fdec.cf,
+                            },
+                            fold_generics(generics, self))
+                    }
+                    foreign_item_static(ref t, m) => {
+                        foreign_item_static(self.fold_ty(t), m)
+                    }
+                },
+            id: self.new_id(ni.id),
+            span: self.new_span(ni.span),
+            vis: ni.vis,
         }
     }
 
-    fn fold_path_list_idents(@self, idents: &[path_list_ident]) -> ~[path_list_ident] {
-        idents.map(|i| self.fold_path_list_ident(i))
+    fn fold_item(&self, i: @item) -> Option<@item> {
+        noop_fold_item(i, self)
     }
 
-    fn fold_path_list_ident(@self, ident: &path_list_ident) -> path_list_ident {
-        self.fold_spanned(ident, |i| self.fold_path_list_ident_(i))
-    }
+    fn fold_struct_field(&self, sf: @struct_field) -> @struct_field {
+        let fold_attribute = |x| fold_attribute_(x, self);
 
-    fn fold_path_list_ident_(@self, ident: &path_list_ident_) -> path_list_ident_ {
-        path_list_ident_ {
-            name: self.fold_ident(ident.name),
-            id: self.new_id(ident.id)
+        @Spanned {
+            node: ast::struct_field_ {
+                kind: sf.node.kind,
+                id: self.new_id(sf.node.id),
+                ty: self.fold_ty(&sf.node.ty),
+                attrs: sf.node.attrs.map(|e| fold_attribute(*e))
+            },
+            span: self.new_span(sf.span)
         }
     }
 
-    fn fold_arg(@self, a: &arg) -> arg {
-        arg {
-            is_mutbl: a.is_mutbl,
-            ty: self.fold_ty(&a.ty),
-            pat: self.fold_pat(a.pat),
-            id: self.new_id(a.id),
+    fn fold_item_underscore(&self, i: &item_) -> item_ {
+        noop_fold_item_underscore(i, self)
+    }
+
+    fn fold_type_method(&self, m: &TypeMethod) -> TypeMethod {
+        noop_fold_type_method(m, self)
+    }
+
+    fn fold_method(&self, m: @method) -> @method {
+        @ast::method {
+            ident: self.fold_ident(m.ident),
+            attrs: m.attrs.map(|a| fold_attribute_(*a, self)),
+            generics: fold_generics(&m.generics, self),
+            explicit_self: m.explicit_self,
+            purity: m.purity,
+            decl: fold_fn_decl(&m.decl, self),
+            body: self.fold_block(&m.body),
+            id: self.new_id(m.id),
+            span: self.new_span(m.span),
+            self_id: self.new_id(m.self_id),
+            vis: m.vis,
         }
     }
 
-    fn fold_trait_ref(@self, p: &trait_ref) -> trait_ref {
-        trait_ref {
-            path: self.fold_path(&p.path),
-            ref_id: self.new_id(p.ref_id),
+    fn fold_block(&self, b: &Block) -> Block {
+        noop_fold_block(b, self)
+    }
+
+    fn fold_stmt(&self, s: &Stmt) -> Option<@Stmt> {
+        noop_fold_stmt(s, self)
+    }
+
+    fn fold_arm(&self, a: &Arm) -> Arm {
+        Arm {
+            pats: a.pats.map(|x| self.fold_pat(*x)),
+            guard: a.guard.map_move(|x| self.fold_expr(x)),
+            body: self.fold_block(&a.body),
         }
     }
 
-    fn fold_ty_param_bound(@self, tpb: &TyParamBound) -> TyParamBound {
-        match *tpb {
-            TraitTyParamBound(ref ty) => {
-                TraitTyParamBound(self.fold_trait_ref(ty))
+    fn fold_pat(&self, p: @Pat) -> @Pat {
+        let node = match p.node {
+            PatWild => PatWild,
+            PatIdent(binding_mode, ref pth, ref sub) => {
+                PatIdent(binding_mode,
+                         self.fold_path(pth),
+                         sub.map_move(|x| self.fold_pat(x)))
+            }
+            PatLit(e) => PatLit(self.fold_expr(e)),
+            PatEnum(ref pth, ref pats) => {
+                PatEnum(self.fold_path(pth),
+                        pats.map(|pats| pats.map(|x| self.fold_pat(*x))))
             }
-            RegionTyParamBound => {
-                RegionTyParamBound
+            PatStruct(ref pth, ref fields, etc) => {
+                let pth_ = self.fold_path(pth);
+                let fs = do fields.map |f| {
+                    ast::FieldPat {
+                        ident: f.ident,
+                        pat: self.fold_pat(f.pat)
+                    }
+                };
+                PatStruct(pth_, fs, etc)
             }
+            PatTup(ref elts) => PatTup(elts.map(|x| self.fold_pat(*x))),
+            PatBox(inner) => PatBox(self.fold_pat(inner)),
+            PatUniq(inner) => PatUniq(self.fold_pat(inner)),
+            PatRegion(inner) => PatRegion(self.fold_pat(inner)),
+            PatRange(e1, e2) => {
+                PatRange(self.fold_expr(e1), self.fold_expr(e2))
+            },
+            PatVec(ref before, ref slice, ref after) => {
+                PatVec(before.map(|x| self.fold_pat(*x)),
+                       slice.map_move(|x| self.fold_pat(x)),
+                       after.map(|x| self.fold_pat(*x)))
+            }
+        };
+
+        @Pat {
+            id: self.new_id(p.id),
+            span: self.new_span(p.span),
+            node: node,
         }
     }
 
-    fn fold_ty_param(@self, tp: &TyParam) -> TyParam {
-        TyParam {
-            ident: self.fold_ident(tp.ident),
-            id: self.new_id(tp.id),
-            bounds: tp.bounds.map(|x| self.fold_ty_param_bound(x))
+    fn fold_decl(&self, d: @Decl) -> Option<@Decl> {
+        let node = match d.node {
+            DeclLocal(ref l) => Some(DeclLocal(self.fold_local(*l))),
+            DeclItem(it) => {
+                match self.fold_item(it) {
+                    Some(it_folded) => Some(DeclItem(it_folded)),
+                    None => None,
+                }
+            }
+        };
+
+        node.map_move(|node| {
+            @Spanned {
+                node: node,
+                span: d.span,
+            }
+        })
+    }
+
+    fn fold_expr(&self, e: @Expr) -> @Expr {
+        noop_fold_expr(e, self)
+    }
+
+    fn fold_ty(&self, t: &Ty) -> Ty {
+        let node = match t.node {
+            ty_nil | ty_bot | ty_infer => t.node.clone(),
+            ty_box(ref mt) => ty_box(fold_mt(mt, self)),
+            ty_uniq(ref mt) => ty_uniq(fold_mt(mt, self)),
+            ty_vec(ref mt) => ty_vec(fold_mt(mt, self)),
+            ty_ptr(ref mt) => ty_ptr(fold_mt(mt, self)),
+            ty_rptr(region, ref mt) => ty_rptr(region, fold_mt(mt, self)),
+            ty_closure(ref f) => {
+                ty_closure(@TyClosure {
+                    sigil: f.sigil,
+                    purity: f.purity,
+                    region: f.region,
+                    onceness: f.onceness,
+                    bounds: fold_opt_bounds(&f.bounds, self),
+                    decl: fold_fn_decl(&f.decl, self),
+                    lifetimes: f.lifetimes.map(|l| fold_lifetime(l, self)),
+                })
+            }
+            ty_bare_fn(ref f) => {
+                ty_bare_fn(@TyBareFn {
+                    lifetimes: f.lifetimes.map(|l| fold_lifetime(l, self)),
+                    purity: f.purity,
+                    abis: f.abis,
+                    decl: fold_fn_decl(&f.decl, self)
+                })
+            }
+            ty_tup(ref tys) => ty_tup(tys.map(|ty| self.fold_ty(ty))),
+            ty_path(ref path, ref bounds, id) => {
+                ty_path(self.fold_path(path),
+                        fold_opt_bounds(bounds, self),
+                        self.new_id(id))
+            }
+            ty_fixed_length_vec(ref mt, e) => {
+                ty_fixed_length_vec(fold_mt(mt, self), self.fold_expr(e))
+            }
+            ty_mac(ref mac) => ty_mac(self.fold_mac(mac)),
+            ty_typeof(expr) => ty_typeof(self.fold_expr(expr)),
+        };
+        Ty {
+            id: self.new_id(t.id),
+            span: self.new_span(t.span),
+            node: node,
         }
     }
 
-    fn fold_ty_params(@self, tps: &OptVec<TyParam>) -> OptVec<TyParam> {
-        tps.map(|tp| self.fold_ty_param(tp))
+    fn fold_mod(&self, m: &_mod) -> _mod {
+        noop_fold_mod(m, self)
     }
 
-    fn fold_lifetime(@self, l: &Lifetime) -> Lifetime {
-        Lifetime {
-            id: self.new_id(l.id),
-            span: self.new_span(l.span),
-            ident: l.ident, // Folding this ident causes hygiene errors - ndm
+    fn fold_foreign_mod(&self, nm: &foreign_mod) -> foreign_mod {
+        ast::foreign_mod {
+            sort: nm.sort,
+            abis: nm.abis,
+            view_items: nm.view_items
+                          .iter()
+                          .map(|x| self.fold_view_item(x))
+                          .collect(),
+            items: nm.items
+                     .iter()
+                     .map(|x| self.fold_foreign_item(*x))
+                     .collect(),
         }
     }
 
-    fn fold_lifetimes(@self, lts: &OptVec<Lifetime>) -> OptVec<Lifetime> {
-        lts.map(|l| self.fold_lifetime(l))
+    fn fold_variant(&self, v: &variant) -> variant {
+        let kind;
+        match v.node.kind {
+            tuple_variant_kind(ref variant_args) => {
+                kind = tuple_variant_kind(variant_args.map(|x|
+                    fold_variant_arg_(x, self)))
+            }
+            struct_variant_kind(ref struct_def) => {
+                kind = struct_variant_kind(@ast::struct_def {
+                    fields: struct_def.fields.iter()
+                        .map(|f| self.fold_struct_field(*f)).collect(),
+                    ctor_id: struct_def.ctor_id.map(|c| self.new_id(*c))
+                })
+            }
+        }
+
+        let fold_attribute = |x| fold_attribute_(x, self);
+        let attrs = v.node.attrs.map(|x| fold_attribute(*x));
+
+        let de = match v.node.disr_expr {
+          Some(e) => Some(self.fold_expr(e)),
+          None => None
+        };
+        let node = ast::variant_ {
+            name: v.node.name,
+            attrs: attrs,
+            kind: kind,
+            id: self.new_id(v.node.id),
+            disr_expr: de,
+            vis: v.node.vis,
+        };
+        Spanned {
+            node: node,
+            span: self.new_span(v.span),
+        }
     }
 
+    fn fold_ident(&self, i: Ident) -> Ident {
+        i
+    }
 
-    fn fold_meta_item(@self, mi: &MetaItem) -> @MetaItem {
-        @self.fold_spanned(mi, |n| match *n {
-                MetaWord(id) => {
-                    MetaWord(id)
-                }
-                MetaList(id, ref mis) => {
-                    MetaList(id, self.fold_meta_items(*mis))
-                }
-                MetaNameValue(id, s) => {
-                    MetaNameValue(id, s)
-                }
+    fn fold_path(&self, p: &Path) -> Path {
+        ast::Path {
+            span: self.new_span(p.span),
+            global: p.global,
+            segments: p.segments.map(|segment| ast::PathSegment {
+                identifier: self.fold_ident(segment.identifier),
+                lifetime: segment.lifetime,
+                types: segment.types.map(|typ| self.fold_ty(typ)),
             })
+        }
     }
 
-    fn fold_meta_items(@self, mis: &[@MetaItem]) -> ~[@MetaItem] {
-        mis.map(|&mi| self.fold_meta_item(mi))
+    fn fold_local(&self, l: @Local) -> @Local {
+        @Local {
+            is_mutbl: l.is_mutbl,
+            ty: self.fold_ty(&l.ty),
+            pat: self.fold_pat(l.pat),
+            init: l.init.map_move(|e| self.fold_expr(e)),
+            id: self.new_id(l.id),
+            span: self.new_span(l.span),
+        }
     }
 
-    fn fold_attribute(@self, at: &Attribute) -> Attribute {
+    fn fold_mac(&self, macro: &mac) -> mac {
         Spanned {
-            span: self.new_span(at.span),
-            node: Attribute_ {
-                style: at.node.style,
-                value: self.fold_meta_item(at.node.value),
-                is_sugared_doc: at.node.is_sugared_doc
-            }
+            node: match macro.node {
+                mac_invoc_tt(ref p, ref tts, ctxt) => {
+                    mac_invoc_tt(self.fold_path(p),
+                                 fold_tts(*tts, self),
+                                 ctxt)
+                }
+            },
+            span: self.new_span(macro.span)
         }
     }
 
-    fn fold_attributes(@self, attrs: &[Attribute]) -> ~[Attribute] {
-        attrs.map(|x| self.fold_attribute(x))
+    fn map_exprs(&self, f: &fn(@Expr) -> @Expr, es: &[@Expr]) -> ~[@Expr] {
+        es.map(|x| f(*x))
+    }
+
+    fn new_id(&self, i: NodeId) -> NodeId {
+        i
+    }
+
+    fn new_span(&self, sp: Span) -> Span {
+        sp
     }
 }
 
-// We may eventually want to be able to fold over type parameters, too
-
-pub struct AstFoldFns {
-    //unlike the others, item_ is non-trivial
-    fold_crate: @fn(&Crate, @ast_fold) -> Crate,
-    fold_view_item: @fn(&view_item_, @ast_fold) -> view_item_,
-    fold_foreign_item: @fn(@foreign_item, @ast_fold) -> @foreign_item,
-    fold_item: @fn(@item, @ast_fold) -> Option<@item>,
-    fold_struct_field: @fn(@struct_field, @ast_fold) -> @struct_field,
-    fold_item_underscore: @fn(&item_, @ast_fold) -> item_,
-    fold_type_method: @fn(&TypeMethod, @ast_fold) -> TypeMethod,
-    fold_method: @fn(@method, @ast_fold) -> @method,
-    fold_block: @fn(&Block, @ast_fold) -> Block,
-    fold_stmt: @fn(&Stmt_, Span, @ast_fold) -> (Option<Stmt_>, Span),
-    fold_arm: @fn(&Arm, @ast_fold) -> Arm,
-    fold_pat: @fn(&Pat_, Span, @ast_fold) -> (Pat_, Span),
-    fold_decl: @fn(&Decl_, Span, @ast_fold) -> (Option<Decl_>, Span),
-    fold_expr: @fn(&Expr_, Span, @ast_fold) -> (Expr_, Span),
-    fold_ty: @fn(&ty_, Span, @ast_fold) -> (ty_, Span),
-    fold_mod: @fn(&_mod, @ast_fold) -> _mod,
-    fold_foreign_mod: @fn(&foreign_mod, @ast_fold) -> foreign_mod,
-    fold_variant: @fn(&variant_, Span, @ast_fold) -> (variant_, Span),
-    fold_ident: @fn(Ident, @ast_fold) -> Ident,
-    fold_path: @fn(&Path, @ast_fold) -> Path,
-    fold_local: @fn(@Local, @ast_fold) -> @Local,
-    fold_mac: @fn(&mac_, Span, @ast_fold) -> (mac_, Span),
-    map_exprs: @fn(@fn(@Expr) -> @Expr, &[@Expr]) -> ~[@Expr],
-    new_id: @fn(NodeId) -> NodeId,
-    new_span: @fn(Span) -> Span
+/* some little folds that probably aren't useful to have in ast_fold itself*/
+
+//used in noop_fold_item and noop_fold_crate and noop_fold_crate_directive
+fn fold_meta_item_<T:ast_fold>(mi: @MetaItem, fld: &T) -> @MetaItem {
+    @Spanned {
+        node:
+            match mi.node {
+                MetaWord(id) => MetaWord(id),
+                MetaList(id, ref mis) => {
+                    let fold_meta_item = |x| fold_meta_item_(x, fld);
+                    MetaList(
+                        id,
+                        mis.map(|e| fold_meta_item(*e))
+                    )
+                }
+                MetaNameValue(id, s) => MetaNameValue(id, s)
+            },
+        span: fld.new_span(mi.span) }
 }
 
-pub type ast_fold_fns = @AstFoldFns;
+//used in noop_fold_item and noop_fold_crate
+fn fold_attribute_<T:ast_fold>(at: Attribute, fld: &T) -> Attribute {
+    Spanned {
+        span: fld.new_span(at.span),
+        node: ast::Attribute_ {
+            style: at.node.style,
+            value: fold_meta_item_(at.node.value, fld),
+            is_sugared_doc: at.node.is_sugared_doc
+        }
+    }
+}
 
-/* some little folds that probably aren't useful to have in ast_fold itself*/
+//used in noop_fold_foreign_item and noop_fold_fn_decl
+fn fold_arg_<T:ast_fold>(a: &arg, fld: &T) -> arg {
+    ast::arg {
+        is_mutbl: a.is_mutbl,
+        ty: fld.fold_ty(&a.ty),
+        pat: fld.fold_pat(a.pat),
+        id: fld.new_id(a.id),
+    }
+}
 
-pub fn fold_tts(tts : &[token_tree], fld: @ast_fold) -> ~[token_tree] {
+// build a new vector of tts by appling the ast_fold's fold_ident to
+// all of the identifiers in the token trees.
+pub fn fold_tts<T:ast_fold>(tts: &[token_tree], fld: &T) -> ~[token_tree] {
     do tts.map |tt| {
         match *tt {
             tt_tok(span, ref tok) =>
             tt_tok(span,maybe_fold_ident(tok,fld)),
-            tt_delim(ref tts) =>
-            tt_delim(@mut fold_tts(**tts, fld)),
+            tt_delim(ref tts) => tt_delim(@mut fold_tts(**tts, fld)),
             tt_seq(span, ref pattern, ref sep, is_optional) =>
             tt_seq(span,
                    @mut fold_tts(**pattern, fld),
@@ -247,33 +454,68 @@ pub fn fold_tts(tts : &[token_tree], fld: @ast_fold) -> ~[token_tree] {
 }
 
 // apply ident folder if it's an ident, otherwise leave it alone
-fn maybe_fold_ident(t : &token::Token, f: @ast_fold) -> token::Token {
+fn maybe_fold_ident<T:ast_fold>(t: &token::Token, fld: &T) -> token::Token {
     match *t {
-        token::IDENT(id,followed_by_colons) =>
-        token::IDENT(f.fold_ident(id),followed_by_colons),
+        token::IDENT(id, followed_by_colons) => {
+            token::IDENT(fld.fold_ident(id), followed_by_colons)
+        }
         _ => (*t).clone()
     }
 }
 
-pub fn fold_fn_decl(decl: &ast::fn_decl, fld: @ast_fold) -> ast::fn_decl {
+pub fn fold_fn_decl<T:ast_fold>(decl: &ast::fn_decl, fld: &T)
+                                -> ast::fn_decl {
     ast::fn_decl {
-        inputs: decl.inputs.map(|x| fld.fold_arg(x)),
+        inputs: decl.inputs.map(|x| fold_arg_(x, fld)), // bad copy
         output: fld.fold_ty(&decl.output),
         cf: decl.cf,
     }
 }
 
-pub fn fold_generics(generics: &Generics, fld: @ast_fold) -> Generics {
-    Generics {ty_params: fld.fold_ty_params(&generics.ty_params),
-              lifetimes: fld.fold_lifetimes(&generics.lifetimes)}
+fn fold_ty_param_bound<T:ast_fold>(tpb: &TyParamBound, fld: &T)
+                                   -> TyParamBound {
+    match *tpb {
+        TraitTyParamBound(ref ty) => TraitTyParamBound(fold_trait_ref(ty, fld)),
+        RegionTyParamBound => RegionTyParamBound
+    }
 }
 
-pub fn noop_fold_crate(c: &Crate, fld: @ast_fold) -> Crate {
-    Crate {
-        module: fld.fold_mod(&c.module),
-        attrs: fld.fold_attributes(c.attrs),
-        config: fld.fold_meta_items(c.config),
-        span: fld.new_span(c.span),
+pub fn fold_ty_param<T:ast_fold>(tp: &TyParam, fld: &T) -> TyParam {
+    TyParam {
+        ident: tp.ident,
+        id: fld.new_id(tp.id),
+        bounds: tp.bounds.map(|x| fold_ty_param_bound(x, fld)),
+    }
+}
+
+pub fn fold_ty_params<T:ast_fold>(tps: &OptVec<TyParam>, fld: &T)
+                                  -> OptVec<TyParam> {
+    tps.map(|tp| fold_ty_param(tp, fld))
+}
+
+pub fn fold_lifetime<T:ast_fold>(l: &Lifetime, fld: &T) -> Lifetime {
+    Lifetime {
+        id: fld.new_id(l.id),
+        span: fld.new_span(l.span),
+        ident: l.ident
+    }
+}
+
+pub fn fold_lifetimes<T:ast_fold>(lts: &OptVec<Lifetime>, fld: &T)
+                                  -> OptVec<Lifetime> {
+    lts.map(|l| fold_lifetime(l, fld))
+}
+
+pub fn fold_generics<T:ast_fold>(generics: &Generics, fld: &T) -> Generics {
+    Generics {ty_params: fold_ty_params(&generics.ty_params, fld),
+              lifetimes: fold_lifetimes(&generics.lifetimes, fld)}
+}
+
+fn fold_struct_def<T:ast_fold>(struct_def: @ast::struct_def, fld: &T)
+                               -> @ast::struct_def {
+    @ast::struct_def {
+        fields: struct_def.fields.map(|f| fold_struct_field(*f, fld)),
+        ctor_id: struct_def.ctor_id.map(|cid| fld.new_id(*cid)),
     }
 }
 
@@ -291,753 +533,333 @@ fn noop_fold_view_item(vi: &view_item_, fld: @ast_fold) -> view_item_ {
     }
 }
 
-fn noop_fold_foreign_item(ni: @foreign_item, fld: @ast_fold)
-    -> @foreign_item {
-    @ast::foreign_item {
-        ident: fld.fold_ident(ni.ident),
-        attrs: fld.fold_attributes(ni.attrs),
-        node:
-            match ni.node {
-                foreign_item_fn(ref fdec, ref generics) => {
-                    foreign_item_fn(
-                        ast::fn_decl {
-                            inputs: fdec.inputs.map(|a| fld.fold_arg(a)),
-                            output: fld.fold_ty(&fdec.output),
-                            cf: fdec.cf,
-                        },
-                        fold_generics(generics, fld))
-                }
-                foreign_item_static(ref t, m) => {
-                    foreign_item_static(fld.fold_ty(t), m)
-                }
-            },
-        id: fld.new_id(ni.id),
-        span: fld.new_span(ni.span),
-        vis: ni.vis,
+fn fold_trait_ref<T:ast_fold>(p: &trait_ref, fld: &T) -> trait_ref {
+    ast::trait_ref {
+        path: fld.fold_path(&p.path),
+        ref_id: fld.new_id(p.ref_id),
     }
 }
 
-pub fn noop_fold_item(i: @item, fld: @ast_fold) -> Option<@item> {
-    Some(@ast::item { ident: fld.fold_ident(i.ident),
-                      attrs: fld.fold_attributes(i.attrs),
-                      id: fld.new_id(i.id),
-                      node: fld.fold_item_underscore(&i.node),
-                      vis: i.vis,
-                      span: fld.new_span(i.span) })
-}
-
-fn noop_fold_struct_field(sf: @struct_field, fld: @ast_fold)
-                       -> @struct_field {
+fn fold_struct_field<T:ast_fold>(f: @struct_field, fld: &T) -> @struct_field {
     @Spanned {
         node: ast::struct_field_ {
-            kind: sf.node.kind,
-            id: fld.new_id(sf.node.id),
-            ty: fld.fold_ty(&sf.node.ty),
-            attrs: fld.fold_attributes(sf.node.attrs),
+            kind: f.node.kind,
+            id: fld.new_id(f.node.id),
+            ty: fld.fold_ty(&f.node.ty),
+            attrs: f.node.attrs.map(|a| fold_attribute_(*a, fld)),
         },
-        span: sf.span
+        span: fld.new_span(f.span),
     }
 }
 
-pub fn noop_fold_type_method(m: &TypeMethod, fld: @ast_fold) -> TypeMethod {
-    TypeMethod {
-        ident: fld.fold_ident(m.ident),
-        attrs: fld.fold_attributes(m.attrs),
-        purity: m.purity,
-        decl: fold_fn_decl(&m.decl, fld),
-        generics: fold_generics(&m.generics, fld),
-        explicit_self: m.explicit_self,
-        id: fld.new_id(m.id),
-        span: fld.new_span(m.span),
+fn fold_field_<T:ast_fold>(field: Field, folder: &T) -> Field {
+    ast::Field {
+        ident: folder.fold_ident(field.ident),
+        expr: folder.fold_expr(field.expr),
+        span: folder.new_span(field.span),
     }
 }
 
-pub fn noop_fold_item_underscore(i: &item_, fld: @ast_fold) -> item_ {
+fn fold_mt<T:ast_fold>(mt: &mt, folder: &T) -> mt {
+    mt {
+        ty: ~folder.fold_ty(mt.ty),
+        mutbl: mt.mutbl,
+    }
+}
+
+fn fold_field<T:ast_fold>(f: TypeField, folder: &T) -> TypeField {
+    ast::TypeField {
+        ident: folder.fold_ident(f.ident),
+        mt: fold_mt(&f.mt, folder),
+        span: folder.new_span(f.span),
+    }
+}
+
+fn fold_opt_bounds<T:ast_fold>(b: &Option<OptVec<TyParamBound>>, folder: &T)
+                               -> Option<OptVec<TyParamBound>> {
+    do b.map |bounds| {
+        do bounds.map |bound| {
+            fold_ty_param_bound(bound, folder)
+        }
+    }
+}
+
+fn fold_variant_arg_<T:ast_fold>(va: &variant_arg, folder: &T)
+                                 -> variant_arg {
+    ast::variant_arg {
+        ty: folder.fold_ty(&va.ty),
+        id: folder.new_id(va.id)
+    }
+}
+
+pub fn noop_fold_block<T:ast_fold>(b: &Block, folder: &T) -> Block {
+    let view_items = b.view_items.map(|x| folder.fold_view_item(x));
+    let mut stmts = ~[];
+    for stmt in b.stmts.iter() {
+        match folder.fold_stmt(*stmt) {
+            None => {}
+            Some(stmt) => stmts.push(stmt)
+        }
+    }
+    ast::Block {
+        view_items: view_items,
+        stmts: stmts,
+        expr: b.expr.map(|x| folder.fold_expr(*x)),
+        id: folder.new_id(b.id),
+        rules: b.rules,
+        span: folder.new_span(b.span),
+    }
+}
+
+pub fn noop_fold_item_underscore<T:ast_fold>(i: &item_, folder: &T) -> item_ {
     match *i {
         item_static(ref t, m, e) => {
-            item_static(fld.fold_ty(t), m, fld.fold_expr(e))
+            item_static(folder.fold_ty(t), m, folder.fold_expr(e))
         }
         item_fn(ref decl, purity, abi, ref generics, ref body) => {
             item_fn(
-                fold_fn_decl(decl, fld),
+                fold_fn_decl(decl, folder),
                 purity,
                 abi,
-                fold_generics(generics, fld),
-                fld.fold_block(body)
+                fold_generics(generics, folder),
+                folder.fold_block(body)
             )
         }
-        item_mod(ref m) => {
-            item_mod(fld.fold_mod(m))
-        }
+        item_mod(ref m) => item_mod(folder.fold_mod(m)),
         item_foreign_mod(ref nm) => {
-            item_foreign_mod(fld.fold_foreign_mod(nm))
+            item_foreign_mod(folder.fold_foreign_mod(nm))
         }
         item_ty(ref t, ref generics) => {
-            item_ty(fld.fold_ty(t), fold_generics(generics, fld))
+            item_ty(folder.fold_ty(t),
+                    fold_generics(generics, folder))
         }
         item_enum(ref enum_definition, ref generics) => {
             item_enum(
                 ast::enum_def {
                     variants: do enum_definition.variants.map |x| {
-                        fld.fold_variant(x)
+                        folder.fold_variant(x)
                     },
                 },
-                fold_generics(generics, fld))
+                fold_generics(generics, folder))
         }
         item_struct(ref struct_def, ref generics) => {
-            let struct_def = fold_struct_def(*struct_def, fld);
-            item_struct(struct_def, fold_generics(generics, fld))
+            let struct_def = fold_struct_def(*struct_def, folder);
+            item_struct(struct_def, fold_generics(generics, folder))
         }
         item_impl(ref generics, ref ifce, ref ty, ref methods) => {
-            item_impl(
-                fold_generics(generics, fld),
-                ifce.map(|p| fld.fold_trait_ref(p)),
-                fld.fold_ty(ty),
-                methods.map(|x| fld.fold_method(*x))
+            item_impl(fold_generics(generics, folder),
+                      ifce.map(|p| fold_trait_ref(p, folder)),
+                      folder.fold_ty(ty),
+                      methods.map(|x| folder.fold_method(*x))
             )
         }
         item_trait(ref generics, ref traits, ref methods) => {
             let methods = do methods.map |method| {
                 match *method {
-                    required(ref m) => required(fld.fold_type_method(m)),
-                    provided(method) => provided(fld.fold_method(method))
+                    required(ref m) => required(folder.fold_type_method(m)),
+                    provided(method) => provided(folder.fold_method(method))
                 }
             };
-            item_trait(
-                fold_generics(generics, fld),
-                traits.map(|p| fld.fold_trait_ref(p)),
-                methods
-            )
-        }
-        item_mac(ref m) => {
-            item_mac(fld.fold_mac(m))
+            item_trait(fold_generics(generics, folder),
+                       traits.map(|p| fold_trait_ref(p, folder)),
+                       methods)
         }
+        item_mac(ref m) => item_mac(folder.fold_mac(m)),
     }
 }
 
-fn fold_struct_def(struct_def: @ast::struct_def, fld: @ast_fold)
-                -> @ast::struct_def {
-    @ast::struct_def {
-        fields: struct_def.fields.map(|f| fold_struct_field(*f, fld)),
-        ctor_id: struct_def.ctor_id.map(|cid| fld.new_id(*cid)),
-    }
-}
-
-fn fold_struct_field(f: @struct_field, fld: @ast_fold) -> @struct_field {
-    @Spanned {
-        node: ast::struct_field_ {
-            kind: f.node.kind,
-            id: fld.new_id(f.node.id),
-            ty: fld.fold_ty(&f.node.ty),
-            attrs: fld.fold_attributes(f.node.attrs),
-        },
-        span: fld.new_span(f.span),
-    }
-}
-
-fn noop_fold_method(m: @method, fld: @ast_fold) -> @method {
-    @ast::method {
+pub fn noop_fold_type_method<T:ast_fold>(m: &TypeMethod, fld: &T)
+                                         -> TypeMethod {
+    TypeMethod {
         ident: fld.fold_ident(m.ident),
-        attrs: fld.fold_attributes(m.attrs),
-        generics: fold_generics(&m.generics, fld),
-        explicit_self: m.explicit_self,
+        attrs: m.attrs.map(|a| fold_attribute_(*a, fld)),
         purity: m.purity,
         decl: fold_fn_decl(&m.decl, fld),
-        body: fld.fold_block(&m.body),
+        generics: fold_generics(&m.generics, fld),
+        explicit_self: m.explicit_self,
         id: fld.new_id(m.id),
         span: fld.new_span(m.span),
-        self_id: fld.new_id(m.self_id),
-        vis: m.vis,
-    }
-}
-
-
-pub fn noop_fold_block(b: &Block, fld: @ast_fold) -> Block {
-    let view_items = b.view_items.map(|x| fld.fold_view_item(x));
-    let mut stmts = ~[];
-    for stmt in b.stmts.iter() {
-        match fld.fold_stmt(*stmt) {
-            None => {}
-            Some(stmt) => stmts.push(stmt)
-        }
-    }
-    ast::Block {
-        view_items: view_items,
-        stmts: stmts,
-        expr: b.expr.map(|x| fld.fold_expr(*x)),
-        id: fld.new_id(b.id),
-        rules: b.rules,
-        span: b.span,
     }
 }
 
-fn noop_fold_stmt(s: &Stmt_, fld: @ast_fold) -> Option<Stmt_> {
-    match *s {
-        StmtDecl(d, nid) => {
-            match fld.fold_decl(d) {
-                Some(d) => Some(StmtDecl(d, fld.new_id(nid))),
-                None => None,
-            }
-        }
-        StmtExpr(e, nid) => {
-            Some(StmtExpr(fld.fold_expr(e), fld.new_id(nid)))
-        }
-        StmtSemi(e, nid) => {
-            Some(StmtSemi(fld.fold_expr(e), fld.new_id(nid)))
-        }
-        StmtMac(ref mac, semi) => Some(StmtMac(fld.fold_mac(mac), semi))
+pub fn noop_fold_mod<T:ast_fold>(m: &_mod, folder: &T) -> _mod {
+    ast::_mod {
+        view_items: m.view_items
+                     .iter()
+                     .map(|x| folder.fold_view_item(x)).collect(),
+        items: m.items.iter().filter_map(|x| folder.fold_item(*x)).collect(),
     }
 }
 
-fn noop_fold_arm(a: &Arm, fld: @ast_fold) -> Arm {
-    Arm {
-        pats: a.pats.map(|x| fld.fold_pat(*x)),
-        guard: a.guard.map_move(|x| fld.fold_expr(x)),
-        body: fld.fold_block(&a.body),
-    }
-}
+pub fn noop_fold_crate<T:ast_fold>(c: &Crate, folder: &T) -> Crate {
+    let fold_meta_item = |x| fold_meta_item_(x, folder);
+    let fold_attribute = |x| fold_attribute_(x, folder);
 
-pub fn noop_fold_pat(p: &Pat_, fld: @ast_fold) -> Pat_ {
-    match *p {
-        PatWild => PatWild,
-        PatIdent(binding_mode, ref pth, ref sub) => {
-            PatIdent(
-                binding_mode,
-                fld.fold_path(pth),
-                sub.map_move(|x| fld.fold_pat(x))
-            )
-        }
-        PatLit(e) => PatLit(fld.fold_expr(e)),
-        PatEnum(ref pth, ref pats) => {
-            PatEnum(
-                fld.fold_path(pth),
-                pats.map(|pats| pats.map(|x| fld.fold_pat(*x)))
-            )
-        }
-        PatStruct(ref pth, ref fields, etc) => {
-            let pth_ = fld.fold_path(pth);
-            let fs = do fields.map |f| {
-                ast::FieldPat {
-                    ident: f.ident,
-                    pat: fld.fold_pat(f.pat)
-                }
-            };
-            PatStruct(pth_, fs, etc)
-        }
-        PatTup(ref elts) => PatTup(elts.map(|x| fld.fold_pat(*x))),
-        PatBox(inner) => PatBox(fld.fold_pat(inner)),
-        PatUniq(inner) => PatUniq(fld.fold_pat(inner)),
-        PatRegion(inner) => PatRegion(fld.fold_pat(inner)),
-        PatRange(e1, e2) => {
-            PatRange(fld.fold_expr(e1), fld.fold_expr(e2))
-        },
-        PatVec(ref before, ref slice, ref after) => {
-            PatVec(
-                before.map(|x| fld.fold_pat(*x)),
-                slice.map_move(|x| fld.fold_pat(x)),
-                after.map(|x| fld.fold_pat(*x))
-            )
-        }
+    Crate {
+        module: folder.fold_mod(&c.module),
+        attrs: c.attrs.map(|x| fold_attribute(*x)),
+        config: c.config.map(|x| fold_meta_item(*x)),
+        span: folder.new_span(c.span),
     }
 }
 
-fn noop_fold_decl(d: &Decl_, fld: @ast_fold) -> Option<Decl_> {
-    match *d {
-        DeclLocal(ref l) => Some(DeclLocal(fld.fold_local(*l))),
-        DeclItem(it) => {
-            match fld.fold_item(it) {
-                Some(it_folded) => Some(DeclItem(it_folded)),
-                None => None,
-            }
-        }
-    }
-}
+pub fn noop_fold_item<T:ast_fold>(i: @ast::item, folder: &T)
+                                  -> Option<@ast::item> {
+    let fold_attribute = |x| fold_attribute_(x, folder);
 
-// lift a function in ast-thingy X fold -> ast-thingy to a function
-// in (ast-thingy X span X fold) -> (ast-thingy X span). Basically,
-// carries the span around.
-// It seems strange to me that the call to new_fold doesn't happen
-// here but instead in the impl down below.... probably just an
-// accident?
-pub fn wrap<T>(f: @fn(&T, @ast_fold) -> T)
-            -> @fn(&T, Span, @ast_fold) -> (T, Span) {
-    let result: @fn(&T, Span, @ast_fold) -> (T, Span) = |x, s, fld| {
-        (f(x, fld), s)
-    };
-    result
+    Some(@ast::item {
+        ident: folder.fold_ident(i.ident),
+        attrs: i.attrs.map(|e| fold_attribute(*e)),
+        id: folder.new_id(i.id),
+        node: folder.fold_item_underscore(&i.node),
+        vis: i.vis,
+        span: folder.new_span(i.span)
+    })
 }
 
-pub fn noop_fold_expr(e: &Expr_, fld: @ast_fold) -> Expr_ {
-    fn fold_field_(field: Field, fld: @ast_fold) -> Field {
-        ast::Field {
-            ident: fld.fold_ident(field.ident),
-            expr: fld.fold_expr(field.expr),
-            span: fld.new_span(field.span),
-        }
-    }
-    let fold_field = |x| fold_field_(x, fld);
+pub fn noop_fold_expr<T:ast_fold>(e: @ast::Expr, folder: &T) -> @ast::Expr {
+    let fold_field = |x| fold_field_(x, folder);
 
-    match *e {
+    let node = match e.node {
         ExprVstore(e, v) => {
-            ExprVstore(fld.fold_expr(e), v)
+            ExprVstore(folder.fold_expr(e), v)
         }
         ExprVec(ref exprs, mutt) => {
-            ExprVec(fld.map_exprs(|x| fld.fold_expr(x), *exprs), mutt)
+            ExprVec(folder.map_exprs(|x| folder.fold_expr(x), *exprs), mutt)
         }
         ExprRepeat(expr, count, mutt) => {
-            ExprRepeat(fld.fold_expr(expr), fld.fold_expr(count), mutt)
+            ExprRepeat(folder.fold_expr(expr), folder.fold_expr(count), mutt)
         }
-        ExprTup(ref elts) => ExprTup(elts.map(|x| fld.fold_expr(*x))),
+        ExprTup(ref elts) => ExprTup(elts.map(|x| folder.fold_expr(*x))),
         ExprCall(f, ref args, blk) => {
-            ExprCall(
-                fld.fold_expr(f),
-                fld.map_exprs(|x| fld.fold_expr(x), *args),
-                blk
-            )
+            ExprCall(folder.fold_expr(f),
+                     folder.map_exprs(|x| folder.fold_expr(x), *args),
+                     blk)
         }
         ExprMethodCall(callee_id, f, i, ref tps, ref args, blk) => {
             ExprMethodCall(
-                fld.new_id(callee_id),
-                fld.fold_expr(f),
-                fld.fold_ident(i),
-                tps.map(|x| fld.fold_ty(x)),
-                fld.map_exprs(|x| fld.fold_expr(x), *args),
+                folder.new_id(callee_id),
+                folder.fold_expr(f),
+                folder.fold_ident(i),
+                tps.map(|x| folder.fold_ty(x)),
+                folder.map_exprs(|x| folder.fold_expr(x), *args),
                 blk
             )
         }
         ExprBinary(callee_id, binop, lhs, rhs) => {
-            ExprBinary(
-                fld.new_id(callee_id),
-                binop,
-                fld.fold_expr(lhs),
-                fld.fold_expr(rhs)
-            )
+            ExprBinary(folder.new_id(callee_id),
+                       binop,
+                       folder.fold_expr(lhs),
+                       folder.fold_expr(rhs))
         }
         ExprUnary(callee_id, binop, ohs) => {
-            ExprUnary(
-                fld.new_id(callee_id),
-                binop,
-                fld.fold_expr(ohs)
-            )
+            ExprUnary(folder.new_id(callee_id), binop, folder.fold_expr(ohs))
         }
-        ExprDoBody(f) => ExprDoBody(fld.fold_expr(f)),
-        ExprLit(_) => (*e).clone(),
+        ExprDoBody(f) => ExprDoBody(folder.fold_expr(f)),
+        ExprLit(_) => e.node.clone(),
         ExprCast(expr, ref ty) => {
-            ExprCast(fld.fold_expr(expr), fld.fold_ty(ty))
+            ExprCast(folder.fold_expr(expr), folder.fold_ty(ty))
         }
-        ExprAddrOf(m, ohs) => ExprAddrOf(m, fld.fold_expr(ohs)),
+        ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)),
         ExprIf(cond, ref tr, fl) => {
-            ExprIf(
-                fld.fold_expr(cond),
-                fld.fold_block(tr),
-                fl.map_move(|x| fld.fold_expr(x))
-            )
+            ExprIf(folder.fold_expr(cond),
+                   folder.fold_block(tr),
+                   fl.map_move(|x| folder.fold_expr(x)))
         }
         ExprWhile(cond, ref body) => {
-            ExprWhile(fld.fold_expr(cond), fld.fold_block(body))
+            ExprWhile(folder.fold_expr(cond), folder.fold_block(body))
         }
-        ExprForLoop(pat, iter, ref body, opt_ident) => {
-            ExprForLoop(fld.fold_pat(pat),
-                        fld.fold_expr(iter),
-                        fld.fold_block(body),
-                        opt_ident.map_move(|x| fld.fold_ident(x)))
+        ExprForLoop(pat, iter, ref body, ref maybe_ident) => {
+            ExprForLoop(folder.fold_pat(pat),
+                        folder.fold_expr(iter),
+                        folder.fold_block(body),
+                        maybe_ident.map_move(|i| folder.fold_ident(i)))
         }
         ExprLoop(ref body, opt_ident) => {
-            ExprLoop(
-                fld.fold_block(body),
-                opt_ident.map_move(|x| fld.fold_ident(x))
-            )
+            ExprLoop(folder.fold_block(body),
+                     opt_ident.map_move(|x| folder.fold_ident(x)))
         }
         ExprMatch(expr, ref arms) => {
-            ExprMatch(
-                fld.fold_expr(expr),
-                arms.map(|x| fld.fold_arm(x))
-            )
+            ExprMatch(folder.fold_expr(expr),
+                      arms.map(|x| folder.fold_arm(x)))
         }
         ExprFnBlock(ref decl, ref body) => {
             ExprFnBlock(
-                fold_fn_decl(decl, fld),
-                fld.fold_block(body)
+                fold_fn_decl(decl, folder),
+                folder.fold_block(body)
             )
         }
-        ExprBlock(ref blk) => ExprBlock(fld.fold_block(blk)),
+        ExprBlock(ref blk) => ExprBlock(folder.fold_block(blk)),
         ExprAssign(el, er) => {
-            ExprAssign(fld.fold_expr(el), fld.fold_expr(er))
+            ExprAssign(folder.fold_expr(el), folder.fold_expr(er))
         }
         ExprAssignOp(callee_id, op, el, er) => {
-            ExprAssignOp(
-                fld.new_id(callee_id),
-                op,
-                fld.fold_expr(el),
-                fld.fold_expr(er)
-            )
+            ExprAssignOp(folder.new_id(callee_id),
+                         op,
+                         folder.fold_expr(el),
+                         folder.fold_expr(er))
         }
         ExprField(el, id, ref tys) => {
-            ExprField(
-                fld.fold_expr(el), fld.fold_ident(id),
-                tys.map(|x| fld.fold_ty(x))
-            )
+            ExprField(folder.fold_expr(el), folder.fold_ident(id),
+                      tys.map(|x| folder.fold_ty(x)))
         }
         ExprIndex(callee_id, el, er) => {
-            ExprIndex(
-                fld.new_id(callee_id),
-                fld.fold_expr(el),
-                fld.fold_expr(er)
-            )
+            ExprIndex(folder.new_id(callee_id),
+                      folder.fold_expr(el),
+                      folder.fold_expr(er))
         }
-        ExprPath(ref pth) => ExprPath(fld.fold_path(pth)),
+        ExprPath(ref pth) => ExprPath(folder.fold_path(pth)),
         ExprSelf => ExprSelf,
-        ExprBreak(ref opt_ident) => {
-            // FIXME #6993: add fold_name to fold.... then cut out the
-            // bogus Name->Ident->Name conversion.
-            ExprBreak(opt_ident.map_move(|x| {
-                // FIXME #9129: Assigning the new ident to a temporary to work around codegen bug
-                let newx = Ident::new(x);
-                fld.fold_ident(newx).name
-            }))
-        }
-        ExprAgain(ref opt_ident) => {
-            // FIXME #6993: add fold_name to fold....
-            ExprAgain(opt_ident.map_move(|x| {
-                // FIXME #9129: Assigning the new ident to a temporary to work around codegen bug
-                let newx = Ident::new(x);
-                fld.fold_ident(newx).name
-            }))
-        }
+        ExprLogLevel => ExprLogLevel,
+        ExprBreak(opt_ident) => ExprBreak(opt_ident),
+        ExprAgain(opt_ident) => ExprAgain(opt_ident),
         ExprRet(ref e) => {
-            ExprRet(e.map_move(|x| fld.fold_expr(x)))
+            ExprRet(e.map_move(|x| folder.fold_expr(x)))
         }
-        ExprLogLevel => ExprLogLevel,
         ExprInlineAsm(ref a) => {
             ExprInlineAsm(inline_asm {
-                inputs: a.inputs.map(|&(c, input)| (c, fld.fold_expr(input))),
-                outputs: a.outputs.map(|&(c, out)| (c, fld.fold_expr(out))),
+                inputs: a.inputs.map(|&(c, input)| (c, folder.fold_expr(input))),
+                outputs: a.outputs.map(|&(c, out)| (c, folder.fold_expr(out))),
                 .. (*a).clone()
             })
         }
-        ExprMac(ref mac) => ExprMac(fld.fold_mac(mac)),
+        ExprMac(ref mac) => ExprMac(folder.fold_mac(mac)),
         ExprStruct(ref path, ref fields, maybe_expr) => {
-            ExprStruct(
-                fld.fold_path(path),
-                fields.map(|x| fold_field(*x)),
-                maybe_expr.map_move(|x| fld.fold_expr(x))
-            )
+            ExprStruct(folder.fold_path(path),
+                       fields.map(|x| fold_field(*x)),
+                       maybe_expr.map_move(|x| folder.fold_expr(x)))
         },
-        ExprParen(ex) => ExprParen(fld.fold_expr(ex))
-    }
-}
-
-pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
-    fn fold_mt(mt: &mt, fld: @ast_fold) -> mt {
-        mt {
-            ty: ~fld.fold_ty(mt.ty),
-            mutbl: mt.mutbl,
-        }
-    }
-    fn fold_field(f: TypeField, fld: @ast_fold) -> TypeField {
-        ast::TypeField {
-            ident: fld.fold_ident(f.ident),
-            mt: fold_mt(&f.mt, fld),
-            span: fld.new_span(f.span),
-        }
-    }
-    fn fold_opt_bounds(b: &Option<OptVec<TyParamBound>>, fld: @ast_fold)
-                        -> Option<OptVec<TyParamBound>> {
-        do b.map |bounds| {
-            do bounds.map |bound| { fld.fold_ty_param_bound(bound) }
-        }
-    }
-    match *t {
-        ty_nil | ty_bot | ty_infer => (*t).clone(),
-        ty_box(ref mt) => ty_box(fold_mt(mt, fld)),
-        ty_uniq(ref mt) => ty_uniq(fold_mt(mt, fld)),
-        ty_vec(ref mt) => ty_vec(fold_mt(mt, fld)),
-        ty_ptr(ref mt) => ty_ptr(fold_mt(mt, fld)),
-        ty_rptr(region, ref mt) => ty_rptr(region, fold_mt(mt, fld)),
-        ty_closure(ref f) => {
-            ty_closure(@TyClosure {
-                sigil: f.sigil,
-                purity: f.purity,
-                region: f.region,
-                onceness: f.onceness,
-                bounds: fold_opt_bounds(&f.bounds, fld),
-                decl: fold_fn_decl(&f.decl, fld),
-                lifetimes: fld.fold_lifetimes(&f.lifetimes)
-            })
-        }
-        ty_bare_fn(ref f) => {
-            ty_bare_fn(@TyBareFn {
-                lifetimes: fld.fold_lifetimes(&f.lifetimes),
-                purity: f.purity,
-                abis: f.abis,
-                decl: fold_fn_decl(&f.decl, fld)
-            })
-        }
-        ty_tup(ref tys) => ty_tup(tys.map(|ty| fld.fold_ty(ty))),
-        ty_path(ref path, ref bounds, id) =>
-            ty_path(fld.fold_path(path), fold_opt_bounds(bounds, fld), fld.new_id(id)),
-        ty_fixed_length_vec(ref mt, e) => {
-            ty_fixed_length_vec(
-                fold_mt(mt, fld),
-                fld.fold_expr(e)
-            )
-        }
-        ty_typeof(e) => ty_typeof(fld.fold_expr(e)),
-        ty_mac(ref mac) => ty_mac(fld.fold_mac(mac))
-    }
-}
-
-// ...nor do modules
-pub fn noop_fold_mod(m: &_mod, fld: @ast_fold) -> _mod {
-    ast::_mod {
-        view_items: m.view_items.iter().map(|x| fld.fold_view_item(x)).collect(),
-        items: m.items.iter().filter_map(|x| fld.fold_item(*x)).collect(),
-    }
-}
-
-fn noop_fold_foreign_mod(nm: &foreign_mod, fld: @ast_fold) -> foreign_mod {
-    ast::foreign_mod {
-        sort: nm.sort,
-        abis: nm.abis,
-        view_items: nm.view_items.iter().map(|x| fld.fold_view_item(x)).collect(),
-        items: nm.items.iter().map(|x| fld.fold_foreign_item(*x)).collect(),
-    }
-}
-
-fn noop_fold_variant(v: &variant_, fld: @ast_fold) -> variant_ {
-    let kind = match v.kind {
-        tuple_variant_kind(ref variant_args) => {
-            tuple_variant_kind(variant_args.map(|x| fld.fold_variant_arg(x)))
-        }
-        struct_variant_kind(ref struct_def) => {
-            struct_variant_kind(@ast::struct_def {
-                fields: struct_def.fields.iter()
-                    .map(|f| fld.fold_struct_field(*f)).collect(),
-                ctor_id: struct_def.ctor_id.map(|c| fld.new_id(*c))
-            })
-        }
-    };
-
-    let attrs = fld.fold_attributes(v.attrs);
-
-    let de = match v.disr_expr {
-      Some(e) => Some(fld.fold_expr(e)),
-      None => None
+        ExprParen(ex) => ExprParen(folder.fold_expr(ex))
     };
-    ast::variant_ {
-        name: v.name,
-        attrs: attrs,
-        kind: kind,
-        id: fld.new_id(v.id),
-        disr_expr: de,
-        vis: v.vis,
-    }
-}
-
-fn noop_fold_ident(i: Ident, _fld: @ast_fold) -> Ident {
-    i
-}
 
-fn noop_fold_path(p: &Path, fld: @ast_fold) -> Path {
-    ast::Path {
-        span: fld.new_span(p.span),
-        global: p.global,
-        segments: p.segments.map(|segment| ast::PathSegment {
-            identifier: fld.fold_ident(segment.identifier),
-            lifetime: segment.lifetime,
-            types: segment.types.map(|typ| fld.fold_ty(typ)),
-        })
+    @Expr {
+        id: folder.new_id(e.id),
+        node: node,
+        span: folder.new_span(e.span),
     }
 }
 
-fn noop_fold_local(l: @Local, fld: @ast_fold) -> @Local {
-    @Local {
-        is_mutbl: l.is_mutbl,
-        ty: fld.fold_ty(&l.ty),
-        pat: fld.fold_pat(l.pat),
-        init: l.init.map_move(|e| fld.fold_expr(e)),
-        id: fld.new_id(l.id),
-        span: fld.new_span(l.span),
-    }
-}
-
-// the default macro traversal. visit the path
-// using fold_path, and the tts using fold_tts,
-// and the span using new_span
-fn noop_fold_mac(m: &mac_, fld: @ast_fold) -> mac_ {
-    match *m {
-        mac_invoc_tt(ref p,ref tts,ctxt) =>
-        mac_invoc_tt(fld.fold_path(p),
-                     fold_tts(*tts,fld),
-                     ctxt)
-    }
-}
-
-
-/* temporarily eta-expand because of a compiler bug with using `fn<T>` as a
-   value */
-fn noop_map_exprs(f: @fn(@Expr) -> @Expr, es: &[@Expr]) -> ~[@Expr] {
-    es.map(|x| f(*x))
-}
-
-fn noop_id(i: NodeId) -> NodeId { return i; }
-
-fn noop_span(sp: Span) -> Span { return sp; }
-
-pub fn default_ast_fold() -> ast_fold_fns {
-    @AstFoldFns {
-        fold_crate: noop_fold_crate,
-        fold_view_item: noop_fold_view_item,
-        fold_foreign_item: noop_fold_foreign_item,
-        fold_item: noop_fold_item,
-        fold_struct_field: noop_fold_struct_field,
-        fold_item_underscore: noop_fold_item_underscore,
-        fold_type_method: noop_fold_type_method,
-        fold_method: noop_fold_method,
-        fold_block: noop_fold_block,
-        fold_stmt: |x, s, fld| (noop_fold_stmt(x, fld), s),
-        fold_arm: noop_fold_arm,
-        fold_pat: wrap(noop_fold_pat),
-        fold_decl: |x, s, fld| (noop_fold_decl(x, fld), s),
-        fold_expr: wrap(noop_fold_expr),
-        fold_ty: wrap(noop_fold_ty),
-        fold_mod: noop_fold_mod,
-        fold_foreign_mod: noop_fold_foreign_mod,
-        fold_variant: wrap(noop_fold_variant),
-        fold_ident: noop_fold_ident,
-        fold_path: noop_fold_path,
-        fold_local: noop_fold_local,
-        fold_mac: wrap(noop_fold_mac),
-        map_exprs: noop_map_exprs,
-        new_id: noop_id,
-        new_span: noop_span,
-    }
-}
-
-impl ast_fold for AstFoldFns {
-    /* naturally, a macro to write these would be nice */
-    fn fold_crate(@self, c: &Crate) -> Crate {
-        (self.fold_crate)(c, self as @ast_fold)
-    }
-    fn fold_view_item(@self, x: &view_item) -> view_item {
-        ast::view_item {
-            node: (self.fold_view_item)(&x.node, self as @ast_fold),
-            attrs: self.fold_attributes(x.attrs),
-            vis: x.vis,
-            span: (self.new_span)(x.span),
-        }
-    }
-    fn fold_foreign_item(@self, x: @foreign_item) -> @foreign_item {
-        (self.fold_foreign_item)(x, self as @ast_fold)
-    }
-    fn fold_item(@self, i: @item) -> Option<@item> {
-        (self.fold_item)(i, self as @ast_fold)
-    }
-    fn fold_struct_field(@self, sf: @struct_field) -> @struct_field {
-        @Spanned {
-            node: ast::struct_field_ {
-                kind: sf.node.kind,
-                id: (self.new_id)(sf.node.id),
-                ty: self.fold_ty(&sf.node.ty),
-                attrs: self.fold_attributes(sf.node.attrs),
-            },
-            span: (self.new_span)(sf.span),
-        }
-    }
-    fn fold_item_underscore(@self, i: &item_) -> item_ {
-        (self.fold_item_underscore)(i, self as @ast_fold)
-    }
-    fn fold_type_method(@self, m: &TypeMethod) -> TypeMethod {
-        (self.fold_type_method)(m, self as @ast_fold)
-    }
-    fn fold_method(@self, x: @method) -> @method {
-        (self.fold_method)(x, self as @ast_fold)
-    }
-    fn fold_block(@self, x: &Block) -> Block {
-        (self.fold_block)(x, self as @ast_fold)
-    }
-    fn fold_stmt(@self, x: &Stmt) -> Option<@Stmt> {
-        let (n_opt, s) = (self.fold_stmt)(&x.node, x.span, self as @ast_fold);
-        match n_opt {
-            Some(n) => Some(@Spanned { node: n, span: (self.new_span)(s) }),
-            None => None,
-        }
-    }
-    fn fold_arm(@self, x: &Arm) -> Arm {
-        (self.fold_arm)(x, self as @ast_fold)
-    }
-    fn fold_pat(@self, x: @Pat) -> @Pat {
-        let (n, s) =  (self.fold_pat)(&x.node, x.span, self as @ast_fold);
-        @Pat {
-            id: (self.new_id)(x.id),
-            node: n,
-            span: (self.new_span)(s),
-        }
-    }
-    fn fold_decl(@self, x: @Decl) -> Option<@Decl> {
-        let (n_opt, s) = (self.fold_decl)(&x.node, x.span, self as @ast_fold);
-        match n_opt {
-            Some(n) => Some(@Spanned { node: n, span: (self.new_span)(s) }),
-            None => None,
+pub fn noop_fold_stmt<T:ast_fold>(s: &Stmt, folder: &T) -> Option<@Stmt> {
+    let node = match s.node {
+        StmtDecl(d, nid) => {
+            match folder.fold_decl(d) {
+                Some(d) => Some(StmtDecl(d, folder.new_id(nid))),
+                None => None,
+            }
         }
-    }
-    fn fold_expr(@self, x: @Expr) -> @Expr {
-        let (n, s) = (self.fold_expr)(&x.node, x.span, self as @ast_fold);
-        @Expr {
-            id: (self.new_id)(x.id),
-            node: n,
-            span: (self.new_span)(s),
+        StmtExpr(e, nid) => {
+            Some(StmtExpr(folder.fold_expr(e), folder.new_id(nid)))
         }
-    }
-    fn fold_ty(@self, x: &Ty) -> Ty {
-        let (n, s) = (self.fold_ty)(&x.node, x.span, self as @ast_fold);
-        Ty {
-            id: (self.new_id)(x.id),
-            node: n,
-            span: (self.new_span)(s),
+        StmtSemi(e, nid) => {
+            Some(StmtSemi(folder.fold_expr(e), folder.new_id(nid)))
         }
-    }
-    fn fold_mod(@self, x: &_mod) -> _mod {
-        (self.fold_mod)(x, self as @ast_fold)
-    }
-    fn fold_foreign_mod(@self, x: &foreign_mod) -> foreign_mod {
-        (self.fold_foreign_mod)(x, self as @ast_fold)
-    }
-    fn fold_variant(@self, x: &variant) -> variant {
-        let (n, s) = (self.fold_variant)(&x.node, x.span, self as @ast_fold);
-        Spanned { node: n, span: (self.new_span)(s) }
-    }
-    fn fold_ident(@self, x: Ident) -> Ident {
-        (self.fold_ident)(x, self as @ast_fold)
-    }
-    fn fold_path(@self, x: &Path) -> Path {
-        (self.fold_path)(x, self as @ast_fold)
-    }
-    fn fold_local(@self, x: @Local) -> @Local {
-        (self.fold_local)(x, self as @ast_fold)
-    }
-    fn fold_mac(@self, x: &mac) -> mac {
-        let (n, s) = (self.fold_mac)(&x.node, x.span, self as @ast_fold);
-        Spanned { node: n, span: (self.new_span)(s) }
-    }
-    fn map_exprs(@self,
-                 f: @fn(@Expr) -> @Expr,
-                 e: &[@Expr])
-              -> ~[@Expr] {
-        (self.map_exprs)(f, e)
-    }
-    fn new_id(@self, node_id: ast::NodeId) -> NodeId {
-        (self.new_id)(node_id)
-    }
-    fn new_span(@self, span: Span) -> Span {
-        (self.new_span)(span)
-    }
-}
+        StmtMac(ref mac, semi) => Some(StmtMac(folder.fold_mac(mac), semi))
+    };
 
-// brson agrees with me that this function's existence is probably
-// not a good or useful thing.
-pub fn make_fold(afp: ast_fold_fns) -> @ast_fold {
-    afp as @ast_fold
+    node.map_move(|node| @Spanned {
+        node: node,
+        span: folder.new_span(s.span),
+    })
 }
 
 #[cfg(test)]
@@ -1048,27 +870,18 @@ mod test {
     use print::pprust;
     use super::*;
 
-    // taken from expand
-    // given a function from idents to idents, produce
-    // an ast_fold that applies that function:
-    pub fn fun_to_ident_folder(f: @fn(ast::Ident)->ast::Ident) -> @ast_fold{
-        let afp = default_ast_fold();
-        let f_pre = @AstFoldFns{
-            fold_ident : |id, _| f(id),
-            .. *afp
-        };
-        make_fold(f_pre)
-    }
-
     // this version doesn't care about getting comments or docstrings in.
     fn fake_print_crate(s: @pprust::ps, crate: &ast::Crate) {
         pprust::print_mod(s, &crate.module, crate.attrs);
     }
 
     // change every identifier to "zz"
-    pub fn to_zz() -> @fn(ast::Ident)->ast::Ident {
-        let zz_id = token::str_to_ident("zz");
-        |_id| {zz_id}
+    struct ToZzIdentFolder;
+
+    impl ast_fold for ToZzIdentFolder {
+        fn fold_ident(&self, _: ast::Ident) -> ast::Ident {
+            token::str_to_ident("zz")
+        }
     }
 
     // maybe add to expand.rs...
@@ -1088,7 +901,7 @@ mod test {
 
     // make sure idents get transformed everywhere
     #[test] fn ident_transformation () {
-        let zz_fold = fun_to_ident_folder(to_zz());
+        let zz_fold = ToZzIdentFolder;
         let ast = string_to_crate(@"#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}");
         assert_pred!(matches_codepattern,
                      "matches_codepattern",
@@ -1099,7 +912,7 @@ mod test {
 
     // even inside macro defs....
     #[test] fn ident_transformation_in_defs () {
-        let zz_fold = fun_to_ident_folder(to_zz());
+        let zz_fold = ToZzIdentFolder;
         let ast = string_to_crate(@"macro_rules! a {(b $c:expr $(d $e:token)f+
 => (g $(d $d $e)+))} ");
         assert_pred!(matches_codepattern,
@@ -1108,15 +921,5 @@ mod test {
                                     token::get_ident_interner()),
                      ~"zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)))");
     }
-
-    // and in cast expressions... this appears to be an existing bug.
-    #[test] fn ident_transformation_in_types () {
-        let zz_fold = fun_to_ident_folder(to_zz());
-        let ast = string_to_crate(@"fn a() {let z = 13 as int;}");
-        assert_pred!(matches_codepattern,
-                     "matches_codepattern",
-                     pprust::to_str(&zz_fold.fold_crate(ast),fake_print_crate,
-                                    token::get_ident_interner()),
-                     ~"fn zz(){let zz=13 as zz;}");
-    }
 }
+
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 9645dab4e8b..91ef55c78f6 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -45,7 +45,7 @@ pub struct ParseSess {
     included_mod_stack: ~[Path],
 }
 
-pub fn new_parse_sess(demitter: Option<Emitter>) -> @mut ParseSess {
+pub fn new_parse_sess(demitter: Option<@Emitter>) -> @mut ParseSess {
     let cm = @CodeMap::new();
     @mut ParseSess {
         cm: cm,
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index b5868cbc63d..867e4fe416b 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -37,16 +37,26 @@ pub enum ann_node<'self> {
     node_expr(@ps, &'self ast::Expr),
     node_pat(@ps, &'self ast::Pat),
 }
-pub struct pp_ann {
-    pre: @fn(ann_node),
-    post: @fn(ann_node)
+
+pub trait pp_ann {
+    fn pre(&self, _node: ann_node) {}
+    fn post(&self, _node: ann_node) {}
+}
+
+pub struct no_ann {
+    contents: (),
 }
 
-pub fn no_ann() -> pp_ann {
-    fn ignore(_node: ann_node) { }
-    return pp_ann {pre: ignore, post: ignore};
+impl no_ann {
+    pub fn new() -> no_ann {
+        no_ann {
+            contents: (),
+        }
+    }
 }
 
+impl pp_ann for no_ann {}
+
 pub struct CurrentCommentAndLiteral {
     cur_cmnt: uint,
     cur_lit: uint,
@@ -60,7 +70,7 @@ pub struct ps {
     literals: Option<~[comments::lit]>,
     cur_cmnt_and_lit: @mut CurrentCommentAndLiteral,
     boxes: @mut ~[pp::breaks],
-    ann: pp_ann
+    ann: @pp_ann
 }
 
 pub fn ibox(s: @ps, u: uint) {
@@ -74,12 +84,13 @@ pub fn end(s: @ps) {
 }
 
 pub fn rust_printer(writer: @io::Writer, intr: @ident_interner) -> @ps {
-    return rust_printer_annotated(writer, intr, no_ann());
+    return rust_printer_annotated(writer, intr, @no_ann::new() as @pp_ann);
 }
 
 pub fn rust_printer_annotated(writer: @io::Writer,
                               intr: @ident_interner,
-                              ann: pp_ann) -> @ps {
+                              ann: @pp_ann)
+                              -> @ps {
     return @ps {
         s: pp::mk_printer(writer, default_columns),
         cm: None::<@CodeMap>,
@@ -109,7 +120,7 @@ pub fn print_crate(cm: @CodeMap,
                    filename: @str,
                    input: @io::Reader,
                    out: @io::Writer,
-                   ann: pp_ann,
+                   ann: @pp_ann,
                    is_expanded: bool) {
     let (cmnts, lits) = comments::gather_comments_and_literals(
         span_diagnostic,
@@ -484,7 +495,7 @@ pub fn print_item(s: @ps, item: &ast::item) {
     maybe_print_comment(s, item.span.lo);
     print_outer_attributes(s, item.attrs);
     let ann_node = node_item(s, item);
-    (s.ann.pre)(ann_node);
+    s.ann.pre(ann_node);
     match item.node {
       ast::item_static(ref ty, m, expr) => {
         head(s, visibility_qualified(item.vis, "static"));
@@ -635,7 +646,7 @@ pub fn print_item(s: @ps, item: &ast::item) {
         end(s);
       }
     }
-    (s.ann.post)(ann_node);
+    s.ann.post(ann_node);
 }
 
 fn print_trait_ref(s: @ps, t: &ast::trait_ref) {
@@ -958,7 +969,7 @@ pub fn print_possibly_embedded_block_(s: @ps,
     }
     maybe_print_comment(s, blk.span.lo);
     let ann_node = node_block(s, blk);
-    (s.ann.pre)(ann_node);
+    s.ann.pre(ann_node);
     match embedded {
       block_block_fn => end(s),
       block_normal => bopen(s)
@@ -979,7 +990,7 @@ pub fn print_possibly_embedded_block_(s: @ps,
       _ => ()
     }
     bclose_maybe_open(s, blk.span, indented, close_box);
-    (s.ann.post)(ann_node);
+    s.ann.post(ann_node);
 }
 
 pub fn print_if(s: @ps, test: &ast::Expr, blk: &ast::Block,
@@ -1121,7 +1132,7 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
     maybe_print_comment(s, expr.span.lo);
     ibox(s, indent_unit);
     let ann_node = node_expr(s, expr);
-    (s.ann.pre)(ann_node);
+    s.ann.pre(ann_node);
     match expr.node {
         ast::ExprVstore(e, v) => {
             print_expr_vstore(s, v);
@@ -1456,7 +1467,7 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
           pclose(s);
       }
     }
-    (s.ann.post)(ann_node);
+    s.ann.post(ann_node);
     end(s);
 }
 
@@ -1578,7 +1589,7 @@ pub fn print_bounded_path(s: @ps, path: &ast::Path,
 pub fn print_pat(s: @ps, pat: &ast::Pat) {
     maybe_print_comment(s, pat.span.lo);
     let ann_node = node_pat(s, pat);
-    (s.ann.pre)(ann_node);
+    s.ann.pre(ann_node);
     /* Pat isn't normalized, but the beauty of it
      is that it doesn't matter */
     match pat.node {
@@ -1678,7 +1689,7 @@ pub fn print_pat(s: @ps, pat: &ast::Pat) {
         word(s.s, "]");
       }
     }
-    (s.ann.post)(ann_node);
+    s.ann.post(ann_node);
 }
 
 pub fn explicit_self_to_str(explicit_self: &ast::explicit_self_, intr: @ident_interner) -> ~str {
@@ -2254,17 +2265,6 @@ pub fn print_fn_header_info(s: @ps,
     print_opt_sigil(s, opt_sigil);
 }
 
-pub fn opt_sigil_to_str(opt_p: Option<ast::Sigil>) -> &'static str {
-    match opt_p {
-      None => "fn",
-      Some(p) => match p {
-          ast::BorrowedSigil => "fn&",
-          ast::OwnedSigil => "fn~",
-          ast::ManagedSigil => "fn@"
-      }
-    }
-}
-
 pub fn purity_to_str(p: ast::purity) -> &'static str {
     match p {
       ast::impure_fn => "impure",