Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision b6fe7e6c491f467e31d7ef488c6c0c23df6534a8)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision add7117c7fabc334eeb5508d12db94492b7fcdbc)
@@ -174,4 +174,16 @@
 			}
 		}
+
+		// flatten tuple type into list of types
+		template< typename OutputIterator >
+		void flatten( Type * type, OutputIterator out ) {
+			if ( TupleType * tupleType = dynamic_cast< TupleType * >( type ) ) {
+				for ( Type * t : *tupleType ) {
+					flatten( t, out );
+				}
+			} else {
+				*out++ = type;
+			}
+		}
 	}
 
@@ -241,5 +253,7 @@
 
 	template< typename StructOrUnionType >
-	void AlternativeFinder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string &name ) {
+	void AlternativeFinder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
+		NameExpr * nameExpr = safe_dynamic_cast< NameExpr * >( member );
+		const std::string & name = nameExpr->get_name();
 		std::list< Declaration* > members;
 		aggInst->lookup( name, members );
@@ -270,5 +284,10 @@
 		std::list< DeclarationWithType* >::iterator formal = formals.begin();
 		std::list< Expression* >& actuals = appExpr->get_args();
+
+		std::list< Type * > formalTypes;
+		std::list< Type * >::iterator formalType = formalTypes.end();
+
 		for ( std::list< Expression* >::iterator actualExpr = actuals.begin(); actualExpr != actuals.end(); ++actualExpr ) {
+
 			PRINT(
 				std::cerr << "actual expression:" << std::endl;
@@ -279,20 +298,33 @@
 			std::list< DeclarationWithType* >::iterator startFormal = formal;
 			Cost actualCost;
-			for ( std::list< Type* >::iterator actual = (*actualExpr)->get_results().begin(); actual != (*actualExpr)->get_results().end(); ++actual ) {
-				if ( formal == formals.end() ) {
-					if ( function->get_isVarArgs() ) {
-						convCost += Cost( 1, 0, 0 );
-						break;
-					} else {
-						return Cost::infinity;
+			for ( std::list< Type* >::iterator actualType = (*actualExpr)->get_results().begin(); actualType != (*actualExpr)->get_results().end(); ++actualType ) {
+
+				// tuple handling code
+				if ( formalType == formalTypes.end() ) {
+					// the type of the formal parameter may be a tuple type. To make this easier to work with,
+					// flatten the tuple type and traverse the resulting list of types, incrementing the formal
+					// iterator once its types have been extracted. Once a particular formal parameter's type has
+					// been exhausted load the next formal parameter's type.
+					if ( formal == formals.end() ) {
+						if ( function->get_isVarArgs() ) {
+							convCost += Cost( 1, 0, 0 );
+							break;
+						} else {
+							return Cost::infinity;
+						}
 					}
+					formalTypes.clear();
+					flatten( (*formal)->get_type(), back_inserter( formalTypes ) );
+					formalType = formalTypes.begin();
+					++formal;
 				}
+
 				PRINT(
 					std::cerr << std::endl << "converting ";
-					(*actual)->print( std::cerr, 8 );
+					(*actualType)->print( std::cerr, 8 );
 					std::cerr << std::endl << " to ";
 					(*formal)->get_type()->print( std::cerr, 8 );
 				)
-				Cost newCost = conversionCost( *actual, (*formal)->get_type(), indexer, alt.env );
+				Cost newCost = conversionCost( *actualType, *formalType, indexer, alt.env );
 				PRINT(
 					std::cerr << std::endl << "cost is" << newCost << std::endl;
@@ -305,7 +337,7 @@
 				actualCost += newCost;
 
-				convCost += Cost( 0, polyCost( (*formal)->get_type(), alt.env, indexer ) + polyCost( *actual, alt.env, indexer ), 0 );
-
-				formal++;
+				convCost += Cost( 0, polyCost( *formalType, alt.env, indexer ) + polyCost( *actualType, alt.env, indexer ), 0 );
+
+				formalType++;
 			}
 			if ( actualCost != Cost( 0, 0, 0 ) ) {
@@ -382,8 +414,23 @@
 		*/
 		std::list< DeclarationWithType* >::iterator formal = formals.begin();
+
+		std::list< Type * > formalTypes;
+		std::list< Type * >::iterator formalType = formalTypes.end();
+
 		for ( AltList::const_iterator actualExpr = actuals.begin(); actualExpr != actuals.end(); ++actualExpr ) {
-			for ( std::list< Type* >::iterator actual = actualExpr->expr->get_results().begin(); actual != actualExpr->expr->get_results().end(); ++actual ) {
-				if ( formal == formals.end() ) {
-					return isVarArgs;
+			std::list< Type* > & actualTypes = actualExpr->expr->get_results();
+			for ( std::list< Type* >::iterator actualType = actualTypes.begin(); actualType != actualTypes.end(); ++actualType ) {
+				if ( formalType == formalTypes.end() ) {
+					// the type of the formal parameter may be a tuple type. To make this easier to work with,
+					// flatten the tuple type and traverse the resulting list of types, incrementing the formal
+					// iterator once its types have been extracted. Once a particular formal parameter's type has
+					// been exhausted load the next formal parameter's type.
+					if ( formal == formals.end() ) {
+						return isVarArgs;
+					}
+					formalTypes.clear();
+					flatten( (*formal)->get_type(), back_inserter( formalTypes ) );
+					formalType = formalTypes.begin();
+					++formal;
 				}
 				PRINT(
@@ -391,13 +438,18 @@
 					(*formal)->get_type()->print( std::cerr );
 					std::cerr << std::endl << "actual type is ";
-					(*actual)->print( std::cerr );
+					(*actualType)->print( std::cerr );
 					std::cerr << std::endl;
 				)
-				if ( ! unify( (*formal)->get_type(), *actual, resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
+				if ( ! unify( *formalType, *actualType, resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
 					return false;
 				}
-				formal++;
-			}
-		}
+				++formalType;
+			}
+		}
+
+		// xxx - a tuple type was not completely matched
+		// partially handle the tuple with default arguments??
+		if ( formalType != formalTypes.end() ) return false;
+
 		// Handling of default values
 		while ( formal != formals.end() ) {
@@ -791,7 +843,9 @@
 			renameTypes( alternatives.back().expr );
 			if ( StructInstType *structInst = dynamic_cast< StructInstType* >( (*i)->get_type() ) ) {
-				addAggMembers( structInst, &newExpr, Cost( 0, 0, 1 ), env, "" );
+				NameExpr nameExpr( "" );
+				addAggMembers( structInst, &newExpr, Cost( 0, 0, 1 ), env, &nameExpr );
 			} else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( (*i)->get_type() ) ) {
-				addAggMembers( unionInst, &newExpr, Cost( 0, 0, 1 ), env, "" );
+				NameExpr nameExpr( "" );
+				addAggMembers( unionInst, &newExpr, Cost( 0, 0, 1 ), env, &nameExpr );
 			} // if
 		} // for
Index: src/ResolvExpr/AlternativeFinder.h
===================================================================
--- src/ResolvExpr/AlternativeFinder.h	(revision b6fe7e6c491f467e31d7ef488c6c0c23df6534a8)
+++ src/ResolvExpr/AlternativeFinder.h	(revision add7117c7fabc334eeb5508d12db94492b7fcdbc)
@@ -68,4 +68,6 @@
 		virtual void visit( ConstructorExpr * ctorExpr );
 	  public:  // xxx - temporary hack - should make Tuples::TupleAssignment a friend
+	  /// Runs a new alternative finder on each element in [begin, end)
+	  /// and writes each alternative finder to out.
 		template< typename InputIterator, typename OutputIterator >
 		void findSubExprs( InputIterator begin, InputIterator end, OutputIterator out );
@@ -73,5 +75,5 @@
 	  private:
 		/// Adds alternatives for member expressions, given the aggregate, conversion cost for that aggregate, and name of the member
-		template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string &name );
+		template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member );
 		/// 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 );
