about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-02-09 10:34:23 -0500
committerNiko Matsakis <niko@alum.mit.edu>2018-03-13 11:21:29 -0400
commit23837c1901ab234ee6bc806744cd47d5a652cdfc (patch)
treebe34e5c15bfee3a8e092b9c22d3f382e5637c44b /src
parentf873c1e2db8d06be6a816b838655906fa9f2dac9 (diff)
downloadrust-23837c1901ab234ee6bc806744cd47d5a652cdfc.tar.gz
rust-23837c1901ab234ee6bc806744cd47d5a652cdfc.zip
improve TypeFoldable/Lift macros and make a bunch of stuff use them
Improvements:

- Use Clone not Copy for the "simple cases"
- Separate TypeFoldable and Lift for the "simple cases"
- Support generics type parameters
- Support named fields in enum variants
- etc
Diffstat (limited to 'src')
-rw-r--r--src/librustc/infer/mod.rs13
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/macros.rs300
-rw-r--r--src/librustc/mir/cache.rs4
-rw-r--r--src/librustc/mir/mod.rs186
-rw-r--r--src/librustc/mir/tcx.rs24
-rw-r--r--src/librustc/traits/structural_impls.rs281
-rw-r--r--src/librustc/ty/fold.rs3
-rw-r--r--src/librustc/ty/relate.rs11
-rw-r--r--src/librustc/ty/structural_impls.rs541
10 files changed, 551 insertions, 813 deletions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 5d44b2043e2..b94f1819c7d 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1647,19 +1647,6 @@ impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        TypeTrace {
-            cause: self.cause.fold_with(folder),
-            values: self.values.fold_with(folder)
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.cause.visit_with(visitor) || self.values.visit_with(visitor)
-    }
-}
-
 impl<'tcx> fmt::Debug for RegionObligation<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "RegionObligation(sub_region={:?}, sup_type={:?})",
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 56de2939ffa..2cf17603629 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -57,6 +57,7 @@
 #![feature(inclusive_range)]
 #![feature(inclusive_range_syntax)]
 #![cfg_attr(windows, feature(libc))]
+#![feature(macro_lifetime_matcher)]
 #![feature(macro_vis_matcher)]
 #![feature(match_default_bindings)]
 #![feature(never_type)]
diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs
index 9a394e52481..6013e3aef81 100644
--- a/src/librustc/macros.rs
+++ b/src/librustc/macros.rs
@@ -138,3 +138,303 @@ macro_rules! impl_stable_hash_for_spanned {
     );
 }
 
+///////////////////////////////////////////////////////////////////////////
+// Lift and TypeFoldable macros
+//
+// When possible, use one of these (relatively) convenient macros to write
+// the impls for you.
+
+#[macro_export]
+macro_rules! CloneLiftImpls {
+    (for <$tcx:lifetime> { $($ty:ty,)+ }) => {
+        $(
+            impl<$tcx> $crate::ty::Lift<$tcx> for $ty {
+                type Lifted = Self;
+                fn lift_to_tcx<'a, 'gcx>(&self, _: $crate::ty::TyCtxt<'a, 'gcx, $tcx>) -> Option<Self> {
+                    Some(Clone::clone(self))
+                }
+            }
+        )+
+    };
+
+    ($($ty:ty,)+) => {
+        CloneLiftImpls! {
+            for <'tcx> {
+                $($ty,)+
+            }
+        }
+    };
+}
+
+/// Used for types that are `Copy` and which **do not care arena
+/// allocated data** (i.e., don't need to be folded).
+#[macro_export]
+macro_rules! CloneTypeFoldableImpls {
+    (for <$tcx:lifetime> { $($ty:ty,)+ }) => {
+        $(
+            impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty {
+                fn super_fold_with<'gcx: $tcx, F: $crate::ty::fold::TypeFolder<'gcx, $tcx>>(
+                    &self,
+                    _: &mut F
+                ) -> $ty {
+                    Clone::clone(self)
+                }
+
+                fn super_visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>(
+                    &self,
+                    _: &mut F)
+                    -> bool
+                {
+                    false
+                }
+            }
+        )+
+    };
+
+    ($($ty:ty,)+) => {
+        CloneTypeFoldableImpls! {
+            for <'tcx> {
+                $($ty,)+
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! CloneTypeFoldableAndLiftImpls {
+    ($($t:tt)*) => {
+        CloneTypeFoldableImpls! { $($t)* }
+        CloneLiftImpls! { $($t)* }
+    }
+}
+
+#[macro_export]
+macro_rules! BraceStructLiftImpl {
+    (impl<$($p:tt),*> Lift<$tcx:tt> for $s:path {
+        type Lifted = $lifted:ty;
+        $($field:ident),* $(,)*
+    } $(where $($wc:tt)*)*) => {
+        impl<$($p),*> $crate::ty::Lift<$tcx> for $s
+            $(where $($wc)*)*
+        {
+            type Lifted = $lifted;
+
+            fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<$lifted> {
+                $(let $field = tcx.lift(&self.$field)?;)*
+                Some(Self::Lifted { $($field),* })
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! EnumLiftImpl {
+    (impl<$($p:tt),*> Lift<$tcx:tt> for $s:path {
+        type Lifted = $lifted:ty;
+        $(
+            ($variant:path) ( $( $variant_arg:ident),* )
+        ),*
+        $(,)*
+    } $(where $($wc:tt)*)*) => {
+        impl<$($p),*> $crate::ty::Lift<$tcx> for $s
+            $(where $($wc)*)*
+        {
+            type Lifted = $lifted;
+
+            fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<$lifted> {
+                match self {
+                    $($variant ( $($variant_arg),* ) => {
+                        Some($variant ( $(tcx.lift($variant_arg)?),* ))
+                    })*
+                }
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! BraceStructTypeFoldableImpl {
+    (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
+        $($field:ident),* $(,)*
+    } $(where $($wc:tt)*)*) => {
+        impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s
+            $(where $($wc)*)*
+        {
+            fn super_fold_with<'gcx: $tcx, V: $crate::ty::fold::TypeFolder<'gcx, $tcx>>(
+                &self,
+                folder: &mut V,
+            ) -> Self {
+                let $s { $($field,)* } = self;
+                $s { $($field: $crate::ty::fold::TypeFoldable::fold_with($field, folder),)* }
+            }
+
+            fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>(
+                &self,
+                visitor: &mut V,
+            ) -> bool {
+                let $s { $($field,)* } = self;
+                false $(|| $crate::ty::fold::TypeFoldable::visit_with($field, visitor))*
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! TupleStructTypeFoldableImpl {
+    (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
+        $($field:ident),* $(,)*
+    } $(where $($wc:tt)*)*) => {
+        impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s
+            $(where $($wc)*)*
+        {
+            fn super_fold_with<'gcx: $tcx, V: $crate::ty::fold::TypeFolder<'gcx, $tcx>>(
+                &self,
+                folder: &mut V,
+            ) -> Self {
+                let $s($($field,)*)= self;
+                $s($($crate::ty::fold::TypeFoldable::fold_with($field, folder),)*)
+            }
+
+            fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>(
+                &self,
+                visitor: &mut V,
+            ) -> bool {
+                let $s($($field,)*) = self;
+                false $(|| $crate::ty::fold::TypeFoldable::visit_with($field, visitor))*
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! EnumTypeFoldableImpl {
+    (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
+        $($variants:tt)*
+    } $(where $($wc:tt)*)*) => {
+        impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s
+            $(where $($wc)*)*
+        {
+            fn super_fold_with<'gcx: $tcx, V: $crate::ty::fold::TypeFolder<'gcx, $tcx>>(
+                &self,
+                folder: &mut V,
+            ) -> Self {
+                EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output())
+            }
+
+            fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>(
+                &self,
+                visitor: &mut V,
+            ) -> bool {
+                EnumTypeFoldableImpl!(@VisitVariants(self, visitor) input($($variants)*) output())
+            }
+        }
+    };
+
+    (@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => {
+        match $this {
+            $($output)*
+        }
+    };
+
+    (@FoldVariants($this:expr, $folder:expr)
+     input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
+     output( $($output:tt)*) ) => {
+        EnumTypeFoldableImpl!(
+            @FoldVariants($this, $folder)
+                input($($input)*)
+                output(
+                    $variant ( $($variant_arg),* ) => {
+                        $variant (
+                            $($crate::ty::fold::TypeFoldable::fold_with($variant_arg, $folder)),*
+                        )
+                    }
+                    $($output)*
+                )
+        )
+    };
+
+    (@FoldVariants($this:expr, $folder:expr)
+     input( ($variant:path) { $($variant_arg:ident),* $(,)* } , $($input:tt)*)
+     output( $($output:tt)*) ) => {
+        EnumTypeFoldableImpl!(
+            @FoldVariants($this, $folder)
+                input($($input)*)
+                output(
+                    $variant { $($variant_arg),* } => {
+                        $variant {
+                            $($variant_arg: $crate::ty::fold::TypeFoldable::fold_with(
+                                $variant_arg, $folder
+                            )),* }
+                    }
+                    $($output)*
+                )
+        )
+    };
+
+    (@FoldVariants($this:expr, $folder:expr)
+     input( ($variant:path), $($input:tt)*)
+     output( $($output:tt)*) ) => {
+        EnumTypeFoldableImpl!(
+            @FoldVariants($this, $folder)
+                input($($input)*)
+                output(
+                    $variant => { $variant }
+                    $($output)*
+                )
+        )
+    };
+
+    (@VisitVariants($this:expr, $visitor:expr) input() output($($output:tt)*)) => {
+        match $this {
+            $($output)*
+        }
+    };
+
+    (@VisitVariants($this:expr, $visitor:expr)
+     input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
+     output( $($output:tt)*) ) => {
+        EnumTypeFoldableImpl!(
+            @VisitVariants($this, $visitor)
+                input($($input)*)
+                output(
+                    $variant ( $($variant_arg),* ) => {
+                        false $(|| $crate::ty::fold::TypeFoldable::visit_with(
+                            $variant_arg, $visitor
+                        ))*
+                    }
+                    $($output)*
+                )
+        )
+    };
+
+    (@VisitVariants($this:expr, $visitor:expr)
+     input( ($variant:path) { $($variant_arg:ident),* $(,)* } , $($input:tt)*)
+     output( $($output:tt)*) ) => {
+        EnumTypeFoldableImpl!(
+            @VisitVariants($this, $visitor)
+                input($($input)*)
+                output(
+                    $variant { $($variant_arg),* } => {
+                        false $(|| $crate::ty::fold::TypeFoldable::visit_with(
+                            $variant_arg, $visitor
+                        ))*
+                    }
+                    $($output)*
+                )
+        )
+    };
+
+    (@VisitVariants($this:expr, $visitor:expr)
+     input( ($variant:path), $($input:tt)*)
+     output( $($output:tt)*) ) => {
+        EnumTypeFoldableImpl!(
+            @VisitVariants($this, $visitor)
+                input($($input)*)
+                output(
+                    $variant => { false }
+                    $($output)*
+                )
+        )
+    };
+}
+
diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs
index 45cb70d0070..9b75c19a875 100644
--- a/src/librustc/mir/cache.rs
+++ b/src/librustc/mir/cache.rs
@@ -76,3 +76,7 @@ fn calculate_predecessors(mir: &Mir) -> IndexVec<BasicBlock, Vec<BasicBlock>> {
 
     result
 }
+
+CloneTypeFoldableAndLiftImpls! {
+    Cache,
+}
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index e39765699f9..939710ffd2b 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -2109,148 +2109,90 @@ pub enum ClosureOutlivesSubject<'tcx> {
  * TypeFoldable implementations for MIR types
  */
 
-impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        Mir {
-            basic_blocks: self.basic_blocks.fold_with(folder),
-            visibility_scopes: self.visibility_scopes.clone(),
-            visibility_scope_info: self.visibility_scope_info.clone(),
-            promoted: self.promoted.fold_with(folder),
-            yield_ty: self.yield_ty.fold_with(folder),
-            generator_drop: self.generator_drop.fold_with(folder),
-            generator_layout: self.generator_layout.fold_with(folder),
-            local_decls: self.local_decls.fold_with(folder),
-            arg_count: self.arg_count,
-            upvar_decls: self.upvar_decls.clone(),
-            spread_arg: self.spread_arg,
-            span: self.span,
-            cache: cache::Cache::new()
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.basic_blocks.visit_with(visitor) ||
-        self.generator_drop.visit_with(visitor) ||
-        self.generator_layout.visit_with(visitor) ||
-        self.yield_ty.visit_with(visitor) ||
-        self.promoted.visit_with(visitor)     ||
-        self.local_decls.visit_with(visitor)
-    }
+CloneTypeFoldableAndLiftImpls! {
+    Mutability,
+    SourceInfo,
+    UpvarDecl,
+    ValidationOp,
+    VisibilityScopeData,
+    VisibilityScope,
+    VisibilityScopeInfo,
 }
 
-impl<'tcx> TypeFoldable<'tcx> for GeneratorLayout<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        GeneratorLayout {
-            fields: self.fields.fold_with(folder),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.fields.visit_with(visitor)
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> {
+        basic_blocks,
+        visibility_scopes,
+        visibility_scope_info,
+        promoted,
+        yield_ty,
+        generator_drop,
+        generator_layout,
+        local_decls,
+        arg_count,
+        upvar_decls,
+        spread_arg,
+        span,
+        cache,
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        LocalDecl {
-            ty: self.ty.fold_with(folder),
-            ..self.clone()
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.ty.visit_with(visitor)
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for GeneratorLayout<'tcx> {
+        fields
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        BasicBlockData {
-            statements: self.statements.fold_with(folder),
-            terminator: self.terminator.fold_with(folder),
-            is_cleanup: self.is_cleanup
-        }
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> {
+        mutability,
+        is_user_variable,
+        internal,
+        ty,
+        name,
+        source_info,
+        syntactic_scope,
     }
+}
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.statements.visit_with(visitor) || self.terminator.visit_with(visitor)
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> {
+        statements,
+        terminator,
+        is_cleanup,
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ValidationOperand<'tcx, Place<'tcx>> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ValidationOperand {
-            place: self.place.fold_with(folder),
-            ty: self.ty.fold_with(folder),
-            re: self.re,
-            mutbl: self.mutbl,
-        }
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ValidationOperand<'tcx, Place<'tcx>> {
+        place, ty, re, mutbl
     }
+}
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.place.visit_with(visitor) || self.ty.visit_with(visitor)
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
+        source_info, kind
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        use mir::StatementKind::*;
-
-        let kind = match self.kind {
-            Assign(ref place, ref rval) => Assign(place.fold_with(folder), rval.fold_with(folder)),
-            SetDiscriminant { ref place, variant_index } => SetDiscriminant {
-                place: place.fold_with(folder),
-                variant_index,
-            },
-            StorageLive(ref local) => StorageLive(local.fold_with(folder)),
-            StorageDead(ref local) => StorageDead(local.fold_with(folder)),
-            InlineAsm { ref asm, ref outputs, ref inputs } => InlineAsm {
-                asm: asm.clone(),
-                outputs: outputs.fold_with(folder),
-                inputs: inputs.fold_with(folder)
-            },
-
-            // Note for future: If we want to expose the region scopes
-            // during the fold, we need to either generalize EndRegion
-            // to carry `[ty::Region]`, or extend the `TypeFolder`
-            // trait with a `fn fold_scope`.
-            EndRegion(ref region_scope) => EndRegion(region_scope.clone()),
-
-            Validate(ref op, ref places) =>
-                Validate(op.clone(),
-                         places.iter().map(|operand| operand.fold_with(folder)).collect()),
-
-            Nop => Nop,
-        };
-        Statement {
-            source_info: self.source_info,
-            kind,
-        }
+EnumTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> {
+        (StatementKind::Assign)(a, b),
+        (StatementKind::SetDiscriminant) { place, variant_index },
+        (StatementKind::StorageLive)(a),
+        (StatementKind::StorageDead)(a),
+        (StatementKind::InlineAsm) { asm, outputs, inputs },
+        (StatementKind::Validate)(a, b),
+        (StatementKind::EndRegion)(a),
+        (StatementKind::Nop),
     }
+}
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        use mir::StatementKind::*;
-
-        match self.kind {
-            Assign(ref place, ref rval) => { place.visit_with(visitor) || rval.visit_with(visitor) }
-            SetDiscriminant { ref place, .. } => place.visit_with(visitor),
-            StorageLive(ref local) |
-            StorageDead(ref local) => local.visit_with(visitor),
-            InlineAsm { ref outputs, ref inputs, .. } =>
-                outputs.visit_with(visitor) || inputs.visit_with(visitor),
-
-            // Note for future: If we want to expose the region scopes
-            // during the visit, we need to either generalize EndRegion
-            // to carry `[ty::Region]`, or extend the `TypeVisitor`
-            // trait with a `fn visit_scope`.
-            EndRegion(ref _scope) => false,
-
-            Validate(ref _op, ref places) =>
-                places.iter().any(|ty_and_place| ty_and_place.visit_with(visitor)),
-
-            Nop => false,
-        }
-    }
+EnumTypeFoldableImpl! {
+    impl<'tcx, T> TypeFoldable<'tcx> for ClearCrossCrate<T> {
+        (ClearCrossCrate::Clear),
+        (ClearCrossCrate::Set)(a),
+    } where T: TypeFoldable<'tcx>
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 7d232ac20bf..d779ccd1736 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -16,7 +16,6 @@
 use mir::*;
 use ty::subst::{Subst, Substs};
 use ty::{self, AdtDef, Ty, TyCtxt};
-use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use hir;
 use ty::util::IntTypeExt;
 
@@ -100,25 +99,10 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for PlaceTy<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        match *self {
-            PlaceTy::Ty { ty } => PlaceTy::Ty { ty: ty.fold_with(folder) },
-            PlaceTy::Downcast { adt_def, substs, variant_index } => {
-                PlaceTy::Downcast {
-                    adt_def,
-                    substs: substs.fold_with(folder),
-                    variant_index,
-                }
-            }
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        match *self {
-            PlaceTy::Ty { ty } => ty.visit_with(visitor),
-            PlaceTy::Downcast { substs, .. } => substs.visit_with(visitor)
-        }
+EnumTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for PlaceTy<'tcx> {
+        (PlaceTy::Ty) { ty },
+        (PlaceTy::Downcast) { adt_def, substs, variant_index },
     }
 }
 
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 9dd5aaee7b7..99adc1fc873 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -363,258 +363,67 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx
     }
 }
 
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        traits::VtableImplData {
-            impl_def_id: self.impl_def_id,
-            substs: self.substs.fold_with(folder),
-            nested: self.nested.fold_with(folder),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.substs.visit_with(visitor) || self.nested.visit_with(visitor)
-    }
+BraceStructTypeFoldableImpl! {
+    impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> {
+        impl_def_id, substs, nested
+    } where N: TypeFoldable<'tcx>
 }
 
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableGeneratorData<'tcx, N> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        traits::VtableGeneratorData {
-            closure_def_id: self.closure_def_id,
-            substs: self.substs.fold_with(folder),
-            nested: self.nested.fold_with(folder),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.substs.visit_with(visitor) || self.nested.visit_with(visitor)
-    }
+BraceStructTypeFoldableImpl! {
+    impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableGeneratorData<'tcx, N> {
+        closure_def_id, substs, nested
+    } where N: TypeFoldable<'tcx>
 }
 
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        traits::VtableClosureData {
-            closure_def_id: self.closure_def_id,
-            substs: self.substs.fold_with(folder),
-            nested: self.nested.fold_with(folder),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.substs.visit_with(visitor) || self.nested.visit_with(visitor)
-    }
+BraceStructTypeFoldableImpl! {
+    impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> {
+        closure_def_id, substs, nested
+    } where N: TypeFoldable<'tcx>
 }
 
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableAutoImplData<N> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        traits::VtableAutoImplData {
-            trait_def_id: self.trait_def_id,
-            nested: self.nested.fold_with(folder),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.nested.visit_with(visitor)
-    }
+BraceStructTypeFoldableImpl! {
+    impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableAutoImplData<N> {
+        trait_def_id, nested
+    } where N: TypeFoldable<'tcx>
 }
 
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData<N> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        traits::VtableBuiltinData {
-            nested: self.nested.fold_with(folder),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.nested.visit_with(visitor)
-    }
+BraceStructTypeFoldableImpl! {
+    impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableBuiltinData<N> {
+        nested
+    } where N: TypeFoldable<'tcx>
 }
 
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx, N> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        traits::VtableObjectData {
-            upcast_trait_ref: self.upcast_trait_ref.fold_with(folder),
-            vtable_base: self.vtable_base,
-            nested: self.nested.fold_with(folder),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.upcast_trait_ref.visit_with(visitor) || self.nested.visit_with(visitor)
-    }
+BraceStructTypeFoldableImpl! {
+    impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx, N> {
+        upcast_trait_ref, vtable_base, nested
+    } where N: TypeFoldable<'tcx>
 }
 
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableFnPointerData<'tcx, N> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        traits::VtableFnPointerData {
-            fn_ty: self.fn_ty.fold_with(folder),
-            nested: self.nested.fold_with(folder),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.fn_ty.visit_with(visitor) || self.nested.visit_with(visitor)
-    }
+BraceStructTypeFoldableImpl! {
+    impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableFnPointerData<'tcx, N> {
+        fn_ty,
+        nested
+    } where N: TypeFoldable<'tcx>
 }
 
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        match *self {
-            traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
-            traits::VtableAutoImpl(ref t) => traits::VtableAutoImpl(t.fold_with(folder)),
-            traits::VtableGenerator(ref d) => {
-                traits::VtableGenerator(d.fold_with(folder))
-            }
-            traits::VtableClosure(ref d) => {
-                traits::VtableClosure(d.fold_with(folder))
-            }
-            traits::VtableFnPointer(ref d) => {
-                traits::VtableFnPointer(d.fold_with(folder))
-            }
-            traits::VtableParam(ref n) => traits::VtableParam(n.fold_with(folder)),
-            traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
-            traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        match *self {
-            traits::VtableImpl(ref v) => v.visit_with(visitor),
-            traits::VtableAutoImpl(ref t) => t.visit_with(visitor),
-            traits::VtableGenerator(ref d) => d.visit_with(visitor),
-            traits::VtableClosure(ref d) => d.visit_with(visitor),
-            traits::VtableFnPointer(ref d) => d.visit_with(visitor),
-            traits::VtableParam(ref n) => n.visit_with(visitor),
-            traits::VtableBuiltin(ref d) => d.visit_with(visitor),
-            traits::VtableObject(ref d) => d.visit_with(visitor),
-        }
-    }
+EnumTypeFoldableImpl! {
+    impl<'tcx, N> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> {
+        (traits::VtableImpl)(a),
+        (traits::VtableAutoImpl)(a),
+        (traits::VtableGenerator)(a),
+        (traits::VtableClosure)(a),
+        (traits::VtableFnPointer)(a),
+        (traits::VtableParam)(a),
+        (traits::VtableBuiltin)(a),
+        (traits::VtableObject)(a),
+    } where N: TypeFoldable<'tcx>
 }
 
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        Normalized {
-            value: self.value.fold_with(folder),
-            obligations: self.obligations.fold_with(folder),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.value.visit_with(visitor) || self.obligations.visit_with(visitor)
-    }
+BraceStructTypeFoldableImpl! {
+    impl<'tcx, T> TypeFoldable<'tcx> for Normalized<'tcx, T> {
+        value,
+        obligations
+    } where T: TypeFoldable<'tcx>
 }
 
-impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        match *self {
-            super::ExprAssignable |
-            super::MatchExpressionArm { arm_span: _, source: _ } |
-            super::IfExpression |
-            super::IfExpressionWithNoElse |
-            super::MainFunctionType |
-            super::StartFunctionType |
-            super::IntrinsicType |
-            super::MethodReceiver |
-            super::MiscObligation |
-            super::SliceOrArrayElem |
-            super::TupleElem |
-            super::ItemObligation(_) |
-            super::AssignmentLhsSized |
-            super::TupleInitializerSized |
-            super::StructInitializerSized |
-            super::VariableType(_) |
-            super::ReturnType(_) |
-            super::SizedReturnType |
-            super::SizedYieldType |
-            super::ReturnNoExpression |
-            super::RepeatVec |
-            super::FieldSized(_) |
-            super::ConstSized |
-            super::SharedStatic |
-            super::BlockTailExpression(_) |
-            super::CompareImplMethodObligation { .. } => self.clone(),
-
-            super::ProjectionWf(proj) => super::ProjectionWf(proj.fold_with(folder)),
-            super::ReferenceOutlivesReferent(ty) => {
-                super::ReferenceOutlivesReferent(ty.fold_with(folder))
-            }
-            super::ObjectTypeBound(ty, r) => {
-                super::ObjectTypeBound(ty.fold_with(folder), r.fold_with(folder))
-            }
-            super::ObjectCastObligation(ty) => {
-                super::ObjectCastObligation(ty.fold_with(folder))
-            }
-            super::BuiltinDerivedObligation(ref cause) => {
-                super::BuiltinDerivedObligation(cause.fold_with(folder))
-            }
-            super::ImplDerivedObligation(ref cause) => {
-                super::ImplDerivedObligation(cause.fold_with(folder))
-            }
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        match *self {
-            super::ExprAssignable |
-            super::MatchExpressionArm { arm_span: _, source: _ } |
-            super::IfExpression |
-            super::IfExpressionWithNoElse |
-            super::MainFunctionType |
-            super::StartFunctionType |
-            super::IntrinsicType |
-            super::MethodReceiver |
-            super::MiscObligation |
-            super::SliceOrArrayElem |
-            super::TupleElem |
-            super::ItemObligation(_) |
-            super::AssignmentLhsSized |
-            super::TupleInitializerSized |
-            super::StructInitializerSized |
-            super::VariableType(_) |
-            super::ReturnType(_) |
-            super::SizedReturnType |
-            super::SizedYieldType |
-            super::ReturnNoExpression |
-            super::RepeatVec |
-            super::FieldSized(_) |
-            super::ConstSized |
-            super::SharedStatic |
-            super::BlockTailExpression(_) |
-            super::CompareImplMethodObligation { .. } => false,
-
-            super::ProjectionWf(proj) => proj.visit_with(visitor),
-            super::ReferenceOutlivesReferent(ty) => ty.visit_with(visitor),
-            super::ObjectTypeBound(ty, r) => ty.visit_with(visitor) || r.visit_with(visitor),
-            super::ObjectCastObligation(ty) => ty.visit_with(visitor),
-            super::BuiltinDerivedObligation(ref cause) => cause.visit_with(visitor),
-            super::ImplDerivedObligation(ref cause) => cause.visit_with(visitor)
-        }
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for traits::DerivedObligationCause<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        traits::DerivedObligationCause {
-            parent_trait_ref: self.parent_trait_ref.fold_with(folder),
-            parent_code: self.parent_code.fold_with(folder)
-        }
-    }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.parent_trait_ref.visit_with(visitor) || self.parent_code.visit_with(visitor)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCause<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        traits::ObligationCause {
-            span: self.span,
-            body_id: self.body_id,
-            code: self.code.fold_with(folder),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.code.visit_with(visitor)
-    }
-}
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index 4cc7406af72..8071cd0c639 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -49,6 +49,9 @@ use util::nodemap::FxHashSet;
 
 /// The TypeFoldable trait is implemented for every type that can be folded.
 /// Basically, every type that has a corresponding method in TypeFolder.
+///
+/// To implement this conveniently, use the
+/// `BraceStructTypeFoldableImpl` etc macros found in `macros.rs`.
 pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self;
     fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index bae1ce31a5e..0ca2769aa17 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -18,7 +18,6 @@ use middle::const_val::ConstVal;
 use traits::Reveal;
 use ty::subst::{UnpackedKind, Substs};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
-use ty::fold::{TypeVisitor, TypeFolder};
 use ty::error::{ExpectedFound, TypeError};
 use mir::interpret::{GlobalId, Value, PrimVal};
 use util::common::ErrorReported;
@@ -326,13 +325,9 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> {
 #[derive(Debug, Clone)]
 struct GeneratorWitness<'tcx>(&'tcx ty::Slice<Ty<'tcx>>);
 
-impl<'tcx> TypeFoldable<'tcx> for GeneratorWitness<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        GeneratorWitness(self.0.fold_with(folder))
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.0.visit_with(visitor)
+TupleStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for GeneratorWitness<'tcx> {
+        a
     }
 }
 
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 78fccaa1131..0627bcdfb0e 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -28,154 +28,38 @@ use std::rc::Rc;
 // For things that don't carry any arena-allocated data (and are
 // copy...), just add them to this list.
 
-macro_rules! CopyImpls {
-    ($($ty:ty,)+) => {
-        $(
-            impl<'tcx> Lift<'tcx> for $ty {
-                type Lifted = Self;
-                fn lift_to_tcx<'a, 'gcx>(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self> {
-                    Some(*self)
-                }
-            }
-
-            impl<'tcx> TypeFoldable<'tcx> for $ty {
-                fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> $ty {
-                    *self
-                }
-
-                fn super_visit_with<F: TypeVisitor<'tcx>>(&self, _: &mut F) -> bool {
-                    false
-                }
-            }
-        )+
-    }
-}
-
-CopyImpls! {
+CloneTypeFoldableAndLiftImpls! {
     (),
+    bool,
+    usize,
+    u64,
+    ::middle::region::Scope,
+    ::syntax::ast::FloatTy,
+    ::syntax::ast::NodeId,
+    ::syntax_pos::symbol::Symbol,
+    ::hir::def::Def,
+    ::hir::def_id::DefId,
+    ::hir::InlineAsm,
+    ::hir::MatchSource,
+    ::hir::Mutability,
     ::hir::Unsafety,
     ::syntax::abi::Abi,
-    ::hir::def_id::DefId,
     ::mir::Local,
     ::mir::Promoted,
     ::traits::Reveal,
+    ::ty::adjustment::AutoBorrowMutability,
+    ::ty::AdtKind,
+    // Including `BoundRegion` is a *bit* dubious, but direct
+    // references to bound region appear in `ty::Error`, and aren't
+    // really meant to be folded. In general, we can only fold a fully
+    // general `Region`.
+    ::ty::BoundRegion,
+    ::ty::ClosureKind,
+    ::ty::IntVarValue,
     ::syntax_pos::Span,
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// Macros
-//
-// When possible, use one of these (relatively) convenient macros to write
-// the impls for you.
-
-#[macro_export]
-macro_rules! BraceStructLiftImpl {
-    (impl<$($p:tt),*> Lift<$tcx:tt> for $s:path {
-        type Lifted = $lifted:ty;
-        $($field:ident),* $(,)*
-    } $(where $($wc:tt)*)*) => {
-        impl<$($p),*> $crate::ty::Lift<$tcx> for $s
-            $(where $($wc)*)*
-        {
-            type Lifted = $lifted;
-
-            fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<$lifted> {
-                $(let $field = tcx.lift(&self.$field)?;)*
-                Some(Self::Lifted { $($field),* })
-            }
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! EnumLiftImpl {
-    (impl<$($p:tt),*> Lift<$tcx:tt> for $s:path {
-        type Lifted = $lifted:ty;
-        $(
-            ($variant:path) ( $( $variant_arg:ident),* )
-        ),*
-        $(,)*
-    } $(where $($wc:tt)*)*) => {
-        impl<$($p),*> $crate::ty::Lift<$tcx> for $s
-            $(where $($wc)*)*
-        {
-            type Lifted = $lifted;
-
-            fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<$lifted> {
-                match self {
-                    $($variant ( $($variant_arg),* ) => {
-                        Some($variant ( $(tcx.lift($variant_arg)?),* ))
-                    })*
-                }
-            }
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! BraceStructTypeFoldableImpl {
-    (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
-        $($field:ident),* $(,)*
-    } $(where $($wc:tt)*)*) => {
-        impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s
-            $(where $($wc)*)*
-        {
-            fn super_fold_with<'gcx: $tcx, V: $crate::ty::fold::TypeFolder<'gcx, $tcx>>(
-                &self,
-                folder: &mut V,
-            ) -> Self {
-                let $s { $($field,)* } = self;
-                $s { $($field: $field.fold_with(folder),)* }
-            }
-
-            fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>(
-                &self,
-                visitor: &mut V,
-            ) -> bool {
-                let $s { $($field,)* } = self;
-                false $(|| $field.visit_with(visitor))*
-            }
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! EnumTypeFoldableImpl {
-    (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
-        $(
-            ($variant:path) ( $( $variant_arg:ident),* )
-        ),*
-        $(,)*
-    } $(where $($wc:tt)*)*) => {
-        impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s
-            $(where $($wc)*)*
-        {
-            fn super_fold_with<'gcx: $tcx, V: $crate::ty::fold::TypeFolder<'gcx, $tcx>>(
-                &self,
-                folder: &mut V,
-            ) -> Self {
-                match self {
-                    $($variant ( $($variant_arg),* ) => {
-                        $variant ( $($variant_arg.fold_with(folder)),* )
-                    })*
-                }
-            }
-
-            fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>(
-                &self,
-                visitor: &mut V,
-            ) -> bool {
-                match self {
-                    $($variant ( $($variant_arg),* ) => {
-                        false $(|| $variant_arg.visit_with(visitor))*
-                    })*
-                }
-            }
-        }
-    };
-}
-
-///////////////////////////////////////////////////////////////////////////
 // Lift implementations
 
 impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) {
@@ -776,6 +660,17 @@ BraceStructLiftImpl! {
 // can easily refactor the folding into the TypeFolder trait as
 // needed.
 
+/// AdtDefs are basically the same as a DefId.
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
+        *self
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
+        false
+    }
+}
+
 impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> (T, U) {
         (self.0.fold_with(folder), self.1.fold_with(folder))
@@ -786,14 +681,11 @@ impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T
     }
 }
 
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Option<T> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        self.as_ref().map(|t| t.fold_with(folder))
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.iter().any(|t| t.visit_with(visitor))
-    }
+EnumTypeFoldableImpl! {
+    impl<'tcx, T> TypeFoldable<'tcx> for Option<T> {
+        (Some)(a),
+        (None),
+    } where T: TypeFoldable<'tcx>
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
@@ -881,22 +773,11 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialPredicate<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self  {
-        use ty::ExistentialPredicate::*;
-        match *self {
-            Trait(ref tr) => Trait(tr.fold_with(folder)),
-            Projection(ref p) => Projection(p.fold_with(folder)),
-            AutoTrait(did) => AutoTrait(did),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        match *self {
-            ty::ExistentialPredicate::Trait(ref tr) => tr.visit_with(visitor),
-            ty::ExistentialPredicate::Projection(ref p) => p.visit_with(visitor),
-            ty::ExistentialPredicate::AutoTrait(_) => false,
-        }
+EnumTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialPredicate<'tcx> {
+        (ty::ExistentialPredicate::Trait)(a),
+        (ty::ExistentialPredicate::Projection)(a),
+        (ty::ExistentialPredicate::AutoTrait)(a),
     }
 }
 
@@ -1049,13 +930,9 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::TypeAndMut { ty: self.ty.fold_with(folder), mutbl: self.mutbl }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.ty.visit_with(visitor)
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
+        ty, mutbl
     }
 }
 
@@ -1065,20 +942,9 @@ BraceStructTypeFoldableImpl! {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        let inputs_and_output = self.inputs_and_output.fold_with(folder);
-        ty::FnSig {
-            inputs_and_output: folder.tcx().intern_type_list(&inputs_and_output),
-            variadic: self.variadic,
-            unsafety: self.unsafety,
-            abi: self.abi,
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.inputs().iter().any(|i| i.visit_with(visitor)) ||
-        self.output().visit_with(visitor)
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
+        inputs_and_output, variadic, unsafety, abi
     }
 }
 
@@ -1117,28 +983,15 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::ClosureSubsts {
-            substs: self.substs.fold_with(folder),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.substs.visit_with(visitor)
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
+        substs,
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::GeneratorInterior<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::GeneratorInterior {
-           witness: self.witness.fold_with(folder),
-           movable: self.movable,
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.witness.visit_with(visitor)
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ty::GeneratorInterior<'tcx> {
+        witness, movable,
     }
 }
 
@@ -1149,74 +1002,32 @@ BraceStructTypeFoldableImpl! {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        match *self {
-            ty::adjustment::Adjust::NeverToAny |
-            ty::adjustment::Adjust::ReifyFnPointer |
-            ty::adjustment::Adjust::UnsafeFnPointer |
-            ty::adjustment::Adjust::ClosureFnPointer |
-            ty::adjustment::Adjust::MutToConstPointer |
-            ty::adjustment::Adjust::Unsize => self.clone(),
-            ty::adjustment::Adjust::Deref(ref overloaded) => {
-                ty::adjustment::Adjust::Deref(overloaded.fold_with(folder))
-            }
-            ty::adjustment::Adjust::Borrow(ref autoref) => {
-                ty::adjustment::Adjust::Borrow(autoref.fold_with(folder))
-            }
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        match *self {
-            ty::adjustment::Adjust::NeverToAny |
-            ty::adjustment::Adjust::ReifyFnPointer |
-            ty::adjustment::Adjust::UnsafeFnPointer |
-            ty::adjustment::Adjust::ClosureFnPointer |
-            ty::adjustment::Adjust::MutToConstPointer |
-            ty::adjustment::Adjust::Unsize => false,
-            ty::adjustment::Adjust::Deref(ref overloaded) => {
-                overloaded.visit_with(visitor)
-            }
-            ty::adjustment::Adjust::Borrow(ref autoref) => {
-                autoref.visit_with(visitor)
-            }
-        }
+EnumTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> {
+        (ty::adjustment::Adjust::NeverToAny),
+        (ty::adjustment::Adjust::ReifyFnPointer),
+        (ty::adjustment::Adjust::UnsafeFnPointer),
+        (ty::adjustment::Adjust::ClosureFnPointer),
+        (ty::adjustment::Adjust::MutToConstPointer),
+        (ty::adjustment::Adjust::Unsize),
+        (ty::adjustment::Adjust::Deref)(a),
+        (ty::adjustment::Adjust::Borrow)(a),
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::OverloadedDeref<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::adjustment::OverloadedDeref {
-            region: self.region.fold_with(folder),
-            mutbl: self.mutbl,
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.region.visit_with(visitor)
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::OverloadedDeref<'tcx> {
+        region, mutbl,
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        match *self {
-            ty::adjustment::AutoBorrow::Ref(ref r, m) => {
-                ty::adjustment::AutoBorrow::Ref(r.fold_with(folder), m)
-            }
-            ty::adjustment::AutoBorrow::RawPtr(m) => ty::adjustment::AutoBorrow::RawPtr(m)
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        match *self {
-            ty::adjustment::AutoBorrow::Ref(r, _m) => r.visit_with(visitor),
-            ty::adjustment::AutoBorrow::RawPtr(_m) => false,
-        }
+EnumTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> {
+        (ty::adjustment::AutoBorrow::Ref)(a, b),
+        (ty::adjustment::AutoBorrow::RawPtr)(m),
     }
 }
 
-
 BraceStructTypeFoldableImpl! {
     impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
         parent, predicates
@@ -1234,43 +1045,17 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<ty::Predicate<'tcx>> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        match *self {
-            ty::Predicate::Trait(ref a) =>
-                ty::Predicate::Trait(a.fold_with(folder)),
-            ty::Predicate::Subtype(ref binder) =>
-                ty::Predicate::Subtype(binder.fold_with(folder)),
-            ty::Predicate::RegionOutlives(ref binder) =>
-                ty::Predicate::RegionOutlives(binder.fold_with(folder)),
-            ty::Predicate::TypeOutlives(ref binder) =>
-                ty::Predicate::TypeOutlives(binder.fold_with(folder)),
-            ty::Predicate::Projection(ref binder) =>
-                ty::Predicate::Projection(binder.fold_with(folder)),
-            ty::Predicate::WellFormed(data) =>
-                ty::Predicate::WellFormed(data.fold_with(folder)),
-            ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) =>
-                ty::Predicate::ClosureKind(closure_def_id, closure_substs.fold_with(folder), kind),
-            ty::Predicate::ObjectSafe(trait_def_id) =>
-                ty::Predicate::ObjectSafe(trait_def_id),
-            ty::Predicate::ConstEvaluatable(def_id, substs) =>
-                ty::Predicate::ConstEvaluatable(def_id, substs.fold_with(folder)),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        match *self {
-            ty::Predicate::Trait(ref a) => a.visit_with(visitor),
-            ty::Predicate::Subtype(ref binder) => binder.visit_with(visitor),
-            ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor),
-            ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor),
-            ty::Predicate::Projection(ref binder) => binder.visit_with(visitor),
-            ty::Predicate::WellFormed(data) => data.visit_with(visitor),
-            ty::Predicate::ClosureKind(_closure_def_id, closure_substs, _kind) =>
-                closure_substs.visit_with(visitor),
-            ty::Predicate::ObjectSafe(_trait_def_id) => false,
-            ty::Predicate::ConstEvaluatable(_def_id, substs) => substs.visit_with(visitor),
-        }
+EnumTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
+        (ty::Predicate::Trait)(a),
+        (ty::Predicate::Subtype)(a),
+        (ty::Predicate::RegionOutlives)(a),
+        (ty::Predicate::TypeOutlives)(a),
+        (ty::Predicate::Projection)(a),
+        (ty::Predicate::WellFormed)(a),
+        (ty::Predicate::ClosureKind)(a, b, c),
+        (ty::Predicate::ObjectSafe)(a),
+        (ty::Predicate::ConstEvaluatable)(a, b),
     }
 }
 
@@ -1298,71 +1083,40 @@ BraceStructTypeFoldableImpl! {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::SubtypePredicate {
-            a_is_expected: self.a_is_expected,
-            a: self.a.fold_with(folder),
-            b: self.b.fold_with(folder)
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.a.visit_with(visitor) || self.b.visit_with(visitor)
-    }
+BraceStructTypeFoldableImpl! {
+    impl<'tcx, T> TypeFoldable<'tcx> for ty::ParamEnvAnd<'tcx, T> {
+        param_env, value
+    } where T: TypeFoldable<'tcx>
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::TraitPredicate {
-            trait_ref: self.trait_ref.fold_with(folder)
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.trait_ref.visit_with(visitor)
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> {
+        a_is_expected, a, b
     }
 }
 
-impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate<T,U>
-    where T : TypeFoldable<'tcx>,
-          U : TypeFoldable<'tcx>,
-{
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::OutlivesPredicate(self.0.fold_with(folder),
-                              self.1.fold_with(folder))
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.0.visit_with(visitor) || self.1.visit_with(visitor)
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> {
+        trait_ref
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::ClosureUpvar {
-            def: self.def,
-            span: self.span,
-            ty: self.ty.fold_with(folder),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.ty.visit_with(visitor)
-    }
+TupleStructTypeFoldableImpl! {
+    impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate<T,U> {
+        a, b
+    } where T : TypeFoldable<'tcx>, U : TypeFoldable<'tcx>,
 }
 
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound<T> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::error::ExpectedFound {
-            expected: self.expected.fold_with(folder),
-            found: self.found.fold_with(folder),
-        }
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> {
+        def, span, ty
     }
+}
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.expected.visit_with(visitor) || self.found.visit_with(visitor)
-    }
+BraceStructTypeFoldableImpl! {
+    impl<'tcx, T> TypeFoldable<'tcx> for ty::error::ExpectedFound<T> {
+        expected, found
+    } where T: TypeFoldable<'tcx>
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> {
@@ -1375,69 +1129,28 @@ impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T>
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        use ty::error::TypeError::*;
-
-        match *self {
-            Mismatch => Mismatch,
-            UnsafetyMismatch(x) => UnsafetyMismatch(x.fold_with(folder)),
-            AbiMismatch(x) => AbiMismatch(x.fold_with(folder)),
-            Mutability => Mutability,
-            TupleSize(x) => TupleSize(x),
-            FixedArraySize(x) => FixedArraySize(x),
-            ArgCount => ArgCount,
-            RegionsDoesNotOutlive(a, b) => {
-                RegionsDoesNotOutlive(a.fold_with(folder), b.fold_with(folder))
-            },
-            RegionsInsufficientlyPolymorphic(a, b) => {
-                RegionsInsufficientlyPolymorphic(a, b.fold_with(folder))
-            },
-            RegionsOverlyPolymorphic(a, b) => {
-                RegionsOverlyPolymorphic(a, b.fold_with(folder))
-            },
-            IntMismatch(x) => IntMismatch(x),
-            FloatMismatch(x) => FloatMismatch(x),
-            Traits(x) => Traits(x),
-            VariadicMismatch(x) => VariadicMismatch(x),
-            CyclicTy(t) => CyclicTy(t.fold_with(folder)),
-            ProjectionMismatched(x) => ProjectionMismatched(x),
-            ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
-            Sorts(x) => Sorts(x.fold_with(folder)),
-            ExistentialMismatch(x) => ExistentialMismatch(x.fold_with(folder)),
-            OldStyleLUB(ref x) => OldStyleLUB(x.fold_with(folder)),
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        use ty::error::TypeError::*;
-
-        match *self {
-            UnsafetyMismatch(x) => x.visit_with(visitor),
-            AbiMismatch(x) => x.visit_with(visitor),
-            RegionsDoesNotOutlive(a, b) => {
-                a.visit_with(visitor) || b.visit_with(visitor)
-            },
-            RegionsInsufficientlyPolymorphic(_, b) |
-            RegionsOverlyPolymorphic(_, b) => {
-                b.visit_with(visitor)
-            },
-            Sorts(x) => x.visit_with(visitor),
-            OldStyleLUB(ref x) => x.visit_with(visitor),
-            ExistentialMismatch(x) => x.visit_with(visitor),
-            CyclicTy(t) => t.visit_with(visitor),
-            Mismatch |
-            Mutability |
-            TupleSize(_) |
-            FixedArraySize(_) |
-            ArgCount |
-            IntMismatch(_) |
-            FloatMismatch(_) |
-            Traits(_) |
-            VariadicMismatch(_) |
-            ProjectionMismatched(_) |
-            ProjectionBoundsLength(_) => false,
-        }
+EnumTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
+        (ty::error::TypeError::Mismatch),
+        (ty::error::TypeError::UnsafetyMismatch)(x),
+        (ty::error::TypeError::AbiMismatch)(x),
+        (ty::error::TypeError::Mutability),
+        (ty::error::TypeError::TupleSize)(x),
+        (ty::error::TypeError::FixedArraySize)(x),
+        (ty::error::TypeError::ArgCount),
+        (ty::error::TypeError::RegionsDoesNotOutlive)(a, b),
+        (ty::error::TypeError::RegionsInsufficientlyPolymorphic)(a, b),
+        (ty::error::TypeError::RegionsOverlyPolymorphic)(a, b),
+        (ty::error::TypeError::IntMismatch)(x),
+        (ty::error::TypeError::FloatMismatch)(x),
+        (ty::error::TypeError::Traits)(x),
+        (ty::error::TypeError::VariadicMismatch)(x),
+        (ty::error::TypeError::CyclicTy)(t),
+        (ty::error::TypeError::ProjectionMismatched)(x),
+        (ty::error::TypeError::ProjectionBoundsLength)(x),
+        (ty::error::TypeError::Sorts)(x),
+        (ty::error::TypeError::ExistentialMismatch)(x),
+        (ty::error::TypeError::OldStyleLUB)(x),
     }
 }