Index: src/GenPoly/ScrubTyVars.cc
===================================================================
--- src/GenPoly/ScrubTyVars.cc	(revision e9a715d38423178893a33deb3484b23f09ed95ca)
+++ src/GenPoly/ScrubTyVars.cc	(revision b8a4f47b1e7e8762a51ca29faaf9b54178526589)
@@ -25,5 +25,5 @@
 
 namespace GenPoly {
-	Type * ScrubTyVars::mutate( TypeInstType *typeInst ) {
+	Type * ScrubTyVars::postmutate( TypeInstType * typeInst ) {
 		if ( ! tyVars ) {
 			if ( typeInst->get_isFtype() ) {
@@ -31,5 +31,5 @@
 				return new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) );
 			} else {
-				PointerType *ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) );
+				PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) );
 				delete typeInst;
 				return ret;
@@ -37,5 +37,5 @@
 		}
 
-		TyVarMap::const_iterator tyVar = tyVars->find( typeInst->get_name() );
+		TyVarMap::const_iterator tyVar = tyVars->find( typeInst->name );
 		if ( tyVar != tyVars->end() ) {
 			switch ( tyVar->second.kind ) {
@@ -43,5 +43,5 @@
 			  case TypeDecl::Ttype:
 				{
-					PointerType *ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) );
+					PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) );
 					delete typeInst;
 					return ret;
@@ -55,7 +55,7 @@
 	}
 
-	Type * ScrubTyVars::mutateAggregateType( Type *ty ) {
+	Type * ScrubTyVars::mutateAggregateType( Type * ty ) {
 		if ( shouldScrub( ty ) ) {
-			PointerType *ret = new PointerType( Type::Qualifiers(), new VoidType( ty->get_qualifiers() ) );
+			PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( ty->get_qualifiers() ) );
 			delete ty;
 			return ret;
@@ -64,54 +64,49 @@
 	}
 
-	Type * ScrubTyVars::mutate( StructInstType *structInst ) {
+	Type * ScrubTyVars::postmutate( StructInstType * structInst ) {
 		return mutateAggregateType( structInst );
 	}
 
-	Type * ScrubTyVars::mutate( UnionInstType *unionInst ) {
+	Type * ScrubTyVars::postmutate( UnionInstType * unionInst ) {
 		return mutateAggregateType( unionInst );
 	}
 
-	Expression * ScrubTyVars::mutate( SizeofExpr *szeof ) {
+	void ScrubTyVars::primeBaseScrub( Type * type ) {
+		// need to determine whether type needs to be scrubbed to determine whether
+		// automatic recursion is necessary
+		if ( Type * t = shouldScrub( type ) ) {
+			visit_children = false;
+			GuardValue( dynType );
+			dynType = t;
+		}
+	}
+
+	Expression * ScrubTyVars::postmutate( SizeofExpr * szeof ) {
 		// sizeof( T ) => _sizeof_T parameter, which is the size of T
-		if ( Type *dynType = shouldScrub( szeof->get_type() ) ) {
+		if ( dynType ) {
 			Expression *expr = new NameExpr( sizeofName( mangleType( dynType ) ) );
 			return expr;
-		} else {
-			return Mutator::mutate( szeof );
 		} // if
+		return szeof;
 	}
 
-	Expression * ScrubTyVars::mutate( AlignofExpr *algnof ) {
+	Expression * ScrubTyVars::postmutate( AlignofExpr * algnof ) {
 		// alignof( T ) => _alignof_T parameter, which is the alignment of T
-		if ( Type *dynType = shouldScrub( algnof->get_type() ) ) {
+		if ( dynType ) {
 			Expression *expr = new NameExpr( alignofName( mangleType( dynType ) ) );
 			return expr;
-		} else {
-			return Mutator::mutate( algnof );
 		} // if
+		return algnof;
 	}
 
-	Type * ScrubTyVars::mutate( PointerType *pointer ) {
-//		// special case of shouldScrub that takes all TypeInstType pointer bases, even if they're not dynamic
-// 		Type *base = pointer->get_base();
-// 		Type *dynType = 0;
-// 		if ( dynamicOnly ) {
-// 			if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( base ) ) {
-// 				if ( tyVars.find( typeInst->get_name() ) != tyVars.end() ) { dynType = typeInst; }
-// 			} else {
-// 				dynType = isDynType( base, tyVars );
-// 			}
-// 		} else {
-// 			dynType = isPolyType( base, tyVars );
-// 		}
-// 		if ( dynType ) {
-		if ( Type *dynType = shouldScrub( pointer->get_base() ) ) {
-			Type *ret = dynType->acceptMutator( *this );
+	Type * ScrubTyVars::postmutate( PointerType * pointer ) {
+		if ( dynType ) {
+			Type * ret = dynType->acceptMutator( *visitor );
 			ret->get_qualifiers() |= pointer->get_qualifiers();
-			pointer->set_base( 0 );
+			pointer->base = nullptr;
 			delete pointer;
 			return ret;
 		}
-		return Mutator::mutate( pointer );
+		return pointer;
 	}
 } // namespace GenPoly
Index: src/GenPoly/ScrubTyVars.h
===================================================================
--- src/GenPoly/ScrubTyVars.h	(revision e9a715d38423178893a33deb3484b23f09ed95ca)
+++ src/GenPoly/ScrubTyVars.h	(revision b8a4f47b1e7e8762a51ca29faaf9b54178526589)
@@ -18,4 +18,5 @@
 #include <cassert>            // for assert
 
+#include "Common/PassVisitor.h"
 #include "GenPoly.h"          // for TyVarMap, isPolyType, isDynType
 #include "SynTree/Mutator.h"  // for Mutator
@@ -27,5 +28,5 @@
 
 namespace GenPoly {
-	class ScrubTyVars : public Mutator {
+	struct ScrubTyVars : public WithVisitorRef<ScrubTyVars>, public WithShortCircuiting, public WithGuards {
 		/// Whether to scrub all type variables from the provided map, dynamic type variables from the provided map, or all type variables
 		enum ScrubMode { FromMap, DynamicFromMap, All };
@@ -51,10 +52,20 @@
 		static SynTreeClass *scrubAll( SynTreeClass *target );
 
-		virtual Type* mutate( TypeInstType *typeInst );
-		virtual Type* mutate( StructInstType *structInst );
-		virtual Type* mutate( UnionInstType *unionInst );
-		virtual Expression* mutate( SizeofExpr *szeof );
-		virtual Expression* mutate( AlignofExpr *algnof );
-		virtual Type* mutate( PointerType *pointer );
+		/// determine if children should be visited based on whether base type should be scrubbed.
+		void primeBaseScrub( Type * );
+
+		void premutate( TypeInstType * ) { visit_children = false; }
+		void premutate( StructInstType * ) { visit_children = false; }
+		void premutate( UnionInstType * ) { visit_children = false; }
+		void premutate( SizeofExpr * szeof ) { primeBaseScrub( szeof->type ); }
+		void premutate( AlignofExpr * algnof ) { primeBaseScrub( algnof->type ); }
+		void premutate( PointerType * pointer ) { primeBaseScrub( pointer->base ); }
+
+		Type * postmutate( TypeInstType * typeInst );
+		Type * postmutate( StructInstType * structInst );
+		Type * postmutate( UnionInstType * unionInst );
+		Expression * postmutate( SizeofExpr * szeof );
+		Expression * postmutate( AlignofExpr * algnof );
+		Type * postmutate( PointerType * pointer );
 
 	  private:
@@ -75,9 +86,11 @@
 		const TyVarMap *tyVars;  ///< Type variables to scrub
 		ScrubMode mode;          ///< which type variables to scrub? [FromMap]
+
+		Type * dynType = nullptr; ///< result of shouldScrub
 	};
 
 	template< typename SynTreeClass >
 	SynTreeClass * ScrubTyVars::scrub( SynTreeClass *target, const TyVarMap &tyVars ) {
-		ScrubTyVars scrubber( tyVars );
+		PassVisitor<ScrubTyVars> scrubber( tyVars );
 		return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );
 	}
@@ -85,5 +98,5 @@
 	template< typename SynTreeClass >
 	SynTreeClass * ScrubTyVars::scrubDynamic( SynTreeClass *target, const TyVarMap &tyVars ) {
-		ScrubTyVars scrubber( tyVars, ScrubTyVars::DynamicFromMap );
+		PassVisitor<ScrubTyVars> scrubber( tyVars, ScrubTyVars::DynamicFromMap );
 		return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );
 	}
@@ -91,5 +104,5 @@
 	template< typename SynTreeClass >
 	SynTreeClass * ScrubTyVars::scrubAll( SynTreeClass *target ) {
-		ScrubTyVars scrubber;
+		PassVisitor<ScrubTyVars> scrubber;
 		return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );
 	}
