Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision fc638d2176b72a88b406e73af7f7f9e548ae05f7)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision 793335167c5347f27e76d8ab9f3434b795a6602d)
@@ -185,5 +185,5 @@
 			if ( alternatives.begin() == oldBegin ) {
 				std::ostringstream stream;
-				stream << "Can't choose between alternatives for expression ";
+				stream << "Can't choose between " << alternatives.size() << " alternatives for expression ";
 				expr->print( stream );
 				stream << "Alternatives are:";
@@ -308,5 +308,5 @@
 					(*actualType)->print( std::cerr, 8 );
 					std::cerr << std::endl << " to ";
-					(*formal)->get_type()->print( std::cerr, 8 );
+					(*formalType)->print( std::cerr, 8 );
 				)
 				Cost newCost = conversionCost( *actualType, *formalType, indexer, alt.env );
@@ -511,6 +511,8 @@
 		if ( ! cur->second ) {
 			inferRecursive( begin, end, newAlt, openVars, decls, newNeed, /*needParents,*/ level, indexer, out );
+			return; // xxx - should this continue? previously this wasn't here, and it looks like it should be
 		}
 		DeclarationWithType *curDecl = cur->first;
+
 		PRINT(
 			std::cerr << "inferRecursive: assertion is ";
@@ -649,5 +651,4 @@
 		AltList candidates;
 		SemanticError errors;
-
 		for ( AltList::const_iterator func = funcFinder.alternatives.begin(); func != funcFinder.alternatives.end(); ++func ) {
 			try {
@@ -758,4 +759,5 @@
 	void AlternativeFinder::visit( CastExpr *castExpr ) {
 		Type *& toType = castExpr->get_result();
+		assert( toType );
 		toType = resolveTypeof( toType, indexer );
 		SymTab::validateType( toType, &indexer );
@@ -763,4 +765,5 @@
 
 		AlternativeFinder finder( indexer, env );
+		finder.targetType = toType;
 		finder.findWithAdjustment( castExpr->get_arg() );
 
@@ -776,5 +779,6 @@
 			int discardedValues = (*i).expr->get_result()->size() - castExpr->get_result()->size();
 			if ( discardedValues < 0 ) continue;
-			// xxx - may need to go into tuple types and extract relavent types and use unifyList
+			// 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 );
@@ -783,7 +787,29 @@
 				// count one safe conversion for each value that is thrown away
 				thisCost += Cost( 0, 0, discardedValues );
-				CastExpr *newExpr = castExpr->clone();
-				newExpr->set_arg( i->expr->clone() );
-				candidates.push_back( Alternative( newExpr, i->env, i->cost, thisCost ) );
+
+				Expression * argExpr = i->expr->clone();
+				if ( argExpr->get_result()->size() > 1 && ! castExpr->get_result()->isVoid() ) {
+					// Argument expression is a tuple and the target type is not void. Cast each member of the tuple
+					// to its corresponding target type, producing the tuple of those cast expressions. If there are
+					// more components of the tuple than components in the target type, then excess components do not
+					// come out in the result expression (but UniqueExprs ensure that side effects will still be done).
+					if ( Tuples::maybeImpure( argExpr ) && ! dynamic_cast< UniqueExpr * >( argExpr ) ) {
+						// expressions which may contain side effects require a single unique instance of the expression.
+						argExpr = new UniqueExpr( argExpr );
+					}
+					std::list< Expression * > componentExprs;
+					for ( unsigned int i = 0; i < castExpr->get_result()->size(); i++ ) {
+						// cast each component
+						TupleIndexExpr * idx = new TupleIndexExpr( argExpr->clone(), i );
+						componentExprs.push_back( new CastExpr( idx, castExpr->get_result()->getComponent( i )->clone() ) );
+					}
+					delete argExpr;
+					assert( componentExprs.size() > 0 );
+					// produce the tuple of casts
+					candidates.push_back( Alternative( new TupleExpr( componentExprs ), i->env, i->cost, thisCost ) );
+				} else {
+					// handle normally
+					candidates.push_back( Alternative( new CastExpr( argExpr->clone(), toType->clone() ), i->env, i->cost, thisCost ) );
+				}
 			} // if
 		} // for
Index: src/ResolvExpr/AlternativeFinder.h
===================================================================
--- src/ResolvExpr/AlternativeFinder.h	(revision fc638d2176b72a88b406e73af7f7f9e548ae05f7)
+++ src/ResolvExpr/AlternativeFinder.h	(revision 793335167c5347f27e76d8ab9f3434b795a6602d)
@@ -91,4 +91,5 @@
 		AltList alternatives;
 		const TypeEnvironment &env;
+		Type * targetType = nullptr;
 	}; // AlternativeFinder
 
