Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(revision c2c6177b76e4392e2fd7a54666c8f159e7efcef6)
+++ src/Makefile.in	(revision a8b27c63155718a34534b0647bd76f979bc66cdf)
@@ -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/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision c2c6177b76e4392e2fd7a54666c8f159e7efcef6)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision a8b27c63155718a34534b0647bd76f979bc66cdf)
@@ -30,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
@@ -587,23 +588,23 @@
 		unsigned nextArg;                  ///< Index of next argument in arguments list
 		unsigned tupleStart;               ///< Number of tuples that start at this index
-		// TODO fix this somehow
-		std::vector<Alternative> expls;    ///< Exploded actuals left over from last match
-
+		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), expls() {}
+			  tupleStart(0), nextExpl(0), explAlt(0) {}
 		
 		ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have, 
 				const OpenVarSet& openVars)
 			: parent(0), expr(), cost(Cost::zero), env(env), need(need), have(have), 
-			  openVars(openVars), nextArg(0), tupleStart(0), expls() {}
+			  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, 
-				std::vector<Alternative>&& expls = std::vector<Alternative>{} )
+				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),
-			  expls(move(expls)) {}
+			  nextExpl(nextExpl), explAlt(explAlt) {}
 		
 		ArgPack(const ArgPack& o, TypeEnvironment&& env, AssertionSet&& need, AssertionSet&& have, 
@@ -611,14 +612,14 @@
 			: 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), expls() {}
+			  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];
+		}
 			  
-
-		// ArgPack(const ArgPack& o)
-		// 	: parent(o.parent), expr(o.expr ? o.expr->clone() : nullptr), env(o.env), 
-		// 	  need(o.need), have(o.have), openVars(o.openVars), nextArg(o.nextArg), 
-		// 	  tupleStart(o.tupleStart), expls(o.expls) {}
-
-		// ArgPack(ArgPack&&) = default;
-		
 		/// Ends a tuple expression, consolidating the appropriate actuals
 		void endTuple( const std::vector<ArgPack>& packs ) {
@@ -641,6 +642,6 @@
 	/// 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::size_t& genStart, const SymTab::Indexer& indexer, unsigned nTuples = 0 ) {
+			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
@@ -673,7 +674,10 @@
 				// add another argument to 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].expls.empty() ) {
-						const Alternative& actual = results[i].expls.front();
+					if ( results[i].hasExpl() ) {
+						const ExplodedActual& expl = results[i].getExpl( args );
+						const Alternative& actual = expl.alts[results[i].nextExpl];
 						
 						TypeEnvironment env = results[i].env;
@@ -682,10 +686,13 @@
 						env.addActual( actual.env, openVars );
 
-						std::vector<Alternative> newExpls( 
-							std::next( results[i].expls.begin() ), results[i].expls.end() );
+						unsigned nextExpl = results[i].nextExpl + 1;
+						if ( nextExpl == expl.alts.size() ) {
+							nextExpl = 0;
+						}
+
 						results.emplace_back(
 							i, actual.expr, move(env), copy(results[i].need), 
-							copy(results[i].have), move(openVars), results[i].nextArg, nTuples, 
-							Cost::zero, move(newExpls) );
+							copy(results[i].have), move(openVars), nextArg, nTuples, 
+							Cost::zero, nextExpl, results[i].explAlt );
 						
 						continue;
@@ -693,9 +700,9 @@
 					
 					// finish result when out of arguments
-					if ( results[i].nextArg >= args.size() ) {
+					if ( nextArg >= args.size() ) {
 						ArgPack newResult{ 
 							results[i].env, results[i].need, results[i].have, 
 							results[i].openVars };
-						newResult.nextArg = results[i].nextArg;
+						newResult.nextArg = nextArg;
 						Type* argType;
 
@@ -741,35 +748,27 @@
 
 					// add each possible next argument
-					auto j = results[i].nextArg;
-					for ( const Alternative& actual : args[j] ) {
+					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( actual.env, openVars );
-
-						// explode argument
-						std::vector<Alternative> exploded;
-						Tuples::explode( actual, indexer, back_inserter( exploded ) );
-						if ( exploded.empty() ) {
-							// skip empty tuple arguments by (near-)cloning parent into next gen
+						env.addActual( expl.env, openVars );
+
+						// skip empty tuple arguments by (near-)cloning parent into next gen
+						if ( expl.alts.empty() ) {
 							results.emplace_back(
 								results[i], move(env), copy(results[i].need), 
-								copy(results[i].have), move(openVars), j + 1, actual.cost );
+								copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
 							
 							continue;
 						}
 
-						// trim first element from exploded
-						std::vector<Alternative> newExpls;
-						newExpls.reserve( exploded.size() - 1 );
-						for ( std::size_t i = 1; i < exploded.size(); ++i ) {
-							newExpls.push_back( move(exploded[i]) );
-						}
 						// add new result
 						results.emplace_back(
-							i, exploded.front().expr, move(env), copy(results[i].need), 
-							copy(results[i].have), move(openVars), results[i].nextArg + 1, 
-							nTuples, actual.cost, move(newExpls) );
+							i, expl.alts.front().expr, move(env), copy(results[i].need), 
+							copy(results[i].have), move(openVars), nextArg + 1, 
+							nTuples, expl.cost, expl.alts.size() == 1 ? 0 : 1, j );
 					}
 				}
@@ -790,7 +789,10 @@
 		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].expls.empty() ) {
-				const Alternative& actual = results[i].expls.front();
+			if ( results[i].hasExpl() ) {
+				const ExplodedActual& expl = results[i].getExpl( args );
+				const Alternative& actual = expl.alts[results[i].nextExpl];
 				
 				TypeEnvironment env = results[i].env;
@@ -810,9 +812,12 @@
 				
 				if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
-					std::vector<Alternative> newExpls( 
-						std::next( results[i].expls.begin() ), results[i].expls.end() );
+					unsigned nextExpl = results[i].nextExpl + 1;
+					if ( nextExpl == expl.alts.size() ) {
+						nextExpl = 0;
+					}
+					
 					results.emplace_back( 
 						i, actual.expr, move(env), move(need), move(have), move(openVars), 
-						results[i].nextArg, nTuples, Cost::zero, move(newExpls) );;
+						nextArg, nTuples, Cost::zero, nextExpl, results[i].explAlt );
 				}
 
@@ -821,5 +826,5 @@
 			
 			// use default initializers if out of arguments
-			if ( results[i].nextArg >= args.size() ) {
+			if ( nextArg >= args.size() ) {
 				if ( ConstantExpr* cnstExpr = getDefaultValue( initializer ) ) {
 					if ( Constant* cnst = dynamic_cast<Constant*>( cnstExpr->get_constant() ) ) {
@@ -832,5 +837,5 @@
 							results.emplace_back(
 								i, cnstExpr, move(env), move(need), move(have), 
-								move(openVars), results[i].nextArg, nTuples );
+								move(openVars), nextArg, nTuples );
 						}
 					}
@@ -841,6 +846,7 @@
 
 			// Check each possible next argument
-			auto j = results[i].nextArg;
-			for ( const Alternative& actual : args[j] ) {
+			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;
@@ -848,14 +854,11 @@
 				OpenVarSet openVars = results[i].openVars;
 
-				env.addActual( actual.env, openVars );
+				env.addActual( expl.env, openVars );
 				
-				// explode argument
-				std::vector<Alternative> exploded;
-				Tuples::explode( actual, indexer, back_inserter( exploded ) );
-				if ( exploded.empty() ) {
-					// skip empty tuple arguments by (near-)cloning parent into next gen
+				// skip empty tuple arguments by (near-)cloning parent into next gen
+				if ( expl.alts.empty() ) {
 					results.emplace_back(
-						results[i], move(env), move(need), move(have), move(openVars), j + 1, 
-						actual.cost );
+						results[i], move(env), move(need), move(have), move(openVars), 
+						nextArg + 1, expl.cost );
 
 					continue;
@@ -863,6 +866,6 @@
 
 				// consider only first exploded actual
-				const Alternative& aActual = exploded.front();
-				Type* actualType = aActual.expr->get_result()->clone();
+				const Alternative& actual = expl.alts.front();
+				Type* actualType = actual.expr->get_result()->clone();
 
 				PRINT(
@@ -876,14 +879,8 @@
 				// attempt to unify types
 				if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
-					// trim first element from exploded
-					std::vector<Alternative> newExpls;
-					newExpls.reserve( exploded.size() - 1 );
-					for ( std::size_t i = 1; i < exploded.size(); ++i ) {
-						newExpls.push_back( move(exploded[i]) );
-					}
 					// add new result
 					results.emplace_back(
-						i, aActual.expr, move(env), move(need), move(have), move(openVars),
-						j + 1, nTuples, actual.cost, move(newExpls) );
+						i, actual.expr, move(env), move(need), move(have), move(openVars),
+						nextArg + 1, nTuples, expl.cost, expl.alts.size() == 1 ? 0 : 1, j );
 				}
 			}
@@ -921,6 +918,5 @@
 	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;
@@ -961,7 +957,10 @@
 				// 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].expls.empty() ) {
-						const Alternative& actual = results[i].expls.front();
+					if ( results[i].hasExpl() ) {
+						const ExplodedActual& expl = results[i].getExpl( args );
+						const Alternative& actual = expl.alts[results[i].nextExpl];
 						
 						TypeEnvironment env = results[i].env;
@@ -970,10 +969,13 @@
 						env.addActual( actual.env, openVars );
 
-						std::vector<Alternative> newExpls( 
-							std::next( results[i].expls.begin() ), results[i].expls.end() );
+						unsigned nextExpl = results[i].nextExpl + 1;
+						if ( nextExpl == expl.alts.size() ) {
+							nextExpl = 0;
+						}
+
 						results.emplace_back(
 							i, actual.expr, move(env), copy(results[i].need), 
-							copy(results[i].have), move(openVars), results[i].nextArg, 0, 
-							Cost::zero, move(newExpls) );
+							copy(results[i].have), move(openVars), nextArg, 0, 
+							Cost::zero, nextExpl, results[i].explAlt );
 						
 						continue;
@@ -981,5 +983,5 @@
 
 					// finish result when out of arguments
-					if ( results[i].nextArg >= args.size() ) {
+					if ( nextArg >= args.size() ) {
 						validateFunctionAlternative( func, results[i], results, out );
 
@@ -988,34 +990,27 @@
 
 					// add each possible next argument
-					auto j = results[i].nextArg;
-					for ( const Alternative& actual : args[j] ) {
+					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( actual.env, openVars );
-
-						// explode argument
-						std::vector<Alternative> exploded;
-						Tuples::explode( actual, indexer, back_inserter( exploded ) );
-						if ( exploded.empty() ) {
-							// skip empty tuple arguments by (near-)cloning parent into next gen
+						env.addActual( expl.env, openVars );
+
+						// skip empty tuple arguments by (near-)cloning parent into next gen
+						if ( expl.alts.empty() ) {
 							results.emplace_back( 
 								results[i], move(env), copy(results[i].need), 
-								copy(results[i].have), move(openVars), j + 1, actual.cost );
+								copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
+							
 							continue;
 						}
 
-						// trim first element from exploded
-						std::vector<Alternative> newExpls;
-						newExpls.reserve( exploded.size() - 1 );
-						for ( std::size_t i = 1; i < exploded.size(); ++i ) {
-							newExpls.push_back( move(exploded[i]) );
-						}
 						// add new result
 						results.emplace_back(
-							i, exploded.front().expr, move(env), copy(results[i].need), 
-							copy(results[i].have), move(openVars), j + 1, 0, 
-							actual.cost, move(newExpls) );
+							i, expl.alts.front().expr, move(env), copy(results[i].need), 
+							copy(results[i].have), move(openVars), nextArg + 1, 0, 
+							expl.cost, expl.alts.size() == 1 ? 0 : 1, j );
 					}
 				}
@@ -1027,5 +1022,5 @@
 			for ( std::size_t i = genStart; i < results.size(); ++i ) {
 				ArgPack& result = results[i];
-				if ( result.expls.empty() && result.nextArg >= args.size() ) {
+				if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
 					validateFunctionAlternative( func, result, results, out );
 				}
@@ -1057,4 +1052,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;
@@ -1071,5 +1080,5 @@
 						Alternative newFunc( *func );
 						referenceToRvalueConversion( newFunc.expr );
-						makeFunctionAlternatives( newFunc, function, argAlternatives,
+						makeFunctionAlternatives( newFunc, function, argExpansions,
 							std::back_inserter( candidates ) );
 					}
@@ -1080,5 +1089,5 @@
 							Alternative newFunc( *func );
 							referenceToRvalueConversion( newFunc.expr );
-							makeFunctionAlternatives( newFunc, function, argAlternatives,
+							makeFunctionAlternatives( newFunc, function, argExpansions,
 								std::back_inserter( candidates ) );
 						} // if
@@ -1092,6 +1101,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(), 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();
@@ -1105,5 +1119,5 @@
 							Alternative newFunc( *funcOp );
 							referenceToRvalueConversion( newFunc.expr );
-							makeFunctionAlternatives( newFunc, function, argAlternatives,
+							makeFunctionAlternatives( newFunc, function, argExpansions,
 								std::back_inserter( candidates ) );
 						}
Index: src/ResolvExpr/AlternativeFinder.h
===================================================================
--- src/ResolvExpr/AlternativeFinder.h	(revision c2c6177b76e4392e2fd7a54666c8f159e7efcef6)
+++ src/ResolvExpr/AlternativeFinder.h	(revision a8b27c63155718a34534b0647bd76f979bc66cdf)
@@ -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
@@ -32,4 +33,8 @@
 namespace ResolvExpr {
 	class 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 {
@@ -133,5 +138,5 @@
 		/// Finds matching alternatives for a function, given a set of arguments
 		template<typename OutputIterator>
-		void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const std::vector< AlternativeFinder >& args, OutputIterator out );
+		void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs& args, OutputIterator out );
 		/// Checks if assertion parameters match for a new alternative
 		template< typename OutputIterator >
Index: src/ResolvExpr/ExplodedActual.cc
===================================================================
--- src/ResolvExpr/ExplodedActual.cc	(revision a8b27c63155718a34534b0647bd76f979bc66cdf)
+++ src/ResolvExpr/ExplodedActual.cc	(revision a8b27c63155718a34534b0647bd76f979bc66cdf)
@@ -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), alts() {
+		Tuples::explode( actual, indexer, back_inserter( alts ) );
+	}
+}
Index: src/ResolvExpr/ExplodedActual.h
===================================================================
--- src/ResolvExpr/ExplodedActual.h	(revision a8b27c63155718a34534b0647bd76f979bc66cdf)
+++ src/ResolvExpr/ExplodedActual.h	(revision a8b27c63155718a34534b0647bd76f979bc66cdf)
@@ -0,0 +1,34 @@
+//
+// 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 "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;
+		AltList alts;  // TODO flatten this down to vector<unique_ptr<Expression>>
+
+		ExplodedActual() : env(), cost(Cost::zero), alts() {}
+
+		ExplodedActual( const Alternative& actual, const SymTab::Indexer& indexer );	
+	};
+}
Index: src/ResolvExpr/module.mk
===================================================================
--- src/ResolvExpr/module.mk	(revision c2c6177b76e4392e2fd7a54666c8f159e7efcef6)
+++ src/ResolvExpr/module.mk	(revision a8b27c63155718a34534b0647bd76f979bc66cdf)
@@ -32,3 +32,4 @@
        ResolvExpr/Occurs.cc \
        ResolvExpr/TypeEnvironment.cc \
-       ResolvExpr/CurrentObject.cc
+       ResolvExpr/CurrentObject.cc \
+       ResolvExpr/ExplodedActual.cc
