Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision d3b7937ae7ab8afece0824b5729b7e86a9f0bd63)
+++ src/GenPoly/Box.cc	(revision ae8b94256813adfe7582e0fabf10bdd0d8c7b864)
@@ -22,6 +22,8 @@
 
 #include "Box.h"
+#include "InstantiateGeneric.h"
 #include "PolyMutator.h"
 #include "FindFunction.h"
+#include "ScopedMap.h"
 #include "ScrubTyVars.h"
 
@@ -69,19 +71,33 @@
 			virtual void doEndScope();
 		  private:
+			/// Makes a new temporary array holding the offsets of the fields of `type`, and returns a new variable expression referencing it
+			Expression *makeOffsetArray( StructInstType *type );
+			/// passes extra type parameters into a polymorphic function application
 			void passTypeVars( ApplicationExpr *appExpr, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars );
+			/// wraps a function application with a new temporary for the out-parameter return value
 			Expression *addRetParam( ApplicationExpr *appExpr, FunctionType *function, Type *retType, std::list< Expression *>::iterator &arg );
-			Expression *addPolyRetParam( ApplicationExpr *appExpr, FunctionType *function, std::string typeName, std::list< Expression *>::iterator &arg );
+			/// Replaces all the type parameters of a generic type with their concrete equivalents under the current environment
+			void replaceParametersWithConcrete( ApplicationExpr *appExpr, std::list< Expression* >& params );
+			/// Replaces a polymorphic type with its concrete equivalant under the current environment (returns itself if concrete).
+			/// If `doClone` is set to false, will not clone interior types
+			Type *replaceWithConcrete( ApplicationExpr *appExpr, Type *type, bool doClone = true );
+			/// wraps a function application returning a polymorphic type with a new temporary for the out-parameter return value
+			Expression *addPolyRetParam( ApplicationExpr *appExpr, FunctionType *function, ReferenceToType *polyType, std::list< Expression *>::iterator &arg );
 			Expression *applyAdapter( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars );
 			void boxParam( Type *formal, Expression *&arg, const TyVarMap &exprTyVars );
 			void boxParams( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars );
 			void addInferredParams( ApplicationExpr *appExpr, FunctionType *functionType, std::list< Expression *>::iterator &arg, const TyVarMap &tyVars );
+			/// Stores assignment operators from assertion list in local map of assignment operations
 			void findAssignOps( const std::list< TypeDecl *> &forall );
 			void passAdapters( ApplicationExpr *appExpr, FunctionType *functionType, const TyVarMap &exprTyVars );
 			FunctionDecl *makeAdapter( FunctionType *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars );
+			/// Replaces intrinsic operator functions with their arithmetic desugaring
 			Expression *handleIntrinsics( ApplicationExpr *appExpr );
+			/// Inserts a new temporary variable into the current scope with an auto-generated name
 			ObjectDecl *makeTemporary( Type *type );
 
 			typedef std::map< std::string, DeclarationWithType *> AdapterMap;
 			std::map< std::string, DeclarationWithType *> assignOps;
+			ScopedMap< std::string, DeclarationWithType *> scopedAssignOps;
 			std::stack< AdapterMap > adapters;
 			DeclarationWithType *retval;
@@ -107,6 +123,6 @@
 		};
 
-		/// Replaces initialization of polymorphic values with alloca, declaration of dtype/ftype with appropriate void expression, and sizeof expressions of polymorphic types with the proper variable
-		class Pass3 : public PolyMutator {
+		/// Replaces member expressions for polymorphic types with calculated add-field-offset-and-dereference
+		class MemberExprFixer : public PolyMutator {
 		  public:
 			template< typename DeclClass >
@@ -119,4 +135,18 @@
 			virtual Type *mutate( PointerType *pointerType );
 			virtual Type *mutate( FunctionType *funcType );
+			virtual Expression *mutate( MemberExpr *memberExpr );
+		};
+		
+		/// Replaces initialization of polymorphic values with alloca, declaration of dtype/ftype with appropriate void expression, and sizeof expressions of polymorphic types with the proper variable
+		class Pass3 : public PolyMutator {
+		  public:
+			template< typename DeclClass >
+			DeclClass *handleDecl( DeclClass *decl, Type *type );
+			virtual DeclarationWithType *mutate( FunctionDecl *functionDecl );
+			virtual ObjectDecl *mutate( ObjectDecl *objectDecl );
+			virtual TypedefDecl *mutate( TypedefDecl *objectDecl );
+			virtual TypeDecl *mutate( TypeDecl *objectDecl );
+			virtual Type *mutate( PointerType *pointerType );
+			virtual Type *mutate( FunctionType *funcType );
 		  private:
 		};
@@ -133,11 +163,40 @@
 	}
 
+	/// version of mutateAll with special handling for translation unit so you can check the end of the prelude when debugging
+	template< typename MutatorType >
+	inline void mutateTranslationUnit( std::list< Declaration* > &translationUnit, MutatorType &mutator ) {
+		bool seenIntrinsic = false;
+		SemanticError errors;
+		for ( typename std::list< Declaration* >::iterator i = translationUnit.begin(); i != translationUnit.end(); ++i ) {
+			try {
+				if ( *i ) {
+					if ( (*i)->get_linkage() == LinkageSpec::Intrinsic ) {
+						seenIntrinsic = true;
+					} else if ( seenIntrinsic ) {
+						seenIntrinsic = false; // break on this line when debugging for end of prelude
+					}
+					
+					*i = dynamic_cast< Declaration* >( (*i)->acceptMutator( mutator ) );
+					assert( *i );
+				} // if
+			} catch( SemanticError &e ) {
+				errors.append( e );
+			} // try
+		} // for
+		if ( ! errors.isEmpty() ) {
+			throw errors;
+		} // if
+	}
+
 	void box( std::list< Declaration *>& translationUnit ) {
 		Pass1 pass1;
 		Pass2 pass2;
+		MemberExprFixer memberFixer;
 		Pass3 pass3;
-		mutateAll( translationUnit, pass1 );
-		mutateAll( translationUnit, pass2 );
-		mutateAll( translationUnit, pass3 );
+		mutateTranslationUnit/*All*/( translationUnit, pass1 );
+		mutateTranslationUnit/*All*/( translationUnit, pass2 );
+		instantiateGeneric( translationUnit );
+		mutateTranslationUnit/*All*/( translationUnit, memberFixer );
+		mutateTranslationUnit/*All*/( translationUnit, pass3 );
 	}
 
@@ -185,17 +244,14 @@
 		}
 
-		// returns true if the given declaration is: (*?=?)(T *, T) for some T (return not checked, but maybe should be)
-		bool checkAssignment( DeclarationWithType *decl, std::string &name ) {
+		/// returns T if the given declaration is: (*?=?)(T *, T) for some T (return not checked, but maybe should be), NULL otherwise
+		ReferenceToType *isAssignment( DeclarationWithType *decl ) {
 			if ( decl->get_name() == "?=?" ) {
-				if ( PointerType *ptrType = dynamic_cast< PointerType *>( decl->get_type() ) ) {
-					if ( FunctionType *funType = dynamic_cast< FunctionType *>( ptrType->get_base() ) ) {
-						if ( funType->get_parameters().size() == 2 ) {
-							if ( PointerType *pointer = dynamic_cast< PointerType *>( funType->get_parameters().front()->get_type() ) ) {
-								if ( TypeInstType *typeInst = dynamic_cast< TypeInstType *>( pointer->get_base() ) ) {
-									if ( TypeInstType *typeInst2 = dynamic_cast< TypeInstType *>( funType->get_parameters().back()->get_type() ) ) {
-										if ( typeInst->get_name() == typeInst2->get_name() ) {
-											name = typeInst->get_name();
-											return true;
-										} // if
+				if ( FunctionType *funType = getFunctionType( decl->get_type() ) ) {
+					if ( funType->get_parameters().size() == 2 ) {
+						if ( PointerType *pointer = dynamic_cast< PointerType *>( funType->get_parameters().front()->get_type() ) ) {
+							if ( ReferenceToType *refType = dynamic_cast< ReferenceToType *>( pointer->get_base() ) ) {
+								if ( ReferenceToType *refType2 = dynamic_cast< ReferenceToType *>( funType->get_parameters().back()->get_type() ) ) {
+									if ( refType->get_name() == refType2->get_name() ) {
+										return refType;
 									} // if
 								} // if
@@ -205,5 +261,5 @@
 				} // if
 			} // if
-			return false;
+			return 0;
 		}
 
@@ -214,6 +270,6 @@
 				for ( std::list< DeclarationWithType *>::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {
 					std::string typeName;
-					if ( checkAssignment( *assert, typeName ) ) {
-						assignOps[ typeName ] = *assert;
+					if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( isAssignment( *assert ) ) ) {
+						assignOps[ typeInst->get_name() ] = *assert;
 					} // if
 				} // for
@@ -222,4 +278,11 @@
 
 		DeclarationWithType *Pass1::mutate( FunctionDecl *functionDecl ) {
+			// if this is a polymorphic assignment function, put it in the map for this scope
+			if ( ReferenceToType *refType = isAssignment( functionDecl ) ) {
+				if ( ! dynamic_cast< TypeInstType* >( refType ) ) {
+					scopedAssignOps.insert( refType->get_name(), functionDecl );
+				}
+			}
+			
 			if ( functionDecl->get_statements() ) {		// empty routine body ?
 				doBeginScope();
@@ -231,6 +294,5 @@
 				// process polymorphic return value
 				retval = 0;
-				std::string typeName;
-				if ( isPolyRet( functionDecl->get_functionType(), typeName ) && functionDecl->get_linkage() == LinkageSpec::Cforall ) {
+				if ( isPolyRet( functionDecl->get_functionType() ) && functionDecl->get_linkage() == LinkageSpec::Cforall ) {
 					retval = functionDecl->get_functionType()->get_returnVals().front();
 
@@ -256,4 +318,5 @@
 					findFunction( (*arg)->get_type(), functions, scopeTyVars, needsAdapter );
 				} // for
+				
 				AdapterMap & adapters = Pass1::adapters.top();
 				for ( std::list< FunctionType *>::iterator funType = functions.begin(); funType != functions.end(); ++funType ) {
@@ -306,4 +369,31 @@
 		}
 
+		Expression *Pass1::makeOffsetArray( StructInstType *ty ) {
+			std::list< Declaration* > &baseMembers = ty->get_baseStruct()->get_members();
+			
+			// make a new temporary array
+			Type *offsetType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
+			std::stringstream lenGen;
+			lenGen << baseMembers.size();
+			ConstantExpr *lenExpr = new ConstantExpr( Constant( offsetType->clone(), lenGen.str() ) );
+			ObjectDecl *arrayTemp = makeTemporary( new ArrayType( Type::Qualifiers(), offsetType, lenExpr, false, false ) );
+
+			// build initializer list for temporary
+			std::list< Initializer* > inits;
+			for ( std::list< Declaration* >::const_iterator member = baseMembers.begin(); member != baseMembers.end(); ++member ) {
+				DeclarationWithType *memberDecl;
+				if ( DeclarationWithType *origMember = dynamic_cast< DeclarationWithType* >( *member ) ) {
+					memberDecl = origMember->clone();
+				} else {
+					memberDecl = new ObjectDecl( (*member)->get_name(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, offsetType->clone(), 0 );
+				}
+				inits.push_back( new SingleInit( new OffsetofExpr( ty->clone(), memberDecl ) ) );
+			}
+			arrayTemp->set_init( new ListInit( inits ) );
+
+			// return variable pointing to temporary
+			return new VariableExpr( arrayTemp );
+		}
+		
 		void Pass1::passTypeVars( ApplicationExpr *appExpr, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ) {
 			// pass size/align for type variables
@@ -325,5 +415,4 @@
 
 			// add size/align for generic types to parameter list
-			//assert( ! appExpr->get_function()->get_results().empty() );
 			if ( appExpr->get_function()->get_results().empty() ) return;
 			FunctionType *funcType = getFunctionType( appExpr->get_function()->get_results().front() );
@@ -334,15 +423,24 @@
 			std::set< std::string > seenTypes; //< names for generic types we've seen
 			for ( ; fnParm != funcType->get_parameters().end() && fnArg != appExpr->get_args().end(); ++fnParm, ++fnArg ) {
-				Type *parmType = (*fnParm)->get_type();
-				if ( ! dynamic_cast< TypeInstType* >( parmType ) && isPolyType( parmType, exprTyVars ) ) {
-					std::string sizeName = sizeofName( parmType );
+				Type *polyBase = hasPolyBase( (*fnParm)->get_type(), exprTyVars );
+				if ( polyBase && ! dynamic_cast< TypeInstType* >( polyBase ) ) {
+					std::string sizeName = sizeofName( polyBase );
 					if ( seenTypes.count( sizeName ) ) continue;
 
-					assert( ! (*fnArg)->get_results().empty() );
-					Type *argType = (*fnArg)->get_results().front();
-					arg = appExpr->get_args().insert( arg, new SizeofExpr( argType->clone() ) );
+					VariableExpr *fnArgBase = getBaseVar( *fnArg );
+					assert( fnArgBase && ! fnArgBase->get_results().empty() );
+					Type *argBaseType = fnArgBase->get_results().front();
+					arg = appExpr->get_args().insert( arg, new SizeofExpr( argBaseType->clone() ) );
 					arg++;
-					arg = appExpr->get_args().insert( arg, new AlignofExpr( argType->clone() ) );
+					arg = appExpr->get_args().insert( arg, new AlignofExpr( argBaseType->clone() ) );
 					arg++;
+					if ( dynamic_cast< StructInstType* >( polyBase ) ) {
+						if ( StructInstType *argBaseStructType = dynamic_cast< StructInstType* >( argBaseType ) ) {
+							arg = appExpr->get_args().insert( arg, makeOffsetArray( argBaseStructType ) );
+							arg++;
+						} else {
+							throw SemanticError( "Cannot pass non-struct type for generic struct" );
+						}
+					}
 
 					seenTypes.insert( sizeName );
@@ -386,11 +484,38 @@
 		}
 
-		Expression *Pass1::addPolyRetParam( ApplicationExpr *appExpr, FunctionType *function, std::string typeName, std::list< Expression *>::iterator &arg ) {
-			ResolvExpr::EqvClass eqvClass;
+		void Pass1::replaceParametersWithConcrete( ApplicationExpr *appExpr, std::list< Expression* >& params ) {
+			for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
+				TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
+				assert(paramType && "Aggregate parameters should be type expressions");
+				paramType->set_type( replaceWithConcrete( appExpr, paramType->get_type(), false ) );
+			}
+		}
+		
+		Type *Pass1::replaceWithConcrete( ApplicationExpr *appExpr, Type *type, bool doClone ) {
+			if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {
+				Type *concrete = env->lookup( typeInst->get_name() );
+				if ( concrete == 0 ) {
+					throw SemanticError( "Unbound type variable " + typeInst->get_name() + " in ", appExpr );
+				} // if
+				return concrete;
+			} else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
+				if ( doClone ) {
+					structType = structType->clone();
+				}
+				replaceParametersWithConcrete( appExpr, structType->get_parameters() );
+				return structType;
+			} else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
+				if ( doClone ) {
+					unionType = unionType->clone();
+				}
+				replaceParametersWithConcrete( appExpr, unionType->get_parameters() );
+				return unionType;
+			}
+			return type;
+		}
+
+		Expression *Pass1::addPolyRetParam( ApplicationExpr *appExpr, FunctionType *function, ReferenceToType *polyType, std::list< Expression *>::iterator &arg ) {
 			assert( env );
-			Type *concrete = env->lookup( typeName );
-			if ( concrete == 0 ) {
-				throw SemanticError( "Unbound type variable " + typeName + " in ", appExpr );
-			} // if
+			Type *concrete = replaceWithConcrete( appExpr, polyType );
 			return addRetParam( appExpr, function, concrete, arg );
 		}
@@ -492,7 +617,4 @@
 			assert( arg );
 			if ( isPolyType( realParam->get_type(), tyVars ) ) {
-//     if ( dynamic_cast< PointerType *>( arg->get_type() ) ) {
-//       return new CastExpr( new VariableExpr( param ), arg->get_type()->clone() );
-//     } else {
 				if ( dynamic_cast<TypeInstType *>(arg->get_type()) == NULL ) {
 					UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) );
@@ -501,5 +623,4 @@
 					return deref;
 				} // if
-//     }
 			} // if
 			return new VariableExpr( param );
@@ -791,7 +912,6 @@
 			std::list< Expression *>::iterator paramBegin = appExpr->get_args().begin();
 
-			std::string typeName;
-			if ( isPolyRet( function, typeName ) ) {
-				ret = addPolyRetParam( appExpr, function, typeName, arg );
+			if ( ReferenceToType *polyType = isPolyRet( function ) ) {
+				ret = addPolyRetParam( appExpr, function, polyType, arg );
 			} else if ( needsAdapter( function, scopeTyVars ) ) {
 				// std::cerr << "needs adapter: ";
@@ -880,11 +1000,28 @@
 					delete castExpr;
 				} //while
-				TypeInstType *typeInst = dynamic_cast< TypeInstType *>( retval->get_type() );
-				assert( typeInst );
-				std::map< std::string, DeclarationWithType *>::const_iterator assignIter = assignOps.find( typeInst->get_name() );
-				if ( assignIter == assignOps.end() ) {
-					throw SemanticError( "Attempt to return dtype or ftype object in ", returnStmt->get_expr() );
-				} // if
-				ApplicationExpr *assignExpr = new ApplicationExpr( new VariableExpr( assignIter->second ) );
+
+				// find assignment operator for (polymorphic) return type
+				DeclarationWithType *assignDecl = 0;
+				if ( TypeInstType *typeInst = dynamic_cast< TypeInstType *>( retval->get_type() ) ) {
+					std::map< std::string, DeclarationWithType *>::const_iterator assignIter = assignOps.find( typeInst->get_name() );
+					if ( assignIter == assignOps.end() ) {
+						throw SemanticError( "Attempt to return dtype or ftype object in ", returnStmt->get_expr() );
+					} // if
+					assignDecl = assignIter->second;
+				} else if ( ReferenceToType *refType = dynamic_cast< ReferenceToType *>( retval->get_type() ) ) {
+					ScopedMap< std::string, DeclarationWithType *>::const_iterator assignIter = scopedAssignOps.find( refType->get_name() );
+					if ( assignIter == scopedAssignOps.end() ) {
+						throw SemanticError( "Attempt to return dtype or ftype generic object in ", returnStmt->get_expr() );
+					}
+					DeclarationWithType *functionDecl = assignIter->second;
+					// line below cloned from FixFunction.cc
+					assignDecl = new ObjectDecl( functionDecl->get_name(), functionDecl->get_storageClass(), functionDecl->get_linkage(), 0,
+					                             new PointerType( Type::Qualifiers(), functionDecl->get_type()->clone() ), 0 );
+					assignDecl->set_mangleName( functionDecl->get_mangleName() );
+				}
+				assert( assignDecl );
+
+				// replace return statement with appropriate assignment to out parameter
+				ApplicationExpr *assignExpr = new ApplicationExpr( new VariableExpr( assignDecl ) );
 				Expression *retParm = new NameExpr( retval->get_name() );
 				retParm->get_results().push_back( new PointerType( Type::Qualifiers(), retval->get_type()->clone() ) );
@@ -927,8 +1064,10 @@
 			// push a copy of the current map
 			adapters.push(adapters.top());
+			scopedAssignOps.beginScope();
 		}
 
 		void Pass1::doEndScope() {
 			adapters.pop();
+			scopedAssignOps.endScope();
 		}
 
@@ -998,6 +1137,5 @@
 
 			// move polymorphic return type to parameter list
-			std::string typeName;
-			if ( isPolyRet( funcType, typeName ) ) {
+			if ( isPolyRet( funcType ) ) {
 				DeclarationWithType *ret = funcType->get_returnVals().front();
 				ret->set_type( new PointerType( Type::Qualifiers(), ret->get_type() ) );
@@ -1010,4 +1148,6 @@
 			std::list< DeclarationWithType *> inferredParams;
 			ObjectDecl newObj( "", DeclarationNode::NoStorageClass, LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), 0 );
+			ObjectDecl newPtr( "", DeclarationNode::NoStorageClass, LinkageSpec::C, 0,
+			                   new PointerType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) ), 0 );
 //   ObjectDecl *newFunPtr = new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) ), 0 );
 			for ( std::list< TypeDecl *>::const_iterator tyParm = funcType->get_forall().begin(); tyParm != funcType->get_forall().end(); ++tyParm ) {
@@ -1036,12 +1176,12 @@
 
 			// add size/align for generic types to parameter list
-			std::set< std::string > seenTypes; //< sizeofName for generic types we've seen
+			std::set< std::string > seenTypes; // sizeofName for generic types we've seen
 			for ( std::list< DeclarationWithType* >::const_iterator fnParm = last; fnParm != funcType->get_parameters().end(); ++fnParm ) {
-				Type *parmType = (*fnParm)->get_type();
-				if ( ! dynamic_cast< TypeInstType* >( parmType ) && isPolyType( parmType, scopeTyVars ) ) {
-					std::string sizeName = sizeofName( parmType );
+				Type *polyBase = hasPolyBase( (*fnParm)->get_type(), scopeTyVars );
+				if ( polyBase && ! dynamic_cast< TypeInstType* >( polyBase ) ) {
+					std::string sizeName = sizeofName( polyBase );
 					if ( seenTypes.count( sizeName ) ) continue;
 
-					ObjectDecl *sizeParm, *alignParm;
+					ObjectDecl *sizeParm, *alignParm, *offsetParm;
 					sizeParm = newObj.clone();
 					sizeParm->set_name( sizeName );
@@ -1050,7 +1190,14 @@
 
 					alignParm = newObj.clone();
-					alignParm->set_name( alignofName( parmType ) );
+					alignParm->set_name( alignofName( polyBase ) );
 					last = funcType->get_parameters().insert( last, alignParm );
 					++last;
+
+					if ( dynamic_cast< StructInstType* >( polyBase ) ) {
+						offsetParm = newPtr.clone();
+						offsetParm->set_name( offsetofName( polyBase ) );
+						last = funcType->get_parameters().insert( last, offsetParm );
+						++last;
+					}
 
 					seenTypes.insert( sizeName );
@@ -1066,4 +1213,137 @@
 			scopeTyVars = oldtyVars;
 			return funcType;
+		}
+
+////////////////////////////////////////// MemberExprFixer ////////////////////////////////////////////////////
+
+		template< typename DeclClass >
+		DeclClass * MemberExprFixer::handleDecl( DeclClass *decl, Type *type ) {
+			TyVarMap oldtyVars = scopeTyVars;
+			makeTyVarMap( type, scopeTyVars );
+
+			DeclClass *ret = static_cast< DeclClass *>( Mutator::mutate( decl ) );
+
+			scopeTyVars = oldtyVars;
+			return ret;
+		}
+
+		ObjectDecl * MemberExprFixer::mutate( ObjectDecl *objectDecl ) {
+			return handleDecl( objectDecl, objectDecl->get_type() );
+		}
+
+		DeclarationWithType * MemberExprFixer::mutate( FunctionDecl *functionDecl ) {
+			return handleDecl( functionDecl, functionDecl->get_functionType() );
+		}
+
+		TypedefDecl * MemberExprFixer::mutate( TypedefDecl *typedefDecl ) {
+			return handleDecl( typedefDecl, typedefDecl->get_base() );
+		}
+
+		TypeDecl * MemberExprFixer::mutate( TypeDecl *typeDecl ) {
+			scopeTyVars[ typeDecl->get_name() ] = typeDecl->get_kind();
+			return Mutator::mutate( typeDecl );
+		}
+
+		Type * MemberExprFixer::mutate( PointerType *pointerType ) {
+			TyVarMap oldtyVars = scopeTyVars;
+			makeTyVarMap( pointerType, scopeTyVars );
+
+			Type *ret = Mutator::mutate( pointerType );
+
+			scopeTyVars = oldtyVars;
+			return ret;
+		}
+
+		Type * MemberExprFixer::mutate( FunctionType *functionType ) {
+			TyVarMap oldtyVars = scopeTyVars;
+			makeTyVarMap( functionType, scopeTyVars );
+
+			Type *ret = Mutator::mutate( functionType );
+
+			scopeTyVars = oldtyVars;
+			return ret;
+		}
+
+		Statement *MemberExprFixer::mutate( DeclStmt *declStmt ) {
+			if ( ObjectDecl *objectDecl = dynamic_cast< ObjectDecl *>( declStmt->get_decl() ) ) {
+				if ( isPolyType( objectDecl->get_type(), scopeTyVars ) ) {
+					// change initialization of a polymorphic value object
+					// to allocate storage with alloca
+					Type *declType = objectDecl->get_type();
+					UntypedExpr *alloc = new UntypedExpr( new NameExpr( "__builtin_alloca" ) );
+					alloc->get_args().push_back( new NameExpr( sizeofName( declType ) ) );
+
+					delete objectDecl->get_init();
+
+					std::list<Expression*> designators;
+					objectDecl->set_init( new SingleInit( alloc, designators ) );
+				}
+			}
+			return Mutator::mutate( declStmt );
+		}
+
+		Expression *MemberExprFixer::mutate( MemberExpr *memberExpr ) {
+			// mutate, exiting early if no longer MemberExpr
+			Expression *expr = Mutator::mutate( memberExpr );
+			memberExpr = dynamic_cast< MemberExpr* >( expr );
+			if ( ! memberExpr ) return expr;
+
+			// get declaration for base struct, exiting early if not found
+			int varDepth;
+			VariableExpr *varExpr = getBaseVar( memberExpr->get_aggregate(), &varDepth );
+			if ( ! varExpr ) return memberExpr;
+			ObjectDecl *objectDecl = dynamic_cast< ObjectDecl* >( varExpr->get_var() );
+			if ( ! objectDecl ) return memberExpr;
+
+			// only mutate member expressions for polymorphic types
+			int tyDepth;
+			Type *objectType = hasPolyBase( objectDecl->get_type(), scopeTyVars, &tyDepth );
+			if ( ! objectType ) return memberExpr;
+
+			// get base aggregate for type so members can be looked up
+			AggregateDecl *memberBase = 0;
+			if ( StructInstType *structType = dynamic_cast< StructInstType* >( objectType ) ) {
+				memberBase = structType->get_baseStruct();
+			} else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( objectType ) ) {
+				memberBase = unionType->get_baseUnion();
+			} else return memberExpr;
+
+			// look up numeric index of member in base aggregate
+			DeclarationWithType *memberDecl = memberExpr->get_member();
+			std::list< Declaration* > &baseDecls = memberBase->get_members();
+			std::list< Declaration* >::const_iterator decl = baseDecls.begin();
+			unsigned long i = 0;
+			for( ; decl != baseDecls.end(); ++decl, ++i ) {
+				if ( memberDecl->get_name() != (*decl)->get_name() ) continue;
+
+				if ( DeclarationWithType *declWithType = dynamic_cast< DeclarationWithType* >( *decl ) ) {
+					if ( memberDecl->get_mangleName() == declWithType->get_mangleName() ) break;
+					else continue;
+				} else break;
+			}
+			if ( decl == baseDecls.end() ) return memberExpr;
+
+			// replace member expression with pointer to base plus offset
+			// get offset for field
+			std::stringstream offset_namer;
+			offset_namer << i;
+			ConstantExpr *fieldIndex = new ConstantExpr( Constant( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), offset_namer.str() ) );
+			UntypedExpr *fieldOffset = new UntypedExpr( new NameExpr( "?[?]" ) );
+			fieldOffset->get_args().push_back( new NameExpr( offsetofName( objectType ) ) );
+			fieldOffset->get_args().push_back( fieldIndex );
+			// build appropriately-dereferenced variable
+			Expression *derefdVar = varExpr->clone();
+			for ( int i = 1; i < varDepth; ++i ) {
+				UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) );
+				derefExpr->get_args().push_back( derefdVar );
+				derefdVar = derefExpr;
+			}
+			// add offset to deref'd variable
+			UntypedExpr *fieldLoc = new UntypedExpr( new NameExpr( "?+?" ) );
+			fieldLoc->get_args().push_back( derefdVar );
+			fieldLoc->get_args().push_back( fieldOffset );
+
+			delete memberExpr;
+			return fieldLoc;
 		}
 
@@ -1126,22 +1406,4 @@
 			return ret;
 		}
-
-		Statement *Pass3::mutate( DeclStmt *declStmt ) {
-			if ( ObjectDecl *objectDecl = dynamic_cast< ObjectDecl *>( declStmt->get_decl() ) ) {
-				if ( isPolyType( objectDecl->get_type(), scopeTyVars ) ) {
-					// change initialization of a polymorphic value object
-					// to allocate storage with alloca
-					Type *declType = objectDecl->get_type();
-					UntypedExpr *alloc = new UntypedExpr( new NameExpr( "__builtin_alloca" ) );
-					alloc->get_args().push_back( new NameExpr( sizeofName( declType ) ) );
-
-					delete objectDecl->get_init();
-
-					std::list<Expression*> designators;
-					objectDecl->set_init( new SingleInit( alloc, designators ) );
-				}
-			}
-			return Mutator::mutate( declStmt );
-		}
 	} // anonymous namespace
 } // namespace GenPoly
Index: src/GenPoly/GenPoly.cc
===================================================================
--- src/GenPoly/GenPoly.cc	(revision d3b7937ae7ab8afece0824b5729b7e86a9f0bd63)
+++ src/GenPoly/GenPoly.cc	(revision ae8b94256813adfe7582e0fabf10bdd0d8c7b864)
@@ -36,33 +36,11 @@
 	}
 
-	bool isPolyRet( FunctionType *function, std::string &name, const TyVarMap &otherTyVars ) {
-		bool doTransform = false;
+	ReferenceToType *isPolyRet( FunctionType *function ) {
 		if ( ! function->get_returnVals().empty() ) {
-			if ( TypeInstType *typeInst = dynamic_cast< TypeInstType *>( function->get_returnVals().front()->get_type() ) ) {
-	
-				// figure out if the return type is specified by a type parameter
-				for ( std::list< TypeDecl *>::const_iterator tyVar = function->get_forall().begin(); tyVar != function->get_forall().end(); ++tyVar ) {
-					if ( (*tyVar)->get_name() == typeInst->get_name() ) {
-						doTransform = true;
-						name = typeInst->get_name();
-						break;
-					} // if
-				} // for
-				if ( ! doTransform && otherTyVars.find( typeInst->get_name() ) != otherTyVars.end() ) {
-					doTransform = true;
-				} // if
-			} // if
-		} // if
-		return doTransform;
-	}
-
-	bool isPolyRet( FunctionType *function, std::string &name ) {
-		TyVarMap dummyTyVars;
-		return isPolyRet( function, name, dummyTyVars );
-	}
-
-	bool isPolyRet( FunctionType *function, const TyVarMap &otherTyVars ) {
-		std::string dummyString;
-		return isPolyRet( function, dummyString, otherTyVars );
+			TyVarMap forallTypes;
+			makeTyVarMap( function, forallTypes );
+			return (ReferenceToType*)isPolyType( function->get_returnVals().front()->get_type(), forallTypes );
+		} // if
+		return 0;
 	}
 
@@ -149,4 +127,46 @@
 	}
 
+	Type * hasPolyBase( Type *type, int *levels, const TypeSubstitution *env ) {
+		int dummy;
+		if ( ! levels ) { levels = &dummy; }
+		*levels = 0;
+
+		while ( true ) {
+			if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
+				type = ptr->get_base();
+				++(*levels);
+			} else if ( env ) {
+				if ( TypeInstType *typeInst = dynamic_cast< TypeInstType *>( type ) ) {
+					if ( Type *newType = env->lookup( typeInst->get_name() ) ) {
+						type = newType;
+					} else break;
+				} else break;
+			} else break;
+		}
+
+		return isPolyType( type, env );
+	}
+	
+	Type * hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels, const TypeSubstitution *env ) {
+		int dummy;
+		if ( ! levels ) { levels = &dummy; }
+		*levels = 0;
+
+		while ( true ) {
+			if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
+				type = ptr->get_base();
+				++(*levels);
+			} else if ( env ) {
+				if ( TypeInstType *typeInst = dynamic_cast< TypeInstType *>( type ) ) {
+					if ( Type *newType = env->lookup( typeInst->get_name() ) ) {
+						type = newType;
+					} else break;
+				} else break;
+			} else break;
+		}
+
+		return isPolyType( type, tyVars, env );
+	}
+
 	FunctionType * getFunctionType( Type *ty ) {
 		PointerType *ptrType;
@@ -158,4 +178,37 @@
 	}
 
+	VariableExpr * getBaseVar( Expression *expr, int *levels ) {
+		int dummy;
+		if ( ! levels ) { levels = &dummy; }
+		*levels = 0;
+
+		while ( true ) {
+			if ( VariableExpr *varExpr = dynamic_cast< VariableExpr* >( expr ) ) {
+				return varExpr;
+			} else if ( AddressExpr *addressExpr = dynamic_cast< AddressExpr* >( expr ) ) {
+				expr = addressExpr->get_arg();
+			} else if ( UntypedExpr *untypedExpr = dynamic_cast< UntypedExpr* >( expr ) ) {
+				// look for compiler-inserted dereference operator
+				NameExpr *fn = dynamic_cast< NameExpr* >( untypedExpr->get_function() );
+				if ( ! fn || fn->get_name() != std::string("*?") ) return 0;
+				expr = *untypedExpr->begin_args();
+			} else break;
+
+			++(*levels);
+		}
+
+		return 0;
+	}
+
+	void makeTyVarMap( Type *type, TyVarMap &tyVarMap ) {
+		for ( std::list< TypeDecl* >::const_iterator tyVar = type->get_forall().begin(); tyVar != type->get_forall().end(); ++tyVar ) {
+			assert( *tyVar );
+			tyVarMap[ (*tyVar)->get_name() ] = (*tyVar)->get_kind();
+		}
+		if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) {
+			makeTyVarMap( pointer->get_base(), tyVarMap );
+		}
+	}
+	
 	void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ) {
 		for ( TyVarMap::const_iterator i = tyVarMap.begin(); i != tyVarMap.end(); ++i ) {
@@ -172,4 +225,9 @@
 		return std::string( "_alignof_" ) + SymTab::Mangler::mangleType( ty );
 	}
+
+	std::string offsetofName( Type* ty ) {
+		return std::string( "_offsetof_" ) + SymTab::Mangler::mangleType( ty );
+	}
+
 } // namespace GenPoly
 
Index: src/GenPoly/GenPoly.h
===================================================================
--- src/GenPoly/GenPoly.h	(revision d3b7937ae7ab8afece0824b5729b7e86a9f0bd63)
+++ src/GenPoly/GenPoly.h	(revision ae8b94256813adfe7582e0fabf10bdd0d8c7b864)
@@ -20,6 +20,8 @@
 #include <string>
 #include <iostream>
+#include <utility>
 
 #include "SynTree/Declaration.h"
+#include "SynTree/Type.h"
 #include "SynTree/TypeSubstitution.h"
 
@@ -32,7 +34,5 @@
 
 	/// true iff function has polymorphic return type
-	bool isPolyRet( FunctionType *function, std::string &name, const TyVarMap &otherTyVars );
-	bool isPolyRet( FunctionType *function, std::string &name );
-	bool isPolyRet( FunctionType *function, const TyVarMap &otherTyVars );
+	ReferenceToType *isPolyRet( FunctionType *function );
 
 	/// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided
@@ -48,7 +48,22 @@
 	Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
 
+	/// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type, returns the base type, NULL otherwise;
+	/// N will be stored in levels, if provided, will look up substitution in env if provided
+	Type *hasPolyBase( Type *type, int *levels = 0, const TypeSubstitution *env = 0 );
+
+	/// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type in tyVars, returns the base type, NULL otherwise;
+	/// N will be stored in levels, if provided, will look up substitution in env if provided
+	Type *hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels = 0, const TypeSubstitution *env = 0 );
+
 	/// Returns a pointer to the base FunctionType if ty is the type of a function (or pointer to one), NULL otherwise
-	FunctionType * getFunctionType( Type *ty );
+	FunctionType *getFunctionType( Type *ty );
 
+	/// If expr (after dereferencing N >= 0 pointers) is a variable expression, returns the variable expression, NULL otherwise;
+	/// N will be stored in levels, if provided
+	VariableExpr *getBaseVar( Expression *expr, int *levels = 0 );
+
+	/// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap`
+	void makeTyVarMap( Type *type, TyVarMap &tyVarMap );
+	
 	/// Prints type variable map
 	void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap );
@@ -59,4 +74,7 @@
 	/// Gets the name of the alignof parameter for the type
 	std::string alignofName( Type *ty );
+
+	/// Gets the name of the offsetof parameter for the type
+	std::string offsetofName( Type *ty );
 } // namespace GenPoly
 
Index: src/GenPoly/PolyMutator.cc
===================================================================
--- src/GenPoly/PolyMutator.cc	(revision d3b7937ae7ab8afece0824b5729b7e86a9f0bd63)
+++ src/GenPoly/PolyMutator.cc	(revision ae8b94256813adfe7582e0fabf10bdd0d8c7b864)
@@ -152,15 +152,4 @@
 	}
 
-
-	/* static class method */
-	void PolyMutator::makeTyVarMap( Type *type, TyVarMap &tyVarMap ) {
-		for ( std::list< TypeDecl* >::const_iterator tyVar = type->get_forall().begin(); tyVar != type->get_forall().end(); ++tyVar ) {
-			assert( *tyVar );
-			tyVarMap[ (*tyVar)->get_name() ] = (*tyVar)->get_kind();
-		}
-		if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) {
-			makeTyVarMap( pointer->get_base(), tyVarMap );
-		}
-	}
 } // namespace GenPoly
 
Index: src/GenPoly/PolyMutator.h
===================================================================
--- src/GenPoly/PolyMutator.h	(revision d3b7937ae7ab8afece0824b5729b7e86a9f0bd63)
+++ src/GenPoly/PolyMutator.h	(revision ae8b94256813adfe7582e0fabf10bdd0d8c7b864)
@@ -51,6 +51,4 @@
 		virtual void doBeginScope() {}
 		virtual void doEndScope() {}
-		
-		static void makeTyVarMap( Type *type, TyVarMap &tyVarMap );
 	  protected:
 		void mutateStatementList( std::list< Statement* > &statements );
Index: src/GenPoly/ScopedMap.h
===================================================================
--- src/GenPoly/ScopedMap.h	(revision ae8b94256813adfe7582e0fabf10bdd0d8c7b864)
+++ src/GenPoly/ScopedMap.h	(revision ae8b94256813adfe7582e0fabf10bdd0d8c7b864)
@@ -0,0 +1,220 @@
+//
+// 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       : Wed Dec 2 11:37:00 2015
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Wed Dec 2 11:37:00 2015
+// Update Count     : 1
+//
+
+#ifndef _SCOPEDMAP_H
+#define _SCOPEDMAP_H
+
+#include <iterator>
+#include <map>
+#include <utility>
+#include <vector>
+
+namespace GenPoly {
+	/// A map where the items are placed into nested scopes;
+	/// inserted items are placed into the innermost scope, lookup looks from the innermost scope outward
+	template<typename Key, typename Value>
+	class ScopedMap {
+		typedef std::map< Key, Value > Scope;
+		typedef std::vector< Scope > ScopeList;
+
+		ScopeList scopes; ///< scoped list of maps
+	public:
+		typedef typename Scope::key_type key_type;
+		typedef typename Scope::mapped_type mapped_type;
+		typedef typename Scope::value_type value_type;
+		typedef typename ScopeList::size_type size_type;
+		typedef typename ScopeList::difference_type difference_type;
+		typedef typename Scope::reference reference;
+		typedef typename Scope::const_reference const_reference;
+		typedef typename Scope::pointer pointer;
+		typedef typename Scope::const_pointer const_pointer;
+		
+		class iterator : public std::iterator< std::bidirectional_iterator_tag,
+		                                       value_type > {
+		friend class ScopedMap;
+		friend class const_iterator;
+			typedef typename std::map< Key, Value >::iterator wrapped_iterator;
+			typedef typename std::vector< std::map< Key, Value > > scope_list;
+			typedef typename scope_list::size_type size_type;
+
+			iterator(scope_list const &_scopes, const wrapped_iterator &_it, size_type _i)
+				: scopes(&_scopes), it(_it), i(_i) {}
+		public:
+			iterator(const iterator &that) : scopes(that.scopes), it(that.it), i(that.i) {}
+			iterator& operator= (const iterator &that) {
+				scopes = that.scopes; i = that.i; it = that.it;
+				return *this;
+			}
+			
+			reference operator* () { return *it; }
+			pointer operator-> () { return it.operator->(); }
+
+			iterator& operator++ () {
+				if ( it == (*scopes)[i].end() ) {
+					if ( i == 0 ) return *this;
+					--i;
+					it = (*scopes)[i].begin();
+					return *this;
+				}
+				++it;
+				return *this;
+			}
+			iterator& operator++ (int) { iterator tmp = *this; ++(*this); return tmp; }
+
+			iterator& operator-- () {
+				// may fail if this is the begin iterator; allowed by STL spec
+				if ( it == (*scopes)[i].begin() ) {
+					++i;
+					it = (*scopes)[i].end();
+				}
+				--it;
+				return *this;
+			}
+			iterator& operator-- (int) { iterator tmp = *this; --(*this); return tmp; }
+
+			bool operator== (const iterator &that) {
+				return scopes == that.scopes && i == that.i && it == that.it;
+			}
+			bool operator!= (const iterator &that) { return !( *this == that ); }
+
+		private:
+			scope_list const *scopes;
+			wrapped_iterator it;
+			size_type i;
+		};
+
+		class const_iterator : public std::iterator< std::bidirectional_iterator_tag,
+		                                             value_type > {
+		friend class ScopedMap;
+			typedef typename std::map< Key, Value >::iterator wrapped_iterator;
+			typedef typename std::map< Key, Value >::const_iterator wrapped_const_iterator;
+			typedef typename std::vector< std::map< Key, Value > > scope_list;
+			typedef typename scope_list::size_type size_type;
+
+			const_iterator(scope_list const &_scopes, const wrapped_const_iterator &_it, size_type _i)
+				: scopes(&_scopes), it(_it), i(_i) {}
+		public:
+			const_iterator(const iterator &that) : scopes(that.scopes), it(that.it), i(that.i) {}
+			const_iterator(const const_iterator &that) : scopes(that.scopes), it(that.it), i(that.i) {}
+			const_iterator& operator= (const iterator &that) {
+				scopes = that.scopes; i = that.i; it = that.it;
+				return *this;
+			}
+			const_iterator& operator= (const const_iterator &that) {
+				scopes = that.scopes; i = that.i; it = that.it;
+				return *this;
+			}
+
+			const_reference operator* () { return *it; }
+			const_pointer operator-> () { return it.operator->(); }
+
+			const_iterator& operator++ () {
+				if ( it == (*scopes)[i].end() ) {
+					if ( i == 0 ) return *this;
+					--i;
+					it = (*scopes)[i].begin();
+					return *this;
+				}
+				++it;
+				return *this;
+			}
+			const_iterator& operator++ (int) { const_iterator tmp = *this; ++(*this); return tmp; }
+
+			const_iterator& operator-- () {
+				// may fail if this is the begin iterator; allowed by STL spec
+				if ( it == (*scopes)[i].begin() ) {
+					++i;
+					it = (*scopes)[i].end();
+				}
+				--it;
+				return *this;
+			}
+			const_iterator& operator-- (int) { const_iterator tmp = *this; --(*this); return tmp; }
+
+			bool operator== (const const_iterator &that) {
+				return scopes == that.scopes && i == that.i && it == that.it;
+			}
+			bool operator!= (const const_iterator &that) { return !( *this == that ); }
+
+		private:
+			scope_list const *scopes;
+			wrapped_const_iterator it;
+			size_type i;
+		};
+		
+		/// Starts a new scope
+		void beginScope() {
+			Scope scope;
+			scopes.push_back(scope);
+		}
+
+		/// Ends a scope; invalidates any iterators pointing to elements of that scope
+		void endScope() {
+			scopes.pop_back();
+		}
+
+		/// Default constructor initializes with one scope
+		ScopedMap() { beginScope(); }
+
+		iterator begin() { return iterator(scopes, scopes.back().begin(), scopes.size()-1); }
+		const_iterator begin() const { return const_iterator(scopes, scopes.back().begin(), scopes.size()-1); }
+		const_iterator cbegin() const { return const_iterator(scopes, scopes.back().begin(), scopes.size()-1); }
+		iterator end() { return iterator(scopes, scopes[0].end(), 0); }
+		const_iterator end() const { return const_iterator(scopes, scopes[0].end(), 0); }
+		const_iterator cend() const { return const_iterator(scopes, scopes[0].end(), 0); }
+
+		/// Gets the index of the current scope (counted from 1)
+		size_type currentScope() const { return scopes.size(); }
+
+		/// Finds the given key in the outermost scope it occurs; returns end() for none such
+		iterator find( const Key &key ) {
+			for ( size_type i = scopes.size() - 1; ; --i ) {
+				typename Scope::iterator val = scopes[i].find( key );
+				if ( val != scopes[i].end() ) return iterator( scopes, val, i );
+				if ( i == 0 ) break;
+			}
+			return end();
+		}
+		const_iterator find( const Key &key ) const { return const_iterator( find( key ) ); }
+		
+		/// Finds the given key in the outermost scope inside the given scope where it occurs
+		iterator findNext( const_iterator &it, const Key &key ) {
+			if ( it.i == 0 ) return end();
+			for ( size_type i = it.i - 1; ; --i ) {
+				typename Scope::iterator val = scopes[i].find( key );
+				if ( val != scopes[i].end() ) return iterator( scopes, val, i );
+				if ( i == 0 ) break;
+			}
+			return end();
+		}
+		const_iterator findNext( const_iterator &it, const Key &key ) const { return const_iterator( findNext( it, key ) ); }
+
+		/// Inserts the given key-value pair into the outermost scope
+		std::pair< iterator, bool > insert( const value_type &value ) {
+			std::pair< typename Scope::iterator, bool > res = scopes.back().insert( value );
+			return std::make_pair( iterator(scopes, res.first, scopes.size()-1), res.second );
+		}
+		std::pair< iterator, bool > insert( const Key &key, const Value &value ) { return insert( std::make_pair( key, value ) ); }
+		
+	};
+} // namespace GenPoly
+
+#endif // _SCOPEDMAP_H
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/GenPoly/ScrubTyVars.cc
===================================================================
--- src/GenPoly/ScrubTyVars.cc	(revision d3b7937ae7ab8afece0824b5729b7e86a9f0bd63)
+++ src/GenPoly/ScrubTyVars.cc	(revision ae8b94256813adfe7582e0fabf10bdd0d8c7b864)
@@ -27,5 +27,5 @@
 	Type * ScrubTyVars::mutate( TypeInstType *typeInst ) {
 		TyVarMap::const_iterator tyVar = tyVars.find( typeInst->get_name() );
-		if ( doAll || tyVar != tyVars.end() ) {
+		if ( tyVar != tyVars.end() ) {
 			switch ( tyVar->second ) {
 			  case TypeDecl::Any:
@@ -42,4 +42,21 @@
 		} // if
 		return typeInst;
+	}
+
+	Type * ScrubTyVars::mutateAggregateType( Type *ty ) {
+		if ( isPolyType( ty, tyVars ) ) {
+			PointerType *ret = new PointerType( Type::Qualifiers(), new VoidType( ty->get_qualifiers() ) );
+			delete ty;
+			return ret;
+		}
+		return ty;
+	}
+	
+	Type * ScrubTyVars::mutate( StructInstType *structInst ) {
+		return mutateAggregateType( structInst );
+	}
+
+	Type * ScrubTyVars::mutate( UnionInstType *unionInst ) {
+		return mutateAggregateType( unionInst );
 	}
 
@@ -65,13 +82,11 @@
 
 	Type * ScrubTyVars::mutate( PointerType *pointer ) {
-		if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( pointer->get_base() ) ) {
-			if ( doAll || tyVars.find( typeInst->get_name() ) != tyVars.end() ) {
-				Type *ret = mutate( typeInst );
-				ret->get_qualifiers() += pointer->get_qualifiers();
-				pointer->set_base( 0 );
-				delete pointer;
-				return ret;
-			} // if
-		} // if
+		if ( Type *polyType = isPolyType( pointer->get_base(), tyVars ) ) {
+			Type *ret = polyType->acceptMutator( *this );
+			ret->get_qualifiers() += pointer->get_qualifiers();
+			pointer->set_base( 0 );
+			delete pointer;
+			return ret;
+		}
 		return Mutator::mutate( pointer );
 	}
Index: src/GenPoly/ScrubTyVars.h
===================================================================
--- src/GenPoly/ScrubTyVars.h	(revision d3b7937ae7ab8afece0824b5729b7e86a9f0bd63)
+++ src/GenPoly/ScrubTyVars.h	(revision ae8b94256813adfe7582e0fabf10bdd0d8c7b864)
@@ -27,19 +27,22 @@
 	class ScrubTyVars : public Mutator {
 	  public:
-		ScrubTyVars( bool doAll, const TyVarMap &tyVars ): doAll( doAll ), tyVars( tyVars ) {}
+		ScrubTyVars( const TyVarMap &tyVars ): tyVars( tyVars ) {}
 
-		/// Like scrub( SynTreeClass* ), but only applies to type variables in `tyVars`
+		/// For all polymorphic types with type variables in `tyVars`, replaces generic types, dtypes, and ftypes with the appropriate void type,
+		/// and sizeof/alignof expressions with the proper variable
 		template< typename SynTreeClass >
 		static SynTreeClass *scrub( SynTreeClass *target, const TyVarMap &tyVars );
-		/// Replaces dtypes and ftypes with the appropriate void type, and sizeof expressions of polymorphic types with the proper variable
-		template< typename SynTreeClass >
-		static SynTreeClass *scrub( SynTreeClass *target );
-  
+
 		virtual Type* mutate( TypeInstType *typeInst );
-		Expression* mutate( SizeofExpr *szeof );
-		Expression* mutate( AlignofExpr *algnof );
+		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 );
+
 	  private:
-		bool doAll;
+		/// Mutates (possibly generic) aggregate types appropriately
+		Type* mutateAggregateType( Type *ty );
+		
 		const TyVarMap &tyVars;
 	};
@@ -48,15 +51,8 @@
 	template< typename SynTreeClass >
 	SynTreeClass * ScrubTyVars::scrub( SynTreeClass *target, const TyVarMap &tyVars ) {
-		ScrubTyVars scrubber( false, tyVars );
+		ScrubTyVars scrubber( tyVars );
 		return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );
 	}
 
-	/* static class method */
-	template< typename SynTreeClass >
-	SynTreeClass * ScrubTyVars::scrub( SynTreeClass *target ) {
-		TyVarMap tyVars;
-		ScrubTyVars scrubber( true, tyVars );
-		return static_cast< SynTreeClass* >( target->acceptMutator( scrubber ) );
-	}
 } // namespace GenPoly
 
