From 3e5de06135fa9a857931191101d61a4abe149c96 Mon Sep 17 00:00:00 2001
From: Patrick Walton <pcwalton@mimiga.net>
Date: Thu, 29 Aug 2013 12:10:02 -0700
Subject: [PATCH] librustc: Change fold to use traits instead of `@fn`.

---
 src/librustc/front/assign_node_ids.rs  |   17 +-
 src/librustc/front/config.rs           |   62 +-
 src/librustc/front/std_inject.rs       |  169 +--
 src/librustc/front/test.rs             |  175 ++-
 src/librustc/middle/astencode.rs       |   77 +-
 src/librustpkg/util.rs                 |   35 +-
 src/libsyntax/ast_util.rs              |   16 -
 src/libsyntax/ext/build.rs             |   30 +
 src/libsyntax/ext/expand.rs            |  463 ++++---
 src/libsyntax/fold.rs                  | 1540 +++++++++++-------------
 src/test/compile-fail/dead-code-ret.rs |    5 +
 src/test/compile-fail/issue-897-2.rs   |    4 +
 12 files changed, 1335 insertions(+), 1258 deletions(-)

diff --git a/src/librustc/front/assign_node_ids.rs b/src/librustc/front/assign_node_ids.rs
index 446db5c35e9..fc1b034de97 100644
--- a/src/librustc/front/assign_node_ids.rs
+++ b/src/librustc/front/assign_node_ids.rs
@@ -11,9 +11,22 @@
 use driver::session::Session;
 
 use syntax::ast;
-use syntax::ast_util;
+use syntax::fold::ast_fold;
+
+struct NodeIdAssigner {
+    sess: Session,
+}
+
+impl ast_fold for NodeIdAssigner {
+    fn new_id(&self, old_id: ast::NodeId) -> ast::NodeId {
+        assert_eq!(old_id, ast::DUMMY_NODE_ID);
+        self.sess.next_node_id()
+    }
+}
 
 pub fn assign_node_ids(sess: Session, crate: @ast::Crate) -> @ast::Crate {
-    let fold = ast_util::node_id_assigner(|| sess.next_node_id());
+    let fold = NodeIdAssigner {
+        sess: sess,
+    };
     @fold.fold_crate(crate)
 }
diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs
index 2c0068729a7..fc1794fb935 100644
--- a/src/librustc/front/config.rs
+++ b/src/librustc/front/config.rs
@@ -10,6 +10,7 @@
 
 
 use std::option;
+use syntax::fold::ast_fold;
 use syntax::{ast, fold, attr};
 
 type in_cfg_pred = @fn(attrs: &[ast::Attribute]) -> bool;
@@ -26,21 +27,34 @@ pub fn strip_unconfigured_items(crate: @ast::Crate) -> @ast::Crate {
     }
 }
 
-pub fn strip_items(crate: &ast::Crate, in_cfg: in_cfg_pred)
-    -> @ast::Crate {
+struct ItemRemover {
+    ctxt: @Context,
+}
 
-    let ctxt = @Context { in_cfg: in_cfg };
+impl fold::ast_fold for ItemRemover {
+    fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
+        fold_mod(self.ctxt, module, self)
+    }
+    fn fold_block(&self, block: &ast::Block) -> ast::Block {
+        fold_block(self.ctxt, block, self)
+    }
+    fn fold_foreign_mod(&self, foreign_module: &ast::foreign_mod)
+                        -> ast::foreign_mod {
+        fold_foreign_mod(self.ctxt, foreign_module, self)
+    }
+    fn fold_item_underscore(&self, item: &ast::item_) -> ast::item_ {
+        fold_item_underscore(self.ctxt, item, self)
+    }
+}
 
-    let precursor = @fold::AstFoldFns {
-          fold_mod: |a,b| fold_mod(ctxt, a, b),
-          fold_block: |a,b| fold_block(ctxt, a, b),
-          fold_foreign_mod: |a,b| fold_foreign_mod(ctxt, a, b),
-          fold_item_underscore: |a,b| fold_item_underscore(ctxt, a, b),
-          .. *fold::default_ast_fold()
+pub fn strip_items(crate: &ast::Crate, in_cfg: in_cfg_pred) -> @ast::Crate {
+    let ctxt = @Context {
+        in_cfg: in_cfg,
     };
-
-    let fold = fold::make_fold(precursor);
-    @fold.fold_crate(crate)
+    let precursor = ItemRemover {
+        ctxt: ctxt,
+    };
+    @precursor.fold_crate(crate)
 }
 
 fn filter_item(cx: @Context, item: @ast::item) ->
@@ -56,7 +70,7 @@ fn filter_view_item<'r>(cx: @Context, view_item: &'r ast::view_item)-> Option<&'
     }
 }
 
-fn fold_mod(cx: @Context, m: &ast::_mod, fld: @fold::ast_fold) -> ast::_mod {
+fn fold_mod(cx: @Context, m: &ast::_mod, fld: &ItemRemover) -> ast::_mod {
     let filtered_items = do  m.items.iter().filter_map |a| {
         filter_item(cx, *a).and_then(|x| fld.fold_item(x))
     }.collect();
@@ -78,12 +92,12 @@ fn filter_foreign_item(cx: @Context, item: @ast::foreign_item) ->
     } else { option::None }
 }
 
-fn fold_foreign_mod(
-    cx: @Context,
-    nm: &ast::foreign_mod,
-    fld: @fold::ast_fold
-) -> ast::foreign_mod {
-    let filtered_items = nm.items.iter().filter_map(|a| filter_foreign_item(cx, *a)).collect();
+fn fold_foreign_mod(cx: @Context, nm: &ast::foreign_mod, fld: &ItemRemover)
+                    -> ast::foreign_mod {
+    let filtered_items = nm.items
+                           .iter()
+                           .filter_map(|a| filter_foreign_item(cx, *a))
+                           .collect();
     let filtered_view_items = do nm.view_items.iter().filter_map |a| {
         do filter_view_item(cx, a).map_move |x| {
             fld.fold_view_item(x)
@@ -97,8 +111,8 @@ fn fold_foreign_mod(
     }
 }
 
-fn fold_item_underscore(cx: @Context, item: &ast::item_,
-                        fld: @fold::ast_fold) -> ast::item_ {
+fn fold_item_underscore(cx: @Context, item: &ast::item_, fld: &ItemRemover)
+                        -> ast::item_ {
     let item = match *item {
         ast::item_impl(ref a, ref b, ref c, ref methods) => {
             let methods = methods.iter().filter(|m| method_in_cfg(cx, **m))
@@ -133,11 +147,7 @@ fn filter_stmt(cx: @Context, stmt: @ast::Stmt) ->
     }
 }
 
-fn fold_block(
-    cx: @Context,
-    b: &ast::Block,
-    fld: @fold::ast_fold
-) -> ast::Block {
+fn fold_block(cx: @Context, b: &ast::Block, fld: &ItemRemover) -> ast::Block {
     let resulting_stmts = do b.stmts.iter().filter_map |a| {
         filter_stmt(cx, *a).and_then(|stmt| fld.fold_stmt(stmt))
     }.collect();
diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs
index 79e554090f3..ab407806bcc 100644
--- a/src/librustc/front/std_inject.rs
+++ b/src/librustc/front/std_inject.rs
@@ -16,6 +16,7 @@ use syntax::ast;
 use syntax::attr;
 use syntax::codemap::dummy_sp;
 use syntax::codemap;
+use syntax::fold::ast_fold;
 use syntax::fold;
 use syntax::opt_vec;
 
@@ -38,91 +39,103 @@ fn no_prelude(attrs: &[ast::Attribute]) -> bool {
     attr::contains_name(attrs, "no_implicit_prelude")
 }
 
-fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
-    fn spanned<T>(x: T) -> codemap::Spanned<T> {
-        codemap::Spanned { node: x, span: dummy_sp() }
+fn spanned<T>(x: T) -> codemap::Spanned<T> {
+    codemap::Spanned {
+        node: x,
+        span: dummy_sp(),
+    }
+}
+
+struct StandardLibraryInjector {
+    sess: Session,
+}
+
+impl fold::ast_fold for StandardLibraryInjector {
+    fn fold_crate(&self, crate: &ast::Crate) -> ast::Crate {
+        let version = STD_VERSION.to_managed();
+        let vi1 = ast::view_item {
+            node: ast::view_item_extern_mod(self.sess.ident_of("std"),
+                                            None,
+                                            ~[],
+                                            ast::DUMMY_NODE_ID),
+            attrs: ~[
+                attr::mk_attr(attr::mk_name_value_item_str(@"vers", version))
+            ],
+            vis: ast::private,
+            span: dummy_sp()
+        };
+
+        let vis = vec::append(~[vi1], crate.module.view_items);
+        let mut new_module = ast::_mod {
+            view_items: vis,
+            ..crate.module.clone()
+        };
+
+        if !no_prelude(crate.attrs) {
+            // only add `use std::prelude::*;` if there wasn't a
+            // `#[no_implicit_prelude];` at the crate level.
+            new_module = self.fold_mod(&new_module);
+        }
+
+        // FIXME #2543: Bad copy.
+        ast::Crate {
+            module: new_module,
+            ..(*crate).clone()
+        }
     }
 
-    let precursor = @fold::AstFoldFns {
-        fold_crate: |crate, fld| {
-            let n1 = ast::DUMMY_NODE_ID;
-            let vi1 = ast::view_item {
-                node: ast::view_item_extern_mod(
-                        sess.ident_of("std"), None, ~[], n1),
-                attrs: ~[
-                    attr::mk_attr(
-                        attr::mk_name_value_item_str(@"vers", STD_VERSION.to_managed()))
-                ],
-                vis: ast::private,
-                span: dummy_sp()
-            };
+    fn fold_item(&self, item: @ast::item) -> Option<@ast::item> {
+        if !no_prelude(item.attrs) {
+            // only recur if there wasn't `#[no_implicit_prelude];`
+            // on this item, i.e. this means that the prelude is not
+            // implicitly imported though the whole subtree
+            fold::noop_fold_item(item, self)
+        } else {
+            Some(item)
+        }
+    }
 
-            let vis = vec::append(~[vi1], crate.module.view_items);
-            let mut new_module = ast::_mod {
-                view_items: vis,
-                ..crate.module.clone()
-            };
+    fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
+        let prelude_path = ast::Path {
+            span: dummy_sp(),
+            global: false,
+            segments: ~[
+                ast::PathSegment {
+                    identifier: self.sess.ident_of("std"),
+                    lifetime: None,
+                    types: opt_vec::Empty,
+                },
+                ast::PathSegment {
+                    identifier: self.sess.ident_of("prelude"),
+                    lifetime: None,
+                    types: opt_vec::Empty,
+                },
+            ],
+        };
 
-            if !no_prelude(crate.attrs) {
-                // only add `use std::prelude::*;` if there wasn't a
-                // `#[no_implicit_prelude];` at the crate level.
-                new_module = fld.fold_mod(&new_module);
-            }
+        let vp = @spanned(ast::view_path_glob(prelude_path,
+                                              ast::DUMMY_NODE_ID));
+        let vi2 = ast::view_item {
+            node: ast::view_item_use(~[vp]),
+            attrs: ~[],
+            vis: ast::private,
+            span: dummy_sp(),
+        };
 
-            // FIXME #2543: Bad copy.
-            ast::Crate {
-                module: new_module,
-                ..(*crate).clone()
-            }
-        },
-        fold_item: |item, fld| {
-            if !no_prelude(item.attrs) {
-                // only recur if there wasn't `#[no_implicit_prelude];`
-                // on this item, i.e. this means that the prelude is not
-                // implicitly imported though the whole subtree
-                fold::noop_fold_item(item, fld)
-            } else {
-                Some(item)
-            }
-        },
-        fold_mod: |module, fld| {
-            let n2 = ast::DUMMY_NODE_ID;
+        let vis = vec::append(~[vi2], module.view_items);
 
-            let prelude_path = ast::Path {
-                span: dummy_sp(),
-                global: false,
-                segments: ~[
-                    ast::PathSegment {
-                        identifier: sess.ident_of("std"),
-                        lifetime: None,
-                        types: opt_vec::Empty,
-                    },
-                    ast::PathSegment {
-                        identifier: sess.ident_of("prelude"),
-                        lifetime: None,
-                        types: opt_vec::Empty,
-                    },
-                ],
-            };
+        // FIXME #2543: Bad copy.
+        let new_module = ast::_mod {
+            view_items: vis,
+            ..(*module).clone()
+        };
+        fold::noop_fold_mod(&new_module, self)
+    }
+}
 
-            let vp = @spanned(ast::view_path_glob(prelude_path, n2));
-            let vi2 = ast::view_item { node: ast::view_item_use(~[vp]),
-                                        attrs: ~[],
-                                        vis: ast::private,
-                                        span: dummy_sp() };
-
-            let vis = vec::append(~[vi2], module.view_items);
-
-            // FIXME #2543: Bad copy.
-            let new_module = ast::_mod {
-                view_items: vis,
-                ..(*module).clone()
-            };
-            fold::noop_fold_mod(&new_module, fld)
-        },
-        ..*fold::default_ast_fold()
+fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
+    let fold = StandardLibraryInjector {
+        sess: sess,
     };
-
-    let fold = fold::make_fold(precursor);
     @fold.fold_crate(crate)
 }
diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs
index f0d7f6c892b..d2baee6c961 100644
--- a/src/librustc/front/test.rs
+++ b/src/librustc/front/test.rs
@@ -21,6 +21,7 @@ use syntax::attr;
 use syntax::codemap::{dummy_sp, Span, ExpnInfo, NameAndSpan};
 use syntax::codemap;
 use syntax::ext::base::ExtCtxt;
+use syntax::fold::ast_fold;
 use syntax::fold;
 use syntax::opt_vec;
 use syntax::print::pprust;
@@ -61,9 +62,89 @@ pub fn modify_for_testing(sess: session::Session,
     }
 }
 
-fn generate_test_harness(sess: session::Session,
-                         crate: @ast::Crate)
-                      -> @ast::Crate {
+struct TestHarnessGenerator {
+    cx: @mut TestCtxt,
+}
+
+impl fold::ast_fold for TestHarnessGenerator {
+    fn fold_crate(&self, c: &ast::Crate) -> ast::Crate {
+        let folded = fold::noop_fold_crate(c, self);
+
+        // Add a special __test module to the crate that will contain code
+        // generated for the test harness
+        ast::Crate {
+            module: add_test_module(self.cx, &folded.module),
+            .. folded
+        }
+    }
+
+    fn fold_item(&self, i: @ast::item) -> Option<@ast::item> {
+        self.cx.path.push(i.ident);
+        debug!("current path: %s",
+               ast_util::path_name_i(self.cx.path.clone()));
+
+        if is_test_fn(self.cx, i) || is_bench_fn(i) {
+            match i.node {
+                ast::item_fn(_, purity, _, _, _)
+                    if purity == ast::unsafe_fn => {
+                    let sess = self.cx.sess;
+                    sess.span_fatal(i.span,
+                                    "unsafe functions cannot be used for \
+                                     tests");
+                }
+                _ => {
+                    debug!("this is a test function");
+                    let test = Test {
+                        span: i.span,
+                        path: self.cx.path.clone(),
+                        bench: is_bench_fn(i),
+                        ignore: is_ignored(self.cx, i),
+                        should_fail: should_fail(i)
+                    };
+                    self.cx.testfns.push(test);
+                    // debug!("have %u test/bench functions",
+                    //        cx.testfns.len());
+                }
+            }
+        }
+
+        let res = fold::noop_fold_item(i, self);
+        self.cx.path.pop();
+        return res;
+    }
+
+    fn fold_mod(&self, m: &ast::_mod) -> ast::_mod {
+        // Remove any #[main] from the AST so it doesn't clash with
+        // the one we're going to add. Only if compiling an executable.
+
+        fn nomain(cx: @mut TestCtxt, item: @ast::item) -> @ast::item {
+            if !*cx.sess.building_library {
+                @ast::item {
+                    attrs: do item.attrs.iter().filter_map |attr| {
+                        if "main" != attr.name() {
+                            Some(*attr)
+                        } else {
+                            None
+                        }
+                    }.collect(),
+                    .. (*item).clone()
+                }
+            } else {
+                item
+            }
+        }
+
+        let mod_nomain = ast::_mod {
+            view_items: m.view_items.clone(),
+            items: m.items.iter().map(|i| nomain(self.cx, *i)).collect(),
+        };
+
+        fold::noop_fold_mod(&mod_nomain, self)
+    }
+}
+
+fn generate_test_harness(sess: session::Session, crate: @ast::Crate)
+                         -> @ast::Crate {
     let cx: @mut TestCtxt = @mut TestCtxt {
         sess: sess,
         crate: crate,
@@ -81,12 +162,9 @@ fn generate_test_harness(sess: session::Session,
         }
     });
 
-    let precursor = @fold::AstFoldFns {
-        fold_crate: |a,b| fold_crate(cx, a, b),
-        fold_item: |a,b| fold_item(cx, a, b),
-        fold_mod: |a,b| fold_mod(cx, a, b),.. *fold::default_ast_fold()};
-
-    let fold = fold::make_fold(precursor);
+    let fold = TestHarnessGenerator {
+        cx: cx
+    };
     let res = @fold.fold_crate(&*crate);
     ext_cx.bt_pop();
     return res;
@@ -101,85 +179,6 @@ fn strip_test_functions(crate: &ast::Crate) -> @ast::Crate {
     }
 }
 
-fn fold_mod(cx: @mut TestCtxt,
-            m: &ast::_mod,
-            fld: @fold::ast_fold)
-         -> ast::_mod {
-    // Remove any #[main] from the AST so it doesn't clash with
-    // the one we're going to add. Only if compiling an executable.
-
-    fn nomain(cx: @mut TestCtxt, item: @ast::item) -> @ast::item {
-        if !*cx.sess.building_library {
-            @ast::item {
-                attrs: do item.attrs.iter().filter_map |attr| {
-                    if "main" != attr.name() {
-                        Some(*attr)
-                    } else {
-                        None
-                    }
-                }.collect(),
-                .. (*item).clone()
-            }
-        } else {
-            item
-        }
-    }
-
-    let mod_nomain = ast::_mod {
-        view_items: m.view_items.clone(),
-        items: m.items.iter().map(|i| nomain(cx, *i)).collect(),
-    };
-
-    fold::noop_fold_mod(&mod_nomain, fld)
-}
-
-fn fold_crate(cx: @mut TestCtxt, c: &ast::Crate, fld: @fold::ast_fold)
-              -> ast::Crate {
-    let folded = fold::noop_fold_crate(c, fld);
-
-    // Add a special __test module to the crate that will contain code
-    // generated for the test harness
-    ast::Crate {
-        module: add_test_module(cx, &folded.module),
-        .. folded
-    }
-}
-
-
-fn fold_item(cx: @mut TestCtxt, i: @ast::item, fld: @fold::ast_fold)
-          -> Option<@ast::item> {
-    cx.path.push(i.ident);
-    debug!("current path: %s",
-           ast_util::path_name_i(cx.path.clone()));
-
-    if is_test_fn(cx, i) || is_bench_fn(i) {
-        match i.node {
-          ast::item_fn(_, purity, _, _, _) if purity == ast::unsafe_fn => {
-            let sess = cx.sess;
-            sess.span_fatal(
-                i.span,
-                "unsafe functions cannot be used for tests");
-          }
-          _ => {
-            debug!("this is a test function");
-            let test = Test {
-                span: i.span,
-                path: cx.path.clone(),
-                bench: is_bench_fn(i),
-                ignore: is_ignored(cx, i),
-                should_fail: should_fail(i)
-            };
-            cx.testfns.push(test);
-            // debug!("have %u test/bench functions", cx.testfns.len());
-          }
-        }
-    }
-
-    let res = fold::noop_fold_item(i, fld);
-    cx.path.pop();
-    return res;
-}
-
 fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool {
     let has_test_attr = attr::contains_name(i.attrs, "test");
 
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index bcc333afeec..6521b4bb3cc 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -287,26 +287,24 @@ fn encode_ast(ebml_w: &mut writer::Encoder, item: ast::inlined_item) {
     ebml_w.end_tag();
 }
 
-// Produces a simplified copy of the AST which does not include things
-// that we do not need to or do not want to export.  For example, we
-// do not include any nested items: if these nested items are to be
-// inlined, their AST will be exported separately (this only makes
-// sense because, in Rust, nested items are independent except for
-// their visibility).
-//
-// As it happens, trans relies on the fact that we do not export
-// nested items, as otherwise it would get confused when translating
-// inlined items.
-fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
-    fn drop_nested_items(blk: &ast::Block, fld: @fold::ast_fold) -> ast::Block {
+struct NestedItemsDropper {
+    contents: (),
+}
+
+impl fold::ast_fold for NestedItemsDropper {
+    fn fold_block(&self, blk: &ast::Block) -> ast::Block {
         let stmts_sans_items = do blk.stmts.iter().filter_map |stmt| {
             match stmt.node {
-              ast::StmtExpr(_, _) | ast::StmtSemi(_, _) |
-              ast::StmtDecl(@codemap::Spanned { node: ast::DeclLocal(_), span: _}, _)
-                => Some(*stmt),
-              ast::StmtDecl(@codemap::Spanned { node: ast::DeclItem(_), span: _}, _)
-                => None,
-              ast::StmtMac(*) => fail!("unexpanded macro in astencode")
+                ast::StmtExpr(_, _) | ast::StmtSemi(_, _) |
+                ast::StmtDecl(@codemap::Spanned {
+                    node: ast::DeclLocal(_),
+                    span: _
+                }, _) => Some(*stmt),
+                ast::StmtDecl(@codemap::Spanned {
+                    node: ast::DeclItem(_),
+                    span: _
+                }, _) => None,
+                ast::StmtMac(*) => fail!("unexpanded macro in astencode")
             }
         }.collect();
         let blk_sans_items = ast::Block {
@@ -318,13 +316,24 @@ fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
             rules: blk.rules,
             span: blk.span,
         };
-        fold::noop_fold_block(&blk_sans_items, fld)
+        fold::noop_fold_block(&blk_sans_items, self)
     }
+}
 
-    let fld = fold::make_fold(@fold::AstFoldFns {
-        fold_block: drop_nested_items,
-        .. *fold::default_ast_fold()
-    });
+// Produces a simplified copy of the AST which does not include things
+// that we do not need to or do not want to export.  For example, we
+// do not include any nested items: if these nested items are to be
+// inlined, their AST will be exported separately (this only makes
+// sense because, in Rust, nested items are independent except for
+// their visibility).
+//
+// As it happens, trans relies on the fact that we do not export
+// nested items, as otherwise it would get confused when translating
+// inlined items.
+fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
+    let fld = NestedItemsDropper {
+        contents: (),
+    };
 
     match *ii {
         //hack: we're not dropping items
@@ -341,14 +350,24 @@ fn decode_ast(par_doc: ebml::Doc) -> ast::inlined_item {
     Decodable::decode(&mut d)
 }
 
+struct AstRenumberer {
+    xcx: @ExtendedDecodeContext,
+}
+
+impl fold::ast_fold for AstRenumberer {
+    fn new_id(&self, id: ast::NodeId) -> ast::NodeId {
+        self.xcx.tr_id(id)
+    }
+    fn new_span(&self, span: Span) -> Span {
+        self.xcx.tr_span(span)
+    }
+}
+
 fn renumber_ast(xcx: @ExtendedDecodeContext, ii: ast::inlined_item)
     -> ast::inlined_item {
-    let fld = fold::make_fold(@fold::AstFoldFns{
-        new_id: |a| xcx.tr_id(a),
-        new_span: |a| xcx.tr_span(a),
-        .. *fold::default_ast_fold()
-    });
-
+    let fld = AstRenumberer {
+        xcx: xcx,
+    };
     match ii {
         ast::ii_item(i) => ast::ii_item(fld.fold_item(i).unwrap()),
         ast::ii_method(d, is_provided, m) =>
diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs
index 906bed2f234..02524b65020 100644
--- a/src/librustpkg/util.rs
+++ b/src/librustpkg/util.rs
@@ -18,6 +18,8 @@ use syntax::codemap::{dummy_sp, Spanned};
 use syntax::ext::base::ExtCtxt;
 use syntax::{ast, attr, codemap, diagnostic, fold};
 use syntax::attr::AttrMetaMethods;
+use syntax::fold::ast_fold;
+use rustc::back::link::output_type_exe;
 use rustc::back::link;
 use rustc::driver::session::{lib_crate, bin_crate};
 use context::{in_target, StopBefore, Link, Assemble, BuildContext};
@@ -70,9 +72,8 @@ struct ReadyCtx {
     fns: ~[ListenerFn]
 }
 
-fn fold_mod(_ctx: @mut ReadyCtx,
-            m: &ast::_mod,
-            fold: @fold::ast_fold) -> ast::_mod {
+fn fold_mod(_ctx: @mut ReadyCtx, m: &ast::_mod, fold: &CrateSetup)
+            -> ast::_mod {
     fn strip_main(item: @ast::item) -> @ast::item {
         @ast::item {
             attrs: do item.attrs.iter().filter_map |attr| {
@@ -94,9 +95,8 @@ fn fold_mod(_ctx: @mut ReadyCtx,
     }, fold)
 }
 
-fn fold_item(ctx: @mut ReadyCtx,
-             item: @ast::item,
-             fold: @fold::ast_fold) -> Option<@ast::item> {
+fn fold_item(ctx: @mut ReadyCtx, item: @ast::item, fold: &CrateSetup)
+             -> Option<@ast::item> {
     ctx.path.push(item.ident);
 
     let mut cmds = ~[];
@@ -134,6 +134,19 @@ fn fold_item(ctx: @mut ReadyCtx,
     res
 }
 
+struct CrateSetup {
+    ctx: @mut ReadyCtx,
+}
+
+impl fold::ast_fold for CrateSetup {
+    fn fold_item(&self, item: @ast::item) -> Option<@ast::item> {
+        fold_item(self.ctx, item, self)
+    }
+    fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
+        fold_mod(self.ctx, module, self)
+    }
+}
+
 /// Generate/filter main function, add the list of commands, etc.
 pub fn ready_crate(sess: session::Session,
                    crate: @ast::Crate) -> @ast::Crate {
@@ -144,15 +157,9 @@ pub fn ready_crate(sess: session::Session,
         path: ~[],
         fns: ~[]
     };
-    let precursor = @fold::AstFoldFns {
-        // fold_crate: fold::wrap(|a, b| fold_crate(ctx, a, b)),
-        fold_item: |a, b| fold_item(ctx, a, b),
-        fold_mod: |a, b| fold_mod(ctx, a, b),
-        .. *fold::default_ast_fold()
+    let fold = CrateSetup {
+        ctx: ctx,
     };
-
-    let fold = fold::make_fold(precursor);
-
     @fold.fold_crate(crate)
 }
 
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index f0f86911f50..2e47050ad6a 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
 
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 889c2a5976e..aa4238ae908 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..0aefbe31338 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,
@@ -101,12 +100,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 +131,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 +228,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 +251,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 +281,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 +307,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 +332,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")
@@ -382,15 +438,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 +451,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,11 +481,16 @@ 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},
+            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(),
                 _ => cx.span_fatal(
                     pth.span,
@@ -438,12 +498,15 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
             };
             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 +514,7 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
                 }
             };
 
-            (fully_expanded, sp)
+            fully_expanded
         }
 
         _ => {
@@ -460,24 +523,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 +582,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 +700,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 +752,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.
+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 +1135,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 +1166,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 expander = @MacroExpander {
+        extsbox: @mut extsbox,
+        cx: cx,
+    } as @ast_fold;
 
-    let ret = @f.fold_crate(c);
+    let ret = @expander.fold_crate(c);
     parse_sess.span_diagnostic.handler().abort_if_errors();
     return ret;
 }
@@ -1145,53 +1305,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.
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 5472c61a155..18ddee34171 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;
+    fn fold_crate(&self, c: &Crate) -> Crate {
+        noop_fold_crate(c, self)
+    }
 
-    // New style, using default methods:
+    fn fold_meta_items(&self, meta_items: &[@MetaItem]) -> ~[@MetaItem] {
+        meta_items.map(|x| fold_meta_item_(*x, self))
+    }
 
-    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_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_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_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_spanned<T>(@self, s: &Spanned<T>, f: &fn(&T) -> T) -> Spanned<T> {
+    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_item(&self, i: @item) -> Option<@item> {
+        noop_fold_item(i, self)
+    }
+
+    fn fold_struct_field(&self, sf: @struct_field) -> @struct_field {
+        let fold_attribute = |x| fold_attribute_(x, self);
+
+        @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_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_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_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))))
+            }
+            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_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_mod(&self, m: &_mod) -> _mod {
+        noop_fold_mod(m, self)
+    }
+
+    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_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: f(&s.node),
-            span: self.new_span(s.span)
+            node: node,
+            span: self.new_span(v.span),
         }
     }
 
-    fn fold_view_path(@self, vp: &view_path) -> view_path {
-        self.fold_spanned(vp, |v| self.fold_view_path_(v))
+    fn fold_ident(&self, i: Ident) -> Ident {
+        i
     }
 
-    fn fold_view_paths(@self, vps: &[@view_path]) -> ~[@view_path] {
-        vps.map(|vp| @self.fold_view_path(*vp))
-    }
-
-    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))
-            }
-            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))
-            }
+    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_path_list_idents(@self, idents: &[path_list_ident]) -> ~[path_list_ident] {
-        idents.map(|i| self.fold_path_list_ident(i))
-    }
-
-    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_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)
-        }
-    }
-
-    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_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_ty_param_bound(@self, tpb: &TyParamBound) -> TyParamBound {
-        match *tpb {
-            TraitTyParamBound(ref ty) => {
-                TraitTyParamBound(self.fold_trait_ref(ty))
-            }
-            RegionTyParamBound => {
-                RegionTyParamBound
-            }
-        }
-    }
-
-    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_ty_params(@self, tps: &OptVec<TyParam>) -> OptVec<TyParam> {
-        tps.map(|tp| self.fold_ty_param(tp))
-    }
-
-    fn fold_lifetime(@self, l: &Lifetime) -> Lifetime {
-        Lifetime {
+    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),
-            ident: l.ident, // Folding this ident causes hygiene errors - ndm
         }
     }
 
-    fn fold_lifetimes(@self, lts: &OptVec<Lifetime>) -> OptVec<Lifetime> {
-        lts.map(|l| self.fold_lifetime(l))
-    }
-
-
-    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_meta_items(@self, mis: &[@MetaItem]) -> ~[@MetaItem] {
-        mis.map(|&mi| self.fold_meta_item(mi))
-    }
-
-    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
-}
-
-pub type ast_fold_fns = @AstFoldFns;
-
 /* some little folds that probably aren't useful to have in ast_fold itself*/
 
-pub fn fold_tts(tts : &[token_tree], fld: @ast_fold) -> ~[token_tree] {
+//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) }
+}
+
+//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
+        }
+    }
+}
+
+//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),
+    }
+}
+
+// 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,172 +533,70 @@ 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 {
-    @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),
-        },
-        span: sf.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),
-    }
-}
-
-pub fn noop_fold_item_underscore(i: &item_, fld: @ast_fold) -> item_ {
-    match *i {
-        item_static(ref t, m, e) => {
-            item_static(fld.fold_ty(t), m, fld.fold_expr(e))
-        }
-        item_fn(ref decl, purity, abi, ref generics, ref body) => {
-            item_fn(
-                fold_fn_decl(decl, fld),
-                purity,
-                abi,
-                fold_generics(generics, fld),
-                fld.fold_block(body)
-            )
-        }
-        item_mod(ref m) => {
-            item_mod(fld.fold_mod(m))
-        }
-        item_foreign_mod(ref nm) => {
-            item_foreign_mod(fld.fold_foreign_mod(nm))
-        }
-        item_ty(ref t, ref generics) => {
-            item_ty(fld.fold_ty(t), fold_generics(generics, fld))
-        }
-        item_enum(ref enum_definition, ref generics) => {
-            item_enum(
-                ast::enum_def {
-                    variants: do enum_definition.variants.map |x| {
-                        fld.fold_variant(x)
-                    },
-                },
-                fold_generics(generics, fld))
-        }
-        item_struct(ref struct_def, ref generics) => {
-            let struct_def = fold_struct_def(*struct_def, fld);
-            item_struct(struct_def, fold_generics(generics, fld))
-        }
-        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_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))
-                }
-            };
-            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))
-        }
-    }
-}
-
-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 {
+fn fold_struct_field<T:ast_fold>(f: @struct_field, fld: &T) -> @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),
+            attrs: f.node.attrs.map(|a| fold_attribute_(*a, fld)),
         },
         span: fld.new_span(f.span),
     }
 }
 
-fn noop_fold_method(m: @method, fld: @ast_fold) -> @method {
-    @ast::method {
-        ident: fld.fold_ident(m.ident),
-        attrs: fld.fold_attributes(m.attrs),
-        generics: fold_generics(&m.generics, fld),
-        explicit_self: m.explicit_self,
-        purity: m.purity,
-        decl: fold_fn_decl(&m.decl, fld),
-        body: fld.fold_block(&m.body),
-        id: fld.new_id(m.id),
-        span: fld.new_span(m.span),
-        self_id: fld.new_id(m.self_id),
-        vis: m.vis,
+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),
     }
 }
 
+fn fold_mt<T:ast_fold>(mt: &mt, folder: &T) -> mt {
+    mt {
+        ty: ~folder.fold_ty(mt.ty),
+        mutbl: mt.mutbl,
+    }
+}
 
-pub fn noop_fold_block(b: &Block, fld: @ast_fold) -> Block {
-    let view_items = b.view_items.map(|x| fld.fold_view_item(x));
+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 fld.fold_stmt(*stmt) {
+        match folder.fold_stmt(*stmt) {
             None => {}
             Some(stmt) => stmts.push(stmt)
         }
@@ -464,580 +604,262 @@ pub fn noop_fold_block(b: &Block, fld: @ast_fold) -> Block {
     ast::Block {
         view_items: view_items,
         stmts: stmts,
-        expr: b.expr.map(|x| fld.fold_expr(*x)),
-        id: fld.new_id(b.id),
+        expr: b.expr.map(|x| folder.fold_expr(*x)),
+        id: folder.new_id(b.id),
         rules: b.rules,
-        span: b.span,
+        span: folder.new_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,
-            }
+pub fn noop_fold_item_underscore<T:ast_fold>(i: &item_, folder: &T) -> item_ {
+    match *i {
+        item_static(ref t, m, e) => {
+            item_static(folder.fold_ty(t), m, folder.fold_expr(e))
         }
-        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))
-    }
-}
-
-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_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))
+        item_fn(ref decl, purity, abi, ref generics, ref body) => {
+            item_fn(
+                fold_fn_decl(decl, folder),
+                purity,
+                abi,
+                fold_generics(generics, folder),
+                folder.fold_block(body)
             )
         }
-        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)))
+        item_mod(ref m) => item_mod(folder.fold_mod(m)),
+        item_foreign_mod(ref nm) => {
+            item_foreign_mod(folder.fold_foreign_mod(nm))
+        }
+        item_ty(ref t, ref generics) => {
+            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| {
+                        folder.fold_variant(x)
+                    },
+                },
+                fold_generics(generics, folder))
+        }
+        item_struct(ref struct_def, ref generics) => {
+            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, folder),
+                      ifce.map(|p| fold_trait_ref(p, folder)),
+                      folder.fold_ty(ty),
+                      methods.map(|x| folder.fold_method(*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)
+        item_trait(ref generics, ref traits, ref methods) => {
+            let methods = do methods.map |method| {
+                match *method {
+                    required(ref m) => required(folder.fold_type_method(m)),
+                    provided(method) => provided(folder.fold_method(method))
                 }
             };
-            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))
-            )
+            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 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_type_method<T:ast_fold>(m: &TypeMethod, fld: &T)
+                                         -> TypeMethod {
+    TypeMethod {
+        ident: fld.fold_ident(m.ident),
+        attrs: m.attrs.map(|a| fold_attribute_(*a, fld)),
+        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),
     }
 }
 
-// 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
+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(),
+    }
 }
 
-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_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);
 
-    match *e {
+    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),
+    }
+}
+
+pub fn noop_fold_item<T:ast_fold>(i: @ast::item, folder: &T)
+                                  -> Option<@ast::item> {
+    let fold_attribute = |x| fold_attribute_(x, folder);
+
+    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<T:ast_fold>(e: @ast::Expr, folder: &T) -> @ast::Expr {
+    let fold_field = |x| fold_field_(x, folder);
+
+    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
-            }))
-        }
-        ExprRet(ref e) => {
-            ExprRet(e.map_move(|x| fld.fold_expr(x)))
-        }
         ExprLogLevel => ExprLogLevel,
+        ExprBreak(opt_ident) => ExprBreak(opt_ident),
+        ExprAgain(opt_ident) => ExprAgain(opt_ident),
+        ExprRet(ref e) => {
+            ExprRet(e.map_move(|x| folder.fold_expr(x)))
+        }
         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))
-            })
-        }
+        ExprParen(ex) => ExprParen(folder.fold_expr(ex))
     };
 
-    let attrs = fld.fold_attributes(v.attrs);
+    @Expr {
+        id: folder.new_id(e.id),
+        node: node,
+        span: folder.new_span(e.span),
+    }
+}
 
-    let de = match v.disr_expr {
-      Some(e) => Some(fld.fold_expr(e)),
-      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,
+            }
+        }
+        StmtExpr(e, nid) => {
+            Some(StmtExpr(folder.fold_expr(e), folder.new_id(nid)))
+        }
+        StmtSemi(e, nid) => {
+            Some(StmtSemi(folder.fold_expr(e), folder.new_id(nid)))
+        }
+        StmtMac(ref mac, semi) => Some(StmtMac(folder.fold_mac(mac), semi))
     };
-    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)),
-        })
-    }
-}
-
-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,
-        }
-    }
-    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),
-        }
-    }
-    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),
-        }
-    }
-    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)
-    }
-}
-
-// 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,16 +870,23 @@ mod test {
     use print::pprust;
     use super::*;
 
+    struct IdentFolder {
+        f: @fn(ast::ident)->ast::ident,
+    }
+
+    impl ast_fold for IdentFolder {
+        fn fold_ident(@self, i: ident) -> ident {
+            (self.f)(i)
+        }
+    }
+
     // 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)
+    pub fn fun_to_ident_folder(f: @fn(ast::ident)->ast::ident) -> @ast_fold {
+        @IdentFolder {
+            f: f,
+        } as @ast_fold
     }
 
     // this version doesn't care about getting comments or docstrings in.
@@ -1120,3 +949,4 @@ mod test {
                      ~"fn zz(){let zz=13 as zz;}");
     }
 }
+
diff --git a/src/test/compile-fail/dead-code-ret.rs b/src/test/compile-fail/dead-code-ret.rs
index 2e4ae7f8544..b6976b2c355 100644
--- a/src/test/compile-fail/dead-code-ret.rs
+++ b/src/test/compile-fail/dead-code-ret.rs
@@ -1,3 +1,8 @@
+// xfail-test
+
+// xfail'd because the lint pass doesn't know to ignore standard library
+// stuff.
+
 // -*- rust -*-
 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
diff --git a/src/test/compile-fail/issue-897-2.rs b/src/test/compile-fail/issue-897-2.rs
index eb60e34df8f..c39c258c701 100644
--- a/src/test/compile-fail/issue-897-2.rs
+++ b/src/test/compile-fail/issue-897-2.rs
@@ -1,3 +1,7 @@
+// xfail-test
+// xfail'd because the lint pass doesn't know to ignore standard library
+// stuff.
+
 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.