Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision fc72845da193aa5bd08d9f818a08d4e83612b356)
+++ src/GenPoly/Box.cc	(revision 201182a7edebd0d3951b3d6a594f323c8b1a2900)
@@ -77,22 +77,21 @@
 
 		/// 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
@@ -160,5 +159,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();
@@ -199,5 +198,4 @@
 			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;
 		};
 
@@ -247,5 +245,5 @@
 	void box( std::list< Declaration *>& translationUnit ) {
 		PassVisitor<LayoutFunctionBuilder> layoutBuilder;
-		Pass1 pass1;
+		PassVisitor<Pass1> pass1;
 		Pass2 pass2;
 		PassVisitor<PolyGenericCalculator> polyCalculator;
@@ -253,5 +251,5 @@
 
 		acceptAll( translationUnit, layoutBuilder );
-		mutateTranslationUnit/*All*/( translationUnit, pass1 );
+		mutateAll( translationUnit, pass1 );
 		mutateTranslationUnit/*All*/( translationUnit, pass2 );
 		mutateAll( translationUnit, polyCalculator );
@@ -500,31 +498,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
@@ -541,21 +537,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
@@ -573,16 +561,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;
-
 		}
 
@@ -658,5 +634,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;
 		}
@@ -774,9 +750,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
@@ -960,5 +936,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() );
@@ -1117,5 +1093,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 ) {
@@ -1123,10 +1099,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 ) ) {
@@ -1181,19 +1155,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() );
 
@@ -1215,5 +1190,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 );
@@ -1230,40 +1205,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();
 		}
@@ -1467,5 +1429,5 @@
 
 		PolyGenericCalculator::PolyGenericCalculator()
-			: knownLayouts(), knownOffsets(), bufNamer( "_buf" ), scopeTyVars( TypeDecl::Data{} ) {}
+			: knownLayouts(), knownOffsets(), bufNamer( "_buf" ) {}
 
 		void PolyGenericCalculator::beginTypeScope( Type *ty ) {
