Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 9bae71f54a1540038ca18b7232347ac138cf2c78)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision aeb75b17b518f4bb9ecd6a4cd511e2a899c417af)
@@ -22,4 +22,5 @@
 #include <memory>                  // for allocator_traits<>::value_type
 #include <utility>                 // for pair
+#include <vector>                  // for vector
 
 #include "Alternative.h"           // for AltList, Alternative
@@ -396,120 +397,4 @@
 ///     needAssertions.insert( needAssertions.end(), (*tyvar)->get_assertions().begin(), (*tyvar)->get_assertions().end() );
 		}
-	}
-
-	/// instantiate a single argument by matching actuals from [actualIt, actualEnd) against formalType,
-	/// producing expression(s) in out and their total cost in cost.
-	template< typename AltIterator, typename OutputIterator >
-	bool instantiateArgument( Type * formalType, Initializer * defaultValue, AltIterator & actualIt, AltIterator actualEnd, OpenVarSet & openVars, TypeEnvironment & resultEnv, AssertionSet & resultNeed, AssertionSet & resultHave, const SymTab::Indexer & indexer, Cost & cost, OutputIterator out ) {
-		if ( TupleType * tupleType = dynamic_cast< TupleType * >( formalType ) ) {
-			// formalType is a TupleType - group actuals into a TupleExpr whose type unifies with the TupleType
-			std::list< Expression * > exprs;
-			for ( Type * type : *tupleType ) {
-				if ( ! instantiateArgument( type, defaultValue, actualIt, actualEnd, openVars, resultEnv, resultNeed, resultHave, indexer, cost, back_inserter( exprs ) ) ) {
-					deleteAll( exprs );
-					return false;
-				}
-			}
-			*out++ = new TupleExpr( exprs );
-		} else if ( TypeInstType * ttype = Tuples::isTtype( formalType ) ) {
-			// xxx - mixing default arguments with variadic??
-			std::list< Expression * > exprs;
-			for ( ; actualIt != actualEnd; ++actualIt ) {
-				exprs.push_back( actualIt->expr->clone() );
-				cost += actualIt->cost;
-			}
-			Expression * arg = nullptr;
-			if ( exprs.size() == 1 && Tuples::isTtype( exprs.front()->get_result() ) ) {
-				// 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.
-				arg = exprs.front();
-			} else {
-				arg = new TupleExpr( exprs );
-			}
-			assert( arg && arg->get_result() );
-			if ( ! unify( ttype, arg->get_result(), resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
-				return false;
-			}
-			*out++ = arg;
-		} else if ( actualIt != actualEnd ) {
-			// both actualType and formalType are atomic (non-tuple) types - if they unify
-			// then accept actual as an argument, otherwise return false (fail to instantiate argument)
-			Expression * actual = actualIt->expr;
-			Type * actualType = actual->get_result();
-
-			PRINT(
-				std::cerr << "formal type is ";
-				formalType->print( std::cerr );
-				std::cerr << std::endl << "actual type is ";
-				actualType->print( std::cerr );
-				std::cerr << std::endl;
-			)
-			if ( ! unify( formalType, actualType, resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
-				// std::cerr << "unify failed" << std::endl;
-				return false;
-			}
-			// move the expression from the alternative to the output iterator
-			*out++ = actual;
-			actualIt->expr = nullptr;
-			cost += actualIt->cost;
-			++actualIt;
-		} else {
-			// End of actuals - Handle default values
-			if ( SingleInit *si = dynamic_cast<SingleInit *>( defaultValue )) {
-				if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( si->get_value() ) ) {
-					// so far, only constant expressions are accepted as default values
-					if ( ConstantExpr *cnstexpr = dynamic_cast<ConstantExpr *>( castExpr->get_arg() ) ) {
-						if ( Constant *cnst = dynamic_cast<Constant *>( cnstexpr->get_constant() ) ) {
-							if ( unify( formalType, cnst->get_type(), resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
-								*out++ = cnstexpr->clone();
-								return true;
-							} // if
-						} // if
-					} // if
-				}
-			} // if
-			return false;
-		} // if
-		return true;
-	}
-
-	bool AlternativeFinder::instantiateFunction( std::list< DeclarationWithType* >& formals, const AltList &actuals, bool isVarArgs, OpenVarSet& openVars, TypeEnvironment &resultEnv, AssertionSet &resultNeed, AssertionSet &resultHave, AltList & out ) {
-		simpleCombineEnvironments( actuals.begin(), actuals.end(), resultEnv );
-		// make sure we don't widen any existing bindings
-		for ( TypeEnvironment::iterator i = resultEnv.begin(); i != resultEnv.end(); ++i ) {
-			i->allowWidening = false;
-		}
-		resultEnv.extractOpenVars( openVars );
-
-		// flatten actuals so that each actual has an atomic (non-tuple) type
-		AltList exploded;
-		Tuples::explode( actuals, indexer, back_inserter( exploded ) );
-
-		AltList::iterator actualExpr = exploded.begin();
-		AltList::iterator actualEnd = exploded.end();
-		for ( DeclarationWithType * formal : formals ) {
-			// match flattened actuals with formal parameters - actuals will be grouped to match
-			// with formals as appropriate
-			Cost cost = Cost::zero;
-			std::list< Expression * > newExprs;
-			ObjectDecl * obj = strict_dynamic_cast< ObjectDecl * >( formal );
-			if ( ! instantiateArgument( obj->get_type(), obj->get_init(), actualExpr, actualEnd, openVars, resultEnv, resultNeed, resultHave, indexer, cost, back_inserter( newExprs ) ) ) {
-				deleteAll( newExprs );
-				return false;
-			}
-			// success - produce argument as a new alternative
-			assert( newExprs.size() == 1 );
-			out.push_back( Alternative( newExprs.front(), resultEnv, cost ) );
-		}
-		if ( actualExpr != actualEnd ) {
-			// there are still actuals remaining, but we've run out of formal parameters to match against
-			// this is okay only if the function is variadic
-			if ( ! isVarArgs ) {
-				return false;
-			}
-			out.splice( out.end(), exploded, actualExpr, actualEnd );
-		}
-		return true;
 	}
 
@@ -667,31 +552,309 @@
 	}
 
-	template< typename OutputIterator >
-	void AlternativeFinder::makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const AltList &actualAlt, OutputIterator out ) {
-		OpenVarSet openVars;
-		AssertionSet resultNeed, resultHave;
-		TypeEnvironment resultEnv;
-		makeUnifiableVars( funcType, openVars, resultNeed );
-		resultEnv.add( funcType->get_forall() ); // add all type variables as open variables now so that those not used in the parameter list are still considered open
-		AltList instantiatedActuals; // filled by instantiate function
+	/// Gets a default value from an initializer, nullptr if not present
+	ConstantExpr* getDefaultValue( Initializer* init ) {
+		if ( SingleInit* si = dynamic_cast<SingleInit*>( init ) ) {
+			if ( CastExpr* ce = dynamic_cast<CastExpr*>( si->get_value() ) ) {
+				return dynamic_cast<ConstantExpr*>( ce->get_arg() );
+			}
+		}
+		return nullptr;
+	}
+
+	/// 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
+		
+		/// Number of elements included in current tuple element (nested appropriately)
+		std::vector<unsigned> tupleEls;
+
+		ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have, 
+				const OpenVarSet& openVars)
+			: actuals(), env(env), need(need), have(have), openVars(openVars), nextArg(0),
+			  tupleEls() {}
+		
+		ArgPack(const ArgPack& old, Expression* actual, const Cost& cost = Cost::zero)
+			: actuals(old.actuals), env(old.env), need(old.need), have(old.have), 
+			  openVars(old.openVars), nextArg(old.nextArg + 1), tupleEls(old.tupleEls) {
+			actuals.emplace_back( actual, this->env, cost );
+		}
+		
+		ArgPack(const ArgPack& old, Expression* actual, TypeEnvironment&& env, AssertionSet&& need, 
+				AssertionSet&& have, const Cost& cost = Cost::zero)
+			: actuals(old.actuals), env(std::move(env)), need(std::move(need)), 
+			  have(std::move(have)), openVars(old.openVars), nextArg(old.nextArg + 1), 
+			  tupleEls(old.tupleEls) {
+			// add new actual
+			actuals.emplace_back( actual, this->env, cost );
+			// count tuple elements, if applicable
+			if ( ! tupleEls.empty() ) ++tupleEls.back();
+		}
+
+		/// Starts a new tuple expression
+		void beginTuple() {
+			if ( ! tupleEls.empty() ) ++tupleEls.back();
+			tupleEls.push_back(0);
+		}
+
+		/// Ends a tuple expression, consolidating the appropriate actuals
+		void endTuple() {
+			// set up new Tuple alternative
+			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 );
+				cost += actuals.back().cost;
+				actuals.pop_back();
+			}
+			tupleEls.pop_back();
+
+			// build new alternative
+			actuals.emplace_back( new TupleExpr( exprs ), this->env, cost );
+		}
+	};
+
+	/// Iterates a result, exploding actuals as needed.
+	/// add is a function that takes the same parameters as this (with the exception of add)
+	template<typename F>
+	void addExplodedActual( ArgPack& result, Expression* expr, Cost cost, 
+			std::vector<ArgPack>& nextResults, F add ) {
+		Type* res = expr->get_result()->stripReferences();
+		if ( TupleType* tupleType = dynamic_cast<TupleType*>( res ) ) {
+			if ( TupleExpr* tupleExpr = dynamic_cast<TupleExpr*>( expr ) ) {
+				// recursively explode tuple
+				for ( Expression* sexpr : tupleExpr->get_exprs() ) {
+					addExplodedActual( result, sexpr, cost, nextResults, add );
+					cost = Cost::zero; // reset cost so not duplicated
+				}
+			} else {
+				// tuple type, but not tuple expr - recursively index into components.
+				// if expr type is reference, convert to value type
+				Expression* arg = expr->clone();
+				if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
+					// expressions which may contain side effects require a single unique instance of the expression.
+					arg = new UniqueExpr( arg );
+				}
+				// cast reference to value type to facilitate further explosion
+				if ( dynamic_cast<ReferenceType*>( arg->get_result() ) ) {
+					arg = new CastExpr( arg, tupleType->clone() );
+				}
+				// explode tuple by index
+				for ( unsigned i = 0; i < tupleType->size(); ++i ) {
+					TupleIndexExpr* idx = new TupleIndexExpr( arg->clone(), i );
+					addExplodedActual( result, idx, cost, nextResults, add );
+					cost = Cost::zero; // reset cost so not duplicated
+					delete idx;
+				}
+				delete arg;
+			}
+		} else {
+			// add non-tuple results directly
+			add( result, expr->clone(), cost, nextResults );
+		}
+	}
+
+	/// 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 ) {
+		if ( TupleType* tupleType = dynamic_cast<TupleType*>( formalType ) ) {
+			// formalType is a TupleType - group actuals into a TupleExpr
+			for ( ArgPack& result : results ) { result.beginTuple(); }
+			for ( Type* type : *tupleType ) {
+				// xxx - dropping initializer changes behaviour from previous, but seems correct
+				if ( ! instantiateArgument( type, nullptr, args, results, nextResults, indexer ) ) 
+					return false;
+			}
+			for ( ArgPack& result : results ) { result.endTuple(); }
+			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(); }
+			// iterate until all results completed
+			while ( ! results.empty() ) {
+				// 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();
+						}
+						// check unification for ttype before adding to final
+						if ( unify( ttype, argType, result.env, result.need, result.have, 
+								result.openVars, indexer ) ) {
+							finalResults.emplace_back( std::move(result) );
+						}
+						continue;
+					}
+
+					// add each possible next argument
+					for ( const Alternative& actual : args[result.nextArg] ) {
+						addExplodedActual( result, actual.expr, actual.cost, nextResults, 
+							[]( ArgPack& result, Expression* expr, Cost cost, 
+									std::vector<ArgPack>& nextResults ) {
+								nextResults.emplace_back( result, expr, cost );
+							} );
+					}
+				}
+
+				// reset for next round
+				results.swap( nextResults );
+				nextResults.clear();
+			}
+			results.swap( finalResults );
+			return ! results.empty();
+		}
+		
+		// iterate each current subresult
+		for ( ArgPack& result : results ) {
+			if ( result.nextArg >= args.size() ) {
+				// If run out of actuals, handle default values
+				if ( ConstantExpr* cnstExpr = getDefaultValue( initializer ) ) {
+					if ( Constant* cnst = dynamic_cast<Constant*>( cnstExpr->get_constant() ) ) {
+						TypeEnvironment resultEnv = result.env;
+						AssertionSet resultNeed = result.need, resultHave = result.have;
+						if ( unify( formalType, cnst->get_type(), 
+								resultEnv, resultNeed, resultHave, result.openVars, 
+								indexer ) ) {
+							nextResults.emplace_back( result, cnstExpr->clone(), 
+								std::move(resultEnv), std::move(resultNeed), 
+								std::move(resultHave) );
+						}
+					}
+				}
+				continue;
+			}
+
+			// Check each possible next argument
+			for ( const Alternative& actual : args[result.nextArg] ) {
+				addExplodedActual( result, actual.expr, actual.cost, nextResults, 
+					[formalType,&indexer]( ArgPack& result, Expression* expr, Cost cost, 
+							std::vector<ArgPack>& nextResults ) {
+						// attempt to unify actual with parameter
+						TypeEnvironment resultEnv = result.env;
+						AssertionSet resultNeed = result.need, resultHave = result.have;
+						Type* actualType = expr->get_result();
+
+						PRINT(
+							std::cerr << "formal type is ";
+							formalType->print( std::cerr );
+							std::cerr << std::endl << "actual type is ";
+							actualType->print( std::cerr );
+							std::cerr << std::endl;
+						)
+
+						if ( unify( formalType, actualType, resultEnv, resultNeed, resultHave, 
+								result.openVars, indexer ) ) {
+							nextResults.emplace_back( result, expr->clone(), 
+								std::move(resultEnv), std::move(resultNeed), std::move(resultHave),
+								cost );
+						}
+					} );
+			}
+		}
+
+		// reset for next parameter
+		results.swap( nextResults );
+		nextResults.clear();
+		
+		return ! results.empty();
+	}
+
+	template<typename OutputIterator>
+	void AlternativeFinder::makeFunctionAlternatives( const Alternative& func, 
+			FunctionType* funcType, const std::vector< AlternativeFinder >& args, 
+			OutputIterator out ) {
+		OpenVarSet funcOpenVars;
+		AssertionSet funcNeed, funcHave;
+		TypeEnvironment funcEnv;
+		makeUnifiableVars( funcType, funcOpenVars, funcNeed );
+		// add all type variables as open variables now so that those not used in the parameter 
+		// list are still considered open.
+		funcEnv.add( funcType->get_forall() );
+
 		if ( targetType && ! targetType->isVoid() && ! funcType->get_returnVals().empty() ) {
 			// attempt to narrow based on expected target type
-			Type * returnType = funcType->get_returnVals().front()->get_type();
-			if ( ! unify( returnType, targetType, resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
-				// unification failed, don't pursue this alternative
+			Type* returnType = funcType->get_returnVals().front()->get_type();
+			if ( ! unify( returnType, targetType, funcEnv, funcNeed, funcHave, funcOpenVars, 
+					indexer ) ) {
+				// unification failed, don't pursue this function alternative
 				return;
 			}
 		}
 
-		if ( instantiateFunction( funcType->get_parameters(), actualAlt, funcType->get_isVarArgs(), openVars, resultEnv, resultNeed, resultHave, instantiatedActuals ) ) {
+		// iteratively build matches, one parameter at a time
+		std::vector<ArgPack> results{ ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars } };
+		std::vector<ArgPack> nextResults{};
+		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 ) )
+				return;
+		}
+
+		// filter out results that don't use all the arguments, and aren't variadic
+		std::vector<ArgPack> finalResults{};
+		if ( funcType->get_isVarArgs() ) {
+			while ( ! results.empty() ) {
+				// build combinations for all remaining arguments
+				for ( ArgPack& result : results ) {
+					// keep if used all arguments
+					if ( result.nextArg >= args.size() ) {
+						finalResults.emplace_back( std::move(result) );
+						continue;
+					}
+
+					// add each possible next argument
+					for ( const Alternative& actual : args[result.nextArg] ) {
+						nextResults.emplace_back( result, actual.expr, actual.cost );
+					}
+				}
+
+				// reset for next round
+				results.swap( nextResults );
+				nextResults.clear();
+			}
+		} else {
+			// filter out results that don't use all the arguments
+			for ( ArgPack& result : results ) {
+				if ( result.nextArg >= args.size() ) {
+					finalResults.emplace_back( std::move(result) );
+				}
+			}
+		}
+
+		// validate matching combos, add to final result list
+		for ( ArgPack& result : finalResults ) {
 			ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() );
-			Alternative newAlt( appExpr, resultEnv, sumCost( instantiatedActuals ) );
-			makeExprList( instantiatedActuals, appExpr->get_args() );
+			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( resultNeed, std::cerr, 8 );
+				printAssertionSet( result.need, std::cerr, 8 );
 			)
-			inferParameters( resultNeed, resultHave, newAlt, openVars, out );
+			inferParameters( result.need, result.have, newAlt, result.openVars, out );
 		}
 	}
@@ -703,14 +866,12 @@
 		if ( funcFinder.alternatives.empty() ) return;
 
-		std::list< AlternativeFinder > argAlternatives;
-		findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(), back_inserter( argAlternatives ) );
-
-		std::list< AltList > possibilities;
-		combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) );
+		std::vector< AlternativeFinder > argAlternatives;
+		findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(), 
+			back_inserter( argAlternatives ) );
 
 		// take care of possible tuple assignments
 		// if not tuple assignment, assignment is taken care of as a normal function call
-		Tuples::handleTupleAssignment( *this, untypedExpr, possibilities );
-
+/*FIX	Tuples::handleTupleAssignment( *this, untypedExpr, possibilities );
+*/
 		// find function operators
 		AlternativeFinder funcOpFinder( indexer, env );
@@ -739,9 +900,6 @@
 						Alternative newFunc( *func );
 						referenceToRvalueConversion( newFunc.expr );
-						for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) {
-							// XXX
-							//Designators::check_alternative( function, *actualAlt );
-							makeFunctionAlternatives( newFunc, function, *actualAlt, std::back_inserter( candidates ) );
-						}
+						makeFunctionAlternatives( newFunc, function, argAlternatives, 
+							std::back_inserter( candidates ) );
 					}
 				} else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->get_result()->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)
@@ -751,31 +909,38 @@
 							Alternative newFunc( *func );
 							referenceToRvalueConversion( newFunc.expr );
-							for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) {
-								makeFunctionAlternatives( newFunc, function, *actualAlt, std::back_inserter( candidates ) );
-							} // for
+							makeFunctionAlternatives( newFunc, function, argAlternatives, 
+								std::back_inserter( candidates ) );
 						} // if
 					} // if
-				}
-
-				// try each function operator ?() with the current function alternative and each of the argument combinations
-				for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin(); funcOp != funcOpFinder.alternatives.end(); ++funcOp ) {
-					// check if the type is pointer to function
-					if ( PointerType *pointer = dynamic_cast< PointerType* >( funcOp->expr->get_result()->stripReferences() ) ) {
-						if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
+				}			
+			} catch ( SemanticError &e ) {
+				errors.append( e );
+			}
+		} // for
+
+		// 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) );
+
+			for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin();
+					funcOp != funcOpFinder.alternatives.end(); ++funcOp ) {
+				try {
+					// check if type is a pointer to function
+					if ( PointerType* pointer = dynamic_cast<PointerType*>( 
+							funcOp->expr->get_result()->stripReferences() ) ) {
+						if ( FunctionType* function = 
+								dynamic_cast<FunctionType*>( pointer->get_base() ) ) {
 							Alternative newFunc( *funcOp );
 							referenceToRvalueConversion( newFunc.expr );
-							for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) {
-								AltList currentAlt;
-								currentAlt.push_back( *func );
-								currentAlt.insert( currentAlt.end(), actualAlt->begin(), actualAlt->end() );
-								makeFunctionAlternatives( newFunc, function, currentAlt, std::back_inserter( candidates ) );
-							} // for
-						} // if
-					} // if
-				} // for
-			} catch ( SemanticError &e ) {
-				errors.append( e );
-			}
-		} // for
+							makeFunctionAlternatives( newFunc, function, argAlternatives, 
+								std::back_inserter( candidates ) );
+						}
+					}
+				} catch ( SemanticError &e ) {
+					errors.append( e );
+				}
+			}
+		}
 
 		// Implement SFINAE; resolution errors are only errors if there aren't any non-erroneous resolutions
Index: src/ResolvExpr/AlternativeFinder.h
===================================================================
--- src/ResolvExpr/AlternativeFinder.h	(revision 9bae71f54a1540038ca18b7232347ac138cf2c78)
+++ src/ResolvExpr/AlternativeFinder.h	(revision aeb75b17b518f4bb9ecd6a4cd511e2a899c417af)
@@ -34,4 +34,31 @@
 	  public:
 		AlternativeFinder( const SymTab::Indexer &indexer, const TypeEnvironment &env );
+
+		AlternativeFinder( const AlternativeFinder& o )
+			: 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), 
+			  targetType(o.targetType) {}
+		
+		AlternativeFinder& operator= ( const AlternativeFinder& o ) {
+			if (&o == this) return *this;
+			
+			// horrific nasty hack to rebind references...
+			alternatives.~AltList();
+			new(this) AlternativeFinder(o);
+			return *this;
+		}
+
+		AlternativeFinder& operator= ( AlternativeFinder&& o ) {
+			if (&o == this) return *this;
+			
+			// horrific nasty hack to rebind references...
+			alternatives.~AltList();
+			new(this) AlternativeFinder(std::move(o));
+			return *this;
+		}
+
 		void find( Expression *expr, bool adjust = false, bool prune = true );
 		/// Calls find with the adjust flag set; adjustment turns array and function types into equivalent pointer types
@@ -94,7 +121,9 @@
 		/// 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 );
-		bool instantiateFunction( std::list< DeclarationWithType* >& formals, const AltList &actuals, bool isVarArgs, OpenVarSet& openVars, TypeEnvironment &resultEnv, AssertionSet &resultNeed, AssertionSet &resultHave, AltList & out );
+/*CUT	bool instantiateFunction( std::list< DeclarationWithType* >& formals, const AltList &actuals, bool isVarArgs, OpenVarSet& openVars, TypeEnvironment &resultEnv, AssertionSet &resultNeed, AssertionSet &resultHave, AltList & out );
 		template< typename OutputIterator >
 		void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const AltList &actualAlt, OutputIterator out );
+*/		template<typename OutputIterator>
+		void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const std::vector< AlternativeFinder >& args, OutputIterator out );
 		template< typename OutputIterator >
 		void inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out );
