From b9686416c63117db3832e8015b609cbc83f11e4b Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Tue, 5 Feb 2019 15:09:23 +1100
Subject: [PATCH 01/10] Remove some unnecessary `ast::` and `fold::`
 qualifiers.

---
 src/libsyntax/ext/expand.rs |  7 ++--
 src/libsyntax/fold.rs       | 76 +++++++++++++++++--------------------
 2 files changed, 37 insertions(+), 46 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 1b4b44270ad06..957187ec71c61 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -9,7 +9,6 @@ use ext::derive::{add_derived_markers, collect_derives};
 use ext::hygiene::{self, Mark, SyntaxContext};
 use ext::placeholders::{placeholder, PlaceholderExpander};
 use feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err};
-use fold;
 use fold::*;
 use parse::{DirectoryOwnership, PResult, ParseSess};
 use parse::token::{self, Token};
@@ -1395,7 +1394,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                 self.check_attributes(&attrs);
                 self.collect_bang(mac, span, AstFragmentKind::TraitItems).make_trait_items()
             }
-            _ => fold::noop_fold_trait_item(item, self),
+            _ => noop_fold_trait_item(item, self),
         }
     }
 
@@ -1414,14 +1413,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                 self.check_attributes(&attrs);
                 self.collect_bang(mac, span, AstFragmentKind::ImplItems).make_impl_items()
             }
-            _ => fold::noop_fold_impl_item(item, self),
+            _ => noop_fold_impl_item(item, self),
         }
     }
 
     fn fold_ty(&mut self, ty: P<ast::Ty>) -> P<ast::Ty> {
         let ty = match ty.node {
             ast::TyKind::Mac(_) => ty.into_inner(),
-            _ => return fold::noop_fold_ty(ty, self),
+            _ => return noop_fold_ty(ty, self),
         };
 
         match ty.node {
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index fdcbbb939a6cf..d8afad5e37912 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -9,7 +9,6 @@
 //! that are created by the expansion of a macro.
 
 use ast::*;
-use ast;
 use syntax_pos::Span;
 use source_map::{Spanned, respan};
 use parse::token::{self, Token};
@@ -785,31 +784,26 @@ pub fn noop_fold_where_predicate<T: Folder>(
                                  fld: &mut T)
                                  -> WherePredicate {
     match pred {
-        ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{bound_generic_params,
-                                                                     bounded_ty,
-                                                                     bounds,
-                                                                     span}) => {
-            ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
+        WherePredicate::BoundPredicate(WhereBoundPredicate { bound_generic_params,
+                                                             bounded_ty,
+                                                             bounds,
+                                                             span }) => {
+            WherePredicate::BoundPredicate(WhereBoundPredicate {
                 bound_generic_params: fld.fold_generic_params(bound_generic_params),
                 bounded_ty: fld.fold_ty(bounded_ty),
                 bounds: bounds.move_map(|x| fld.fold_param_bound(x)),
                 span: fld.new_span(span)
             })
         }
-        ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{lifetime,
-                                                                       bounds,
-                                                                       span}) => {
-            ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
+        WherePredicate::RegionPredicate(WhereRegionPredicate { lifetime, bounds, span }) => {
+            WherePredicate::RegionPredicate(WhereRegionPredicate {
                 span: fld.new_span(span),
                 lifetime: noop_fold_lifetime(lifetime, fld),
                 bounds: bounds.move_map(|bound| noop_fold_param_bound(bound, fld))
             })
         }
-        ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{id,
-                                                               lhs_ty,
-                                                               rhs_ty,
-                                                               span}) => {
-            ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{
+        WherePredicate::EqPredicate(WhereEqPredicate { id, lhs_ty, rhs_ty, span }) => {
+            WherePredicate::EqPredicate(WhereEqPredicate{
                 id: fld.new_id(id),
                 lhs_ty: fld.fold_ty(lhs_ty),
                 rhs_ty: fld.fold_ty(rhs_ty),
@@ -821,15 +815,13 @@ pub fn noop_fold_where_predicate<T: Folder>(
 
 pub fn noop_fold_variant_data<T: Folder>(vdata: VariantData, fld: &mut T) -> VariantData {
     match vdata {
-        ast::VariantData::Struct(fields, id) => {
-            ast::VariantData::Struct(fields.move_map(|f| fld.fold_struct_field(f)),
-                                     fld.new_id(id))
+        VariantData::Struct(fields, id) => {
+            VariantData::Struct(fields.move_map(|f| fld.fold_struct_field(f)), fld.new_id(id))
         }
-        ast::VariantData::Tuple(fields, id) => {
-            ast::VariantData::Tuple(fields.move_map(|f| fld.fold_struct_field(f)),
-                                    fld.new_id(id))
+        VariantData::Tuple(fields, id) => {
+            VariantData::Tuple(fields.move_map(|f| fld.fold_struct_field(f)), fld.new_id(id))
         }
-        ast::VariantData::Unit(id) => ast::VariantData::Unit(fld.new_id(id))
+        VariantData::Unit(id) => VariantData::Unit(fld.new_id(id))
     }
 }
 
@@ -839,14 +831,14 @@ pub fn noop_fold_trait_ref<T: Folder>(p: TraitRef, fld: &mut T) -> TraitRef {
         path,
         ref_id: _,
     } = p;
-    ast::TraitRef {
+    TraitRef {
         path: fld.fold_path(path),
         ref_id: id,
     }
 }
 
 pub fn noop_fold_poly_trait_ref<T: Folder>(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef {
-    ast::PolyTraitRef {
+    PolyTraitRef {
         bound_generic_params: fld.fold_generic_params(p.bound_generic_params),
         trait_ref: fld.fold_trait_ref(p.trait_ref),
         span: fld.new_span(p.span),
@@ -932,7 +924,7 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
         ItemKind::Enum(enum_definition, generics) => {
             let generics = folder.fold_generics(generics);
             let variants = enum_definition.variants.move_map(|x| folder.fold_variant(x));
-            ItemKind::Enum(ast::EnumDef { variants }, generics)
+            ItemKind::Enum(EnumDef { variants }, generics)
         }
         ItemKind::Struct(struct_def, generics) => {
             let generics = folder.fold_generics(generics);
@@ -991,7 +983,7 @@ pub fn noop_fold_trait_item<T: Folder>(i: TraitItem, folder: &mut T) -> SmallVec
                 TraitItemKind::Type(folder.fold_bounds(bounds),
                               default.map(|x| folder.fold_ty(x)))
             }
-            ast::TraitItemKind::Macro(mac) => {
+            TraitItemKind::Macro(mac) => {
                 TraitItemKind::Macro(folder.fold_mac(mac))
             }
         },
@@ -1009,18 +1001,18 @@ pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T)-> SmallVec<[I
         generics: folder.fold_generics(i.generics),
         defaultness: i.defaultness,
         node: match i.node  {
-            ast::ImplItemKind::Const(ty, expr) => {
-                ast::ImplItemKind::Const(folder.fold_ty(ty), folder.fold_expr(expr))
+            ImplItemKind::Const(ty, expr) => {
+                ImplItemKind::Const(folder.fold_ty(ty), folder.fold_expr(expr))
             }
-            ast::ImplItemKind::Method(sig, body) => {
-                ast::ImplItemKind::Method(noop_fold_method_sig(sig, folder),
+            ImplItemKind::Method(sig, body) => {
+                ImplItemKind::Method(noop_fold_method_sig(sig, folder),
                                folder.fold_block(body))
             }
-            ast::ImplItemKind::Type(ty) => ast::ImplItemKind::Type(folder.fold_ty(ty)),
-            ast::ImplItemKind::Existential(bounds) => {
-                ast::ImplItemKind::Existential(folder.fold_bounds(bounds))
+            ImplItemKind::Type(ty) => ImplItemKind::Type(folder.fold_ty(ty)),
+            ImplItemKind::Existential(bounds) => {
+                ImplItemKind::Existential(folder.fold_bounds(bounds))
             },
-            ast::ImplItemKind::Macro(mac) => ast::ImplItemKind::Macro(folder.fold_mac(mac))
+            ImplItemKind::Macro(mac) => ImplItemKind::Macro(folder.fold_mac(mac))
         },
         span: folder.new_span(i.span),
         tokens: i.tokens,
@@ -1042,13 +1034,13 @@ pub fn noop_fold_mod<T: Folder>(Mod {inner, items, inline}: Mod, folder: &mut T)
 
 pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, span}: Crate,
                                   folder: &mut T) -> Crate {
-    let mut items = folder.fold_item(P(ast::Item {
+    let mut items = folder.fold_item(P(Item {
         ident: keywords::Invalid.ident(),
         attrs,
-        id: ast::DUMMY_NODE_ID,
-        vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Public),
+        id: DUMMY_NODE_ID,
+        vis: respan(span.shrink_to_lo(), VisibilityKind::Public),
         span,
-        node: ast::ItemKind::Mod(module),
+        node: ItemKind::Mod(module),
         tokens: None,
     })).into_iter();
 
@@ -1056,14 +1048,14 @@ pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, span}: Crate,
         Some(item) => {
             assert!(items.next().is_none(),
                     "a crate cannot expand to more than one item");
-            item.and_then(|ast::Item { attrs, span, node, .. }| {
+            item.and_then(|Item { attrs, span, node, .. }| {
                 match node {
-                    ast::ItemKind::Mod(m) => (m, attrs, span),
+                    ItemKind::Mod(m) => (m, attrs, span),
                     _ => panic!("fold converted a module to not a module"),
                 }
             })
         }
-        None => (ast::Mod {
+        None => (Mod {
             inner: span,
             items: vec![],
             inline: true,
@@ -1155,7 +1147,7 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
                 let pth = folder.fold_path(pth);
                 let fs = fields.move_map(|f| {
                     Spanned { span: folder.new_span(f.span),
-                              node: ast::FieldPat {
+                              node: FieldPat {
                                   ident: folder.fold_ident(f.node.ident),
                                   pat: folder.fold_pat(f.node.pat),
                                   is_shorthand: f.node.is_shorthand,

From faa82eb46c800857756ddc5458623a906a9f103e Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Tue, 5 Feb 2019 15:10:04 +1100
Subject: [PATCH 02/10] Streamline `Folder`.

Specifically:

- Remove dead methods: fold_usize, fold_meta_items, fold_opt_bounds.

- Remove useless methods: fold_global_asm, fold_range_end.

- Inline and remove unnecessary methods: fold_item_simple,
  fold_foreign_item_simple.
---
 src/libsyntax/fold.rs | 97 +++++++++----------------------------------
 1 file changed, 20 insertions(+), 77 deletions(-)

diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index d8afad5e37912..6f856f63d6c7f 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -45,10 +45,6 @@ pub trait Folder : Sized {
         noop_fold_crate(c, self)
     }
 
-    fn fold_meta_items(&mut self, meta_items: Vec<MetaItem>) -> Vec<MetaItem> {
-        noop_fold_meta_items(meta_items, self)
-    }
-
     fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem {
         noop_fold_meta_list_item(list_item, self)
     }
@@ -65,18 +61,10 @@ pub trait Folder : Sized {
         noop_fold_foreign_item(ni, self)
     }
 
-    fn fold_foreign_item_simple(&mut self, ni: ForeignItem) -> ForeignItem {
-        noop_fold_foreign_item_simple(ni, self)
-    }
-
     fn fold_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> {
         noop_fold_item(i, self)
     }
 
-    fn fold_item_simple(&mut self, i: Item) -> Item {
-        noop_fold_item_simple(i, self)
-    }
-
     fn fold_fn_header(&mut self, header: FnHeader) -> FnHeader {
         noop_fold_fn_header(header, self)
     }
@@ -133,10 +121,6 @@ pub trait Folder : Sized {
         e.map(|e| noop_fold_expr(e, self))
     }
 
-    fn fold_range_end(&mut self, re: RangeEnd) -> RangeEnd {
-        noop_fold_range_end(re, self)
-    }
-
     fn fold_opt_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> {
         noop_fold_opt_expr(e, self)
     }
@@ -172,10 +156,6 @@ pub trait Folder : Sized {
         noop_fold_foreign_mod(nm, self)
     }
 
-    fn fold_global_asm(&mut self, ga: P<GlobalAsm>) -> P<GlobalAsm> {
-        noop_fold_global_asm(ga, self)
-    }
-
     fn fold_variant(&mut self, v: Variant) -> Variant {
         noop_fold_variant(v, self)
     }
@@ -184,10 +164,6 @@ pub trait Folder : Sized {
         noop_fold_ident(i, self)
     }
 
-    fn fold_usize(&mut self, i: usize) -> usize {
-        noop_fold_usize(i, self)
-    }
-
     fn fold_path(&mut self, p: Path) -> Path {
         noop_fold_path(p, self)
     }
@@ -281,10 +257,6 @@ pub trait Folder : Sized {
         noop_fold_interpolated(nt, self)
     }
 
-    fn fold_opt_bounds(&mut self, b: Option<GenericBounds>) -> Option<GenericBounds> {
-        noop_fold_opt_bounds(b, self)
-    }
-
     fn fold_bounds(&mut self, b: GenericBounds) -> GenericBounds {
         noop_fold_bounds(b, self)
     }
@@ -324,10 +296,6 @@ pub trait Folder : Sized {
     }
 }
 
-pub fn noop_fold_meta_items<T: Folder>(meta_items: Vec<MetaItem>, fld: &mut T) -> Vec<MetaItem> {
-    meta_items.move_map(|x| fld.fold_meta_item(x))
-}
-
 pub fn noop_fold_use_tree<T: Folder>(use_tree: UseTree, fld: &mut T) -> UseTree {
     UseTree {
         span: fld.new_span(use_tree.span),
@@ -430,11 +398,6 @@ pub fn noop_fold_foreign_mod<T: Folder>(ForeignMod {abi, items}: ForeignMod,
     }
 }
 
-pub fn noop_fold_global_asm<T: Folder>(ga: P<GlobalAsm>,
-                                       _: &mut T) -> P<GlobalAsm> {
-    ga
-}
-
 pub fn noop_fold_variant<T: Folder>(v: Variant, fld: &mut T) -> Variant {
     Spanned {
         node: Variant_ {
@@ -451,10 +414,6 @@ pub fn noop_fold_ident<T: Folder>(ident: Ident, fld: &mut T) -> Ident {
     Ident::new(ident.name, fld.new_span(ident.span))
 }
 
-pub fn noop_fold_usize<T: Folder>(i: usize, _: &mut T) -> usize {
-    i
-}
-
 pub fn noop_fold_path<T: Folder>(Path { segments, span }: Path, fld: &mut T) -> Path {
     Path {
         segments: segments.move_map(|PathSegment { ident, id, args }| PathSegment {
@@ -873,11 +832,6 @@ pub fn noop_fold_mt<T: Folder>(MutTy {ty, mutbl}: MutTy, folder: &mut T) -> MutT
     }
 }
 
-pub fn noop_fold_opt_bounds<T: Folder>(b: Option<GenericBounds>, folder: &mut T)
-                                       -> Option<GenericBounds> {
-    b.map(|bounds| folder.fold_bounds(bounds))
-}
-
 fn noop_fold_bounds<T: Folder>(bounds: GenericBounds, folder: &mut T)
                           -> GenericBounds {
     bounds.move_map(|bound| folder.fold_param_bound(bound))
@@ -913,7 +867,7 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
         }
         ItemKind::Mod(m) => ItemKind::Mod(folder.fold_mod(m)),
         ItemKind::ForeignMod(nm) => ItemKind::ForeignMod(folder.fold_foreign_mod(nm)),
-        ItemKind::GlobalAsm(ga) => ItemKind::GlobalAsm(folder.fold_global_asm(ga)),
+        ItemKind::GlobalAsm(ga) => ItemKind::GlobalAsm(ga),
         ItemKind::Ty(t, generics) => {
             ItemKind::Ty(folder.fold_ty(t), folder.fold_generics(generics))
         }
@@ -1071,34 +1025,27 @@ pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, span}: Crate,
 
 // fold one item into possibly many items
 pub fn noop_fold_item<T: Folder>(i: P<Item>, folder: &mut T) -> SmallVec<[P<Item>; 1]> {
-    smallvec![i.map(|i| folder.fold_item_simple(i))]
-}
-
-// fold one item into exactly one item
-pub fn noop_fold_item_simple<T: Folder>(Item {id, ident, attrs, node, vis, span, tokens}: Item,
-                                        folder: &mut T) -> Item {
-    Item {
-        id: folder.new_id(id),
-        vis: folder.fold_vis(vis),
-        ident: folder.fold_ident(ident),
-        attrs: fold_attrs(attrs, folder),
-        node: folder.fold_item_kind(node),
-        span: folder.new_span(span),
-
-        // FIXME: if this is replaced with a call to `folder.fold_tts` it causes
-        //        an ICE during resolve... odd!
-        tokens,
-    }
+    smallvec![i.map(|i| {
+        let Item {id, ident, attrs, node, vis, span, tokens} = i;
+        Item {
+            id: folder.new_id(id),
+            vis: folder.fold_vis(vis),
+            ident: folder.fold_ident(ident),
+            attrs: fold_attrs(attrs, folder),
+            node: folder.fold_item_kind(node),
+            span: folder.new_span(span),
+
+            // FIXME: if this is replaced with a call to `folder.fold_tts` it causes
+            //        an ICE during resolve... odd!
+            tokens,
+        }
+    })]
 }
 
 pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T)
     -> SmallVec<[ForeignItem; 1]>
 {
-    smallvec![folder.fold_foreign_item_simple(ni)]
-}
-
-pub fn noop_fold_foreign_item_simple<T: Folder>(ni: ForeignItem, folder: &mut T) -> ForeignItem {
-    ForeignItem {
+    smallvec![ForeignItem {
         id: folder.new_id(ni.id),
         vis: folder.fold_vis(ni.vis),
         ident: folder.fold_ident(ni.ident),
@@ -1114,7 +1061,7 @@ pub fn noop_fold_foreign_item_simple<T: Folder>(ni: ForeignItem, folder: &mut T)
             ForeignItemKind::Macro(mac) => ForeignItemKind::Macro(folder.fold_mac(mac)),
         },
         span: folder.new_span(ni.span)
-    }
+    }]
 }
 
 pub fn noop_fold_method_sig<T: Folder>(sig: MethodSig, folder: &mut T) -> MethodSig {
@@ -1161,10 +1108,10 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
             }
             PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)),
             PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl),
-            PatKind::Range(e1, e2, Spanned { span, node: end }) => {
+            PatKind::Range(e1, e2, Spanned { span, node }) => {
                 PatKind::Range(folder.fold_expr(e1),
                                folder.fold_expr(e2),
-                               Spanned { span, node: folder.fold_range_end(end) })
+                               Spanned { span, node })
             },
             PatKind::Slice(before, slice, after) => {
                 PatKind::Slice(before.move_map(|x| folder.fold_pat(x)),
@@ -1178,10 +1125,6 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
     })
 }
 
-pub fn noop_fold_range_end<T: Folder>(end: RangeEnd, _folder: &mut T) -> RangeEnd {
-    end
-}
-
 pub fn noop_fold_anon_const<T: Folder>(constant: AnonConst, folder: &mut T) -> AnonConst {
     let AnonConst {id, value} = constant;
     AnonConst {

From eea2dfe76f7afea0df3ae99fcdd30f1afbf4402d Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Tue, 5 Feb 2019 15:11:10 +1100
Subject: [PATCH 03/10] Fold some overlooked spans.

---
 src/libsyntax/fold.rs | 27 ++++++++++++++++-----------
 1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 6f856f63d6c7f..c01ac3107b6d8 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -734,7 +734,7 @@ pub fn noop_fold_where_clause<T: Folder>(
         predicates: predicates.move_map(|predicate| {
             fld.fold_where_predicate(predicate)
         }),
-        span,
+        span: fld.new_span(span),
     }
 }
 
@@ -1111,7 +1111,7 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
             PatKind::Range(e1, e2, Spanned { span, node }) => {
                 PatKind::Range(folder.fold_expr(e1),
                                folder.fold_expr(e2),
-                               Spanned { span, node })
+                               Spanned { node, span: folder.new_span(span) })
             },
             PatKind::Slice(before, slice, after) => {
                 PatKind::Slice(before.move_map(|x| folder.fold_pat(x)),
@@ -1342,15 +1342,20 @@ pub fn noop_fold_stmt_kind<T: Folder>(node: StmtKind, folder: &mut T) -> SmallVe
     }
 }
 
-pub fn noop_fold_vis<T: Folder>(vis: Visibility, folder: &mut T) -> Visibility {
-    match vis.node {
-        VisibilityKind::Restricted { path, id } => {
-            respan(vis.span, VisibilityKind::Restricted {
-                path: path.map(|path| folder.fold_path(path)),
-                id: folder.new_id(id),
-            })
-        }
-        _ => vis,
+pub fn noop_fold_vis<T: Folder>(Spanned { node, span }: Visibility, folder: &mut T) -> Visibility {
+    Visibility {
+        node: match node {
+            VisibilityKind::Public => VisibilityKind::Public,
+            VisibilityKind::Crate(sugar) => VisibilityKind::Crate(sugar),
+            VisibilityKind::Restricted { path, id } => {
+                VisibilityKind::Restricted {
+                    path: path.map(|path| folder.fold_path(path)),
+                    id: folder.new_id(id),
+                }
+            }
+            VisibilityKind::Inherited => VisibilityKind::Inherited,
+        },
+        span: folder.new_span(span),
     }
 }
 

From f97e896fd669b61051027d76d6dccb89c72c4c52 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Tue, 5 Feb 2019 15:11:27 +1100
Subject: [PATCH 04/10] Simplify `fold_attribute`.

It doesn't need to return an `Option`.
---
 src/libsyntax/ext/expand.rs |  8 +++-----
 src/libsyntax/fold.rs       | 16 ++++++----------
 2 files changed, 9 insertions(+), 15 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 957187ec71c61..72e0a86bf5909 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -1465,7 +1465,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
         noop_fold_generic_param(param, self)
     }
 
-    fn fold_attribute(&mut self, at: ast::Attribute) -> Option<ast::Attribute> {
+    fn fold_attribute(&mut self, at: ast::Attribute) -> ast::Attribute {
         // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
         // contents="file contents")]` attributes
         if !at.check_name("doc") {
@@ -1585,10 +1585,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
 
             let meta = attr::mk_list_item(DUMMY_SP, Ident::from_str("doc"), items);
             match at.style {
-                ast::AttrStyle::Inner =>
-                    Some(attr::mk_spanned_attr_inner(at.span, at.id, meta)),
-                ast::AttrStyle::Outer =>
-                    Some(attr::mk_spanned_attr_outer(at.span, at.id, meta)),
+                ast::AttrStyle::Inner => attr::mk_spanned_attr_inner(at.span, at.id, meta),
+                ast::AttrStyle::Outer => attr::mk_spanned_attr_outer(at.span, at.id, meta),
             }
         } else {
             noop_fold_attribute(at, self)
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index c01ac3107b6d8..1ab1de1ba5c33 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -209,7 +209,7 @@ pub trait Folder : Sized {
         noop_fold_label(label, self)
     }
 
-    fn fold_attribute(&mut self, at: Attribute) -> Option<Attribute> {
+    fn fold_attribute(&mut self, at: Attribute) -> Attribute {
         noop_fold_attribute(at, self)
     }
 
@@ -313,7 +313,7 @@ pub fn noop_fold_use_tree<T: Folder>(use_tree: UseTree, fld: &mut T) -> UseTree
 }
 
 pub fn fold_attrs<T: Folder>(attrs: Vec<Attribute>, fld: &mut T) -> Vec<Attribute> {
-    attrs.move_flat_map(|x| fld.fold_attribute(x))
+    attrs.move_map(|x| fld.fold_attribute(x))
 }
 
 pub fn fold_thin_attrs<T: Folder>(attrs: ThinVec<Attribute>, fld: &mut T) -> ThinVec<Attribute> {
@@ -485,15 +485,15 @@ pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
     })
 }
 
-pub fn noop_fold_attribute<T: Folder>(attr: Attribute, fld: &mut T) -> Option<Attribute> {
-    Some(Attribute {
+pub fn noop_fold_attribute<T: Folder>(attr: Attribute, fld: &mut T) -> Attribute {
+    Attribute {
         id: attr.id,
         style: attr.style,
         path: fld.fold_path(attr.path),
         tokens: fld.fold_tts(attr.tokens),
         is_sugared_doc: attr.is_sugared_doc,
         span: fld.new_span(attr.span),
-    })
+    }
 }
 
 pub fn noop_fold_mac<T: Folder>(Spanned {node, span}: Mac, fld: &mut T) -> Mac {
@@ -678,14 +678,10 @@ pub fn noop_fold_param_bound<T>(pb: GenericBound, fld: &mut T) -> GenericBound w
 }
 
 pub fn noop_fold_generic_param<T: Folder>(param: GenericParam, fld: &mut T) -> GenericParam {
-    let attrs: Vec<_> = param.attrs.into();
     GenericParam {
         ident: fld.fold_ident(param.ident),
         id: fld.new_id(param.id),
-        attrs: attrs.into_iter()
-                    .flat_map(|x| fld.fold_attribute(x).into_iter())
-                    .collect::<Vec<_>>()
-                    .into(),
+        attrs: fold_thin_attrs(param.attrs, fld),
         bounds: param.bounds.move_map(|l| noop_fold_param_bound(l, fld)),
         kind: match param.kind {
             GenericParamKind::Lifetime => GenericParamKind::Lifetime,

From 8909f70a3249f61be10627fc6b6634dedf66f77a Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Tue, 5 Feb 2019 15:11:52 +1100
Subject: [PATCH 05/10] Change `fold_qpath` to `fold_qself`.

It's simpler that way.
---
 src/libsyntax/fold.rs | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 1ab1de1ba5c33..a7e835fbd45f2 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -168,8 +168,8 @@ pub trait Folder : Sized {
         noop_fold_path(p, self)
     }
 
-    fn fold_qpath(&mut self, qs: Option<QSelf>, p: Path) -> (Option<QSelf>, Path) {
-        noop_fold_qpath(qs, p, self)
+    fn fold_qself(&mut self, qs: Option<QSelf>) -> Option<QSelf> {
+        noop_fold_qself(qs, self)
     }
 
     fn fold_generic_args(&mut self, p: GenericArgs) -> GenericArgs {
@@ -367,8 +367,7 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
             TyKind::Tup(tys) => TyKind::Tup(tys.move_map(|ty| fld.fold_ty(ty))),
             TyKind::Paren(ty) => TyKind::Paren(fld.fold_ty(ty)),
             TyKind::Path(qself, path) => {
-                let (qself, path) = fld.fold_qpath(qself, path);
-                TyKind::Path(qself, path)
+                TyKind::Path(fld.fold_qself(qself), fld.fold_path(path))
             }
             TyKind::Array(ty, length) => {
                 TyKind::Array(fld.fold_ty(ty), fld.fold_anon_const(length))
@@ -425,17 +424,14 @@ pub fn noop_fold_path<T: Folder>(Path { segments, span }: Path, fld: &mut T) ->
     }
 }
 
-pub fn noop_fold_qpath<T: Folder>(qself: Option<QSelf>,
-                                  path: Path,
-                                  fld: &mut T) -> (Option<QSelf>, Path) {
-    let qself = qself.map(|QSelf { ty, path_span, position }| {
+pub fn noop_fold_qself<T: Folder>(qself: Option<QSelf>, fld: &mut T) -> Option<QSelf> {
+    qself.map(|QSelf { ty, path_span, position }| {
         QSelf {
             ty: fld.fold_ty(ty),
             path_span: fld.new_span(path_span),
             position,
         }
-    });
-    (qself, fld.fold_path(path))
+    })
 }
 
 pub fn noop_fold_generic_args<T: Folder>(generic_args: GenericArgs, fld: &mut T) -> GenericArgs
@@ -1083,8 +1079,7 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
                         pats.move_map(|x| folder.fold_pat(x)), ddpos)
             }
             PatKind::Path(qself, pth) => {
-                let (qself, pth) = folder.fold_qpath(qself, pth);
-                PatKind::Path(qself, pth)
+                PatKind::Path(folder.fold_qself(qself), folder.fold_path(pth))
             }
             PatKind::Struct(pth, fields, etc) => {
                 let pth = folder.fold_path(pth);
@@ -1251,8 +1246,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                                 lim)
             }
             ExprKind::Path(qself, path) => {
-                let (qself, path) = folder.fold_qpath(qself, path);
-                ExprKind::Path(qself, path)
+                ExprKind::Path(folder.fold_qself(qself), folder.fold_path(path))
             }
             ExprKind::Break(opt_label, opt_expr) => {
                 ExprKind::Break(opt_label.map(|label| folder.fold_label(label)),

From 473095345b74b4d6b836d3ab2e3ace0c6719b20f Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Tue, 5 Feb 2019 15:12:15 +1100
Subject: [PATCH 06/10] Neaten up `fold_crate`.

---
 src/libsyntax/fold.rs | 39 +++++++++++++++------------------------
 1 file changed, 15 insertions(+), 24 deletions(-)

diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index a7e835fbd45f2..567175b84df1a 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -980,7 +980,7 @@ pub fn noop_fold_mod<T: Folder>(Mod {inner, items, inline}: Mod, folder: &mut T)
 
 pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, span}: Crate,
                                   folder: &mut T) -> Crate {
-    let mut items = folder.fold_item(P(Item {
+    let item = P(Item {
         ident: keywords::Invalid.ident(),
         attrs,
         id: DUMMY_NODE_ID,
@@ -988,30 +988,21 @@ pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, span}: Crate,
         span,
         node: ItemKind::Mod(module),
         tokens: None,
-    })).into_iter();
-
-    let (module, attrs, span) = match items.next() {
-        Some(item) => {
-            assert!(items.next().is_none(),
-                    "a crate cannot expand to more than one item");
-            item.and_then(|Item { attrs, span, node, .. }| {
-                match node {
-                    ItemKind::Mod(m) => (m, attrs, span),
-                    _ => panic!("fold converted a module to not a module"),
-                }
-            })
+    });
+    let items = folder.fold_item(item);
+
+    let len = items.len();
+    if len == 0 {
+        let module = Mod { inner: span, items: vec![], inline: true };
+        Crate { module, attrs: vec![], span }
+    } else if len == 1 {
+        let Item { attrs, span, node, .. } = items.into_iter().next().unwrap().into_inner();
+        match node {
+            ItemKind::Mod(module) => Crate { module, attrs, span },
+            _ => panic!("fold converted a module to not a module"),
         }
-        None => (Mod {
-            inner: span,
-            items: vec![],
-            inline: true,
-        }, vec![], span)
-    };
-
-    Crate {
-        module,
-        attrs,
-        span,
+    } else {
+        panic!("a crate cannot expand to more than one item");
     }
 }
 

From 372fe84a8349ab4a8693d656bd786a5a47e22a56 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Tue, 5 Feb 2019 15:13:12 +1100
Subject: [PATCH 07/10] Streamline `Folder` some more.

By eliminating some unnecessary methods, and moving/renaming some
functions that look like they might be methods but aren't.
---
 src/libsyntax/fold.rs | 82 ++++++++++++++++++++-----------------------
 1 file changed, 39 insertions(+), 43 deletions(-)

diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 567175b84df1a..5fb0132ad4566 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -125,10 +125,6 @@ pub trait Folder : Sized {
         noop_fold_opt_expr(e, self)
     }
 
-    fn fold_exprs(&mut self, es: Vec<P<Expr>>) -> Vec<P<Expr>> {
-        noop_fold_exprs(es, self)
-    }
-
     fn fold_generic_arg(&mut self, arg: GenericArg) -> GenericArg {
         match arg {
             GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.fold_lifetime(lt)),
@@ -257,10 +253,6 @@ pub trait Folder : Sized {
         noop_fold_interpolated(nt, self)
     }
 
-    fn fold_bounds(&mut self, b: GenericBounds) -> GenericBounds {
-        noop_fold_bounds(b, self)
-    }
-
     fn fold_param_bound(&mut self, tpb: GenericBound) -> GenericBound {
         noop_fold_param_bound(tpb, self)
     }
@@ -296,6 +288,34 @@ pub trait Folder : Sized {
     }
 }
 
+// No `noop_` prefix because there isn't a corresponding method in `Folder`.
+fn fold_attrs<T: Folder>(attrs: Vec<Attribute>, fld: &mut T) -> Vec<Attribute> {
+    attrs.move_map(|x| fld.fold_attribute(x))
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `Folder`.
+fn fold_thin_attrs<T: Folder>(attrs: ThinVec<Attribute>, fld: &mut T) -> ThinVec<Attribute> {
+    fold_attrs(attrs.into(), fld).into()
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `Folder`.
+fn fold_exprs<T: Folder>(es: Vec<P<Expr>>, fld: &mut T) -> Vec<P<Expr>> {
+    es.move_flat_map(|e| fld.fold_opt_expr(e))
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `Folder`.
+fn fold_bounds<T: Folder>(bounds: GenericBounds, folder: &mut T) -> GenericBounds {
+    bounds.move_map(|bound| folder.fold_param_bound(bound))
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `Folder`.
+fn fold_method_sig<T: Folder>(sig: MethodSig, folder: &mut T) -> MethodSig {
+    MethodSig {
+        header: folder.fold_fn_header(sig.header),
+        decl: folder.fold_fn_decl(sig.decl)
+    }
+}
+
 pub fn noop_fold_use_tree<T: Folder>(use_tree: UseTree, fld: &mut T) -> UseTree {
     UseTree {
         span: fld.new_span(use_tree.span),
@@ -312,14 +332,6 @@ pub fn noop_fold_use_tree<T: Folder>(use_tree: UseTree, fld: &mut T) -> UseTree
     }
 }
 
-pub fn fold_attrs<T: Folder>(attrs: Vec<Attribute>, fld: &mut T) -> Vec<Attribute> {
-    attrs.move_map(|x| fld.fold_attribute(x))
-}
-
-pub fn fold_thin_attrs<T: Folder>(attrs: ThinVec<Attribute>, fld: &mut T) -> ThinVec<Attribute> {
-    fold_attrs(attrs.into(), fld).into()
-}
-
 pub fn noop_fold_arm<T: Folder>(Arm {attrs, pats, guard, body}: Arm,
     fld: &mut T) -> Arm {
     Arm {
@@ -824,11 +836,6 @@ pub fn noop_fold_mt<T: Folder>(MutTy {ty, mutbl}: MutTy, folder: &mut T) -> MutT
     }
 }
 
-fn noop_fold_bounds<T: Folder>(bounds: GenericBounds, folder: &mut T)
-                          -> GenericBounds {
-    bounds.move_map(|bound| folder.fold_param_bound(bound))
-}
-
 pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
     b.map(|Block {id, stmts, rules, span}| Block {
         id: folder.new_id(id),
@@ -864,7 +871,7 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
             ItemKind::Ty(folder.fold_ty(t), folder.fold_generics(generics))
         }
         ItemKind::Existential(bounds, generics) => ItemKind::Existential(
-            folder.fold_bounds(bounds),
+            fold_bounds(bounds, folder),
             folder.fold_generics(generics),
         ),
         ItemKind::Enum(enum_definition, generics) => {
@@ -899,12 +906,12 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
             is_auto,
             unsafety,
             folder.fold_generics(generics),
-            folder.fold_bounds(bounds),
+            fold_bounds(bounds, folder),
             items.move_flat_map(|item| folder.fold_trait_item(item)),
         ),
         ItemKind::TraitAlias(generics, bounds) => ItemKind::TraitAlias(
             folder.fold_generics(generics),
-            folder.fold_bounds(bounds)),
+            fold_bounds(bounds, folder)),
         ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)),
         ItemKind::MacroDef(def) => ItemKind::MacroDef(folder.fold_macro_def(def)),
     }
@@ -922,11 +929,11 @@ pub fn noop_fold_trait_item<T: Folder>(i: TraitItem, folder: &mut T) -> SmallVec
                                default.map(|x| folder.fold_expr(x)))
             }
             TraitItemKind::Method(sig, body) => {
-                TraitItemKind::Method(noop_fold_method_sig(sig, folder),
+                TraitItemKind::Method(fold_method_sig(sig, folder),
                                 body.map(|x| folder.fold_block(x)))
             }
             TraitItemKind::Type(bounds, default) => {
-                TraitItemKind::Type(folder.fold_bounds(bounds),
+                TraitItemKind::Type(fold_bounds(bounds, folder),
                               default.map(|x| folder.fold_ty(x)))
             }
             TraitItemKind::Macro(mac) => {
@@ -951,12 +958,12 @@ pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T)-> SmallVec<[I
                 ImplItemKind::Const(folder.fold_ty(ty), folder.fold_expr(expr))
             }
             ImplItemKind::Method(sig, body) => {
-                ImplItemKind::Method(noop_fold_method_sig(sig, folder),
+                ImplItemKind::Method(fold_method_sig(sig, folder),
                                folder.fold_block(body))
             }
             ImplItemKind::Type(ty) => ImplItemKind::Type(folder.fold_ty(ty)),
             ImplItemKind::Existential(bounds) => {
-                ImplItemKind::Existential(folder.fold_bounds(bounds))
+                ImplItemKind::Existential(fold_bounds(bounds, folder))
             },
             ImplItemKind::Macro(mac) => ImplItemKind::Macro(folder.fold_mac(mac))
         },
@@ -1047,13 +1054,6 @@ pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T)
     }]
 }
 
-pub fn noop_fold_method_sig<T: Folder>(sig: MethodSig, folder: &mut T) -> MethodSig {
-    MethodSig {
-        header: folder.fold_fn_header(sig.header),
-        decl: folder.fold_fn_decl(sig.decl)
-    }
-}
-
 pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
     p.map(|Pat {id, node, span}| Pat {
         id: folder.new_id(id),
@@ -1125,15 +1125,15 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                 ExprKind::ObsoleteInPlace(folder.fold_expr(a), folder.fold_expr(b))
             }
             ExprKind::Array(exprs) => {
-                ExprKind::Array(folder.fold_exprs(exprs))
+                ExprKind::Array(fold_exprs(exprs, folder))
             }
             ExprKind::Repeat(expr, count) => {
                 ExprKind::Repeat(folder.fold_expr(expr), folder.fold_anon_const(count))
             }
-            ExprKind::Tup(exprs) => ExprKind::Tup(folder.fold_exprs(exprs)),
+            ExprKind::Tup(exprs) => ExprKind::Tup(fold_exprs(exprs, folder)),
             ExprKind::Call(f, args) => {
                 ExprKind::Call(folder.fold_expr(f),
-                         folder.fold_exprs(args))
+                         fold_exprs(args, folder))
             }
             ExprKind::MethodCall(seg, args) => {
                 ExprKind::MethodCall(
@@ -1144,7 +1144,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                             args.map(|args| folder.fold_generic_args(args))
                         }),
                     },
-                    folder.fold_exprs(args))
+                    fold_exprs(args, folder))
             }
             ExprKind::Binary(binop, lhs, rhs) => {
                 ExprKind::Binary(binop,
@@ -1294,10 +1294,6 @@ pub fn noop_fold_opt_expr<T: Folder>(e: P<Expr>, folder: &mut T) -> Option<P<Exp
     Some(folder.fold_expr(e))
 }
 
-pub fn noop_fold_exprs<T: Folder>(es: Vec<P<Expr>>, folder: &mut T) -> Vec<P<Expr>> {
-    es.move_flat_map(|e| folder.fold_opt_expr(e))
-}
-
 pub fn noop_fold_stmt<T: Folder>(Stmt {node, span, id}: Stmt, folder: &mut T) -> SmallVec<[Stmt; 1]>
 {
     let id = folder.new_id(id);

From 970b5d189af48dd6ec26e90bb8d6d236824edf4b Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Tue, 5 Feb 2019 15:18:29 +1100
Subject: [PATCH 08/10] Various improvements in `Folder` impls.

---
 src/libsyntax/config.rs           | 44 +++++++++----------------------
 src/libsyntax/ext/expand.rs       |  5 +---
 src/libsyntax/ext/placeholders.rs | 15 ++++-------
 3 files changed, 18 insertions(+), 46 deletions(-)

diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index 2930ce079c848..b35730bf2381b 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -13,6 +13,7 @@ use edition::Edition;
 use parse::{token, ParseSess};
 use smallvec::SmallVec;
 use errors::Applicability;
+use util::move_map::MoveMap;
 
 use ptr::P;
 
@@ -220,19 +221,19 @@ impl<'a> StripUnconfigured<'a> {
     pub fn configure_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
         ast::ForeignMod {
             abi: foreign_mod.abi,
-            items: foreign_mod.items.into_iter().filter_map(|item| self.configure(item)).collect(),
+            items: foreign_mod.items.move_flat_map(|item| self.configure(item)),
         }
     }
 
     fn configure_variant_data(&mut self, vdata: ast::VariantData) -> ast::VariantData {
         match vdata {
             ast::VariantData::Struct(fields, id) => {
-                let fields = fields.into_iter().filter_map(|field| self.configure(field));
-                ast::VariantData::Struct(fields.collect(), id)
+                let fields = fields.move_flat_map(|field| self.configure(field));
+                ast::VariantData::Struct(fields, id)
             }
             ast::VariantData::Tuple(fields, id) => {
-                let fields = fields.into_iter().filter_map(|field| self.configure(field));
-                ast::VariantData::Tuple(fields.collect(), id)
+                let fields = fields.move_flat_map(|field| self.configure(field));
+                ast::VariantData::Tuple(fields, id)
             }
             ast::VariantData::Unit(id) => ast::VariantData::Unit(id)
         }
@@ -247,7 +248,7 @@ impl<'a> StripUnconfigured<'a> {
                 ast::ItemKind::Union(self.configure_variant_data(def), generics)
             }
             ast::ItemKind::Enum(def, generics) => {
-                let variants = def.variants.into_iter().filter_map(|v| {
+                let variants = def.variants.move_flat_map(|v| {
                     self.configure(v).map(|v| {
                         Spanned {
                             node: ast::Variant_ {
@@ -260,9 +261,7 @@ impl<'a> StripUnconfigured<'a> {
                         }
                     })
                 });
-                ast::ItemKind::Enum(ast::EnumDef {
-                    variants: variants.collect(),
-                }, generics)
+                ast::ItemKind::Enum(ast::EnumDef { variants }, generics)
             }
             item => item,
         }
@@ -271,15 +270,11 @@ impl<'a> StripUnconfigured<'a> {
     pub fn configure_expr_kind(&mut self, expr_kind: ast::ExprKind) -> ast::ExprKind {
         match expr_kind {
             ast::ExprKind::Match(m, arms) => {
-                let arms = arms.into_iter().filter_map(|a| self.configure(a)).collect();
+                let arms = arms.move_flat_map(|a| self.configure(a));
                 ast::ExprKind::Match(m, arms)
             }
             ast::ExprKind::Struct(path, fields, base) => {
-                let fields = fields.into_iter()
-                    .filter_map(|field| {
-                        self.configure(field)
-                    })
-                    .collect();
+                let fields = fields.move_flat_map(|field| self.configure(field));
                 ast::ExprKind::Struct(path, fields, base)
             }
             _ => expr_kind,
@@ -304,22 +299,10 @@ impl<'a> StripUnconfigured<'a> {
         self.process_cfg_attrs(expr)
     }
 
-    pub fn configure_stmt(&mut self, stmt: ast::Stmt) -> Option<ast::Stmt> {
-        self.configure(stmt)
-    }
-
-    pub fn configure_struct_expr_field(&mut self, field: ast::Field) -> Option<ast::Field> {
-        self.configure(field)
-    }
-
     pub fn configure_pat(&mut self, pattern: P<ast::Pat>) -> P<ast::Pat> {
         pattern.map(|mut pattern| {
             if let ast::PatKind::Struct(path, fields, etc) = pattern.node {
-                let fields = fields.into_iter()
-                    .filter_map(|field| {
-                        self.configure(field)
-                    })
-                    .collect();
+                let fields = fields.move_flat_map(|field| self.configure(field));
                 pattern.node = ast::PatKind::Struct(path, fields, etc);
             }
             pattern
@@ -367,10 +350,7 @@ impl<'a> fold::Folder for StripUnconfigured<'a> {
     }
 
     fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
-        match self.configure_stmt(stmt) {
-            Some(stmt) => fold::noop_fold_stmt(stmt, self),
-            None => return SmallVec::new(),
-        }
+        fold::noop_fold_stmt(configure!(self, stmt), self)
     }
 
     fn fold_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 72e0a86bf5909..2effd910e8545 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -1247,10 +1247,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
     }
 
     fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
-        let mut stmt = match self.cfg.configure_stmt(stmt) {
-            Some(stmt) => stmt,
-            None => return SmallVec::new(),
-        };
+        let mut stmt = configure!(self, stmt);
 
         // we'll expand attributes on expressions separately
         if !stmt.is_expr() {
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index 3b0402d910a85..0928bc804041d 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -181,17 +181,12 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
 
     fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
         noop_fold_block(block, self).map(|mut block| {
-            let mut remaining_stmts = block.stmts.len();
-
-            block.stmts = block.stmts.move_flat_map(|mut stmt| {
-                remaining_stmts -= 1;
-
+            block.stmts = block.stmts.move_map(|mut stmt| {
                 if self.monotonic {
                     assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
                     stmt.id = self.cx.resolver.next_node_id();
                 }
-
-                Some(stmt)
+                stmt
             });
 
             block
@@ -200,9 +195,9 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
 
     fn fold_mod(&mut self, module: ast::Mod) -> ast::Mod {
         let mut module = noop_fold_mod(module, self);
-        module.items = module.items.move_flat_map(|item| match item.node {
-            ast::ItemKind::Mac(_) if !self.cx.ecfg.keep_macs => None, // remove macro definitions
-            _ => Some(item),
+        module.items.retain(|item| match item.node {
+            ast::ItemKind::Mac(_) if !self.cx.ecfg.keep_macs => false, // remove macro definitions
+            _ => true,
         });
         module
     }

From 9fcb1658ab13a7f722e4747c5a4b691291e88a3b Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Tue, 5 Feb 2019 15:20:55 +1100
Subject: [PATCH 09/10] Overhaul `syntax::fold::Folder`.

This commit changes `syntax::fold::Folder` from a functional style
(where most methods take a `T` and produce a new `T`) to a more
imperative style (where most methods take and modify a `&mut T`), and
renames it `syntax::mut_visit::MutVisitor`.

The first benefit is speed. The functional style does not require any
reallocations, due to the use of `P::map` and
`MoveMap::move_{,flat_}map`. However, every field in the AST must be
overwritten; even those fields that are unchanged are overwritten with
the same value. This causes a lot of unnecessary memory writes. The
imperative style reduces instruction counts by 1--3% across a wide range
of workloads, particularly incremental workloads.

The second benefit is conciseness; the imperative style is usually more
concise. E.g. compare the old functional style:
```
fn fold_abc(&mut self, abc: ABC) {
    ABC {
        a: fold_a(abc.a),
        b: fold_b(abc.b),
        c: abc.c,
    }
}
```
with the imperative style:
```
fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) {
    visit_a(a);
    visit_b(b);
}
```
(The reductions get larger in more complex examples.)

Overall, the patch removes over 200 lines of code -- even though the new
code has more comments -- and a lot of the remaining lines have fewer
characters.

Some notes:

- The old style used methods called `fold_*`. The new style mostly uses
  methods called `visit_*`, but there are a few methods that map a `T`
  to something other than a `T`, which are called `flat_map_*` (`T` maps
  to multiple `T`s) or `filter_map_*` (`T` maps to 0 or 1 `T`s).

- `move_map.rs`/`MoveMap`/`move_map`/`move_flat_map` are renamed
  `map_in_place.rs`/`MapInPlace`/`map_in_place`/`flat_map_in_place` to
  reflect their slightly changed signatures.

- Although this commit renames the `fold` module as `mut_visit`, it
  keeps it in the `fold.rs` file, so as not to confuse git. The next
  commit will rename the file.
---
 src/librustc_allocator/expand.rs              |   27 +-
 src/librustc_data_structures/thin_vec.rs      |    9 +
 src/librustc_driver/driver.rs                 |   12 +-
 src/librustc_driver/lib.rs                    |    9 +-
 src/librustc_driver/pretty.rs                 |   42 +-
 src/libsyntax/attr/mod.rs                     |   60 +-
 src/libsyntax/config.rs                       |  166 +-
 src/libsyntax/ext/base.rs                     |   48 +-
 src/libsyntax/ext/derive.rs                   |    7 +-
 src/libsyntax/ext/expand.rs                   |  290 +--
 src/libsyntax/ext/placeholders.rs             |   79 +-
 src/libsyntax/ext/tt/transcribe.rs            |    6 +-
 src/libsyntax/fold.rs                         | 2002 ++++++++---------
 src/libsyntax/lib.rs                          |    4 +-
 src/libsyntax/parse/parser.rs                 |    3 +-
 src/libsyntax/parse/token.rs                  |    2 +-
 src/libsyntax/test.rs                         |   64 +-
 src/libsyntax/tokenstream.rs                  |    2 +-
 .../util/{move_map.rs => map_in_place.rs}     |   29 +-
 src/libsyntax_ext/deriving/generic/mod.rs     |   12 +-
 src/libsyntax_ext/proc_macro_decls.rs         |    4 +-
 .../pprust-expr-roundtrip.rs                  |   52 +-
 src/test/ui/issues/issue-49934.rs             |    4 +-
 23 files changed, 1417 insertions(+), 1516 deletions(-)
 rename src/libsyntax/util/{move_map.rs => map_in_place.rs} (82%)

diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs
index 73a35c7cdcd5f..1fb1794d5147d 100644
--- a/src/librustc_allocator/expand.rs
+++ b/src/librustc_allocator/expand.rs
@@ -16,7 +16,7 @@ use syntax::{
         expand::ExpansionConfig,
         hygiene::{self, Mark, SyntaxContext},
     },
-    fold::{self, Folder},
+    mut_visit::{self, MutVisitor},
     parse::ParseSess,
     ptr::P,
     symbol::Symbol
@@ -28,10 +28,10 @@ use {AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS};
 pub fn modify(
     sess: &ParseSess,
     resolver: &mut dyn Resolver,
-    krate: Crate,
+    krate: &mut Crate,
     crate_name: String,
     handler: &rustc_errors::Handler,
-) -> ast::Crate {
+) {
     ExpandAllocatorDirectives {
         handler,
         sess,
@@ -39,7 +39,7 @@ pub fn modify(
         found: false,
         crate_name: Some(crate_name),
         in_submod: -1, // -1 to account for the "root" module
-    }.fold_crate(krate)
+    }.visit_crate(krate);
 }
 
 struct ExpandAllocatorDirectives<'a> {
@@ -54,14 +54,14 @@ struct ExpandAllocatorDirectives<'a> {
     in_submod: isize,
 }
 
-impl<'a> Folder for ExpandAllocatorDirectives<'a> {
-    fn fold_item(&mut self, item: P<Item>) -> SmallVec<[P<Item>; 1]> {
+impl<'a> MutVisitor for ExpandAllocatorDirectives<'a> {
+    fn flat_map_item(&mut self, item: P<Item>) -> SmallVec<[P<Item>; 1]> {
         debug!("in submodule {}", self.in_submod);
 
         let name = if attr::contains_name(&item.attrs, "global_allocator") {
             "global_allocator"
         } else {
-            return fold::noop_fold_item(item, self);
+            return mut_visit::noop_flat_map_item(item, self);
         };
         match item.node {
             ItemKind::Static(..) => {}
@@ -139,25 +139,24 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> {
         let name = f.kind.fn_name("allocator_abi");
         let allocator_abi = Ident::with_empty_ctxt(Symbol::gensym(&name));
         let module = f.cx.item_mod(span, span, allocator_abi, Vec::new(), items);
-        let module = f.cx.monotonic_expander().fold_item(module).pop().unwrap();
+        let module = f.cx.monotonic_expander().flat_map_item(module).pop().unwrap();
 
         // Return the item and new submodule
         smallvec![item, module]
     }
 
     // If we enter a submodule, take note.
-    fn fold_mod(&mut self, m: Mod) -> Mod {
+    fn visit_mod(&mut self, m: &mut Mod) {
         debug!("enter submodule");
         self.in_submod += 1;
-        let ret = fold::noop_fold_mod(m, self);
+        mut_visit::noop_visit_mod(m, self);
         self.in_submod -= 1;
         debug!("exit submodule");
-        ret
     }
 
-    // `fold_mac` is disabled by default. Enable it here.
-    fn fold_mac(&mut self, mac: Mac) -> Mac {
-        fold::noop_fold_mac(mac, self)
+    // `visit_mac` is disabled by default. Enable it here.
+    fn visit_mac(&mut self, mac: &mut Mac) {
+        mut_visit::noop_visit_mac(mac, self)
     }
 }
 
diff --git a/src/librustc_data_structures/thin_vec.rs b/src/librustc_data_structures/thin_vec.rs
index 359f9b7842da3..ed57c528f51e0 100644
--- a/src/librustc_data_structures/thin_vec.rs
+++ b/src/librustc_data_structures/thin_vec.rs
@@ -39,6 +39,15 @@ impl<T> ::std::ops::Deref for ThinVec<T> {
     }
 }
 
+impl<T> ::std::ops::DerefMut for ThinVec<T> {
+    fn deref_mut(&mut self) -> &mut [T] {
+        match *self {
+            ThinVec(None) => &mut [],
+            ThinVec(Some(ref mut vec)) => vec,
+        }
+    }
+}
+
 impl<T> Extend<T> for ThinVec<T> {
     fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
         match *self {
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index d3412ec2dd93d..4549b20899dd5 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -32,7 +32,7 @@ use rustc_typeck as typeck;
 use syntax::{self, ast, attr, diagnostics, visit};
 use syntax::early_buffered_lints::BufferedEarlyLint;
 use syntax::ext::base::ExtCtxt;
-use syntax::fold::Folder;
+use syntax::mut_visit::MutVisitor;
 use syntax::parse::{self, PResult};
 use syntax::util::node_count::NodeCounter;
 use syntax::util::lev_distance::find_best_match_for_name;
@@ -1000,12 +1000,12 @@ where
     });
     sess.profiler(|p| p.end_activity(ProfileCategory::Expansion));
 
-    krate = time(sess, "maybe building test harness", || {
+    time(sess, "maybe building test harness", || {
         syntax::test::modify_for_testing(
             &sess.parse_sess,
             &mut resolver,
             sess.opts.test,
-            krate,
+            &mut krate,
             sess.diagnostic(),
             &sess.features_untracked(),
         )
@@ -1014,7 +1014,7 @@ where
     // If we're actually rustdoc then there's no need to actually compile
     // anything, so switch everything to just looping
     if sess.opts.actually_rustdoc {
-        krate = ReplaceBodyWithLoop::new(sess).fold_crate(krate);
+        ReplaceBodyWithLoop::new(sess).visit_crate(&mut krate);
     }
 
     let (has_proc_macro_decls, has_global_allocator) = time(sess, "AST validation", || {
@@ -1045,11 +1045,11 @@ where
 
     if has_global_allocator {
         // Expand global allocators, which are treated as an in-tree proc macro
-        krate = time(sess, "creating allocators", || {
+        time(sess, "creating allocators", || {
             allocator::expand::modify(
                 &sess.parse_sess,
                 &mut resolver,
-                krate,
+                &mut krate,
                 crate_name.to_string(),
                 sess.diagnostic(),
             )
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index a95ce810ffaeb..d0dc7799c7b72 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -870,9 +870,9 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
                 control.after_hir_lowering.stop = Compilation::Stop;
 
                 control.after_parse.callback = box move |state| {
-                    state.krate = Some(pretty::fold_crate(state.session,
-                                                          state.krate.take().unwrap(),
-                                                          ppm));
+                    let mut krate = state.krate.take().unwrap();
+                    pretty::visit_crate(state.session, &mut krate, ppm);
+                    state.krate = Some(krate);
                 };
                 control.after_hir_lowering.callback = box move |state| {
                     pretty::print_after_hir_lowering(state.session,
@@ -891,7 +891,8 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
                 control.after_parse.stop = Compilation::Stop;
 
                 control.after_parse.callback = box move |state| {
-                    let krate = pretty::fold_crate(state.session, state.krate.take().unwrap(), ppm);
+                    let mut krate = state.krate.take().unwrap();
+                    pretty::visit_crate(state.session, &mut krate, ppm);
                     pretty::print_after_parsing(state.session,
                                                 state.input,
                                                 &krate,
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index d980c5a3d29c3..4caf2ec676f07 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -16,7 +16,7 @@ use rustc_metadata::cstore::CStore;
 use rustc_mir::util::{write_mir_pretty, write_mir_graphviz};
 
 use syntax::ast::{self, BlockCheckMode};
-use syntax::fold::{self, Folder};
+use syntax::mut_visit::{*, MutVisitor, visit_clobber};
 use syntax::print::{pprust};
 use syntax::print::pprust::PrintState;
 use syntax::ptr::P;
@@ -28,6 +28,7 @@ use smallvec::SmallVec;
 use std::cell::Cell;
 use std::fs::File;
 use std::io::{self, Write};
+use std::ops::DerefMut;
 use std::option;
 use std::path::Path;
 use std::str::FromStr;
@@ -703,42 +704,42 @@ impl<'a> ReplaceBodyWithLoop<'a> {
     }
 }
 
-impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> {
-    fn fold_item_kind(&mut self, i: ast::ItemKind) -> ast::ItemKind {
+impl<'a> MutVisitor for ReplaceBodyWithLoop<'a> {
+    fn visit_item_kind(&mut self, i: &mut ast::ItemKind) {
         let is_const = match i {
             ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true,
             ast::ItemKind::Fn(ref decl, ref header, _, _) =>
                 header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl),
             _ => false,
         };
-        self.run(is_const, |s| fold::noop_fold_item_kind(i, s))
+        self.run(is_const, |s| noop_visit_item_kind(i, s))
     }
 
-    fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
+    fn flat_map_trait_item(&mut self, i: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
         let is_const = match i.node {
             ast::TraitItemKind::Const(..) => true,
             ast::TraitItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) =>
                 header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl),
             _ => false,
         };
-        self.run(is_const, |s| fold::noop_fold_trait_item(i, s))
+        self.run(is_const, |s| noop_flat_map_trait_item(i, s))
     }
 
-    fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
+    fn flat_map_impl_item(&mut self, i: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
         let is_const = match i.node {
             ast::ImplItemKind::Const(..) => true,
             ast::ImplItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) =>
                 header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl),
             _ => false,
         };
-        self.run(is_const, |s| fold::noop_fold_impl_item(i, s))
+        self.run(is_const, |s| noop_flat_map_impl_item(i, s))
     }
 
-    fn fold_anon_const(&mut self, c: ast::AnonConst) -> ast::AnonConst {
-        self.run(true, |s| fold::noop_fold_anon_const(c, s))
+    fn visit_anon_const(&mut self, c: &mut ast::AnonConst) {
+        self.run(true, |s| noop_visit_anon_const(c, s))
     }
 
-    fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> {
+    fn visit_block(&mut self, b: &mut P<ast::Block>) {
         fn stmt_to_block(rules: ast::BlockCheckMode,
                          s: Option<ast::Stmt>,
                          sess: &Session) -> ast::Block {
@@ -780,14 +781,14 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> {
         };
 
         if self.within_static_or_const {
-            fold::noop_fold_block(b, self)
+            noop_visit_block(b, self)
         } else {
-            b.map(|b| {
+            visit_clobber(b.deref_mut(), |b| {
                 let mut stmts = vec![];
                 for s in b.stmts {
                     let old_blocks = self.nested_blocks.replace(vec![]);
 
-                    stmts.extend(self.fold_stmt(s).into_iter().filter(|s| s.is_item()));
+                    stmts.extend(self.flat_map_stmt(s).into_iter().filter(|s| s.is_item()));
 
                     // we put a Some in there earlier with that replace(), so this is valid
                     let new_blocks = self.nested_blocks.take().unwrap();
@@ -818,9 +819,9 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> {
     }
 
     // in general the pretty printer processes unexpanded code, so
-    // we override the default `fold_mac` method which panics.
-    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
-        fold::noop_fold_mac(mac, self)
+    // we override the default `visit_mac` method which panics.
+    fn visit_mac(&mut self, mac: &mut ast::Mac) {
+        noop_visit_mac(mac, self)
     }
 }
 
@@ -889,12 +890,9 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
     }
 }
 
-pub fn fold_crate(sess: &Session, krate: ast::Crate, ppm: PpMode) -> ast::Crate {
+pub fn visit_crate(sess: &Session, krate: &mut ast::Crate, ppm: PpMode) {
     if let PpmSource(PpmEveryBodyLoops) = ppm {
-        let mut fold = ReplaceBodyWithLoop::new(sess);
-        fold.fold_crate(krate)
-    } else {
-        krate
+        ReplaceBodyWithLoop::new(sess).visit_crate(krate);
     }
 }
 
diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs
index 58be7c3e085c3..c5a397e048078 100644
--- a/src/libsyntax/attr/mod.rs
+++ b/src/libsyntax/attr/mod.rs
@@ -15,6 +15,7 @@ use ast;
 use ast::{AttrId, Attribute, AttrStyle, Name, Ident, Path, PathSegment};
 use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
 use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind, GenericParam};
+use mut_visit::visit_clobber;
 use source_map::{BytePos, Spanned, respan, dummy_spanned};
 use syntax_pos::{FileName, Span};
 use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
@@ -28,6 +29,7 @@ use tokenstream::{TokenStream, TokenTree, DelimSpan};
 use GLOBALS;
 
 use std::iter;
+use std::ops::DerefMut;
 
 pub fn mark_used(attr: &Attribute) {
     debug!("Marking {:?} as used.", attr);
@@ -695,13 +697,13 @@ impl LitKind {
 
 pub trait HasAttrs: Sized {
     fn attrs(&self) -> &[ast::Attribute];
-    fn map_attrs<F: FnOnce(Vec<ast::Attribute>) -> Vec<ast::Attribute>>(self, f: F) -> Self;
+    fn visit_attrs<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F);
 }
 
 impl<T: HasAttrs> HasAttrs for Spanned<T> {
     fn attrs(&self) -> &[ast::Attribute] { self.node.attrs() }
-    fn map_attrs<F: FnOnce(Vec<ast::Attribute>) -> Vec<ast::Attribute>>(self, f: F) -> Self {
-        respan(self.span, self.node.map_attrs(f))
+    fn visit_attrs<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F) {
+        self.node.visit_attrs(f);
     }
 }
 
@@ -709,7 +711,7 @@ impl HasAttrs for Vec<Attribute> {
     fn attrs(&self) -> &[Attribute] {
         self
     }
-    fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
+    fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
         f(self)
     }
 }
@@ -718,8 +720,12 @@ impl HasAttrs for ThinVec<Attribute> {
     fn attrs(&self) -> &[Attribute] {
         self
     }
-    fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
-        f(self.into()).into()
+    fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
+        visit_clobber(self, |this| {
+            let mut vec = this.into();
+            f(&mut vec);
+            vec.into()
+        });
     }
 }
 
@@ -727,8 +733,8 @@ impl<T: HasAttrs + 'static> HasAttrs for P<T> {
     fn attrs(&self) -> &[Attribute] {
         (**self).attrs()
     }
-    fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
-        self.map(|t| t.map_attrs(f))
+    fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
+        (**self).visit_attrs(f);
     }
 }
 
@@ -745,23 +751,27 @@ impl HasAttrs for StmtKind {
         }
     }
 
-    fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
+    fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
         match self {
-            StmtKind::Local(local) => StmtKind::Local(local.map_attrs(f)),
-            StmtKind::Item(..) => self,
-            StmtKind::Expr(expr) => StmtKind::Expr(expr.map_attrs(f)),
-            StmtKind::Semi(expr) => StmtKind::Semi(expr.map_attrs(f)),
-            StmtKind::Mac(mac) => StmtKind::Mac(mac.map(|(mac, style, attrs)| {
-                (mac, style, attrs.map_attrs(f))
-            })),
+            StmtKind::Local(local) => local.visit_attrs(f),
+            StmtKind::Item(..) => {}
+            StmtKind::Expr(expr) => expr.visit_attrs(f),
+            StmtKind::Semi(expr) => expr.visit_attrs(f),
+            StmtKind::Mac(mac) => {
+                let (_mac, _style, attrs) = mac.deref_mut();
+                attrs.visit_attrs(f);
+            }
         }
     }
 }
 
 impl HasAttrs for Stmt {
-    fn attrs(&self) -> &[ast::Attribute] { self.node.attrs() }
-    fn map_attrs<F: FnOnce(Vec<ast::Attribute>) -> Vec<ast::Attribute>>(self, f: F) -> Self {
-        Stmt { id: self.id, node: self.node.map_attrs(f), span: self.span }
+    fn attrs(&self) -> &[ast::Attribute] {
+        self.node.attrs()
+    }
+
+    fn visit_attrs<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F) {
+        self.node.visit_attrs(f);
     }
 }
 
@@ -770,9 +780,8 @@ impl HasAttrs for GenericParam {
         &self.attrs
     }
 
-    fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(mut self, f: F) -> Self {
-        self.attrs = self.attrs.map_attrs(f);
-        self
+    fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
+        self.attrs.visit_attrs(f);
     }
 }
 
@@ -783,11 +792,8 @@ macro_rules! derive_has_attrs {
                 &self.attrs
             }
 
-            fn map_attrs<F>(mut self, f: F) -> Self
-                where F: FnOnce(Vec<Attribute>) -> Vec<Attribute>,
-            {
-                self.attrs = self.attrs.map_attrs(f);
-                self
+            fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
+                self.attrs.visit_attrs(f);
             }
         }
     )* }
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index b35730bf2381b..fce2601e3aa84 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -6,16 +6,15 @@ use feature_gate::{
     get_features,
     GateIssue,
 };
-use {fold, attr};
+use attr;
 use ast;
-use source_map::Spanned;
 use edition::Edition;
-use parse::{token, ParseSess};
-use smallvec::SmallVec;
 use errors::Applicability;
-use util::move_map::MoveMap;
-
+use mut_visit::*;
+use parse::{token, ParseSess};
 use ptr::P;
+use smallvec::SmallVec;
+use util::map_in_place::MapInPlace;
 
 /// A folder that strips out items that do not belong in the current configuration.
 pub struct StripUnconfigured<'a> {
@@ -65,8 +64,8 @@ macro_rules! configure {
 }
 
 impl<'a> StripUnconfigured<'a> {
-    pub fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
-        let node = self.process_cfg_attrs(node);
+    pub fn configure<T: HasAttrs>(&mut self, mut node: T) -> Option<T> {
+        self.process_cfg_attrs(&mut node);
         if self.in_cfg(node.attrs()) { Some(node) } else { None }
     }
 
@@ -76,10 +75,10 @@ impl<'a> StripUnconfigured<'a> {
     /// Gives compiler warnigns if any `cfg_attr` does not contain any
     /// attributes and is in the original source code. Gives compiler errors if
     /// the syntax of any `cfg_attr` is incorrect.
-    pub fn process_cfg_attrs<T: HasAttrs>(&mut self, node: T) -> T {
-        node.map_attrs(|attrs| {
-            attrs.into_iter().flat_map(|attr| self.process_cfg_attr(attr)).collect()
-        })
+    pub fn process_cfg_attrs<T: HasAttrs>(&mut self, node: &mut T) {
+        node.visit_attrs(|attrs| {
+            attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
+        });
     }
 
     /// Parse and expand a single `cfg_attr` attribute into a list of attributes
@@ -218,70 +217,47 @@ impl<'a> StripUnconfigured<'a> {
         }
     }
 
-    pub fn configure_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
-        ast::ForeignMod {
-            abi: foreign_mod.abi,
-            items: foreign_mod.items.move_flat_map(|item| self.configure(item)),
-        }
+    pub fn configure_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) {
+        let ast::ForeignMod { abi: _, items } = foreign_mod;
+        items.flat_map_in_place(|item| self.configure(item));
     }
 
-    fn configure_variant_data(&mut self, vdata: ast::VariantData) -> ast::VariantData {
+    fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) {
         match vdata {
-            ast::VariantData::Struct(fields, id) => {
-                let fields = fields.move_flat_map(|field| self.configure(field));
-                ast::VariantData::Struct(fields, id)
-            }
-            ast::VariantData::Tuple(fields, id) => {
-                let fields = fields.move_flat_map(|field| self.configure(field));
-                ast::VariantData::Tuple(fields, id)
-            }
-            ast::VariantData::Unit(id) => ast::VariantData::Unit(id)
+            ast::VariantData::Struct(fields, _id) |
+            ast::VariantData::Tuple(fields, _id) =>
+                fields.flat_map_in_place(|field| self.configure(field)),
+            ast::VariantData::Unit(_id) => {}
         }
     }
 
-    pub fn configure_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
+    pub fn configure_item_kind(&mut self, item: &mut ast::ItemKind) {
         match item {
-            ast::ItemKind::Struct(def, generics) => {
-                ast::ItemKind::Struct(self.configure_variant_data(def), generics)
-            }
-            ast::ItemKind::Union(def, generics) => {
-                ast::ItemKind::Union(self.configure_variant_data(def), generics)
-            }
-            ast::ItemKind::Enum(def, generics) => {
-                let variants = def.variants.move_flat_map(|v| {
-                    self.configure(v).map(|v| {
-                        Spanned {
-                            node: ast::Variant_ {
-                                ident: v.node.ident,
-                                attrs: v.node.attrs,
-                                data: self.configure_variant_data(v.node.data),
-                                disr_expr: v.node.disr_expr,
-                            },
-                            span: v.span
-                        }
-                    })
-                });
-                ast::ItemKind::Enum(ast::EnumDef { variants }, generics)
+            ast::ItemKind::Struct(def, _generics) |
+            ast::ItemKind::Union(def, _generics) => self.configure_variant_data(def),
+            ast::ItemKind::Enum(ast::EnumDef { variants }, _generics) => {
+                variants.flat_map_in_place(|variant| self.configure(variant));
+                for variant in variants {
+                    self.configure_variant_data(&mut variant.node.data);
+                }
             }
-            item => item,
+            _ => {}
         }
     }
 
-    pub fn configure_expr_kind(&mut self, expr_kind: ast::ExprKind) -> ast::ExprKind {
+    pub fn configure_expr_kind(&mut self, expr_kind: &mut ast::ExprKind) {
         match expr_kind {
-            ast::ExprKind::Match(m, arms) => {
-                let arms = arms.move_flat_map(|a| self.configure(a));
-                ast::ExprKind::Match(m, arms)
+            ast::ExprKind::Match(_m, arms) => {
+                arms.flat_map_in_place(|arm| self.configure(arm));
             }
-            ast::ExprKind::Struct(path, fields, base) => {
-                let fields = fields.move_flat_map(|field| self.configure(field));
-                ast::ExprKind::Struct(path, fields, base)
+            ast::ExprKind::Struct(_path, fields, _base) => {
+                fields.flat_map_in_place(|field| self.configure(field));
             }
-            _ => expr_kind,
+            _ => {}
         }
     }
 
-    pub fn configure_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
+    pub fn configure_expr(&mut self, expr: &mut P<ast::Expr>) {
         self.visit_expr_attrs(expr.attrs());
 
         // If an expr is valid to cfg away it will have been removed by the
@@ -289,8 +265,8 @@ impl<'a> StripUnconfigured<'a> {
         // Anything else is always required, and thus has to error out
         // in case of a cfg attr.
         //
-        // N.B., this is intentionally not part of the fold_expr() function
-        //     in order for fold_opt_expr() to be able to avoid this check
+        // N.B., this is intentionally not part of the visit_expr() function
+        //     in order for filter_map_expr() to be able to avoid this check
         if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) {
             let msg = "removing an expression is not supported in this position";
             self.sess.span_diagnostic.span_err(attr.span, msg);
@@ -299,14 +275,10 @@ impl<'a> StripUnconfigured<'a> {
         self.process_cfg_attrs(expr)
     }
 
-    pub fn configure_pat(&mut self, pattern: P<ast::Pat>) -> P<ast::Pat> {
-        pattern.map(|mut pattern| {
-            if let ast::PatKind::Struct(path, fields, etc) = pattern.node {
-                let fields = fields.move_flat_map(|field| self.configure(field));
-                pattern.node = ast::PatKind::Struct(path, fields, etc);
-            }
-            pattern
-        })
+    pub fn configure_pat(&mut self, pat: &mut P<ast::Pat>) {
+        if let ast::PatKind::Struct(_path, fields, _etc) = &mut pat.node {
+            fields.flat_map_in_place(|field| self.configure(field));
+        }
     }
 
     // deny #[cfg] on generic parameters until we decide what to do with it.
@@ -326,54 +298,54 @@ impl<'a> StripUnconfigured<'a> {
     }
 }
 
-impl<'a> fold::Folder for StripUnconfigured<'a> {
-    fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
-        let foreign_mod = self.configure_foreign_mod(foreign_mod);
-        fold::noop_fold_foreign_mod(foreign_mod, self)
+impl<'a> MutVisitor for StripUnconfigured<'a> {
+    fn visit_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) {
+        self.configure_foreign_mod(foreign_mod);
+        noop_visit_foreign_mod(foreign_mod, self);
     }
 
-    fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
-        let item = self.configure_item_kind(item);
-        fold::noop_fold_item_kind(item, self)
+    fn visit_item_kind(&mut self, item: &mut ast::ItemKind) {
+        self.configure_item_kind(item);
+        noop_visit_item_kind(item, self);
     }
 
-    fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
-        let mut expr = self.configure_expr(expr).into_inner();
-        expr.node = self.configure_expr_kind(expr.node);
-        P(fold::noop_fold_expr(expr, self))
+    fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
+        self.configure_expr(expr);
+        self.configure_expr_kind(&mut expr.node);
+        noop_visit_expr(expr, self);
     }
 
-    fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
-        let mut expr = configure!(self, expr).into_inner();
-        expr.node = self.configure_expr_kind(expr.node);
-        Some(P(fold::noop_fold_expr(expr, self)))
+    fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
+        let mut expr = configure!(self, expr);
+        self.configure_expr_kind(&mut expr.node);
+        noop_visit_expr(&mut expr, self);
+        Some(expr)
     }
 
-    fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
-        fold::noop_fold_stmt(configure!(self, stmt), self)
+    fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
+        noop_flat_map_stmt(configure!(self, stmt), self)
     }
 
-    fn fold_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
-        fold::noop_fold_item(configure!(self, item), self)
+    fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
+        noop_flat_map_item(configure!(self, item), self)
     }
 
-    fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]>
-    {
-        fold::noop_fold_impl_item(configure!(self, item), self)
+    fn flat_map_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
+        noop_flat_map_impl_item(configure!(self, item), self)
     }
 
-    fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
-        fold::noop_fold_trait_item(configure!(self, item), self)
+    fn flat_map_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
+        noop_flat_map_trait_item(configure!(self, item), self)
     }
 
-    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
+    fn visit_mac(&mut self, _mac: &mut ast::Mac) {
         // Don't configure interpolated AST (cf. issue #34171).
         // Interpolated AST will get configured once the surrounding tokens are parsed.
-        mac
     }
 
-    fn fold_pat(&mut self, pattern: P<ast::Pat>) -> P<ast::Pat> {
-        fold::noop_fold_pat(self.configure_pat(pattern), self)
+    fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
+        self.configure_pat(pat);
+        noop_visit_pat(pat, self)
     }
 }
 
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 09e7e57f78cfa..b53068f5bc2a4 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -8,7 +8,7 @@ use edition::Edition;
 use errors::{DiagnosticBuilder, DiagnosticId};
 use ext::expand::{self, AstFragment, Invocation};
 use ext::hygiene::{self, Mark, SyntaxContext, Transparency};
-use fold::{self, Folder};
+use mut_visit::{self, MutVisitor};
 use parse::{self, parser, DirectoryOwnership};
 use parse::token;
 use ptr::P;
@@ -47,15 +47,14 @@ impl HasAttrs for Annotatable {
         }
     }
 
-    fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
+    fn visit_attrs<F: FnOnce(&mut Vec<Attribute>)>(&mut self, f: F) {
         match self {
-            Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)),
-            Annotatable::TraitItem(trait_item) => Annotatable::TraitItem(trait_item.map_attrs(f)),
-            Annotatable::ImplItem(impl_item) => Annotatable::ImplItem(impl_item.map_attrs(f)),
-            Annotatable::ForeignItem(foreign_item) =>
-                Annotatable::ForeignItem(foreign_item.map_attrs(f)),
-            Annotatable::Stmt(stmt) => Annotatable::Stmt(stmt.map_attrs(f)),
-            Annotatable::Expr(expr) => Annotatable::Expr(expr.map_attrs(f)),
+            Annotatable::Item(item) => item.visit_attrs(f),
+            Annotatable::TraitItem(trait_item) => trait_item.visit_attrs(f),
+            Annotatable::ImplItem(impl_item) => impl_item.visit_attrs(f),
+            Annotatable::ForeignItem(foreign_item) => foreign_item.visit_attrs(f),
+            Annotatable::Stmt(stmt) => stmt.visit_attrs(f),
+            Annotatable::Expr(expr) => expr.visit_attrs(f),
         }
     }
 }
@@ -263,24 +262,24 @@ impl<F> TTMacroExpander for F
     ) -> Box<dyn MacResult+'cx> {
         struct AvoidInterpolatedIdents;
 
-        impl Folder for AvoidInterpolatedIdents {
-            fn fold_tt(&mut self, tt: tokenstream::TokenTree) -> tokenstream::TokenTree {
-                if let tokenstream::TokenTree::Token(_, token::Interpolated(ref nt)) = tt {
+        impl MutVisitor for AvoidInterpolatedIdents {
+            fn visit_tt(&mut self, tt: &mut tokenstream::TokenTree) {
+                if let tokenstream::TokenTree::Token(_, token::Interpolated(nt)) = tt {
                     if let token::NtIdent(ident, is_raw) = nt.0 {
-                        return tokenstream::TokenTree::Token(ident.span,
-                                                             token::Ident(ident, is_raw));
+                        *tt = tokenstream::TokenTree::Token(ident.span,
+                                                            token::Ident(ident, is_raw));
                     }
                 }
-                fold::noop_fold_tt(tt, self)
+                mut_visit::noop_visit_tt(tt, self)
             }
 
-            fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
-                fold::noop_fold_mac(mac, self)
+            fn visit_mac(&mut self, mac: &mut ast::Mac) {
+                mut_visit::noop_visit_mac(mac, self)
             }
         }
 
         let input: Vec<_> =
-            input.trees().map(|tt| AvoidInterpolatedIdents.fold_tt(tt)).collect();
+            input.trees().map(|mut tt| { AvoidInterpolatedIdents.visit_tt(&mut tt); tt }).collect();
         (*self)(ecx, span, &input)
     }
 }
@@ -981,17 +980,14 @@ impl<'a> ExtCtxt<'a> {
 /// compilation on error, merely emits a non-fatal error and returns None.
 pub fn expr_to_spanned_string<'a>(
     cx: &'a mut ExtCtxt,
-    expr: P<ast::Expr>,
+    mut expr: P<ast::Expr>,
     err_msg: &str,
 ) -> Result<Spanned<(Symbol, ast::StrStyle)>, Option<DiagnosticBuilder<'a>>> {
     // Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation.
-    let expr = expr.map(|mut expr| {
-        expr.span = expr.span.apply_mark(cx.current_expansion.mark);
-        expr
-    });
+    expr.span = expr.span.apply_mark(cx.current_expansion.mark);
 
     // we want to be able to handle e.g., `concat!("foo", "bar")`
-    let expr = cx.expander().fold_expr(expr);
+    cx.expander().visit_expr(&mut expr);
     Err(match expr.node {
         ast::ExprKind::Lit(ref l) => match l.node {
             ast::LitKind::Str(s, style) => return Ok(respan(expr.span, (s, style))),
@@ -1055,7 +1051,9 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
     let mut p = cx.new_parser_from_tts(tts);
     let mut es = Vec::new();
     while p.token != token::Eof {
-        es.push(cx.expander().fold_expr(panictry!(p.parse_expr())));
+        let mut expr = panictry!(p.parse_expr());
+        cx.expander().visit_expr(&mut expr);
+        es.push(expr);
         if p.eat(&token::Comma) {
             continue;
         }
diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs
index 7ef09ce5fbd40..fa8cf6c496a39 100644
--- a/src/libsyntax/ext/derive.rs
+++ b/src/libsyntax/ext/derive.rs
@@ -40,7 +40,7 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec
     result
 }
 
-pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path], item: T) -> T
+pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path], item: &mut T)
     where T: HasAttrs,
 {
     let (mut names, mut pretty_name) = (FxHashSet::default(), "derive(".to_owned());
@@ -64,7 +64,7 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path]
     });
 
     let span = span.with_ctxt(cx.backtrace());
-    item.map_attrs(|mut attrs| {
+    item.visit_attrs(|attrs| {
         if names.contains(&Symbol::intern("Eq")) && names.contains(&Symbol::intern("PartialEq")) {
             let meta = cx.meta_word(span, Symbol::intern("structural_match"));
             attrs.push(cx.attribute(span, meta));
@@ -73,6 +73,5 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path]
             let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
             attrs.push(cx.attribute(span, meta));
         }
-        attrs
-    })
+    });
 }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 2effd910e8545..a0ccce986592a 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -9,7 +9,7 @@ use ext::derive::{add_derived_markers, collect_derives};
 use ext::hygiene::{self, Mark, SyntaxContext};
 use ext::placeholders::{placeholder, PlaceholderExpander};
 use feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err};
-use fold::*;
+use mut_visit::*;
 use parse::{DirectoryOwnership, PResult, ParseSess};
 use parse::token::{self, Token};
 use parse::parser::Parser;
@@ -21,11 +21,13 @@ use syntax_pos::{Span, DUMMY_SP, FileName};
 use syntax_pos::hygiene::ExpnFormat;
 use tokenstream::{TokenStream, TokenTree};
 use visit::{self, Visitor};
+use util::map_in_place::MapInPlace;
 
 use rustc_data_structures::fx::FxHashMap;
 use std::fs;
 use std::io::ErrorKind;
 use std::{iter, mem};
+use std::ops::DerefMut;
 use std::rc::Rc;
 use std::path::PathBuf;
 
@@ -35,8 +37,8 @@ macro_rules! ast_fragments {
             $kind_name:expr;
             // FIXME: HACK: this should be `$(one ...)?` and `$(many ...)?` but `?` macro
             // repetition was removed from 2015 edition in #51587 because of ambiguities.
-            $(one fn $fold_ast:ident; fn $visit_ast:ident;)*
-            $(many fn $fold_ast_elt:ident; fn $visit_ast_elt:ident;)*
+            $(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)*
+            $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident;)*
             fn $make_ast:ident;
         })*
     ) => {
@@ -86,16 +88,20 @@ macro_rules! ast_fragments {
                 }
             })*
 
-            pub fn fold_with<F: Folder>(self, folder: &mut F) -> Self {
+            pub fn mut_visit_with<F: MutVisitor>(&mut self, vis: &mut F) {
                 match self {
-                    AstFragment::OptExpr(expr) =>
-                        AstFragment::OptExpr(expr.and_then(|expr| folder.fold_opt_expr(expr))),
-                    $($(AstFragment::$Kind(ast) =>
-                        AstFragment::$Kind(folder.$fold_ast(ast)),)*)*
+                    AstFragment::OptExpr(opt_expr) => {
+                        visit_clobber(opt_expr, |opt_expr| {
+                            if let Some(expr) = opt_expr {
+                                vis.filter_map_expr(expr)
+                            } else {
+                                None
+                            }
+                        });
+                    }
+                    $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)*)*
                     $($(AstFragment::$Kind(ast) =>
-                        AstFragment::$Kind(ast.into_iter()
-                                              .flat_map(|ast| folder.$fold_ast_elt(ast))
-                                              .collect()),)*)*
+                        ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)*)*
                 }
             }
 
@@ -111,14 +117,14 @@ macro_rules! ast_fragments {
             }
         }
 
-        impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
-            fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
+        impl<'a, 'b> MutVisitor for MacroExpander<'a, 'b> {
+            fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
                 self.expand_fragment(AstFragment::OptExpr(Some(expr))).make_opt_expr()
             }
-            $($(fn $fold_ast(&mut self, ast: $AstTy) -> $AstTy {
-                self.expand_fragment(AstFragment::$Kind(ast)).$make_ast()
+            $($(fn $mut_visit_ast(&mut self, ast: &mut $AstTy) {
+                visit_clobber(ast, |ast| self.expand_fragment(AstFragment::$Kind(ast)).$make_ast());
             })*)*
-            $($(fn $fold_ast_elt(&mut self, ast_elt: <$AstTy as IntoIterator>::Item) -> $AstTy {
+            $($(fn $flat_map_ast_elt(&mut self, ast_elt: <$AstTy as IntoIterator>::Item) -> $AstTy {
                 self.expand_fragment(AstFragment::$Kind(smallvec![ast_elt])).$make_ast()
             })*)*
         }
@@ -133,23 +139,23 @@ macro_rules! ast_fragments {
 }
 
 ast_fragments! {
-    Expr(P<ast::Expr>) { "expression"; one fn fold_expr; fn visit_expr; fn make_expr; }
-    Pat(P<ast::Pat>) { "pattern"; one fn fold_pat; fn visit_pat; fn make_pat; }
-    Ty(P<ast::Ty>) { "type"; one fn fold_ty; fn visit_ty; fn make_ty; }
+    Expr(P<ast::Expr>) { "expression"; one fn visit_expr; fn visit_expr; fn make_expr; }
+    Pat(P<ast::Pat>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; }
+    Ty(P<ast::Ty>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; }
     Stmts(SmallVec<[ast::Stmt; 1]>) {
-        "statement"; many fn fold_stmt; fn visit_stmt; fn make_stmts;
+        "statement"; many fn flat_map_stmt; fn visit_stmt; fn make_stmts;
     }
     Items(SmallVec<[P<ast::Item>; 1]>) {
-        "item"; many fn fold_item; fn visit_item; fn make_items;
+        "item"; many fn flat_map_item; fn visit_item; fn make_items;
     }
     TraitItems(SmallVec<[ast::TraitItem; 1]>) {
-        "trait item"; many fn fold_trait_item; fn visit_trait_item; fn make_trait_items;
+        "trait item"; many fn flat_map_trait_item; fn visit_trait_item; fn make_trait_items;
     }
     ImplItems(SmallVec<[ast::ImplItem; 1]>) {
-        "impl item"; many fn fold_impl_item; fn visit_impl_item; fn make_impl_items;
+        "impl item"; many fn flat_map_impl_item; fn visit_impl_item; fn make_impl_items;
     }
     ForeignItems(SmallVec<[ast::ForeignItem; 1]>) {
-        "foreign item"; many fn fold_foreign_item; fn visit_foreign_item; fn make_foreign_items;
+        "foreign item"; many fn flat_map_foreign_item; fn visit_foreign_item; fn make_foreign_items;
     }
 }
 
@@ -297,7 +303,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         self.cx.current_expansion.depth = 0;
 
         // Collect all macro invocations and replace them with placeholders.
-        let (fragment_with_placeholders, mut invocations)
+        let (mut fragment_with_placeholders, mut invocations)
             = self.collect_invocations(input_fragment, &[]);
 
         // Optimization: if we resolve all imports now,
@@ -369,10 +375,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         err.emit();
                     }
 
-                    let item = self.fully_configure(item)
-                        .map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs });
-                    let item_with_markers =
-                        add_derived_markers(&mut self.cx, item.span(), &traits, item.clone());
+                    let mut item = self.fully_configure(item);
+                    item.visit_attrs(|attrs| attrs.retain(|a| a.path != "derive"));
+                    let mut item_with_markers = item.clone();
+                    add_derived_markers(&mut self.cx, item.span(), &traits, &mut item_with_markers);
                     let derives = derives.entry(invoc.expansion_data.mark).or_default();
 
                     derives.reserve(traits.len());
@@ -427,7 +433,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                                          expanded_fragment, derives);
             }
         }
-        fragment_with_placeholders.fold_with(&mut placeholder_expander)
+        fragment_with_placeholders.mut_visit_with(&mut placeholder_expander);
+        fragment_with_placeholders
     }
 
     fn resolve_imports(&mut self) {
@@ -440,12 +447,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     /// them with "placeholders" - dummy macro invocations with specially crafted `NodeId`s.
     /// Then call into resolver that builds a skeleton ("reduced graph") of the fragment and
     /// prepares data for resolving paths of macro invocations.
-    fn collect_invocations(&mut self, fragment: AstFragment, derives: &[Mark])
+    fn collect_invocations(&mut self, mut fragment: AstFragment, derives: &[Mark])
                            -> (AstFragment, Vec<Invocation>) {
         // Resolve `$crate`s in the fragment for pretty-printing.
         self.cx.resolver.resolve_dollar_crates(&fragment);
 
-        let (fragment_with_placeholders, invocations) = {
+        let invocations = {
             let mut collector = InvocationCollector {
                 cfg: StripUnconfigured {
                     sess: self.cx.parse_sess,
@@ -455,16 +462,16 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 invocations: Vec::new(),
                 monotonic: self.monotonic,
             };
-            (fragment.fold_with(&mut collector), collector.invocations)
+            fragment.mut_visit_with(&mut collector);
+            collector.invocations
         };
 
         if self.monotonic {
             self.cx.resolver.visit_ast_fragment_with_placeholders(
-                self.cx.current_expansion.mark, &fragment_with_placeholders, derives
-            );
+                self.cx.current_expansion.mark, &fragment, derives);
         }
 
-        (fragment_with_placeholders, invocations)
+        (fragment, invocations)
     }
 
     fn fully_configure(&mut self, item: Annotatable) -> Annotatable {
@@ -476,24 +483,25 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         // we know that fold result vector will contain exactly one element
         match item {
             Annotatable::Item(item) => {
-                Annotatable::Item(cfg.fold_item(item).pop().unwrap())
+                Annotatable::Item(cfg.flat_map_item(item).pop().unwrap())
             }
             Annotatable::TraitItem(item) => {
-                Annotatable::TraitItem(item.map(|item| cfg.fold_trait_item(item).pop().unwrap()))
+                Annotatable::TraitItem(
+                    item.map(|item| cfg.flat_map_trait_item(item).pop().unwrap()))
             }
             Annotatable::ImplItem(item) => {
-                Annotatable::ImplItem(item.map(|item| cfg.fold_impl_item(item).pop().unwrap()))
+                Annotatable::ImplItem(item.map(|item| cfg.flat_map_impl_item(item).pop().unwrap()))
             }
             Annotatable::ForeignItem(item) => {
                 Annotatable::ForeignItem(
-                    item.map(|item| cfg.fold_foreign_item(item).pop().unwrap())
+                    item.map(|item| cfg.flat_map_foreign_item(item).pop().unwrap())
                 )
             }
             Annotatable::Stmt(stmt) => {
-                Annotatable::Stmt(stmt.map(|stmt| cfg.fold_stmt(stmt).pop().unwrap()))
+                Annotatable::Stmt(stmt.map(|stmt| cfg.flat_map_stmt(stmt).pop().unwrap()))
             }
-            Annotatable::Expr(expr) => {
-                Annotatable::Expr(cfg.fold_expr(expr))
+            Annotatable::Expr(mut expr) => {
+                Annotatable::Expr({ cfg.visit_expr(&mut expr); expr })
             }
         }
     }
@@ -535,7 +543,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                          invoc: Invocation,
                          ext: &SyntaxExtension)
                          -> Option<AstFragment> {
-        let (attr, item) = match invoc.kind {
+        let (attr, mut item) = match invoc.kind {
             InvocationKind::Attr { attr, item, .. } => (attr?, item),
             _ => unreachable!(),
         };
@@ -558,7 +566,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         match *ext {
             NonMacroAttr { .. } => {
                 attr::mark_known(&attr);
-                let item = item.map_attrs(|mut attrs| { attrs.push(attr); attrs });
+                item.visit_attrs(|attrs| attrs.push(attr));
                 Some(invoc.fragment_kind.expect_from_annotatables(iter::once(item)))
             }
             MultiModifier(ref mac) => {
@@ -1113,34 +1121,32 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
     }
 
     /// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
-    fn classify_item<T>(&mut self, mut item: T)
-                        -> (Option<ast::Attribute>, Vec<Path>, T, /* after_derive */ bool)
+    fn classify_item<T>(&mut self, item: &mut T)
+                        -> (Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool)
         where T: HasAttrs,
     {
         let (mut attr, mut traits, mut after_derive) = (None, Vec::new(), false);
 
-        item = item.map_attrs(|mut attrs| {
+        item.visit_attrs(|mut attrs| {
             attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
             traits = collect_derives(&mut self.cx, &mut attrs);
-            attrs
         });
 
-        (attr, traits, item, after_derive)
+        (attr, traits, after_derive)
     }
 
-    /// Alternative of `classify_item()` that ignores `#[derive]` so invocations fallthrough
+    /// Alternative to `classify_item()` that ignores `#[derive]` so invocations fallthrough
     /// to the unused-attributes lint (making it an error on statements and expressions
     /// is a breaking change)
-    fn classify_nonitem<T: HasAttrs>(&mut self, mut item: T)
-                                     -> (Option<ast::Attribute>, T, /* after_derive */ bool) {
+    fn classify_nonitem<T: HasAttrs>(&mut self, nonitem: &mut T)
+                                     -> (Option<ast::Attribute>, /* after_derive */ bool) {
         let (mut attr, mut after_derive) = (None, false);
 
-        item = item.map_attrs(|mut attrs| {
+        nonitem.visit_attrs(|mut attrs| {
             attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
-            attrs
         });
 
-        (attr, item, after_derive)
+        (attr, after_derive)
     }
 
     fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
@@ -1173,14 +1179,14 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
     }
 }
 
-impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
-    fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
-        let expr = self.cfg.configure_expr(expr);
-        expr.map(|mut expr| {
-            expr.node = self.cfg.configure_expr_kind(expr.node);
+impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
+    fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
+        self.cfg.configure_expr(expr);
+        visit_clobber(expr.deref_mut(), |mut expr| {
+            self.cfg.configure_expr_kind(&mut expr.node);
 
             // ignore derives so they remain unused
-            let (attr, expr, after_derive) = self.classify_nonitem(expr);
+            let (attr, after_derive) = self.classify_nonitem(&mut expr);
 
             if attr.is_some() {
                 // Collect the invoc regardless of whether or not attributes are permitted here
@@ -1189,7 +1195,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
 
                 // AstFragmentKind::Expr requires the macro to emit an expression.
                 return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
-                                         AstFragmentKind::Expr, after_derive)
+                                          AstFragmentKind::Expr, after_derive)
                     .make_expr()
                     .into_inner()
             }
@@ -1200,18 +1206,19 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                     .make_expr()
                     .into_inner()
             } else {
-                noop_fold_expr(expr, self)
+                noop_visit_expr(&mut expr, self);
+                expr
             }
-        })
+        });
     }
 
-    fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
+    fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
         let expr = configure!(self, expr);
         expr.filter_map(|mut expr| {
-            expr.node = self.cfg.configure_expr_kind(expr.node);
+            self.cfg.configure_expr_kind(&mut expr.node);
 
             // Ignore derives so they remain unused.
-            let (attr, expr, after_derive) = self.classify_nonitem(expr);
+            let (attr, after_derive) = self.classify_nonitem(&mut expr);
 
             if attr.is_some() {
                 attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
@@ -1228,44 +1235,45 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                     .make_opt_expr()
                     .map(|expr| expr.into_inner())
             } else {
-                Some(noop_fold_expr(expr, self))
+                Some({ noop_visit_expr(&mut expr, self); expr })
             }
         })
     }
 
-    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
-        let pat = self.cfg.configure_pat(pat);
+    fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
+        self.cfg.configure_pat(pat);
         match pat.node {
             PatKind::Mac(_) => {}
-            _ => return noop_fold_pat(pat, self),
+            _ => return noop_visit_pat(pat, self),
         }
 
-        pat.and_then(|pat| match pat.node {
-            PatKind::Mac(mac) => self.collect_bang(mac, pat.span, AstFragmentKind::Pat).make_pat(),
-            _ => unreachable!(),
-        })
+        visit_clobber(pat, |mut pat| {
+            match mem::replace(&mut pat.node, PatKind::Wild) {
+                PatKind::Mac(mac) =>
+                    self.collect_bang(mac, pat.span, AstFragmentKind::Pat).make_pat(),
+                _ => unreachable!(),
+            }
+        });
     }
 
-    fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
+    fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
         let mut stmt = configure!(self, stmt);
 
         // we'll expand attributes on expressions separately
         if !stmt.is_expr() {
-            let (attr, derives, stmt_, after_derive) = if stmt.is_item() {
-                self.classify_item(stmt)
+            let (attr, derives, after_derive) = if stmt.is_item() {
+                self.classify_item(&mut stmt)
             } else {
                 // ignore derives on non-item statements so it falls through
                 // to the unused-attributes lint
-                let (attr, stmt, after_derive) = self.classify_nonitem(stmt);
-                (attr, vec![], stmt, after_derive)
+                let (attr, after_derive) = self.classify_nonitem(&mut stmt);
+                (attr, vec![], after_derive)
             };
 
             if attr.is_some() || !derives.is_empty() {
-                return self.collect_attr(attr, derives, Annotatable::Stmt(P(stmt_)),
+                return self.collect_attr(attr, derives, Annotatable::Stmt(P(stmt)),
                                          AstFragmentKind::Stmts, after_derive).make_stmts();
             }
-
-            stmt = stmt_;
         }
 
         if let StmtKind::Mac(mac) = stmt.node {
@@ -1287,24 +1295,23 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
 
         // The placeholder expander gives ids to statements, so we avoid folding the id here.
         let ast::Stmt { id, node, span } = stmt;
-        noop_fold_stmt_kind(node, self).into_iter().map(|node| {
+        noop_flat_map_stmt_kind(node, self).into_iter().map(|node| {
             ast::Stmt { id, node, span }
         }).collect()
 
     }
 
-    fn fold_block(&mut self, block: P<Block>) -> P<Block> {
+    fn visit_block(&mut self, block: &mut P<Block>) {
         let old_directory_ownership = self.cx.current_expansion.directory_ownership;
         self.cx.current_expansion.directory_ownership = DirectoryOwnership::UnownedViaBlock;
-        let result = noop_fold_block(block, self);
+        noop_visit_block(block, self);
         self.cx.current_expansion.directory_ownership = old_directory_ownership;
-        result
     }
 
-    fn fold_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
-        let item = configure!(self, item);
+    fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
+        let mut item = configure!(self, item);
 
-        let (attr, traits, item, after_derive) = self.classify_item(item);
+        let (attr, traits, after_derive) = self.classify_item(&mut item);
         if attr.is_some() || !traits.is_empty() {
             return self.collect_attr(attr, traits, Annotatable::Item(item),
                                      AstFragmentKind::Items, after_derive).make_items();
@@ -1326,7 +1333,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
             }
             ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
                 if item.ident == keywords::Invalid.ident() {
-                    return noop_fold_item(item, self);
+                    return noop_flat_map_item(item, self);
                 }
 
                 let orig_directory_ownership = self.cx.current_expansion.directory_ownership;
@@ -1366,20 +1373,20 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
 
                 let orig_module =
                     mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
-                let result = noop_fold_item(item, self);
+                let result = noop_flat_map_item(item, self);
                 self.cx.current_expansion.module = orig_module;
                 self.cx.current_expansion.directory_ownership = orig_directory_ownership;
                 result
             }
 
-            _ => noop_fold_item(item, self),
+            _ => noop_flat_map_item(item, self),
         }
     }
 
-    fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
-        let item = configure!(self, item);
+    fn flat_map_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
+        let mut item = configure!(self, item);
 
-        let (attr, traits, item, after_derive) = self.classify_item(item);
+        let (attr, traits, after_derive) = self.classify_item(&mut item);
         if attr.is_some() || !traits.is_empty() {
             return self.collect_attr(attr, traits, Annotatable::TraitItem(P(item)),
                                      AstFragmentKind::TraitItems, after_derive).make_trait_items()
@@ -1391,14 +1398,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                 self.check_attributes(&attrs);
                 self.collect_bang(mac, span, AstFragmentKind::TraitItems).make_trait_items()
             }
-            _ => noop_fold_trait_item(item, self),
+            _ => noop_flat_map_trait_item(item, self),
         }
     }
 
-    fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
-        let item = configure!(self, item);
+    fn flat_map_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
+        let mut item = configure!(self, item);
 
-        let (attr, traits, item, after_derive) = self.classify_item(item);
+        let (attr, traits, after_derive) = self.classify_item(&mut item);
         if attr.is_some() || !traits.is_empty() {
             return self.collect_attr(attr, traits, Annotatable::ImplItem(P(item)),
                                      AstFragmentKind::ImplItems, after_derive).make_impl_items();
@@ -1410,30 +1417,34 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                 self.check_attributes(&attrs);
                 self.collect_bang(mac, span, AstFragmentKind::ImplItems).make_impl_items()
             }
-            _ => noop_fold_impl_item(item, self),
+            _ => noop_flat_map_impl_item(item, self),
         }
     }
 
-    fn fold_ty(&mut self, ty: P<ast::Ty>) -> P<ast::Ty> {
-        let ty = match ty.node {
-            ast::TyKind::Mac(_) => ty.into_inner(),
-            _ => return noop_fold_ty(ty, self),
+    fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
+        match ty.node {
+            ast::TyKind::Mac(_) => {}
+            _ => return noop_visit_ty(ty, self),
         };
 
-        match ty.node {
-            ast::TyKind::Mac(mac) => self.collect_bang(mac, ty.span, AstFragmentKind::Ty).make_ty(),
-            _ => unreachable!(),
-        }
+        visit_clobber(ty, |mut ty| {
+            match mem::replace(&mut ty.node, ast::TyKind::Err) {
+                ast::TyKind::Mac(mac) =>
+                    self.collect_bang(mac, ty.span, AstFragmentKind::Ty).make_ty(),
+                _ => unreachable!(),
+            }
+        });
     }
 
-    fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
-        noop_fold_foreign_mod(self.cfg.configure_foreign_mod(foreign_mod), self)
+    fn visit_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) {
+        self.cfg.configure_foreign_mod(foreign_mod);
+        noop_visit_foreign_mod(foreign_mod, self);
     }
 
-    fn fold_foreign_item(&mut self, foreign_item: ast::ForeignItem)
+    fn flat_map_foreign_item(&mut self, mut foreign_item: ast::ForeignItem)
         -> SmallVec<[ast::ForeignItem; 1]>
     {
-        let (attr, traits, foreign_item, after_derive) = self.classify_item(foreign_item);
+        let (attr, traits, after_derive) = self.classify_item(&mut foreign_item);
 
         if attr.is_some() || !traits.is_empty() {
             return self.collect_attr(attr, traits, Annotatable::ForeignItem(P(foreign_item)),
@@ -1447,38 +1458,41 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                 .make_foreign_items();
         }
 
-        noop_fold_foreign_item(foreign_item, self)
+        noop_flat_map_foreign_item(foreign_item, self)
     }
 
-    fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
+    fn visit_item_kind(&mut self, item: &mut ast::ItemKind) {
         match item {
-            ast::ItemKind::MacroDef(..) => item,
-            _ => noop_fold_item_kind(self.cfg.configure_item_kind(item), self),
+            ast::ItemKind::MacroDef(..) => {}
+            _ => {
+                self.cfg.configure_item_kind(item);
+                noop_visit_item_kind(item, self);
+            }
         }
     }
 
-    fn fold_generic_param(&mut self, param: ast::GenericParam) -> ast::GenericParam {
+    fn visit_generic_param(&mut self, param: &mut ast::GenericParam) {
         self.cfg.disallow_cfg_on_generic_param(&param);
-        noop_fold_generic_param(param, self)
+        noop_visit_generic_param(param, self)
     }
 
-    fn fold_attribute(&mut self, at: ast::Attribute) -> ast::Attribute {
+    fn visit_attribute(&mut self, at: &mut ast::Attribute) {
         // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
         // contents="file contents")]` attributes
         if !at.check_name("doc") {
-            return noop_fold_attribute(at, self);
+            return noop_visit_attribute(at, self);
         }
 
         if let Some(list) = at.meta_item_list() {
             if !list.iter().any(|it| it.check_name("include")) {
-                return noop_fold_attribute(at, self);
+                return noop_visit_attribute(at, self);
             }
 
             let mut items = vec![];
 
-            for it in list {
+            for mut it in list {
                 if !it.check_name("include") {
-                    items.push(noop_fold_meta_list_item(it, self));
+                    items.push({ noop_visit_meta_list_item(&mut it, self); it });
                     continue;
                 }
 
@@ -1487,7 +1501,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                     self.check_attribute(&at);
                     if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
                         // avoid loading the file if they haven't enabled the feature
-                        return noop_fold_attribute(at, self);
+                        return noop_visit_attribute(at, self);
                     }
 
                     let filename = self.cx.root_path.join(file.to_string());
@@ -1582,20 +1596,18 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
 
             let meta = attr::mk_list_item(DUMMY_SP, Ident::from_str("doc"), items);
             match at.style {
-                ast::AttrStyle::Inner => attr::mk_spanned_attr_inner(at.span, at.id, meta),
-                ast::AttrStyle::Outer => attr::mk_spanned_attr_outer(at.span, at.id, meta),
+                ast::AttrStyle::Inner => *at = attr::mk_spanned_attr_inner(at.span, at.id, meta),
+                ast::AttrStyle::Outer => *at = attr::mk_spanned_attr_outer(at.span, at.id, meta),
             }
         } else {
-            noop_fold_attribute(at, self)
+            noop_visit_attribute(at, self)
         }
     }
 
-    fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId {
+    fn visit_id(&mut self, id: &mut ast::NodeId) {
         if self.monotonic {
-            assert_eq!(id, ast::DUMMY_NODE_ID);
-            self.cx.resolver.next_node_id()
-        } else {
-            id
+            debug_assert_eq!(*id, ast::DUMMY_NODE_ID);
+            *id = self.cx.resolver.next_node_id()
         }
     }
 }
@@ -1660,12 +1672,12 @@ impl<'feat> ExpansionConfig<'feat> {
 #[derive(Debug)]
 pub struct Marker(pub Mark);
 
-impl Folder for Marker {
-    fn new_span(&mut self, span: Span) -> Span {
-        span.apply_mark(self.0)
+impl MutVisitor for Marker {
+    fn visit_span(&mut self, span: &mut Span) {
+        *span = span.apply_mark(self.0)
     }
 
-    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
-        noop_fold_mac(mac, self)
+    fn visit_mac(&mut self, mac: &mut ast::Mac) {
+        noop_visit_mac(mac, self)
     }
 }
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index 0928bc804041d..23b34c2660bda 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -4,12 +4,11 @@ use ext::base::ExtCtxt;
 use ext::expand::{AstFragment, AstFragmentKind};
 use ext::hygiene::Mark;
 use tokenstream::TokenStream;
-use fold::*;
+use mut_visit::*;
 use ptr::P;
 use smallvec::SmallVec;
 use symbol::keywords;
 use ThinVec;
-use util::move_map::MoveMap;
 
 use rustc_data_structures::fx::FxHashMap;
 
@@ -85,8 +84,8 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
         }
     }
 
-    pub fn add(&mut self, id: ast::NodeId, fragment: AstFragment, derives: Vec<Mark>) {
-        let mut fragment = fragment.fold_with(self);
+    pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment, derives: Vec<Mark>) {
+        fragment.mut_visit_with(self);
         if let AstFragment::Items(mut items) = fragment {
             for derive in derives {
                 match self.remove(NodeId::placeholder_from_mark(derive)) {
@@ -104,56 +103,56 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
     }
 }
 
-impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
-    fn fold_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
+impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
+    fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
         match item.node {
             ast::ItemKind::Mac(_) => return self.remove(item.id).make_items(),
             ast::ItemKind::MacroDef(_) => return smallvec![item],
             _ => {}
         }
 
-        noop_fold_item(item, self)
+        noop_flat_map_item(item, self)
     }
 
-    fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
+    fn flat_map_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
         match item.node {
             ast::TraitItemKind::Macro(_) => self.remove(item.id).make_trait_items(),
-            _ => noop_fold_trait_item(item, self),
+            _ => noop_flat_map_trait_item(item, self),
         }
     }
 
-    fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
+    fn flat_map_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
         match item.node {
             ast::ImplItemKind::Macro(_) => self.remove(item.id).make_impl_items(),
-            _ => noop_fold_impl_item(item, self),
+            _ => noop_flat_map_impl_item(item, self),
         }
     }
 
-    fn fold_foreign_item(&mut self, item: ast::ForeignItem) -> SmallVec<[ast::ForeignItem; 1]> {
+    fn flat_map_foreign_item(&mut self, item: ast::ForeignItem) -> SmallVec<[ast::ForeignItem; 1]> {
         match item.node {
             ast::ForeignItemKind::Macro(_) => self.remove(item.id).make_foreign_items(),
-            _ => noop_fold_foreign_item(item, self),
+            _ => noop_flat_map_foreign_item(item, self),
         }
     }
 
-    fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
+    fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
         match expr.node {
-            ast::ExprKind::Mac(_) => self.remove(expr.id).make_expr(),
-            _ => expr.map(|expr| noop_fold_expr(expr, self)),
+            ast::ExprKind::Mac(_) => *expr = self.remove(expr.id).make_expr(),
+            _ => noop_visit_expr(expr, self),
         }
     }
 
-    fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
+    fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
         match expr.node {
             ast::ExprKind::Mac(_) => self.remove(expr.id).make_opt_expr(),
-            _ => noop_fold_opt_expr(expr, self),
+            _ => noop_filter_map_expr(expr, self),
         }
     }
 
-    fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
+    fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
         let (style, mut stmts) = match stmt.node {
             ast::StmtKind::Mac(mac) => (mac.1, self.remove(stmt.id).make_stmts()),
-            _ => return noop_fold_stmt(stmt, self),
+            _ => return noop_flat_map_stmt(stmt, self),
         };
 
         if style == ast::MacStmtStyle::Semicolon {
@@ -165,44 +164,40 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
         stmts
     }
 
-    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
+    fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
         match pat.node {
-            ast::PatKind::Mac(_) => self.remove(pat.id).make_pat(),
-            _ => noop_fold_pat(pat, self),
+            ast::PatKind::Mac(_) => *pat = self.remove(pat.id).make_pat(),
+            _ => noop_visit_pat(pat, self),
         }
     }
 
-    fn fold_ty(&mut self, ty: P<ast::Ty>) -> P<ast::Ty> {
+    fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
         match ty.node {
-            ast::TyKind::Mac(_) => self.remove(ty.id).make_ty(),
-            _ => noop_fold_ty(ty, self),
+            ast::TyKind::Mac(_) => *ty = self.remove(ty.id).make_ty(),
+            _ => noop_visit_ty(ty, self),
         }
     }
 
-    fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
-        noop_fold_block(block, self).map(|mut block| {
-            block.stmts = block.stmts.move_map(|mut stmt| {
-                if self.monotonic {
-                    assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
-                    stmt.id = self.cx.resolver.next_node_id();
-                }
-                stmt
-            });
+    fn visit_block(&mut self, block: &mut P<ast::Block>) {
+        noop_visit_block(block, self);
 
-            block
-        })
+        for stmt in block.stmts.iter_mut() {
+            if self.monotonic {
+                assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
+                stmt.id = self.cx.resolver.next_node_id();
+            }
+        }
     }
 
-    fn fold_mod(&mut self, module: ast::Mod) -> ast::Mod {
-        let mut module = noop_fold_mod(module, self);
+    fn visit_mod(&mut self, module: &mut ast::Mod) {
+        noop_visit_mod(module, self);
         module.items.retain(|item| match item.node {
             ast::ItemKind::Mac(_) if !self.cx.ecfg.keep_macs => false, // remove macro definitions
             _ => true,
         });
-        module
     }
 
-    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
-        mac
+    fn visit_mac(&mut self, _mac: &mut ast::Mac) {
+        // Do nothing.
     }
 }
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs
index 0ef2d3b749d81..08f34b22328b6 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/tt/transcribe.rs
@@ -3,7 +3,7 @@ use ext::base::ExtCtxt;
 use ext::expand::Marker;
 use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
 use ext::tt::quoted;
-use fold::noop_fold_tt;
+use mut_visit::noop_visit_tt;
 use parse::token::{self, Token, NtTT};
 use smallvec::SmallVec;
 use syntax_pos::DUMMY_SP;
@@ -170,7 +170,9 @@ pub fn transcribe(cx: &ExtCtxt,
             }
             quoted::TokenTree::Token(sp, tok) => {
                 let mut marker = Marker(cx.current_expansion.mark);
-                result.push(noop_fold_tt(TokenTree::Token(sp, tok), &mut marker).into())
+                let mut tt = TokenTree::Token(sp, tok);
+                noop_visit_tt(&mut tt, &mut marker);
+                result.push(tt.into());
             }
             quoted::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"),
         }
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 5fb0132ad4566..93fedb73d271a 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1,11 +1,10 @@
-//! A Folder represents an AST->AST fold; it accepts an AST piece,
-//! and returns a piece of the same type. So, for instance, macro
-//! expansion is a Folder that walks over an AST and produces another
-//! AST.
+//! A MutVisitor represents an AST modification; it accepts an AST piece and
+//! and mutates it in place. So, for instance, macro expansion is a MutVisitor
+//! that walks over an AST and modifies it.
 //!
-//! Note: using a Folder (other than the MacroExpander Folder) on
+//! Note: using a MutVisitor (other than the MacroExpander MutVisitor) on
 //! an AST before macro expansion is probably a bad idea. For instance,
-//! a folder renaming item names in a module will miss all of those
+//! a MutVisitor renaming item names in a module will miss all of those
 //! that are created by the expansion of a macro.
 
 use ast::*;
@@ -14,10 +13,11 @@ use source_map::{Spanned, respan};
 use parse::token::{self, Token};
 use ptr::P;
 use smallvec::{Array, SmallVec};
+use std::ops::DerefMut;
 use symbol::keywords;
 use ThinVec;
 use tokenstream::*;
-use util::move_map::MoveMap;
+use util::map_in_place::MapInPlace;
 
 use rustc_data_structures::sync::Lrc;
 
@@ -32,1308 +32,1225 @@ impl<A: Array> ExpectOne<A> for SmallVec<A> {
     }
 }
 
-pub trait Folder : Sized {
-    // Any additions to this trait should happen in form
-    // of a call to a public `noop_*` function that only calls
-    // out to the folder again, not other `noop_*` functions.
+pub trait MutVisitor: Sized {
+    // Methods in this trait have one of three forms:
     //
-    // This is a necessary API workaround to the problem of not
-    // being able to call out to the super default method
-    // in an overridden default method.
+    //   fn visit_t(&mut self, t: &mut T);                      // common
+    //   fn flat_map_t(&mut self, t: T) -> SmallVec<[T; 1]>;    // rare
+    //   fn filter_map_t(&mut self, t: T) -> Option<T>;         // rarest
+    //
+    // Any additions to this trait should happen in form of a call to a public
+    // `noop_*` function that only calls out to the visitor again, not other
+    // `noop_*` functions. This is a necessary API workaround to the problem of
+    // not being able to call out to the super default method in an overridden
+    // default method.
+    //
+    // When writing these methods, it is better to use destructuring like this:
+    //
+    //   fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) {
+    //       visit_a(a);
+    //       visit_b(b);
+    //   }
+    //
+    // than to use field access like this:
+    //
+    //   fn visit_abc(&mut self, abc: &mut ABC) {
+    //       visit_a(&mut abc.a);
+    //       visit_b(&mut abc.b);
+    //       // ignore abc.c
+    //   }
+    //
+    // As well as being more concise, the former is explicit about which fields
+    // are skipped. Furthermore, if a new field is added, the destructuring
+    // version will cause a compile error, which is good. In comparison, the
+    // field access version will continue working and it would be easy to
+    // forget to add handling for it.
 
-    fn fold_crate(&mut self, c: Crate) -> Crate {
-        noop_fold_crate(c, self)
+    fn visit_crate(&mut self, c: &mut Crate) {
+        noop_visit_crate(c, self)
     }
 
-    fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem {
-        noop_fold_meta_list_item(list_item, self)
+    fn visit_meta_list_item(&mut self, list_item: &mut NestedMetaItem) {
+        noop_visit_meta_list_item(list_item, self);
     }
 
-    fn fold_meta_item(&mut self, meta_item: MetaItem) -> MetaItem {
-        noop_fold_meta_item(meta_item, self)
+    fn visit_meta_item(&mut self, meta_item: &mut MetaItem) {
+        noop_visit_meta_item(meta_item, self);
     }
 
-    fn fold_use_tree(&mut self, use_tree: UseTree) -> UseTree {
-        noop_fold_use_tree(use_tree, self)
+    fn visit_use_tree(&mut self, use_tree: &mut UseTree) {
+        noop_visit_use_tree(use_tree, self);
     }
 
-    fn fold_foreign_item(&mut self, ni: ForeignItem) -> SmallVec<[ForeignItem; 1]> {
-        noop_fold_foreign_item(ni, self)
+    fn flat_map_foreign_item(&mut self, ni: ForeignItem) -> SmallVec<[ForeignItem; 1]> {
+        noop_flat_map_foreign_item(ni, self)
     }
 
-    fn fold_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> {
-        noop_fold_item(i, self)
+    fn flat_map_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> {
+        noop_flat_map_item(i, self)
     }
 
-    fn fold_fn_header(&mut self, header: FnHeader) -> FnHeader {
-        noop_fold_fn_header(header, self)
+    fn visit_fn_header(&mut self, header: &mut FnHeader) {
+        noop_visit_fn_header(header, self);
     }
 
-    fn fold_struct_field(&mut self, sf: StructField) -> StructField {
-        noop_fold_struct_field(sf, self)
+    fn visit_struct_field(&mut self, sf: &mut StructField) {
+        noop_visit_struct_field(sf, self);
     }
 
-    fn fold_item_kind(&mut self, i: ItemKind) -> ItemKind {
-        noop_fold_item_kind(i, self)
+    fn visit_item_kind(&mut self, i: &mut ItemKind) {
+        noop_visit_item_kind(i, self);
     }
 
-    fn fold_trait_item(&mut self, i: TraitItem) -> SmallVec<[TraitItem; 1]> {
-        noop_fold_trait_item(i, self)
+    fn flat_map_trait_item(&mut self, i: TraitItem) -> SmallVec<[TraitItem; 1]> {
+        noop_flat_map_trait_item(i, self)
     }
 
-    fn fold_impl_item(&mut self, i: ImplItem) -> SmallVec<[ImplItem; 1]> {
-        noop_fold_impl_item(i, self)
+    fn flat_map_impl_item(&mut self, i: ImplItem) -> SmallVec<[ImplItem; 1]> {
+        noop_flat_map_impl_item(i, self)
     }
 
-    fn fold_fn_decl(&mut self, d: P<FnDecl>) -> P<FnDecl> {
-        noop_fold_fn_decl(d, self)
+    fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
+        noop_visit_fn_decl(d, self);
     }
 
-    fn fold_asyncness(&mut self, a: IsAsync) -> IsAsync {
-        noop_fold_asyncness(a, self)
+    fn visit_asyncness(&mut self, a: &mut IsAsync) {
+        noop_visit_asyncness(a, self);
     }
 
-    fn fold_block(&mut self, b: P<Block>) -> P<Block> {
-        noop_fold_block(b, self)
+    fn visit_block(&mut self, b: &mut P<Block>) {
+        noop_visit_block(b, self);
     }
 
-    fn fold_stmt(&mut self, s: Stmt) -> SmallVec<[Stmt; 1]> {
-        noop_fold_stmt(s, self)
+    fn flat_map_stmt(&mut self, s: Stmt) -> SmallVec<[Stmt; 1]> {
+        noop_flat_map_stmt(s, self)
     }
 
-    fn fold_arm(&mut self, a: Arm) -> Arm {
-        noop_fold_arm(a, self)
+    fn visit_arm(&mut self, a: &mut Arm) {
+        noop_visit_arm(a, self);
     }
 
-    fn fold_guard(&mut self, g: Guard) -> Guard {
-        noop_fold_guard(g, self)
+    fn visit_guard(&mut self, g: &mut Guard) {
+        noop_visit_guard(g, self);
     }
 
-    fn fold_pat(&mut self, p: P<Pat>) -> P<Pat> {
-        noop_fold_pat(p, self)
+    fn visit_pat(&mut self, p: &mut P<Pat>) {
+        noop_visit_pat(p, self);
     }
 
-    fn fold_anon_const(&mut self, c: AnonConst) -> AnonConst {
-        noop_fold_anon_const(c, self)
+    fn visit_anon_const(&mut self, c: &mut AnonConst) {
+        noop_visit_anon_const(c, self);
     }
 
-    fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
-        e.map(|e| noop_fold_expr(e, self))
+    fn visit_expr(&mut self, e: &mut P<Expr>) {
+        noop_visit_expr(e, self);
     }
 
-    fn fold_opt_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> {
-        noop_fold_opt_expr(e, self)
+    fn filter_map_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> {
+        noop_filter_map_expr(e, self)
     }
 
-    fn fold_generic_arg(&mut self, arg: GenericArg) -> GenericArg {
-        match arg {
-            GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.fold_lifetime(lt)),
-            GenericArg::Type(ty) => GenericArg::Type(self.fold_ty(ty)),
-        }
+    fn visit_generic_arg(&mut self, arg: &mut GenericArg) {
+        noop_visit_generic_arg(arg, self);
     }
 
-    fn fold_ty(&mut self, t: P<Ty>) -> P<Ty> {
-        noop_fold_ty(t, self)
+    fn visit_ty(&mut self, t: &mut P<Ty>) {
+        noop_visit_ty(t, self);
     }
 
-    fn fold_lifetime(&mut self, l: Lifetime) -> Lifetime {
-        noop_fold_lifetime(l, self)
+    fn visit_lifetime(&mut self, l: &mut Lifetime) {
+        noop_visit_lifetime(l, self);
     }
 
-    fn fold_ty_binding(&mut self, t: TypeBinding) -> TypeBinding {
-        noop_fold_ty_binding(t, self)
+    fn visit_ty_binding(&mut self, t: &mut TypeBinding) {
+        noop_visit_ty_binding(t, self);
     }
 
-    fn fold_mod(&mut self, m: Mod) -> Mod {
-        noop_fold_mod(m, self)
+    fn visit_mod(&mut self, m: &mut Mod) {
+        noop_visit_mod(m, self);
     }
 
-    fn fold_foreign_mod(&mut self, nm: ForeignMod) -> ForeignMod {
-        noop_fold_foreign_mod(nm, self)
+    fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) {
+        noop_visit_foreign_mod(nm, self);
     }
 
-    fn fold_variant(&mut self, v: Variant) -> Variant {
-        noop_fold_variant(v, self)
+    fn visit_variant(&mut self, v: &mut Variant) {
+        noop_visit_variant(v, self);
     }
 
-    fn fold_ident(&mut self, i: Ident) -> Ident {
-        noop_fold_ident(i, self)
+    fn visit_ident(&mut self, i: &mut Ident) {
+        noop_visit_ident(i, self);
     }
 
-    fn fold_path(&mut self, p: Path) -> Path {
-        noop_fold_path(p, self)
+    fn visit_path(&mut self, p: &mut Path) {
+        noop_visit_path(p, self);
     }
 
-    fn fold_qself(&mut self, qs: Option<QSelf>) -> Option<QSelf> {
-        noop_fold_qself(qs, self)
+    fn visit_qself(&mut self, qs: &mut Option<QSelf>) {
+        noop_visit_qself(qs, self);
     }
 
-    fn fold_generic_args(&mut self, p: GenericArgs) -> GenericArgs {
-        noop_fold_generic_args(p, self)
+    fn visit_generic_args(&mut self, p: &mut GenericArgs) {
+        noop_visit_generic_args(p, self);
     }
 
-    fn fold_angle_bracketed_parameter_data(&mut self, p: AngleBracketedArgs)
-                                           -> AngleBracketedArgs
-    {
-        noop_fold_angle_bracketed_parameter_data(p, self)
+    fn visit_angle_bracketed_parameter_data(&mut self, p: &mut AngleBracketedArgs) {
+        noop_visit_angle_bracketed_parameter_data(p, self);
     }
 
-    fn fold_parenthesized_parameter_data(&mut self, p: ParenthesizedArgs)
-                                         -> ParenthesizedArgs
-    {
-        noop_fold_parenthesized_parameter_data(p, self)
+    fn visit_parenthesized_parameter_data(&mut self, p: &mut ParenthesizedArgs) {
+        noop_visit_parenthesized_parameter_data(p, self);
     }
 
-    fn fold_local(&mut self, l: P<Local>) -> P<Local> {
-        noop_fold_local(l, self)
+    fn visit_local(&mut self, l: &mut P<Local>) {
+        noop_visit_local(l, self);
     }
 
-    fn fold_mac(&mut self, _mac: Mac) -> Mac {
-        panic!("fold_mac disabled by default");
-        // N.B., see note about macros above.
-        // if you really want a folder that
-        // works on macros, use this
-        // definition in your trait impl:
-        // fold::noop_fold_mac(_mac, self)
+    fn visit_mac(&mut self, _mac: &mut Mac) {
+        panic!("visit_mac disabled by default");
+        // N.B., see note about macros above. If you really want a visitor that
+        // works on macros, use this definition in your trait impl:
+        //   mut_visit::noop_visit_mac(_mac, self);
     }
 
-    fn fold_macro_def(&mut self, def: MacroDef) -> MacroDef {
-        noop_fold_macro_def(def, self)
+    fn visit_macro_def(&mut self, def: &mut MacroDef) {
+        noop_visit_macro_def(def, self);
     }
 
-    fn fold_label(&mut self, label: Label) -> Label {
-        noop_fold_label(label, self)
+    fn visit_label(&mut self, label: &mut Label) {
+        noop_visit_label(label, self);
     }
 
-    fn fold_attribute(&mut self, at: Attribute) -> Attribute {
-        noop_fold_attribute(at, self)
+    fn visit_attribute(&mut self, at: &mut Attribute) {
+        noop_visit_attribute(at, self);
     }
 
-    fn fold_arg(&mut self, a: Arg) -> Arg {
-        noop_fold_arg(a, self)
+    fn visit_arg(&mut self, a: &mut Arg) {
+        noop_visit_arg(a, self);
     }
 
-    fn fold_generics(&mut self, generics: Generics) -> Generics {
-        noop_fold_generics(generics, self)
+    fn visit_generics(&mut self, generics: &mut Generics) {
+        noop_visit_generics(generics, self);
     }
 
-    fn fold_trait_ref(&mut self, p: TraitRef) -> TraitRef {
-        noop_fold_trait_ref(p, self)
+    fn visit_trait_ref(&mut self, tr: &mut TraitRef) {
+        noop_visit_trait_ref(tr, self);
     }
 
-    fn fold_poly_trait_ref(&mut self, p: PolyTraitRef) -> PolyTraitRef {
-        noop_fold_poly_trait_ref(p, self)
+    fn visit_poly_trait_ref(&mut self, p: &mut PolyTraitRef) {
+        noop_visit_poly_trait_ref(p, self);
     }
 
-    fn fold_variant_data(&mut self, vdata: VariantData) -> VariantData {
-        noop_fold_variant_data(vdata, self)
+    fn visit_variant_data(&mut self, vdata: &mut VariantData) {
+        noop_visit_variant_data(vdata, self);
     }
 
-    fn fold_generic_param(&mut self, param: GenericParam) -> GenericParam {
-        noop_fold_generic_param(param, self)
+    fn visit_generic_param(&mut self, param: &mut GenericParam) {
+        noop_visit_generic_param(param, self);
     }
 
-    fn fold_generic_params(&mut self, params: Vec<GenericParam>) -> Vec<GenericParam> {
-        noop_fold_generic_params(params, self)
+    fn visit_generic_params(&mut self, params: &mut Vec<GenericParam>) {
+        noop_visit_generic_params(params, self);
     }
 
-    fn fold_tt(&mut self, tt: TokenTree) -> TokenTree {
-        noop_fold_tt(tt, self)
+    fn visit_tt(&mut self, tt: &mut TokenTree) {
+        noop_visit_tt(tt, self);
     }
 
-    fn fold_tts(&mut self, tts: TokenStream) -> TokenStream {
-        noop_fold_tts(tts, self)
+    fn visit_tts(&mut self, tts: &mut TokenStream) {
+        noop_visit_tts(tts, self);
     }
 
-    fn fold_token(&mut self, t: token::Token) -> token::Token {
-        noop_fold_token(t, self)
+    fn visit_token(&mut self, t: &mut Token) {
+        noop_visit_token(t, self);
     }
 
-    fn fold_interpolated(&mut self, nt: token::Nonterminal) -> token::Nonterminal {
-        noop_fold_interpolated(nt, self)
+    fn visit_interpolated(&mut self, nt: &mut token::Nonterminal) {
+        noop_visit_interpolated(nt, self);
     }
 
-    fn fold_param_bound(&mut self, tpb: GenericBound) -> GenericBound {
-        noop_fold_param_bound(tpb, self)
+    fn visit_param_bound(&mut self, tpb: &mut GenericBound) {
+        noop_visit_param_bound(tpb, self);
     }
 
-    fn fold_mt(&mut self, mt: MutTy) -> MutTy {
-        noop_fold_mt(mt, self)
+    fn visit_mt(&mut self, mt: &mut MutTy) {
+        noop_visit_mt(mt, self);
     }
 
-    fn fold_field(&mut self, field: Field) -> Field {
-        noop_fold_field(field, self)
+    fn visit_field(&mut self, field: &mut Field) {
+        noop_visit_field(field, self);
     }
 
-    fn fold_where_clause(&mut self, where_clause: WhereClause)
-                         -> WhereClause {
-        noop_fold_where_clause(where_clause, self)
+    fn visit_where_clause(&mut self, where_clause: &mut WhereClause) {
+        noop_visit_where_clause(where_clause, self);
     }
 
-    fn fold_where_predicate(&mut self, where_predicate: WherePredicate)
-                            -> WherePredicate {
-        noop_fold_where_predicate(where_predicate, self)
+    fn visit_where_predicate(&mut self, where_predicate: &mut WherePredicate) {
+        noop_visit_where_predicate(where_predicate, self);
     }
 
-    fn fold_vis(&mut self, vis: Visibility) -> Visibility {
-        noop_fold_vis(vis, self)
+    fn visit_vis(&mut self, vis: &mut Visibility) {
+        noop_visit_vis(vis, self);
     }
 
-    fn new_id(&mut self, i: NodeId) -> NodeId {
-        i
+    fn visit_id(&mut self, _id: &mut NodeId) {
+        // Do nothing.
     }
 
-    fn new_span(&mut self, sp: Span) -> Span {
-        sp
+    fn visit_span(&mut self, _sp: &mut Span) {
+        // Do nothing.
     }
 }
 
-// No `noop_` prefix because there isn't a corresponding method in `Folder`.
-fn fold_attrs<T: Folder>(attrs: Vec<Attribute>, fld: &mut T) -> Vec<Attribute> {
-    attrs.move_map(|x| fld.fold_attribute(x))
+/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
+/// when using a `flat_map_*` or `filter_map_*` method within a `visit_`
+/// method.
+//
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_clobber<T, F>(t: &mut T, f: F) where F: FnOnce(T) -> T {
+    unsafe { std::ptr::write(t, f(std::ptr::read(t))); }
 }
 
-// No `noop_` prefix because there isn't a corresponding method in `Folder`.
-fn fold_thin_attrs<T: Folder>(attrs: ThinVec<Attribute>, fld: &mut T) -> ThinVec<Attribute> {
-    fold_attrs(attrs.into(), fld).into()
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+#[inline]
+pub fn visit_vec<T, F>(elems: &mut Vec<T>, mut visit_elem: F) where F: FnMut(&mut T) {
+    for elem in elems {
+        visit_elem(elem);
+    }
 }
 
-// No `noop_` prefix because there isn't a corresponding method in `Folder`.
-fn fold_exprs<T: Folder>(es: Vec<P<Expr>>, fld: &mut T) -> Vec<P<Expr>> {
-    es.move_flat_map(|e| fld.fold_opt_expr(e))
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+#[inline]
+pub fn visit_opt<T, F>(opt: &mut Option<T>, mut visit_elem: F) where F: FnMut(&mut T) {
+    if let Some(elem) = opt {
+        visit_elem(elem);
+    }
 }
 
-// No `noop_` prefix because there isn't a corresponding method in `Folder`.
-fn fold_bounds<T: Folder>(bounds: GenericBounds, folder: &mut T) -> GenericBounds {
-    bounds.move_map(|bound| folder.fold_param_bound(bound))
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_attrs<T: MutVisitor>(attrs: &mut Vec<Attribute>, vis: &mut T) {
+    visit_vec(attrs, |attr| vis.visit_attribute(attr));
 }
 
-// No `noop_` prefix because there isn't a corresponding method in `Folder`.
-fn fold_method_sig<T: Folder>(sig: MethodSig, folder: &mut T) -> MethodSig {
-    MethodSig {
-        header: folder.fold_fn_header(sig.header),
-        decl: folder.fold_fn_decl(sig.decl)
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_thin_attrs<T: MutVisitor>(attrs: &mut ThinVec<Attribute>, vis: &mut T) {
+    for attr in attrs.iter_mut() {
+        vis.visit_attribute(attr);
     }
 }
 
-pub fn noop_fold_use_tree<T: Folder>(use_tree: UseTree, fld: &mut T) -> UseTree {
-    UseTree {
-        span: fld.new_span(use_tree.span),
-        prefix: fld.fold_path(use_tree.prefix),
-        kind: match use_tree.kind {
-            UseTreeKind::Simple(rename, id1, id2) =>
-                UseTreeKind::Simple(rename.map(|ident| fld.fold_ident(ident)),
-                                    fld.new_id(id1), fld.new_id(id2)),
-            UseTreeKind::Glob => UseTreeKind::Glob,
-            UseTreeKind::Nested(items) => UseTreeKind::Nested(items.move_map(|(tree, id)| {
-                (fld.fold_use_tree(tree), fld.new_id(id))
-            })),
-        },
-    }
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_exprs<T: MutVisitor>(exprs: &mut Vec<P<Expr>>, vis: &mut T) {
+    exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr))
 }
 
-pub fn noop_fold_arm<T: Folder>(Arm {attrs, pats, guard, body}: Arm,
-    fld: &mut T) -> Arm {
-    Arm {
-        attrs: fold_attrs(attrs, fld),
-        pats: pats.move_map(|x| fld.fold_pat(x)),
-        guard: guard.map(|x| fld.fold_guard(x)),
-        body: fld.fold_expr(body),
-    }
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_bounds<T: MutVisitor>(bounds: &mut GenericBounds, vis: &mut T) {
+    visit_vec(bounds, |bound| vis.visit_param_bound(bound));
 }
 
-pub fn noop_fold_guard<T: Folder>(g: Guard, fld: &mut T) -> Guard {
-    match g {
-        Guard::If(e) => Guard::If(fld.fold_expr(e)),
-    }
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_method_sig<T: MutVisitor>(MethodSig { header, decl }: &mut MethodSig, vis: &mut T) {
+    vis.visit_fn_header(header);
+    vis.visit_fn_decl(decl);
 }
 
-pub fn noop_fold_ty_binding<T: Folder>(b: TypeBinding, fld: &mut T) -> TypeBinding {
-    TypeBinding {
-        id: fld.new_id(b.id),
-        ident: fld.fold_ident(b.ident),
-        ty: fld.fold_ty(b.ty),
-        span: fld.new_span(b.span),
+pub fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) {
+    let UseTree { prefix, kind, span } = use_tree;
+    vis.visit_path(prefix);
+    match kind {
+        UseTreeKind::Simple(rename, id1, id2) => {
+            visit_opt(rename, |rename| vis.visit_ident(rename));
+            vis.visit_id(id1);
+            vis.visit_id(id2);
+        }
+        UseTreeKind::Nested(items) => {
+            for (tree, id) in items {
+                vis.visit_use_tree(tree);
+                vis.visit_id(id);
+            }
+        }
+        UseTreeKind::Glob => {}
     }
+    vis.visit_span(span);
 }
 
-pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
-    t.map(|Ty {id, node, span}| Ty {
-        id: fld.new_id(id),
-        node: match node {
-            TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => node,
-            TyKind::Slice(ty) => TyKind::Slice(fld.fold_ty(ty)),
-            TyKind::Ptr(mt) => TyKind::Ptr(fld.fold_mt(mt)),
-            TyKind::Rptr(region, mt) => {
-                TyKind::Rptr(region.map(|lt| noop_fold_lifetime(lt, fld)), fld.fold_mt(mt))
-            }
-            TyKind::BareFn(f) => {
-                TyKind::BareFn(f.map(|BareFnTy {generic_params, unsafety, abi, decl}| BareFnTy {
-                    generic_params: fld.fold_generic_params(generic_params),
-                    unsafety,
-                    abi,
-                    decl: fld.fold_fn_decl(decl)
-                }))
-            }
-            TyKind::Never => node,
-            TyKind::Tup(tys) => TyKind::Tup(tys.move_map(|ty| fld.fold_ty(ty))),
-            TyKind::Paren(ty) => TyKind::Paren(fld.fold_ty(ty)),
-            TyKind::Path(qself, path) => {
-                TyKind::Path(fld.fold_qself(qself), fld.fold_path(path))
-            }
-            TyKind::Array(ty, length) => {
-                TyKind::Array(fld.fold_ty(ty), fld.fold_anon_const(length))
-            }
-            TyKind::Typeof(expr) => {
-                TyKind::Typeof(fld.fold_anon_const(expr))
-            }
-            TyKind::TraitObject(bounds, syntax) => {
-                TyKind::TraitObject(bounds.move_map(|b| fld.fold_param_bound(b)), syntax)
-            }
-            TyKind::ImplTrait(id, bounds) => {
-                TyKind::ImplTrait(fld.new_id(id), bounds.move_map(|b| fld.fold_param_bound(b)))
-            }
-            TyKind::Mac(mac) => {
-                TyKind::Mac(fld.fold_mac(mac))
-            }
-        },
-        span: fld.new_span(span)
-    })
+pub fn noop_visit_arm<T: MutVisitor>(Arm { attrs, pats, guard, body }: &mut Arm, vis: &mut T) {
+    visit_attrs(attrs, vis);
+    visit_vec(pats, |pat| vis.visit_pat(pat));
+    visit_opt(guard, |guard| vis.visit_guard(guard));
+    vis.visit_expr(body);
 }
 
-pub fn noop_fold_foreign_mod<T: Folder>(ForeignMod {abi, items}: ForeignMod,
-                                        fld: &mut T) -> ForeignMod {
-    ForeignMod {
-        abi,
-        items: items.move_flat_map(|x| fld.fold_foreign_item(x)),
+pub fn noop_visit_guard<T: MutVisitor>(g: &mut Guard, vis: &mut T) {
+    match g {
+        Guard::If(e) => vis.visit_expr(e),
     }
 }
 
-pub fn noop_fold_variant<T: Folder>(v: Variant, fld: &mut T) -> Variant {
-    Spanned {
-        node: Variant_ {
-            ident: fld.fold_ident(v.node.ident),
-            attrs: fold_attrs(v.node.attrs, fld),
-            data: fld.fold_variant_data(v.node.data),
-            disr_expr: v.node.disr_expr.map(|e| fld.fold_anon_const(e)),
-        },
-        span: fld.new_span(v.span),
+pub fn noop_visit_ty_binding<T: MutVisitor>(TypeBinding { id, ident, ty, span }: &mut TypeBinding,
+                                            vis: &mut T) {
+    vis.visit_id(id);
+    vis.visit_ident(ident);
+    vis.visit_ty(ty);
+    vis.visit_span(span);
+}
+
+pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
+    let Ty { id, node, span } = ty.deref_mut();
+    vis.visit_id(id);
+    match node {
+        TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never => {}
+        TyKind::Slice(ty) => vis.visit_ty(ty),
+        TyKind::Ptr(mt) => vis.visit_mt(mt),
+        TyKind::Rptr(lt, mt) => {
+            visit_opt(lt, |lt| noop_visit_lifetime(lt, vis));
+            vis.visit_mt(mt);
+        }
+        TyKind::BareFn(bft) => {
+            let BareFnTy { unsafety: _, abi: _, generic_params, decl } = bft.deref_mut();
+            vis.visit_generic_params(generic_params);
+            vis.visit_fn_decl(decl);
+        }
+        TyKind::Tup(tys) => visit_vec(tys, |ty| vis.visit_ty(ty)),
+        TyKind::Paren(ty) => vis.visit_ty(ty),
+        TyKind::Path(qself, path) => {
+            vis.visit_qself(qself);
+            vis.visit_path(path);
+        }
+        TyKind::Array(ty, length) => {
+            vis.visit_ty(ty);
+            vis.visit_anon_const(length);
+        }
+        TyKind::Typeof(expr) => vis.visit_anon_const(expr),
+        TyKind::TraitObject(bounds, _syntax) =>
+            visit_vec(bounds, |bound| vis.visit_param_bound(bound)),
+        TyKind::ImplTrait(id, bounds) => {
+            vis.visit_id(id);
+            visit_vec(bounds, |bound| vis.visit_param_bound(bound));
+        }
+        TyKind::Mac(mac) => vis.visit_mac(mac),
     }
+    vis.visit_span(span);
+}
+
+pub fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) {
+    let ForeignMod { abi: _, items} = foreign_mod;
+    items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
+}
+
+pub fn noop_visit_variant<T: MutVisitor>(variant: &mut Variant, vis: &mut T) {
+    let Spanned { node: Variant_ { ident, attrs, data, disr_expr }, span } = variant;
+    vis.visit_ident(ident);
+    visit_attrs(attrs, vis);
+    vis.visit_variant_data(data);
+    visit_opt(disr_expr, |disr_expr| vis.visit_anon_const(disr_expr));
+    vis.visit_span(span);
 }
 
-pub fn noop_fold_ident<T: Folder>(ident: Ident, fld: &mut T) -> Ident {
-    Ident::new(ident.name, fld.new_span(ident.span))
+pub fn noop_visit_ident<T: MutVisitor>(Ident { name: _, span }: &mut Ident, vis: &mut T) {
+    vis.visit_span(span);
 }
 
-pub fn noop_fold_path<T: Folder>(Path { segments, span }: Path, fld: &mut T) -> Path {
-    Path {
-        segments: segments.move_map(|PathSegment { ident, id, args }| PathSegment {
-            ident: fld.fold_ident(ident),
-            id: fld.new_id(id),
-            args: args.map(|args| args.map(|args| fld.fold_generic_args(args))),
-        }),
-        span: fld.new_span(span)
+pub fn noop_visit_path<T: MutVisitor>(Path { segments, span }: &mut Path, vis: &mut T) {
+    vis.visit_span(span);
+    for PathSegment { ident, id, args } in segments {
+        vis.visit_ident(ident);
+        vis.visit_id(id);
+        visit_opt(args, |args| vis.visit_generic_args(args));
     }
 }
 
-pub fn noop_fold_qself<T: Folder>(qself: Option<QSelf>, fld: &mut T) -> Option<QSelf> {
-    qself.map(|QSelf { ty, path_span, position }| {
-        QSelf {
-            ty: fld.fold_ty(ty),
-            path_span: fld.new_span(path_span),
-            position,
-        }
+pub fn noop_visit_qself<T: MutVisitor>(qself: &mut Option<QSelf>, vis: &mut T) {
+    visit_opt(qself, |QSelf { ty, path_span, position: _ }| {
+        vis.visit_ty(ty);
+        vis.visit_span(path_span);
     })
 }
 
-pub fn noop_fold_generic_args<T: Folder>(generic_args: GenericArgs, fld: &mut T) -> GenericArgs
-{
+pub fn noop_visit_generic_args<T: MutVisitor>(generic_args: &mut GenericArgs, vis: &mut T) {
     match generic_args {
-        GenericArgs::AngleBracketed(data) => {
-            GenericArgs::AngleBracketed(fld.fold_angle_bracketed_parameter_data(data))
-        }
-        GenericArgs::Parenthesized(data) => {
-            GenericArgs::Parenthesized(fld.fold_parenthesized_parameter_data(data))
-        }
+        GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data),
+        GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data),
     }
 }
 
-pub fn noop_fold_angle_bracketed_parameter_data<T: Folder>(data: AngleBracketedArgs,
-                                                           fld: &mut T)
-                                                           -> AngleBracketedArgs
-{
-    let AngleBracketedArgs { args, bindings, span } = data;
-    AngleBracketedArgs {
-        args: args.move_map(|arg| fld.fold_generic_arg(arg)),
-        bindings: bindings.move_map(|b| fld.fold_ty_binding(b)),
-        span: fld.new_span(span)
+pub fn noop_visit_generic_arg<T: MutVisitor>(arg: &mut GenericArg, vis: &mut T) {
+    match arg {
+        GenericArg::Lifetime(lt) => vis.visit_lifetime(lt),
+        GenericArg::Type(ty) => vis.visit_ty(ty),
     }
 }
 
-pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedArgs,
-                                                         fld: &mut T)
-                                                         -> ParenthesizedArgs
-{
-    let ParenthesizedArgs { inputs, output, span } = data;
-    ParenthesizedArgs {
-        inputs: inputs.move_map(|ty| fld.fold_ty(ty)),
-        output: output.map(|ty| fld.fold_ty(ty)),
-        span: fld.new_span(span)
-    }
-}
-
-pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
-    l.map(|Local {id, pat, ty, init, span, attrs}| Local {
-        id: fld.new_id(id),
-        pat: fld.fold_pat(pat),
-        ty: ty.map(|t| fld.fold_ty(t)),
-        init: init.map(|e| fld.fold_expr(e)),
-        span: fld.new_span(span),
-        attrs: fold_attrs(attrs.into(), fld).into(),
-    })
+pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(data: &mut AngleBracketedArgs,
+                                                                vis: &mut T) {
+    let AngleBracketedArgs { args, bindings, span } = data;
+    visit_vec(args, |arg| vis.visit_generic_arg(arg));
+    visit_vec(bindings, |binding| vis.visit_ty_binding(binding));
+    vis.visit_span(span);
 }
 
-pub fn noop_fold_attribute<T: Folder>(attr: Attribute, fld: &mut T) -> Attribute {
-    Attribute {
-        id: attr.id,
-        style: attr.style,
-        path: fld.fold_path(attr.path),
-        tokens: fld.fold_tts(attr.tokens),
-        is_sugared_doc: attr.is_sugared_doc,
-        span: fld.new_span(attr.span),
-    }
+pub fn noop_visit_parenthesized_parameter_data<T: MutVisitor>(args: &mut ParenthesizedArgs,
+                                                              vis: &mut T) {
+    let ParenthesizedArgs { inputs, output, span } = args;
+    visit_vec(inputs, |input| vis.visit_ty(input));
+    visit_opt(output, |output| vis.visit_ty(output));
+    vis.visit_span(span);
 }
 
-pub fn noop_fold_mac<T: Folder>(Spanned {node, span}: Mac, fld: &mut T) -> Mac {
-    Spanned {
-        node: Mac_ {
-            tts: fld.fold_tts(node.stream()).into(),
-            path: fld.fold_path(node.path),
-            delim: node.delim,
-        },
-        span: fld.new_span(span)
-    }
+pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
+    let Local { id, pat, ty, init, span, attrs } = local.deref_mut();
+    vis.visit_id(id);
+    vis.visit_pat(pat);
+    visit_opt(ty, |ty| vis.visit_ty(ty));
+    visit_opt(init, |init| vis.visit_expr(init));
+    vis.visit_span(span);
+    visit_thin_attrs(attrs, vis);
 }
 
-pub fn noop_fold_macro_def<T: Folder>(def: MacroDef, fld: &mut T) -> MacroDef {
-    MacroDef {
-        tokens: fld.fold_tts(def.tokens.into()).into(),
-        legacy: def.legacy,
-    }
+pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
+    let Attribute { id: _, style: _, path, tokens, is_sugared_doc: _, span } = attr;
+    vis.visit_path(path);
+    vis.visit_tts(tokens);
+    vis.visit_span(span);
 }
 
-pub fn noop_fold_meta_list_item<T: Folder>(li: NestedMetaItem, fld: &mut T)
-    -> NestedMetaItem {
-    Spanned {
-        node: match li.node {
-            NestedMetaItemKind::MetaItem(mi) =>  {
-                NestedMetaItemKind::MetaItem(fld.fold_meta_item(mi))
-            },
-            NestedMetaItemKind::Literal(lit) => NestedMetaItemKind::Literal(lit)
-        },
-        span: fld.new_span(li.span)
-    }
+pub fn noop_visit_mac<T: MutVisitor>(Spanned { node, span }: &mut Mac, vis: &mut T) {
+    let Mac_ { path, delim: _, tts } = node;
+    vis.visit_path(path);
+    vis.visit_tts(tts);
+    vis.visit_span(span);
 }
 
-pub fn noop_fold_meta_item<T: Folder>(mi: MetaItem, fld: &mut T) -> MetaItem {
-    MetaItem {
-        ident: mi.ident,
-        node: match mi.node {
-            MetaItemKind::Word => MetaItemKind::Word,
-            MetaItemKind::List(mis) => {
-                MetaItemKind::List(mis.move_map(|e| fld.fold_meta_list_item(e)))
-            },
-            MetaItemKind::NameValue(s) => MetaItemKind::NameValue(s),
-        },
-        span: fld.new_span(mi.span)
+pub fn noop_visit_macro_def<T: MutVisitor>(macro_def: &mut MacroDef, vis: &mut T) {
+    let MacroDef { tokens, legacy: _ } = macro_def;
+    vis.visit_tts(tokens);
+}
+
+pub fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T) {
+    let Spanned { node, span } = li;
+    match node {
+        NestedMetaItemKind::MetaItem(mi) => vis.visit_meta_item(mi),
+        NestedMetaItemKind::Literal(_lit) => {}
     }
+    vis.visit_span(span);
 }
 
-pub fn noop_fold_arg<T: Folder>(Arg {id, pat, ty}: Arg, fld: &mut T) -> Arg {
-    Arg {
-        id: fld.new_id(id),
-        pat: fld.fold_pat(pat),
-        ty: fld.fold_ty(ty)
+pub fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) {
+    let MetaItem { ident: _, node, span } = mi;
+    match node {
+        MetaItemKind::Word => {}
+        MetaItemKind::List(mis) => visit_vec(mis, |mi| vis.visit_meta_list_item(mi)),
+        MetaItemKind::NameValue(_s) => {}
     }
+    vis.visit_span(span);
+}
+
+pub fn noop_visit_arg<T: MutVisitor>(Arg { id, pat, ty }: &mut Arg, vis: &mut T) {
+    vis.visit_id(id);
+    vis.visit_pat(pat);
+    vis.visit_ty(ty);
 }
 
-pub fn noop_fold_tt<T: Folder>(tt: TokenTree, fld: &mut T) -> TokenTree {
+pub fn noop_visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) {
     match tt {
-        TokenTree::Token(span, tok) =>
-            TokenTree::Token(fld.new_span(span), fld.fold_token(tok)),
-        TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited(
-            DelimSpan::from_pair(fld.new_span(span.open), fld.new_span(span.close)),
-            delim,
-            fld.fold_tts(tts).into(),
-        ),
+        TokenTree::Token(span, tok) => {
+            vis.visit_span(span);
+            vis.visit_token(tok);
+        }
+        TokenTree::Delimited(DelimSpan { open, close }, _delim, tts) => {
+            vis.visit_span(open);
+            vis.visit_span(close);
+            vis.visit_tts(tts);
+        }
     }
 }
 
-pub fn noop_fold_tts<T: Folder>(tts: TokenStream, fld: &mut T) -> TokenStream {
-    tts.map(|tt| fld.fold_tt(tt))
+pub fn noop_visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T) {
+    visit_opt(tts, |tts| {
+        let tts = Lrc::make_mut(tts);
+        visit_vec(tts, |(tree, _is_joint)| vis.visit_tt(tree));
+    })
 }
 
-// apply ident folder if it's an ident, apply other folds to interpolated nodes
-pub fn noop_fold_token<T: Folder>(t: token::Token, fld: &mut T) -> token::Token {
+// apply ident visitor if it's an ident, apply other visits to interpolated nodes
+pub fn noop_visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
     match t {
-        token::Ident(id, is_raw) => token::Ident(fld.fold_ident(id), is_raw),
-        token::Lifetime(id) => token::Lifetime(fld.fold_ident(id)),
+        token::Ident(id, _is_raw) => vis.visit_ident(id),
+        token::Lifetime(id) => vis.visit_ident(id),
         token::Interpolated(nt) => {
-            let nt = match Lrc::try_unwrap(nt) {
-                Ok(nt) => nt,
-                Err(nt) => (*nt).clone(),
-            };
-            Token::interpolated(fld.fold_interpolated(nt.0))
+            let nt = Lrc::make_mut(nt);
+            vis.visit_interpolated(&mut nt.0);
+            nt.1 = token::LazyTokenStream::new();
         }
-        _ => t
+        _ => {}
     }
 }
 
-/// apply folder to elements of interpolated nodes
+/// Apply visitor to elements of interpolated nodes.
 //
-// N.B., this can occur only when applying a fold to partially expanded code, where
-// parsed pieces have gotten implanted ito *other* macro invocations. This is relevant
-// for macro hygiene, but possibly not elsewhere.
+// N.B., this can occur only when applying a visitor to partially expanded
+// code, where parsed pieces have gotten implanted ito *other* macro
+// invocations. This is relevant for macro hygiene, but possibly not elsewhere.
 //
-// One problem here occurs because the types for fold_item, fold_stmt, etc. allow the
-// folder to return *multiple* items; this is a problem for the nodes here, because
-// they insist on having exactly one piece. One solution would be to mangle the fold
-// trait to include one-to-many and one-to-one versions of these entry points, but that
-// would probably confuse a lot of people and help very few. Instead, I'm just going
-// to put in dynamic checks. I think the performance impact of this will be pretty much
-// nonexistent. The danger is that someone will apply a fold to a partially expanded
-// node, and will be confused by the fact that their "fold_item" or "fold_stmt" isn't
-// getting called on NtItem or NtStmt nodes. Hopefully they'll wind up reading this
-// comment, and doing something appropriate.
+// One problem here occurs because the types for flat_map_item, flat_map_stmt,
+// etc. allow the visitor to return *multiple* items; this is a problem for the
+// nodes here, because they insist on having exactly one piece. One solution
+// would be to mangle the MutVisitor trait to include one-to-many and
+// one-to-one versions of these entry points, but that would probably confuse a
+// lot of people and help very few. Instead, I'm just going to put in dynamic
+// checks. I think the performance impact of this will be pretty much
+// nonexistent. The danger is that someone will apply a MutVisitor to a
+// partially expanded node, and will be confused by the fact that their
+// "flat_map_item" or "flat_map_stmt" isn't getting called on NtItem or NtStmt
+// nodes. Hopefully they'll wind up reading this comment, and doing something
+// appropriate.
 //
-// BTW, design choice: I considered just changing the type of, e.g., NtItem to contain
-// multiple items, but decided against it when I looked at parse_item_or_view_item and
-// tried to figure out what I would do with multiple items there....
-pub fn noop_fold_interpolated<T: Folder>(nt: token::Nonterminal, fld: &mut T)
-                                         -> token::Nonterminal {
+// BTW, design choice: I considered just changing the type of, e.g., NtItem to
+// contain multiple items, but decided against it when I looked at
+// parse_item_or_view_item and tried to figure out what I would do with
+// multiple items there....
+pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
     match nt {
         token::NtItem(item) =>
-            token::NtItem(fld.fold_item(item)
-                          // this is probably okay, because the only folds likely
-                          // to peek inside interpolated nodes will be renamings/markings,
-                          // which map single items to single items
-                          .expect_one("expected fold to produce exactly one item")),
-        token::NtBlock(block) => token::NtBlock(fld.fold_block(block)),
+            visit_clobber(item, |item| {
+                // This is probably okay, because the only visitors likely to
+                // peek inside interpolated nodes will be renamings/markings,
+                // which map single items to single items.
+                vis.flat_map_item(item).expect_one("expected visitor to produce exactly one item")
+            }),
+        token::NtBlock(block) => vis.visit_block(block),
         token::NtStmt(stmt) =>
-            token::NtStmt(fld.fold_stmt(stmt)
-                          // this is probably okay, because the only folds likely
-                          // to peek inside interpolated nodes will be renamings/markings,
-                          // which map single items to single items
-                          .expect_one("expected fold to produce exactly one statement")),
-        token::NtPat(pat) => token::NtPat(fld.fold_pat(pat)),
-        token::NtExpr(expr) => token::NtExpr(fld.fold_expr(expr)),
-        token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)),
-        token::NtIdent(ident, is_raw) => token::NtIdent(fld.fold_ident(ident), is_raw),
-        token::NtLifetime(ident) => token::NtLifetime(fld.fold_ident(ident)),
-        token::NtLiteral(expr) => token::NtLiteral(fld.fold_expr(expr)),
-        token::NtMeta(meta) => token::NtMeta(fld.fold_meta_item(meta)),
-        token::NtPath(path) => token::NtPath(fld.fold_path(path)),
-        token::NtTT(tt) => token::NtTT(fld.fold_tt(tt)),
-        token::NtArm(arm) => token::NtArm(fld.fold_arm(arm)),
+            visit_clobber(stmt, |stmt| {
+                // See reasoning above.
+                vis.flat_map_stmt(stmt).expect_one("expected visitor to produce exactly one item")
+            }),
+        token::NtPat(pat) => vis.visit_pat(pat),
+        token::NtExpr(expr) => vis.visit_expr(expr),
+        token::NtTy(ty) => vis.visit_ty(ty),
+        token::NtIdent(ident, _is_raw) => vis.visit_ident(ident),
+        token::NtLifetime(ident) => vis.visit_ident(ident),
+        token::NtLiteral(expr) => vis.visit_expr(expr),
+        token::NtMeta(meta) => vis.visit_meta_item(meta),
+        token::NtPath(path) => vis.visit_path(path),
+        token::NtTT(tt) => vis.visit_tt(tt),
+        token::NtArm(arm) => vis.visit_arm(arm),
         token::NtImplItem(item) =>
-            token::NtImplItem(fld.fold_impl_item(item)
-                              .expect_one("expected fold to produce exactly one item")),
+            visit_clobber(item, |item| {
+                // See reasoning above.
+                vis.flat_map_impl_item(item)
+                    .expect_one("expected visitor to produce exactly one item")
+            }),
         token::NtTraitItem(item) =>
-            token::NtTraitItem(fld.fold_trait_item(item)
-                               .expect_one("expected fold to produce exactly one item")),
-        token::NtGenerics(generics) => token::NtGenerics(fld.fold_generics(generics)),
-        token::NtWhereClause(where_clause) =>
-            token::NtWhereClause(fld.fold_where_clause(where_clause)),
-        token::NtArg(arg) => token::NtArg(fld.fold_arg(arg)),
-        token::NtVis(vis) => token::NtVis(fld.fold_vis(vis)),
-        token::NtForeignItem(ni) =>
-            token::NtForeignItem(fld.fold_foreign_item(ni)
-                                 // see reasoning above
-                                 .expect_one("expected fold to produce exactly one item")),
-    }
-}
-
-pub fn noop_fold_asyncness<T: Folder>(asyncness: IsAsync, fld: &mut T) -> IsAsync {
+            visit_clobber(item, |item| {
+                // See reasoning above.
+                vis.flat_map_trait_item(item)
+                    .expect_one("expected visitor to produce exactly one item")
+            }),
+        token::NtGenerics(generics) => vis.visit_generics(generics),
+        token::NtWhereClause(where_clause) => vis.visit_where_clause(where_clause),
+        token::NtArg(arg) => vis.visit_arg(arg),
+        token::NtVis(visib) => vis.visit_vis(visib),
+        token::NtForeignItem(item) =>
+            visit_clobber(item, |item| {
+                // See reasoning above.
+                vis.flat_map_foreign_item(item)
+                    .expect_one("expected visitor to produce exactly one item")
+            }),
+    }
+}
+
+pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut IsAsync, vis: &mut T) {
     match asyncness {
-        IsAsync::Async { closure_id, return_impl_trait_id } => IsAsync::Async {
-            closure_id: fld.new_id(closure_id),
-            return_impl_trait_id: fld.new_id(return_impl_trait_id),
-        },
-        IsAsync::NotAsync => IsAsync::NotAsync,
+        IsAsync::Async { closure_id, return_impl_trait_id } => {
+            vis.visit_id(closure_id);
+            vis.visit_id(return_impl_trait_id);
+        }
+        IsAsync::NotAsync => {}
     }
 }
 
-pub fn noop_fold_fn_decl<T: Folder>(decl: P<FnDecl>, fld: &mut T) -> P<FnDecl> {
-    decl.map(|FnDecl {inputs, output, variadic}| FnDecl {
-        inputs: inputs.move_map(|x| fld.fold_arg(x)),
-        output: match output {
-            FunctionRetTy::Ty(ty) => FunctionRetTy::Ty(fld.fold_ty(ty)),
-            FunctionRetTy::Default(span) => FunctionRetTy::Default(fld.new_span(span)),
-        },
-        variadic,
-    })
+pub fn noop_visit_fn_decl<T: MutVisitor>(decl: &mut P<FnDecl>, vis: &mut T) {
+    let FnDecl { inputs, output, variadic: _ } = decl.deref_mut();
+    visit_vec(inputs, |input| vis.visit_arg(input));
+    match output {
+        FunctionRetTy::Default(span) => vis.visit_span(span),
+        FunctionRetTy::Ty(ty) => vis.visit_ty(ty),
+    }
 }
 
-pub fn noop_fold_param_bound<T>(pb: GenericBound, fld: &mut T) -> GenericBound where T: Folder {
+pub fn noop_visit_param_bound<T: MutVisitor>(pb: &mut GenericBound, vis: &mut T) {
     match pb {
-        GenericBound::Trait(ty, modifier) => {
-            GenericBound::Trait(fld.fold_poly_trait_ref(ty), modifier)
-        }
-        GenericBound::Outlives(lifetime) => {
-            GenericBound::Outlives(noop_fold_lifetime(lifetime, fld))
-        }
+        GenericBound::Trait(ty, _modifier) => vis.visit_poly_trait_ref(ty),
+        GenericBound::Outlives(lifetime) => noop_visit_lifetime(lifetime, vis),
     }
 }
 
-pub fn noop_fold_generic_param<T: Folder>(param: GenericParam, fld: &mut T) -> GenericParam {
-    GenericParam {
-        ident: fld.fold_ident(param.ident),
-        id: fld.new_id(param.id),
-        attrs: fold_thin_attrs(param.attrs, fld),
-        bounds: param.bounds.move_map(|l| noop_fold_param_bound(l, fld)),
-        kind: match param.kind {
-            GenericParamKind::Lifetime => GenericParamKind::Lifetime,
-            GenericParamKind::Type { default } => GenericParamKind::Type {
-                default: default.map(|ty| fld.fold_ty(ty))
-            }
+pub fn noop_visit_generic_param<T: MutVisitor>(param: &mut GenericParam, vis: &mut T) {
+    let GenericParam { id, ident, attrs, bounds, kind } = param;
+    vis.visit_id(id);
+    vis.visit_ident(ident);
+    visit_thin_attrs(attrs, vis);
+    visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis));
+    match kind {
+        GenericParamKind::Lifetime => {}
+        GenericParamKind::Type { default } => {
+            visit_opt(default, |default| vis.visit_ty(default));
         }
     }
 }
 
-pub fn noop_fold_generic_params<T: Folder>(
-    params: Vec<GenericParam>,
-    fld: &mut T
-) -> Vec<GenericParam> {
-    params.move_map(|p| fld.fold_generic_param(p))
+pub fn noop_visit_generic_params<T: MutVisitor>(params: &mut Vec<GenericParam>, vis: &mut T){
+    visit_vec(params, |param| vis.visit_generic_param(param));
 }
 
-pub fn noop_fold_label<T: Folder>(label: Label, fld: &mut T) -> Label {
-    Label {
-        ident: fld.fold_ident(label.ident),
-    }
+pub fn noop_visit_label<T: MutVisitor>(Label { ident }: &mut Label, vis: &mut T) {
+    vis.visit_ident(ident);
 }
 
-fn noop_fold_lifetime<T: Folder>(l: Lifetime, fld: &mut T) -> Lifetime {
-    Lifetime {
-        id: fld.new_id(l.id),
-        ident: fld.fold_ident(l.ident),
-    }
+fn noop_visit_lifetime<T: MutVisitor>(Lifetime { id, ident }: &mut Lifetime, vis: &mut T) {
+    vis.visit_id(id);
+    vis.visit_ident(ident);
 }
 
-pub fn noop_fold_generics<T: Folder>(Generics { params, where_clause, span }: Generics,
-                                     fld: &mut T) -> Generics {
-    Generics {
-        params: fld.fold_generic_params(params),
-        where_clause: fld.fold_where_clause(where_clause),
-        span: fld.new_span(span),
-    }
+pub fn noop_visit_generics<T: MutVisitor>(generics: &mut Generics, vis: &mut T) {
+    let Generics { params, where_clause, span } = generics;
+    vis.visit_generic_params(params);
+    vis.visit_where_clause(where_clause);
+    vis.visit_span(span);
 }
 
-pub fn noop_fold_where_clause<T: Folder>(
-                              WhereClause {id, predicates, span}: WhereClause,
-                              fld: &mut T)
-                              -> WhereClause {
-    WhereClause {
-        id: fld.new_id(id),
-        predicates: predicates.move_map(|predicate| {
-            fld.fold_where_predicate(predicate)
-        }),
-        span: fld.new_span(span),
-    }
+pub fn noop_visit_where_clause<T: MutVisitor>(wc: &mut WhereClause, vis: &mut T) {
+    let WhereClause { id, predicates, span } = wc;
+    vis.visit_id(id);
+    visit_vec(predicates, |predicate| vis.visit_where_predicate(predicate));
+    vis.visit_span(span);
 }
 
-pub fn noop_fold_where_predicate<T: Folder>(
-                                 pred: WherePredicate,
-                                 fld: &mut T)
-                                 -> WherePredicate {
+pub fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis: &mut T) {
     match pred {
-        WherePredicate::BoundPredicate(WhereBoundPredicate { bound_generic_params,
-                                                             bounded_ty,
-                                                             bounds,
-                                                             span }) => {
-            WherePredicate::BoundPredicate(WhereBoundPredicate {
-                bound_generic_params: fld.fold_generic_params(bound_generic_params),
-                bounded_ty: fld.fold_ty(bounded_ty),
-                bounds: bounds.move_map(|x| fld.fold_param_bound(x)),
-                span: fld.new_span(span)
-            })
-        }
-        WherePredicate::RegionPredicate(WhereRegionPredicate { lifetime, bounds, span }) => {
-            WherePredicate::RegionPredicate(WhereRegionPredicate {
-                span: fld.new_span(span),
-                lifetime: noop_fold_lifetime(lifetime, fld),
-                bounds: bounds.move_map(|bound| noop_fold_param_bound(bound, fld))
-            })
-        }
-        WherePredicate::EqPredicate(WhereEqPredicate { id, lhs_ty, rhs_ty, span }) => {
-            WherePredicate::EqPredicate(WhereEqPredicate{
-                id: fld.new_id(id),
-                lhs_ty: fld.fold_ty(lhs_ty),
-                rhs_ty: fld.fold_ty(rhs_ty),
-                span: fld.new_span(span)
-            })
-        }
-    }
-}
-
-pub fn noop_fold_variant_data<T: Folder>(vdata: VariantData, fld: &mut T) -> VariantData {
-    match vdata {
-        VariantData::Struct(fields, id) => {
-            VariantData::Struct(fields.move_map(|f| fld.fold_struct_field(f)), fld.new_id(id))
+        WherePredicate::BoundPredicate(bp) => {
+            let WhereBoundPredicate { span, bound_generic_params, bounded_ty, bounds } = bp;
+            vis.visit_span(span);
+            vis.visit_generic_params(bound_generic_params);
+            vis.visit_ty(bounded_ty);
+            visit_vec(bounds, |bound| vis.visit_param_bound(bound));
         }
-        VariantData::Tuple(fields, id) => {
-            VariantData::Tuple(fields.move_map(|f| fld.fold_struct_field(f)), fld.new_id(id))
+        WherePredicate::RegionPredicate(rp) => {
+            let WhereRegionPredicate { span, lifetime, bounds } = rp;
+            vis.visit_span(span);
+            noop_visit_lifetime(lifetime, vis);
+            visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis));
+        }
+        WherePredicate::EqPredicate(ep) => {
+            let WhereEqPredicate { id, span, lhs_ty, rhs_ty } = ep;
+            vis.visit_id(id);
+            vis.visit_span(span);
+            vis.visit_ty(lhs_ty);
+            vis.visit_ty(rhs_ty);
         }
-        VariantData::Unit(id) => VariantData::Unit(fld.new_id(id))
     }
 }
 
-pub fn noop_fold_trait_ref<T: Folder>(p: TraitRef, fld: &mut T) -> TraitRef {
-    let id = fld.new_id(p.ref_id);
-    let TraitRef {
-        path,
-        ref_id: _,
-    } = p;
-    TraitRef {
-        path: fld.fold_path(path),
-        ref_id: id,
+pub fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut T) {
+    match vdata {
+        VariantData::Struct(fields, id) |
+        VariantData::Tuple(fields, id) => {
+            visit_vec(fields, |field| vis.visit_struct_field(field));
+            vis.visit_id(id);
+        }
+        VariantData::Unit(id) => vis.visit_id(id),
     }
 }
 
-pub fn noop_fold_poly_trait_ref<T: Folder>(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef {
-    PolyTraitRef {
-        bound_generic_params: fld.fold_generic_params(p.bound_generic_params),
-        trait_ref: fld.fold_trait_ref(p.trait_ref),
-        span: fld.new_span(p.span),
-    }
+pub fn noop_visit_trait_ref<T: MutVisitor>(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) {
+    vis.visit_path(path);
+    vis.visit_id(ref_id);
 }
 
-pub fn noop_fold_struct_field<T: Folder>(f: StructField, fld: &mut T) -> StructField {
-    StructField {
-        span: fld.new_span(f.span),
-        id: fld.new_id(f.id),
-        ident: f.ident.map(|ident| fld.fold_ident(ident)),
-        vis: fld.fold_vis(f.vis),
-        ty: fld.fold_ty(f.ty),
-        attrs: fold_attrs(f.attrs, fld),
-    }
+pub fn noop_visit_poly_trait_ref<T: MutVisitor>(p: &mut PolyTraitRef, vis: &mut T) {
+    let PolyTraitRef { bound_generic_params, trait_ref, span } = p;
+    vis.visit_generic_params(bound_generic_params);
+    vis.visit_trait_ref(trait_ref);
+    vis.visit_span(span);
 }
 
-pub fn noop_fold_field<T: Folder>(f: Field, folder: &mut T) -> Field {
-    Field {
-        ident: folder.fold_ident(f.ident),
-        expr: folder.fold_expr(f.expr),
-        span: folder.new_span(f.span),
-        is_shorthand: f.is_shorthand,
-        attrs: fold_thin_attrs(f.attrs, folder),
-    }
+pub fn noop_visit_struct_field<T: MutVisitor>(f: &mut StructField, visitor: &mut T) {
+    let StructField { span, ident, vis, id, ty, attrs } = f;
+    visitor.visit_span(span);
+    visit_opt(ident, |ident| visitor.visit_ident(ident));
+    visitor.visit_vis(vis);
+    visitor.visit_id(id);
+    visitor.visit_ty(ty);
+    visit_attrs(attrs, visitor);
 }
 
-pub fn noop_fold_mt<T: Folder>(MutTy {ty, mutbl}: MutTy, folder: &mut T) -> MutTy {
-    MutTy {
-        ty: folder.fold_ty(ty),
-        mutbl,
-    }
+pub fn noop_visit_field<T: MutVisitor>(f: &mut Field, vis: &mut T) {
+    let Field { ident, expr, span, is_shorthand: _, attrs } = f;
+    vis.visit_ident(ident);
+    vis.visit_expr(expr);
+    vis.visit_span(span);
+    visit_thin_attrs(attrs, vis);
 }
 
-pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
-    b.map(|Block {id, stmts, rules, span}| Block {
-        id: folder.new_id(id),
-        stmts: stmts.move_flat_map(|s| folder.fold_stmt(s).into_iter()),
-        rules,
-        span: folder.new_span(span),
-    })
+pub fn noop_visit_mt<T: MutVisitor>(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mut T) {
+    vis.visit_ty(ty);
 }
 
-pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
-    match i {
-        ItemKind::ExternCrate(orig_name) => ItemKind::ExternCrate(orig_name),
-        ItemKind::Use(use_tree) => {
-            ItemKind::Use(use_tree.map(|tree| folder.fold_use_tree(tree)))
-        }
-        ItemKind::Static(t, m, e) => {
-            ItemKind::Static(folder.fold_ty(t), m, folder.fold_expr(e))
+pub fn noop_visit_block<T: MutVisitor>(block: &mut P<Block>, vis: &mut T) {
+    let Block { id, stmts, rules: _, span } = block.deref_mut();
+    vis.visit_id(id);
+    stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt));
+    vis.visit_span(span);
+}
+
+pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
+    match kind {
+        ItemKind::ExternCrate(_orig_name) => {}
+        ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
+        ItemKind::Static(ty, _mut, expr) => {
+            vis.visit_ty(ty);
+            vis.visit_expr(expr);
         }
-        ItemKind::Const(t, e) => {
-            ItemKind::Const(folder.fold_ty(t), folder.fold_expr(e))
+        ItemKind::Const(ty, expr) => {
+            vis.visit_ty(ty);
+            vis.visit_expr(expr);
         }
         ItemKind::Fn(decl, header, generics, body) => {
-            let generics = folder.fold_generics(generics);
-            let header = folder.fold_fn_header(header);
-            let decl = folder.fold_fn_decl(decl);
-            let body = folder.fold_block(body);
-            ItemKind::Fn(decl, header, generics, body)
-        }
-        ItemKind::Mod(m) => ItemKind::Mod(folder.fold_mod(m)),
-        ItemKind::ForeignMod(nm) => ItemKind::ForeignMod(folder.fold_foreign_mod(nm)),
-        ItemKind::GlobalAsm(ga) => ItemKind::GlobalAsm(ga),
-        ItemKind::Ty(t, generics) => {
-            ItemKind::Ty(folder.fold_ty(t), folder.fold_generics(generics))
-        }
-        ItemKind::Existential(bounds, generics) => ItemKind::Existential(
-            fold_bounds(bounds, folder),
-            folder.fold_generics(generics),
-        ),
-        ItemKind::Enum(enum_definition, generics) => {
-            let generics = folder.fold_generics(generics);
-            let variants = enum_definition.variants.move_map(|x| folder.fold_variant(x));
-            ItemKind::Enum(EnumDef { variants }, generics)
-        }
-        ItemKind::Struct(struct_def, generics) => {
-            let generics = folder.fold_generics(generics);
-            ItemKind::Struct(folder.fold_variant_data(struct_def), generics)
-        }
-        ItemKind::Union(struct_def, generics) => {
-            let generics = folder.fold_generics(generics);
-            ItemKind::Union(folder.fold_variant_data(struct_def), generics)
-        }
-        ItemKind::Impl(unsafety,
-                       polarity,
-                       defaultness,
-                       generics,
-                       ifce,
-                       ty,
-                       impl_items) => ItemKind::Impl(
-            unsafety,
-            polarity,
-            defaultness,
-            folder.fold_generics(generics),
-            ifce.map(|trait_ref| folder.fold_trait_ref(trait_ref)),
-            folder.fold_ty(ty),
-            impl_items.move_flat_map(|item| folder.fold_impl_item(item)),
-        ),
-        ItemKind::Trait(is_auto, unsafety, generics, bounds, items) => ItemKind::Trait(
-            is_auto,
-            unsafety,
-            folder.fold_generics(generics),
-            fold_bounds(bounds, folder),
-            items.move_flat_map(|item| folder.fold_trait_item(item)),
-        ),
-        ItemKind::TraitAlias(generics, bounds) => ItemKind::TraitAlias(
-            folder.fold_generics(generics),
-            fold_bounds(bounds, folder)),
-        ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)),
-        ItemKind::MacroDef(def) => ItemKind::MacroDef(folder.fold_macro_def(def)),
-    }
-}
-
-pub fn noop_fold_trait_item<T: Folder>(i: TraitItem, folder: &mut T) -> SmallVec<[TraitItem; 1]> {
-    smallvec![TraitItem {
-        id: folder.new_id(i.id),
-        ident: folder.fold_ident(i.ident),
-        attrs: fold_attrs(i.attrs, folder),
-        generics: folder.fold_generics(i.generics),
-        node: match i.node {
-            TraitItemKind::Const(ty, default) => {
-                TraitItemKind::Const(folder.fold_ty(ty),
-                               default.map(|x| folder.fold_expr(x)))
-            }
-            TraitItemKind::Method(sig, body) => {
-                TraitItemKind::Method(fold_method_sig(sig, folder),
-                                body.map(|x| folder.fold_block(x)))
-            }
-            TraitItemKind::Type(bounds, default) => {
-                TraitItemKind::Type(fold_bounds(bounds, folder),
-                              default.map(|x| folder.fold_ty(x)))
-            }
-            TraitItemKind::Macro(mac) => {
-                TraitItemKind::Macro(folder.fold_mac(mac))
-            }
-        },
-        span: folder.new_span(i.span),
-        tokens: i.tokens,
-    }]
-}
-
-pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T)-> SmallVec<[ImplItem; 1]> {
-    smallvec![ImplItem {
-        id: folder.new_id(i.id),
-        vis: folder.fold_vis(i.vis),
-        ident: folder.fold_ident(i.ident),
-        attrs: fold_attrs(i.attrs, folder),
-        generics: folder.fold_generics(i.generics),
-        defaultness: i.defaultness,
-        node: match i.node  {
-            ImplItemKind::Const(ty, expr) => {
-                ImplItemKind::Const(folder.fold_ty(ty), folder.fold_expr(expr))
-            }
-            ImplItemKind::Method(sig, body) => {
-                ImplItemKind::Method(fold_method_sig(sig, folder),
-                               folder.fold_block(body))
-            }
-            ImplItemKind::Type(ty) => ImplItemKind::Type(folder.fold_ty(ty)),
-            ImplItemKind::Existential(bounds) => {
-                ImplItemKind::Existential(fold_bounds(bounds, folder))
-            },
-            ImplItemKind::Macro(mac) => ImplItemKind::Macro(folder.fold_mac(mac))
-        },
-        span: folder.new_span(i.span),
-        tokens: i.tokens,
-    }]
-}
-
-pub fn noop_fold_fn_header<T: Folder>(mut header: FnHeader, folder: &mut T) -> FnHeader {
-    header.asyncness = folder.fold_asyncness(header.asyncness);
-    header
+            vis.visit_fn_decl(decl);
+            vis.visit_fn_header(header);
+            vis.visit_generics(generics);
+            vis.visit_block(body);
+        }
+        ItemKind::Mod(m) => vis.visit_mod(m),
+        ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
+        ItemKind::GlobalAsm(_ga) => {}
+        ItemKind::Ty(ty, generics) => {
+            vis.visit_ty(ty);
+            vis.visit_generics(generics);
+        }
+        ItemKind::Existential(bounds, generics) => {
+            visit_bounds(bounds, vis);
+            vis.visit_generics(generics);
+        }
+        ItemKind::Enum(EnumDef { variants }, generics) => {
+            visit_vec(variants, |variant| vis.visit_variant(variant));
+            vis.visit_generics(generics);
+        }
+        ItemKind::Struct(variant_data, generics) |
+        ItemKind::Union(variant_data, generics) => {
+            vis.visit_variant_data(variant_data);
+            vis.visit_generics(generics);
+        }
+        ItemKind::Impl(_unsafety, _polarity, _defaultness, generics, trait_ref, ty, items) => {
+            vis.visit_generics(generics);
+            visit_opt(trait_ref, |trait_ref| vis.visit_trait_ref(trait_ref));
+            vis.visit_ty(ty);
+            items.flat_map_in_place(|item| vis.flat_map_impl_item(item));
+        }
+        ItemKind::Trait(_is_auto, _unsafety, generics, bounds, items) => {
+            vis.visit_generics(generics);
+            visit_bounds(bounds, vis);
+            items.flat_map_in_place(|item| vis.flat_map_trait_item(item));
+        }
+        ItemKind::TraitAlias(generics, bounds) => {
+            vis.visit_generics(generics);
+            visit_bounds(bounds, vis);
+        }
+        ItemKind::Mac(m) => vis.visit_mac(m),
+        ItemKind::MacroDef(def) => vis.visit_macro_def(def),
+    }
 }
 
-pub fn noop_fold_mod<T: Folder>(Mod {inner, items, inline}: Mod, folder: &mut T) -> Mod {
-    Mod {
-        inner: folder.new_span(inner),
-        items: items.move_flat_map(|x| folder.fold_item(x)),
-        inline: inline,
+pub fn noop_flat_map_trait_item<T: MutVisitor>(mut item: TraitItem, vis: &mut T)
+    -> SmallVec<[TraitItem; 1]>
+{
+    let TraitItem { id, ident, attrs, generics, node, span, tokens: _ } = &mut item;
+    vis.visit_id(id);
+    vis.visit_ident(ident);
+    visit_attrs(attrs, vis);
+    vis.visit_generics(generics);
+    match node {
+        TraitItemKind::Const(ty, default) => {
+            vis.visit_ty(ty);
+            visit_opt(default, |default| vis.visit_expr(default));
+        }
+        TraitItemKind::Method(sig, body) => {
+            visit_method_sig(sig, vis);
+            visit_opt(body, |body| vis.visit_block(body));
+        }
+        TraitItemKind::Type(bounds, default) => {
+            visit_bounds(bounds, vis);
+            visit_opt(default, |default| vis.visit_ty(default));
+        }
+        TraitItemKind::Macro(mac) => {
+            vis.visit_mac(mac);
+        }
     }
-}
+    vis.visit_span(span);
 
-pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, span}: Crate,
-                                  folder: &mut T) -> Crate {
-    let item = P(Item {
-        ident: keywords::Invalid.ident(),
-        attrs,
-        id: DUMMY_NODE_ID,
-        vis: respan(span.shrink_to_lo(), VisibilityKind::Public),
-        span,
-        node: ItemKind::Mod(module),
-        tokens: None,
-    });
-    let items = folder.fold_item(item);
+    smallvec![item]
+}
 
-    let len = items.len();
-    if len == 0 {
-        let module = Mod { inner: span, items: vec![], inline: true };
-        Crate { module, attrs: vec![], span }
-    } else if len == 1 {
-        let Item { attrs, span, node, .. } = items.into_iter().next().unwrap().into_inner();
-        match node {
-            ItemKind::Mod(module) => Crate { module, attrs, span },
-            _ => panic!("fold converted a module to not a module"),
+pub fn noop_flat_map_impl_item<T: MutVisitor>(mut item: ImplItem, visitor: &mut T)
+                                              -> SmallVec<[ImplItem; 1]>
+{
+    let ImplItem { id, ident, vis, defaultness: _, attrs, generics, node, span, tokens: _ } =
+        &mut item;
+    visitor.visit_id(id);
+    visitor.visit_ident(ident);
+    visitor.visit_vis(vis);
+    visit_attrs(attrs, visitor);
+    visitor.visit_generics(generics);
+    match node  {
+        ImplItemKind::Const(ty, expr) => {
+            visitor.visit_ty(ty);
+            visitor.visit_expr(expr);
         }
-    } else {
-        panic!("a crate cannot expand to more than one item");
-    }
+        ImplItemKind::Method(sig, body) => {
+            visit_method_sig(sig, visitor);
+            visitor.visit_block(body);
+        }
+        ImplItemKind::Type(ty) => visitor.visit_ty(ty),
+        ImplItemKind::Existential(bounds) => visit_bounds(bounds, visitor),
+        ImplItemKind::Macro(mac) => visitor.visit_mac(mac),
+    }
+    visitor.visit_span(span);
+
+    smallvec![item]
+}
+
+pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
+    let FnHeader { unsafety: _, asyncness, constness: _, abi: _ } = header;
+    vis.visit_asyncness(asyncness);
+}
+
+pub fn noop_visit_mod<T: MutVisitor>(Mod { inner, items, inline: _ }: &mut Mod, vis: &mut T) {
+    vis.visit_span(inner);
+    items.flat_map_in_place(|item| vis.flat_map_item(item));
+}
+
+pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
+    visit_clobber(krate, |Crate { module, attrs, span }| {
+        let item = P(Item {
+            ident: keywords::Invalid.ident(),
+            attrs,
+            id: DUMMY_NODE_ID,
+            vis: respan(span.shrink_to_lo(), VisibilityKind::Public),
+            span,
+            node: ItemKind::Mod(module),
+            tokens: None,
+        });
+        let items = vis.flat_map_item(item);
+
+        let len = items.len();
+        if len == 0 {
+            let module = Mod { inner: span, items: vec![], inline: true };
+            Crate { module, attrs: vec![], span }
+        } else if len == 1 {
+            let Item { attrs, span, node, .. } = items.into_iter().next().unwrap().into_inner();
+            match node {
+                ItemKind::Mod(module) => Crate { module, attrs, span },
+                _ => panic!("visitor converted a module to not a module"),
+            }
+        } else {
+            panic!("a crate cannot expand to more than one item");
+        }
+    });
 }
 
-// fold one item into possibly many items
-pub fn noop_fold_item<T: Folder>(i: P<Item>, folder: &mut T) -> SmallVec<[P<Item>; 1]> {
-    smallvec![i.map(|i| {
-        let Item {id, ident, attrs, node, vis, span, tokens} = i;
-        Item {
-            id: folder.new_id(id),
-            vis: folder.fold_vis(vis),
-            ident: folder.fold_ident(ident),
-            attrs: fold_attrs(attrs, folder),
-            node: folder.fold_item_kind(node),
-            span: folder.new_span(span),
+// Mutate one item into possibly many items.
+pub fn noop_flat_map_item<T: MutVisitor>(mut item: P<Item>, visitor: &mut T)
+                                         -> SmallVec<[P<Item>; 1]> {
+    let Item { ident, attrs, id, node, vis, span, tokens: _ } = item.deref_mut();
+    visitor.visit_ident(ident);
+    visit_attrs(attrs, visitor);
+    visitor.visit_id(id);
+    visitor.visit_item_kind(node);
+    visitor.visit_vis(vis);
+    visitor.visit_span(span);
 
-            // FIXME: if this is replaced with a call to `folder.fold_tts` it causes
-            //        an ICE during resolve... odd!
-            tokens,
-        }
-    })]
+    // FIXME: if `tokens` is modified with a call to `vis.visit_tts` it causes
+    //        an ICE during resolve... odd!
+
+    smallvec![item]
 }
 
-pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T)
+pub fn noop_flat_map_foreign_item<T: MutVisitor>(mut item: ForeignItem, visitor: &mut T)
     -> SmallVec<[ForeignItem; 1]>
 {
-    smallvec![ForeignItem {
-        id: folder.new_id(ni.id),
-        vis: folder.fold_vis(ni.vis),
-        ident: folder.fold_ident(ni.ident),
-        attrs: fold_attrs(ni.attrs, folder),
-        node: match ni.node {
-            ForeignItemKind::Fn(fdec, generics) => {
-                ForeignItemKind::Fn(folder.fold_fn_decl(fdec), folder.fold_generics(generics))
-            }
-            ForeignItemKind::Static(t, m) => {
-                ForeignItemKind::Static(folder.fold_ty(t), m)
-            }
-            ForeignItemKind::Ty => ForeignItemKind::Ty,
-            ForeignItemKind::Macro(mac) => ForeignItemKind::Macro(folder.fold_mac(mac)),
-        },
-        span: folder.new_span(ni.span)
-    }]
-}
-
-pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
-    p.map(|Pat {id, node, span}| Pat {
-        id: folder.new_id(id),
-        node: match node {
-            PatKind::Wild => PatKind::Wild,
-            PatKind::Ident(binding_mode, ident, sub) => {
-                PatKind::Ident(binding_mode,
-                               folder.fold_ident(ident),
-                               sub.map(|x| folder.fold_pat(x)))
-            }
-            PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)),
-            PatKind::TupleStruct(pth, pats, ddpos) => {
-                PatKind::TupleStruct(folder.fold_path(pth),
-                        pats.move_map(|x| folder.fold_pat(x)), ddpos)
-            }
-            PatKind::Path(qself, pth) => {
-                PatKind::Path(folder.fold_qself(qself), folder.fold_path(pth))
-            }
-            PatKind::Struct(pth, fields, etc) => {
-                let pth = folder.fold_path(pth);
-                let fs = fields.move_map(|f| {
-                    Spanned { span: folder.new_span(f.span),
-                              node: FieldPat {
-                                  ident: folder.fold_ident(f.node.ident),
-                                  pat: folder.fold_pat(f.node.pat),
-                                  is_shorthand: f.node.is_shorthand,
-                                  attrs: fold_attrs(f.node.attrs.into(), folder).into()
-                              }}
-                });
-                PatKind::Struct(pth, fs, etc)
-            }
-            PatKind::Tuple(elts, ddpos) => {
-                PatKind::Tuple(elts.move_map(|x| folder.fold_pat(x)), ddpos)
-            }
-            PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)),
-            PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl),
-            PatKind::Range(e1, e2, Spanned { span, node }) => {
-                PatKind::Range(folder.fold_expr(e1),
-                               folder.fold_expr(e2),
-                               Spanned { node, span: folder.new_span(span) })
-            },
-            PatKind::Slice(before, slice, after) => {
-                PatKind::Slice(before.move_map(|x| folder.fold_pat(x)),
-                       slice.map(|x| folder.fold_pat(x)),
-                       after.move_map(|x| folder.fold_pat(x)))
-            }
-            PatKind::Paren(inner) => PatKind::Paren(folder.fold_pat(inner)),
-            PatKind::Mac(mac) => PatKind::Mac(folder.fold_mac(mac))
-        },
-        span: folder.new_span(span)
-    })
+    let ForeignItem { ident, attrs, node, id, span, vis } = &mut item;
+    visitor.visit_ident(ident);
+    visit_attrs(attrs, visitor);
+    match node {
+        ForeignItemKind::Fn(fdec, generics) => {
+            visitor.visit_fn_decl(fdec);
+            visitor.visit_generics(generics);
+        }
+        ForeignItemKind::Static(t, _m) => visitor.visit_ty(t),
+        ForeignItemKind::Ty => {}
+        ForeignItemKind::Macro(mac) => visitor.visit_mac(mac),
+    }
+    visitor.visit_id(id);
+    visitor.visit_span(span);
+    visitor.visit_vis(vis);
+
+    smallvec![item]
 }
 
-pub fn noop_fold_anon_const<T: Folder>(constant: AnonConst, folder: &mut T) -> AnonConst {
-    let AnonConst {id, value} = constant;
-    AnonConst {
-        id: folder.new_id(id),
-        value: folder.fold_expr(value),
+pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
+    let Pat { id, node, span } = pat.deref_mut();
+    vis.visit_id(id);
+    match node {
+        PatKind::Wild => {}
+        PatKind::Ident(_binding_mode, ident, sub) => {
+            vis.visit_ident(ident);
+            visit_opt(sub, |sub| vis.visit_pat(sub));
+        }
+        PatKind::Lit(e) => vis.visit_expr(e),
+        PatKind::TupleStruct(path, pats, _ddpos) => {
+            vis.visit_path(path);
+            visit_vec(pats, |pat| vis.visit_pat(pat));
+        }
+        PatKind::Path(qself, path) => {
+            vis.visit_qself(qself);
+            vis.visit_path(path);
+        }
+        PatKind::Struct(path, fields, _etc) => {
+            vis.visit_path(path);
+            for Spanned { node: FieldPat { ident, pat, is_shorthand: _, attrs }, span } in fields {
+                vis.visit_ident(ident);
+                vis.visit_pat(pat);
+                visit_thin_attrs(attrs, vis);
+                vis.visit_span(span);
+            };
+        }
+        PatKind::Tuple(elts, _ddpos) => visit_vec(elts, |elt| vis.visit_pat(elt)),
+        PatKind::Box(inner) => vis.visit_pat(inner),
+        PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner),
+        PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => {
+            vis.visit_expr(e1);
+            vis.visit_expr(e2);
+            vis.visit_span(span);
+        },
+        PatKind::Slice(before, slice, after) => {
+            visit_vec(before, |pat| vis.visit_pat(pat));
+            visit_opt(slice, |slice| vis.visit_pat(slice));
+            visit_vec(after, |pat| vis.visit_pat(pat));
+        }
+        PatKind::Paren(inner) => vis.visit_pat(inner),
+        PatKind::Mac(mac) => vis.visit_mac(mac),
     }
+    vis.visit_span(span);
 }
 
-pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mut T) -> Expr {
-    Expr {
-        node: match node {
-            ExprKind::Box(e) => {
-                ExprKind::Box(folder.fold_expr(e))
-            }
-            ExprKind::ObsoleteInPlace(a, b) => {
-                ExprKind::ObsoleteInPlace(folder.fold_expr(a), folder.fold_expr(b))
-            }
-            ExprKind::Array(exprs) => {
-                ExprKind::Array(fold_exprs(exprs, folder))
-            }
-            ExprKind::Repeat(expr, count) => {
-                ExprKind::Repeat(folder.fold_expr(expr), folder.fold_anon_const(count))
-            }
-            ExprKind::Tup(exprs) => ExprKind::Tup(fold_exprs(exprs, folder)),
-            ExprKind::Call(f, args) => {
-                ExprKind::Call(folder.fold_expr(f),
-                         fold_exprs(args, folder))
-            }
-            ExprKind::MethodCall(seg, args) => {
-                ExprKind::MethodCall(
-                    PathSegment {
-                        ident: folder.fold_ident(seg.ident),
-                        id: folder.new_id(seg.id),
-                        args: seg.args.map(|args| {
-                            args.map(|args| folder.fold_generic_args(args))
-                        }),
-                    },
-                    fold_exprs(args, folder))
-            }
-            ExprKind::Binary(binop, lhs, rhs) => {
-                ExprKind::Binary(binop,
-                        folder.fold_expr(lhs),
-                        folder.fold_expr(rhs))
-            }
-            ExprKind::Unary(binop, ohs) => {
-                ExprKind::Unary(binop, folder.fold_expr(ohs))
-            }
-            ExprKind::Lit(l) => ExprKind::Lit(l),
-            ExprKind::Cast(expr, ty) => {
-                ExprKind::Cast(folder.fold_expr(expr), folder.fold_ty(ty))
-            }
-            ExprKind::Type(expr, ty) => {
-                ExprKind::Type(folder.fold_expr(expr), folder.fold_ty(ty))
-            }
-            ExprKind::AddrOf(m, ohs) => ExprKind::AddrOf(m, folder.fold_expr(ohs)),
-            ExprKind::If(cond, tr, fl) => {
-                ExprKind::If(folder.fold_expr(cond),
-                       folder.fold_block(tr),
-                       fl.map(|x| folder.fold_expr(x)))
-            }
-            ExprKind::IfLet(pats, expr, tr, fl) => {
-                ExprKind::IfLet(pats.move_map(|pat| folder.fold_pat(pat)),
-                          folder.fold_expr(expr),
-                          folder.fold_block(tr),
-                          fl.map(|x| folder.fold_expr(x)))
-            }
-            ExprKind::While(cond, body, opt_label) => {
-                ExprKind::While(folder.fold_expr(cond),
-                          folder.fold_block(body),
-                          opt_label.map(|label| folder.fold_label(label)))
-            }
-            ExprKind::WhileLet(pats, expr, body, opt_label) => {
-                ExprKind::WhileLet(pats.move_map(|pat| folder.fold_pat(pat)),
-                             folder.fold_expr(expr),
-                             folder.fold_block(body),
-                             opt_label.map(|label| folder.fold_label(label)))
-            }
-            ExprKind::ForLoop(pat, iter, body, opt_label) => {
-                ExprKind::ForLoop(folder.fold_pat(pat),
-                            folder.fold_expr(iter),
-                            folder.fold_block(body),
-                            opt_label.map(|label| folder.fold_label(label)))
-            }
-            ExprKind::Loop(body, opt_label) => {
-                ExprKind::Loop(folder.fold_block(body),
-                               opt_label.map(|label| folder.fold_label(label)))
-            }
-            ExprKind::Match(expr, arms) => {
-                ExprKind::Match(folder.fold_expr(expr),
-                          arms.move_map(|x| folder.fold_arm(x)))
-            }
-            ExprKind::Closure(capture_clause, asyncness, movability, decl, body, span) => {
-                ExprKind::Closure(capture_clause,
-                                  folder.fold_asyncness(asyncness),
-                                  movability,
-                                  folder.fold_fn_decl(decl),
-                                  folder.fold_expr(body),
-                                  folder.new_span(span))
-            }
-            ExprKind::Block(blk, opt_label) => {
-                ExprKind::Block(folder.fold_block(blk),
-                                opt_label.map(|label| folder.fold_label(label)))
-            }
-            ExprKind::Async(capture_clause, node_id, body) => {
-                ExprKind::Async(
-                    capture_clause,
-                    folder.new_id(node_id),
-                    folder.fold_block(body),
-                )
-            }
-            ExprKind::Assign(el, er) => {
-                ExprKind::Assign(folder.fold_expr(el), folder.fold_expr(er))
-            }
-            ExprKind::AssignOp(op, el, er) => {
-                ExprKind::AssignOp(op,
-                            folder.fold_expr(el),
-                            folder.fold_expr(er))
-            }
-            ExprKind::Field(el, ident) => {
-                ExprKind::Field(folder.fold_expr(el), folder.fold_ident(ident))
-            }
-            ExprKind::Index(el, er) => {
-                ExprKind::Index(folder.fold_expr(el), folder.fold_expr(er))
-            }
-            ExprKind::Range(e1, e2, lim) => {
-                ExprKind::Range(e1.map(|x| folder.fold_expr(x)),
-                                e2.map(|x| folder.fold_expr(x)),
-                                lim)
-            }
-            ExprKind::Path(qself, path) => {
-                ExprKind::Path(folder.fold_qself(qself), folder.fold_path(path))
-            }
-            ExprKind::Break(opt_label, opt_expr) => {
-                ExprKind::Break(opt_label.map(|label| folder.fold_label(label)),
-                                opt_expr.map(|e| folder.fold_expr(e)))
-            }
-            ExprKind::Continue(opt_label) => {
-                ExprKind::Continue(opt_label.map(|label| folder.fold_label(label)))
-            }
-            ExprKind::Ret(e) => ExprKind::Ret(e.map(|x| folder.fold_expr(x))),
-            ExprKind::InlineAsm(asm) => ExprKind::InlineAsm(asm.map(|asm| {
-                InlineAsm {
-                    inputs: asm.inputs.move_map(|(c, input)| {
-                        (c, folder.fold_expr(input))
-                    }),
-                    outputs: asm.outputs.move_map(|out| {
-                        InlineAsmOutput {
-                            constraint: out.constraint,
-                            expr: folder.fold_expr(out.expr),
-                            is_rw: out.is_rw,
-                            is_indirect: out.is_indirect,
-                        }
-                    }),
-                    ..asm
-                }
-            })),
-            ExprKind::Mac(mac) => ExprKind::Mac(folder.fold_mac(mac)),
-            ExprKind::Struct(path, fields, maybe_expr) => {
-                ExprKind::Struct(folder.fold_path(path),
-                        fields.move_map(|x| folder.fold_field(x)),
-                        maybe_expr.map(|x| folder.fold_expr(x)))
-            },
-            ExprKind::Paren(ex) => {
-                let sub_expr = folder.fold_expr(ex);
-                return Expr {
-                    // Nodes that are equal modulo `Paren` sugar no-ops should have the same ids.
-                    id: sub_expr.id,
-                    node: ExprKind::Paren(sub_expr),
-                    span: folder.new_span(span),
-                    attrs: fold_attrs(attrs.into(), folder).into(),
-                };
+pub fn noop_visit_anon_const<T: MutVisitor>(AnonConst { id, value }: &mut AnonConst, vis: &mut T) {
+    vis.visit_id(id);
+    vis.visit_expr(value);
+}
+
+pub fn noop_visit_expr<T: MutVisitor>(Expr { node, id, span, attrs }: &mut Expr, vis: &mut T) {
+    match node {
+        ExprKind::Box(expr) => vis.visit_expr(expr),
+        ExprKind::ObsoleteInPlace(a, b) => {
+            vis.visit_expr(a);
+            vis.visit_expr(b);
+        }
+        ExprKind::Array(exprs) => visit_exprs(exprs, vis),
+        ExprKind::Repeat(expr, count) => {
+            vis.visit_expr(expr);
+            vis.visit_anon_const(count);
+        }
+        ExprKind::Tup(exprs) => visit_exprs(exprs, vis),
+        ExprKind::Call(f, args) => {
+            vis.visit_expr(f);
+            visit_exprs(args, vis);
+        }
+        ExprKind::MethodCall(PathSegment { ident, id, args }, exprs) => {
+            vis.visit_ident(ident);
+            vis.visit_id(id);
+            visit_opt(args, |args| vis.visit_generic_args(args));
+            visit_exprs(exprs, vis);
+        }
+        ExprKind::Binary(_binop, lhs, rhs) => {
+            vis.visit_expr(lhs);
+            vis.visit_expr(rhs);
+        }
+        ExprKind::Unary(_unop, ohs) => vis.visit_expr(ohs),
+        ExprKind::Lit(_lit) => {}
+        ExprKind::Cast(expr, ty) => {
+            vis.visit_expr(expr);
+            vis.visit_ty(ty);
+        }
+        ExprKind::Type(expr, ty) => {
+            vis.visit_expr(expr);
+            vis.visit_ty(ty);
+        }
+        ExprKind::AddrOf(_m, ohs) => vis.visit_expr(ohs),
+        ExprKind::If(cond, tr, fl) => {
+            vis.visit_expr(cond);
+            vis.visit_block(tr);
+            visit_opt(fl, |fl| vis.visit_expr(fl));
+        }
+        ExprKind::IfLet(pats, expr, tr, fl) => {
+            visit_vec(pats, |pat| vis.visit_pat(pat));
+            vis.visit_expr(expr);
+            vis.visit_block(tr);
+            visit_opt(fl, |fl| vis.visit_expr(fl));
+        }
+        ExprKind::While(cond, body, label) => {
+            vis.visit_expr(cond);
+            vis.visit_block(body);
+            visit_opt(label, |label| vis.visit_label(label));
+        }
+        ExprKind::WhileLet(pats, expr, body, label) => {
+            visit_vec(pats, |pat| vis.visit_pat(pat));
+            vis.visit_expr(expr);
+            vis.visit_block(body);
+            visit_opt(label, |label| vis.visit_label(label));
+        }
+        ExprKind::ForLoop(pat, iter, body, label) => {
+            vis.visit_pat(pat);
+            vis.visit_expr(iter);
+            vis.visit_block(body);
+            visit_opt(label, |label| vis.visit_label(label));
+        }
+        ExprKind::Loop(body, label) => {
+            vis.visit_block(body);
+            visit_opt(label, |label| vis.visit_label(label));
+        }
+        ExprKind::Match(expr, arms) => {
+            vis.visit_expr(expr);
+            visit_vec(arms, |arm| vis.visit_arm(arm));
+        }
+        ExprKind::Closure(_capture_by, asyncness, _movability, decl, body, span) => {
+            vis.visit_asyncness(asyncness);
+            vis.visit_fn_decl(decl);
+            vis.visit_expr(body);
+            vis.visit_span(span);
+        }
+        ExprKind::Block(blk, label) => {
+            vis.visit_block(blk);
+            visit_opt(label, |label| vis.visit_label(label));
+        }
+        ExprKind::Async(_capture_by, node_id, body) => {
+            vis.visit_id(node_id);
+            vis.visit_block(body);
+        }
+        ExprKind::Assign(el, er) => {
+            vis.visit_expr(el);
+            vis.visit_expr(er);
+        }
+        ExprKind::AssignOp(_op, el, er) => {
+            vis.visit_expr(el);
+            vis.visit_expr(er);
+        }
+        ExprKind::Field(el, ident) => {
+            vis.visit_expr(el);
+            vis.visit_ident(ident);
+        }
+        ExprKind::Index(el, er) => {
+            vis.visit_expr(el);
+            vis.visit_expr(er);
+        }
+        ExprKind::Range(e1, e2, _lim) => {
+            visit_opt(e1, |e1| vis.visit_expr(e1));
+            visit_opt(e2, |e2| vis.visit_expr(e2));
+        }
+        ExprKind::Path(qself, path) => {
+            vis.visit_qself(qself);
+            vis.visit_path(path);
+        }
+        ExprKind::Break(label, expr) => {
+            visit_opt(label, |label| vis.visit_label(label));
+            visit_opt(expr, |expr| vis.visit_expr(expr));
+        }
+        ExprKind::Continue(label) => {
+            visit_opt(label, |label| vis.visit_label(label));
+        }
+        ExprKind::Ret(expr) => {
+            visit_opt(expr, |expr| vis.visit_expr(expr));
+        }
+        ExprKind::InlineAsm(asm) => {
+            let InlineAsm { asm: _, asm_str_style: _, outputs, inputs, clobbers: _, volatile: _,
+                            alignstack: _, dialect: _, ctxt: _ } = asm.deref_mut();
+            for out in outputs {
+                let InlineAsmOutput { constraint: _, expr, is_rw: _, is_indirect: _ } = out;
+                vis.visit_expr(expr);
             }
-            ExprKind::Yield(ex) => ExprKind::Yield(ex.map(|x| folder.fold_expr(x))),
-            ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)),
-            ExprKind::TryBlock(body) => ExprKind::TryBlock(folder.fold_block(body)),
-            ExprKind::Err => ExprKind::Err,
+            visit_vec(inputs, |(_c, expr)| vis.visit_expr(expr));
+        }
+        ExprKind::Mac(mac) => vis.visit_mac(mac),
+        ExprKind::Struct(path, fields, expr) => {
+            vis.visit_path(path);
+            visit_vec(fields, |field| vis.visit_field(field));
+            visit_opt(expr, |expr| vis.visit_expr(expr));
         },
-        id: folder.new_id(id),
-        span: folder.new_span(span),
-        attrs: fold_attrs(attrs.into(), folder).into(),
+        ExprKind::Paren(expr) => {
+            vis.visit_expr(expr);
+
+            // Nodes that are equal modulo `Paren` sugar no-ops should have the same ids.
+            *id = expr.id;
+            vis.visit_span(span);
+            visit_thin_attrs(attrs, vis);
+            return;
+        }
+        ExprKind::Yield(expr) => {
+            visit_opt(expr, |expr| vis.visit_expr(expr));
+        }
+        ExprKind::Try(expr) => vis.visit_expr(expr),
+        ExprKind::TryBlock(body) => vis.visit_block(body),
+        ExprKind::Err => {}
     }
+    vis.visit_id(id);
+    vis.visit_span(span);
+    visit_thin_attrs(attrs, vis);
 }
 
-pub fn noop_fold_opt_expr<T: Folder>(e: P<Expr>, folder: &mut T) -> Option<P<Expr>> {
-    Some(folder.fold_expr(e))
+pub fn noop_filter_map_expr<T: MutVisitor>(mut e: P<Expr>, vis: &mut T) -> Option<P<Expr>> {
+    Some({ vis.visit_expr(&mut e); e })
 }
 
-pub fn noop_fold_stmt<T: Folder>(Stmt {node, span, id}: Stmt, folder: &mut T) -> SmallVec<[Stmt; 1]>
+pub fn noop_flat_map_stmt<T: MutVisitor>(Stmt { node, mut span, mut id }: Stmt, vis: &mut T)
+    -> SmallVec<[Stmt; 1]>
 {
-    let id = folder.new_id(id);
-    let span = folder.new_span(span);
-    noop_fold_stmt_kind(node, folder).into_iter().map(|node| {
-        Stmt { id: id, node: node, span: span }
+    vis.visit_id(&mut id);
+    vis.visit_span(&mut span);
+    noop_flat_map_stmt_kind(node, vis).into_iter().map(|node| {
+        Stmt { id, node, span }
     }).collect()
 }
 
-pub fn noop_fold_stmt_kind<T: Folder>(node: StmtKind, folder: &mut T) -> SmallVec<[StmtKind; 1]> {
+pub fn noop_flat_map_stmt_kind<T: MutVisitor>(node: StmtKind, vis: &mut T)
+                                              -> SmallVec<[StmtKind; 1]> {
     match node {
-        StmtKind::Local(local) => smallvec![StmtKind::Local(folder.fold_local(local))],
-        StmtKind::Item(item) => folder.fold_item(item).into_iter().map(StmtKind::Item).collect(),
+        StmtKind::Local(mut local) =>
+            smallvec![StmtKind::Local({ vis.visit_local(&mut local); local })],
+        StmtKind::Item(item) => vis.flat_map_item(item).into_iter().map(StmtKind::Item).collect(),
         StmtKind::Expr(expr) => {
-            folder.fold_opt_expr(expr).into_iter().map(StmtKind::Expr).collect()
+            vis.filter_map_expr(expr).into_iter().map(StmtKind::Expr).collect()
         }
         StmtKind::Semi(expr) => {
-            folder.fold_opt_expr(expr).into_iter().map(StmtKind::Semi).collect()
+            vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect()
+        }
+        StmtKind::Mac(mut mac) => {
+            let (mac_, _semi, attrs) = mac.deref_mut();
+            vis.visit_mac(mac_);
+            visit_thin_attrs(attrs, vis);
+            smallvec![StmtKind::Mac(mac)]
         }
-        StmtKind::Mac(mac) => smallvec![StmtKind::Mac(mac.map(|(mac, semi, attrs)| {
-            (folder.fold_mac(mac), semi, fold_attrs(attrs.into(), folder).into())
-        }))],
     }
 }
 
-pub fn noop_fold_vis<T: Folder>(Spanned { node, span }: Visibility, folder: &mut T) -> Visibility {
-    Visibility {
-        node: match node {
-            VisibilityKind::Public => VisibilityKind::Public,
-            VisibilityKind::Crate(sugar) => VisibilityKind::Crate(sugar),
-            VisibilityKind::Restricted { path, id } => {
-                VisibilityKind::Restricted {
-                    path: path.map(|path| folder.fold_path(path)),
-                    id: folder.new_id(id),
-                }
-            }
-            VisibilityKind::Inherited => VisibilityKind::Inherited,
-        },
-        span: folder.new_span(span),
+pub fn noop_visit_vis<T: MutVisitor>(Spanned { node, span }: &mut Visibility, vis: &mut T) {
+    match node {
+        VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {}
+        VisibilityKind::Restricted { path, id } => {
+            vis.visit_path(path);
+            vis.visit_id(id);
+        }
     }
+    vis.visit_span(span);
 }
 
 #[cfg(test)]
@@ -1342,7 +1259,7 @@ mod tests {
     use ast::{self, Ident};
     use util::parser_testing::{string_to_crate, matches_codepattern};
     use print::pprust;
-    use fold;
+    use mut_visit;
     use with_globals;
     use super::*;
 
@@ -1353,14 +1270,14 @@ mod tests {
     }
 
     // change every identifier to "zz"
-    struct ToZzIdentFolder;
+    struct ToZzIdentMutVisitor;
 
-    impl Folder for ToZzIdentFolder {
-        fn fold_ident(&mut self, _: ast::Ident) -> ast::Ident {
-            Ident::from_str("zz")
+    impl MutVisitor for ToZzIdentMutVisitor {
+        fn visit_ident(&mut self, ident: &mut ast::Ident) {
+            *ident = Ident::from_str("zz");
         }
-        fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
-            fold::noop_fold_mac(mac, self)
+        fn visit_mac(&mut self, mac: &mut ast::Mac) {
+            mut_visit::noop_visit_mac(mac, self)
         }
     }
 
@@ -1382,14 +1299,14 @@ mod tests {
     // make sure idents get transformed everywhere
     #[test] fn ident_transformation () {
         with_globals(|| {
-            let mut zz_fold = ToZzIdentFolder;
-            let ast = string_to_crate(
+            let mut zz_visitor = ToZzIdentMutVisitor;
+            let mut krate = string_to_crate(
                 "#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}".to_string());
-            let folded_crate = zz_fold.fold_crate(ast);
+            zz_visitor.visit_crate(&mut krate);
             assert_pred!(
                 matches_codepattern,
                 "matches_codepattern",
-                pprust::to_string(|s| fake_print_crate(s, &folded_crate)),
+                pprust::to_string(|s| fake_print_crate(s, &krate)),
                 "#[zz]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string());
         })
     }
@@ -1397,16 +1314,17 @@ mod tests {
     // even inside macro defs....
     #[test] fn ident_transformation_in_defs () {
         with_globals(|| {
-            let mut zz_fold = ToZzIdentFolder;
-            let ast = string_to_crate(
+            let mut zz_visitor = ToZzIdentMutVisitor;
+            let mut krate = string_to_crate(
                 "macro_rules! a {(b $c:expr $(d $e:token)f+ => \
                 (g $(d $d $e)+))} ".to_string());
-            let folded_crate = zz_fold.fold_crate(ast);
+            zz_visitor.visit_crate(&mut krate);
             assert_pred!(
                 matches_codepattern,
                 "matches_codepattern",
-                pprust::to_string(|s| fake_print_crate(s, &folded_crate)),
+                pprust::to_string(|s| fake_print_crate(s, &krate)),
                 "macro_rules! zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)));".to_string());
         })
     }
 }
+
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index b2a3ae7f9d975..dacb0d811cedb 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -133,7 +133,7 @@ pub mod util {
     pub mod parser;
     #[cfg(test)]
     pub mod parser_testing;
-    pub mod move_map;
+    pub mod map_in_place;
 }
 
 pub mod json;
@@ -151,7 +151,7 @@ pub mod source_map;
 pub mod config;
 pub mod entry;
 pub mod feature_gate;
-pub mod fold;
+#[path="fold.rs"] pub mod mut_visit;    // temporary
 pub mod parse;
 pub mod ptr;
 pub mod show_span;
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 514b2952c5036..a9f3acecc818b 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -7046,7 +7046,8 @@ impl<'a> Parser<'a> {
                 sess: self.sess,
                 features: None, // don't perform gated feature checking
             };
-            let outer_attrs = strip_unconfigured.process_cfg_attrs(outer_attrs.to_owned());
+            let mut outer_attrs = outer_attrs.to_owned();
+            strip_unconfigured.process_cfg_attrs(&mut outer_attrs);
             (!self.cfg_mods || strip_unconfigured.in_cfg(&outer_attrs), outer_attrs)
         };
 
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index f06e975a6d95a..5181bb8f34e66 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -735,7 +735,7 @@ impl fmt::Debug for LazyTokenStream {
 }
 
 impl LazyTokenStream {
-    fn new() -> Self {
+    pub fn new() -> Self {
         LazyTokenStream(Lock::new(None))
     }
 
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index b352486e39a64..12f82a01dcfcd 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -20,10 +20,9 @@ use ext::base::{ExtCtxt, Resolver};
 use ext::build::AstBuilder;
 use ext::expand::ExpansionConfig;
 use ext::hygiene::{self, Mark, SyntaxContext};
-use fold::Folder;
+use mut_visit::{*, ExpectOne};
 use feature_gate::Features;
-use util::move_map::MoveMap;
-use fold::{self, ExpectOne};
+use util::map_in_place::MapInPlace;
 use parse::{token, ParseSess};
 use print::pprust;
 use ast::{self, Ident};
@@ -57,9 +56,9 @@ struct TestCtxt<'a> {
 pub fn modify_for_testing(sess: &ParseSess,
                           resolver: &mut dyn Resolver,
                           should_test: bool,
-                          krate: ast::Crate,
+                          krate: &mut ast::Crate,
                           span_diagnostic: &errors::Handler,
-                          features: &Features) -> ast::Crate {
+                          features: &Features) {
     // Check for #[reexport_test_harness_main = "some_name"] which
     // creates a `use __test::main as some_name;`. This needs to be
     // unconditional, so that the attribute is still marked as used in
@@ -75,8 +74,6 @@ pub fn modify_for_testing(sess: &ParseSess,
     if should_test {
         generate_test_harness(sess, resolver, reexport_test_harness_main,
                               krate, span_diagnostic, features, test_runner)
-    } else {
-        krate
     }
 }
 
@@ -88,21 +85,20 @@ struct TestHarnessGenerator<'a> {
     tested_submods: Vec<(Ident, Ident)>,
 }
 
-impl<'a> fold::Folder for TestHarnessGenerator<'a> {
-    fn fold_crate(&mut self, c: ast::Crate) -> ast::Crate {
-        let mut folded = fold::noop_fold_crate(c, self);
+impl<'a> MutVisitor for TestHarnessGenerator<'a> {
+    fn visit_crate(&mut self, c: &mut ast::Crate) {
+        noop_visit_crate(c, self);
 
         // Create a main function to run our tests
         let test_main = {
             let unresolved = mk_main(&mut self.cx);
-            self.cx.ext_cx.monotonic_expander().fold_item(unresolved).pop().unwrap()
+            self.cx.ext_cx.monotonic_expander().flat_map_item(unresolved).pop().unwrap()
         };
 
-        folded.module.items.push(test_main);
-        folded
+        c.module.items.push(test_main);
     }
 
-    fn fold_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
+    fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
         let ident = i.ident;
         if ident.name != keywords::Invalid.name() {
             self.cx.path.push(ident);
@@ -123,16 +119,16 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
 
         // We don't want to recurse into anything other than mods, since
         // mods or tests inside of functions will break things
-        if let ast::ItemKind::Mod(module) = item.node {
+        if let ast::ItemKind::Mod(mut module) = item.node {
             let tests = mem::replace(&mut self.tests, Vec::new());
             let tested_submods = mem::replace(&mut self.tested_submods, Vec::new());
-            let mut mod_folded = fold::noop_fold_mod(module, self);
+            noop_visit_mod(&mut module, self);
             let tests = mem::replace(&mut self.tests, tests);
             let tested_submods = mem::replace(&mut self.tested_submods, tested_submods);
 
             if !tests.is_empty() || !tested_submods.is_empty() {
                 let (it, sym) = mk_reexport_mod(&mut self.cx, item.id, tests, tested_submods);
-                mod_folded.items.push(it);
+                module.items.push(it);
 
                 if !self.cx.path.is_empty() {
                     self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym));
@@ -141,7 +137,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
                     self.cx.toplevel_reexport = Some(sym);
                 }
             }
-            item.node = ast::ItemKind::Mod(mod_folded);
+            item.node = ast::ItemKind::Mod(module);
         }
         if ident.name != keywords::Invalid.name() {
             self.cx.path.pop();
@@ -149,7 +145,9 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
         smallvec![P(item)]
     }
 
-    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
+    fn visit_mac(&mut self, _mac: &mut ast::Mac) {
+        // Do nothing.
+    }
 }
 
 /// A folder used to remove any entry points (like fn main) because the harness
@@ -159,20 +157,20 @@ struct EntryPointCleaner {
     depth: usize,
 }
 
-impl fold::Folder for EntryPointCleaner {
-    fn fold_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
+impl MutVisitor for EntryPointCleaner {
+    fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
         self.depth += 1;
-        let folded = fold::noop_fold_item(i, self).expect_one("noop did something");
+        let item = noop_flat_map_item(i, self).expect_one("noop did something");
         self.depth -= 1;
 
         // Remove any #[main] or #[start] from the AST so it doesn't
         // clash with the one we're going to add, but mark it as
         // #[allow(dead_code)] to avoid printing warnings.
-        let folded = match entry::entry_point_type(&folded, self.depth) {
+        let item = match entry::entry_point_type(&item, self.depth) {
             EntryPointType::MainNamed |
             EntryPointType::MainAttr |
             EntryPointType::Start =>
-                folded.map(|ast::Item {id, ident, attrs, node, vis, span, tokens}| {
+                item.map(|ast::Item {id, ident, attrs, node, vis, span, tokens}| {
                     let allow_ident = Ident::from_str("allow");
                     let dc_nested = attr::mk_nested_word_item(Ident::from_str("dead_code"));
                     let allow_dead_code_item = attr::mk_list_item(DUMMY_SP, allow_ident,
@@ -197,13 +195,15 @@ impl fold::Folder for EntryPointCleaner {
                     }
                 }),
             EntryPointType::None |
-            EntryPointType::OtherMain => folded,
+            EntryPointType::OtherMain => item,
         };
 
-        smallvec![folded]
+        smallvec![item]
     }
 
-    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
+    fn visit_mac(&mut self, _mac: &mut ast::Mac) {
+        // Do nothing.
+    }
 }
 
 /// Creates an item (specifically a module) that "pub use"s the tests passed in.
@@ -235,7 +235,7 @@ fn mk_reexport_mod(cx: &mut TestCtxt,
     let sym = Ident::with_empty_ctxt(Symbol::gensym("__test_reexports"));
     let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent };
     cx.ext_cx.current_expansion.mark = cx.ext_cx.resolver.get_module_scope(parent);
-    let it = cx.ext_cx.monotonic_expander().fold_item(P(ast::Item {
+    let it = cx.ext_cx.monotonic_expander().flat_map_item(P(ast::Item {
         ident: sym,
         attrs: Vec::new(),
         id: ast::DUMMY_NODE_ID,
@@ -252,13 +252,13 @@ fn mk_reexport_mod(cx: &mut TestCtxt,
 fn generate_test_harness(sess: &ParseSess,
                          resolver: &mut dyn Resolver,
                          reexport_test_harness_main: Option<Symbol>,
-                         krate: ast::Crate,
+                         krate: &mut ast::Crate,
                          sd: &errors::Handler,
                          features: &Features,
-                         test_runner: Option<ast::Path>) -> ast::Crate {
+                         test_runner: Option<ast::Path>) {
     // Remove the entry points
     let mut cleaner = EntryPointCleaner { depth: 0 };
-    let krate = cleaner.fold_crate(krate);
+    cleaner.visit_crate(krate);
 
     let mark = Mark::fresh(Mark::root());
 
@@ -293,7 +293,7 @@ fn generate_test_harness(sess: &ParseSess,
         cx,
         tests: Vec::new(),
         tested_submods: Vec::new(),
-    }.fold_crate(krate)
+    }.visit_crate(krate);
 }
 
 /// Craft a span that will be ignored by the stability lint's
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index f5d2d6f18ee87..ff5978a7ee581 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -147,7 +147,7 @@ impl TokenTree {
 /// empty stream is represented with `None`; it may be represented as a `Some`
 /// around an empty `Vec`.
 #[derive(Clone, Debug)]
-pub struct TokenStream(Option<Lrc<Vec<TreeAndJoint>>>);
+pub struct TokenStream(pub Option<Lrc<Vec<TreeAndJoint>>>);
 
 pub type TreeAndJoint = (TokenTree, IsJoint);
 
diff --git a/src/libsyntax/util/move_map.rs b/src/libsyntax/util/map_in_place.rs
similarity index 82%
rename from src/libsyntax/util/move_map.rs
rename to src/libsyntax/util/map_in_place.rs
index a0f9d39ce89b3..5724b540a0dcf 100644
--- a/src/libsyntax/util/move_map.rs
+++ b/src/libsyntax/util/map_in_place.rs
@@ -1,18 +1,18 @@
 use std::ptr;
 use smallvec::{Array, SmallVec};
 
-pub trait MoveMap<T>: Sized {
-    fn move_map<F>(self, mut f: F) -> Self where F: FnMut(T) -> T {
-        self.move_flat_map(|e| Some(f(e)))
+pub trait MapInPlace<T>: Sized {
+    fn map_in_place<F>(&mut self, mut f: F) where F: FnMut(T) -> T {
+        self.flat_map_in_place(|e| Some(f(e)))
     }
 
-    fn move_flat_map<F, I>(self, f: F) -> Self
+    fn flat_map_in_place<F, I>(&mut self, f: F)
         where F: FnMut(T) -> I,
               I: IntoIterator<Item=T>;
 }
 
-impl<T> MoveMap<T> for Vec<T> {
-    fn move_flat_map<F, I>(mut self, mut f: F) -> Self
+impl<T> MapInPlace<T> for Vec<T> {
+    fn flat_map_in_place<F, I>(&mut self, mut f: F)
         where F: FnMut(T) -> I,
               I: IntoIterator<Item=T>
     {
@@ -53,22 +53,11 @@ impl<T> MoveMap<T> for Vec<T> {
             // write_i tracks the number of actually written new items.
             self.set_len(write_i);
         }
-
-        self
-    }
-}
-
-impl<T> MoveMap<T> for ::ptr::P<[T]> {
-    fn move_flat_map<F, I>(self, f: F) -> Self
-        where F: FnMut(T) -> I,
-              I: IntoIterator<Item=T>
-    {
-        ::ptr::P::from_vec(self.into_vec().move_flat_map(f))
     }
 }
 
-impl<T, A: Array<Item = T>> MoveMap<T> for SmallVec<A> {
-    fn move_flat_map<F, I>(mut self, mut f: F) -> Self
+impl<T, A: Array<Item = T>> MapInPlace<T> for SmallVec<A> {
+    fn flat_map_in_place<F, I>(&mut self, mut f: F)
         where F: FnMut(T) -> I,
               I: IntoIterator<Item=T>
     {
@@ -109,7 +98,5 @@ impl<T, A: Array<Item = T>> MoveMap<T> for SmallVec<A> {
             // write_i tracks the number of actually written new items.
             self.set_len(write_i);
         }
-
-        self
     }
 }
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 22643db501693..ec2c3113fab95 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -189,7 +189,7 @@ use syntax::attr;
 use syntax::ext::base::{Annotatable, ExtCtxt};
 use syntax::ext::build::AstBuilder;
 use syntax::source_map::{self, respan};
-use syntax::util::move_map::MoveMap;
+use syntax::util::map_in_place::MapInPlace;
 use syntax::ptr::P;
 use syntax::symbol::{Symbol, keywords};
 use syntax::parse::ParseSess;
@@ -1184,7 +1184,7 @@ impl<'a> MethodDef<'a> {
                                   enum_def: &'b EnumDef,
                                   type_attrs: &[ast::Attribute],
                                   type_ident: Ident,
-                                  self_args: Vec<P<Expr>>,
+                                  mut self_args: Vec<P<Expr>>,
                                   nonself_args: &[P<Expr>])
                                   -> P<Expr> {
         let sp = trait_.span;
@@ -1417,8 +1417,8 @@ impl<'a> MethodDef<'a> {
             // them when they are fed as r-values into a tuple
             // expression; here add a layer of borrowing, turning
             // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
-            let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg));
-            let match_arg = cx.expr(sp, ast::ExprKind::Tup(borrowed_self_args));
+            self_args.map_in_place(|self_arg| cx.expr_addr_of(sp, self_arg));
+            let match_arg = cx.expr(sp, ast::ExprKind::Tup(self_args));
 
             // Lastly we create an expression which branches on all discriminants being equal
             //  if discriminant_test {
@@ -1494,8 +1494,8 @@ impl<'a> MethodDef<'a> {
             // them when they are fed as r-values into a tuple
             // expression; here add a layer of borrowing, turning
             // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
-            let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg));
-            let match_arg = cx.expr(sp, ast::ExprKind::Tup(borrowed_self_args));
+            self_args.map_in_place(|self_arg| cx.expr_addr_of(sp, self_arg));
+            let match_arg = cx.expr(sp, ast::ExprKind::Tup(self_args));
             cx.expr_match(sp, match_arg, match_arms)
         }
     }
diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs
index 46c502965eea8..663fb12242c44 100644
--- a/src/libsyntax_ext/proc_macro_decls.rs
+++ b/src/libsyntax_ext/proc_macro_decls.rs
@@ -9,7 +9,7 @@ use syntax::ext::base::ExtCtxt;
 use syntax::ext::build::AstBuilder;
 use syntax::ext::expand::ExpansionConfig;
 use syntax::ext::hygiene::Mark;
-use syntax::fold::Folder;
+use syntax::mut_visit::MutVisitor;
 use syntax::parse::ParseSess;
 use syntax::ptr::P;
 use syntax::symbol::Symbol;
@@ -412,5 +412,5 @@ fn mk_decls(
         i
     });
 
-    cx.monotonic_expander().fold_item(module).pop().unwrap()
+    cx.monotonic_expander().flat_map_item(module).pop().unwrap()
 }
diff --git a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
index ce3b03efd2604..ee4ecde44f28e 100644
--- a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
+++ b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
@@ -27,7 +27,7 @@ use rustc_data_structures::thin_vec::ThinVec;
 use syntax::ast::*;
 use syntax::source_map::{Spanned, DUMMY_SP, FileName};
 use syntax::source_map::FilePathMapping;
-use syntax::fold::{self, Folder};
+use syntax::mut_visit::{self, MutVisitor, visit_clobber};
 use syntax::parse::{self, ParseSess};
 use syntax::print::pprust;
 use syntax::ptr::P;
@@ -157,32 +157,34 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P<Expr>)) {
 
 // Folders for manipulating the placement of `Paren` nodes.  See below for why this is needed.
 
-/// Folder that removes all `ExprKind::Paren` nodes.
+/// MutVisitor that removes all `ExprKind::Paren` nodes.
 struct RemoveParens;
 
-impl Folder for RemoveParens {
-    fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
-        let e = match e.node {
-            ExprKind::Paren(ref inner) => inner.clone(),
-            _ => e.clone(),
+impl MutVisitor for RemoveParens {
+    fn visit_expr(&mut self, e: &mut P<Expr>) {
+        match e.node.clone() {
+            ExprKind::Paren(inner) => *e = inner,
+            _ => {}
         };
-        e.map(|e| fold::noop_fold_expr(e, self))
+        mut_visit::noop_visit_expr(e, self);
     }
 }
 
 
-/// Folder that inserts `ExprKind::Paren` nodes around every `Expr`.
+/// MutVisitor that inserts `ExprKind::Paren` nodes around every `Expr`.
 struct AddParens;
 
-impl Folder for AddParens {
-    fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
-        let e = e.map(|e| fold::noop_fold_expr(e, self));
-        P(Expr {
-            id: DUMMY_NODE_ID,
-            node: ExprKind::Paren(e),
-            span: DUMMY_SP,
-            attrs: ThinVec::new(),
-        })
+impl MutVisitor for AddParens {
+    fn visit_expr(&mut self, e: &mut P<Expr>) {
+        mut_visit::noop_visit_expr(e, self);
+        visit_clobber(e, |e| {
+            P(Expr {
+                id: DUMMY_NODE_ID,
+                node: ExprKind::Paren(e),
+                span: DUMMY_SP,
+                attrs: ThinVec::new(),
+            })
+        });
     }
 }
 
@@ -193,13 +195,13 @@ fn main() {
 fn run() {
     let ps = ParseSess::new(FilePathMapping::empty());
 
-    iter_exprs(2, &mut |e| {
+    iter_exprs(2, &mut |mut e| {
         // If the pretty printer is correct, then `parse(print(e))` should be identical to `e`,
         // modulo placement of `Paren` nodes.
         let printed = pprust::expr_to_string(&e);
         println!("printed: {}", printed);
 
-        let parsed = parse_expr(&ps, &printed);
+        let mut parsed = parse_expr(&ps, &printed);
 
         // We want to know if `parsed` is structurally identical to `e`, ignoring trivial
         // differences like placement of `Paren`s or the exact ranges of node spans.
@@ -207,10 +209,12 @@ fn run() {
         // everywhere we can, then pretty-print.  This should give an unambiguous representation of
         // each `Expr`, and it bypasses nearly all of the parenthesization logic, so we aren't
         // relying on the correctness of the very thing we're testing.
-        let e1 = AddParens.fold_expr(RemoveParens.fold_expr(e));
-        let text1 = pprust::expr_to_string(&e1);
-        let e2 = AddParens.fold_expr(RemoveParens.fold_expr(parsed));
-        let text2 = pprust::expr_to_string(&e2);
+        RemoveParens.visit_expr(&mut e);
+        AddParens.visit_expr(&mut e);
+        let text1 = pprust::expr_to_string(&e);
+        RemoveParens.visit_expr(&mut parsed);
+        AddParens.visit_expr(&mut parsed);
+        let text2 = pprust::expr_to_string(&parsed);
         assert!(text1 == text2,
                 "exprs are not equal:\n  e =      {:?}\n  parsed = {:?}",
                 text1, text2);
diff --git a/src/test/ui/issues/issue-49934.rs b/src/test/ui/issues/issue-49934.rs
index 59ca6cc292db9..ad410f30c04d4 100644
--- a/src/test/ui/issues/issue-49934.rs
+++ b/src/test/ui/issues/issue-49934.rs
@@ -30,12 +30,12 @@ fn main() {
     #[derive(Debug)] //~ WARN unused attribute
     let _ = "Hello, world!";
 
-    // fold_expr
+    // visit_expr
     let _ = #[derive(Debug)] "Hello, world!";
     //~^ WARN unused attribute
 
     let _ = [
-        // fold_opt_expr
+        // filter_map_expr
         #[derive(Debug)] //~ WARN unused attribute
         "Hello, world!"
     ];

From bfcbd235a28f989c0e3c1f0a7542f4e5caaf6e0d Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <nnethercote@mozilla.com>
Date: Wed, 6 Feb 2019 09:10:05 +1100
Subject: [PATCH 10/10] Rename `fold.rs` as `mut_visit.rs`.

---
 src/libsyntax/lib.rs                    | 2 +-
 src/libsyntax/{fold.rs => mut_visit.rs} | 0
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename src/libsyntax/{fold.rs => mut_visit.rs} (100%)

diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index dacb0d811cedb..f2b8f23ee8530 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -151,7 +151,7 @@ pub mod source_map;
 pub mod config;
 pub mod entry;
 pub mod feature_gate;
-#[path="fold.rs"] pub mod mut_visit;    // temporary
+pub mod mut_visit;
 pub mod parse;
 pub mod ptr;
 pub mod show_span;
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/mut_visit.rs
similarity index 100%
rename from src/libsyntax/fold.rs
rename to src/libsyntax/mut_visit.rs