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
Index: src/GenPoly/DeclMutator.cc
===================================================================
--- src/GenPoly/DeclMutator.cc	(revision eada3cfc526a731d1ac85003f73c04f68d7ae037)
+++ 	(revision )
@@ -1,195 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// DeclMutator.cc --
-//
-// Author           : Aaron B. Moss
-// Created On       : Fri Nov 27 14:44:00 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Thu Jun 22 13:49:00 2017
-// Update Count     : 4
-//
-
-#include "DeclMutator.h"
-
-#include <memory>                  // for allocator_traits<>::value_type
-
-#include "Common/SemanticError.h"  // for SemanticError
-#include "SynTree/Declaration.h"   // for Declaration
-#include "SynTree/Expression.h"    // for Expression
-#include "SynTree/Label.h"         // for Label, noLabels
-#include "SynTree/Statement.h"     // for CatchStmt, Statement, CompoundStmt
-
-namespace GenPoly {
-	DeclMutator::DeclMutator() : Mutator(), declsToAdd(1), declsToAddAfter(1) {}
-
-	DeclMutator::~DeclMutator() {}
-
-	void DeclMutator::mutateDeclarationList( std::list< Declaration* > &decls ) {
-		for ( std::list< Declaration* >::iterator decl = decls.begin(); ; ++decl ) {
-			// splice in new declarations after previous decl
-			decls.splice( decl, declsToAddAfter.back() );
-
-			if ( decl == decls.end() ) break;
-
-			// run mutator on declaration
-			*decl = maybeMutate( *decl, *this );
-
-			// splice in new declarations before current decl
-			decls.splice( decl, declsToAdd.back() );
-		}
-	}
-
-	void DeclMutator::doBeginScope() {
-		// add new decl lists for inside of scope
-		declsToAdd.resize( declsToAdd.size()+1 );
-		declsToAddAfter.resize( declsToAddAfter.size()+1 );
-	}
-
-	void DeclMutator::doEndScope() {
-		// splice any leftover declarations from this scope onto the containing scope
-		std::vector< std::list< Declaration* > >::reverse_iterator back = declsToAdd.rbegin();
-		std::vector< std::list< Declaration* > >::reverse_iterator newBack = back + 1;
-		newBack->splice( newBack->end(), *back );
-		declsToAdd.pop_back();
-
-		back = declsToAddAfter.rbegin();
-		newBack = back + 1;
-		newBack->splice( newBack->end(), *back );
-		declsToAddAfter.pop_back();
-	}
-
-	Statement* DeclMutator::mutateStatement( Statement *stmt ) {
-		// shunt over to compound statement handling if applicable
-		CompoundStmt *compoundStmt = dynamic_cast< CompoundStmt* >(stmt);
-		if ( compoundStmt ) return mutate( compoundStmt );
-
-		doBeginScope();
-
-		// run mutator on statement
-		stmt = maybeMutate( stmt, *this );
-		// return if no declarations to add
-		if ( declsToAdd.back().empty() && declsToAddAfter.back().empty() ) {
-			doEndScope();
-			return stmt;
-		}
-
-		// otherwise add declarations to new compound statement
-		CompoundStmt *compound = new CompoundStmt( noLabels );
-		for ( std::list< Declaration* >::iterator decl = declsToAdd.back().begin(); decl != declsToAdd.back().end(); ++decl ) {
-			DeclStmt *declStmt = new DeclStmt( noLabels, *decl );
-			compound->get_kids().push_back( declStmt );
-		}
-		declsToAdd.back().clear();
-
-		// add mutated statement
-		compound->get_kids().push_back( stmt );
-
-		// add declarations after to new compound statement
-		for ( std::list< Declaration* >::iterator decl = declsToAddAfter.back().begin(); decl != declsToAddAfter.back().end(); ++decl ) {
-			DeclStmt *declStmt = new DeclStmt( noLabels, *decl );
-			compound->get_kids().push_back( declStmt );
-		}
-		declsToAddAfter.back().clear();
-
-		doEndScope();
-		return compound;
-	}
-
-	void DeclMutator::mutateStatementList( std::list< Statement* > &stmts ) {
-		doBeginScope();
-
-
-		for ( std::list< Statement* >::iterator stmt = stmts.begin(); ; ++stmt ) {
-			// add any new declarations after the previous statement
-			for ( std::list< Declaration* >::iterator decl = declsToAddAfter.back().begin(); decl != declsToAddAfter.back().end(); ++decl ) {
-				DeclStmt *declStmt = new DeclStmt( noLabels, *decl );
-				stmts.insert( stmt, declStmt );
-			}
-			declsToAddAfter.back().clear();
-
-			if ( stmt == stmts.end() ) break;
-
-			// run mutator on statement
-			*stmt = maybeMutate( *stmt, *this );
-
-			// add any new declarations before the statement
-			for ( std::list< Declaration* >::iterator decl = declsToAdd.back().begin(); decl != declsToAdd.back().end(); ++decl ) {
-				DeclStmt *declStmt = new DeclStmt( noLabels, *decl );
-				stmts.insert( stmt, declStmt );
-			}
-			declsToAdd.back().clear();
-		}
-
-		doEndScope();
-	}
-
-	void DeclMutator::addDeclaration( Declaration *decl ) {
-		declsToAdd.back().push_back( decl );
-	}
-
-	void DeclMutator::addDeclarationAfter( Declaration *decl ) {
-		declsToAddAfter.back().push_back( decl );
-	}
-
-	CompoundStmt* DeclMutator::mutate(CompoundStmt *compoundStmt) {
-		mutateStatementList( compoundStmt->get_kids() );
-		return compoundStmt;
-	}
-
-	Statement* DeclMutator::mutate(IfStmt *ifStmt) {
-		ifStmt->set_condition( maybeMutate( ifStmt->get_condition(), *this ) );
-		ifStmt->set_thenPart( mutateStatement( ifStmt->get_thenPart() ) );
-		ifStmt->set_elsePart( mutateStatement( ifStmt->get_elsePart() ) );
-		return ifStmt;
-	}
-
-	Statement* DeclMutator::mutate(WhileStmt *whileStmt) {
-		whileStmt->set_condition( maybeMutate( whileStmt->get_condition(), *this ) );
-		whileStmt->set_body(  mutateStatement( whileStmt->get_body() ) );
-		return whileStmt;
-	}
-
-	Statement* DeclMutator::mutate(ForStmt *forStmt) {
-		mutateAll( forStmt->get_initialization(), *this );
-		forStmt->set_condition(  maybeMutate( forStmt->get_condition(), *this ) );
-		forStmt->set_increment(  maybeMutate( forStmt->get_increment(), *this ) );
-		forStmt->set_body(  mutateStatement( forStmt->get_body() ) );
-		return forStmt;
-	}
-
-	Statement* DeclMutator::mutate(SwitchStmt *switchStmt) {
-		switchStmt->set_condition( maybeMutate( switchStmt->get_condition(), *this ) );
-		mutateAll( switchStmt->get_statements(), *this );
-		return switchStmt;
-	}
-
-	Statement* DeclMutator::mutate(CaseStmt *caseStmt) {
-		caseStmt->set_condition( maybeMutate( caseStmt->get_condition(), *this ) );
-		mutateAll( caseStmt->get_statements(), *this );
-		return caseStmt;
-	}
-
-	Statement* DeclMutator::mutate(TryStmt *tryStmt) {
-		tryStmt->set_block( maybeMutate( tryStmt->get_block(), *this ) );
-		mutateAll( tryStmt->get_catchers(), *this );
-		tryStmt->set_finally( maybeMutate( tryStmt->get_finally(), *this ) );
-		return tryStmt;
-	}
-
-	Statement* DeclMutator::mutate(CatchStmt *catchStmt) {
-		catchStmt->set_decl( maybeMutate( catchStmt->get_decl(), *this ) );
-		catchStmt->set_cond( maybeMutate( catchStmt->get_cond(), *this ) );
-		catchStmt->set_body( mutateStatement( catchStmt->get_body() ) );
-		return catchStmt;
-	}
-}  // namespace GenPoly
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/GenPoly/DeclMutator.h
===================================================================
--- src/GenPoly/DeclMutator.h	(revision eada3cfc526a731d1ac85003f73c04f68d7ae037)
+++ 	(revision )
@@ -1,71 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// DeclMutator.h --
-//
-// Author           : Aaron B. Moss
-// Created On       : Fri Nov 27 14:44:00 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:21:12 2017
-// Update Count     : 4
-//
-
-#pragma once
-
-#include <list>               // for list
-#include <vector>             // for vector
-
-#include "SynTree/Mutator.h"  // for Mutator
-#include "SynTree/SynTree.h"  // for Visitor Nodes
-
-namespace GenPoly {
-	/// Mutates a list of declarations, providing a means of adding new declarations into the list
-	class DeclMutator : public Mutator {
-	  public:
-		typedef Mutator Parent;
-
-		DeclMutator();
-		virtual ~DeclMutator();
-
-		using Parent::mutate;
-		virtual CompoundStmt* mutate(CompoundStmt *compoundStmt);
-		virtual Statement* mutate(IfStmt *ifStmt);
-		virtual Statement* mutate(WhileStmt *whileStmt);
-		virtual Statement* mutate(ForStmt *forStmt);
-		virtual Statement* mutate(SwitchStmt *switchStmt);
-		virtual Statement* mutate(CaseStmt *caseStmt);
-		virtual Statement* mutate(TryStmt *tryStmt);
-		virtual Statement* mutate(CatchStmt *catchStmt);
-
-		/// Mutates a list of declarations with this visitor
-		void mutateDeclarationList(std::list< Declaration* >& decls);
-
-		/// Called on entry to a new scope; overriders should call this as a super-class call
-		virtual void doBeginScope();
-		/// Called on exit from a scope; overriders should call this as a super-class call
-		virtual void doEndScope();
-	  protected:
-		/// Mutate a statement that forms its own scope
-		Statement* mutateStatement( Statement *stmt );
-		/// Mutate a list of statements that form a scope
-		void mutateStatementList( std::list< Statement* > &stmts );
-		/// Add a declaration to the list to be added before the current position
-		void addDeclaration( Declaration* decl );
-		/// Add a declaration to the list to be added after the current position
-		void addDeclarationAfter( Declaration* decl );
-	  private:
-		/// A stack of declarations to add before the current declaration or statement
-		std::vector< std::list< Declaration* > > declsToAdd;
-		/// A stack of declarations to add after the current declaration or statement
-		std::vector< std::list< Declaration* > > declsToAddAfter;
-	};
-} // namespace
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/GenPoly/PolyMutator.cc
===================================================================
--- src/GenPoly/PolyMutator.cc	(revision eada3cfc526a731d1ac85003f73c04f68d7ae037)
+++ 	(revision )
@@ -1,187 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// PolyMutator.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Thu Jun 22 13:47:00 2017
-// Update Count     : 17
-//
-
-#include "PolyMutator.h"
-
-#include "Common/SemanticError.h"  // for SemanticError
-#include "Common/utility.h"        // for ValueGuard
-#include "SynTree/Declaration.h"   // for Declaration, TypeDecl, TypeDecl::Data
-#include "SynTree/Expression.h"    // for Expression, UntypedExpr, StmtExpr ...
-#include "SynTree/Initializer.h"   // for SingleInit, Initializer (ptr only)
-#include "SynTree/Label.h"         // for Label, noLabels
-#include "SynTree/Mutator.h"       // for maybeMutate, mutateAll
-#include "SynTree/Statement.h"     // for CatchStmt, CompoundStmt, ForStmt
-
-class TypeSubstitution;
-
-namespace GenPoly {
-	PolyMutator::PolyMutator() : scopeTyVars( TypeDecl::Data{} ), env( 0 ) {}
-
-	void PolyMutator::mutateStatementList( std::list< Statement* > &statements ) {
-		SemanticError errors;
-
-		for ( std::list< Statement* >::iterator i = statements.begin(); i != statements.end(); ++i ) {
-			if ( ! stmtsToAddAfter.empty() ) {
-				statements.splice( i, stmtsToAddAfter );
-			} // if
-			try {
-				*i = (*i)->acceptMutator( *this );
-			} catch ( SemanticError &e ) {
-				errors.append( e );
-			} // try
-			if ( ! stmtsToAdd.empty() ) {
-				statements.splice( i, stmtsToAdd );
-			} // if
-		} // for
-		if ( ! stmtsToAddAfter.empty() ) {
-			statements.splice( statements.end(), stmtsToAddAfter );
-		} // if
-		if ( ! errors.isEmpty() ) {
-			throw errors;
-		}
-	}
-
-	Statement * PolyMutator::mutateStatement( Statement *stmt ) {
-		// don't want statements from outer CompoundStmts to be added to this CompoundStmt
-		ValueGuard< std::list< Statement* > > oldStmtsToAdd( stmtsToAdd );
-		ValueGuard< std::list< Statement* > > oldStmtsToAddAfter( stmtsToAddAfter );
-		ValueGuard< TypeSubstitution * > oldEnv( env );
-		stmtsToAdd.clear();
-		stmtsToAddAfter.clear();
-
-		Statement *newStmt = maybeMutate( stmt, *this );
-		if ( ! stmtsToAdd.empty() || ! stmtsToAddAfter.empty() ) {
-			CompoundStmt *compound = new CompoundStmt( noLabels );
-			compound->get_kids().splice( compound->get_kids().end(), stmtsToAdd );
-			compound->get_kids().push_back( newStmt );
-			compound->get_kids().splice( compound->get_kids().end(), stmtsToAddAfter );
-			// doEndScope();
-			return compound;
-		} else {
-			return newStmt;
-		}
-	}
-
-	Expression * PolyMutator::mutateExpression( Expression *expr ) {
-		if ( expr ) {
-			if ( expr->get_env() ) {
-				env = expr->get_env();
-			}
-			// xxx - should env be cloned (or moved) onto the result of the mutate?
-			return expr->acceptMutator( *this );
-		} else {
-			return expr;
-		}
-	}
-
-	CompoundStmt * PolyMutator::mutate(CompoundStmt *compoundStmt) {
-		doBeginScope();
-		mutateStatementList( compoundStmt->get_kids() );
-		doEndScope();
-		return compoundStmt;
-	}
-
-	Statement * PolyMutator::mutate(IfStmt *ifStmt) {
-		ifStmt->set_condition(  mutateExpression( ifStmt->get_condition() ) );
-		ifStmt->set_thenPart(  mutateStatement( ifStmt->get_thenPart() ) );
-		ifStmt->set_elsePart(  mutateStatement( ifStmt->get_elsePart() ) );
-		return ifStmt;
-	}
-
-	Statement * PolyMutator::mutate(WhileStmt *whileStmt) {
-		whileStmt->set_condition(  mutateExpression( whileStmt->get_condition() ) );
-		whileStmt->set_body(  mutateStatement( whileStmt->get_body() ) );
-		return whileStmt;
-	}
-
-	Statement * PolyMutator::mutate(ForStmt *forStmt) {
-		mutateAll( forStmt->get_initialization(), *this );
-		forStmt->set_condition(  mutateExpression( forStmt->get_condition() ) );
-		forStmt->set_increment(  mutateExpression( forStmt->get_increment() ) );
-		forStmt->set_body(  mutateStatement( forStmt->get_body() ) );
-		return forStmt;
-	}
-
-	Statement * PolyMutator::mutate(SwitchStmt *switchStmt) {
-		switchStmt->set_condition( mutateExpression( switchStmt->get_condition() ) );
-		mutateStatementList( switchStmt->get_statements() );
-		return switchStmt;
-	}
-
-	Statement * PolyMutator::mutate(CaseStmt *caseStmt) {
-		caseStmt->set_condition(  mutateExpression( caseStmt->get_condition() ) );
-		mutateStatementList( caseStmt->get_statements() );
-		return caseStmt;
-	}
-
-	Statement * PolyMutator::mutate(TryStmt *tryStmt) {
-		tryStmt->set_block( maybeMutate( tryStmt->get_block(), *this ) );
-		mutateAll( tryStmt->get_catchers(), *this );
-		tryStmt->set_finally( maybeMutate( tryStmt->get_finally(), *this ) );
-		return tryStmt;
-	}
-
-	Statement * PolyMutator::mutate(CatchStmt *cathStmt) {
-		cathStmt->set_body( mutateStatement( cathStmt->get_body() ) );
-		cathStmt->set_cond( maybeMutate( cathStmt->get_cond(), *this ) );
-		cathStmt->set_decl( maybeMutate( cathStmt->get_decl(), *this ) );
-		return cathStmt;
-	}
-
-	Statement * PolyMutator::mutate(ReturnStmt *retStmt) {
-		retStmt->set_expr( mutateExpression( retStmt->get_expr() ) );
-		return retStmt;
-	}
-
-	Statement * PolyMutator::mutate(ExprStmt *exprStmt) {
-		exprStmt->set_expr( mutateExpression( exprStmt->get_expr() ) );
-		return exprStmt;
-	}
-
-
-	Expression * PolyMutator::mutate(UntypedExpr *untypedExpr) {
-		for ( std::list< Expression* >::iterator i = untypedExpr->get_args().begin(); i != untypedExpr->get_args().end(); ++i ) {
-			*i = mutateExpression( *i );
-		} // for
-		return untypedExpr;
-	}
-
-	Expression *PolyMutator::mutate( StmtExpr * stmtExpr ) {
-		// don't want statements from outer CompoundStmts to be added to this StmtExpr
-		ValueGuard< std::list< Statement* > > oldStmtsToAdd( stmtsToAdd );
-		ValueGuard< std::list< Statement* > > oldStmtsToAddAfter( stmtsToAddAfter );
-		ValueGuard< TypeSubstitution * > oldEnv( env );
-
-		// xxx - not sure if this is needed, along with appropriate reset, but I don't think so...
-		// ValueGuard< TyVarMap > oldScopeTyVars( scopeTyVars );
-
-		stmtsToAdd.clear();
-		stmtsToAddAfter.clear();
-		// scopeTyVars.clear();
-
-		return Parent::mutate( stmtExpr );
-	}
-
-	Initializer *PolyMutator::mutate( SingleInit *singleInit ) {
-		singleInit->set_value( mutateExpression( singleInit->get_value() ) );
-		return singleInit;
-	}
-} // namespace GenPoly
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/GenPoly/PolyMutator.h
===================================================================
--- src/GenPoly/PolyMutator.h	(revision eada3cfc526a731d1ac85003f73c04f68d7ae037)
+++ 	(revision )
@@ -1,67 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// PolyMutator.h --
-//
-// Author           : Richard C. Bilson
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:20:31 2017
-// Update Count     : 7
-//
-
-#pragma once
-
-#include <list>               // for list
-
-#include "GenPoly.h"          // for TyVarMap
-#include "SynTree/Mutator.h"  // for Mutator
-#include "SynTree/SynTree.h"  // for Visitor Nodes
-
-namespace GenPoly {
-	class PolyMutator : public Mutator {
-	  public:
-		typedef Mutator Parent;
-		using Parent::mutate;
-
-		PolyMutator();
-
-		virtual CompoundStmt* mutate(CompoundStmt *compoundStmt);
-		virtual Statement* mutate(IfStmt *ifStmt);
-		virtual Statement* mutate(WhileStmt *whileStmt);
-		virtual Statement* mutate(ForStmt *forStmt);
-		virtual Statement* mutate(SwitchStmt *switchStmt);
-		virtual Statement* mutate(CaseStmt *caseStmt);
-		virtual Statement* mutate(TryStmt *returnStmt);
-		virtual Statement* mutate(CatchStmt *catchStmt);
-		virtual Statement* mutate(ExprStmt *catchStmt);
-		virtual Statement* mutate(ReturnStmt *catchStmt);
-
-		virtual Expression* mutate(UntypedExpr *untypedExpr);
-		virtual Expression* mutate( StmtExpr *stmtExpr );
-
-		virtual Initializer* mutate(SingleInit *SingleInit);
-
-		// template method
-		virtual void doBeginScope() {}
-		virtual void doEndScope() {}
-	  protected:
-		void mutateStatementList( std::list< Statement* > &statements );
-		Statement* mutateStatement( Statement *stmt );
-		Expression* mutateExpression( Expression *expr );
-
-		TyVarMap scopeTyVars;
-		TypeSubstitution *env;
-		std::list< Statement* > stmtsToAdd;
-		std::list< Statement* > stmtsToAddAfter;
-	};
-} // namespace
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/GenPoly/Specialize.cc
===================================================================
--- src/GenPoly/Specialize.cc	(revision eada3cfc526a731d1ac85003f73c04f68d7ae037)
+++ src/GenPoly/Specialize.cc	(revision d67cdb749954789d84d7a8bbabc0ec601347a7bb)
@@ -22,4 +22,5 @@
 #include <utility>                       // for pair
 
+#include "Common/PassVisitor.h"
 #include "Common/SemanticError.h"        // for SemanticError
 #include "Common/UniqueName.h"           // for UniqueName
@@ -28,5 +29,4 @@
 #include "InitTweak/InitTweak.h"         // for isIntrinsicCallExpr
 #include "Parser/LinkageSpec.h"          // for C
-#include "PolyMutator.h"                 // for PolyMutator
 #include "ResolvExpr/FindOpenVars.h"     // for findOpenVars
 #include "ResolvExpr/TypeEnvironment.h"  // for OpenVarSet, AssertionSet
@@ -43,13 +43,8 @@
 
 namespace GenPoly {
-	class Specialize final : public PolyMutator {
-	  public:
-		using PolyMutator::mutate;
-		virtual Expression * mutate( ApplicationExpr *applicationExpr ) override;
-		virtual Expression * mutate( AddressExpr *castExpr ) override;
-		virtual Expression * mutate( CastExpr *castExpr ) override;
-		// virtual Expression * mutate( LogicalExpr *logicalExpr );
-		// virtual Expression * mutate( ConditionalExpr *conditionalExpr );
-		// virtual Expression * mutate( CommaExpr *commaExpr );
+	struct Specialize final : public WithTypeSubstitution, public WithStmtsToAdd, public WithVisitorRef<Specialize> {
+		Expression * postmutate( ApplicationExpr *applicationExpr );
+		Expression * postmutate( AddressExpr *castExpr );
+		Expression * postmutate( CastExpr *castExpr );
 
 		void handleExplicitParams( ApplicationExpr *appExpr );
@@ -204,11 +199,11 @@
 	}
 
-	struct EnvTrimmer : public Visitor {
+	struct EnvTrimmer {
 		TypeSubstitution * env, * newEnv;
 		EnvTrimmer( TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
-		virtual void visit( TypeDecl * tyDecl ) {
+		void previsit( TypeDecl * tyDecl ) {
 			// transfer known bindings for seen type variables
-			if ( Type * t = env->lookup( tyDecl->get_name() ) ) {
-				newEnv->add( tyDecl->get_name(), t );
+			if ( Type * t = env->lookup( tyDecl->name ) ) {
+				newEnv->add( tyDecl->name, t );
 			}
 		}
@@ -219,5 +214,5 @@
 		if ( env ) {
 			TypeSubstitution * newEnv = new TypeSubstitution();
-			EnvTrimmer trimmer( env, newEnv );
+			PassVisitor<EnvTrimmer> trimmer( env, newEnv );
 			expr->accept( trimmer );
 			return newEnv;
@@ -277,25 +272,25 @@
 		std::string oldParamPrefix = paramPrefix;
 		paramPrefix += "p";
-		// save stmtsToAdd in oldStmts
+		// save stmtsToAddBefore in oldStmts
 		std::list< Statement* > oldStmts;
-		oldStmts.splice( oldStmts.end(), stmtsToAdd );
-		mutate( appExpr );
+		oldStmts.splice( oldStmts.end(), stmtsToAddBefore );
+		appExpr->acceptMutator( *visitor );
 		paramPrefix = oldParamPrefix;
 		// write any statements added for recursive specializations into the thunk body
-		thunkFunc->get_statements()->get_kids().splice( thunkFunc->get_statements()->get_kids().end(), stmtsToAdd );
-		// restore oldStmts into stmtsToAdd
-		stmtsToAdd.splice( stmtsToAdd.end(), oldStmts );
+		thunkFunc->statements->kids.splice( thunkFunc->statements->kids.end(), stmtsToAddBefore );
+		// restore oldStmts into stmtsToAddBefore
+		stmtsToAddBefore.splice( stmtsToAddBefore.end(), oldStmts );
 
 		// add return (or valueless expression) to the thunk
 		Statement *appStmt;
-		if ( funType->get_returnVals().empty() ) {
+		if ( funType->returnVals.empty() ) {
 			appStmt = new ExprStmt( noLabels, appExpr );
 		} else {
 			appStmt = new ReturnStmt( noLabels, appExpr );
 		} // if
-		thunkFunc->get_statements()->get_kids().push_back( appStmt );
+		thunkFunc->statements->kids.push_back( appStmt );
 
 		// add thunk definition to queue of statements to add
-		stmtsToAdd.push_back( new DeclStmt( noLabels, thunkFunc ) );
+		stmtsToAddBefore.push_back( new DeclStmt( noLabels, thunkFunc ) );
 		// return address of thunk function as replacement expression
 		return new AddressExpr( new VariableExpr( thunkFunc ) );
@@ -304,18 +299,15 @@
 	void Specialize::handleExplicitParams( ApplicationExpr *appExpr ) {
 		// create thunks for the explicit parameters
-		assert( appExpr->get_function()->has_result() );
-		FunctionType *function = getFunctionType( appExpr->get_function()->get_result() );
+		assert( appExpr->function->result );
+		FunctionType *function = getFunctionType( appExpr->function->result );
 		assert( function );
 		std::list< DeclarationWithType* >::iterator formal;
 		std::list< Expression* >::iterator actual;
 		for ( formal = function->get_parameters().begin(), actual = appExpr->get_args().begin(); formal != function->get_parameters().end() && actual != appExpr->get_args().end(); ++formal, ++actual ) {
-			*actual = doSpecialization( (*formal )->get_type(), *actual, &appExpr->get_inferParams() );
-		}
-	}
-
-	Expression * Specialize::mutate( ApplicationExpr *appExpr ) {
-		appExpr->get_function()->acceptMutator( *this );
-		mutateAll( appExpr->get_args(), *this );
-
+			*actual = doSpecialization( (*formal)->get_type(), *actual, &appExpr->get_inferParams() );
+		}
+	}
+
+	Expression * Specialize::postmutate( ApplicationExpr *appExpr ) {
 		if ( ! InitTweak::isIntrinsicCallExpr( appExpr ) ) {
 			// create thunks for the inferred parameters
@@ -331,19 +323,17 @@
 	}
 
-	Expression * Specialize::mutate( AddressExpr *addrExpr ) {
-		addrExpr->get_arg()->acceptMutator( *this );
-		assert( addrExpr->has_result() );
-		addrExpr->set_arg( doSpecialization( addrExpr->get_result(), addrExpr->get_arg() ) );
+	Expression * Specialize::postmutate( AddressExpr *addrExpr ) {
+		assert( addrExpr->result );
+		addrExpr->set_arg( doSpecialization( addrExpr->result, addrExpr->arg ) );
 		return addrExpr;
 	}
 
-	Expression * Specialize::mutate( CastExpr *castExpr ) {
-		castExpr->get_arg()->acceptMutator( *this );
-		if ( castExpr->get_result()->isVoid() ) {
+	Expression * Specialize::postmutate( CastExpr *castExpr ) {
+		if ( castExpr->result->isVoid() ) {
 			// can't specialize if we don't have a return value
 			return castExpr;
 		}
-		Expression *specialized = doSpecialization( castExpr->get_result(), castExpr->get_arg() );
-		if ( specialized != castExpr->get_arg() ) {
+		Expression *specialized = doSpecialization( castExpr->result, castExpr->arg );
+		if ( specialized != castExpr->arg ) {
 			// assume here that the specialization incorporates the cast
 			return specialized;
@@ -353,22 +343,6 @@
 	}
 
-	// Removing these for now. Richard put these in for some reason, but it's not clear why.
-	// In particular, copy constructors produce a comma expression, and with this code the parts
-	// of that comma expression are not specialized, which causes problems.
-
-	// Expression * Specialize::mutate( LogicalExpr *logicalExpr ) {
-	// 	return logicalExpr;
-	// }
-
-	// Expression * Specialize::mutate( ConditionalExpr *condExpr ) {
-	// 	return condExpr;
-	// }
-
-	// Expression * Specialize::mutate( CommaExpr *commaExpr ) {
-	// 	return commaExpr;
-	// }
-
 	void convertSpecializations( std::list< Declaration* >& translationUnit ) {
-		Specialize spec;
+		PassVisitor<Specialize> spec;
 		mutateAll( translationUnit, spec );
 	}
Index: src/GenPoly/module.mk
===================================================================
--- src/GenPoly/module.mk	(revision eada3cfc526a731d1ac85003f73c04f68d7ae037)
+++ src/GenPoly/module.mk	(revision d67cdb749954789d84d7a8bbabc0ec601347a7bb)
@@ -6,5 +6,5 @@
 ## file "LICENCE" distributed with Cforall.
 ##
-## module.mk -- 
+## module.mk --
 ##
 ## Author           : Richard C. Bilson
@@ -17,5 +17,4 @@
 SRC += GenPoly/Box.cc \
        GenPoly/GenPoly.cc \
-       GenPoly/PolyMutator.cc \
        GenPoly/ScrubTyVars.cc \
        GenPoly/Lvalue.cc \
@@ -23,4 +22,3 @@
        GenPoly/CopyParams.cc \
        GenPoly/FindFunction.cc \
-       GenPoly/DeclMutator.cc \
        GenPoly/InstantiateGeneric.cc
