Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/GenPoly/Box.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -167,4 +167,6 @@
 			Expression *postmutate( OffsetofExpr *offsetofExpr );
 			Expression *postmutate( OffsetPackExpr *offsetPackExpr );
+			void premutate( StructDecl * );
+			void premutate( UnionDecl * );
 
 			void beginScope();
@@ -178,4 +180,6 @@
 			/// adds type parameters to the layout call; will generate the appropriate parameters if needed
 			void addOtypeParamsToLayoutCall( UntypedExpr *layoutCall, const std::list< Type* > &otypeParams );
+			/// change the type of generic aggregate members to char[]
+			void mutateMembers( AggregateDecl * aggrDecl );
 
 			/// Enters a new scope for type-variables, adding the type variables from ty
@@ -1414,4 +1418,5 @@
 
 		void PolyGenericCalculator::premutate( TypedefDecl *typedefDecl ) {
+			assert(false);
 			beginTypeScope( typedefDecl->get_base() );
 		}
@@ -1460,4 +1465,43 @@
 		}
 
+		/// converts polymorphic type T into a suitable monomorphic representation, currently: __attribute__((aligned(8)) char[size_T]
+		Type * polyToMonoType( Type * declType ) {
+			Type * charType = new BasicType( Type::Qualifiers(), BasicType::Kind::Char);
+			Expression * size = new NameExpr( sizeofName( mangleType(declType) ) );
+			Attribute * aligned = new Attribute( "aligned", std::list<Expression*>{ new ConstantExpr( Constant::from_int(8) ) } );
+			return new ArrayType( Type::Qualifiers(), charType, size,
+				true, false, std::list<Attribute *>{ aligned } );
+		}
+
+		void PolyGenericCalculator::mutateMembers( AggregateDecl * aggrDecl ) {
+			std::set< std::string > genericParams;
+			for ( TypeDecl * td : aggrDecl->parameters ) {
+				genericParams.insert( td->name );
+			}
+			for ( Declaration * decl : aggrDecl->members ) {
+				if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( decl ) ) {
+					Type * ty = replaceTypeInst( field->type, env );
+					if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( ty ) ) {
+						// do not try to monomorphize generic parameters
+						if ( scopeTyVars.find( typeInst->get_name() ) != scopeTyVars.end() && ! genericParams.count( typeInst->name ) ) {
+							// polymorphic aggregate members should be converted into monomorphic members.
+							// Using char[size_T] here respects the expected sizing rules of an aggregate type.
+							Type * newType = polyToMonoType( field->type );
+							delete field->type;
+							field->type = newType;
+						}
+					}
+				}
+			}
+		}
+
+		void PolyGenericCalculator::premutate( StructDecl * structDecl ) {
+			mutateMembers( structDecl );
+		}
+
+		void PolyGenericCalculator::premutate( UnionDecl * unionDecl ) {
+			mutateMembers( unionDecl );
+		}
+
 		void PolyGenericCalculator::premutate( DeclStmt *declStmt ) {
 			if ( ObjectDecl *objectDecl = dynamic_cast< ObjectDecl *>( declStmt->get_decl() ) ) {
@@ -1465,8 +1509,5 @@
 					// change initialization of a polymorphic value object to allocate via a VLA
 					// (alloca was previously used, but can't be safely used in loops)
-					Type *declType = objectDecl->get_type();
-					ObjectDecl *newBuf = new ObjectDecl( bufNamer.newName(), Type::StorageClasses(), LinkageSpec::C, 0,
-						new ArrayType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::Kind::Char), new NameExpr( sizeofName( mangleType(declType) ) ),
-						true, false, std::list<Attribute*>{ new Attribute( "aligned", std::list<Expression*>{ new ConstantExpr( Constant::from_int(8) ) } ) } ), 0 );
+					ObjectDecl *newBuf = ObjectDecl::newObject( bufNamer.newName(), polyToMonoType( objectDecl->type ), nullptr );
 					stmtsToAddBefore.push_back( new DeclStmt( noLabels, newBuf ) );
 
Index: src/GenPoly/InstantiateGeneric.cc
===================================================================
--- src/GenPoly/InstantiateGeneric.cc	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/GenPoly/InstantiateGeneric.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -27,4 +27,5 @@
 #include "Common/utility.h"            // for deleteAll, cloneAll
 #include "GenPoly.h"                   // for isPolyType, typesPolyCompatible
+#include "ResolvExpr/typeops.h"
 #include "ScopedSet.h"                 // for ScopedSet, ScopedSet<>::iterator
 #include "ScrubTyVars.h"               // for ScrubTyVars
@@ -151,4 +152,12 @@
 		return gt;
 	}
+
+	/// Add cast to dtype-static member expressions so that type information is not lost in GenericInstantiator
+	struct FixDtypeStatic final {
+		Expression * postmutate( MemberExpr * memberExpr );
+
+		template<typename AggrInst>
+		Expression * fixMemberExpr( AggrInst * inst, MemberExpr * memberExpr );
+	};
 
 	/// Mutator pass that replaces concrete instantiations of generic types with actual struct declarations, scoped appropriately
@@ -198,6 +207,13 @@
 
 	void instantiateGeneric( std::list< Declaration* > &translationUnit ) {
+		PassVisitor<FixDtypeStatic> fixer;
 		PassVisitor<GenericInstantiator> instantiator;
+
+		mutateAll( translationUnit, fixer );
 		mutateAll( translationUnit, instantiator );
+	}
+
+	bool isDtypeStatic( const std::list< TypeDecl* >& baseParams ) {
+		return std::all_of( baseParams.begin(), baseParams.end(), []( TypeDecl * td ) { return ! td->isComplete(); } );
 	}
 
@@ -479,4 +495,29 @@
 	}
 
+	template< typename AggrInst >
+	Expression * FixDtypeStatic::fixMemberExpr( AggrInst * inst, MemberExpr * memberExpr ) {
+		// need to cast dtype-static member expressions to their actual type before that type is erased.
+		auto & baseParams = *inst->get_baseParameters();
+		if ( isDtypeStatic( baseParams ) ) {
+			if ( ! ResolvExpr::typesCompatible( memberExpr->result, memberExpr->member->get_type(), SymTab::Indexer() ) ) {
+				// type of member and type of expression differ, so add cast to actual type
+				return new CastExpr( memberExpr, memberExpr->result->clone() );
+			}
+		}
+		return memberExpr;
+	}
+
+	Expression * FixDtypeStatic::postmutate( MemberExpr * memberExpr ) {
+		Type * aggrType = memberExpr->aggregate->result;
+		if ( isGenericType( aggrType ) ) {
+			if ( StructInstType * inst = dynamic_cast< StructInstType * >( aggrType ) ) {
+				return fixMemberExpr( inst, memberExpr );
+			} else if ( UnionInstType * inst = dynamic_cast< UnionInstType * >( aggrType ) ) {
+				return fixMemberExpr( inst, memberExpr );
+			}
+		}
+		return memberExpr;
+	}
+
 } // namespace GenPoly
 
Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/InitTweak/FixInit.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -393,7 +393,7 @@
 			if ( skipCopyConstruct( result ) ) return; // skip certain non-copyable types
 
-			// type may involve type variables, so apply type substitution to get temporary variable's actual type.
+			// type may involve type variables, so apply type substitution to get temporary variable's actual type,
+			// since result type may not be substituted (e.g., if the type does not appear in the parameter list)
 			// Use applyFree so that types bound in function pointers are not substituted, e.g. in forall(dtype T) void (*)(T).
-			result = result->clone();
 			env->applyFree( result );
 			ObjectDecl * tmp = ObjectDecl::newObject( "__tmp", result, nullptr );
@@ -570,11 +570,5 @@
 
 			if ( returnDecl ) {
-				UntypedExpr * assign = new UntypedExpr( new NameExpr( "?=?" ) );
-				assign->get_args().push_back( new VariableExpr( returnDecl ) );
-				assign->get_args().push_back( callExpr );
-				// know the result type of the assignment is the type of the LHS (minus the pointer), so
-				// add that onto the assignment expression so that later steps have the necessary information
-				assign->set_result( returnDecl->get_type()->clone() );
-
+				ApplicationExpr * assign = createBitwiseAssignment( new VariableExpr( returnDecl ), callExpr );
 				Expression * retExpr = new CommaExpr( assign, new VariableExpr( returnDecl ) );
 				// move env from callExpr to retExpr
@@ -943,17 +937,4 @@
 		}
 
-		void addIds( SymTab::Indexer & indexer, const std::list< DeclarationWithType * > & decls ) {
-			for ( auto d : decls ) {
-				indexer.addId( d );
-			}
-		}
-
-		void addTypes( SymTab::Indexer & indexer, const std::list< TypeDecl * > & tds ) {
-			for ( auto td : tds ) {
-				indexer.addType( td );
-				addIds( indexer, td->assertions );
-			}
-		}
-
 		void GenStructMemberCalls::previsit( FunctionDecl * funcDecl ) {
 			GuardValue( function );
@@ -1012,7 +993,5 @@
 				// need to explicitly re-add function parameters to the indexer in order to resolve copy constructors
 				auto guard = makeFuncGuard( [this]() { indexer.enterScope(); }, [this]() { indexer.leaveScope(); } );
-				addTypes( indexer, function->type->forall );
-				addIds( indexer, function->type->returnVals );
-				addIds( indexer, function->type->parameters );
+				indexer.addFunctionType( function->type );
 
 				// need to iterate through members in reverse in order for
@@ -1029,5 +1008,5 @@
 					// insert and resolve default/copy constructor call for each field that's unhandled
 					std::list< Statement * > stmt;
-					Expression * arg2 = 0;
+					Expression * arg2 = nullptr;
 					if ( isCopyConstructor( function ) ) {
 						// if copy ctor, need to pass second-param-of-this-function.field
@@ -1161,8 +1140,4 @@
 			assert( ctorExpr->result && ctorExpr->get_result()->size() == 1 );
 
-			// xxx - ideally we would reuse the temporary generated from the copy constructor passes from within firstArg if it exists and not generate a temporary if it's unnecessary.
-			ObjectDecl * tmp = ObjectDecl::newObject( tempNamer.newName(), ctorExpr->get_result()->clone(), nullptr );
-			declsToAddBefore.push_back( tmp );
-
 			// xxx - this can be TupleAssignExpr now. Need to properly handle this case.
 			ApplicationExpr * callExpr = strict_dynamic_cast< ApplicationExpr * > ( ctorExpr->get_callExpr() );
@@ -1170,4 +1145,8 @@
 			ctorExpr->set_callExpr( nullptr );
 			ctorExpr->set_env( nullptr );
+
+			// xxx - ideally we would reuse the temporary generated from the copy constructor passes from within firstArg if it exists and not generate a temporary if it's unnecessary.
+			ObjectDecl * tmp = ObjectDecl::newObject( tempNamer.newName(), callExpr->args.front()->result->clone(), nullptr );
+			declsToAddBefore.push_back( tmp );
 			delete ctorExpr;
 
Index: src/InitTweak/InitTweak.cc
===================================================================
--- src/InitTweak/InitTweak.cc	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/InitTweak/InitTweak.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -12,4 +12,5 @@
 #include "Parser/LinkageSpec.h"    // for Spec, isBuiltin, Intrinsic
 #include "ResolvExpr/typeops.h"    // for typesCompatibleIgnoreQualifiers
+#include "SymTab/Autogen.h"
 #include "SymTab/Indexer.h"        // for Indexer
 #include "SynTree/Attribute.h"     // for Attribute
@@ -524,4 +525,23 @@
 	}
 
+	ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src ) {
+		static FunctionDecl * assign = nullptr;
+		if ( ! assign ) {
+			// temporary? Generate a fake assignment operator to represent bitwise assignments.
+			// This operator could easily exist as a real function, but it's tricky because nothing should resolve to this function.
+			TypeDecl * td = new TypeDecl( "T", noStorageClasses, nullptr, TypeDecl::Dtype, true );
+			assign = new FunctionDecl( "?=?", noStorageClasses, LinkageSpec::Intrinsic, SymTab::genAssignType( new TypeInstType( noQualifiers, td->name, td ) ), nullptr );
+		}
+		if ( dynamic_cast< ReferenceType * >( dst->result ) ) {
+			dst = new AddressExpr( dst );
+		} else {
+			dst = new CastExpr( dst, new ReferenceType( noQualifiers, dst->result->clone() ) );
+		}
+		if ( dynamic_cast< ReferenceType * >( src->result ) ) {
+			src = new CastExpr( src, new ReferenceType( noQualifiers, src->result->stripReferences()->clone() ) );
+		}
+		return new ApplicationExpr( VariableExpr::functionPointer( assign ), { dst, src } );
+	}
+
 	class ConstExprChecker : public Visitor {
 	public:
Index: src/InitTweak/InitTweak.h
===================================================================
--- src/InitTweak/InitTweak.h	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/InitTweak/InitTweak.h	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -35,4 +35,7 @@
 	/// returns the first parameter of a constructor/destructor/assignment function
 	ObjectDecl * getParamThis( FunctionType * ftype );
+
+	/// generate a bitwise assignment operation.
+	ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src );
 
 	/// transform Initializer into an argument list that can be passed to a call expression
Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/Makefile.in	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -210,4 +210,5 @@
 	ResolvExpr/driver_cfa_cpp-TypeEnvironment.$(OBJEXT) \
 	ResolvExpr/driver_cfa_cpp-CurrentObject.$(OBJEXT) \
+	ResolvExpr/driver_cfa_cpp-ExplodedActual.$(OBJEXT) \
 	SymTab/driver_cfa_cpp-Indexer.$(OBJEXT) \
 	SymTab/driver_cfa_cpp-Mangler.$(OBJEXT) \
@@ -511,12 +512,13 @@
 	ResolvExpr/FindOpenVars.cc ResolvExpr/PolyCost.cc \
 	ResolvExpr/Occurs.cc ResolvExpr/TypeEnvironment.cc \
-	ResolvExpr/CurrentObject.cc SymTab/Indexer.cc \
-	SymTab/Mangler.cc SymTab/Validate.cc SymTab/FixFunction.cc \
-	SymTab/ImplementationType.cc SymTab/TypeEquality.cc \
-	SymTab/Autogen.cc SynTree/Type.cc SynTree/VoidType.cc \
-	SynTree/BasicType.cc SynTree/PointerType.cc \
-	SynTree/ArrayType.cc SynTree/ReferenceType.cc \
-	SynTree/FunctionType.cc SynTree/ReferenceToType.cc \
-	SynTree/TupleType.cc SynTree/TypeofType.cc SynTree/AttrType.cc \
+	ResolvExpr/CurrentObject.cc ResolvExpr/ExplodedActual.cc \
+	SymTab/Indexer.cc SymTab/Mangler.cc SymTab/Validate.cc \
+	SymTab/FixFunction.cc SymTab/ImplementationType.cc \
+	SymTab/TypeEquality.cc SymTab/Autogen.cc SynTree/Type.cc \
+	SynTree/VoidType.cc SynTree/BasicType.cc \
+	SynTree/PointerType.cc SynTree/ArrayType.cc \
+	SynTree/ReferenceType.cc SynTree/FunctionType.cc \
+	SynTree/ReferenceToType.cc SynTree/TupleType.cc \
+	SynTree/TypeofType.cc SynTree/AttrType.cc \
 	SynTree/VarArgsType.cc SynTree/ZeroOneType.cc \
 	SynTree/Constant.cc SynTree/Expression.cc SynTree/TupleExpr.cc \
@@ -825,4 +827,7 @@
 	ResolvExpr/$(am__dirstamp) \
 	ResolvExpr/$(DEPDIR)/$(am__dirstamp)
+ResolvExpr/driver_cfa_cpp-ExplodedActual.$(OBJEXT):  \
+	ResolvExpr/$(am__dirstamp) \
+	ResolvExpr/$(DEPDIR)/$(am__dirstamp)
 SymTab/$(am__dirstamp):
 	@$(MKDIR_P) SymTab
@@ -1022,4 +1027,5 @@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/driver_cfa_cpp-ConversionCost.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/driver_cfa_cpp-CurrentObject.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/driver_cfa_cpp-ExplodedActual.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/driver_cfa_cpp-FindOpenVars.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/driver_cfa_cpp-Occurs.Po@am__quote@
@@ -1964,4 +1970,18 @@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o ResolvExpr/driver_cfa_cpp-CurrentObject.obj `if test -f 'ResolvExpr/CurrentObject.cc'; then $(CYGPATH_W) 'ResolvExpr/CurrentObject.cc'; else $(CYGPATH_W) '$(srcdir)/ResolvExpr/CurrentObject.cc'; fi`
 
+ResolvExpr/driver_cfa_cpp-ExplodedActual.o: ResolvExpr/ExplodedActual.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT ResolvExpr/driver_cfa_cpp-ExplodedActual.o -MD -MP -MF ResolvExpr/$(DEPDIR)/driver_cfa_cpp-ExplodedActual.Tpo -c -o ResolvExpr/driver_cfa_cpp-ExplodedActual.o `test -f 'ResolvExpr/ExplodedActual.cc' || echo '$(srcdir)/'`ResolvExpr/ExplodedActual.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) ResolvExpr/$(DEPDIR)/driver_cfa_cpp-ExplodedActual.Tpo ResolvExpr/$(DEPDIR)/driver_cfa_cpp-ExplodedActual.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='ResolvExpr/ExplodedActual.cc' object='ResolvExpr/driver_cfa_cpp-ExplodedActual.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o ResolvExpr/driver_cfa_cpp-ExplodedActual.o `test -f 'ResolvExpr/ExplodedActual.cc' || echo '$(srcdir)/'`ResolvExpr/ExplodedActual.cc
+
+ResolvExpr/driver_cfa_cpp-ExplodedActual.obj: ResolvExpr/ExplodedActual.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT ResolvExpr/driver_cfa_cpp-ExplodedActual.obj -MD -MP -MF ResolvExpr/$(DEPDIR)/driver_cfa_cpp-ExplodedActual.Tpo -c -o ResolvExpr/driver_cfa_cpp-ExplodedActual.obj `if test -f 'ResolvExpr/ExplodedActual.cc'; then $(CYGPATH_W) 'ResolvExpr/ExplodedActual.cc'; else $(CYGPATH_W) '$(srcdir)/ResolvExpr/ExplodedActual.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) ResolvExpr/$(DEPDIR)/driver_cfa_cpp-ExplodedActual.Tpo ResolvExpr/$(DEPDIR)/driver_cfa_cpp-ExplodedActual.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='ResolvExpr/ExplodedActual.cc' object='ResolvExpr/driver_cfa_cpp-ExplodedActual.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o ResolvExpr/driver_cfa_cpp-ExplodedActual.obj `if test -f 'ResolvExpr/ExplodedActual.cc'; then $(CYGPATH_W) 'ResolvExpr/ExplodedActual.cc'; else $(CYGPATH_W) '$(srcdir)/ResolvExpr/ExplodedActual.cc'; fi`
+
 SymTab/driver_cfa_cpp-Indexer.o: SymTab/Indexer.cc
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT SymTab/driver_cfa_cpp-Indexer.o -MD -MP -MF SymTab/$(DEPDIR)/driver_cfa_cpp-Indexer.Tpo -c -o SymTab/driver_cfa_cpp-Indexer.o `test -f 'SymTab/Indexer.cc' || echo '$(srcdir)/'`SymTab/Indexer.cc
Index: src/ResolvExpr/Alternative.cc
===================================================================
--- src/ResolvExpr/Alternative.cc	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/ResolvExpr/Alternative.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -18,4 +18,5 @@
 #include <ostream>                       // for operator<<, ostream, basic_o...
 #include <string>                        // for operator<<, char_traits, string
+#include <utility>                       // for move
 
 #include "Common/utility.h"              // for maybeClone
@@ -81,4 +82,18 @@
 		os << std::endl;
 	}
+
+	void splice( AltList& dst, AltList& src ) {
+		dst.reserve( dst.size() + src.size() );
+		for ( Alternative& alt : src ) {
+			dst.push_back( std::move(alt) );
+		}
+		src.clear();
+	}
+
+	void spliceBegin( AltList& dst, AltList& src ) {
+		splice( src, dst );
+		dst.swap( src );
+	}
+
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/Alternative.h
===================================================================
--- src/ResolvExpr/Alternative.h	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/ResolvExpr/Alternative.h	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -17,5 +17,5 @@
 
 #include <iosfwd>             // for ostream
-#include <list>               // for list
+#include <vector>             // for vector
 
 #include "Cost.h"             // for Cost
@@ -25,8 +25,4 @@
 
 namespace ResolvExpr {
-	struct Alternative;
-
-	typedef std::list< Alternative > AltList;
-
 	struct Alternative {
 		Alternative();
@@ -41,4 +37,11 @@
 		void print( std::ostream &os, Indenter indent = {} ) const;
 
+		/// Returns the stored expression, but released from management of this Alternative
+		Expression* release_expr() {
+			Expression* tmp = expr;
+			expr = nullptr;
+			return tmp;
+		}
+
 		Cost cost;
 		Cost cvtCost;
@@ -46,4 +49,12 @@
 		TypeEnvironment env;
 	};
+
+	typedef std::vector< Alternative > AltList;
+
+	/// Moves all elements from src to the end of dst
+	void splice( AltList& dst, AltList& src );
+
+	/// Moves all elements from src to the beginning of dst
+	void spliceBegin( AltList& dst, AltList& src );
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -16,9 +16,10 @@
 #include <algorithm>               // for copy
 #include <cassert>                 // for strict_dynamic_cast, assert, assertf
+#include <cstddef>                 // for size_t
 #include <iostream>                // for operator<<, cerr, ostream, endl
 #include <iterator>                // for back_insert_iterator, back_inserter
 #include <list>                    // for _List_iterator, list, _List_const_...
 #include <map>                     // for _Rb_tree_iterator, map, _Rb_tree_c...
-#include <memory>                  // for allocator_traits<>::value_type
+#include <memory>                  // for allocator_traits<>::value_type, unique_ptr
 #include <utility>                 // for pair
 #include <vector>                  // for vector
@@ -29,4 +30,5 @@
 #include "Common/utility.h"        // for deleteAll, printAll, CodeLocation
 #include "Cost.h"                  // for Cost, Cost::zero, operator<<, Cost...
+#include "ExplodedActual.h"        // for ExplodedActual
 #include "InitTweak/InitTweak.h"   // for getFunctionName
 #include "RenameVars.h"            // for RenameVars, global_renamer
@@ -50,4 +52,10 @@
 #define PRINT( text ) if ( resolvep ) { text }
 //#define DEBUG_COST
+
+using std::move;
+
+/// copies any copyable type
+template<typename T>
+T copy(const T& x) { return x; }
 
 namespace ResolvExpr {
@@ -179,4 +187,7 @@
 		expr->accept( *this );
 		if ( failFast && alternatives.empty() ) {
+			PRINT(
+				std::cerr << "No reasonable alternatives for expression " << expr << std::endl;
+			)
 			throw SemanticError( "No reasonable alternatives for expression ", expr );
 		}
@@ -187,7 +198,7 @@
 				printAlts( alternatives, std::cerr );
 			)
-			AltList::iterator oldBegin = alternatives.begin();
-			pruneAlternatives( alternatives.begin(), alternatives.end(), front_inserter( alternatives ) );
-			if ( failFast && alternatives.begin() == oldBegin ) {
+			AltList pruned;
+			pruneAlternatives( alternatives.begin(), alternatives.end(), back_inserter( pruned ) );
+			if ( failFast && pruned.empty() ) {
 				std::ostringstream stream;
 				AltList winners;
@@ -199,5 +210,5 @@
 				throw SemanticError( stream.str() );
 			}
-			alternatives.erase( oldBegin, alternatives.end() );
+			alternatives = move(pruned);
 			PRINT(
 				std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
@@ -571,49 +582,63 @@
 	/// State to iteratively build a match of parameter expressions to arguments
 	struct ArgPack {
-		AltList actuals;                 ///< Arguments included in this pack
-		TypeEnvironment env;             ///< Environment for this pack
-		AssertionSet need;               ///< Assertions outstanding for this pack
-		AssertionSet have;               ///< Assertions found for this pack
-		OpenVarSet openVars;             ///< Open variables for this pack
-		unsigned nextArg;                ///< Index of next argument in arguments list
-		std::vector<Alternative> expls;  ///< Exploded actuals left over from last match
-		unsigned nextExpl;               ///< Index of next exploded alternative to use
-		std::vector<unsigned> tupleEls;  /// Number of elements in current tuple element(s)
+		std::size_t parent;                ///< Index of parent pack
+		std::unique_ptr<Expression> expr;  ///< The argument stored here
+		Cost cost;                         ///< The cost of this argument
+		TypeEnvironment env;               ///< Environment for this pack
+		AssertionSet need;                 ///< Assertions outstanding for this pack
+		AssertionSet have;                 ///< Assertions found for this pack
+		OpenVarSet openVars;               ///< Open variables for this pack
+		unsigned nextArg;                  ///< Index of next argument in arguments list
+		unsigned tupleStart;               ///< Number of tuples that start at this index
+		unsigned nextExpl;                 ///< Index of next exploded element
+		unsigned explAlt;                  ///< Index of alternative for nextExpl > 0
+
+		ArgPack()
+			: parent(0), expr(), cost(Cost::zero), env(), need(), have(), openVars(), nextArg(0),
+
+			  tupleStart(0), nextExpl(0), explAlt(0) {}
 
 		ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have,
 				const OpenVarSet& openVars)
-			: actuals(), env(env), need(need), have(have), openVars(openVars), nextArg(0),
-			  expls(), nextExpl(0), tupleEls() {}
-
-		/// Starts a new tuple expression
-		void beginTuple() {
-			if ( ! tupleEls.empty() ) ++tupleEls.back();
-			tupleEls.push_back(0);
+			: parent(0), expr(), cost(Cost::zero), env(env), need(need), have(have),
+			  openVars(openVars), nextArg(0), tupleStart(0), nextExpl(0), explAlt(0) {}
+
+		ArgPack(std::size_t parent, Expression* expr, TypeEnvironment&& env, AssertionSet&& need,
+				AssertionSet&& have, OpenVarSet&& openVars, unsigned nextArg,
+				unsigned tupleStart = 0, Cost cost = Cost::zero, unsigned nextExpl = 0,
+				unsigned explAlt = 0 )
+			: parent(parent), expr(expr->clone()), cost(cost), env(move(env)), need(move(need)),
+			  have(move(have)), openVars(move(openVars)), nextArg(nextArg), tupleStart(tupleStart),
+			  nextExpl(nextExpl), explAlt(explAlt) {}
+
+		ArgPack(const ArgPack& o, TypeEnvironment&& env, AssertionSet&& need, AssertionSet&& have,
+				OpenVarSet&& openVars, unsigned nextArg, Cost added )
+			: parent(o.parent), expr(o.expr ? o.expr->clone() : nullptr), cost(o.cost + added),
+			  env(move(env)), need(move(need)), have(move(have)), openVars(move(openVars)),
+			  nextArg(nextArg), tupleStart(o.tupleStart), nextExpl(0), explAlt(0) {}
+
+		/// true iff this pack is in the middle of an exploded argument
+		bool hasExpl() const { return nextExpl > 0; }
+
+		/// Gets the list of exploded alternatives for this pack
+		const ExplodedActual& getExpl( const ExplodedArgs& args ) const {
+			return args[nextArg-1][explAlt];
 		}
 
 		/// Ends a tuple expression, consolidating the appropriate actuals
-		void endTuple() {
-			// set up new Tuple alternative
+		void endTuple( const std::vector<ArgPack>& packs ) {
+			// add all expressions in tuple to list, summing cost
 			std::list<Expression*> exprs;
-			Cost cost = Cost::zero;
-
-			// transfer elements into alternative
-			for (unsigned i = 0; i < tupleEls.back(); ++i) {
-				exprs.push_front( actuals.back().expr );
-				actuals.back().expr = nullptr;
-				cost += actuals.back().cost;
-				actuals.pop_back();
-			}
-			tupleEls.pop_back();
-
-			// build new alternative
-			actuals.emplace_back( new TupleExpr( exprs ), this->env, cost );
-		}
-
-		/// Clones and adds an actual, returns this
-		ArgPack& withArg( Expression* expr, Cost cost = Cost::zero ) {
-			actuals.emplace_back( expr->clone(), this->env, cost );
-			if ( ! tupleEls.empty() ) ++tupleEls.back();
-			return *this;
+			const ArgPack* pack = this;
+			if ( expr ) { exprs.push_front( expr.release() ); }
+			while ( pack->tupleStart == 0 ) {
+				pack = &packs[pack->parent];
+				exprs.push_front( pack->expr->clone() );
+				cost += pack->cost;
+			}
+			// reset pack to appropriate tuple
+			expr.reset( new TupleExpr( exprs ) );
+			tupleStart = pack->tupleStart - 1;
+			parent = pack->parent;
 		}
 	};
@@ -621,99 +646,158 @@
 	/// Instantiates an argument to match a formal, returns false if no results left
 	bool instantiateArgument( Type* formalType, Initializer* initializer,
-			const std::vector< AlternativeFinder >& args,
-			std::vector<ArgPack>& results, std::vector<ArgPack>& nextResults,
-			const SymTab::Indexer& indexer ) {
+			const ExplodedArgs& args, std::vector<ArgPack>& results, std::size_t& genStart,
+			const SymTab::Indexer& indexer, unsigned nTuples = 0 ) {
 		if ( TupleType* tupleType = dynamic_cast<TupleType*>( formalType ) ) {
 			// formalType is a TupleType - group actuals into a TupleExpr
-			for ( ArgPack& result : results ) { result.beginTuple(); }
+			++nTuples;
 			for ( Type* type : *tupleType ) {
 				// xxx - dropping initializer changes behaviour from previous, but seems correct
-				if ( ! instantiateArgument( type, nullptr, args, results, nextResults, indexer ) )
+				if ( ! instantiateArgument(
+						type, nullptr, args, results, genStart, indexer, nTuples ) )
 					return false;
-			}
-			for ( ArgPack& result : results ) { result.endTuple(); }
+				nTuples = 0;
+			}
+			// re-consititute tuples for final generation
+			for ( auto i = genStart; i < results.size(); ++i ) {
+				results[i].endTuple( results );
+			}
 			return true;
 		} else if ( TypeInstType* ttype = Tuples::isTtype( formalType ) ) {
 			// formalType is a ttype, consumes all remaining arguments
 			// xxx - mixing default arguments with variadic??
-			std::vector<ArgPack> finalResults{};  /// list of completed tuples
-			// start tuples
-			for ( ArgPack& result : results ) {
-				result.beginTuple();
-
-				// use rest of exploded tuple if present
-				while ( result.nextExpl < result.expls.size() ) {
-					const Alternative& actual = result.expls[result.nextExpl];
-					result.env.addActual( actual.env, result.openVars );
-					result.withArg( actual.expr );
-					++result.nextExpl;
-				}
-			}
+
+			// completed tuples; will be spliced to end of results to finish
+			std::vector<ArgPack> finalResults{};
+
 			// iterate until all results completed
-			while ( ! results.empty() ) {
+			std::size_t genEnd;
+			++nTuples;
+			do {
+				genEnd = results.size();
+
 				// add another argument to results
-				for ( ArgPack& result : results ) {
-					// finish result when out of arguments
-					if ( result.nextArg >= args.size() ) {
-						Type* argType = result.actuals.back().expr->get_result();
-						if ( result.tupleEls.back() == 1 && Tuples::isTtype( argType ) ) {
-							// the case where a ttype value is passed directly is special, e.g. for
-							// argument forwarding purposes
-							// xxx - what if passing multiple arguments, last of which is ttype?
-							// xxx - what would happen if unify was changed so that unifying tuple
-							// types flattened both before unifying lists? then pass in TupleType
-							// (ttype) below.
-							result.tupleEls.pop_back();
-						} else {
-							// collapse leftover arguments into tuple
-							result.endTuple();
-							argType = result.actuals.back().expr->get_result();
+				for ( std::size_t i = genStart; i < genEnd; ++i ) {
+					auto nextArg = results[i].nextArg;
+
+					// use next element of exploded tuple if present
+					if ( results[i].hasExpl() ) {
+						const ExplodedActual& expl = results[i].getExpl( args );
+
+						unsigned nextExpl = results[i].nextExpl + 1;
+						if ( nextExpl == expl.exprs.size() ) {
+							nextExpl = 0;
 						}
-						// check unification for ttype before adding to final
-						if ( unify( ttype, argType, result.env, result.need, result.have,
-								result.openVars, indexer ) ) {
-							finalResults.push_back( std::move(result) );
-						}
+
+						results.emplace_back(
+							i, expl.exprs[results[i].nextExpl].get(), copy(results[i].env),
+							copy(results[i].need), copy(results[i].have),
+							copy(results[i].openVars), nextArg, nTuples, Cost::zero, nextExpl,
+							results[i].explAlt );
+
 						continue;
 					}
 
+					// finish result when out of arguments
+					if ( nextArg >= args.size() ) {
+						ArgPack newResult{
+							results[i].env, results[i].need, results[i].have,
+							results[i].openVars };
+						newResult.nextArg = nextArg;
+						Type* argType;
+
+						if ( nTuples > 0 ) {
+							// first iteration, push empty tuple expression
+							newResult.parent = i;
+							std::list<Expression*> emptyList;
+							newResult.expr.reset( new TupleExpr( emptyList ) );
+							argType = newResult.expr->get_result();
+						} else {
+							// clone result to collect tuple
+							newResult.parent = results[i].parent;
+							newResult.cost = results[i].cost;
+							newResult.tupleStart = results[i].tupleStart;
+							newResult.expr.reset( results[i].expr->clone() );
+							argType = newResult.expr->get_result();
+
+							if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {
+								// the case where a ttype value is passed directly is special,
+								// e.g. for argument forwarding purposes
+								// xxx - what if passing multiple arguments, last of which is
+								//       ttype?
+								// xxx - what would happen if unify was changed so that unifying
+								//       tuple
+								// types flattened both before unifying lists? then pass in
+								// TupleType (ttype) below.
+								--newResult.tupleStart;
+							} else {
+								// collapse leftover arguments into tuple
+								newResult.endTuple( results );
+								argType = newResult.expr->get_result();
+							}
+						}
+
+						// check unification for ttype before adding to final
+						if ( unify( ttype, argType, newResult.env, newResult.need, newResult.have,
+								newResult.openVars, indexer ) ) {
+							finalResults.push_back( move(newResult) );
+						}
+
+						continue;
+					}
+
 					// add each possible next argument
-					for ( const Alternative& actual : args[result.nextArg] ) {
-						ArgPack aResult = result;  // copy to clone everything
-						// add details of actual to result
-						aResult.env.addActual( actual.env, aResult.openVars );
-						Cost cost = actual.cost;
-
-						// explode argument
-						std::vector<Alternative> exploded;
-						Tuples::explode( actual, indexer, back_inserter( exploded ) );
-
-						// add exploded argument to tuple
-						for ( Alternative& aActual : exploded ) {
-							aResult.withArg( aActual.expr, cost );
-							cost = Cost::zero;
+					for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
+						const ExplodedActual& expl = args[nextArg][j];
+
+						// fresh copies of parent parameters for this iteration
+						TypeEnvironment env = results[i].env;
+						OpenVarSet openVars = results[i].openVars;
+
+						env.addActual( expl.env, openVars );
+
+						// skip empty tuple arguments by (near-)cloning parent into next gen
+						if ( expl.exprs.empty() ) {
+							results.emplace_back(
+								results[i], move(env), copy(results[i].need),
+								copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
+
+							continue;
 						}
-						++aResult.nextArg;
-						nextResults.push_back( std::move(aResult) );
+
+						// add new result
+						results.emplace_back(
+							i, expl.exprs.front().get(), move(env), copy(results[i].need),
+							copy(results[i].have), move(openVars), nextArg + 1,
+							nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
 					}
 				}
 
 				// reset for next round
-				results.swap( nextResults );
-				nextResults.clear();
-			}
-			results.swap( finalResults );
-			return ! results.empty();
+				genStart = genEnd;
+				nTuples = 0;
+			} while ( genEnd != results.size() );
+
+			// splice final results onto results
+			for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
+				results.push_back( move(finalResults[i]) );
+			}
+			return ! finalResults.empty();
 		}
 
 		// iterate each current subresult
-		for ( unsigned iResult = 0; iResult < results.size(); ++iResult ) {
-			ArgPack& result = results[iResult];
-
-			if ( result.nextExpl < result.expls.size() ) {
-				// use remainder of exploded tuple if present
-				const Alternative& actual = result.expls[result.nextExpl];
-				result.env.addActual( actual.env, result.openVars );
-				Type* actualType = actual.expr->get_result();
+		std::size_t genEnd = results.size();
+		for ( std::size_t i = genStart; i < genEnd; ++i ) {
+			auto nextArg = results[i].nextArg;
+
+			// use remainder of exploded tuple if present
+			if ( results[i].hasExpl() ) {
+				const ExplodedActual& expl = results[i].getExpl( args );
+				Expression* expr = expl.exprs[results[i].nextExpl].get();
+
+				TypeEnvironment env = results[i].env;
+				AssertionSet need = results[i].need, have = results[i].have;
+				OpenVarSet openVars = results[i].openVars;
+
+				Type* actualType = expr->get_result();
 
 				PRINT(
@@ -725,43 +809,61 @@
 				)
 
-				if ( unify( formalType, actualType, result.env, result.need, result.have,
-						result.openVars, indexer ) ) {
-					++result.nextExpl;
-					nextResults.push_back( std::move(result.withArg( actual.expr )) );
+				if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
+					unsigned nextExpl = results[i].nextExpl + 1;
+					if ( nextExpl == expl.exprs.size() ) {
+						nextExpl = 0;
+					}
+
+					results.emplace_back(
+						i, expr, move(env), move(need), move(have), move(openVars), nextArg,
+						nTuples, Cost::zero, nextExpl, results[i].explAlt );
 				}
 
 				continue;
-			} else if ( result.nextArg >= args.size() ) {
-				// use default initializers if out of arguments
+			}
+
+			// use default initializers if out of arguments
+			if ( nextArg >= args.size() ) {
 				if ( ConstantExpr* cnstExpr = getDefaultValue( initializer ) ) {
 					if ( Constant* cnst = dynamic_cast<Constant*>( cnstExpr->get_constant() ) ) {
-						if ( unify( formalType, cnst->get_type(), result.env, result.need,
-								result.have, result.openVars, indexer ) ) {
-							nextResults.push_back( std::move(result.withArg( cnstExpr )) );
+						TypeEnvironment env = results[i].env;
+						AssertionSet need = results[i].need, have = results[i].have;
+						OpenVarSet openVars = results[i].openVars;
+
+						if ( unify( formalType, cnst->get_type(), env, need, have, openVars,
+								indexer ) ) {
+							results.emplace_back(
+								i, cnstExpr, move(env), move(need), move(have),
+								move(openVars), nextArg, nTuples );
 						}
 					}
 				}
+
 				continue;
 			}
 
 			// Check each possible next argument
-			for ( const Alternative& actual : args[result.nextArg] ) {
-				ArgPack aResult = result;  // copy to clone everything
-				// add details of actual to result
-				aResult.env.addActual( actual.env, aResult.openVars );
-
-				// explode argument
-				std::vector<Alternative> exploded;
-				Tuples::explode( actual, indexer, back_inserter( exploded ) );
-				if ( exploded.empty() ) {
-					// skip empty tuple arguments
-					++aResult.nextArg;
-					results.push_back( std::move(aResult) );
+			for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
+				const ExplodedActual& expl = args[nextArg][j];
+
+				// fresh copies of parent parameters for this iteration
+				TypeEnvironment env = results[i].env;
+				AssertionSet need = results[i].need, have = results[i].have;
+				OpenVarSet openVars = results[i].openVars;
+
+				env.addActual( expl.env, openVars );
+
+				// skip empty tuple arguments by (near-)cloning parent into next gen
+				if ( expl.exprs.empty() ) {
+					results.emplace_back(
+						results[i], move(env), move(need), move(have), move(openVars),
+						nextArg + 1, expl.cost );
+
 					continue;
 				}
 
 				// consider only first exploded actual
-				const Alternative& aActual = exploded.front();
-				Type* actualType = aActual.expr->get_result()->clone();
+				Expression* expr = expl.exprs.front().get();
+				Type* actualType = expr->get_result()->clone();
 
 				PRINT(
@@ -774,14 +876,9 @@
 
 				// attempt to unify types
-				if ( unify( formalType, actualType, aResult.env, aResult.need, aResult.have, aResult.openVars, indexer ) ) {
-					// add argument
-					aResult.withArg( aActual.expr, actual.cost );
-					++aResult.nextArg;
-					if ( exploded.size() > 1 ) {
-						// other parts of tuple left over
-						aResult.expls = std::move( exploded );
-						aResult.nextExpl = 1;
-					}
-					nextResults.push_back( std::move(aResult) );
+				if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
+					// add new result
+					results.emplace_back(
+						i, expr, move(env), move(need), move(have), move(openVars), nextArg + 1,
+						nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
 				}
 			}
@@ -789,14 +886,35 @@
 
 		// reset for next parameter
-		results.swap( nextResults );
-		nextResults.clear();
-
-		return ! results.empty();
+		genStart = genEnd;
+
+		return genEnd != results.size();
+	}
+
+	template<typename OutputIterator>
+	void AlternativeFinder::validateFunctionAlternative( const Alternative &func, ArgPack& result,
+			const std::vector<ArgPack>& results, OutputIterator out ) {
+		ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() );
+		// sum cost and accumulate actuals
+		std::list<Expression*>& args = appExpr->get_args();
+		Cost cost = Cost::zero;
+		const ArgPack* pack = &result;
+		while ( pack->expr ) {
+			args.push_front( pack->expr->clone() );
+			cost += pack->cost;
+			pack = &results[pack->parent];
+		}
+		// build and validate new alternative
+		Alternative newAlt( appExpr, result.env, cost );
+		PRINT(
+			std::cerr << "instantiate function success: " << appExpr << std::endl;
+			std::cerr << "need assertions:" << std::endl;
+			printAssertionSet( result.need, std::cerr, 8 );
+		)
+		inferParameters( result.need, result.have, newAlt, result.openVars, out );
 	}
 
 	template<typename OutputIterator>
 	void AlternativeFinder::makeFunctionAlternatives( const Alternative &func,
-			FunctionType *funcType, const std::vector< AlternativeFinder > &args,
-			OutputIterator out ) {
+			FunctionType *funcType, const ExplodedArgs &args, OutputIterator out ) {
 		OpenVarSet funcOpenVars;
 		AssertionSet funcNeed, funcHave;
@@ -818,80 +936,87 @@
 
 		// iteratively build matches, one parameter at a time
-		std::vector<ArgPack> results{ ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars } };
-		std::vector<ArgPack> nextResults{};
+		std::vector<ArgPack> results;
+		results.push_back( ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars } );
+		std::size_t genStart = 0;
+
 		for ( DeclarationWithType* formal : funcType->get_parameters() ) {
 			ObjectDecl* obj = strict_dynamic_cast< ObjectDecl* >( formal );
 			if ( ! instantiateArgument(
-					obj->get_type(), obj->get_init(), args, results, nextResults, indexer ) )
+					obj->get_type(), obj->get_init(), args, results, genStart, indexer ) )
 				return;
 		}
 
-		// filter out results that don't use all the arguments, and aren't variadic
-		std::vector<ArgPack> finalResults{};
 		if ( funcType->get_isVarArgs() ) {
-			for ( ArgPack& result : results ) {
-				// use rest of exploded tuple if present
-				while ( result.nextExpl < result.expls.size() ) {
-					const Alternative& actual = result.expls[result.nextExpl];
-					result.env.addActual( actual.env, result.openVars );
-					result.withArg( actual.expr );
-					++result.nextExpl;
-				}
-			}
-
-			while ( ! results.empty() ) {
-				// build combinations for all remaining arguments
-				for ( ArgPack& result : results ) {
-					// keep if used all arguments
-					if ( result.nextArg >= args.size() ) {
-						finalResults.push_back( std::move(result) );
+			// append any unused arguments to vararg pack
+			std::size_t genEnd;
+			do {
+				genEnd = results.size();
+
+				// iterate results
+				for ( std::size_t i = genStart; i < genEnd; ++i ) {
+					auto nextArg = results[i].nextArg;
+
+					// use remainder of exploded tuple if present
+					if ( results[i].hasExpl() ) {
+						const ExplodedActual& expl = results[i].getExpl( args );
+
+						unsigned nextExpl = results[i].nextExpl + 1;
+						if ( nextExpl == expl.exprs.size() ) {
+							nextExpl = 0;
+						}
+
+						results.emplace_back(
+							i, expl.exprs[results[i].nextExpl].get(), copy(results[i].env),
+							copy(results[i].need), copy(results[i].have),
+							copy(results[i].openVars), nextArg, 0, Cost::zero, nextExpl,
+							results[i].explAlt );
+
 						continue;
 					}
 
+					// finish result when out of arguments
+					if ( nextArg >= args.size() ) {
+						validateFunctionAlternative( func, results[i], results, out );
+
+						continue;
+					}
+
 					// add each possible next argument
-					for ( const Alternative& actual : args[result.nextArg] ) {
-						ArgPack aResult = result; // copy to clone everything
-						// add details of actual to result
-						aResult.env.addActual( actual.env, aResult.openVars );
-						Cost cost = actual.cost;
-
-						// explode argument
-						std::vector<Alternative> exploded;
-						Tuples::explode( actual, indexer, back_inserter( exploded ) );
-
-						// add exploded argument to arg list
-						for ( Alternative& aActual : exploded ) {
-							aResult.withArg( aActual.expr, cost );
-							cost = Cost::zero;
+					for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
+						const ExplodedActual& expl = args[nextArg][j];
+
+						// fresh copies of parent parameters for this iteration
+						TypeEnvironment env = results[i].env;
+						OpenVarSet openVars = results[i].openVars;
+
+						env.addActual( expl.env, openVars );
+
+						// skip empty tuple arguments by (near-)cloning parent into next gen
+						if ( expl.exprs.empty() ) {
+							results.emplace_back(
+								results[i], move(env), copy(results[i].need),
+								copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
+
+							continue;
 						}
-						++aResult.nextArg;
-						nextResults.push_back( std::move(aResult) );
+
+						// add new result
+						results.emplace_back(
+							i, expl.exprs.front().get(), move(env), copy(results[i].need),
+							copy(results[i].have), move(openVars), nextArg + 1, 0,
+							expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
 					}
 				}
 
-				// reset for next round
-				results.swap( nextResults );
-				nextResults.clear();
-			}
+				genStart = genEnd;
+			} while ( genEnd != results.size() );
 		} else {
 			// filter out results that don't use all the arguments
-			for ( ArgPack& result : results ) {
-				if ( result.nextExpl >= result.expls.size() && result.nextArg >= args.size() ) {
-					finalResults.push_back( std::move(result) );
+			for ( std::size_t i = genStart; i < results.size(); ++i ) {
+				ArgPack& result = results[i];
+				if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
+					validateFunctionAlternative( func, result, results, out );
 				}
 			}
-		}
-
-		// validate matching combos, add to final result list
-		for ( ArgPack& result : finalResults ) {
-			ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() );
-			Alternative newAlt( appExpr, result.env, sumCost( result.actuals ) );
-			makeExprList( result.actuals, appExpr->get_args() );
-			PRINT(
-				std::cerr << "instantiate function success: " << appExpr << std::endl;
-				std::cerr << "need assertions:" << std::endl;
-				printAssertionSet( result.need, std::cerr, 8 );
-			)
-			inferParameters( result.need, result.have, newAlt, result.openVars, out );
 		}
 	}
@@ -920,4 +1045,18 @@
 			printAlts( funcOpFinder.alternatives, std::cerr, 1 );
 		)
+
+		// pre-explode arguments
+		ExplodedArgs argExpansions;
+		argExpansions.reserve( argAlternatives.size() );
+
+		for ( const AlternativeFinder& arg : argAlternatives ) {
+			argExpansions.emplace_back();
+			auto& argE = argExpansions.back();
+			argE.reserve( arg.alternatives.size() );
+
+			for ( const Alternative& actual : arg ) {
+				argE.emplace_back( actual, indexer );
+			}
+		}
 
 		AltList candidates;
@@ -934,5 +1073,5 @@
 						Alternative newFunc( *func );
 						referenceToRvalueConversion( newFunc.expr );
-						makeFunctionAlternatives( newFunc, function, argAlternatives,
+						makeFunctionAlternatives( newFunc, function, argExpansions,
 							std::back_inserter( candidates ) );
 					}
@@ -943,5 +1082,5 @@
 							Alternative newFunc( *func );
 							referenceToRvalueConversion( newFunc.expr );
-							makeFunctionAlternatives( newFunc, function, argAlternatives,
+							makeFunctionAlternatives( newFunc, function, argExpansions,
 								std::back_inserter( candidates ) );
 						} // if
@@ -955,6 +1094,11 @@
 		// try each function operator ?() with each function alternative
 		if ( ! funcOpFinder.alternatives.empty() ) {
-			// add function alternatives to front of argument list
-			argAlternatives.insert( argAlternatives.begin(), std::move(funcFinder) );
+			// add exploded function alternatives to front of argument list
+			std::vector<ExplodedActual> funcE;
+			funcE.reserve( funcFinder.alternatives.size() );
+			for ( const Alternative& actual : funcFinder ) {
+				funcE.emplace_back( actual, indexer );
+			}
+			argExpansions.insert( argExpansions.begin(), move(funcE) );
 
 			for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin();
@@ -968,5 +1112,5 @@
 							Alternative newFunc( *funcOp );
 							referenceToRvalueConversion( newFunc.expr );
-							makeFunctionAlternatives( newFunc, function, argAlternatives,
+							makeFunctionAlternatives( newFunc, function, argExpansions,
 								std::back_inserter( candidates ) );
 						}
@@ -982,9 +1126,9 @@
 
 		// compute conversionsion costs
-		for ( AltList::iterator withFunc = candidates.begin(); withFunc != candidates.end(); ++withFunc ) {
-			Cost cvtCost = computeApplicationConversionCost( *withFunc, indexer );
+		for ( Alternative& withFunc : candidates ) {
+			Cost cvtCost = computeApplicationConversionCost( withFunc, indexer );
 
 			PRINT(
-				ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( withFunc->expr );
+				ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( withFunc.expr );
 				PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
 				FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() );
@@ -995,15 +1139,14 @@
 				printAll( appExpr->get_args(), std::cerr, 8 );
 				std::cerr << "bindings are:" << std::endl;
-				withFunc->env.print( std::cerr, 8 );
+				withFunc.env.print( std::cerr, 8 );
 				std::cerr << "cost of conversion is:" << cvtCost << std::endl;
 			)
 			if ( cvtCost != Cost::infinity ) {
-				withFunc->cvtCost = cvtCost;
-				alternatives.push_back( *withFunc );
+				withFunc.cvtCost = cvtCost;
+				alternatives.push_back( withFunc );
 			} // if
 		} // for
 
-		candidates.clear();
-		candidates.splice( candidates.end(), alternatives );
+		candidates = move(alternatives);
 
 		// use a new list so that alternatives are not examined by addAnonConversions twice.
@@ -1011,11 +1154,11 @@
 		findMinCost( candidates.begin(), candidates.end(), std::back_inserter( winners ) );
 
-		// function may return struct or union value, in which case we need to add alternatives for implicit
-		// conversions to each of the anonymous members, must happen after findMinCost since anon conversions
-		// are never the cheapest expression
+		// function may return struct or union value, in which case we need to add alternatives
+		// for implicitconversions to each of the anonymous members, must happen after findMinCost
+		// since anon conversions are never the cheapest expression
 		for ( const Alternative & alt : winners ) {
 			addAnonConversions( alt );
 		}
-		alternatives.splice( alternatives.begin(), winners );
+		spliceBegin( alternatives, winners );
 
 		if ( alternatives.empty() && targetType && ! targetType->isVoid() ) {
@@ -1041,7 +1184,8 @@
 		AlternativeFinder finder( indexer, env );
 		finder.find( addressExpr->get_arg() );
-		for ( std::list< Alternative >::iterator i = finder.alternatives.begin(); i != finder.alternatives.end(); ++i ) {
-			if ( isLvalue( i->expr ) ) {
-				alternatives.push_back( Alternative( new AddressExpr( i->expr->clone() ), i->env, i->cost ) );
+		for ( Alternative& alt : finder.alternatives ) {
+			if ( isLvalue( alt.expr ) ) {
+				alternatives.push_back(
+					Alternative{ new AddressExpr( alt.expr->clone() ), alt.env, alt.cost } );
 			} // if
 		} // for
@@ -1049,5 +1193,5 @@
 
 	void AlternativeFinder::visit( LabelAddressExpr * expr ) {
-		alternatives.push_back( Alternative( expr->clone(), env, Cost::zero) );
+		alternatives.push_back( Alternative{ expr->clone(), env, Cost::zero } );
 	}
 
@@ -1091,5 +1235,5 @@
 
 		AltList candidates;
-		for ( std::list< Alternative >::iterator i = finder.alternatives.begin(); i != finder.alternatives.end(); ++i ) {
+		for ( Alternative & alt : finder.alternatives ) {
 			AssertionSet needAssertions, haveAssertions;
 			OpenVarSet openVars;
@@ -1099,16 +1243,28 @@
 			// that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
 			// to.
-			int discardedValues = i->expr->get_result()->size() - castExpr->get_result()->size();
+			int discardedValues = alt.expr->get_result()->size() - castExpr->get_result()->size();
 			if ( discardedValues < 0 ) continue;
 			// xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
 			// allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
 			// unification run for side-effects
-			unify( castExpr->get_result(), i->expr->get_result(), i->env, needAssertions, haveAssertions, openVars, indexer );
-			Cost thisCost = castCost( i->expr->get_result(), castExpr->get_result(), indexer, i->env );
+			unify( castExpr->get_result(), alt.expr->get_result(), alt.env, needAssertions,
+				haveAssertions, openVars, indexer );
+			Cost thisCost = castCost( alt.expr->get_result(), castExpr->get_result(), indexer,
+				alt.env );
+			PRINT(
+				std::cerr << "working on cast with result: " << castExpr->result << std::endl;
+				std::cerr << "and expr type: " << alt.expr->result << std::endl;
+				std::cerr << "env: " << alt.env << std::endl;
+			)
 			if ( thisCost != Cost::infinity ) {
+				PRINT(
+					std::cerr << "has finite cost." << std::endl;
+				)
 				// count one safe conversion for each value that is thrown away
 				thisCost.incSafe( discardedValues );
-				Alternative newAlt( restructureCast( i->expr->clone(), toType ), i->env, i->cost, thisCost );
-				inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) );
+				Alternative newAlt( restructureCast( alt.expr->clone(), toType ), alt.env,
+					alt.cost, thisCost );
+				inferParameters( needAssertions, haveAssertions, newAlt, openVars,
+					back_inserter( candidates ) );
 			} // if
 		} // for
@@ -1397,15 +1553,18 @@
 
 	void AlternativeFinder::visit( UntypedTupleExpr *tupleExpr ) {
-		std::list< AlternativeFinder > subExprAlternatives;
-		findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(), back_inserter( subExprAlternatives ) );
-		std::list< AltList > possibilities;
-		combos( subExprAlternatives.begin(), subExprAlternatives.end(), back_inserter( possibilities ) );
-		for ( std::list< AltList >::const_iterator i = possibilities.begin(); i != possibilities.end(); ++i ) {
+		std::vector< AlternativeFinder > subExprAlternatives;
+		findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(),
+			back_inserter( subExprAlternatives ) );
+		std::vector< AltList > possibilities;
+		combos( subExprAlternatives.begin(), subExprAlternatives.end(),
+			back_inserter( possibilities ) );
+		for ( const AltList& alts : possibilities ) {
 			std::list< Expression * > exprs;
-			makeExprList( *i, exprs );
+			makeExprList( alts, exprs );
 
 			TypeEnvironment compositeEnv;
-			simpleCombineEnvironments( i->begin(), i->end(), compositeEnv );
-			alternatives.push_back( Alternative( new TupleExpr( exprs ) , compositeEnv, sumCost( *i ) ) );
+			simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv );
+			alternatives.push_back(
+				Alternative{ new TupleExpr( exprs ), compositeEnv, sumCost( alts ) } );
 		} // for
 	}
Index: src/ResolvExpr/AlternativeFinder.h
===================================================================
--- src/ResolvExpr/AlternativeFinder.h	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/ResolvExpr/AlternativeFinder.h	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -21,4 +21,5 @@
 
 #include "Alternative.h"                 // for AltList, Alternative
+#include "ExplodedActual.h"              // for ExplodedActual
 #include "ResolvExpr/Cost.h"             // for Cost, Cost::infinity
 #include "ResolvExpr/TypeEnvironment.h"  // for AssertionSet, OpenVarSet
@@ -31,4 +32,10 @@
 
 namespace ResolvExpr {
+	struct ArgPack;
+
+	/// First index is which argument, second index is which alternative for that argument,
+	/// third index is which exploded element of that alternative
+	using ExplodedArgs = std::vector< std::vector< ExplodedActual > >;
+
 	class AlternativeFinder : public Visitor {
 	  public:
@@ -36,14 +43,14 @@
 
 		AlternativeFinder( const AlternativeFinder& o )
-			: indexer(o.indexer), alternatives(o.alternatives), env(o.env), 
+			: indexer(o.indexer), alternatives(o.alternatives), env(o.env),
 			  targetType(o.targetType) {}
-		
+
 		AlternativeFinder( AlternativeFinder&& o )
-			: indexer(o.indexer), alternatives(std::move(o.alternatives)), env(o.env), 
+			: indexer(o.indexer), alternatives(std::move(o.alternatives)), env(o.env),
 			  targetType(o.targetType) {}
-		
+
 		AlternativeFinder& operator= ( const AlternativeFinder& o ) {
 			if (&o == this) return *this;
-			
+
 			// horrific nasty hack to rebind references...
 			alternatives.~AltList();
@@ -54,5 +61,5 @@
 		AlternativeFinder& operator= ( AlternativeFinder&& o ) {
 			if (&o == this) return *this;
-			
+
 			// horrific nasty hack to rebind references...
 			alternatives.~AltList();
@@ -126,6 +133,11 @@
 		/// Adds alternatives for offsetof expressions, given the base type and name of the member
 		template< typename StructOrUnionType > void addOffsetof( StructOrUnionType *aggInst, const std::string &name );
+		/// Takes a final result and checks if its assertions can be satisfied
 		template<typename OutputIterator>
-		void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const std::vector< AlternativeFinder >& args, OutputIterator out );
+		void validateFunctionAlternative( const Alternative &func, ArgPack& result, const std::vector<ArgPack>& results, OutputIterator out );
+		/// Finds matching alternatives for a function, given a set of arguments
+		template<typename OutputIterator>
+		void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs& args, OutputIterator out );
+		/// Checks if assertion parameters match for a new alternative
 		template< typename OutputIterator >
 		void inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out );
Index: src/ResolvExpr/ExplodedActual.cc
===================================================================
--- src/ResolvExpr/ExplodedActual.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
+++ src/ResolvExpr/ExplodedActual.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -0,0 +1,25 @@
+//
+// 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.
+//
+// Alternative.h --
+//
+// Author           : Aaron B. Moss
+// Created On       : Tue Nov 22 17:06:00 2017
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Tue Nov 22 17:06:00 2017
+// Update Count     : 1
+//
+
+#include "ExplodedActual.h"
+
+#include "Tuples/Explode.h"   // for Tuples::explode
+
+namespace ResolvExpr {
+	ExplodedActual::ExplodedActual( const Alternative& actual, const SymTab::Indexer& indexer ) 
+			: env(actual.env), cost(actual.cost), exprs() {
+		Tuples::explode( actual, indexer, *this );
+	}
+}
Index: src/ResolvExpr/ExplodedActual.h
===================================================================
--- src/ResolvExpr/ExplodedActual.h	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
+++ src/ResolvExpr/ExplodedActual.h	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -0,0 +1,37 @@
+//
+// 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.
+//
+// Alternative.h --
+//
+// Author           : Aaron B. Moss
+// Created On       : Tue Nov 22 17:06:00 2017
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Tue Nov 22 17:06:00 2017
+// Update Count     : 1
+//
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include "Alternative.h"      // for Alternative, AltList
+#include "Cost.h"             // for Cost
+#include "TypeEnvironment.h"  // for TypeEnvironment
+#include "SymTab/Indexer.h"   // for Indexer
+
+namespace ResolvExpr {
+	/// Pre-exploded actual
+	struct ExplodedActual {
+		TypeEnvironment env;
+		Cost cost;
+		std::vector< std::unique_ptr<Expression> > exprs;
+
+		ExplodedActual() : env(), cost(Cost::zero), exprs() {}
+
+		ExplodedActual( const Alternative& actual, const SymTab::Indexer& indexer );
+	};
+}
Index: src/ResolvExpr/PtrsAssignable.cc
===================================================================
--- src/ResolvExpr/PtrsAssignable.cc	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/ResolvExpr/PtrsAssignable.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -68,9 +68,6 @@
 
 	void PtrsAssignable::visit( __attribute((unused)) VoidType *voidType ) {
-		if ( ! dynamic_cast< FunctionType* >( dest ) ) {
-			// T * = void * is safe for any T that is not a function type.
-			// xxx - this should be unsafe...
-			result = 1;
-		} // if
+		// T * = void * is disallowed - this is a change from C, where any
+		// void * can be assigned or passed to a non-void pointer without a cast.
 	}
 
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/ResolvExpr/Resolver.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -18,4 +18,5 @@
 #include <memory>                        // for allocator, allocator_traits<...
 #include <tuple>                         // for get
+#include <vector>
 
 #include "Alternative.h"                 // for Alternative, AltList
@@ -411,9 +412,9 @@
 
 			// Find all alternatives for all arguments in canonical form
-			std::list< AlternativeFinder > argAlternatives;
+			std::vector< AlternativeFinder > argAlternatives;
 			funcFinder.findSubExprs( clause.target.arguments.begin(), clause.target.arguments.end(), back_inserter( argAlternatives ) );
 
 			// List all combinations of arguments
-			std::list< AltList > possibilities;
+			std::vector< AltList > possibilities;
 			combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) );
 
Index: src/ResolvExpr/TypeEnvironment.cc
===================================================================
--- src/ResolvExpr/TypeEnvironment.cc	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/ResolvExpr/TypeEnvironment.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -212,4 +212,8 @@
 	}
 
+	std::ostream & operator<<( std::ostream & out, const TypeEnvironment & env ) {
+		env.print( out );
+		return out;
+	}
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/TypeEnvironment.h
===================================================================
--- src/ResolvExpr/TypeEnvironment.h	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/ResolvExpr/TypeEnvironment.h	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -86,5 +86,5 @@
 		TypeEnvironment *clone() const { return new TypeEnvironment( *this ); }
 
-		/// Iteratively adds the environment of a new actual (with allowWidening = false), 
+		/// Iteratively adds the environment of a new actual (with allowWidening = false),
 		/// and extracts open variables.
 		void addActual( const TypeEnvironment& actualEnv, OpenVarSet& openVars );
@@ -114,4 +114,6 @@
 		return sub.applyFree( type );
 	}
+
+	std::ostream & operator<<( std::ostream & out, const TypeEnvironment & env );
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/module.mk
===================================================================
--- src/ResolvExpr/module.mk	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/ResolvExpr/module.mk	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -32,3 +32,4 @@
        ResolvExpr/Occurs.cc \
        ResolvExpr/TypeEnvironment.cc \
-       ResolvExpr/CurrentObject.cc
+       ResolvExpr/CurrentObject.cc \
+       ResolvExpr/ExplodedActual.cc
Index: src/ResolvExpr/typeops.h
===================================================================
--- src/ResolvExpr/typeops.h	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/ResolvExpr/typeops.h	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -16,4 +16,6 @@
 #pragma once
 
+#include <vector>
+
 #include "SynTree/SynTree.h"
 #include "SynTree/Type.h"
@@ -28,5 +30,5 @@
 	void combos( InputIterator begin, InputIterator end, OutputIterator out ) {
 		typedef typename InputIterator::value_type SetType;
-		typedef typename std::list< typename SetType::value_type > ListType;
+		typedef typename std::vector< typename SetType::value_type > ListType;
 
 		if ( begin == end )	{
@@ -38,16 +40,14 @@
 		begin++;
 
-		std::list< ListType > recursiveResult;
+		std::vector< ListType > recursiveResult;
 		combos( begin, end, back_inserter( recursiveResult ) );
 
-		for ( typename std::list< ListType >::const_iterator i = recursiveResult.begin(); i != recursiveResult.end(); ++i ) {
-			for ( typename ListType::const_iterator j = current->begin(); j != current->end(); ++j ) {
-				ListType result;
-				std::back_insert_iterator< ListType > inserter = back_inserter( result );
-				*inserter++ = *j;
-				std::copy( i->begin(), i->end(), inserter );
-				*out++ = result;
-			} // for
-		} // for
+		for ( const auto& i : recursiveResult ) for ( const auto& j : *current ) {
+			ListType result;
+			std::back_insert_iterator< ListType > inserter = back_inserter( result );
+			*inserter++ = j;
+			std::copy( i.begin(), i.end(), inserter );
+			*out++ = result;
+		}
 	}
 
Index: src/SymTab/Autogen.cc
===================================================================
--- src/SymTab/Autogen.cc	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/SymTab/Autogen.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -62,7 +62,4 @@
 		void previsit( FunctionDecl * functionDecl );
 
-		void previsit( FunctionType * ftype );
-		void previsit( PointerType * ptype );
-
 		void previsit( CompoundStmt * compoundStmt );
 
@@ -72,5 +69,4 @@
 		unsigned int functionNesting = 0;     // current level of nested functions
 
-		InitTweak::ManagedTypes managedTypes;
 		std::vector< FuncData > data;
 	};
@@ -622,5 +618,4 @@
 	// generate ctor/dtors/assign for typedecls, e.g., otype T = int *;
 	void AutogenerateRoutines::previsit( TypeDecl * typeDecl ) {
-		visit_children = false;
 		if ( ! typeDecl->base ) return;
 
@@ -628,14 +623,5 @@
 		TypeFuncGenerator gen( typeDecl, &refType, data, functionNesting, indexer );
 		generateFunctions( gen, declsToAddAfter );
-	}
-
-	void AutogenerateRoutines::previsit( FunctionType *) {
-		// ensure that we don't add assignment ops for types defined as part of the function
-		visit_children = false;
-	}
-
-	void AutogenerateRoutines::previsit( PointerType *) {
-		// ensure that we don't add assignment ops for types defined as part of the pointer
-		visit_children = false;
+
 	}
 
@@ -645,17 +631,13 @@
 	}
 
-	void AutogenerateRoutines::previsit( FunctionDecl * functionDecl ) {
-		visit_children = false;
-		// record the existence of this function as appropriate
-		managedTypes.handleDWT( functionDecl );
-
-		maybeAccept( functionDecl->type, *visitor );
+	void AutogenerateRoutines::previsit( FunctionDecl * ) {
+		// Track whether we're currently in a function.
+		// Can ignore function type idiosyncrasies, because function type can never
+		// declare a new type.
 		functionNesting += 1;
-		maybeAccept( functionDecl->statements, *visitor );
-		functionNesting -= 1;
+		GuardAction( [this]()  { functionNesting -= 1; } );
 	}
 
 	void AutogenerateRoutines::previsit( CompoundStmt * ) {
-		GuardScope( managedTypes );
 		GuardScope( structsDone );
 	}
Index: src/SymTab/Autogen.h
===================================================================
--- src/SymTab/Autogen.h	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/SymTab/Autogen.h	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -56,10 +56,10 @@
 	/// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls.
 	template< typename OutputIterator >
-	Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, bool addCast = false, bool forward = true );
+	Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast = nullptr, bool forward = true );
 
 	/// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types.
 	/// optionally returns a statement which must be inserted prior to the containing loop, if there is one
 	template< typename OutputIterator >
-	Statement * genScalarCall( InitTweak::InitExpander & srcParam, Expression * dstParam, std::string fname, OutputIterator out, Type * type, bool addCast = false ) {
+	Statement * genScalarCall( InitTweak::InitExpander & srcParam, Expression * dstParam, std::string fname, OutputIterator out, Type * type, Type * addCast = nullptr ) {
 		bool isReferenceCtorDtor = false;
 		if ( dynamic_cast< ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) {
@@ -68,5 +68,5 @@
 			fname = "?=?";
 			dstParam = new AddressExpr( dstParam );
-			addCast = false;
+			addCast = nullptr;
 			isReferenceCtorDtor = true;
 		}
@@ -83,6 +83,5 @@
 			// remove lvalue as a qualifier, this can change to
 			//   type->get_qualifiers() = Type::Qualifiers();
-			assert( type );
-			Type * castType = type->clone();
+			Type * castType = addCast->clone();
 			castType->get_qualifiers() -= Type::Qualifiers( Type::Lvalue | Type::Const | Type::Volatile | Type::Restrict | Type::Atomic );
 			// castType->set_lvalue( true ); // xxx - might not need this
@@ -115,9 +114,15 @@
 	/// If forward is true, loop goes from 0 to N-1, else N-1 to 0
 	template< typename OutputIterator >
-	void genArrayCall( InitTweak::InitExpander & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, bool addCast = false, bool forward = true ) {
+	void genArrayCall( InitTweak::InitExpander & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, Type * addCast = nullptr, bool forward = true ) {
 		static UniqueName indexName( "_index" );
 
 		// for a flexible array member nothing is done -- user must define own assignment
-		if ( ! array->get_dimension() ) return ;
+		if ( ! array->get_dimension() ) return;
+
+		if ( addCast ) {
+			// peel off array layer from cast
+			ArrayType * at = strict_dynamic_cast< ArrayType * >( addCast );
+			addCast = at->base;
+		}
 
 		Expression * begin, * end, * update, * cmp;
@@ -171,5 +176,5 @@
 
 	template< typename OutputIterator >
-	Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, bool addCast, bool forward ) {
+	Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) {
 		if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
 			genArrayCall( srcParam, dstParam, fname, out, at, addCast, forward );
@@ -191,5 +196,9 @@
 		if ( isUnnamedBitfield( obj ) ) return;
 
-		bool addCast = (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && ! obj->get_bitfieldWidth() ) );
+		Type * addCast = nullptr;
+		if ( (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && ! obj->get_bitfieldWidth() ) ) ) {
+			assert( dstParam->result );
+			addCast = dstParam->result;
+		}
 		std::list< Statement * > stmts;
 		genCall( srcParam, dstParam, fname, back_inserter( stmts ), obj->type, addCast, forward );
Index: src/SymTab/Indexer.cc
===================================================================
--- src/SymTab/Indexer.cc	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/SymTab/Indexer.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -567,4 +567,23 @@
 	}
 
+	void Indexer::addIds( const std::list< DeclarationWithType * > & decls ) {
+		for ( auto d : decls ) {
+			addId( d );
+		}
+	}
+
+	void Indexer::addTypes( const std::list< TypeDecl * > & tds ) {
+		for ( auto td : tds ) {
+			addType( td );
+			addIds( td->assertions );
+		}
+	}
+
+	void Indexer::addFunctionType( FunctionType * ftype ) {
+		addTypes( ftype->forall );
+		addIds( ftype->returnVals );
+		addIds( ftype->parameters );
+	}
+
 	void Indexer::enterScope() {
 		++scope;
Index: src/SymTab/Indexer.h
===================================================================
--- src/SymTab/Indexer.h	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/SymTab/Indexer.h	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -76,4 +76,13 @@
 		void addTrait( TraitDecl *decl );
 
+		/// convenience function for adding a list of Ids to the indexer
+		void addIds( const std::list< DeclarationWithType * > & decls );
+
+		/// convenience function for adding a list of forall parameters to the indexer
+		void addTypes( const std::list< TypeDecl * > & tds );
+
+		/// convenience function for adding all of the declarations in a function type to the indexer
+		void addFunctionType( FunctionType * ftype );
+
 		bool doDebug = false; ///< Display debugging trace?
 	  private:
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/SymTab/Validate.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -124,5 +124,5 @@
 
 	/// Associates forward declarations of aggregates with their definitions
-	struct LinkReferenceToTypes final : public WithIndexer {
+	struct LinkReferenceToTypes final : public WithIndexer, public WithGuards {
 		LinkReferenceToTypes( const Indexer *indexer );
 		void postvisit( TypeInstType *typeInst );
@@ -137,4 +137,9 @@
 		void postvisit( UnionDecl *unionDecl );
 		void postvisit( TraitDecl * traitDecl );
+
+		void previsit( StructDecl *structDecl );
+		void previsit( UnionDecl *unionDecl );
+
+		void renameGenericParams( std::list< TypeDecl * > & params );
 
 	  private:
@@ -147,4 +152,6 @@
 		ForwardStructsType forwardStructs;
 		ForwardUnionsType forwardUnions;
+		/// true if currently in a generic type body, so that type parameter instances can be renamed appropriately
+		bool inGeneric = false;
 	};
 
@@ -561,4 +568,30 @@
 	}
 
+	void LinkReferenceToTypes::renameGenericParams( std::list< TypeDecl * > & params ) {
+		// rename generic type parameters uniquely so that they do not conflict with user-defined function forall parameters, e.g.
+		//   forall(otype T)
+		//   struct Box {
+		//     T x;
+		//   };
+		//   forall(otype T)
+		//   void f(Box(T) b) {
+		//     ...
+		//   }
+		// The T in Box and the T in f are different, so internally the naming must reflect that.
+		GuardValue( inGeneric );
+		inGeneric = ! params.empty();
+		for ( TypeDecl * td : params ) {
+			td->name = "__" + td->name + "_generic_";
+		}
+	}
+
+	void LinkReferenceToTypes::previsit( StructDecl * structDecl ) {
+		renameGenericParams( structDecl->parameters );
+	}
+
+	void LinkReferenceToTypes::previsit( UnionDecl * unionDecl ) {
+		renameGenericParams( unionDecl->parameters );
+	}
+
 	void LinkReferenceToTypes::postvisit( StructDecl *structDecl ) {
 		// visit struct members first so that the types of self-referencing members are updated properly
@@ -588,4 +621,6 @@
 
 	void LinkReferenceToTypes::postvisit( TypeInstType *typeInst ) {
+		// ensure generic parameter instances are renamed like the base type
+		if ( inGeneric && typeInst->baseType ) typeInst->name = typeInst->baseType->name;
 		if ( NamedTypeDecl *namedTypeDecl = local_indexer->lookupType( typeInst->get_name() ) ) {
 			if ( TypeDecl *typeDecl = dynamic_cast< TypeDecl * >( namedTypeDecl ) ) {
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/SynTree/Expression.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -88,4 +88,18 @@
 	Type * type = var->get_type()->clone();
 	type->set_lvalue( true );
+
+	// xxx - doesn't quite work yet - get different alternatives with the same cost
+
+	// // enumerators are not lvalues
+	// if ( EnumInstType * inst = dynamic_cast< EnumInstType * >( var->get_type() ) ) {
+	// 	assert( inst->baseEnum );
+	// 	EnumDecl * decl = inst->baseEnum;
+	// 	for ( Declaration * member : decl->members ) {
+	// 		if ( member == _var ) {
+	// 			type->set_lvalue( false );
+	// 		}
+	// 	}
+	// }
+
 	set_result( type );
 }
@@ -324,7 +338,7 @@
 			return makeSub( refType->get_base() );
 		} else if ( StructInstType * aggInst = dynamic_cast< StructInstType * >( t ) ) {
-			return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->get_parameters().begin() );
+			return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->parameters.begin() );
 		} else if ( UnionInstType * aggInst = dynamic_cast< UnionInstType * >( t ) ) {
-			return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->get_parameters().begin() );
+			return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->parameters.begin() );
 		} else {
 			assertf( false, "makeSub expects struct or union type for aggregate, but got: %s", toString( t ).c_str() );
Index: src/Tuples/Explode.h
===================================================================
--- src/Tuples/Explode.h	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/Tuples/Explode.h	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -16,10 +16,12 @@
 #pragma once
 
-#include <iterator>                  // for back_inserter, back_insert_iterator
+#include <iterator>                     // for back_inserter, back_insert_iterator
+#include <utility>                      // for forward
 
-#include "ResolvExpr/Alternative.h"  // for Alternative, AltList
-#include "SynTree/Expression.h"      // for Expression, UniqueExpr, AddressExpr
-#include "SynTree/Type.h"            // for TupleType, Type
-#include "Tuples.h"                  // for maybeImpure
+#include "ResolvExpr/Alternative.h"     // for Alternative, AltList
+#include "ResolvExpr/ExplodedActual.h"  // for ExplodedActual
+#include "SynTree/Expression.h"         // for Expression, UniqueExpr, AddressExpr
+#include "SynTree/Type.h"               // for TupleType, Type
+#include "Tuples.h"                     // for maybeImpure
 
 namespace SymTab {
@@ -39,16 +41,32 @@
 	}
 
+	/// Append alternative to an OutputIterator of Alternatives
+	template<typename OutputIterator>
+	void append( OutputIterator out, Expression* expr, const ResolvExpr::TypeEnvironment& env, 
+			const ResolvExpr::Cost& cost, const ResolvExpr::Cost& cvtCost ) {
+		*out++ = ResolvExpr::Alternative{ expr, env, cost, cvtCost };
+	}
+
+	/// Append alternative to an ExplodedActual
+	static inline void append( ResolvExpr::ExplodedActual& ea, Expression* expr, 
+			const ResolvExpr::TypeEnvironment&, const ResolvExpr::Cost&, const ResolvExpr::Cost& ) {
+		ea.exprs.emplace_back( expr );
+		/// xxx -- merge environment, cost?
+	}
+
 	/// helper function used by explode
-	template< typename OutputIterator >
-	void explodeUnique( Expression * expr, const ResolvExpr::Alternative & alt, const SymTab::Indexer & indexer, OutputIterator out, bool isTupleAssign ) {
+	template< typename Output >
+	void explodeUnique( Expression * expr, const ResolvExpr::Alternative & alt, 
+			const SymTab::Indexer & indexer, Output&& out, bool isTupleAssign ) {
 		if ( isTupleAssign ) {
 			// tuple assignment needs CastExprs to be recursively exploded to easily get at all of the components
 			if ( CastExpr * castExpr = isReferenceCast( expr ) ) {
 				ResolvExpr::AltList alts;
-				explodeUnique( castExpr->get_arg(), alt, indexer, back_inserter( alts ), isTupleAssign );
+				explodeUnique( 
+					castExpr->get_arg(), alt, indexer, back_inserter( alts ), isTupleAssign );
 				for ( ResolvExpr::Alternative & alt : alts ) {
 					// distribute reference cast over all components
-					alt.expr = distributeReference( alt.expr );
-					*out++ = alt;
+					append( std::forward<Output>(out), distributeReference( alt.release_expr() ), 
+						alt.env, alt.cost, alt.cvtCost );
 				}
 				// in tuple assignment, still need to handle the other cases, but only if not already handled here (don't want to output too many alternatives)
@@ -61,5 +79,5 @@
 				// can open tuple expr and dump its exploded components
 				for ( Expression * expr : tupleExpr->get_exprs() ) {
-					explodeUnique( expr, alt, indexer, out, isTupleAssign );
+					explodeUnique( expr, alt, indexer, std::forward<Output>(out), isTupleAssign );
 				}
 			} else {
@@ -77,5 +95,5 @@
 				for ( unsigned int i = 0; i < tupleType->size(); i++ ) {
 					TupleIndexExpr * idx = new TupleIndexExpr( arg->clone(), i );
-					explodeUnique( idx, alt, indexer, out, isTupleAssign );
+					explodeUnique( idx, alt, indexer, std::forward<Output>(out), isTupleAssign );
 					delete idx;
 				}
@@ -84,25 +102,28 @@
 		} else {
 			// atomic (non-tuple) type - output a clone of the expression in a new alternative
-			*out++ = ResolvExpr::Alternative( expr->clone(), alt.env, alt.cost, alt.cvtCost );
+			append( std::forward<Output>(out), expr->clone(), alt.env, alt.cost, alt.cvtCost );
 		}
 	}
 
 	/// expands a tuple-valued alternative into multiple alternatives, each with a non-tuple-type
-	template< typename OutputIterator >
-	void explode( const ResolvExpr::Alternative &alt, const SymTab::Indexer & indexer, OutputIterator out, bool isTupleAssign = false ) {
-		explodeUnique( alt.expr, alt, indexer, out, isTupleAssign );
+	template< typename Output >
+	void explode( const ResolvExpr::Alternative &alt, const SymTab::Indexer & indexer, 
+			Output&& out, bool isTupleAssign = false ) {
+		explodeUnique( alt.expr, alt, indexer, std::forward<Output>(out), isTupleAssign );
 	}
 
 	// explode list of alternatives
-	template< typename AltIterator, typename OutputIterator >
-	void explode( AltIterator altBegin, AltIterator altEnd, const SymTab::Indexer & indexer, OutputIterator out, bool isTupleAssign = false ) {
+	template< typename AltIterator, typename Output >
+	void explode( AltIterator altBegin, AltIterator altEnd, const SymTab::Indexer & indexer, 
+			Output&& out, bool isTupleAssign = false ) {
 		for ( ; altBegin != altEnd; ++altBegin ) {
-			explode( *altBegin, indexer, out, isTupleAssign );
+			explode( *altBegin, indexer, std::forward<Output>(out), isTupleAssign );
 		}
 	}
 
-	template< typename OutputIterator >
-	void explode( const ResolvExpr::AltList & alts, const SymTab::Indexer & indexer, OutputIterator out, bool isTupleAssign = false ) {
-		explode( alts.begin(), alts.end(), indexer, out, isTupleAssign );
+	template< typename Output >
+	void explode( const ResolvExpr::AltList & alts, const SymTab::Indexer & indexer, Output&& out, 
+			bool isTupleAssign = false ) {
+		explode( alts.begin(), alts.end(), indexer, std::forward<Output>(out), isTupleAssign );
 	}
 } // namespace Tuples
Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/Tuples/TupleAssignment.cc	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -251,5 +251,6 @@
 		// combine assignment environments into combined expression environment
 		simpleCombineEnvironments( current.begin(), current.end(), matcher->compositeEnv );
-		currentFinder.get_alternatives().push_front( ResolvExpr::Alternative(
+		// xxx -- was push_front
+		currentFinder.get_alternatives().push_back( ResolvExpr::Alternative(
 			new TupleAssignExpr(solved_assigns, matcher->tmpDecls), matcher->compositeEnv, 
 			ResolvExpr::sumCost( current ) + matcher->baseCost ) );
Index: src/libcfa/concurrency/kernel
===================================================================
--- src/libcfa/concurrency/kernel	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/libcfa/concurrency/kernel	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -108,5 +108,5 @@
 #ifdef __CFA_DEBUG__
 	// Last function to enable preemption on this processor
-	char * last_enable;
+	const char * last_enable;
 #endif
 };
Index: src/libcfa/concurrency/monitor.c
===================================================================
--- src/libcfa/concurrency/monitor.c	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/libcfa/concurrency/monitor.c	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -823,5 +823,5 @@
 		this.monitor_count = thrd->monitors.size;
 
-		this.monitors = malloc( this.monitor_count * sizeof( *this.monitors ) );
+		this.monitors = (monitor_desc **)malloc( this.monitor_count * sizeof( *this.monitors ) );
 		for( int i = 0; i < this.monitor_count; i++ ) {
 			this.monitors[i] = thrd->monitors[i];
Index: src/libcfa/stdhdr/stddef.h
===================================================================
--- src/libcfa/stdhdr/stddef.h	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/libcfa/stdhdr/stddef.h	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -4,7 +4,7 @@
 // The contents of this file are covered under the licence agreement in the
 // file "LICENCE" distributed with Cforall.
-// 
-// stddef.h -- 
-// 
+//
+// stddef.h --
+//
 // Author           : Peter A. Buhr
 // Created On       : Mon Jul  4 23:25:26 2016
@@ -12,8 +12,10 @@
 // Last Modified On : Tue Jul  5 20:40:01 2016
 // Update Count     : 12
-// 
+//
 
 extern "C" {
-#include_next <stddef.h>								// has internal check for multiple expansion
+#include_next <stddef.h>                // has internal check for multiple expansion
+#undef NULL
+#define NULL 0                          // define NULL as 0 rather than (void*)0 to take advantage of zero_t
 } // extern "C"
 
Index: src/libcfa/stdlib
===================================================================
--- src/libcfa/stdlib	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/libcfa/stdlib	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -77,5 +77,5 @@
 	//printf( "X8\n" );
 	T * ptr = (T *)(void *)malloc( (size_t)sizeof(T) );	// C malloc
-    return memset( ptr, (int)fill, sizeof(T) );			// initial with fill value
+    return (T *)memset( ptr, (int)fill, sizeof(T) );			// initial with fill value
 } // alloc
 
@@ -87,10 +87,10 @@
 	//printf( "X10\n" );
 	T * ptr = (T *)(void *)malloc( dim * (size_t)sizeof(T) ); // C malloc
-    return memset( ptr, (int)fill, dim * sizeof(T) );
+    return (T *)memset( ptr, (int)fill, dim * sizeof(T) );
 } // alloc
 
 static inline forall( dtype T | sized(T) ) T * alloc( T ptr[], size_t dim ) {
 	//printf( "X11\n" );
-	return (void *)realloc( (void *)ptr, dim * (size_t)sizeof(T) ); // C realloc
+	return (T *)(void *)realloc( (void *)ptr, dim * (size_t)sizeof(T) ); // C realloc
 } // alloc
 forall( dtype T | sized(T) ) T * alloc( T ptr[], size_t dim, char fill );
@@ -103,5 +103,5 @@
 	//printf( "X14\n" );
     T * ptr = (T *)memalign( align, sizeof(T) );
-    return memset( ptr, (int)fill, sizeof(T) );
+    return (T *)memset( ptr, (int)fill, sizeof(T) );
 } // align_alloc
 
@@ -113,5 +113,5 @@
 	//printf( "X16\n" );
     T * ptr = (T *)memalign( align, dim * sizeof(T) );
-    return memset( ptr, (int)fill, dim * sizeof(T) );
+    return (T *)memset( ptr, (int)fill, dim * sizeof(T) );
 } // align_alloc
 
@@ -120,10 +120,10 @@
 static inline forall( dtype T | sized(T) ) T * memset( T * dest, char c ) {
 	//printf( "X17\n" );
-	return memset( dest, c, sizeof(T) );
+	return (T *)memset( dest, c, sizeof(T) );
 } // memset
 extern "C" { void * memcpy( void * dest, const void * src, size_t size ); } // use default C routine for void *
 static inline forall( dtype T | sized(T) ) T * memcpy( T * dest, const T * src ) {
 	//printf( "X18\n" );
-	return memcpy( dest, src, sizeof(T) );
+	return (T *)memcpy( dest, src, sizeof(T) );
 } // memcpy
 
@@ -131,9 +131,9 @@
 static inline forall( dtype T | sized(T) ) T * memset( T dest[], size_t dim, char c ) {
 	//printf( "X19\n" );
-	return (void *)memset( dest, c, dim * sizeof(T) );	// C memset
+	return (T *)(void *)memset( dest, c, dim * sizeof(T) );	// C memset
 } // memset
 static inline forall( dtype T | sized(T) ) T * memcpy( T dest[], const T src[], size_t dim ) {
 	//printf( "X20\n" );
-	return (void *)memcpy( dest, src, dim * sizeof(T) ); // C memcpy
+	return (T *)(void *)memcpy( dest, src, dim * sizeof(T) ); // C memcpy
 } // memcpy
 
Index: src/prelude/prelude.cf
===================================================================
--- src/prelude/prelude.cf	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/prelude/prelude.cf	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -403,24 +403,4 @@
 forall( dtype DT ) const volatile DT *  ?=?( const volatile  DT * volatile &, const volatile	DT * );
 
-forall( dtype DT ) DT *			?=?(		     DT *	   &,			void * );
-forall( dtype DT ) DT *			?=?(		     DT * volatile &,			void * );
-forall( dtype DT ) const DT *		?=?( const	     DT *	   &,			void * );
-forall( dtype DT ) const DT *		?=?( const	     DT * volatile &,			void * );
-forall( dtype DT ) const DT *		?=?( const	     DT *	   &, const		void * );
-forall( dtype DT ) const DT *		?=?( const	     DT * volatile &, const		void * );
-forall( dtype DT ) volatile DT *	?=?(	   volatile  DT *	   &,			void * );
-forall( dtype DT ) volatile DT *	?=?(	   volatile  DT * volatile &,			void * );
-forall( dtype DT ) volatile DT *	?=?(	   volatile  DT *	   &,	    volatile	void * );
-forall( dtype DT ) volatile DT *	?=?(	   volatile  DT * volatile &,	    volatile	void * );
-
-forall( dtype DT ) const volatile DT *	?=?( const volatile  DT *	   &,			void * );
-forall( dtype DT ) const volatile DT *	?=?( const volatile  DT * volatile &,			void * );
-forall( dtype DT ) const volatile DT *	?=?( const volatile  DT *	   &, const		void * );
-forall( dtype DT ) const volatile DT *	?=?( const volatile  DT * volatile &, const		void * );
-forall( dtype DT ) const volatile DT *	?=?( const volatile  DT *	   &,	    volatile	void * );
-forall( dtype DT ) const volatile DT *	?=?( const volatile  DT * volatile &,	    volatile	void * );
-forall( dtype DT ) const volatile DT *	?=?( const volatile  DT *	   &, const volatile	void * );
-forall( dtype DT ) const volatile DT *	?=?( const volatile  DT * volatile &, const volatile	void * );
-
 forall( dtype DT ) void *		 ?=?(		     void *	     &,			DT * );
 forall( dtype DT ) void *		 ?=?(		     void * volatile &,			DT * );
@@ -441,23 +421,4 @@
 forall( dtype DT ) const volatile void * ?=?( const volatile void *	     &, const volatile	DT * );
 forall( dtype DT ) const volatile void * ?=?( const volatile void * volatile &, const volatile	DT * );
-
-void *			?=?(		    void *	    &,		      void * );
-void *			?=?(		    void * volatile &,		      void * );
-const void *		?=?( const	    void *	    &,		      void * );
-const void *		?=?( const	    void * volatile &,		      void * );
-const void *		?=?( const	    void *	    &, const	      void * );
-const void *		?=?( const	    void * volatile &, const	      void * );
-volatile void *		?=?(	   volatile void *	    &,		      void * );
-volatile void *		?=?(	   volatile void * volatile &,		      void * );
-volatile void *		?=?(	   volatile void *	    &,	     volatile void * );
-volatile void *		?=?(	   volatile void * volatile &,	     volatile void * );
-const volatile void *	?=?( const volatile void *	    &,		      void * );
-const volatile void *	?=?( const volatile void * volatile &,		      void * );
-const volatile void *	?=?( const volatile void *	    &, const	      void * );
-const volatile void *	?=?( const volatile void * volatile &, const	      void * );
-const volatile void *	?=?( const volatile void *	    &,	     volatile void * );
-const volatile void *	?=?( const volatile void * volatile &,	     volatile void * );
-const volatile void *	?=?( const volatile void *	    &, const volatile void * );
-const volatile void *	?=?( const volatile void * volatile &, const volatile void * );
 
 //forall( dtype DT ) DT *			?=?(		    DT *	  &, zero_t );
@@ -781,15 +742,4 @@
 forall( dtype DT ) void ?{}( const volatile  DT *	   &, const volatile	DT * );
 
-forall( dtype DT ) void ?{}(		     DT *	   &,			void * );
-forall( dtype DT ) void ?{}( const	     DT *	   &,			void * );
-forall( dtype DT ) void ?{}( const	     DT *	   &, const		void * );
-forall( dtype DT ) void ?{}(	   volatile  DT *	   &,			void * );
-forall( dtype DT ) void ?{}(	   volatile  DT *	   &,	    volatile	void * );
-
-forall( dtype DT ) void ?{}( const volatile  DT *	   &,			void * );
-forall( dtype DT ) void ?{}( const volatile  DT *	   &, const		void * );
-forall( dtype DT ) void ?{}( const volatile  DT *	   &,	    volatile	void * );
-forall( dtype DT ) void ?{}( const volatile  DT *	   &, const volatile	void * );
-
 forall( dtype DT ) void ?{}(		     void *	     &,			DT * );
 forall( dtype DT ) void ?{}( const	     void *	     &,			DT * );
@@ -802,14 +752,4 @@
 forall( dtype DT ) void ?{}( const volatile void *	     &, const volatile	DT * );
 
-void 	?{}(		    void *	    &,		      void * );
-void 	?{}( const	    void *	    &,		      void * );
-void 	?{}( const	    void *	    &, const	      void * );
-void 	?{}(	   volatile void *	    &,		      void * );
-void 	?{}(	   volatile void *	    &,	     volatile void * );
-void 	?{}( const volatile void *	    &,		      void * );
-void 	?{}( const volatile void *	    &, const	      void * );
-void 	?{}( const volatile void *	    &,	     volatile void * );
-void 	?{}( const volatile void *	    &, const volatile void * );
-
 //forall( dtype DT ) void ?{}(		    DT *	  &, zero_t );
 //forall( dtype DT ) void ?{}(		    DT * volatile &, zero_t );
Index: src/tests/.expect/alloc-ERROR.txt
===================================================================
--- src/tests/.expect/alloc-ERROR.txt	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
+++ src/tests/.expect/alloc-ERROR.txt	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -0,0 +1,44 @@
+alloc.c:259:1 error: No reasonable alternatives for expression Applying untyped: 
+  Name: ?=?
+...to: 
+  Name: p
+  Applying untyped: 
+    Name: alloc
+  ...to: 
+    Name: stp
+    Applying untyped: 
+      Name: ?*?
+    ...to: 
+      Name: dim
+      Sizeof Expression on: Applying untyped: 
+          Name: *?
+        ...to: 
+          Name: stp
+
+
+
+
+alloc.c:260:1 error: No reasonable alternatives for expression Applying untyped: 
+  Name: ?=?
+...to: 
+  Name: p
+  Applying untyped: 
+    Name: memset
+  ...to: 
+    Name: stp
+    constant expression (10 10: signed int)
+
+
+alloc.c:261:1 error: No reasonable alternatives for expression Applying untyped: 
+  Name: ?=?
+...to: 
+  Name: p
+  Applying untyped: 
+    Name: memcpy
+  ...to: 
+    Address of:
+      Name: st1
+    Address of:
+      Name: st
+
+
Index: src/tests/.expect/castError.txt
===================================================================
--- src/tests/.expect/castError.txt	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/tests/.expect/castError.txt	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -5,5 +5,8 @@
   charAlternatives are:
 Cost ( 1, 0, 0, 0 ): Cast of:
-     Variable Expression: f: signed int
+     Variable Expression: f: function
+       accepting unspecified arguments
+     ... returning nothing 
+
    ... to:
      char
@@ -23,8 +26,5 @@
 
 Cost ( 1, 0, 0, 0 ): Cast of:
-     Variable Expression: f: function
-       accepting unspecified arguments
-     ... returning nothing 
-
+     Variable Expression: f: signed int
    ... to:
      char
Index: src/tests/.expect/completeTypeError.txt
===================================================================
--- src/tests/.expect/completeTypeError.txt	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/tests/.expect/completeTypeError.txt	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -1,7 +1,16 @@
-completeTypeError.c:34:1 error: No reasonable alternatives for expression Applying untyped: 
+completeTypeError.c:33:1 error: No reasonable alternatives for expression Applying untyped: 
   Name: *?
 ...to: 
   Name: v
 
+completeTypeError.c:34:1 error: No reasonable alternatives for expression Applying untyped: 
+  Name: *?
+...to: 
+  Name: y
+
+completeTypeError.c:35:1 error: No reasonable alternatives for expression Applying untyped: 
+  Name: foo
+...to: 
+  Name: v
 
 completeTypeError.c:36:1 error: No reasonable alternatives for expression Applying untyped: 
@@ -10,10 +19,8 @@
   Name: v
 
-
 completeTypeError.c:37:1 error: No reasonable alternatives for expression Applying untyped: 
   Name: quux
 ...to: 
   Name: v
-
 
 completeTypeError.c:58:1 error: No reasonable alternatives for expression Applying untyped: 
@@ -22,10 +29,8 @@
   Name: y
 
-
 completeTypeError.c:59:1 error: No reasonable alternatives for expression Applying untyped: 
   Name: quux
 ...to: 
   Name: y
-
 
 completeTypeError.c:60:1 error: No reasonable alternatives for expression Applying untyped: 
@@ -34,5 +39,4 @@
   Name: y
 
-
 completeTypeError.c:72:1 error: No reasonable alternatives for expression Applying untyped: 
   Name: baz
@@ -40,3 +44,2 @@
   Name: z
 
-
Index: src/tests/Makefile.am
===================================================================
--- src/tests/Makefile.am	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/tests/Makefile.am	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -141,2 +141,5 @@
 typedefRedef-ERR1: typedefRedef.c @CFA_BINDIR@/@CFA_NAME@
 	${CC} ${AM_CFLAGS} ${CFLAGS} -DERR1 ${<} -o ${@}
+
+alloc-ERROR: alloc.c @CFA_BINDIR@/@CFA_NAME@
+	${CC} ${AM_CFLAGS} ${CFLAGS} -DERR1 ${<} -o ${@}
Index: src/tests/Makefile.in
===================================================================
--- src/tests/Makefile.in	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/tests/Makefile.in	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -895,4 +895,7 @@
 	${CC} ${AM_CFLAGS} ${CFLAGS} -DERR1 ${<} -o ${@}
 
+alloc-ERROR: alloc.c @CFA_BINDIR@/@CFA_NAME@
+	${CC} ${AM_CFLAGS} ${CFLAGS} -DERR1 ${<} -o ${@}
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
Index: src/tests/alloc.c
===================================================================
--- src/tests/alloc.c	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/tests/alloc.c	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -32,5 +32,5 @@
 	// allocation, non-array types
 
-	p = (void *)malloc( sizeof(*p) );                   // C malloc, type unsafe
+	p = (int *)(void *)malloc( sizeof(*p) );                   // C malloc, type unsafe
 	*p = 0xdeadbeef;
 	printf( "C   malloc %#x\n", *p );
@@ -54,5 +54,5 @@
 	printf( "\n" );
 
-	p = calloc( dim, sizeof( *p ) );                    // C array calloc, type unsafe
+	p = (int *)calloc( dim, sizeof( *p ) );                    // C array calloc, type unsafe
 	printf( "C   array calloc, fill 0\n" );
 	for ( int i = 0; i < dim; i += 1 ) { printf( "%#x ", p[i] ); }
@@ -83,5 +83,5 @@
 	printf( "\n" );
 
-	p = (void *)realloc( p, dim * sizeof(*p) );         // C realloc
+	p = (int *)(void *)realloc( p, dim * sizeof(*p) );         // C realloc
 	for ( int i = 0; i < dim; i += 1 ) { p[i] = 0xdeadbeef; }
 	printf( "C   realloc\n" );
@@ -256,7 +256,9 @@
 	stp = malloc();
 	printf( "\nSHOULD FAIL\n" );
+#ifdef ERR1
 	p = alloc( stp, dim * sizeof(*stp) );
 	p = memset( stp, 10 );
 	p = memcpy( &st1, &st );
+#endif
 } // main
 
Index: src/tests/completeTypeError.c
===================================================================
--- src/tests/completeTypeError.c	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/tests/completeTypeError.c	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -12,13 +12,13 @@
 	void *v;
 
-	// A * x;
-	// A * y;
-	// B * x;
-	// B * z;
+	A * x;
+	A * y;
+	B * x;
+	B * z;
 
 	// okay
 	*i;
-	// *x; // picks B
-	// *z;
+	*x; // picks B
+	*z;
 	foo(i);
 	bar(i);
@@ -29,9 +29,9 @@
 	bar(v);
 	qux(v);
-	foo(v); // questionable, but works at the moment for C compatibility
 
 	// bad
 	*v;
-	// *y;
+	*y;
+	foo(v);
 	baz(v);
 	quux(v);
Index: src/tests/dtor-early-exit.c
===================================================================
--- src/tests/dtor-early-exit.c	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/tests/dtor-early-exit.c	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -22,5 +22,5 @@
 
 struct A {
-	char * name;
+	const char * name;
 	int * x;
 };
Index: src/tests/init_once.c
===================================================================
--- src/tests/init_once.c	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/tests/init_once.c	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -72,5 +72,5 @@
 	insert( &constructed, &x );
 
-	x.x = malloc(sizeof(int));
+	x.x = (int *)malloc(sizeof(int));
 }
 
Index: src/tests/multiDimension.c
===================================================================
--- src/tests/multiDimension.c	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/tests/multiDimension.c	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -7,5 +7,5 @@
   printf("default constructing\n");
   (this.a){ 123 };
-  this.ptr = malloc(sizeof(int));
+  this.ptr = (int *)malloc(sizeof(int));
 }
 
@@ -13,5 +13,5 @@
   printf("copy constructing\n");
   (this.a){ other.a };
-  this.ptr = malloc(sizeof(int));
+  this.ptr = (int *)malloc(sizeof(int));
 }
 
@@ -19,5 +19,5 @@
   printf("constructing with %d\n", a);
   (this.a){ a };
-  this.ptr = malloc(sizeof(int));
+  this.ptr = (int *)malloc(sizeof(int));
 }
 
Index: src/tests/polymorphism.c
===================================================================
--- src/tests/polymorphism.c	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/tests/polymorphism.c	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -14,4 +14,7 @@
 //
 
+#include <assert.h>
+#include <inttypes.h>
+
 forall(otype T)
 T f(T x, T y) {
@@ -24,15 +27,90 @@
 }
 
+forall( otype T, otype U )
+size_t struct_size( T i, U j ) {
+	struct S { T i; U j; };
+	return sizeof(S);
+}
+
+forall( otype T, otype U )
+size_t union_size( T i, U j ) {
+	union B { T i; U j; };
+	return sizeof(B);
+}
+
+// perform some simple operations on aggregates of T and U
+forall( otype T | { void print(T); int ?==?(T, T); }, otype U | { void print(U); U ?=?(U&, zero_t); } )
+U foo(T i, U j) {
+	struct S { T i; U j; };
+	union B { T i; U j; };
+
+	S s;
+	s.i = i;
+	assert(s.i == i);
+
+	B b;
+	b.j = 0;
+	b.i = s.i;
+	return b.j;
+}
+
 int main() {
-	// ensure that x is not changed by the invocation of a polymorphic function
-	int x = 123;
-	int y = 456;
-	int z = f(x, y);
-	printf("%d %d %d\n", x, y, z);
+	{
+		// ensure that x is not changed by the invocation of a polymorphic function
+		int x = 123;
+		int y = 456;
+		int z = f(x, y);
+		printf("%d %d %d\n", x, y, z);
+	}
 
-	// explicitly specialize function
-	int (*f)(int) = ident;
-	((int(*)(int))ident);
-	printf("%d %d\n", f(5), ((int(*)(int))ident)(5));
+	{
+		// explicitly specialize function
+		int (*f)(int) = ident;
+		((int(*)(int))ident);
+		printf("%d %d\n", f(5), ((int(*)(int))ident)(5));
+	}
+
+	{
+		// test aggregates with polymorphic members
+		typedef uint32_t x_type;
+		typedef uint64_t y_type;
+
+		x_type x = 3;
+		y_type y = 3;
+
+		struct S {
+			x_type f1;
+			y_type f2;
+		};
+		union U {
+			x_type f1;
+			y_type f2;
+		};
+		// ensure that the size of aggregates with polymorphic members
+		// matches the size of the aggregates in a monomorphic context
+		assert( struct_size(x, y) == sizeof(S) );
+		assert( union_size(x, y) == sizeof(U) );
+
+		y_type ?=?(y_type & this, zero_t) {
+			this = (int)0;
+			return this;
+		}
+
+		void print(x_type x) {
+			printf("%"PRIu32"\n", x);
+		}
+
+		void print(y_type y) {
+			printf("%"PRIu64"\n", y);
+		}
+
+		y_type ret = foo(x, y);
+
+		// duplicate logic from inside of foo to ensure the same results
+		U u;
+		u.f2 = 0;
+		u.f1 = x;
+		assert(ret == u.f2);
+	}
 }
 
Index: src/tests/tupleVariadic.c
===================================================================
--- src/tests/tupleVariadic.c	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/tests/tupleVariadic.c	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -73,5 +73,5 @@
 	[a0, a1, a2, a3] = args;
 	a.size = 4;
-	a.data = malloc(sizeof(int)*a.size);
+	a.data = (int *)malloc(sizeof(int)*a.size);
 	a.data[0] = a0;
 	a.data[1] = a1;
Index: src/tests/vector/vector_int.c
===================================================================
--- src/tests/vector/vector_int.c	(revision 50abab9cbe0831c614ab6df0acdcf274367dd902)
+++ src/tests/vector/vector_int.c	(revision 2b716ec28ad95c2132e5e2ff74fd1bb6fb81fd9d)
@@ -27,5 +27,5 @@
 	vec.last = -1;
 	vec.capacity = reserve;
-	vec.data = malloc( sizeof( int ) * reserve );
+	vec.data = (int *)malloc( sizeof( int ) * reserve );
 }
 
@@ -33,5 +33,5 @@
 	vec.last = other.last;
 	vec.capacity = other.capacity;
-	vec.data = malloc( sizeof( int ) * other.capacity );
+	vec.data = (int *)malloc( sizeof( int ) * other.capacity );
 	for (int i = 0; i < vec.last; i++) {
 		vec.data[i] = other.data[i];
@@ -45,5 +45,5 @@
 void reserve( vector_int *vec, int reserve ) {
 	if ( reserve > vec->capacity ) {
-		vec->data = realloc( vec->data, sizeof( int ) * reserve );
+		vec->data = (int *)realloc( vec->data, sizeof( int ) * reserve );
 		vec->capacity = reserve;
 	}
@@ -54,5 +54,5 @@
 	if ( vec->last == vec->capacity ) {
 		vec->capacity *= 2;
-		vec->data = realloc( vec->data, sizeof( int ) * vec->capacity );
+		vec->data = (int *)realloc( vec->data, sizeof( int ) * vec->capacity );
 	}
 	vec->data[ vec->last ] = element;
