Index: src/ResolvExpr/AdjustExprType.cc
===================================================================
--- src/ResolvExpr/AdjustExprType.cc	(revision 3c398b6c889afd06fdf9de3208cd23fbf26275e5)
+++ src/ResolvExpr/AdjustExprType.cc	(revision cd034920302a4c438731188dac8d4dc2fc608705)
@@ -14,4 +14,5 @@
 //
 
+#include "Common/PassVisitor.h"
 #include "SymTab/Indexer.h"       // for Indexer
 #include "SynTree/Declaration.h"  // for TypeDecl, TypeDecl::Kind::Ftype
@@ -21,25 +22,26 @@
 
 namespace ResolvExpr {
-	class AdjustExprType : public Mutator {
-		typedef Mutator Parent;
-		using Parent::mutate;
+	class AdjustExprType : public WithShortCircuiting {
 	  public:
 		AdjustExprType( const TypeEnvironment &env, const SymTab::Indexer &indexer );
+		void premutate( VoidType * ) { visit_children = false; }
+		void premutate( BasicType * ) { visit_children = false; }
+		void premutate( PointerType * ) { visit_children = false; }
+		void premutate( FunctionType * ) { visit_children = false; }
+		void premutate( StructInstType * ) { visit_children = false; }
+		void premutate( UnionInstType * ) { visit_children = false; }
+		void premutate( EnumInstType * ) { visit_children = false; }
+		void premutate( TraitInstType * ) { visit_children = false; }
+		void premutate( TypeInstType * ) { visit_children = false; }
+		void premutate( TupleType * ) { visit_children = false; }
+		void premutate( VarArgsType * ) { visit_children = false; }
+		void premutate( ZeroType * ) { visit_children = false; }
+		void premutate( OneType * ) { visit_children = false; }
+
+		Type * postmutate( ArrayType *arrayType );
+		Type * postmutate( FunctionType *functionType );
+		Type * postmutate( TypeInstType *aggregateUseType );
+
 	  private:
-		virtual Type* mutate( VoidType *voidType );
-		virtual Type* mutate( BasicType *basicType );
-		virtual Type* mutate( PointerType *pointerType );
-		virtual Type* mutate( ArrayType *arrayType );
-		virtual Type* mutate( FunctionType *functionType );
-		virtual Type* mutate( StructInstType *aggregateUseType );
-		virtual Type* mutate( UnionInstType *aggregateUseType );
-		virtual Type* mutate( EnumInstType *aggregateUseType );
-		virtual Type* mutate( TraitInstType *aggregateUseType );
-		virtual Type* mutate( TypeInstType *aggregateUseType );
-		virtual Type* mutate( TupleType *tupleType );
-		virtual Type* mutate( VarArgsType *varArgsType );
-		virtual Type* mutate( ZeroType *zeroType );
-		virtual Type* mutate( OneType *oneType );
-
 		const TypeEnvironment &env;
 		const SymTab::Indexer &indexer;
@@ -47,5 +49,5 @@
 
 	void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
-		AdjustExprType adjuster( env, indexer );
+		PassVisitor<AdjustExprType> adjuster( env, indexer );
 		Type *newType = type->acceptMutator( adjuster );
 		type = newType;
@@ -56,45 +58,17 @@
 	}
 
-	Type *AdjustExprType::mutate( VoidType *voidType ) {
-		return voidType;
-	}
-
-	Type *AdjustExprType::mutate( BasicType *basicType ) {
-		return basicType;
-	}
-
-	Type *AdjustExprType::mutate( PointerType *pointerType ) {
-		return pointerType;
-	}
-
-	Type *AdjustExprType::mutate( ArrayType *arrayType ) {
+	Type * AdjustExprType::postmutate( ArrayType * arrayType ) {
 		// need to recursively mutate the base type in order for multi-dimensional arrays to work.
-		PointerType *pointerType = new PointerType( arrayType->get_qualifiers(), arrayType->get_base()->clone()->acceptMutator( *this ) );
+		PointerType *pointerType = new PointerType( arrayType->get_qualifiers(), arrayType->base );
+		arrayType->base = nullptr;
 		delete arrayType;
 		return pointerType;
 	}
 
-	Type *AdjustExprType::mutate( FunctionType *functionType ) {
-		PointerType *pointerType = new PointerType( Type::Qualifiers(), functionType );
-		return pointerType;
+	Type * AdjustExprType::postmutate( FunctionType * functionType ) {
+		return new PointerType( Type::Qualifiers(), functionType );
 	}
 
-	Type *AdjustExprType::mutate( StructInstType *aggregateUseType ) {
-		return aggregateUseType;
-	}
-
-	Type *AdjustExprType::mutate( UnionInstType *aggregateUseType ) {
-		return aggregateUseType;
-	}
-
-	Type *AdjustExprType::mutate( EnumInstType *aggregateUseType ) {
-		return aggregateUseType;
-	}
-
-	Type *AdjustExprType::mutate( TraitInstType *aggregateUseType ) {
-		return aggregateUseType;
-	}
-
-	Type *AdjustExprType::mutate( TypeInstType *typeInst ) {
+	Type * AdjustExprType::postmutate( TypeInstType * typeInst ) {
 		EqvClass eqvClass;
 		if ( env.lookup( typeInst->get_name(), eqvClass ) ) {
@@ -113,20 +87,4 @@
 		return typeInst;
 	}
-
-	Type *AdjustExprType::mutate( TupleType *tupleType ) {
-		return tupleType;
-	}
-
-	Type *AdjustExprType::mutate( VarArgsType *varArgsType ) {
-		return varArgsType;
-	}
-
-	Type *AdjustExprType::mutate( ZeroType *zeroType ) {
-		return zeroType;
-	}
-
-	Type *AdjustExprType::mutate( OneType *oneType ) {
-		return oneType;
-	}
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/Alternative.cc
===================================================================
--- src/ResolvExpr/Alternative.cc	(revision 3c398b6c889afd06fdf9de3208cd23fbf26275e5)
+++ src/ResolvExpr/Alternative.cc	(revision cd034920302a4c438731188dac8d4dc2fc608705)
@@ -66,17 +66,17 @@
 	}
 
-	void Alternative::print( std::ostream &os, int indent ) const {
-		os << std::string( indent, ' ' ) << "Cost " << cost << ": ";
+	void Alternative::print( std::ostream &os, Indenter indent ) const {
+		os << "Cost " << cost << ": ";
 		if ( expr ) {
-			expr->print( os, indent );
-			os << "(types:" << std::endl;
-			os << std::string( indent+4, ' ' );
-			expr->get_result()->print( os, indent + 4 );
-			os << std::endl << ")" << std::endl;
+			expr->print( os, indent+1 );
+			os << std::endl << indent << "(types:" << std::endl;
+			os << indent+1;
+			expr->result->print( os, indent+1 );
+			os << std::endl << indent << ")" << std::endl;
 		} else {
 			os << "Null expression!" << std::endl;
 		} // if
-		os << std::string( indent, ' ' ) << "Environment: ";
-		env.print( os, indent+2 );
+		os << indent << "Environment: ";
+		env.print( os, indent+1 );
 		os << std::endl;
 	}
Index: src/ResolvExpr/Alternative.h
===================================================================
--- src/ResolvExpr/Alternative.h	(revision 3c398b6c889afd06fdf9de3208cd23fbf26275e5)
+++ src/ResolvExpr/Alternative.h	(revision cd034920302a4c438731188dac8d4dc2fc608705)
@@ -39,5 +39,5 @@
 		~Alternative();
 
-		void print( std::ostream &os, int indent = 0 ) const;
+		void print( std::ostream &os, Indenter indent = {} ) const;
 
 		Cost cost;
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 3c398b6c889afd06fdf9de3208cd23fbf26275e5)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision cd034920302a4c438731188dac8d4dc2fc608705)
@@ -75,5 +75,6 @@
 
 	namespace {
-		void printAlts( const AltList &list, std::ostream &os, int indent = 0 ) {
+		void printAlts( const AltList &list, std::ostream &os, unsigned int indentAmt = 0 ) {
+			Indenter indent = { Indenter::tabsize, indentAmt };
 			for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {
 				i->print( os, indent );
@@ -195,8 +196,8 @@
 				AltList winners;
 				findMinCost( alternatives.begin(), alternatives.end(), back_inserter( winners ) );
-				stream << "Cannot choose between " << winners.size() << " alternatives for expression ";
+				stream << "Cannot choose between " << winners.size() << " alternatives for expression\n";
 				expr->print( stream );
-				stream << "Alternatives are:";
-				printAlts( winners, stream, 8 );
+				stream << "Alternatives are:\n";
+				printAlts( winners, stream, 1 );
 				throw SemanticError( stream.str() );
 			}
@@ -728,5 +729,5 @@
 		PRINT(
 			std::cerr << "known function ops:" << std::endl;
-			printAlts( funcOpFinder.alternatives, std::cerr, 8 );
+			printAlts( funcOpFinder.alternatives, std::cerr, 1 );
 		)
 
@@ -838,5 +839,5 @@
 	bool isLvalue( Expression *expr ) {
 		// xxx - recurse into tuples?
-		return expr->has_result() && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) );
+		return expr->result && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) );
 	}
 
@@ -972,5 +973,5 @@
 		PRINT( std::cerr << "nameExpr is " << nameExpr->get_name() << std::endl; )
 		for ( std::list< DeclarationWithType* >::iterator i = declList.begin(); i != declList.end(); ++i ) {
-			VariableExpr newExpr( *i, nameExpr->get_argName() );
+			VariableExpr newExpr( *i );
 			alternatives.push_back( Alternative( newExpr.clone(), env, Cost::zero ) );
 			PRINT(
Index: src/ResolvExpr/ResolveTypeof.cc
===================================================================
--- src/ResolvExpr/ResolveTypeof.cc	(revision 3c398b6c889afd06fdf9de3208cd23fbf26275e5)
+++ src/ResolvExpr/ResolveTypeof.cc	(revision cd034920302a4c438731188dac8d4dc2fc608705)
@@ -18,4 +18,5 @@
 #include <cassert>               // for assert
 
+#include "Common/PassVisitor.h"  // for PassVisitor
 #include "Resolver.h"            // for resolveInVoidContext
 #include "SynTree/Expression.h"  // for Expression
@@ -41,8 +42,9 @@
 	}
 
-	class ResolveTypeof : public Mutator {
+	class ResolveTypeof : public WithShortCircuiting {
 	  public:
 		ResolveTypeof( const SymTab::Indexer &indexer ) : indexer( indexer ) {}
-		Type *mutate( TypeofType *typeofType );
+		void premutate( TypeofType *typeofType );
+		Type * postmutate( TypeofType *typeofType );
 
 	  private:
@@ -50,20 +52,24 @@
 	};
 
-	Type *resolveTypeof( Type *type, const SymTab::Indexer &indexer ) {
-		ResolveTypeof mutator( indexer );
+	Type * resolveTypeof( Type *type, const SymTab::Indexer &indexer ) {
+		PassVisitor<ResolveTypeof> mutator( indexer );
 		return type->acceptMutator( mutator );
 	}
 
-	Type *ResolveTypeof::mutate( TypeofType *typeofType ) {
+	void ResolveTypeof::premutate( TypeofType * ) {
+		visit_children = false;
+	}
+
+	Type * ResolveTypeof::postmutate( TypeofType *typeofType ) {
 #if 0
-		std::cout << "resolving typeof: ";
-		typeofType->print( std::cout );
-		std::cout << std::endl;
+		std::cerr << "resolving typeof: ";
+		typeofType->print( std::cerr );
+		std::cerr << std::endl;
 #endif
-		if ( typeofType->get_expr() ) {
-			Expression *newExpr = resolveInVoidContext( typeofType->get_expr(), indexer );
-			assert( newExpr->has_result() && ! newExpr->get_result()->isVoid() );
-			Type *newType = newExpr->get_result();
-			newExpr->set_result( nullptr );
+		if ( typeofType->expr ) {
+			Expression * newExpr = resolveInVoidContext( typeofType->expr, indexer );
+			assert( newExpr->result && ! newExpr->result->isVoid() );
+			Type * newType = newExpr->result;
+			newExpr->result = nullptr;
 			delete typeofType;
 			delete newExpr;
Index: src/ResolvExpr/TypeEnvironment.cc
===================================================================
--- src/ResolvExpr/TypeEnvironment.cc	(revision 3c398b6c889afd06fdf9de3208cd23fbf26275e5)
+++ src/ResolvExpr/TypeEnvironment.cc	(revision cd034920302a4c438731188dac8d4dc2fc608705)
@@ -68,11 +68,11 @@
 	}
 
-	void EqvClass::print( std::ostream &os, int indent ) const {
-		os << std::string( indent, ' ' ) << "( ";
+	void EqvClass::print( std::ostream &os, Indenter indent ) const {
+		os << "( ";
 		std::copy( vars.begin(), vars.end(), std::ostream_iterator< std::string >( os, " " ) );
 		os << ")";
 		if ( type ) {
 			os << " -> ";
-			type->print( os, indent );
+			type->print( os, indent+1 );
 		} // if
 		if ( ! allowWidening ) {
@@ -144,5 +144,5 @@
 	}
 
-	void TypeEnvironment::print( std::ostream &os, int indent ) const {
+	void TypeEnvironment::print( std::ostream &os, Indenter indent ) const {
 		for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i ) {
 			i->print( os, indent );
Index: src/ResolvExpr/TypeEnvironment.h
===================================================================
--- src/ResolvExpr/TypeEnvironment.h	(revision 3c398b6c889afd06fdf9de3208cd23fbf26275e5)
+++ src/ResolvExpr/TypeEnvironment.h	(revision cd034920302a4c438731188dac8d4dc2fc608705)
@@ -68,5 +68,5 @@
 		EqvClass &operator=( const EqvClass &other );
 		~EqvClass();
-		void print( std::ostream &os, int indent = 0 ) const;
+		void print( std::ostream &os, Indenter indent = {} ) const;
 	};
 
@@ -80,5 +80,5 @@
 		void makeSubstitution( TypeSubstitution &result ) const;
 		bool isEmpty() const { return env.empty(); }
-		void print( std::ostream &os, int indent = 0 ) const;
+		void print( std::ostream &os, Indenter indent = {} ) const;
 		void combine( const TypeEnvironment &second, Type *(*combineFunc)( Type*, Type* ) );
 		void simpleCombine( const TypeEnvironment &second );
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision 3c398b6c889afd06fdf9de3208cd23fbf26275e5)
+++ src/ResolvExpr/Unify.cc	(revision cd034920302a4c438731188dac8d4dc2fc608705)
@@ -22,4 +22,5 @@
 #include <utility>                // for pair
 
+#include "Common/PassVisitor.h"   // for PassVisitor
 #include "FindOpenVars.h"         // for findOpenVars
 #include "Parser/LinkageSpec.h"   // for C
@@ -537,10 +538,11 @@
 	/// If this isn't done then argument lists can have wildly different
 	/// size and structure, when they should be compatible.
-	struct TtypeExpander : public Mutator {
-		TypeEnvironment & env;
-		TtypeExpander( TypeEnvironment & env ) : env( env ) {}
-		Type * mutate( TypeInstType * typeInst ) {
+	struct TtypeExpander : public WithShortCircuiting {
+		TypeEnvironment & tenv;
+		TtypeExpander( TypeEnvironment & tenv ) : tenv( tenv ) {}
+		void premutate( TypeInstType * ) { visit_children = false; }
+		Type * postmutate( TypeInstType * typeInst ) {
 			EqvClass eqvClass;
-			if ( env.lookup( typeInst->get_name(), eqvClass ) ) {
+			if ( tenv.lookup( typeInst->get_name(), eqvClass ) ) {
 				if ( eqvClass.data.kind == TypeDecl::Ttype ) {
 					// expand ttype parameter into its actual type
@@ -560,5 +562,5 @@
 		dst.clear();
 		for ( DeclarationWithType * dcl : src ) {
-			TtypeExpander expander( env );
+			PassVisitor<TtypeExpander> expander( env );
 			dcl->acceptMutator( expander );
 			std::list< Type * > types;
@@ -750,5 +752,5 @@
 			std::list<Type *> types1, types2;
 
-			TtypeExpander expander( env );
+			PassVisitor<TtypeExpander> expander( env );
 			flat1->acceptMutator( expander );
 			flat2->acceptMutator( expander );
