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
