Index: src/GenPoly/Specialize.cc
===================================================================
--- src/GenPoly/Specialize.cc	(revision 8135d4c79504a6c3047246007261186efa5ba4c9)
+++ 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 );
 	}
