Index: src/CodeGen/GenType.cc
===================================================================
--- src/CodeGen/GenType.cc	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/CodeGen/GenType.cc	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -26,24 +26,26 @@
 
 namespace CodeGen {
-	class GenType : public Visitor {
-	  public:
+	struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting {
 		GenType( const std::string &typeString, bool pretty = false, bool genC = false, bool lineMarks = false );
 		std::string get_typeString() const { return typeString; }
 		void set_typeString( const std::string &newValue ) { typeString = newValue; }
 
-		virtual void visit( FunctionType *funcType );
-		virtual void visit( VoidType *voidType );
-		virtual void visit( BasicType *basicType );
-		virtual void visit( PointerType *pointerType );
-		virtual void visit( ArrayType *arrayType );
-		virtual void visit( ReferenceType *refType );
-		virtual void visit( StructInstType *structInst );
-		virtual void visit( UnionInstType *unionInst );
-		virtual void visit( EnumInstType *enumInst );
-		virtual void visit( TypeInstType *typeInst );
-		virtual void visit( TupleType * tupleType );
-		virtual void visit( VarArgsType *varArgsType );
-		virtual void visit( ZeroType *zeroType );
-		virtual void visit( OneType *oneType );
+		void previsit( BaseSyntaxNode * );
+		void postvisit( BaseSyntaxNode * );
+
+		void postvisit( FunctionType * funcType );
+		void postvisit( VoidType * voidType );
+		void postvisit( BasicType * basicType );
+		void postvisit( PointerType * pointerType );
+		void postvisit( ArrayType * arrayType );
+		void postvisit( ReferenceType * refType );
+		void postvisit( StructInstType * structInst );
+		void postvisit( UnionInstType * unionInst );
+		void postvisit( EnumInstType * enumInst );
+		void postvisit( TypeInstType * typeInst );
+		void postvisit( TupleType  * tupleType );
+		void postvisit( VarArgsType * varArgsType );
+		void postvisit( ZeroType * zeroType );
+		void postvisit( OneType * oneType );
 
 	  private:
@@ -59,5 +61,5 @@
 
 	std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) {
-		GenType gt( baseString, pretty, genC, lineMarks );
+		PassVisitor<GenType> gt( baseString, pretty, genC, lineMarks );
 		std::ostringstream os;
 
@@ -68,5 +70,5 @@
 
 		type->accept( gt );
-		return os.str() + gt.get_typeString();
+		return os.str() + gt.pass.get_typeString();
 	}
 
@@ -77,11 +79,24 @@
 	GenType::GenType( const std::string &typeString, bool pretty, bool genC, bool lineMarks ) : typeString( typeString ), pretty( pretty ), genC( genC ), lineMarks( lineMarks ) {}
 
-	void GenType::visit( VoidType *voidType ) {
+	// *** BaseSyntaxNode
+	void GenType::previsit( BaseSyntaxNode * ) {
+		// turn off automatic recursion for all nodes, to allow each visitor to
+		// precisely control the order in which its children are visited.
+		visit_children = false;
+	}
+
+	void GenType::postvisit( BaseSyntaxNode * node ) {
+		std::stringstream ss;
+		node->print( ss );
+		assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );
+	}
+
+	void GenType::postvisit( VoidType * voidType ) {
 		typeString = "void " + typeString;
 		handleQualifiers( voidType );
 	}
 
-	void GenType::visit( BasicType *basicType ) {
-		BasicType::Kind kind = basicType->get_kind();
+	void GenType::postvisit( BasicType * basicType ) {
+		BasicType::Kind kind = basicType->kind;
 		assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES );
 		typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString;
@@ -89,5 +104,5 @@
 	}
 
-	void GenType::genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic ) {
+	void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool isStatic ) {
 		std::ostringstream os;
 		if ( typeString != "" ) {
@@ -126,11 +141,11 @@
 		typeString = os.str();
 
-		base->accept( *this );
-	}
-
-	void GenType::visit( PointerType *pointerType ) {
-		assert( pointerType->get_base() != 0);
-		if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->get_dimension() ) {
-			genArray( pointerType->get_qualifiers(), pointerType->get_base(), pointerType->get_dimension(), pointerType->get_isVarLen(), pointerType->get_isStatic() );
+		base->accept( *visitor );
+	}
+
+	void GenType::postvisit( PointerType * pointerType ) {
+		assert( pointerType->base != 0);
+		if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) {
+			genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() );
 		} else {
 			handleQualifiers( pointerType );
@@ -140,21 +155,21 @@
 				typeString = "*" + typeString;
 			} // if
-			pointerType->get_base()->accept( *this );
-		} // if
-	}
-
-	void GenType::visit( ArrayType *arrayType ) {
-		genArray( arrayType->get_qualifiers(), arrayType->get_base(), arrayType->get_dimension(), arrayType->get_isVarLen(), arrayType->get_isStatic() );
-	}
-
-	void GenType::visit( ReferenceType *refType ) {
-		assert( refType->get_base() != 0);
+			pointerType->base->accept( *visitor );
+		} // if
+	}
+
+	void GenType::postvisit( ArrayType * arrayType ) {
+		genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() );
+	}
+
+	void GenType::postvisit( ReferenceType * refType ) {
+		assert( refType->base != 0);
 		assertf( ! genC, "Reference types should not reach code generation." );
 		handleQualifiers( refType );
 		typeString = "&" + typeString;
-		refType->get_base()->accept( *this );
-	}
-
-	void GenType::visit( FunctionType *funcType ) {
+		refType->base->accept( *visitor );
+	}
+
+	void GenType::postvisit( FunctionType * funcType ) {
 		std::ostringstream os;
 
@@ -169,5 +184,5 @@
 		/************* parameters ***************/
 
-		const std::list<DeclarationWithType *> &pars = funcType->get_parameters();
+		const std::list<DeclarationWithType *> &pars = funcType->parameters;
 
 		if ( pars.empty() ) {
@@ -191,17 +206,17 @@
 		typeString = os.str();
 
-		if ( funcType->get_returnVals().size() == 0 ) {
+		if ( funcType->returnVals.size() == 0 ) {
 			typeString = "void " + typeString;
 		} else {
-			funcType->get_returnVals().front()->get_type()->accept( *this );
+			funcType->returnVals.front()->get_type()->accept( *visitor );
 		} // if
 
 		// add forall
-		if( ! funcType->get_forall().empty() && ! genC ) {
+		if( ! funcType->forall.empty() && ! genC ) {
 			// assertf( ! genC, "Aggregate type parameters should not reach code generation." );
 			std::ostringstream os;
 			PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
 			os << "forall(";
-			cg.pass.genCommaList( funcType->get_forall().begin(), funcType->get_forall().end() );
+			cg.pass.genCommaList( funcType->forall.begin(), funcType->forall.end() );
 			os << ")" << std::endl;
 			typeString = os.str() + typeString;
@@ -221,28 +236,28 @@
 	}
 
-	void GenType::visit( StructInstType *structInst )  {
-		typeString = structInst->get_name() + handleGeneric( structInst ) + " " + typeString;
+	void GenType::postvisit( StructInstType * structInst )  {
+		typeString = structInst->name + handleGeneric( structInst ) + " " + typeString;
 		if ( genC ) typeString = "struct " + typeString;
 		handleQualifiers( structInst );
 	}
 
-	void GenType::visit( UnionInstType *unionInst ) {
-		typeString = unionInst->get_name() + handleGeneric( unionInst ) + " " + typeString;
+	void GenType::postvisit( UnionInstType * unionInst ) {
+		typeString = unionInst->name + handleGeneric( unionInst ) + " " + typeString;
 		if ( genC ) typeString = "union " + typeString;
 		handleQualifiers( unionInst );
 	}
 
-	void GenType::visit( EnumInstType *enumInst ) {
-		typeString = enumInst->get_name() + " " + typeString;
+	void GenType::postvisit( EnumInstType * enumInst ) {
+		typeString = enumInst->name + " " + typeString;
 		if ( genC ) typeString = "enum " + typeString;
 		handleQualifiers( enumInst );
 	}
 
-	void GenType::visit( TypeInstType *typeInst ) {
-		typeString = typeInst->get_name() + " " + typeString;
+	void GenType::postvisit( TypeInstType * typeInst ) {
+		typeString = typeInst->name + " " + typeString;
 		handleQualifiers( typeInst );
 	}
 
-	void GenType::visit( TupleType * tupleType ) {
+	void GenType::postvisit( TupleType * tupleType ) {
 		assertf( ! genC, "Tuple types should not reach code generation." );
 		unsigned int i = 0;
@@ -257,10 +272,10 @@
 	}
 
-	void GenType::visit( VarArgsType *varArgsType ) {
+	void GenType::postvisit( VarArgsType * varArgsType ) {
 		typeString = "__builtin_va_list " + typeString;
 		handleQualifiers( varArgsType );
 	}
 
-	void GenType::visit( ZeroType *zeroType ) {
+	void GenType::postvisit( ZeroType * zeroType ) {
 		// ideally these wouldn't hit codegen at all, but should be safe to make them ints
 		typeString = (pretty ? "zero_t " : "long int ") + typeString;
@@ -268,5 +283,5 @@
 	}
 
-	void GenType::visit( OneType *oneType ) {
+	void GenType::postvisit( OneType * oneType ) {
 		// ideally these wouldn't hit codegen at all, but should be safe to make them ints
 		typeString = (pretty ? "one_t " : "long int ") + typeString;
@@ -274,5 +289,5 @@
 	}
 
-	void GenType::handleQualifiers( Type *type ) {
+	void GenType::handleQualifiers( Type * type ) {
 		if ( type->get_const() ) {
 			typeString = "const " + typeString;
Index: src/CodeTools/DeclStats.cc
===================================================================
--- src/CodeTools/DeclStats.cc	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/CodeTools/DeclStats.cc	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -23,4 +23,5 @@
 #include <utility>                 // for pair, make_pair
 
+#include "Common/PassVisitor.h"
 #include "Common/SemanticError.h"  // for SemanticError
 #include "Common/VectorMap.h"      // for VectorMap
@@ -35,5 +36,5 @@
 namespace CodeTools {
 
-	class DeclStats : public Visitor {
+	struct DeclStats : public WithShortCircuiting {
 		template<typename T>
 		static void sum(T& a, const T& b) { a += b; }
@@ -126,7 +127,7 @@
 			ArgPackStats assn_returns;
 
-			Stats() : n_decls(0), n_type_params(), n_generic_params(), n_generic_nesting(), 
-				by_name(), basic_type_names(), generic_type_names(), compound_type_names(), 
-				basic_type_decls(), generic_type_decls(), compound_type_decls(), params(), 
+			Stats() : n_decls(0), n_type_params(), n_generic_params(), n_generic_nesting(),
+				by_name(), basic_type_names(), generic_type_names(), compound_type_names(),
+				basic_type_decls(), generic_type_decls(), compound_type_decls(), params(),
 				returns(), n_assns(), assn_params(), assn_returns() {}
 
@@ -165,6 +166,6 @@
 		std::map<std::pair<unsigned, unsigned>, unsigned> exprs_by_fanout_at_depth;
 
-		void countType( const std::string& name, unsigned& n, std::unordered_map<std::string, 
-				unsigned>& names, std::unordered_map<std::string, unsigned>& decls, 
+		void countType( const std::string& name, unsigned& n, std::unordered_map<std::string,
+				unsigned>& names, std::unordered_map<std::string, unsigned>& decls,
 				std::unordered_set<std::string>& elSeen ) {
 			++n;
@@ -177,5 +178,5 @@
 		}
 
-		void analyzeSubtype( Type* ty, Stats& stats, std::unordered_set<std::string>& elSeen, 
+		void analyzeSubtype( Type* ty, Stats& stats, std::unordered_set<std::string>& elSeen,
 				unsigned& n_poly, bool& seen_poly, unsigned& max_depth, unsigned depth ) {
 			unsigned x;
@@ -183,6 +184,6 @@
 		}
 
-		void analyzeSubtypes( std::list<DeclarationWithType*>& tys, Stats& stats, 
-				std::unordered_set<std::string>& elSeen, unsigned& n_poly, bool& seen_poly, 
+		void analyzeSubtypes( std::list<DeclarationWithType*>& tys, Stats& stats,
+				std::unordered_set<std::string>& elSeen, unsigned& n_poly, bool& seen_poly,
 				unsigned& max_depth, unsigned depth, unsigned& n_subs ) {
 			for ( DeclarationWithType* dwt : tys ) {
@@ -193,6 +194,6 @@
 		}
 
-		void analyzeSubtypes( std::list<Expression*>& tys, Stats& stats, 
-				std::unordered_set<std::string>& elSeen, unsigned& n_poly, bool& seen_poly, 
+		void analyzeSubtypes( std::list<Expression*>& tys, Stats& stats,
+				std::unordered_set<std::string>& elSeen, unsigned& n_poly, bool& seen_poly,
 				unsigned& max_depth, unsigned depth ) {
 			for ( Expression* expr : tys ) {
@@ -204,6 +205,6 @@
 		}
 
-		void analyzeSubtypes( std::list<Type*>& tys, Stats& stats, 
-				std::unordered_set<std::string>& elSeen, unsigned& n_poly, bool& seen_poly, 
+		void analyzeSubtypes( std::list<Type*>& tys, Stats& stats,
+				std::unordered_set<std::string>& elSeen, unsigned& n_poly, bool& seen_poly,
 				unsigned& max_depth, unsigned depth ) {
 			for ( Type* ty : tys ) {
@@ -212,6 +213,6 @@
 		}
 
-		void analyzeType( Type* ty, Stats& stats, std::unordered_set<std::string>& elSeen, 
-				unsigned& n_basic, unsigned& n_generic, unsigned& n_poly, unsigned& n_agg,  
+		void analyzeType( Type* ty, Stats& stats, std::unordered_set<std::string>& elSeen,
+				unsigned& n_basic, unsigned& n_generic, unsigned& n_poly, unsigned& n_agg,
 				bool& seen_poly, unsigned& max_depth, unsigned depth = 0 ) {
 			if ( BasicType* bt = dynamic_cast<BasicType*>(ty) ) {
@@ -221,33 +222,33 @@
 			} else if ( PointerType* pt = dynamic_cast<PointerType*>(ty) ) {
 				std::string name = "*";
-				countType( 
+				countType(
 					name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
-				analyzeSubtype( 
+				analyzeSubtype(
 					pt->get_base(), stats, elSeen, n_poly, seen_poly, max_depth, depth );
 				++stats.n_generic_params.at( 1 );
 			} else if ( ArrayType* at = dynamic_cast<ArrayType*>(ty) ) {
 				std::string name = "[]";
-				countType( 
+				countType(
 					name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
-				analyzeSubtype( 
+				analyzeSubtype(
 					at->get_base(), stats, elSeen, n_poly, seen_poly, max_depth, depth );
 				++stats.n_generic_params.at( 1 );
 			} else if ( ReferenceType* rt = dynamic_cast<ReferenceType*>(ty) ) {
 				std::string name = "&";
-				countType( 
+				countType(
 					name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
-				analyzeSubtype( 
+				analyzeSubtype(
 					rt->get_base(), stats, elSeen, n_poly, seen_poly, max_depth, depth );
 				++stats.n_generic_params.at( 1 );
 			} else if ( FunctionType* ft = dynamic_cast<FunctionType*>(ty) ) {
 				std::string name = "(*)";
-				countType( 
+				countType(
 					name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
 				unsigned n_subs = 0;
-				analyzeSubtypes( 
-					ft->get_returnVals(), stats, elSeen, n_poly, seen_poly, max_depth, depth, 
+				analyzeSubtypes(
+					ft->get_returnVals(), stats, elSeen, n_poly, seen_poly, max_depth, depth,
 					n_subs );
-				analyzeSubtypes( 
-					ft->get_parameters(), stats, elSeen, n_poly, seen_poly, max_depth, depth, 
+				analyzeSubtypes(
+					ft->get_parameters(), stats, elSeen, n_poly, seen_poly, max_depth, depth,
 					n_subs );
 				++stats.n_generic_params.at( n_subs );
@@ -257,6 +258,6 @@
 					seen_poly = true;
 				}
-				countType( 
-					vt->get_name(), n_agg, stats.compound_type_names, stats.compound_type_decls, 
+				countType(
+					vt->get_name(), n_agg, stats.compound_type_names, stats.compound_type_decls,
 					elSeen );
 				update_max( max_depth, depth );
@@ -264,11 +265,11 @@
 				std::list<Expression*>& params = st->get_parameters();
 				if ( params.empty() ) {
-					countType( 
-						st->get_name(), n_agg, stats.compound_type_names, 
+					countType(
+						st->get_name(), n_agg, stats.compound_type_names,
 						stats.compound_type_decls, elSeen );
 					update_max( max_depth, depth );
 				} else {
-					countType( 
-						st->get_name(), n_generic, stats.generic_type_names, 
+					countType(
+						st->get_name(), n_generic, stats.generic_type_names,
 						stats.generic_type_decls, elSeen);
 					analyzeSubtypes( params, stats, elSeen, n_poly, seen_poly, max_depth, depth );
@@ -277,12 +278,12 @@
 			} else if ( TupleType* tt = dynamic_cast<TupleType*>(ty) ) {
 				std::string name = "[,]";
-				countType( 
+				countType(
 					name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
-				analyzeSubtypes( 
+				analyzeSubtypes(
 					tt->get_types(), stats, elSeen, n_poly, seen_poly, max_depth, depth );
 				++stats.n_generic_params.at( tt->size() );
 			} else if ( dynamic_cast<VarArgsType*>(ty) ) {
 				std::string name = "...";
-				countType( 
+				countType(
 					name, n_agg, stats.compound_type_names, stats.compound_type_decls, elSeen );
 				update_max( max_depth, depth );
@@ -299,6 +300,6 @@
 
 		/// Update arg pack stats based on a declaration list
-		void analyze( Stats& stats, std::unordered_set<std::string>& seen, 
-				std::unordered_set<std::string>& elSeen, ArgPackStats& pstats, 
+		void analyze( Stats& stats, std::unordered_set<std::string>& seen,
+				std::unordered_set<std::string>& elSeen, ArgPackStats& pstats,
 				std::list<DeclarationWithType*>& decls ) {
 			std::unordered_set<std::string> types;
@@ -309,5 +310,5 @@
 			unsigned n_agg = 0;             ///< number of non-generic aggregate types
 			unsigned n_new = 0;             ///< number of new types
-			
+
 			for ( auto decl : decls ) {
 				Type* dt = decl->get_type();
@@ -322,9 +323,9 @@
 				bool seen_poly = false;
 				unsigned max_depth = 0;
-				analyzeType( 
+				analyzeType(
 					dt, stats, elSeen, n_basic, n_generic, n_poly, n_agg, seen_poly, max_depth );
 				++stats.n_generic_nesting.at( max_depth );
 			}
-			
+
 			++pstats.n.at( n );
 			++pstats.n_basic.at( n_basic );
@@ -362,46 +363,37 @@
 
 	public:
-		using Visitor::visit;
-
-		virtual void visit( FunctionDecl *decl ) {
+		void previsit( FunctionDecl *decl ) {
 			// skip if already seen declaration for this function
-			const std::string& mangleName = decl->get_mangleName().empty() ? decl->get_name() : decl->get_mangleName();
-			if ( ! seen_names.insert( mangleName ).second ) {
-				maybeAccept( decl->get_statements(), *this );
-				return;
-			}
-
-			Stats& stats = for_linkage[ ind_for_linkage[ decl->get_linkage() ] ];
-
-			++stats.n_decls;
-			FunctionType* fnTy = decl->get_functionType();
-			const Type::ForallList& forall = fnTy->get_forall();
-			++stats.n_type_params.at( forall.size() );
-			unsigned n_assns = 0;
-			for ( TypeDecl* fdecl : forall ) {
-				n_assns += fdecl->get_assertions().size();
-				for ( DeclarationWithType* assn : fdecl->get_assertions() ) {
-					FunctionType *assnTy = 0;
-					if ( ObjectDecl *assnObj = dynamic_cast<ObjectDecl*>(assn) ) {
-						if ( PointerType *ptrTy = dynamic_cast<PointerType*>(assnObj->get_type()) ) {
-							assnTy = dynamic_cast<FunctionType*>(ptrTy->get_base());
-						} else assnTy = dynamic_cast<FunctionType*>(assnObj->get_type());
-					} else if ( FunctionDecl *assnDecl = dynamic_cast<FunctionDecl*>(assn) ) {
-						assnTy = assnDecl->get_functionType();
+			const std::string& mangleName = decl->get_mangleName().empty() ? decl->name : decl->get_mangleName();
+			if ( seen_names.insert( mangleName ).second ) {
+				Stats& stats = for_linkage[ ind_for_linkage[ decl->linkage ] ];
+
+				++stats.n_decls;
+				FunctionType* fnTy = decl->type;
+				const Type::ForallList& forall = fnTy->forall;
+				++stats.n_type_params.at( forall.size() );
+				unsigned n_assns = 0;
+				for ( TypeDecl* fdecl : forall ) {
+					n_assns += fdecl->assertions.size();
+					for ( DeclarationWithType* assn : fdecl->assertions ) {
+						FunctionType *assnTy = nullptr;
+						if ( ObjectDecl *assnObj = dynamic_cast<ObjectDecl*>(assn) ) {
+							if ( PointerType *ptrTy = dynamic_cast<PointerType*>(assnObj->get_type()) ) {
+								assnTy = dynamic_cast<FunctionType*>(ptrTy->base);
+							} else assnTy = dynamic_cast<FunctionType*>(assnObj->get_type());
+						} else if ( FunctionDecl *assnDecl = dynamic_cast<FunctionDecl*>(assn) ) {
+							assnTy = assnDecl->type;
+						}
+						if ( assnTy ) analyzeFunc( assnTy, stats, stats.assn_params, stats.assn_returns );
 					}
-					if ( assnTy ) analyzeFunc( assnTy, stats, stats.assn_params, stats.assn_returns );
-				}
-			}
-			++stats.n_assns[ n_assns ];
-
-			++stats.by_name[ decl->get_name() ];
-
-			analyzeFunc( fnTy, stats, stats.params, stats.returns );
-
-			// analyze expressions in decl statements
-			maybeAccept( decl->get_statements(), *this );
-		}
-
-		virtual void visit( UntypedExpr *expr ) {
+				}
+				++stats.n_assns[ n_assns ];
+				++stats.by_name[ decl->name ];
+				analyzeFunc( fnTy, stats, stats.params, stats.returns );
+			}
+		}
+
+		void previsit( UntypedExpr *expr ) {
+			visit_children = false;
 			analyzeExpr( expr, 0 );
 		}
@@ -536,11 +528,11 @@
 	};
 
-	const unsigned DeclStats::ind_for_linkage[] 
+	const unsigned DeclStats::ind_for_linkage[]
 		= { 7, 7, 2, 1,   7, 7, 7, 3,   4, 7, 6, 5,   7, 7, 7, 0 };
 
 	void printDeclStats( std::list< Declaration * > &translationUnit ) {
-		DeclStats stats;
+		PassVisitor<DeclStats> stats;
 		acceptAll( translationUnit, stats );
-		stats.print();
+		stats.pass.print();
 	}
 
Index: src/Common/PassVisitor.h
===================================================================
--- src/Common/PassVisitor.h	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/Common/PassVisitor.h	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -119,4 +119,6 @@
 	virtual void visit( StmtExpr *  stmtExpr ) override final;
 	virtual void visit( UniqueExpr *  uniqueExpr ) override final;
+	virtual void visit( UntypedInitExpr *  initExpr ) override final;
+	virtual void visit( InitExpr *  initExpr ) override final;
 
 	virtual void visit( VoidType * basicType ) override final;
@@ -211,4 +213,6 @@
 	virtual Expression * mutate( StmtExpr *  stmtExpr ) override final;
 	virtual Expression * mutate( UniqueExpr *  uniqueExpr ) override final;
+	virtual Expression * mutate( UntypedInitExpr *  initExpr ) override final;
+	virtual Expression * mutate( InitExpr *  initExpr ) override final;
 
 	virtual Type * mutate( VoidType * basicType ) override final;
Index: src/Common/PassVisitor.impl.h
===================================================================
--- src/Common/PassVisitor.impl.h	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/Common/PassVisitor.impl.h	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -1853,4 +1853,54 @@
 }
 
+//--------------------------------------------------------------------------
+// UntypedInitExpr
+template< typename pass_type >
+void PassVisitor< pass_type >::visit( UntypedInitExpr * node ) {
+	VISIT_START( node );
+
+	indexerScopedAccept( node->result, *this );
+	maybeAccept_impl   ( node->expr  , *this );
+	// not currently visiting initAlts, but this doesn't matter since this node is only used in the resolver.
+
+	VISIT_END( node );
+}
+
+template< typename pass_type >
+Expression * PassVisitor< pass_type >::mutate( UntypedInitExpr * node ) {
+	MUTATE_START( node );
+
+	indexerScopedMutate( node->env   , *this );
+	indexerScopedMutate( node->result, *this );
+	maybeMutate_impl   ( node->expr  , *this );
+	// not currently visiting initAlts, but this doesn't matter since this node is only used in the resolver.
+
+	MUTATE_END( Expression, node );
+}
+
+//--------------------------------------------------------------------------
+// InitExpr
+template< typename pass_type >
+void PassVisitor< pass_type >::visit( InitExpr * node ) {
+	VISIT_START( node );
+
+	indexerScopedAccept( node->result, *this );
+	maybeAccept_impl   ( node->expr  , *this );
+	maybeAccept_impl   ( node->designation, *this );
+
+	VISIT_END( node );
+}
+
+template< typename pass_type >
+Expression * PassVisitor< pass_type >::mutate( InitExpr * node ) {
+	MUTATE_START( node );
+
+	indexerScopedMutate( node->env   , *this );
+	indexerScopedMutate( node->result, *this );
+	maybeMutate_impl   ( node->expr  , *this );
+	maybeMutate_impl   ( node->designation, *this );
+
+	MUTATE_END( Expression, node );
+}
+
 template< typename pass_type >
 void PassVisitor< pass_type >::visit( VoidType * node ) {
Index: src/ControlStruct/ExceptTranslate.cc
===================================================================
--- src/ControlStruct/ExceptTranslate.cc	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/ControlStruct/ExceptTranslate.cc	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -316,6 +316,5 @@
 				VarExprReplacer::DeclMap mapping;
 				mapping[ handler_decl ] = local_except;
-				VarExprReplacer mapper( mapping );
-				handler->get_body()->accept( mapper );
+				VarExprReplacer::replace( handler->body, mapping );
 			}
 
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -60,4 +60,65 @@
 
 namespace ResolvExpr {
+	struct AlternativeFinder::Finder : public WithShortCircuiting {
+		Finder( AlternativeFinder & altFinder ) : altFinder( altFinder ), indexer( altFinder.indexer ), alternatives( altFinder.alternatives ), env( altFinder.env ), targetType( altFinder.targetType )  {}
+
+		void previsit( BaseSyntaxNode * ) { visit_children = false; }
+
+		void postvisit( ApplicationExpr * applicationExpr );
+		void postvisit( UntypedExpr * untypedExpr );
+		void postvisit( AddressExpr * addressExpr );
+		void postvisit( LabelAddressExpr * labelExpr );
+		void postvisit( CastExpr * castExpr );
+		void postvisit( VirtualCastExpr * castExpr );
+		void postvisit( UntypedMemberExpr * memberExpr );
+		void postvisit( MemberExpr * memberExpr );
+		void postvisit( NameExpr * variableExpr );
+		void postvisit( VariableExpr * variableExpr );
+		void postvisit( ConstantExpr * constantExpr );
+		void postvisit( SizeofExpr * sizeofExpr );
+		void postvisit( AlignofExpr * alignofExpr );
+		void postvisit( UntypedOffsetofExpr * offsetofExpr );
+		void postvisit( OffsetofExpr * offsetofExpr );
+		void postvisit( OffsetPackExpr * offsetPackExpr );
+		void postvisit( AttrExpr * attrExpr );
+		void postvisit( LogicalExpr * logicalExpr );
+		void postvisit( ConditionalExpr * conditionalExpr );
+		void postvisit( CommaExpr * commaExpr );
+		void postvisit( ImplicitCopyCtorExpr  * impCpCtorExpr );
+		void postvisit( ConstructorExpr  * ctorExpr );
+		void postvisit( RangeExpr  * rangeExpr );
+		void postvisit( UntypedTupleExpr * tupleExpr );
+		void postvisit( TupleExpr * tupleExpr );
+		void postvisit( TupleIndexExpr * tupleExpr );
+		void postvisit( TupleAssignExpr * tupleExpr );
+		void postvisit( UniqueExpr * unqExpr );
+		void postvisit( StmtExpr * stmtExpr );
+		void postvisit( UntypedInitExpr * initExpr );
+
+		/// Adds alternatives for anonymous members
+		void addAnonConversions( const Alternative & alt );
+		/// Adds alternatives for member expressions, given the aggregate, conversion cost for that aggregate, and name of the member
+		template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member );
+		/// Adds alternatives for member expressions where the left side has tuple type
+		void addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member );
+		/// Adds alternatives for offsetof expressions, given the base type and name of the member
+		template< typename StructOrUnionType > void addOffsetof( StructOrUnionType *aggInst, const std::string &name );
+		/// Takes a final result and checks if its assertions can be satisfied
+		template<typename OutputIterator>
+		void validateFunctionAlternative( const Alternative &func, ArgPack& result, const std::vector<ArgPack>& results, OutputIterator out );
+		/// Finds matching alternatives for a function, given a set of arguments
+		template<typename OutputIterator>
+		void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs& args, OutputIterator out );
+		/// Checks if assertion parameters match for a new alternative
+		template< typename OutputIterator >
+		void inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out );
+	private:
+		AlternativeFinder & altFinder;
+		const SymTab::Indexer &indexer;
+		AltList & alternatives;
+		const TypeEnvironment &env;
+		Type *& targetType;
+	};
+
 	Expression *resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer, TypeEnvironment &env ) {
 		CastExpr *castToVoid = new CastExpr( expr );
@@ -152,5 +213,5 @@
 
 		void renameTypes( Expression *expr ) {
-			expr->get_result()->accept( global_renamer );
+			renameTyVars( expr->result );
 		}
 	} // namespace
@@ -185,5 +246,6 @@
 
 	void AlternativeFinder::find( Expression *expr, bool adjust, bool prune, bool failFast ) {
-		expr->accept( *this );
+		PassVisitor<Finder> finder( *this );
+		expr->accept( finder );
 		if ( failFast && alternatives.empty() ) {
 			PRINT(
@@ -244,5 +306,5 @@
 	}
 
-	void AlternativeFinder::addAnonConversions( const Alternative & alt ) {
+	void AlternativeFinder::Finder::addAnonConversions( const Alternative & alt ) {
 		// adds anonymous member interpretations whenever an aggregate value type is seen.
 		// it's okay for the aggregate expression to have reference type -- cast it to the base type to treat the aggregate as the referenced value
@@ -265,5 +327,5 @@
 
 	template< typename StructOrUnionType >
-	void AlternativeFinder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
+	void AlternativeFinder::Finder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
 		// by this point, member must be a name expr
 		NameExpr * nameExpr = dynamic_cast< NameExpr * >( member );
@@ -284,5 +346,5 @@
 	}
 
-	void AlternativeFinder::addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
+	void AlternativeFinder::Finder::addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
 		if ( ConstantExpr * constantExpr = dynamic_cast< ConstantExpr * >( member ) ) {
 			// get the value of the constant expression as an int, must be between 0 and the length of the tuple type to have meaning
@@ -308,5 +370,5 @@
 	}
 
-	void AlternativeFinder::visit( ApplicationExpr *applicationExpr ) {
+	void AlternativeFinder::Finder::postvisit( ApplicationExpr *applicationExpr ) {
 		alternatives.push_back( Alternative( applicationExpr->clone(), env, Cost::zero ) );
 	}
@@ -485,5 +547,5 @@
 			Type *adjType = candidate->get_type()->clone();
 			adjustExprType( adjType, newEnv, indexer );
-			adjType->accept( global_renamer );
+			renameTyVars( adjType );
 			PRINT(
 				std::cerr << "unifying ";
@@ -541,5 +603,5 @@
 
 	template< typename OutputIterator >
-	void AlternativeFinder::inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out ) {
+	void AlternativeFinder::Finder::inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out ) {
 //	PRINT(
 //	    std::cerr << "inferParameters: assertions needed are" << std::endl;
@@ -595,5 +657,5 @@
 
 		ArgPack()
-			: parent(0), expr(), cost(Cost::zero), env(), need(), have(), openVars(), nextArg(0), 
+			: parent(0), expr(), cost(Cost::zero), env(), need(), have(), openVars(), nextArg(0),
 			  tupleStart(0), nextExpl(0), explAlt(0) {}
 
@@ -706,5 +768,5 @@
 
 						if ( nTuples > 0 || ! results[i].expr ) {
-							// first iteration or no expression to clone, 
+							// first iteration or no expression to clone,
 							// push empty tuple expression
 							newResult.parent = i;
@@ -892,5 +954,5 @@
 
 	template<typename OutputIterator>
-	void AlternativeFinder::validateFunctionAlternative( const Alternative &func, ArgPack& result,
+	void AlternativeFinder::Finder::validateFunctionAlternative( const Alternative &func, ArgPack& result,
 			const std::vector<ArgPack>& results, OutputIterator out ) {
 		ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() );
@@ -915,5 +977,5 @@
 
 	template<typename OutputIterator>
-	void AlternativeFinder::makeFunctionAlternatives( const Alternative &func,
+	void AlternativeFinder::Finder::makeFunctionAlternatives( const Alternative &func,
 			FunctionType *funcType, const ExplodedArgs &args, OutputIterator out ) {
 		OpenVarSet funcOpenVars;
@@ -1022,5 +1084,5 @@
 	}
 
-	void AlternativeFinder::visit( UntypedExpr *untypedExpr ) {
+	void AlternativeFinder::Finder::postvisit( UntypedExpr *untypedExpr ) {
 		AlternativeFinder funcFinder( indexer, env );
 		funcFinder.findWithAdjustment( untypedExpr->get_function() );
@@ -1029,10 +1091,10 @@
 
 		std::vector< AlternativeFinder > argAlternatives;
-		findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(),
+		altFinder.findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(),
 			back_inserter( argAlternatives ) );
 
 		// take care of possible tuple assignments
 		// if not tuple assignment, assignment is taken care of as a normal function call
-		Tuples::handleTupleAssignment( *this, untypedExpr, argAlternatives );
+		Tuples::handleTupleAssignment( altFinder, untypedExpr, argAlternatives );
 
 		// find function operators
@@ -1172,5 +1234,5 @@
 			// fix this issue in a more robust way.
 			targetType = nullptr;
-			visit( untypedExpr );
+			postvisit( untypedExpr );
 		}
 	}
@@ -1181,5 +1243,5 @@
 	}
 
-	void AlternativeFinder::visit( AddressExpr *addressExpr ) {
+	void AlternativeFinder::Finder::postvisit( AddressExpr *addressExpr ) {
 		AlternativeFinder finder( indexer, env );
 		finder.find( addressExpr->get_arg() );
@@ -1192,5 +1254,5 @@
 	}
 
-	void AlternativeFinder::visit( LabelAddressExpr * expr ) {
+	void AlternativeFinder::Finder::postvisit( LabelAddressExpr * expr ) {
 		alternatives.push_back( Alternative{ expr->clone(), env, Cost::zero } );
 	}
@@ -1223,5 +1285,5 @@
 	}
 
-	void AlternativeFinder::visit( CastExpr *castExpr ) {
+	void AlternativeFinder::Finder::postvisit( CastExpr *castExpr ) {
 		Type *& toType = castExpr->get_result();
 		assert( toType );
@@ -1278,5 +1340,5 @@
 	}
 
-	void AlternativeFinder::visit( VirtualCastExpr * castExpr ) {
+	void AlternativeFinder::Finder::postvisit( VirtualCastExpr * castExpr ) {
 		assertf( castExpr->get_result(), "Implicate virtual cast targets not yet supported." );
 		AlternativeFinder finder( indexer, env );
@@ -1290,5 +1352,5 @@
 	}
 
-	void AlternativeFinder::visit( UntypedMemberExpr *memberExpr ) {
+	void AlternativeFinder::Finder::postvisit( UntypedMemberExpr *memberExpr ) {
 		AlternativeFinder funcFinder( indexer, env );
 		funcFinder.findWithAdjustment( memberExpr->get_aggregate() );
@@ -1312,9 +1374,9 @@
 	}
 
-	void AlternativeFinder::visit( MemberExpr *memberExpr ) {
+	void AlternativeFinder::Finder::postvisit( MemberExpr *memberExpr ) {
 		alternatives.push_back( Alternative( memberExpr->clone(), env, Cost::zero ) );
 	}
 
-	void AlternativeFinder::visit( NameExpr *nameExpr ) {
+	void AlternativeFinder::Finder::postvisit( NameExpr *nameExpr ) {
 		std::list< SymTab::Indexer::IdData > declList;
 		indexer.lookupId( nameExpr->get_name(), declList );
@@ -1337,5 +1399,5 @@
 	}
 
-	void AlternativeFinder::visit( VariableExpr *variableExpr ) {
+	void AlternativeFinder::Finder::postvisit( VariableExpr *variableExpr ) {
 		// not sufficient to clone here, because variable's type may have changed
 		// since the VariableExpr was originally created.
@@ -1343,9 +1405,9 @@
 	}
 
-	void AlternativeFinder::visit( ConstantExpr *constantExpr ) {
+	void AlternativeFinder::Finder::postvisit( ConstantExpr *constantExpr ) {
 		alternatives.push_back( Alternative( constantExpr->clone(), env, Cost::zero ) );
 	}
 
-	void AlternativeFinder::visit( SizeofExpr *sizeofExpr ) {
+	void AlternativeFinder::Finder::postvisit( SizeofExpr *sizeofExpr ) {
 		if ( sizeofExpr->get_isType() ) {
 			Type * newType = sizeofExpr->get_type()->clone();
@@ -1368,5 +1430,5 @@
 	}
 
-	void AlternativeFinder::visit( AlignofExpr *alignofExpr ) {
+	void AlternativeFinder::Finder::postvisit( AlignofExpr *alignofExpr ) {
 		if ( alignofExpr->get_isType() ) {
 			Type * newType = alignofExpr->get_type()->clone();
@@ -1390,5 +1452,5 @@
 
 	template< typename StructOrUnionType >
-	void AlternativeFinder::addOffsetof( StructOrUnionType *aggInst, const std::string &name ) {
+	void AlternativeFinder::Finder::addOffsetof( StructOrUnionType *aggInst, const std::string &name ) {
 		std::list< Declaration* > members;
 		aggInst->lookup( name, members );
@@ -1403,5 +1465,5 @@
 	}
 
-	void AlternativeFinder::visit( UntypedOffsetofExpr *offsetofExpr ) {
+	void AlternativeFinder::Finder::postvisit( UntypedOffsetofExpr *offsetofExpr ) {
 		AlternativeFinder funcFinder( indexer, env );
 		// xxx - resolveTypeof?
@@ -1413,9 +1475,9 @@
 	}
 
-	void AlternativeFinder::visit( OffsetofExpr *offsetofExpr ) {
+	void AlternativeFinder::Finder::postvisit( OffsetofExpr *offsetofExpr ) {
 		alternatives.push_back( Alternative( offsetofExpr->clone(), env, Cost::zero ) );
 	}
 
-	void AlternativeFinder::visit( OffsetPackExpr *offsetPackExpr ) {
+	void AlternativeFinder::Finder::postvisit( OffsetPackExpr *offsetPackExpr ) {
 		alternatives.push_back( Alternative( offsetPackExpr->clone(), env, Cost::zero ) );
 	}
@@ -1444,5 +1506,5 @@
 	}
 
-	void AlternativeFinder::visit( AttrExpr *attrExpr ) {
+	void AlternativeFinder::Finder::postvisit( AttrExpr *attrExpr ) {
 		// assume no 'pointer-to-attribute'
 		NameExpr *nameExpr = dynamic_cast< NameExpr* >( attrExpr->get_attr() );
@@ -1458,5 +1520,5 @@
 					if ( function->get_parameters().size() == 1 ) {
 						if ( attrExpr->get_isType() ) {
-							resolveAttr( data, function, attrExpr->get_type(), env, *this );
+							resolveAttr( data, function, attrExpr->get_type(), env, altFinder);
 						} else {
 							AlternativeFinder finder( indexer, env );
@@ -1464,5 +1526,5 @@
 							for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) {
 								if ( choice->expr->get_result()->size() == 1 ) {
-									resolveAttr(data, function, choice->expr->get_result(), choice->env, *this );
+									resolveAttr(data, function, choice->expr->get_result(), choice->env, altFinder );
 								} // fi
 							} // for
@@ -1479,5 +1541,5 @@
 	}
 
-	void AlternativeFinder::visit( LogicalExpr *logicalExpr ) {
+	void AlternativeFinder::Finder::postvisit( LogicalExpr *logicalExpr ) {
 		AlternativeFinder firstFinder( indexer, env );
 		firstFinder.findWithAdjustment( logicalExpr->get_arg1() );
@@ -1492,5 +1554,5 @@
 	}
 
-	void AlternativeFinder::visit( ConditionalExpr *conditionalExpr ) {
+	void AlternativeFinder::Finder::postvisit( ConditionalExpr *conditionalExpr ) {
 		// find alternatives for condition
 		AlternativeFinder firstFinder( indexer, env );
@@ -1524,5 +1586,5 @@
 	}
 
-	void AlternativeFinder::visit( CommaExpr *commaExpr ) {
+	void AlternativeFinder::Finder::postvisit( CommaExpr *commaExpr ) {
 		TypeEnvironment newEnv( env );
 		Expression *newFirstArg = resolveInVoidContext( commaExpr->get_arg1(), indexer, newEnv );
@@ -1535,5 +1597,5 @@
 	}
 
-	void AlternativeFinder::visit( RangeExpr * rangeExpr ) {
+	void AlternativeFinder::Finder::postvisit( RangeExpr * rangeExpr ) {
 		// resolve low and high, accept alternatives whose low and high types unify
 		AlternativeFinder firstFinder( indexer, env );
@@ -1557,7 +1619,7 @@
 	}
 
-	void AlternativeFinder::visit( UntypedTupleExpr *tupleExpr ) {
+	void AlternativeFinder::Finder::postvisit( UntypedTupleExpr *tupleExpr ) {
 		std::vector< AlternativeFinder > subExprAlternatives;
-		findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(),
+		altFinder.findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(),
 			back_inserter( subExprAlternatives ) );
 		std::vector< AltList > possibilities;
@@ -1575,13 +1637,13 @@
 	}
 
-	void AlternativeFinder::visit( TupleExpr *tupleExpr ) {
+	void AlternativeFinder::Finder::postvisit( TupleExpr *tupleExpr ) {
 		alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
 	}
 
-	void AlternativeFinder::visit( ImplicitCopyCtorExpr * impCpCtorExpr ) {
+	void AlternativeFinder::Finder::postvisit( ImplicitCopyCtorExpr * impCpCtorExpr ) {
 		alternatives.push_back( Alternative( impCpCtorExpr->clone(), env, Cost::zero ) );
 	}
 
-	void AlternativeFinder::visit( ConstructorExpr * ctorExpr ) {
+	void AlternativeFinder::Finder::postvisit( ConstructorExpr * ctorExpr ) {
 		AlternativeFinder finder( indexer, env );
 		// don't prune here, since it's guaranteed all alternatives will have the same type
@@ -1593,13 +1655,13 @@
 	}
 
-	void AlternativeFinder::visit( TupleIndexExpr *tupleExpr ) {
+	void AlternativeFinder::Finder::postvisit( TupleIndexExpr *tupleExpr ) {
 		alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
 	}
 
-	void AlternativeFinder::visit( TupleAssignExpr *tupleAssignExpr ) {
+	void AlternativeFinder::Finder::postvisit( TupleAssignExpr *tupleAssignExpr ) {
 		alternatives.push_back( Alternative( tupleAssignExpr->clone(), env, Cost::zero ) );
 	}
 
-	void AlternativeFinder::visit( UniqueExpr *unqExpr ) {
+	void AlternativeFinder::Finder::postvisit( UniqueExpr *unqExpr ) {
 		AlternativeFinder finder( indexer, env );
 		finder.findWithAdjustment( unqExpr->get_expr() );
@@ -1611,5 +1673,5 @@
 	}
 
-	void AlternativeFinder::visit( StmtExpr *stmtExpr ) {
+	void AlternativeFinder::Finder::postvisit( StmtExpr *stmtExpr ) {
 		StmtExpr * newStmtExpr = stmtExpr->clone();
 		ResolvExpr::resolveStmtExpr( newStmtExpr, indexer );
@@ -1618,8 +1680,10 @@
 	}
 
-	void AlternativeFinder::visit( UntypedInitExpr *initExpr ) {
+	void AlternativeFinder::Finder::postvisit( UntypedInitExpr *initExpr ) {
 		// handle each option like a cast
 		AltList candidates;
-		PRINT( std::cerr << "untyped init expr: " << initExpr << std::endl; )
+		PRINT(
+			std::cerr << "untyped init expr: " << initExpr << std::endl;
+		)
 		// O(N^2) checks of d-types with e-types
 		for ( InitAlternative & initAlt : initExpr->get_initAlts() ) {
@@ -1637,5 +1701,7 @@
 				AssertionSet needAssertions, haveAssertions;
 				OpenVarSet openVars;  // find things in env that don't have a "representative type" and claim those are open vars?
-				PRINT( std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl; )
+				PRINT(
+					std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
+				 )
 				// It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
 				// cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
Index: src/ResolvExpr/AlternativeFinder.h
===================================================================
--- src/ResolvExpr/AlternativeFinder.h	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/ResolvExpr/AlternativeFinder.h	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -38,5 +38,5 @@
 	using ExplodedArgs = std::vector< std::vector< ExplodedActual > >;
 
-	class AlternativeFinder : public Visitor {
+	class AlternativeFinder {
 	  public:
 		AlternativeFinder( const SymTab::Indexer &indexer, const TypeEnvironment &env );
@@ -94,53 +94,5 @@
 		void findSubExprs( InputIterator begin, InputIterator end, OutputIterator out );
 	  private:
-		virtual void visit( ApplicationExpr *applicationExpr );
-		virtual void visit( UntypedExpr *untypedExpr );
-		virtual void visit( AddressExpr *addressExpr );
-		virtual void visit( LabelAddressExpr *labelExpr );
-		virtual void visit( CastExpr *castExpr );
-		virtual void visit( VirtualCastExpr *castExpr );
-		virtual void visit( UntypedMemberExpr *memberExpr );
-		virtual void visit( MemberExpr *memberExpr );
-		virtual void visit( NameExpr *variableExpr );
-		virtual void visit( VariableExpr *variableExpr );
-		virtual void visit( ConstantExpr *constantExpr );
-		virtual void visit( SizeofExpr *sizeofExpr );
-		virtual void visit( AlignofExpr *alignofExpr );
-		virtual void visit( UntypedOffsetofExpr *offsetofExpr );
-		virtual void visit( OffsetofExpr *offsetofExpr );
-		virtual void visit( OffsetPackExpr *offsetPackExpr );
-		virtual void visit( AttrExpr *attrExpr );
-		virtual void visit( LogicalExpr *logicalExpr );
-		virtual void visit( ConditionalExpr *conditionalExpr );
-		virtual void visit( CommaExpr *commaExpr );
-		virtual void visit( ImplicitCopyCtorExpr * impCpCtorExpr );
-		virtual void visit( ConstructorExpr * ctorExpr );
-		virtual void visit( RangeExpr * rangeExpr );
-		virtual void visit( UntypedTupleExpr *tupleExpr );
-		virtual void visit( TupleExpr *tupleExpr );
-		virtual void visit( TupleIndexExpr *tupleExpr );
-		virtual void visit( TupleAssignExpr *tupleExpr );
-		virtual void visit( UniqueExpr *unqExpr );
-		virtual void visit( StmtExpr *stmtExpr );
-		virtual void visit( UntypedInitExpr *initExpr );
-
-		/// Adds alternatives for anonymous members
-		void addAnonConversions( const Alternative & alt );
-		/// Adds alternatives for member expressions, given the aggregate, conversion cost for that aggregate, and name of the member
-		template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member );
-		/// Adds alternatives for member expressions where the left side has tuple type
-		void addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member );
-		/// Adds alternatives for offsetof expressions, given the base type and name of the member
-		template< typename StructOrUnionType > void addOffsetof( StructOrUnionType *aggInst, const std::string &name );
-		/// Takes a final result and checks if its assertions can be satisfied
-		template<typename OutputIterator>
-		void validateFunctionAlternative( const Alternative &func, ArgPack& result, const std::vector<ArgPack>& results, OutputIterator out );
-		/// Finds matching alternatives for a function, given a set of arguments
-		template<typename OutputIterator>
-		void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs& args, OutputIterator out );
-		/// Checks if assertion parameters match for a new alternative
-		template< typename OutputIterator >
-		void inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out );
-
+		struct Finder;
 		const SymTab::Indexer &indexer;
 		AltList alternatives;
Index: src/ResolvExpr/CommonType.cc
===================================================================
--- src/ResolvExpr/CommonType.cc	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/ResolvExpr/CommonType.cc	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -18,4 +18,5 @@
 #include <utility>                       // for pair
 
+#include "Common/PassVisitor.h"
 #include "ResolvExpr/TypeEnvironment.h"  // for OpenVarSet, AssertionSet
 #include "SymTab/Indexer.h"              // for Indexer
@@ -29,25 +30,27 @@
 
 namespace ResolvExpr {
-	class CommonType : public Visitor {
-	  public:
+	struct CommonType : public WithShortCircuiting {
 		CommonType( Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );
 		Type *get_result() const { return result; }
+
+		void previsit( BaseSyntaxNode * ) { visit_children = false; }
+
+		void postvisit( VoidType * voidType );
+		void postvisit( BasicType * basicType );
+		void postvisit( PointerType * pointerType );
+		void postvisit( ArrayType * arrayType );
+		void postvisit( ReferenceType * refType );
+		void postvisit( FunctionType * functionType );
+		void postvisit( StructInstType * aggregateUseType );
+		void postvisit( UnionInstType * aggregateUseType );
+		void postvisit( EnumInstType * aggregateUseType );
+		void postvisit( TraitInstType * aggregateUseType );
+		void postvisit( TypeInstType * aggregateUseType );
+		void postvisit( TupleType * tupleType );
+		void postvisit( VarArgsType * varArgsType );
+		void postvisit( ZeroType * zeroType );
+		void postvisit( OneType * oneType );
+
 	  private:
-		virtual void visit( VoidType *voidType );
-		virtual void visit( BasicType *basicType );
-		virtual void visit( PointerType *pointerType );
-		virtual void visit( ArrayType *arrayType );
-		virtual void visit( ReferenceType *refType );
-		virtual void visit( FunctionType *functionType );
-		virtual void visit( StructInstType *aggregateUseType );
-		virtual void visit( UnionInstType *aggregateUseType );
-		virtual void visit( EnumInstType *aggregateUseType );
-		virtual void visit( TraitInstType *aggregateUseType );
-		virtual void visit( TypeInstType *aggregateUseType );
-		virtual void visit( TupleType *tupleType );
-		virtual void visit( VarArgsType *varArgsType );
-		virtual void visit( ZeroType *zeroType );
-		virtual void visit( OneType *oneType );
-
 		template< typename Pointer > void getCommonWithVoidPointer( Pointer* voidPointer, Pointer* otherPointer );
 		template< typename RefType > void handleRefType( RefType *inst, Type *other );
@@ -80,5 +83,5 @@
 
 	Type *commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) {
-		CommonType visitor( type2, widenFirst, widenSecond, indexer, env, openVars );
+		PassVisitor<CommonType> visitor( type2, widenFirst, widenSecond, indexer, env, openVars );
 
 		int depth1 = type1->referenceDepth();
@@ -116,5 +119,5 @@
 
 		type1->accept( visitor );
-		Type *result = visitor.get_result();
+		Type *result = visitor.pass.get_result();
 		if ( ! result ) {
 			// this appears to be handling for opaque type declarations
@@ -188,7 +191,7 @@
 	}
 
-	void CommonType::visit( VoidType * ) {}
-
-	void CommonType::visit( BasicType *basicType ) {
+	void CommonType::postvisit( VoidType * ) {}
+
+	void CommonType::postvisit( BasicType *basicType ) {
 		if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {
 			BasicType::Kind newType = combinedType[ basicType->get_kind() ][ otherBasic->get_kind() ];
@@ -219,5 +222,5 @@
 	}
 
-	void CommonType::visit( PointerType *pointerType ) {
+	void CommonType::postvisit( PointerType *pointerType ) {
 		if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {
 			// std::cerr << "commonType: two pointers: " << pointerType << " / " << otherPointer << std::endl;
@@ -254,7 +257,7 @@
 	}
 
-	void CommonType::visit( ArrayType * ) {}
-
-	void CommonType::visit( ReferenceType *refType ) {
+	void CommonType::postvisit( ArrayType * ) {}
+
+	void CommonType::postvisit( ReferenceType *refType ) {
 		if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {
 			// std::cerr << "commonType: both references: " << refType << " / " << otherRef << std::endl;
@@ -291,21 +294,19 @@
 	}
 
-	void CommonType::visit( FunctionType * ) {}
-	void CommonType::visit( StructInstType * ) {}
-	void CommonType::visit( UnionInstType * ) {}
-
-	void CommonType::visit( EnumInstType *enumInstType ) {
+	void CommonType::postvisit( FunctionType * ) {}
+	void CommonType::postvisit( StructInstType * ) {}
+	void CommonType::postvisit( UnionInstType * ) {}
+
+	void CommonType::postvisit( EnumInstType *enumInstType ) {
 		if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< ZeroType* >( type2 ) || dynamic_cast< OneType* >( type2 ) ) {
 			// reuse BasicType, EnumInstType code by swapping type2 with enumInstType
-			ValueGuard< Type * > temp( type2 );
-			type2 = enumInstType;
-			temp.old->accept( *this );
-		} // if
-	}
-
-	void CommonType::visit( TraitInstType * ) {
-	}
-
-	void CommonType::visit( TypeInstType *inst ) {
+			result = commonType( type2, enumInstType, widenSecond, widenFirst, indexer, env, openVars );
+		} // if
+	}
+
+	void CommonType::postvisit( TraitInstType * ) {
+	}
+
+	void CommonType::postvisit( TypeInstType *inst ) {
 		if ( widenFirst ) {
 			NamedTypeDecl *nt = indexer.lookupType( inst->get_name() );
@@ -329,8 +330,8 @@
 	}
 
-	void CommonType::visit( TupleType * ) {}
-	void CommonType::visit( VarArgsType * ) {}
-
-	void CommonType::visit( ZeroType *zeroType ) {
+	void CommonType::postvisit( TupleType * ) {}
+	void CommonType::postvisit( VarArgsType * ) {}
+
+	void CommonType::postvisit( ZeroType *zeroType ) {
 		if ( widenFirst ) {
 			if ( dynamic_cast< BasicType* >( type2 ) || dynamic_cast< PointerType* >( type2 ) || dynamic_cast< EnumInstType* >( type2 ) ) {
@@ -346,5 +347,5 @@
 	}
 
-	void CommonType::visit( OneType *oneType ) {
+	void CommonType::postvisit( OneType *oneType ) {
 		if ( widenFirst ) {
 			if ( dynamic_cast< BasicType* >( type2 ) || dynamic_cast< EnumInstType* >( type2 ) ) {
Index: src/ResolvExpr/CurrentObject.cc
===================================================================
--- src/ResolvExpr/CurrentObject.cc	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/ResolvExpr/CurrentObject.cc	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -443,5 +443,5 @@
 				return new UnionIterator( uit );
 			} else {
-				assertf( dynamic_cast< TypeInstType * >( type ), "some other reftotype" );
+				assertf( dynamic_cast< EnumInstType * >( type ) || dynamic_cast< TypeInstType * >( type ), "Encountered unhandled ReferenceToType in createMemberIterator: %s", toString( type ).c_str() );
 				return new SimpleIterator( type );
 			}
Index: src/ResolvExpr/PtrsAssignable.cc
===================================================================
--- src/ResolvExpr/PtrsAssignable.cc	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/ResolvExpr/PtrsAssignable.cc	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -14,4 +14,5 @@
 //
 
+#include "Common/PassVisitor.h"
 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
 #include "SynTree/Type.h"                // for TypeInstType, Type, BasicType
@@ -20,24 +21,25 @@
 
 namespace ResolvExpr {
-	class PtrsAssignable : public Visitor {
-	  public:
+	struct PtrsAssignable : public WithShortCircuiting {
 		PtrsAssignable( Type *dest, const TypeEnvironment &env );
 
 		int get_result() const { return result; }
 
-		virtual void visit( VoidType *voidType );
-		virtual void visit( BasicType *basicType );
-		virtual void visit( PointerType *pointerType );
-		virtual void visit( ArrayType *arrayType );
-		virtual void visit( FunctionType *functionType );
-		virtual void visit( StructInstType *inst );
-		virtual void visit( UnionInstType *inst );
-		virtual void visit( EnumInstType *inst );
-		virtual void visit( TraitInstType *inst );
-		virtual void visit( TypeInstType *inst );
-		virtual void visit( TupleType *tupleType );
-		virtual void visit( VarArgsType *varArgsType );
-		virtual void visit( ZeroType *zeroType );
-		virtual void visit( OneType *oneType );
+		void previsit( Type * ) { visit_children = false; }
+
+		void postvisit( VoidType * voidType );
+		void postvisit( BasicType * basicType );
+		void postvisit( PointerType * pointerType );
+		void postvisit( ArrayType * arrayType );
+		void postvisit( FunctionType * functionType );
+		void postvisit( StructInstType * inst );
+		void postvisit( UnionInstType * inst );
+		void postvisit( EnumInstType * inst );
+		void postvisit( TraitInstType * inst );
+		void postvisit( TypeInstType * inst );
+		void postvisit( TupleType * tupleType );
+		void postvisit( VarArgsType * varArgsType );
+		void postvisit( ZeroType * zeroType );
+		void postvisit( OneType * oneType );
 	  private:
 		Type *dest;
@@ -59,7 +61,7 @@
 			return -1;
 		} else {
-			PtrsAssignable ptrs( dest, env );
+			PassVisitor<PtrsAssignable> ptrs( dest, env );
 			src->accept( ptrs );
-			return ptrs.get_result();
+			return ptrs.pass.get_result();
 		} // if
 	}
@@ -67,18 +69,18 @@
 	PtrsAssignable::PtrsAssignable( Type *dest, const TypeEnvironment &env ) : dest( dest ), result( 0 ), env( env ) {}
 
-	void PtrsAssignable::visit( VoidType * ) {
+	void PtrsAssignable::postvisit( VoidType * ) {
 		// T * = void * is disallowed - this is a change from C, where any
 		// void * can be assigned or passed to a non-void pointer without a cast.
 	}
 
-	void PtrsAssignable::visit( __attribute__((unused)) BasicType *basicType ) {}
-	void PtrsAssignable::visit( __attribute__((unused)) PointerType *pointerType ) {}
-	void PtrsAssignable::visit( __attribute__((unused)) ArrayType *arrayType ) {}
-	void PtrsAssignable::visit( __attribute__((unused)) FunctionType *functionType ) {}
+	void PtrsAssignable::postvisit( __attribute__((unused)) BasicType *basicType ) {}
+	void PtrsAssignable::postvisit( __attribute__((unused)) PointerType *pointerType ) {}
+	void PtrsAssignable::postvisit( __attribute__((unused)) ArrayType *arrayType ) {}
+	void PtrsAssignable::postvisit( __attribute__((unused)) FunctionType *functionType ) {}
 
-	void PtrsAssignable::visit(  __attribute__((unused)) StructInstType *inst ) {}
-	void PtrsAssignable::visit(  __attribute__((unused)) UnionInstType *inst ) {}
+	void PtrsAssignable::postvisit(  __attribute__((unused)) StructInstType *inst ) {}
+	void PtrsAssignable::postvisit(  __attribute__((unused)) UnionInstType *inst ) {}
 
-	void PtrsAssignable::visit( EnumInstType * ) {
+	void PtrsAssignable::postvisit( EnumInstType * ) {
 		if ( dynamic_cast< BasicType* >( dest ) ) {
 			// int * = E *, etc. is safe. This isn't technically correct, as each
@@ -91,6 +93,6 @@
 	}
 
-	void PtrsAssignable::visit(  __attribute__((unused)) TraitInstType *inst ) {}
-	void PtrsAssignable::visit( TypeInstType *inst ) {
+	void PtrsAssignable::postvisit(  __attribute__((unused)) TraitInstType *inst ) {}
+	void PtrsAssignable::postvisit( TypeInstType *inst ) {
 		EqvClass eqvClass;
 		if ( env.lookup( inst->get_name(), eqvClass ) && eqvClass.type ) {
@@ -100,8 +102,8 @@
 	}
 
-	void PtrsAssignable::visit(  __attribute__((unused)) TupleType *tupleType ) {}
-	void PtrsAssignable::visit(  __attribute__((unused)) VarArgsType *varArgsType ) {}
-	void PtrsAssignable::visit(  __attribute__((unused)) ZeroType *zeroType ) {}
-	void PtrsAssignable::visit(  __attribute__((unused)) OneType *oneType ) {}
+	void PtrsAssignable::postvisit(  __attribute__((unused)) TupleType *tupleType ) {}
+	void PtrsAssignable::postvisit(  __attribute__((unused)) VarArgsType *varArgsType ) {}
+	void PtrsAssignable::postvisit(  __attribute__((unused)) ZeroType *zeroType ) {}
+	void PtrsAssignable::postvisit(  __attribute__((unused)) OneType *oneType ) {}
 
 } // namespace ResolvExpr
Index: src/ResolvExpr/PtrsCastable.cc
===================================================================
--- src/ResolvExpr/PtrsCastable.cc	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/ResolvExpr/PtrsCastable.cc	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -14,4 +14,5 @@
 //
 
+#include "Common/PassVisitor.h"
 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
 #include "SymTab/Indexer.h"              // for Indexer
@@ -21,7 +22,6 @@
 #include "typeops.h"                     // for ptrsAssignable
 
-
 namespace ResolvExpr {
-	class PtrsCastable : public Visitor {
+	struct PtrsCastable : public WithShortCircuiting  {
 	  public:
 		PtrsCastable( Type *dest, const TypeEnvironment &env, const SymTab::Indexer &indexer );
@@ -29,18 +29,20 @@
 		int get_result() const { return result; }
 
-		virtual void visit(VoidType *voidType);
-		virtual void visit(BasicType *basicType);
-		virtual void visit(PointerType *pointerType);
-		virtual void visit(ArrayType *arrayType);
-		virtual void visit(FunctionType *functionType);
-		virtual void visit(StructInstType *inst);
-		virtual void visit(UnionInstType *inst);
-		virtual void visit(EnumInstType *inst);
-		virtual void visit(TraitInstType *inst);
-		virtual void visit(TypeInstType *inst);
-		virtual void visit(TupleType *tupleType);
-		virtual void visit(VarArgsType *varArgsType);
-		virtual void visit(ZeroType *zeroType);
-		virtual void visit(OneType *oneType);
+		void previsit( Type * ) { visit_children = false; }
+
+		void postvisit( VoidType * voidType );
+		void postvisit( BasicType * basicType );
+		void postvisit( PointerType * pointerType );
+		void postvisit( ArrayType * arrayType );
+		void postvisit( FunctionType * functionType );
+		void postvisit( StructInstType * inst );
+		void postvisit( UnionInstType * inst );
+		void postvisit( EnumInstType * inst );
+		void postvisit( TraitInstType * inst );
+		void postvisit( TypeInstType * inst );
+		void postvisit( TupleType * tupleType );
+		void postvisit( VarArgsType * varArgsType );
+		void postvisit( ZeroType * zeroType );
+		void postvisit( OneType * oneType );
 	  private:
 		Type *dest;
@@ -79,4 +81,5 @@
 			EqvClass eqvClass;
 			if ( env.lookup( destAsTypeInst->get_name(), eqvClass ) ) {
+				// xxx - should this be ptrsCastable?
 				return ptrsAssignable( src, eqvClass.type, env );
 			} // if
@@ -85,7 +88,7 @@
 			return objectCast( src, env, indexer );
 		} else {
-			PtrsCastable ptrs( dest, env, indexer );
+			PassVisitor<PtrsCastable> ptrs( dest, env, indexer );
 			src->accept( ptrs );
-			return ptrs.get_result();
+			return ptrs.pass.get_result();
 		} // if
 	}
@@ -95,34 +98,34 @@
 	}
 
-	void PtrsCastable::visit( VoidType * ) {
+	void PtrsCastable::postvisit( VoidType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( BasicType * ) {
+	void PtrsCastable::postvisit( BasicType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( PointerType * ) {
+	void PtrsCastable::postvisit( PointerType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( ArrayType * ) {
+	void PtrsCastable::postvisit( ArrayType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( FunctionType * ) {
+	void PtrsCastable::postvisit( FunctionType * ) {
 		// result = -1;
 		result = functionCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( StructInstType * ) {
+	void PtrsCastable::postvisit( StructInstType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( UnionInstType * ) {
+	void PtrsCastable::postvisit( UnionInstType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( EnumInstType * ) {
+	void PtrsCastable::postvisit( EnumInstType * ) {
 		if ( dynamic_cast< EnumInstType* >( dest ) ) {
 			result = 1;
@@ -138,24 +141,24 @@
 	}
 
-	void PtrsCastable::visit( TraitInstType * ) {}
+	void PtrsCastable::postvisit( TraitInstType * ) {}
 
-	void PtrsCastable::visit(TypeInstType *inst) {
+	void PtrsCastable::postvisit(TypeInstType *inst) {
 		//result = objectCast( inst, env, indexer ) > 0 && objectCast( dest, env, indexer ) > 0 ? 1 : -1;
 		result = objectCast( inst, env, indexer ) == objectCast( dest, env, indexer ) ? 1 : -1;
 	}
 
-	void PtrsCastable::visit( TupleType * ) {
+	void PtrsCastable::postvisit( TupleType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( VarArgsType * ) {
+	void PtrsCastable::postvisit( VarArgsType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( ZeroType * ) {
+	void PtrsCastable::postvisit( ZeroType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( OneType * ) {
+	void PtrsCastable::postvisit( OneType * ) {
 		result = objectCast( dest, env, indexer );
 	}
Index: src/ResolvExpr/RenameVars.cc
===================================================================
--- src/ResolvExpr/RenameVars.cc	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/ResolvExpr/RenameVars.cc	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -19,4 +19,5 @@
 #include <utility>                 // for pair
 
+#include "Common/PassVisitor.h"
 #include "Common/SemanticError.h"  // for SemanticError
 #include "RenameVars.h"
@@ -27,126 +28,72 @@
 
 namespace ResolvExpr {
-	RenameVars global_renamer;
+	namespace {
+		struct RenameVars {
+			RenameVars();
+			void reset();
 
-	RenameVars::RenameVars() : level( 0 ), resetCount( 0 ) {
-		mapStack.push_front( std::map< std::string, std::string >() );
+			void previsit( TypeInstType * instType );
+			void previsit( Type * );
+			void postvisit( Type * );
+
+		  private:
+			int level, resetCount;
+			std::list< std::map< std::string, std::string > > mapStack;
+		};
+
+		PassVisitor<RenameVars> global_renamer;
+	} // namespace
+
+	void renameTyVars( Type * t ) {
+		t->accept( global_renamer );
 	}
 
-	void RenameVars::reset() {
-		level = 0;
-		resetCount++;
+	void resetTyVarRenaming() {
+		global_renamer.pass.reset();
 	}
 
-	void RenameVars::visit( VoidType *voidType ) {
-		typeBefore( voidType );
-		typeAfter( voidType );
-	}
+	namespace {
+		RenameVars::RenameVars() : level( 0 ), resetCount( 0 ) {
+			mapStack.push_front( std::map< std::string, std::string >() );
+		}
 
-	void RenameVars::visit( BasicType *basicType ) {
-		typeBefore( basicType );
-		typeAfter( basicType );
-	}
+		void RenameVars::reset() {
+			level = 0;
+			resetCount++;
+		}
 
-	void RenameVars::visit( PointerType *pointerType ) {
-		typeBefore( pointerType );
-		maybeAccept( pointerType->get_base(), *this );
-		typeAfter( pointerType );
-	}
+		void RenameVars::previsit( TypeInstType * instType ) {
+			previsit( (Type *)instType );
+			std::map< std::string, std::string >::const_iterator i = mapStack.front().find( instType->name );
+			if ( i != mapStack.front().end() ) {
+				instType->name = i->second;
+			} // if
+		}
 
-	void RenameVars::visit( ArrayType *arrayType ) {
-		typeBefore( arrayType );
-		maybeAccept( arrayType->get_dimension(), *this );
-		maybeAccept( arrayType->get_base(), *this );
-		typeAfter( arrayType );
-	}
+		void RenameVars::previsit( Type * type ) {
+			if ( ! type->forall.empty() ) {
+				// copies current name mapping into new mapping
+				mapStack.push_front( mapStack.front() );
+				// renames all "forall" type names to `_${level}_${name}'
+				for ( auto td : type->forall ) {
+					std::ostringstream output;
+					output << "_" << resetCount << "_" << level << "_" << td->name;
+					std::string newname( output.str() );
+					mapStack.front()[ td->get_name() ] = newname;
+					td->name = newname;
+					// ditto for assertion names, the next level in
+					level++;
+					// acceptAll( td->assertions, *this );
+				} // for
+			} // if
+		}
 
-	void RenameVars::visit( FunctionType *functionType ) {
-		typeBefore( functionType );
-		acceptAll( functionType->get_returnVals(), *this );
-		acceptAll( functionType->get_parameters(), *this );
-		typeAfter( functionType );
-	}
-
-	void RenameVars::visit( StructInstType *aggregateUseType ) {
-		typeBefore( aggregateUseType );
-		acceptAll( aggregateUseType->get_parameters(), *this );
-		typeAfter( aggregateUseType );
-	}
-
-	void RenameVars::visit( UnionInstType *aggregateUseType ) {
-		typeBefore( aggregateUseType );
-		acceptAll( aggregateUseType->get_parameters(), *this );
-		typeAfter( aggregateUseType );
-	}
-
-	void RenameVars::visit( EnumInstType *aggregateUseType ) {
-		typeBefore( aggregateUseType );
-		acceptAll( aggregateUseType->get_parameters(), *this );
-		typeAfter( aggregateUseType );
-	}
-
-	void RenameVars::visit( TraitInstType *aggregateUseType ) {
-		typeBefore( aggregateUseType );
-		acceptAll( aggregateUseType->get_parameters(), *this );
-		typeAfter( aggregateUseType );
-	}
-
-	void RenameVars::visit( TypeInstType *instType ) {
-		typeBefore( instType );
-		std::map< std::string, std::string >::const_iterator i = mapStack.front().find( instType->get_name() );
-		if ( i != mapStack.front().end() ) {
-			instType->set_name( i->second );
-		} else {
-		} // if
-		acceptAll( instType->get_parameters(), *this );
-		typeAfter( instType );
-	}
-
-	void RenameVars::visit( TupleType *tupleType ) {
-		typeBefore( tupleType );
-		acceptAll( tupleType->get_types(), *this );
-		typeAfter( tupleType );
-	}
-
-	void RenameVars::visit( VarArgsType *varArgsType ) {
-		typeBefore( varArgsType );
-		typeAfter( varArgsType );
-	}
-
-	void RenameVars::visit( ZeroType *zeroType ) {
-		typeBefore( zeroType );
-		typeAfter( zeroType );
-	}
-
-	void RenameVars::visit( OneType *oneType ) {
-		typeBefore( oneType );
-		typeAfter( oneType );
-	}
-
-	void RenameVars::typeBefore( Type *type ) {
-		if ( ! type->get_forall().empty() ) {
-			// copies current name mapping into new mapping
-			mapStack.push_front( mapStack.front() );
-			// renames all "forall" type names to `_${level}_${name}'
-			for ( Type::ForallList::iterator i = type->get_forall().begin(); i != type->get_forall().end(); ++i ) {
-				std::ostringstream output;
-				output << "_" << resetCount << "_" << level << "_" << (*i)->get_name();
-				std::string newname( output.str() );
-				mapStack.front()[ (*i)->get_name() ] = newname;
-				(*i)->set_name( newname );
-				// ditto for assertion names, the next level in
-				level++;
-				acceptAll( (*i)->get_assertions(), *this );
-			} // for
-		} // if
-	}
-
-	void RenameVars::typeAfter( Type *type ) {
-		// clears name mapping added by typeBefore()
-		if ( ! type->get_forall().empty() ) {
-			mapStack.pop_front();
-		} // if
-	}
-
+		void RenameVars::postvisit( Type * type ) {
+			// clears name mapping added by typeBefore()
+			if ( ! type->forall.empty() ) {
+				mapStack.pop_front();
+			} // if
+		}
+	} // namespace
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/RenameVars.h
===================================================================
--- src/ResolvExpr/RenameVars.h	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/ResolvExpr/RenameVars.h	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -24,33 +24,9 @@
 
 namespace ResolvExpr {
+	/// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID
+	void renameTyVars( Type * );
 
-	/// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID
-	class RenameVars : public Visitor {
-	  public:
-		RenameVars();
-		void reset();
-	  private:
-		virtual void visit( VoidType *basicType );
-		virtual void visit( BasicType *basicType );
-		virtual void visit( PointerType *pointerType );
-		virtual void visit( ArrayType *arrayType );
-		virtual void visit( FunctionType *functionType );
-		virtual void visit( StructInstType *aggregateUseType );
-		virtual void visit( UnionInstType *aggregateUseType );
-		virtual void visit( EnumInstType *aggregateUseType );
-		virtual void visit( TraitInstType *aggregateUseType );
-		virtual void visit( TypeInstType *aggregateUseType );
-		virtual void visit( TupleType *tupleType );
-		virtual void visit( VarArgsType *varArgsType );
-		virtual void visit( ZeroType *zeroType );
-		virtual void visit( OneType *oneType );
-
-		void typeBefore( Type *type );
-		void typeAfter( Type *type );
-		int level, resetCount;
-		std::list< std::map< std::string, std::string > > mapStack;
-	};
-
-	extern RenameVars global_renamer;
+	/// resets internal state of renamer to avoid overflow
+	void resetTyVarRenaming();
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/ResolvExpr/Resolver.cc	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -132,5 +132,5 @@
 
 	void findVoidExpression( Expression *& untyped, const SymTab::Indexer &indexer ) {
-		global_renamer.reset();
+		resetTyVarRenaming();
 		TypeEnvironment env;
 		Expression *newExpr = resolveInVoidContext( untyped, indexer, env );
Index: src/ResolvExpr/TypeMap.h
===================================================================
--- src/ResolvExpr/TypeMap.h	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ 	(revision )
@@ -1,209 +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.
-//
-// ScopedMap.h --
-//
-// Author           : Aaron B. Moss
-// Created On       : Fri Feb 19 13:55:00 2016
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:37:19 2017
-// Update Count     : 2
-//
-
-#pragma once
-
-#include <map>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "SynTree/Type.h"
-#include "SynTree/Visitor.h"
-
-namespace ResolvExpr {
-
-	/// A map from types to some value; lookup is done by structural decomposition on types.
-	/// The TypeMap stores its values by reference, so stored objects should be kept alive by the caller.
-	/// The scoping mechanism essentially by keeping a list of changes to roll back, then rolling them back
-	/// WARNING: This map is only incompletely and approximately consistent with the resolution rules in Unify.cc;
-	/// it has potential, if extended, to form the basis of a resolver that is more performant than the current
-	/// linear-search-by-unification approach, but is only currently used for finding assignment operators in GenPoly::box.
-	template< typename Value >
-	class TypeMap {
-		/// Map of names to types
-		typedef typename std::map< std::string, Value* > ValueMap;
-		typedef typename ValueMap::iterator ValueMapIterator;
-
-		Value *voidValue;                                     ///< Value for void type
-		Value *basicValue[BasicType::NUMBER_OF_BASIC_TYPES];  ///< Values for basic types
-		Value *pointerValue;                                  ///< Value for all pointer types
-		Value *voidPointerValue;                              ///< Value for void* types
-		Value *functionPointerValue;                          ///< Value for all function pointer types
-		ValueMap structValue;                                 ///< Values for struct types, indexed by name
-		ValueMap unionValue;                                  ///< Values for struct types, indexed by name
-		ValueMap enumValue;                                   ///< Values for struct types, indexed by name
-
-		/// Information needed to roll back one scope change
-		struct Rollback {
-			/// One scope of pointer rollbacks
-			typedef std::vector< std::pair< Value **, Value* > > PointerScope;
-			/// One scope of map rollbacks
-			typedef std::vector< std::pair< ValueMapIterator, Value* > > MapScope;
-
-			PointerScope pointers;  ///< Value pointers to roll back to their previous state
-			MapScope mapNodes;      ///< Value map iterators to roll back to their previous state
-
-			void addRollback( Value **loc, Value *old ) {
-				pointers.push_back( std::make_pair( loc, old ) );
-			}
-
-			void addRollback( ValueMapIterator loc, Value *old ) {
-				mapNodes.push_back( std::make_pair( loc, old ) );
-			}
-		};
-
-		std::vector< Rollback > scopes;  ///< Scope rollback information
-
-		struct Lookup : public Visitor {
-			Lookup( TypeMap<Value> &typeMap ) : typeMap( typeMap ), found( 0 ), toInsert( 0 ) {}
-
-			/// Inserts a new value into the map; returns the old value (if set, NULL otherwise).
-			/// key must be non-null.
-			Value *insert( Type *key, Value *val ) {
-				toInsert = val;
-				key->accept( *this );
-				return found;
-			}
-
-			/// Looks up a value in the map.
-			/// key must be non-null.
-			Value *find( Type *key ) {
-				//toInsert = 0;
-				key->accept( *this );
-				return found;
-			}
-
-			void findAndReplace( Value *&loc ) {
-				found = loc;
-				if ( toInsert ) {
-					typeMap.scopes.back().addRollback( &loc, found );
-					loc = toInsert;
-				}
-			}
-
-			void findAndReplace( ValueMap &map, const std::string &name ) {
-				ValueMapIterator loc = map.find( name );
-				if ( loc != map.end() ) {
-					found = loc->second;
-					if ( toInsert ) {
-						typeMap.scopes.back().addRollback( loc, found );
-						loc->second = toInsert;
-					}
-				} else if ( toInsert ) {
-					loc = map.insert( loc, std::make_pair( name, toInsert ) );
-					typeMap.scopes.back().addRollback( loc, found );
-				}
-			}
-
-			virtual void visit( __attribute__((unused)) VoidType *voidType ) {
-				findAndReplace( typeMap.voidValue );
-			}
-
-			virtual void visit( BasicType *basicType ) {
-				findAndReplace( typeMap.basicValue[basicType->get_kind()] );
-			}
-
-			virtual void visit( PointerType *pointerType ) {
-				// NOTE This is one of the places where the apporoximation of the resolver is (deliberately) poor;
-				// A better version would likely not equate all pointer types to a match.
-				if ( dynamic_cast< FunctionType* >( pointerType->get_base() ) ) {
-					findAndReplace( typeMap.functionPointerValue );
-				} else if ( dynamic_cast< VoidType* >( pointerType->get_base() ) ) {
-					findAndReplace( typeMap.voidPointerValue );
-				} else {
-					findAndReplace( typeMap.pointerValue );
-				}
-			}
-
-			virtual void visit( ArrayType *arrayType ) {
-				if ( dynamic_cast< FunctionType* >( arrayType->get_base() ) ) {
-					findAndReplace( typeMap.functionPointerValue );
-				} else {
-					findAndReplace( typeMap.pointerValue );
-				}
-			}
-
-			virtual void visit( __attribute__((unused)) FunctionType *functionType ) {
-				findAndReplace( typeMap.functionPointerValue );
-			}
-
-			virtual void visit( StructInstType *structType ) {
-				findAndReplace( typeMap.structValue, structType->get_name() );
-			}
-
-			virtual void visit( UnionInstType *unionType ) {
-				findAndReplace( typeMap.unionValue, unionType->get_name() );
-			}
-
-			virtual void visit( EnumInstType *enumType ) {
-				findAndReplace( typeMap.enumValue, enumType->get_name() );
-			}
-
-			TypeMap<Value> &typeMap;  ///< map storage
-			Value *found;             ///< Value found (NULL if none yet)
-			Value *toInsert;          ///< Value to insert (NULL if a lookup)
-		};  // struct Lookup
-		friend struct Lookup;
-
-	public:
-		/// Starts a new scope
-		void beginScope() {
-			Rollback scope;
-			scopes.push_back(scope);
-		}
-
-		/// Ends a scope; rolls back any changes made during that scope
-		void endScope() {
-			Rollback &scope = scopes.back();
-			/// Roll back pointer changes
-			for (unsigned i = 0; i < scope.pointers.size(); ++i) {
-				*scope.pointers[i].first = scope.pointers[i].second;
-			}
-			/// Roll back map changes
-			for (unsigned i = 0; i < scope.mapNodes.size(); ++i) {
-				scope.mapNodes[i].first->second = scope.mapNodes[i].second;
-			}
-			scopes.pop_back();
-		}
-
-		TypeMap() : voidValue( 0 ), pointerValue( 0 ), voidPointerValue( 0 ), functionPointerValue( 0 ), structValue(), unionValue(), enumValue(), scopes() {
-			beginScope();
-			for (int i = 0; i < BasicType::NUMBER_OF_BASIC_TYPES; ++i) { basicValue[i] = 0; }
-		}
-
-		/// Inserts a new value into the map; returns the old value (if set, NULL otherwise).
-		/// key, val must be non-null.
-		Value *insert( Type *key, Value *val ) {
-			Lookup searcher( *this );
-			return searcher.insert( key, val );
-		}
-
-		/// Looks up a value in the map.
-		/// key must be non-null
-		Value *find( Type *key ) {
-			Lookup searcher( *this );
-			return searcher.find( key );
-		}
-
-	}; // class TypeMap
-
-}  // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/ResolvExpr/Unify.cc	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -44,26 +44,28 @@
 namespace ResolvExpr {
 
-	class Unify : public Visitor {
-	  public:
+	struct Unify : public WithShortCircuiting {
 		Unify( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );
 
 		bool get_result() const { return result; }
+
+		void previsit( BaseSyntaxNode * ) { visit_children = false; }
+
+		void postvisit( VoidType * voidType );
+		void postvisit( BasicType * basicType );
+		void postvisit( PointerType * pointerType );
+		void postvisit( ArrayType * arrayType );
+		void postvisit( ReferenceType * refType );
+		void postvisit( FunctionType * functionType );
+		void postvisit( StructInstType * aggregateUseType );
+		void postvisit( UnionInstType * aggregateUseType );
+		void postvisit( EnumInstType * aggregateUseType );
+		void postvisit( TraitInstType * aggregateUseType );
+		void postvisit( TypeInstType * aggregateUseType );
+		void postvisit( TupleType * tupleType );
+		void postvisit( VarArgsType * varArgsType );
+		void postvisit( ZeroType * zeroType );
+		void postvisit( OneType * oneType );
+
 	  private:
-		virtual void visit(VoidType *voidType);
-		virtual void visit(BasicType *basicType);
-		virtual void visit(PointerType *pointerType);
-		virtual void visit(ArrayType *arrayType);
-		virtual void visit(ReferenceType *refType);
-		virtual void visit(FunctionType *functionType);
-		virtual void visit(StructInstType *aggregateUseType);
-		virtual void visit(UnionInstType *aggregateUseType);
-		virtual void visit(EnumInstType *aggregateUseType);
-		virtual void visit(TraitInstType *aggregateUseType);
-		virtual void visit(TypeInstType *aggregateUseType);
-		virtual void visit(TupleType *tupleType);
-		virtual void visit(VarArgsType *varArgsType);
-		virtual void visit(ZeroType *zeroType);
-		virtual void visit(OneType *oneType);
-
 		template< typename RefType > void handleRefType( RefType *inst, Type *other );
 		template< typename RefType > void handleGenericRefType( RefType *inst, Type *other );
@@ -325,7 +327,7 @@
 			result = bindVar( var2, type1, entry2->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
 		} else {
-			Unify comparator( type2, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
+			PassVisitor<Unify> comparator( type2, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
 			type1->accept( comparator );
-			result = comparator.get_result();
+			result = comparator.pass.get_result();
 		} // if
 #ifdef DEBUG
@@ -404,9 +406,9 @@
 	}
 
-	void Unify::visit( __attribute__((unused)) VoidType *voidType) {
+	void Unify::postvisit( __attribute__((unused)) VoidType *voidType) {
 		result = dynamic_cast< VoidType* >( type2 );
 	}
 
-	void Unify::visit(BasicType *basicType) {
+	void Unify::postvisit(BasicType *basicType) {
 		if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {
 			result = basicType->get_kind() == otherBasic->get_kind();
@@ -436,5 +438,5 @@
 	}
 
-	void Unify::visit(PointerType *pointerType) {
+	void Unify::postvisit(PointerType *pointerType) {
 		if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {
 			result = unifyExact( pointerType->get_base(), otherPointer->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
@@ -444,5 +446,5 @@
 	}
 
-	void Unify::visit(ReferenceType *refType) {
+	void Unify::postvisit(ReferenceType *refType) {
 		if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {
 			result = unifyExact( refType->get_base(), otherRef->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
@@ -452,5 +454,5 @@
 	}
 
-	void Unify::visit(ArrayType *arrayType) {
+	void Unify::postvisit(ArrayType *arrayType) {
 		ArrayType *otherArray = dynamic_cast< ArrayType* >( type2 );
 		// to unify, array types must both be VLA or both not VLA
@@ -567,5 +569,5 @@
 	}
 
-	void Unify::visit(FunctionType *functionType) {
+	void Unify::postvisit(FunctionType *functionType) {
 		FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 );
 		if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) {
@@ -669,21 +671,21 @@
 	}
 
-	void Unify::visit(StructInstType *structInst) {
+	void Unify::postvisit(StructInstType *structInst) {
 		handleGenericRefType( structInst, type2 );
 	}
 
-	void Unify::visit(UnionInstType *unionInst) {
+	void Unify::postvisit(UnionInstType *unionInst) {
 		handleGenericRefType( unionInst, type2 );
 	}
 
-	void Unify::visit(EnumInstType *enumInst) {
+	void Unify::postvisit(EnumInstType *enumInst) {
 		handleRefType( enumInst, type2 );
 	}
 
-	void Unify::visit(TraitInstType *contextInst) {
+	void Unify::postvisit(TraitInstType *contextInst) {
 		handleRefType( contextInst, type2 );
 	}
 
-	void Unify::visit(TypeInstType *typeInst) {
+	void Unify::postvisit(TypeInstType *typeInst) {
 		assert( openVars.find( typeInst->get_name() ) == openVars.end() );
 		TypeInstType *otherInst = dynamic_cast< TypeInstType* >( type2 );
@@ -740,5 +742,5 @@
 	}
 
-	void Unify::visit(TupleType *tupleType) {
+	void Unify::postvisit(TupleType *tupleType) {
 		if ( TupleType *otherTuple = dynamic_cast< TupleType* >( type2 ) ) {
 			std::unique_ptr<TupleType> flat1( tupleType->clone() );
@@ -757,13 +759,13 @@
 	}
 
-	void Unify::visit( __attribute__((unused)) VarArgsType *varArgsType ) {
+	void Unify::postvisit( __attribute__((unused)) VarArgsType *varArgsType ) {
 		result = dynamic_cast< VarArgsType* >( type2 );
 	}
 
-	void Unify::visit( __attribute__((unused)) ZeroType *zeroType ) {
+	void Unify::postvisit( __attribute__((unused)) ZeroType *zeroType ) {
 		result = dynamic_cast< ZeroType* >( type2 );
 	}
 
-	void Unify::visit( __attribute__((unused)) OneType *oneType ) {
+	void Unify::postvisit( __attribute__((unused)) OneType *oneType ) {
 		result = dynamic_cast< OneType* >( type2 );
 	}
Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/SymTab/Mangler.cc	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -23,4 +23,5 @@
 
 #include "CodeGen/OperatorTable.h"  // for OperatorInfo, operatorLookup
+#include "Common/PassVisitor.h"
 #include "Common/SemanticError.h"   // for SemanticError
 #include "Common/utility.h"         // for toString
@@ -31,285 +32,340 @@
 
 namespace SymTab {
-	std::string Mangler::mangleType( Type * ty ) {
-		Mangler mangler( false, true, true );
-		maybeAccept( ty, mangler );
-		return mangler.get_mangleName();
-	}
-
-	std::string Mangler::mangleConcrete( Type* ty ) {
-		Mangler mangler( false, false, false );
-		maybeAccept( ty, mangler );
-		return mangler.get_mangleName();
-	}
-
-	Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams )
-		: nextVarNum( 0 ), isTopLevel( true ), mangleOverridable( mangleOverridable ), typeMode( typeMode ), mangleGenericParams( mangleGenericParams ) {}
-
-	Mangler::Mangler( const Mangler &rhs ) : mangleName() {
-		varNums = rhs.varNums;
-		nextVarNum = rhs.nextVarNum;
-		isTopLevel = rhs.isTopLevel;
-		mangleOverridable = rhs.mangleOverridable;
-		typeMode = rhs.typeMode;
-	}
-
-	void Mangler::mangleDecl( DeclarationWithType * declaration ) {
-		bool wasTopLevel = isTopLevel;
-		if ( isTopLevel ) {
-			varNums.clear();
-			nextVarNum = 0;
-			isTopLevel = false;
-		} // if
-		mangleName << "__";
-		CodeGen::OperatorInfo opInfo;
-		if ( operatorLookup( declaration->get_name(), opInfo ) ) {
-			mangleName << opInfo.outputName;
-		} else {
-			mangleName << declaration->get_name();
-		} // if
-		mangleName << "__";
-		maybeAccept( declaration->get_type(), *this );
-		if ( mangleOverridable && LinkageSpec::isOverridable( declaration->get_linkage() ) ) {
-			// want to be able to override autogenerated and intrinsic routines,
-			// so they need a different name mangling
-			if ( declaration->get_linkage() == LinkageSpec::AutoGen ) {
-				mangleName << "autogen__";
-			} else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) {
-				mangleName << "intrinsic__";
-			} else {
-				// if we add another kind of overridable function, this has to change
-				assert( false && "unknown overrideable linkage" );
-			} // if
+	namespace Mangler {
+		namespace {
+			/// Mangles names to a unique C identifier
+			struct Mangler : public WithShortCircuiting, public WithVisitorRef<Mangler> {
+				Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams );
+				Mangler( const Mangler & );
+
+				void previsit( BaseSyntaxNode * ) { visit_children = false; }
+
+				void postvisit( ObjectDecl * declaration );
+				void postvisit( FunctionDecl * declaration );
+				void postvisit( TypeDecl * declaration );
+
+				void postvisit( VoidType * voidType );
+				void postvisit( BasicType * basicType );
+				void postvisit( PointerType * pointerType );
+				void postvisit( ArrayType * arrayType );
+				void postvisit( ReferenceType * refType );
+				void postvisit( FunctionType * functionType );
+				void postvisit( StructInstType * aggregateUseType );
+				void postvisit( UnionInstType * aggregateUseType );
+				void postvisit( EnumInstType * aggregateUseType );
+				void postvisit( TypeInstType * aggregateUseType );
+				void postvisit( TupleType * tupleType );
+				void postvisit( VarArgsType * varArgsType );
+				void postvisit( ZeroType * zeroType );
+				void postvisit( OneType * oneType );
+
+				std::string get_mangleName() { return mangleName.str(); }
+			  private:
+				std::ostringstream mangleName;  ///< Mangled name being constructed
+				typedef std::map< std::string, std::pair< int, int > > VarMapType;
+				VarMapType varNums;             ///< Map of type variables to indices
+				int nextVarNum;                 ///< Next type variable index
+				bool isTopLevel;                ///< Is the Mangler at the top level
+				bool mangleOverridable;         ///< Specially mangle overridable built-in methods
+				bool typeMode;                  ///< Produce a unique mangled name for a type
+				bool mangleGenericParams;       ///< Include generic parameters in name mangling if true
+
+				void mangleDecl( DeclarationWithType *declaration );
+				void mangleRef( ReferenceToType *refType, std::string prefix );
+
+				void printQualifiers( Type *type );
+			}; // Mangler
+		} // namespace
+
+		std::string mangle( BaseSyntaxNode * decl, bool mangleOverridable, bool typeMode, bool mangleGenericParams ) {
+			PassVisitor<Mangler> mangler( mangleOverridable, typeMode, mangleGenericParams );
+			maybeAccept( decl, mangler );
+			return mangler.pass.get_mangleName();
 		}
-		isTopLevel = wasTopLevel;
-	}
-
-	void Mangler::visit( ObjectDecl * declaration ) {
-		mangleDecl( declaration );
-	}
-
-	void Mangler::visit( FunctionDecl * declaration ) {
-		mangleDecl( declaration );
-	}
-
-	void Mangler::visit( VoidType * voidType ) {
-		printQualifiers( voidType );
-		mangleName << "v";
-	}
-
-	void Mangler::visit( BasicType * basicType ) {
-		static const char *btLetter[] = {
-			"b",	// Bool
-			"c",	// Char
-			"Sc",	// SignedChar
-			"Uc",	// UnsignedChar
-			"s",	// ShortSignedInt
-			"Us",	// ShortUnsignedInt
-			"i",	// SignedInt
-			"Ui",	// UnsignedInt
-			"l",	// LongSignedInt
-			"Ul",	// LongUnsignedInt
-			"q",	// LongLongSignedInt
-			"Uq",	// LongLongUnsignedInt
-			"f",	// Float
-			"d",	// Double
-			"r",	// LongDouble
-			"Xf",	// FloatComplex
-			"Xd",	// DoubleComplex
-			"Xr",	// LongDoubleComplex
-			"If",	// FloatImaginary
-			"Id",	// DoubleImaginary
-			"Ir",	// LongDoubleImaginary
-			"w",	// SignedInt128
-			"Uw",	// UnsignedInt128
-		};
-
-		printQualifiers( basicType );
-		mangleName << btLetter[ basicType->get_kind() ];
-	}
-
-	void Mangler::visit( PointerType * pointerType ) {
-		printQualifiers( pointerType );
-		mangleName << "P";
-		maybeAccept( pointerType->get_base(), *this );
-	}
-
-	void Mangler::visit( ArrayType * arrayType ) {
-		// TODO: encode dimension
-		printQualifiers( arrayType );
-		mangleName << "A0";
-		maybeAccept( arrayType->get_base(), *this );
-	}
-
-	void Mangler::visit( ReferenceType * refType ) {
-		printQualifiers( refType );
-		mangleName << "R";
-		maybeAccept( refType->get_base(), *this );
-	}
-
-	namespace {
-		inline std::list< Type* > getTypes( const std::list< DeclarationWithType* > decls ) {
-			std::list< Type* > ret;
-			std::transform( decls.begin(), decls.end(), std::back_inserter( ret ),
-							std::mem_fun( &DeclarationWithType::get_type ) );
-			return ret;
+
+		std::string mangleType( Type * ty ) {
+			PassVisitor<Mangler> mangler( false, true, true );
+			maybeAccept( ty, mangler );
+			return mangler.pass.get_mangleName();
 		}
-	}
-
-	void Mangler::visit( FunctionType * functionType ) {
-		printQualifiers( functionType );
-		mangleName << "F";
-		std::list< Type* > returnTypes = getTypes( functionType->get_returnVals() );
-		acceptAll( returnTypes, *this );
-		mangleName << "_";
-		std::list< Type* > paramTypes = getTypes( functionType->get_parameters() );
-		acceptAll( paramTypes, *this );
-		mangleName << "_";
-	}
-
-	void Mangler::mangleRef( ReferenceToType * refType, std::string prefix ) {
-		printQualifiers( refType );
-
-		mangleName << ( refType->get_name().length() + prefix.length() ) << prefix << refType->get_name();
-
-		if ( mangleGenericParams ) {
-			std::list< Expression* >& params = refType->get_parameters();
-			if ( ! params.empty() ) {
+
+		std::string mangleConcrete( Type * ty ) {
+			PassVisitor<Mangler> mangler( false, false, false );
+			maybeAccept( ty, mangler );
+			return mangler.pass.get_mangleName();
+		}
+
+		namespace {
+			Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams )
+				: nextVarNum( 0 ), isTopLevel( true ), mangleOverridable( mangleOverridable ), typeMode( typeMode ), mangleGenericParams( mangleGenericParams ) {}
+
+			Mangler::Mangler( const Mangler &rhs ) : mangleName() {
+				varNums = rhs.varNums;
+				nextVarNum = rhs.nextVarNum;
+				isTopLevel = rhs.isTopLevel;
+				mangleOverridable = rhs.mangleOverridable;
+				typeMode = rhs.typeMode;
+			}
+
+			void Mangler::mangleDecl( DeclarationWithType * declaration ) {
+				bool wasTopLevel = isTopLevel;
+				if ( isTopLevel ) {
+					varNums.clear();
+					nextVarNum = 0;
+					isTopLevel = false;
+				} // if
+				mangleName << "__";
+				CodeGen::OperatorInfo opInfo;
+				if ( operatorLookup( declaration->get_name(), opInfo ) ) {
+					mangleName << opInfo.outputName;
+				} else {
+					mangleName << declaration->get_name();
+				} // if
+				mangleName << "__";
+				maybeAccept( declaration->get_type(), *visitor );
+				if ( mangleOverridable && LinkageSpec::isOverridable( declaration->get_linkage() ) ) {
+					// want to be able to override autogenerated and intrinsic routines,
+					// so they need a different name mangling
+					if ( declaration->get_linkage() == LinkageSpec::AutoGen ) {
+						mangleName << "autogen__";
+					} else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) {
+						mangleName << "intrinsic__";
+					} else {
+						// if we add another kind of overridable function, this has to change
+						assert( false && "unknown overrideable linkage" );
+					} // if
+				}
+				isTopLevel = wasTopLevel;
+			}
+
+			void Mangler::postvisit( ObjectDecl * declaration ) {
+				mangleDecl( declaration );
+			}
+
+			void Mangler::postvisit( FunctionDecl * declaration ) {
+				mangleDecl( declaration );
+			}
+
+			void Mangler::postvisit( VoidType * voidType ) {
+				printQualifiers( voidType );
+				mangleName << "v";
+			}
+
+			void Mangler::postvisit( BasicType * basicType ) {
+				static const char *btLetter[] = {
+					"b",	// Bool
+					"c",	// Char
+					"Sc",	// SignedChar
+					"Uc",	// UnsignedChar
+					"s",	// ShortSignedInt
+					"Us",	// ShortUnsignedInt
+					"i",	// SignedInt
+					"Ui",	// UnsignedInt
+					"l",	// LongSignedInt
+					"Ul",	// LongUnsignedInt
+					"q",	// LongLongSignedInt
+					"Uq",	// LongLongUnsignedInt
+					"f",	// Float
+					"d",	// Double
+					"r",	// LongDouble
+					"Xf",	// FloatComplex
+					"Xd",	// DoubleComplex
+					"Xr",	// LongDoubleComplex
+					"If",	// FloatImaginary
+					"Id",	// DoubleImaginary
+					"Ir",	// LongDoubleImaginary
+					"w",	// SignedInt128
+					"Uw",	// UnsignedInt128
+				};
+
+				printQualifiers( basicType );
+				mangleName << btLetter[ basicType->get_kind() ];
+			}
+
+			void Mangler::postvisit( PointerType * pointerType ) {
+				printQualifiers( pointerType );
+				mangleName << "P";
+				maybeAccept( pointerType->get_base(), *visitor );
+			}
+
+			void Mangler::postvisit( ArrayType * arrayType ) {
+				// TODO: encode dimension
+				printQualifiers( arrayType );
+				mangleName << "A0";
+				maybeAccept( arrayType->get_base(), *visitor );
+			}
+
+			void Mangler::postvisit( ReferenceType * refType ) {
+				printQualifiers( refType );
+				mangleName << "R";
+				maybeAccept( refType->get_base(), *visitor );
+			}
+
+			namespace {
+				inline std::list< Type* > getTypes( const std::list< DeclarationWithType* > decls ) {
+					std::list< Type* > ret;
+					std::transform( decls.begin(), decls.end(), std::back_inserter( ret ),
+									std::mem_fun( &DeclarationWithType::get_type ) );
+					return ret;
+				}
+			}
+
+			void Mangler::postvisit( FunctionType * functionType ) {
+				printQualifiers( functionType );
+				mangleName << "F";
+				std::list< Type* > returnTypes = getTypes( functionType->get_returnVals() );
+				acceptAll( returnTypes, *visitor );
 				mangleName << "_";
-				for ( std::list< Expression* >::const_iterator param = params.begin(); param != params.end(); ++param ) {
-					TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
-					assertf(paramType, "Aggregate parameters should be type expressions: %s", toString(*param).c_str());
-					maybeAccept( paramType->get_type(), *this );
+				std::list< Type* > paramTypes = getTypes( functionType->get_parameters() );
+				acceptAll( paramTypes, *visitor );
+				mangleName << "_";
+			}
+
+			void Mangler::mangleRef( ReferenceToType * refType, std::string prefix ) {
+				printQualifiers( refType );
+
+				mangleName << ( refType->get_name().length() + prefix.length() ) << prefix << refType->get_name();
+
+				if ( mangleGenericParams ) {
+					std::list< Expression* >& params = refType->get_parameters();
+					if ( ! params.empty() ) {
+						mangleName << "_";
+						for ( std::list< Expression* >::const_iterator param = params.begin(); param != params.end(); ++param ) {
+							TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
+							assertf(paramType, "Aggregate parameters should be type expressions: %s", toString(*param).c_str());
+							maybeAccept( paramType->get_type(), *visitor );
+						}
+						mangleName << "_";
+					}
 				}
+			}
+
+			void Mangler::postvisit( StructInstType * aggregateUseType ) {
+				mangleRef( aggregateUseType, "s" );
+			}
+
+			void Mangler::postvisit( UnionInstType * aggregateUseType ) {
+				mangleRef( aggregateUseType, "u" );
+			}
+
+			void Mangler::postvisit( EnumInstType * aggregateUseType ) {
+				mangleRef( aggregateUseType, "e" );
+			}
+
+			void Mangler::postvisit( TypeInstType * typeInst ) {
+				VarMapType::iterator varNum = varNums.find( typeInst->get_name() );
+				if ( varNum == varNums.end() ) {
+					mangleRef( typeInst, "t" );
+				} else {
+					printQualifiers( typeInst );
+					std::ostringstream numStream;
+					numStream << varNum->second.first;
+					switch ( (TypeDecl::Kind )varNum->second.second ) {
+					  case TypeDecl::Dtype:
+						mangleName << "d";
+						break;
+					  case TypeDecl::Ftype:
+						mangleName << "f";
+						break;
+						case TypeDecl::Ttype:
+						mangleName << "tVARGS";
+						break;
+						default:
+						assert( false );
+					} // switch
+					mangleName << numStream.str();
+				} // if
+			}
+
+			void Mangler::postvisit( TupleType * tupleType ) {
+				printQualifiers( tupleType );
+				mangleName << "T";
+				acceptAll( tupleType->types, *visitor );
 				mangleName << "_";
 			}
-		}
-	}
-
-	void Mangler::visit( StructInstType * aggregateUseType ) {
-		mangleRef( aggregateUseType, "s" );
-	}
-
-	void Mangler::visit( UnionInstType * aggregateUseType ) {
-		mangleRef( aggregateUseType, "u" );
-	}
-
-	void Mangler::visit( EnumInstType * aggregateUseType ) {
-		mangleRef( aggregateUseType, "e" );
-	}
-
-	void Mangler::visit( TypeInstType * typeInst ) {
-		VarMapType::iterator varNum = varNums.find( typeInst->get_name() );
-		if ( varNum == varNums.end() ) {
-			mangleRef( typeInst, "t" );
-		} else {
-			printQualifiers( typeInst );
-			std::ostringstream numStream;
-			numStream << varNum->second.first;
-			switch ( (TypeDecl::Kind )varNum->second.second ) {
-			  case TypeDecl::Dtype:
-				mangleName << "d";
-				break;
-			  case TypeDecl::Ftype:
-				mangleName << "f";
-				break;
-				case TypeDecl::Ttype:
-				mangleName << "tVARGS";
-				break;
-				default:
-				assert( false );
-			} // switch
-			mangleName << numStream.str();
-		} // if
-	}
-
-	void Mangler::visit( TupleType * tupleType ) {
-		printQualifiers( tupleType );
-		mangleName << "T";
-		acceptAll( tupleType->types, *this );
-		mangleName << "_";
-	}
-
-	void Mangler::visit( VarArgsType * varArgsType ) {
-		printQualifiers( varArgsType );
-		mangleName << "VARGS";
-	}
-
-	void Mangler::visit( ZeroType * ) {
-		mangleName << "Z";
-	}
-
-	void Mangler::visit( OneType * ) {
-		mangleName << "O";
-	}
-
-	void Mangler::visit( TypeDecl * decl ) {
-		static const char *typePrefix[] = { "BT", "BD", "BF" };
-		mangleName << typePrefix[ decl->get_kind() ] << ( decl->name.length() + 1 ) << decl->name;
-	}
-
-	void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) {
-		for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {
-			os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl;
-		} // for
-	}
-
-	void Mangler::printQualifiers( Type * type ) {
-		// skip if not including qualifiers
-		if ( typeMode ) return;
-
-		if ( ! type->get_forall().empty() ) {
-			std::list< std::string > assertionNames;
-			int tcount = 0, dcount = 0, fcount = 0, vcount = 0;
-			mangleName << "A";
-			for ( Type::ForallList::iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {
-				switch ( (*i)->get_kind() ) {
-				  case TypeDecl::Dtype:
-					dcount++;
-					break;
-				  case TypeDecl::Ftype:
-					fcount++;
-					break;
-				  case TypeDecl::Ttype:
-					vcount++;
-					break;
-				  default:
-					assert( false );
-				} // switch
-				varNums[ (*i)->name ] = std::pair< int, int >( nextVarNum++, (int)(*i)->get_kind() );
-				for ( std::list< DeclarationWithType* >::iterator assert = (*i)->assertions.begin(); assert != (*i)->assertions.end(); ++assert ) {
-					Mangler sub_mangler( mangleOverridable, typeMode, mangleGenericParams );
-					sub_mangler.nextVarNum = nextVarNum;
-					sub_mangler.isTopLevel = false;
-					sub_mangler.varNums = varNums;
-					(*assert)->accept( sub_mangler );
-					assertionNames.push_back( sub_mangler.mangleName.str() );
+
+			void Mangler::postvisit( VarArgsType * varArgsType ) {
+				printQualifiers( varArgsType );
+				mangleName << "VARGS";
+			}
+
+			void Mangler::postvisit( ZeroType * ) {
+				mangleName << "Z";
+			}
+
+			void Mangler::postvisit( OneType * ) {
+				mangleName << "O";
+			}
+
+			void Mangler::postvisit( TypeDecl * decl ) {
+				static const char *typePrefix[] = { "BT", "BD", "BF" };
+				mangleName << typePrefix[ decl->get_kind() ] << ( decl->name.length() + 1 ) << decl->name;
+			}
+
+			__attribute__((unused)) void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) {
+				for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {
+					os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl;
 				} // for
-			} // for
-			mangleName << tcount << "_" << dcount << "_" << fcount << "_" << vcount << "_";
-			std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
-			mangleName << "_";
-		} // if
-		if ( type->get_const() ) {
-			mangleName << "C";
-		} // if
-		if ( type->get_volatile() ) {
-			mangleName << "V";
-		} // if
-		if ( type->get_mutex() ) {
-			mangleName << "M";
-		} // if
-		// Removed due to restrict not affecting function compatibility in GCC
-//		if ( type->get_isRestrict() ) {
-//			mangleName << "E";
-//		} // if
-		if ( type->get_lvalue() ) {
-			// mangle based on whether the type is lvalue, so that the resolver can differentiate lvalues and rvalues
-			mangleName << "L";
-		}
-		if ( type->get_atomic() ) {
-			mangleName << "A";
-		} // if
-	}
+			}
+
+			void Mangler::printQualifiers( Type * type ) {
+				// skip if not including qualifiers
+				if ( typeMode ) return;
+
+				if ( ! type->get_forall().empty() ) {
+					std::list< std::string > assertionNames;
+					int tcount = 0, dcount = 0, fcount = 0, vcount = 0;
+					mangleName << "A";
+					for ( Type::ForallList::iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {
+						switch ( (*i)->get_kind() ) {
+						  case TypeDecl::Dtype:
+							dcount++;
+							break;
+						  case TypeDecl::Ftype:
+							fcount++;
+							break;
+						  case TypeDecl::Ttype:
+							vcount++;
+							break;
+						  default:
+							assert( false );
+						} // switch
+						varNums[ (*i)->name ] = std::pair< int, int >( nextVarNum++, (int)(*i)->get_kind() );
+						for ( std::list< DeclarationWithType* >::iterator assert = (*i)->assertions.begin(); assert != (*i)->assertions.end(); ++assert ) {
+							PassVisitor<Mangler> sub_mangler( mangleOverridable, typeMode, mangleGenericParams );
+							sub_mangler.pass.nextVarNum = nextVarNum;
+							sub_mangler.pass.isTopLevel = false;
+							sub_mangler.pass.varNums = varNums;
+							(*assert)->accept( sub_mangler );
+							assertionNames.push_back( sub_mangler.pass.mangleName.str() );
+						} // for
+					} // for
+					mangleName << tcount << "_" << dcount << "_" << fcount << "_" << vcount << "_";
+					std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
+					mangleName << "_";
+				} // if
+				if ( type->get_const() ) {
+					mangleName << "C";
+				} // if
+				if ( type->get_volatile() ) {
+					mangleName << "V";
+				} // if
+				if ( type->get_mutex() ) {
+					mangleName << "M";
+				} // if
+				// Removed due to restrict not affecting function compatibility in GCC
+		//		if ( type->get_isRestrict() ) {
+		//			mangleName << "E";
+		//		} // if
+				if ( type->get_lvalue() ) {
+					// mangle based on whether the type is lvalue, so that the resolver can differentiate lvalues and rvalues
+					mangleName << "L";
+				}
+				if ( type->get_atomic() ) {
+					mangleName << "A";
+				} // if
+			}
+		}	// namespace
+	} // namespace Mangler
 } // namespace SymTab
 
Index: src/SymTab/Mangler.h
===================================================================
--- src/SymTab/Mangler.h	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/SymTab/Mangler.h	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -25,61 +25,13 @@
 
 namespace SymTab {
-	/// Mangles names to a unique C identifier
-	class Mangler : public Visitor {
-	  public:
+	namespace Mangler {
 		/// Mangle syntax tree object; primary interface to clients
-		template< typename SynTreeClass >
-	    static std::string mangle( SynTreeClass *decl, bool mangleOverridable = true, bool typeMode = false, bool mangleGenericParams = true );
+		std::string mangle( BaseSyntaxNode * decl, bool mangleOverridable = true, bool typeMode = false, bool mangleGenericParams = true );
+
 		/// Mangle a type name; secondary interface
-		static std::string mangleType( Type* ty );
+		std::string mangleType( Type* ty );
 		/// Mangle ignoring generic type parameters
-		static std::string mangleConcrete( Type* ty );
-
-
-		virtual void visit( ObjectDecl *declaration );
-		virtual void visit( FunctionDecl *declaration );
-		virtual void visit( TypeDecl *declaration );
-
-		virtual void visit( VoidType *voidType );
-		virtual void visit( BasicType *basicType );
-		virtual void visit( PointerType *pointerType );
-		virtual void visit( ArrayType *arrayType );
-		virtual void visit( ReferenceType *refType );
-		virtual void visit( FunctionType *functionType );
-		virtual void visit( StructInstType *aggregateUseType );
-		virtual void visit( UnionInstType *aggregateUseType );
-		virtual void visit( EnumInstType *aggregateUseType );
-		virtual void visit( TypeInstType *aggregateUseType );
-		virtual void visit( TupleType *tupleType );
-		virtual void visit( VarArgsType *varArgsType );
-		virtual void visit( ZeroType *zeroType );
-		virtual void visit( OneType *oneType );
-
-		std::string get_mangleName() { return mangleName.str(); }
-	  private:
-		std::ostringstream mangleName;  ///< Mangled name being constructed
-		typedef std::map< std::string, std::pair< int, int > > VarMapType;
-		VarMapType varNums;             ///< Map of type variables to indices
-		int nextVarNum;                 ///< Next type variable index
-		bool isTopLevel;                ///< Is the Mangler at the top level
-		bool mangleOverridable;         ///< Specially mangle overridable built-in methods
-		bool typeMode;                  ///< Produce a unique mangled name for a type
-		bool mangleGenericParams;       ///< Include generic parameters in name mangling if true
-
-		Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams );
-		Mangler( const Mangler & );
-
-		void mangleDecl( DeclarationWithType *declaration );
-		void mangleRef( ReferenceToType *refType, std::string prefix );
-
-		void printQualifiers( Type *type );
-	}; // Mangler
-
-	template< typename SynTreeClass >
-	std::string Mangler::mangle( SynTreeClass *decl, bool mangleOverridable, bool typeMode, bool mangleGenericParams ) {
-		Mangler mangler( mangleOverridable, typeMode, mangleGenericParams );
-		maybeAccept( decl, mangler );
-		return mangler.get_mangleName();
-	}
+		std::string mangleConcrete( Type* ty );
+	} // Mangler
 } // SymTab
 
Index: src/SynTree/CompoundStmt.cc
===================================================================
--- src/SynTree/CompoundStmt.cc	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/SynTree/CompoundStmt.cc	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -64,6 +64,5 @@
 	}
 	if ( ! declMap.empty() ) {
-		VarExprReplacer replacer( declMap );
-		accept( replacer );
+		VarExprReplacer::replace( this, declMap );
 	}
 }
Index: src/SynTree/FunctionDecl.cc
===================================================================
--- src/SynTree/FunctionDecl.cc	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/SynTree/FunctionDecl.cc	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -49,6 +49,5 @@
 	}
 	if ( ! declMap.empty() ) {
-		VarExprReplacer replacer( declMap );
-		accept( replacer );
+		VarExprReplacer::replace( this, declMap );
 	}
 }
Index: src/SynTree/VarExprReplacer.cc
===================================================================
--- src/SynTree/VarExprReplacer.cc	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/SynTree/VarExprReplacer.cc	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -16,18 +16,49 @@
 #include <iostream>       // for operator<<, basic_ostream, ostream, basic_o...
 
+#include "Common/PassVisitor.h"
 #include "Declaration.h"  // for operator<<, DeclarationWithType
 #include "Expression.h"   // for VariableExpr
 #include "VarExprReplacer.h"
 
-VarExprReplacer::VarExprReplacer( const DeclMap & declMap, bool debug ) : declMap( declMap ), debug( debug ) {}
+namespace VarExprReplacer {
+	namespace {
+		/// Visitor that replaces the declarations that VariableExprs refer to, according to the supplied mapping
+		struct VarExprReplacer {
+		private:
+			const DeclMap & declMap;
+			bool debug;
+		public:
+			VarExprReplacer( const DeclMap & declMap, bool debug = false );
 
-// replace variable with new node from decl map
-void VarExprReplacer::visit( VariableExpr * varExpr ) {
-	// xxx - assertions and parameters aren't accounted for in this... (i.e. they aren't inserted into the map when it's made, only DeclStmts are)
-	if ( declMap.count( varExpr->get_var() ) ) {
-		if ( debug ) {
-			std::cerr << "replacing variable reference: " << (void*)varExpr->get_var() << " " << varExpr->get_var() << " with " << (void*)declMap.at( varExpr->get_var() ) << " " << declMap.at( varExpr->get_var() ) << std::endl;
+			// replace variable with new node from decl map
+			void previsit( VariableExpr * varExpr );
+		};
+	}
+
+	void replace( BaseSyntaxNode * node, const DeclMap & declMap, bool debug ) {
+		PassVisitor<VarExprReplacer> replacer( declMap, debug );
+		maybeAccept( node, replacer );
+	}
+
+	namespace {
+		VarExprReplacer::VarExprReplacer( const DeclMap & declMap, bool debug ) : declMap( declMap ), debug( debug ) {}
+
+		// replace variable with new node from decl map
+		void VarExprReplacer::previsit( VariableExpr * varExpr ) {
+			// xxx - assertions and parameters aren't accounted for in this... (i.e. they aren't inserted into the map when it's made, only DeclStmts are)
+			if ( declMap.count( varExpr->var ) ) {
+				if ( debug ) {
+					std::cerr << "replacing variable reference: " << (void*)varExpr->var << " " << varExpr->var << " with " << (void*)declMap.at( varExpr->var ) << " " << declMap.at( varExpr->var ) << std::endl;
+				}
+				varExpr->var = declMap.at( varExpr->var );
+			}
 		}
-		varExpr->set_var( declMap.at( varExpr->get_var() ) );
 	}
-}
+} // namespace VarExprReplacer
+
+
+
+
+
+
+
Index: src/SynTree/VarExprReplacer.h
===================================================================
--- src/SynTree/VarExprReplacer.h	(revision 9cdfb4d06fe4ce29013ae3fd6dbf94776788c075)
+++ src/SynTree/VarExprReplacer.h	(revision e23d20bed910cc2aff120de5e6198b26265ffd5d)
@@ -23,22 +23,9 @@
 class VariableExpr;
 
-/// Visitor that replaces the declarations that VariableExprs refer to, according to the supplied mapping
-class VarExprReplacer : public Visitor {
-public:
+namespace VarExprReplacer {
 	typedef std::map< DeclarationWithType *, DeclarationWithType * > DeclMap;
-private:
-	const DeclMap & declMap;
-	bool debug;
-public:
-	VarExprReplacer( const DeclMap & declMap, bool debug = false );
 
-	// replace variable with new node from decl map
-	virtual void visit( VariableExpr * varExpr );
-
-	static void replace( BaseSyntaxNode * node, const DeclMap & declMap, bool debug = false ) {
-		VarExprReplacer replacer( declMap, debug );
-		maybeAccept( node, replacer );
-	}
-};
+	void replace( BaseSyntaxNode * node, const DeclMap & declMap, bool debug = false );
+}
 
 // Local Variables: //
