Index: src/GenPoly/InstantiateGeneric.cc
===================================================================
--- src/GenPoly/InstantiateGeneric.cc	(revision ea5daeb4b5e91cb1198c40e000259aabd648fe5a)
+++ src/GenPoly/InstantiateGeneric.cc	(revision 3bb195cb021bb5008ad9c88e1f86b38eb2b977b1)
@@ -24,4 +24,5 @@
 #include "GenPoly.h"
 #include "ScopedMap.h"
+#include "ScopedSet.h"
 
 #include "ResolvExpr/typeops.h"
@@ -122,4 +123,26 @@
 		}
 	};
+
+	/// Possible options for a given specialization of a generic type
+	enum class genericType {
+		dtypeStatic,  ///< Concrete instantiation based solely on {d,f}type-to-void conversions
+		concrete,     ///< Concrete instantiation requiring at least one parameter type
+		dynamic       ///< No concrete instantiation
+	};
+
+	genericType& operator |= ( genericType& gt, const genericType& ht ) {
+		switch ( gt ) {
+		case genericType::dtypeStatic:
+			gt = ht;
+			break;
+		case genericType::concrete:
+			if ( ht == genericType::dynamic ) { gt = genericType::dynamic; }
+			break;
+		case genericType::dynamic:
+			// nothing possible
+			break;
+		}
+		return gt;
+	}
 	
 	/// Mutator pass that replaces concrete instantiations of generic types with actual struct declarations, scoped appropriately
@@ -127,9 +150,11 @@
 		/// Map of (generic type, parameter list) pairs to concrete type instantiations
 		InstantiationMap< AggregateDecl, AggregateDecl > instantiations;
+		/// Set of types which are dtype-only generic (and therefore have static layout)
+		ScopedSet< AggregateDecl* > dtypeStatics;
 		/// Namer for concrete types
 		UniqueName typeNamer;
 
 	public:
-		GenericInstantiator() : DeclMutator(), instantiations(), typeNamer("_conc_") {}
+		GenericInstantiator() : DeclMutator(), instantiations(), dtypeStatics(), typeNamer("_conc_") {}
 
 		virtual Type* mutate( StructInstType *inst );
@@ -147,4 +172,10 @@
 		/// Wrap instantiation insertion for unions
 		void insert( UnionInstType *inst, const std::list< TypeExpr* > &typeSubs, UnionDecl *decl ) { instantiations.insert( inst->get_baseUnion(), typeSubs, decl ); }
+
+		/// If this is an instance of a type already determined to be dtype-static, strips the instances's type parameters and returns true
+		bool stripInstParams( AggregateDecl *base, ReferenceToType *inst );
+	
+		/// Strips a dtype-static aggregate decl of its type parameters, marks it as stripped
+		void stripDtypeParams( AggregateDecl *base, std::list< TypeDecl* >& baseParams, const std::list< TypeExpr* >& typeSubs );
 	};
 
@@ -154,29 +185,6 @@
 	}
 
-	//////////////////////////////////////// GenericInstantiator //////////////////////////////////////////////////
-
-	/// Possible options for a given specialization of a generic type
-	enum class genericType {
-		dtypeStatic,  ///< Concrete instantiation based solely on {d,f}type-to-void conversions
-		concrete,     ///< Concrete instantiation requiring at least one parameter type
-		dynamic       ///< No concrete instantiation
-	};
-
-	genericType& operator |= ( genericType& gt, const genericType& ht ) {
-		switch ( gt ) {
-		case genericType::dtypeStatic:
-			gt = ht;
-			break;
-		case genericType::concrete:
-			if ( ht == genericType::dynamic ) { gt = genericType::dynamic; }
-			break;
-		case genericType::dynamic:
-			// nothing possible
-			break;
-		}
-		return gt;
-	}
-
-	/// Makes substitutions of params into baseParams; returns true if all parameters substituted for a concrete type
+	/// Makes substitutions of params into baseParams; returns dtypeStatic if there is a concrete instantiation based only on {d,f}type-to-void conversions,
+	/// concrete if there is a concrete instantiation requiring at least one parameter type, and dynamic if there is no concrete instantiation
 	genericType makeSubstitutions( const std::list< TypeDecl* >& baseParams, const std::list< Expression* >& params, std::list< TypeExpr* >& out ) {
 		genericType gt = genericType::dtypeStatic;
@@ -223,4 +231,31 @@
 	}
 
+	/// Substitutes types of members according to baseParams => typeSubs, working in-place
+	void substituteMembers( std::list< Declaration* >& members, const std::list< TypeDecl* >& baseParams, const std::list< TypeExpr* >& typeSubs ) {
+		// substitute types into new members
+		TypeSubstitution subs( baseParams.begin(), baseParams.end(), typeSubs.begin() );
+		for ( std::list< Declaration* >::iterator member = members.begin(); member != members.end(); ++member ) {
+			subs.apply(*member);
+		}
+	}
+
+	bool GenericInstantiator::stripInstParams( AggregateDecl *base, ReferenceToType *inst ) {
+		if ( dtypeStatics.find( base ) == dtypeStatics.end() ) return false;
+
+		deleteAll( inst->get_parameters() );
+		inst->get_parameters().clear();
+
+		return true;
+	}
+	
+	void GenericInstantiator::stripDtypeParams( AggregateDecl *base, std::list< TypeDecl* >& baseParams, const std::list< TypeExpr* >& typeSubs ) {
+		substituteMembers( base->get_members(), baseParams, typeSubs );
+
+		deleteAll( baseParams );
+		baseParams.clear();
+		
+		dtypeStatics.insert( base );
+	}
+
 	Type* GenericInstantiator::mutate( StructInstType *inst ) {
 		// mutate subtypes
@@ -231,13 +266,18 @@
 		// exit early if no need for further mutation
 		if ( inst->get_parameters().empty() ) return inst;
+
+		// check for an already-instantiatiated dtype-static type
+		if ( stripInstParams( inst->get_baseStruct(), inst ) ) return inst;
+		
+		// check if type can be concretely instantiated; put substitutions into typeSubs
 		assert( inst->get_baseParameters() && "Base struct has parameters" );
-
-		// check if type can be concretely instantiated; put substitutions into typeSubs
 		std::list< TypeExpr* > typeSubs;
 		genericType gt = makeSubstitutions( *inst->get_baseParameters(), inst->get_parameters(), typeSubs );
 		switch ( gt ) {
-		case genericType::dtypeStatic: // TODO strip params off original decl and reuse here
-		case genericType::concrete:
-		{
+		case genericType::dtypeStatic:
+			stripDtypeParams( inst->get_baseStruct(), *inst->get_baseParameters(), typeSubs );
+			break;
+		
+		case genericType::concrete: {
 			// make concrete instantiation of generic type
 			StructDecl *concDecl = lookup( inst, typeSubs );
@@ -274,11 +314,17 @@
 		// exit early if no need for further mutation
 		if ( inst->get_parameters().empty() ) return inst;
+
+		// check for an already-instantiatiated dtype-static type
+		if ( stripInstParams( inst->get_baseUnion(), inst ) ) return inst;
+
+		// check if type can be concretely instantiated; put substitutions into typeSubs
 		assert( inst->get_baseParameters() && "Base union has parameters" );
-
-		// check if type can be concretely instantiated; put substitutions into typeSubs
 		std::list< TypeExpr* > typeSubs;
 		genericType gt = makeSubstitutions( *inst->get_baseParameters(), inst->get_parameters(), typeSubs );
 		switch ( gt ) {
-		case genericType::dtypeStatic:  // TODO strip params off original decls and reuse here
+		case genericType::dtypeStatic:
+			stripDtypeParams( inst->get_baseUnion(), *inst->get_baseParameters(), typeSubs );
+			break;
+			
 		case genericType::concrete:
 		{
@@ -311,4 +357,5 @@
 		DeclMutator::doBeginScope();
 		instantiations.beginScope();
+		dtypeStatics.beginScope();
 	}
 
@@ -316,4 +363,5 @@
 		DeclMutator::doEndScope();
 		instantiations.endScope();
+		dtypeStatics.endScope();
 	}
 
