Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision eada3cfc526a731d1ac85003f73c04f68d7ae037)
+++ src/GenPoly/Box.cc	(revision d67cdb749954789d84d7a8bbabc0ec601347a7bb)
@@ -32,5 +32,4 @@
 #include "Common/UniqueName.h"           // for UniqueName
 #include "Common/utility.h"              // for toString
-#include "DeclMutator.h"                 // for DeclMutator
 #include "FindFunction.h"                // for findFunction, findAndReplace...
 #include "GenPoly/ErasableScopedMap.h"   // for ErasableScopedMap<>::const_i...
@@ -39,5 +38,4 @@
 #include "Lvalue.h"                      // for generalizedLvalue
 #include "Parser/LinkageSpec.h"          // for C, Spec, Cforall, Intrinsic
-#include "PolyMutator.h"                 // for PolyMutator
 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass
 #include "ResolvExpr/typeops.h"          // for typesCompatible
@@ -62,35 +60,37 @@
 		FunctionType *makeAdapterType( FunctionType *adaptee, const TyVarMap &tyVars );
 
+		class BoxPass {
+		protected:
+			BoxPass() : scopeTyVars( TypeDecl::Data{} ) {}
+			TyVarMap scopeTyVars;
+		};
+
 		/// Adds layout-generation functions to polymorphic types
-		class LayoutFunctionBuilder final : public DeclMutator {
-			unsigned int functionNesting;  // current level of nested functions
+		class LayoutFunctionBuilder final : public WithDeclsToAdd, public WithVisitorRef<LayoutFunctionBuilder>, public WithShortCircuiting {
+			unsigned int functionNesting = 0;  // current level of nested functions
 		public:
-			LayoutFunctionBuilder() : functionNesting( 0 ) {}
-
-			using DeclMutator::mutate;
-			virtual DeclarationWithType *mutate( FunctionDecl *functionDecl ) override;
-			virtual Declaration *mutate( StructDecl *structDecl ) override;
-			virtual Declaration *mutate( UnionDecl *unionDecl ) override;
+			void previsit( FunctionDecl *functionDecl );
+			void previsit( StructDecl *structDecl );
+			void previsit( UnionDecl *unionDecl );
 		};
 
 		/// Replaces polymorphic return types with out-parameters, replaces calls to polymorphic functions with adapter calls as needed, and adds appropriate type variables to the function call
-		class Pass1 final : public PolyMutator {
+		class Pass1 final : public BoxPass, public WithTypeSubstitution, public WithStmtsToAdd, public WithGuards, public WithVisitorRef<Pass1>, public WithShortCircuiting {
 		  public:
 			Pass1();
 
-			using PolyMutator::mutate;
-			virtual Expression *mutate( ApplicationExpr *appExpr ) override;
-			virtual Expression *mutate( AddressExpr *addrExpr ) override;
-			virtual Expression *mutate( UntypedExpr *expr ) override;
-			virtual DeclarationWithType* mutate( FunctionDecl *functionDecl ) override;
-			virtual TypeDecl *mutate( TypeDecl *typeDecl ) override;
-			virtual Expression *mutate( CommaExpr *commaExpr ) override;
-			virtual Expression *mutate( ConditionalExpr *condExpr ) override;
-			virtual Statement * mutate( ReturnStmt *returnStmt ) override;
-			virtual Type *mutate( PointerType *pointerType ) override;
-			virtual Type * mutate( FunctionType *functionType ) override;
-
-			virtual void doBeginScope() override;
-			virtual void doEndScope() override;
+			void premutate( FunctionDecl * functionDecl );
+			void premutate( TypeDecl * typeDecl );
+			void premutate( CommaExpr * commaExpr );
+			Expression * postmutate( ApplicationExpr * appExpr );
+			Expression * postmutate( UntypedExpr *expr );
+			void premutate( AddressExpr * addrExpr );
+			Expression * postmutate( AddressExpr * addrExpr );
+			void premutate( ReturnStmt * returnStmt );
+			void premutate( PointerType * pointerType );
+			void premutate( FunctionType * functionType );
+
+			void beginScope();
+			void endScope();
 		  private:
 			/// Pass the extra type parameters from polymorphic generic arguments or return types into a function application
@@ -129,22 +129,14 @@
 		/// * Moves polymorphic returns in function types to pointer-type parameters
 		/// * adds type size and assertion parameters to parameter lists
-		class Pass2 final : public PolyMutator {
-		  public:
-			template< typename DeclClass >
-			DeclClass *handleDecl( DeclClass *decl );
-			template< typename AggDecl >
-			AggDecl * handleAggDecl( AggDecl * aggDecl );
-
-			typedef PolyMutator Parent;
-			using Parent::mutate;
-			virtual DeclarationWithType *mutate( FunctionDecl *functionDecl ) override;
-			virtual ObjectDecl *mutate( ObjectDecl *objectDecl ) override;
-			virtual StructDecl *mutate( StructDecl *structDecl ) override;
-			virtual UnionDecl *mutate( UnionDecl *unionDecl ) override;
-			virtual TraitDecl *mutate( TraitDecl *unionDecl ) override;
-			virtual TypeDecl *mutate( TypeDecl *typeDecl ) override;
-			virtual TypedefDecl *mutate( TypedefDecl *typedefDecl ) override;
-			virtual Type *mutate( PointerType *pointerType ) override;
-			virtual Type *mutate( FunctionType *funcType ) override;
+		struct Pass2 final : public BoxPass, public WithGuards {
+			void handleAggDecl();
+
+			DeclarationWithType * postmutate( FunctionDecl *functionDecl );
+			void premutate( StructDecl *structDecl );
+			void premutate( UnionDecl *unionDecl );
+			void premutate( TraitDecl *unionDecl );
+			void premutate( TypeDecl *typeDecl );
+			void premutate( PointerType *pointerType );
+			void premutate( FunctionType *funcType );
 
 		  private:
@@ -158,5 +150,5 @@
 		/// * Calculates polymorphic offsetof expressions from offset array
 		/// * Inserts dynamic calculation of polymorphic type layouts where needed
-		class PolyGenericCalculator final : public WithGuards, public WithVisitorRef<PolyGenericCalculator>, public WithStmtsToAdd, public WithDeclsToAdd, public WithTypeSubstitution {
+		class PolyGenericCalculator final : public BoxPass, public WithGuards, public WithVisitorRef<PolyGenericCalculator>, public WithStmtsToAdd, public WithDeclsToAdd, public WithTypeSubstitution {
 		public:
 			PolyGenericCalculator();
@@ -197,23 +189,19 @@
 			ScopedSet< std::string > knownOffsets;          ///< Set of non-generic types for which the offset array exists in the current scope, indexed by offsetofName
 			UniqueName bufNamer;                           ///< Namer for VLA buffers
-			TyVarMap scopeTyVars;
 		};
 
 		/// Replaces initialization of polymorphic values with alloca, declaration of dtype/ftype with appropriate void expression, sizeof expressions of polymorphic types with the proper variable, and strips fields from generic struct declarations.
-		class Pass3 final : public PolyMutator {
-		  public:
+		struct Pass3 final : public BoxPass, public WithGuards {
 			template< typename DeclClass >
-			DeclClass *handleDecl( DeclClass *decl, Type *type );
-
-			using PolyMutator::mutate;
-			virtual DeclarationWithType *mutate( FunctionDecl *functionDecl ) override;
-			virtual Declaration *mutate( StructDecl *structDecl ) override;
-			virtual Declaration *mutate( UnionDecl *unionDecl ) override;
-			virtual ObjectDecl *mutate( ObjectDecl *objectDecl ) override;
-			virtual TypedefDecl *mutate( TypedefDecl *objectDecl ) override;
-			virtual TypeDecl *mutate( TypeDecl *objectDecl ) override;
-			virtual Type *mutate( PointerType *pointerType ) override;
-			virtual Type *mutate( FunctionType *funcType ) override;
-		  private:
+			void handleDecl( DeclClass * decl, Type * type );
+
+			void premutate( ObjectDecl * objectDecl );
+			void premutate( FunctionDecl * functionDecl );
+			void premutate( TypedefDecl * typedefDecl );
+			void premutate( StructDecl * structDecl );
+			void premutate( UnionDecl * unionDecl );
+			void premutate( TypeDecl * typeDecl );
+			void premutate( PointerType * pointerType );
+			void premutate( FunctionType * funcType );
 		};
 	} // anonymous namespace
@@ -247,25 +235,25 @@
 
 	void box( std::list< Declaration *>& translationUnit ) {
-		LayoutFunctionBuilder layoutBuilder;
-		Pass1 pass1;
-		Pass2 pass2;
+		PassVisitor<LayoutFunctionBuilder> layoutBuilder;
+		PassVisitor<Pass1> pass1;
+		PassVisitor<Pass2> pass2;
 		PassVisitor<PolyGenericCalculator> polyCalculator;
-		Pass3 pass3;
-
-		layoutBuilder.mutateDeclarationList( translationUnit );
-		mutateTranslationUnit/*All*/( translationUnit, pass1 );
-		mutateTranslationUnit/*All*/( translationUnit, pass2 );
+		PassVisitor<Pass3> pass3;
+
+		acceptAll( translationUnit, layoutBuilder );
+		mutateAll( translationUnit, pass1 );
+		mutateAll( translationUnit, pass2 );
 		mutateAll( translationUnit, polyCalculator );
-		mutateTranslationUnit/*All*/( translationUnit, pass3 );
+		mutateAll( translationUnit, pass3 );
 	}
 
 	////////////////////////////////// LayoutFunctionBuilder ////////////////////////////////////////////
 
-	DeclarationWithType *LayoutFunctionBuilder::mutate( FunctionDecl *functionDecl ) {
-		functionDecl->set_functionType( maybeMutate( functionDecl->get_functionType(), *this ) );
+	void LayoutFunctionBuilder::previsit( FunctionDecl *functionDecl ) {
+		visit_children = false;
+		maybeAccept( functionDecl->get_functionType(), *visitor );
 		++functionNesting;
-		functionDecl->set_statements( maybeMutate( functionDecl->get_statements(), *this ) );
+		maybeAccept( functionDecl->get_statements(), *visitor );
 		--functionNesting;
-		return functionDecl;
 	}
 
@@ -356,11 +344,12 @@
 	}
 
-	Declaration *LayoutFunctionBuilder::mutate( StructDecl *structDecl ) {
+	void LayoutFunctionBuilder::previsit( StructDecl *structDecl ) {
 		// do not generate layout function for "empty" tag structs
-		if ( structDecl->get_members().empty() ) return structDecl;
+		visit_children = false;
+		if ( structDecl->get_members().empty() ) return;
 
 		// get parameters that can change layout, exiting early if none
 		std::list< TypeDecl* > otypeParams = takeOtypeOnly( structDecl->get_parameters() );
-		if ( otypeParams.empty() ) return structDecl;
+		if ( otypeParams.empty() ) return;
 
 		// build layout function signature
@@ -413,15 +402,15 @@
 		addStmt( layoutDecl->get_statements(), makeAlignTo( derefVar( sizeParam ), derefVar( alignParam ) ) );
 
-		addDeclarationAfter( layoutDecl );
-		return structDecl;
+		declsToAddAfter.push_back( layoutDecl );
 	}
 
-	Declaration *LayoutFunctionBuilder::mutate( UnionDecl *unionDecl ) {
+	void LayoutFunctionBuilder::previsit( UnionDecl *unionDecl ) {
 		// do not generate layout function for "empty" tag unions
-		if ( unionDecl->get_members().empty() ) return unionDecl;
+		visit_children = false;
+		if ( unionDecl->get_members().empty() ) return;
 
 		// get parameters that can change layout, exiting early if none
 		std::list< TypeDecl* > otypeParams = takeOtypeOnly( unionDecl->get_parameters() );
-		if ( otypeParams.empty() ) return unionDecl;
+		if ( otypeParams.empty() ) return;
 
 		// build layout function signature
@@ -456,6 +445,5 @@
 		addStmt( layoutDecl->get_statements(), makeAlignTo( derefVar( sizeParam ), derefVar( alignParam ) ) );
 
-		addDeclarationAfter( layoutDecl );
-		return unionDecl;
+		declsToAddAfter.push_back( layoutDecl );
 	}
 
@@ -501,31 +489,29 @@
 		Pass1::Pass1() : tempNamer( "_temp" ) {}
 
-		DeclarationWithType *Pass1::mutate( FunctionDecl *functionDecl ) {
+		void Pass1::premutate( FunctionDecl *functionDecl ) {
 			if ( functionDecl->get_statements() ) {		// empty routine body ?
 				// std::cerr << "mutating function: " << functionDecl->get_mangleName() << std::endl;
-				doBeginScope();
-				scopeTyVars.beginScope();
-
-				DeclarationWithType *oldRetval = retval;
+				GuardScope( scopeTyVars );
+				GuardValue( retval );
 
 				// process polymorphic return value
 				retval = nullptr;
-				if ( isDynRet( functionDecl->get_functionType() ) && functionDecl->get_linkage() != LinkageSpec::C ) {
-					retval = functionDecl->get_functionType()->get_returnVals().front();
+				FunctionType *functionType = functionDecl->type;
+				if ( isDynRet( functionType ) && functionDecl->linkage != LinkageSpec::C ) {
+					retval = functionType->returnVals.front();
 
 					// give names to unnamed return values
-					if ( retval->get_name() == "" ) {
-						retval->set_name( "_retparm" );
-						retval->set_linkage( LinkageSpec::C );
+					if ( retval->name == "" ) {
+						retval->name = "_retparm";
+						retval->linkage = LinkageSpec::C;
 					} // if
 				} // if
 
-				FunctionType *functionType = functionDecl->get_functionType();
-				makeTyVarMap( functionDecl->get_functionType(), scopeTyVars );
-
-				std::list< DeclarationWithType *> &paramList = functionType->get_parameters();
+				makeTyVarMap( functionType, scopeTyVars );
+
+				std::list< DeclarationWithType *> &paramList = functionType->parameters;
 				std::list< FunctionType *> functions;
-				for ( Type::ForallList::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) {
-					for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->get_assertions().begin(); assert != (*tyVar)->get_assertions().end(); ++assert ) {
+				for ( Type::ForallList::iterator tyVar = functionType->forall.begin(); tyVar != functionType->forall.end(); ++tyVar ) {
+					for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->assertions.begin(); assert != (*tyVar)->assertions.end(); ++assert ) {
 						findFunction( (*assert)->get_type(), functions, scopeTyVars, needsAdapter );
 					} // for
@@ -542,21 +528,13 @@
 					} // if
 				} // for
-
-				functionDecl->set_statements( functionDecl->get_statements()->acceptMutator( *this ) );
-
-				scopeTyVars.endScope();
-				retval = oldRetval;
-				doEndScope();
 				// std::cerr << "end function: " << functionDecl->get_mangleName() << std::endl;
 			} // if
-			return functionDecl;
-		}
-
-		TypeDecl *Pass1::mutate( TypeDecl *typeDecl ) {
+		}
+
+		void Pass1::premutate( TypeDecl *typeDecl ) {
 			addToTyVarMap( typeDecl, scopeTyVars );
-			return dynamic_cast<TypeDecl*>( Mutator::mutate( typeDecl ) );
-		}
-
-		Expression *Pass1::mutate( CommaExpr *commaExpr ) {
+		}
+
+		void Pass1::premutate( CommaExpr *commaExpr ) {
 			// Attempting to find application expressions that were mutated by the copy constructor passes
 			// to use an explicit return variable, so that the variable can be reused as a parameter to the
@@ -574,16 +552,4 @@
 				}
 			}
-
-			commaExpr->set_arg1( maybeMutate( commaExpr->get_arg1(), *this ) );
-			commaExpr->set_arg2( maybeMutate( commaExpr->get_arg2(), *this ) );
-			return commaExpr;
-		}
-
-		Expression *Pass1::mutate( ConditionalExpr *condExpr ) {
-			condExpr->set_arg1( maybeMutate( condExpr->get_arg1(), *this ) );
-			condExpr->set_arg2( maybeMutate( condExpr->get_arg2(), *this ) );
-			condExpr->set_arg3( maybeMutate( condExpr->get_arg3(), *this ) );
-			return condExpr;
-
 		}
 
@@ -659,5 +625,5 @@
 		ObjectDecl *Pass1::makeTemporary( Type *type ) {
 			ObjectDecl *newObj = new ObjectDecl( tempNamer.newName(), Type::StorageClasses(), LinkageSpec::C, 0, type, 0 );
-			stmtsToAdd.push_back( new DeclStmt( noLabels, newObj ) );
+			stmtsToAddBefore.push_back( new DeclStmt( noLabels, newObj ) );
 			return newObj;
 		}
@@ -775,9 +741,9 @@
 					ObjectDecl *newObj = new ObjectDecl( tempNamer.newName(), Type::StorageClasses(), LinkageSpec::C, 0, newType, 0 );
 					newObj->get_type()->get_qualifiers() = Type::Qualifiers(); // TODO: is this right???
-					stmtsToAdd.push_back( new DeclStmt( noLabels, newObj ) );
+					stmtsToAddBefore.push_back( new DeclStmt( noLabels, newObj ) );
 					UntypedExpr *assign = new UntypedExpr( new NameExpr( "?=?" ) ); // TODO: why doesn't this just use initialization syntax?
 					assign->get_args().push_back( new VariableExpr( newObj ) );
 					assign->get_args().push_back( arg );
-					stmtsToAdd.push_back( new ExprStmt( noLabels, assign ) );
+					stmtsToAddBefore.push_back( new ExprStmt( noLabels, assign ) );
 					arg = new AddressExpr( new VariableExpr( newObj ) );
 				} // if
@@ -961,5 +927,5 @@
 						std::pair< AdapterIter, bool > answer = adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, newAdapter ) );
 						adapter = answer.first;
-						stmtsToAdd.push_back( new DeclStmt( noLabels, newAdapter ) );
+						stmtsToAddBefore.push_back( new DeclStmt( noLabels, newAdapter ) );
 					} // if
 					assert( adapter != adapters.end() );
@@ -1118,5 +1084,5 @@
 		}
 
-		Expression *Pass1::mutate( ApplicationExpr *appExpr ) {
+		Expression *Pass1::postmutate( ApplicationExpr *appExpr ) {
 			// std::cerr << "mutate appExpr: " << InitTweak::getFunctionName( appExpr ) << std::endl;
 			// for ( TyVarMap::iterator i = scopeTyVars.begin(); i != scopeTyVars.end(); ++i ) {
@@ -1124,10 +1090,8 @@
 			// }
 			// std::cerr << "\n";
-			appExpr->get_function()->acceptMutator( *this );
-			mutateAll( appExpr->get_args(), *this );
-
-			assert( appExpr->get_function()->has_result() );
-			FunctionType * function = getFunctionType( appExpr->get_function()->get_result() );
-			assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->get_function()->get_result() ).c_str() );
+
+			assert( appExpr->function->result );
+			FunctionType * function = getFunctionType( appExpr->function->result );
+			assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->function->result ).c_str() );
 
 			if ( Expression *newExpr = handleIntrinsics( appExpr ) ) {
@@ -1182,19 +1146,20 @@
 		}
 
-		Expression *Pass1::mutate( UntypedExpr *expr ) {
-			if ( expr->has_result() && isPolyType( expr->get_result(), scopeTyVars, env ) ) {
-				if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->get_function() ) ) {
+		Expression * Pass1::postmutate( UntypedExpr *expr ) {
+			if ( expr->result && isPolyType( expr->result, scopeTyVars, env ) ) {
+				if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->function ) ) {
 					if ( name->get_name() == "*?" ) {
-						Expression *ret = expr->get_args().front();
-						expr->get_args().clear();
+						Expression *ret = expr->args.front();
+						expr->args.clear();
 						delete expr;
-						return ret->acceptMutator( *this );
+						return ret;
 					} // if
 				} // if
 			} // if
-			return PolyMutator::mutate( expr );
-		}
-
-		Expression *Pass1::mutate( AddressExpr *addrExpr ) {
+			return expr;
+		}
+
+		void Pass1::premutate( AddressExpr * ) { visit_children = false; }
+		Expression * Pass1::postmutate( AddressExpr * addrExpr ) {
 			assert( addrExpr->get_arg()->has_result() && ! addrExpr->get_arg()->get_result()->isVoid() );
 
@@ -1216,5 +1181,5 @@
 			// isPolyType check needs to happen before mutating addrExpr arg, so pull it forward
 			// out of the if condition.
-			addrExpr->set_arg( mutateExpression( addrExpr->get_arg() ) );
+			addrExpr->arg = addrExpr->get_arg()->acceptMutator( *visitor );
 			// ... but must happen after mutate, since argument might change (e.g. intrinsic *?, ?[?]) - re-evaluate above comment
 			bool polytype = isPolyType( addrExpr->get_arg()->get_result(), scopeTyVars, env );
@@ -1231,40 +1196,27 @@
 		}
 
-		Statement * Pass1::mutate( ReturnStmt *returnStmt ) {
-			if ( retval && returnStmt->get_expr() ) {
-				assert( returnStmt->get_expr()->has_result() && ! returnStmt->get_expr()->get_result()->isVoid() );
-				delete returnStmt->get_expr();
-				returnStmt->set_expr( 0 );
-			} else {
-				returnStmt->set_expr( mutateExpression( returnStmt->get_expr() ) );
+		void Pass1::premutate( ReturnStmt *returnStmt ) {
+			if ( retval && returnStmt->expr ) {
+				assert( returnStmt->expr->result && ! returnStmt->expr->result->isVoid() );
+				delete returnStmt->expr;
+				returnStmt->expr = nullptr;
 			} // if
-			return returnStmt;
-		}
-
-		Type * Pass1::mutate( PointerType *pointerType ) {
-			scopeTyVars.beginScope();
+		}
+
+		void Pass1::premutate( PointerType *pointerType ) {
+			GuardScope( scopeTyVars );
 			makeTyVarMap( pointerType, scopeTyVars );
-
-			Type *ret = Mutator::mutate( pointerType );
-
-			scopeTyVars.endScope();
-			return ret;
-		}
-
-		Type * Pass1::mutate( FunctionType *functionType ) {
-			scopeTyVars.beginScope();
+		}
+
+		void Pass1::premutate( FunctionType *functionType ) {
+			GuardScope( scopeTyVars );
 			makeTyVarMap( functionType, scopeTyVars );
-
-			Type *ret = Mutator::mutate( functionType );
-
-			scopeTyVars.endScope();
-			return ret;
-		}
-
-		void Pass1::doBeginScope() {
+		}
+
+		void Pass1::beginScope() {
 			adapters.beginScope();
 		}
 
-		void Pass1::doEndScope() {
+		void Pass1::endScope() {
 			adapters.endScope();
 		}
@@ -1293,13 +1245,5 @@
 		}
 
-		template< typename DeclClass >
-		DeclClass * Pass2::handleDecl( DeclClass *decl ) {
-			DeclClass *ret = static_cast< DeclClass *>( Parent::mutate( decl ) );
-
-			return ret;
-		}
-
-		DeclarationWithType * Pass2::mutate( FunctionDecl *functionDecl ) {
-			functionDecl = strict_dynamic_cast< FunctionDecl * > ( handleDecl( functionDecl ) );
+		DeclarationWithType * Pass2::postmutate( FunctionDecl *functionDecl ) {
 			FunctionType * ftype = functionDecl->get_functionType();
 			if ( ! ftype->get_returnVals().empty() && functionDecl->get_statements() ) {
@@ -1325,55 +1269,30 @@
 		}
 
-		ObjectDecl * Pass2::mutate( ObjectDecl *objectDecl ) {
-			return handleDecl( objectDecl );
-		}
-
-		template< typename AggDecl >
-		AggDecl * Pass2::handleAggDecl( AggDecl * aggDecl ) {
+		void Pass2::premutate( StructDecl * ) {
 			// prevent tyVars from leaking into containing scope
-			scopeTyVars.beginScope();
-			Parent::mutate( aggDecl );
-			scopeTyVars.endScope();
-			return aggDecl;
-		}
-
-		StructDecl * Pass2::mutate( StructDecl *aggDecl ) {
-			return handleAggDecl( aggDecl );
-		}
-
-		UnionDecl * Pass2::mutate( UnionDecl *aggDecl ) {
-			return handleAggDecl( aggDecl );
-		}
-
-		TraitDecl * Pass2::mutate( TraitDecl *aggDecl ) {
-			return handleAggDecl( aggDecl );
-		}
-
-		TypeDecl * Pass2::mutate( TypeDecl *typeDecl ) {
+			GuardScope( scopeTyVars );
+		}
+
+		void Pass2::premutate( UnionDecl * ) {
+			// prevent tyVars from leaking into containing scope
+			GuardScope( scopeTyVars );
+		}
+
+		void Pass2::premutate( TraitDecl * ) {
+			// prevent tyVars from leaking into containing scope
+			GuardScope( scopeTyVars );
+		}
+
+		void Pass2::premutate( TypeDecl *typeDecl ) {
 			addToTyVarMap( typeDecl, scopeTyVars );
-			if ( typeDecl->get_base() ) {
-				return handleDecl( typeDecl );
-			} else {
-				return dynamic_cast<TypeDecl*>( Parent::mutate( typeDecl ) );
-			}
-		}
-
-		TypedefDecl * Pass2::mutate( TypedefDecl *typedefDecl ) {
-			return handleDecl( typedefDecl );
-		}
-
-		Type * Pass2::mutate( PointerType *pointerType ) {
-			scopeTyVars.beginScope();
+		}
+
+		void Pass2::premutate( PointerType *pointerType ) {
+			GuardScope( scopeTyVars );
 			makeTyVarMap( pointerType, scopeTyVars );
-
-			Type *ret = Parent::mutate( pointerType );
-
-			scopeTyVars.endScope();
-			return ret;
-		}
-
-		Type *Pass2::mutate( FunctionType *funcType ) {
-			scopeTyVars.beginScope();
-
+		}
+
+		void Pass2::premutate( FunctionType *funcType ) {
+			GuardScope( scopeTyVars );
 			makeTyVarMap( funcType, scopeTyVars );
 
@@ -1414,5 +1333,4 @@
 				// move all assertions into parameter list
 				for ( std::list< DeclarationWithType *>::iterator assert = (*tyParm)->get_assertions().begin(); assert != (*tyParm)->get_assertions().end(); ++assert ) {
-//      *assert = (*assert)->acceptMutator( *this );
 					// assertion parameters may not be used in body, pass along with unused attribute.
 					(*assert)->get_attributes().push_back( new Attribute( "unused" ) );
@@ -1450,5 +1368,4 @@
 						}
 					}
-
 					seenTypes.insert( typeName );
 				}
@@ -1458,9 +1375,4 @@
 			funcType->get_parameters().splice( last, inferredParams );
 			addAdapters( funcType );
-			mutateAll( funcType->get_returnVals(), *this );
-			mutateAll( funcType->get_parameters(), *this );
-
-			scopeTyVars.endScope();
-			return funcType;
 		}
 
@@ -1468,5 +1380,5 @@
 
 		PolyGenericCalculator::PolyGenericCalculator()
-			: knownLayouts(), knownOffsets(), bufNamer( "_buf" ), scopeTyVars( TypeDecl::Data{} ) {}
+			: knownLayouts(), knownOffsets(), bufNamer( "_buf" ) {}
 
 		void PolyGenericCalculator::beginTypeScope( Type *ty ) {
@@ -1829,74 +1741,47 @@
 
 		template< typename DeclClass >
-		DeclClass * Pass3::handleDecl( DeclClass *decl, Type *type ) {
-			scopeTyVars.beginScope();
+		void Pass3::handleDecl( DeclClass * decl, Type * type ) {
+			GuardScope( scopeTyVars );
 			makeTyVarMap( type, scopeTyVars );
-
-			DeclClass *ret = static_cast< DeclClass *>( Mutator::mutate( decl ) );
-			// ScrubTyVars::scrub( decl, scopeTyVars );
 			ScrubTyVars::scrubAll( decl );
-
-			scopeTyVars.endScope();
-			return ret;
-		}
-
-		ObjectDecl * Pass3::mutate( ObjectDecl *objectDecl ) {
-			return handleDecl( objectDecl, objectDecl->get_type() );
-		}
-
-		DeclarationWithType * Pass3::mutate( FunctionDecl *functionDecl ) {
-			return handleDecl( functionDecl, functionDecl->get_functionType() );
-		}
-
-		TypedefDecl * Pass3::mutate( TypedefDecl *typedefDecl ) {
-			return handleDecl( typedefDecl, typedefDecl->get_base() );
+		}
+
+		void Pass3::premutate( ObjectDecl * objectDecl ) {
+			handleDecl( objectDecl, objectDecl->type );
+		}
+
+		void Pass3::premutate( FunctionDecl * functionDecl ) {
+			handleDecl( functionDecl, functionDecl->type );
+		}
+
+		void Pass3::premutate( TypedefDecl * typedefDecl ) {
+			handleDecl( typedefDecl, typedefDecl->base );
 		}
 
 		/// Strips the members from a generic aggregate
-		void stripGenericMembers(AggregateDecl* decl) {
-			if ( ! decl->get_parameters().empty() ) decl->get_members().clear();
-		}
-
-		Declaration *Pass3::mutate( StructDecl *structDecl ) {
+		void stripGenericMembers(AggregateDecl * decl) {
+			if ( ! decl->parameters.empty() ) decl->members.clear();
+		}
+
+		void Pass3::premutate( StructDecl * structDecl ) {
 			stripGenericMembers( structDecl );
-			return structDecl;
-		}
-
-		Declaration *Pass3::mutate( UnionDecl *unionDecl ) {
+		}
+
+		void Pass3::premutate( UnionDecl * unionDecl ) {
 			stripGenericMembers( unionDecl );
-			return unionDecl;
-		}
-
-		TypeDecl * Pass3::mutate( TypeDecl *typeDecl ) {
-//   Initializer *init = 0;
-//   std::list< Expression *> designators;
-//   addToTyVarMap( typeDecl, scopeTyVars );
-//   if ( typeDecl->get_base() ) {
-//     init = new SimpleInit( new SizeofExpr( handleDecl( typeDecl, typeDecl->get_base() ) ), designators );
-//   }
-//   return new ObjectDecl( typeDecl->get_name(), Declaration::Extern, LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::UnsignedInt ), init );
-
+		}
+
+		void Pass3::premutate( TypeDecl * typeDecl ) {
 			addToTyVarMap( typeDecl, scopeTyVars );
-			return dynamic_cast<TypeDecl*>( Mutator::mutate( typeDecl ) );
-		}
-
-		Type * Pass3::mutate( PointerType *pointerType ) {
-			scopeTyVars.beginScope();
+		}
+
+		void Pass3::premutate( PointerType * pointerType ) {
+			GuardScope( scopeTyVars );
 			makeTyVarMap( pointerType, scopeTyVars );
-
-			Type *ret = Mutator::mutate( pointerType );
-
-			scopeTyVars.endScope();
-			return ret;
-		}
-
-		Type * Pass3::mutate( FunctionType *functionType ) {
-			scopeTyVars.beginScope();
+		}
+
+		void Pass3::premutate( FunctionType * functionType ) {
+			GuardScope( scopeTyVars );
 			makeTyVarMap( functionType, scopeTyVars );
-
-			Type *ret = Mutator::mutate( functionType );
-
-			scopeTyVars.endScope();
-			return ret;
 		}
 	} // anonymous namespace
