Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision fae6f21adb40b4f21213c00786146d211814c241)
+++ src/Tuples/TupleAssignment.cc	(revision 783152722192169260028e02eebed9a9a0c374a7)
@@ -20,4 +20,5 @@
 #include <memory>                          // for unique_ptr, allocator_trai...
 #include <string>                          // for string
+#include <vector>
 
 #include "CodeGen/OperatorTable.h"
@@ -60,5 +61,6 @@
 		struct Matcher {
 		  public:
-			Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts );
+			Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs, const 
+				ResolvExpr::AltList& rhs );
 			virtual ~Matcher() {}
 			virtual void match( std::list< Expression * > &out ) = 0;
@@ -73,5 +75,6 @@
 		struct MassAssignMatcher : public Matcher {
 		  public:
-			MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts );
+			MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs, 
+				const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
 			virtual void match( std::list< Expression * > &out );
 		};
@@ -79,5 +82,6 @@
 		struct MultipleAssignMatcher : public Matcher {
 		  public:
-			MultipleAssignMatcher( TupleAssignSpotter &spot, const ResolvExpr::AltList & alts );
+			MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs, 
+				const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
 			virtual void match( std::list< Expression * > &out );
 		};
@@ -91,5 +95,5 @@
 	bool isTuple( Expression *expr ) {
 		if ( ! expr ) return false;
-		assert( expr->result );
+		assert( expr->has_result() );
 		return dynamic_cast< TupleType * >( expr->get_result()->stripReferences() );
 	}
@@ -116,7 +120,7 @@
 
 	void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr, 
-		std::vector<ResolvExpr::AlternativeFinder> &args ) {
-	TupleAssignSpotter spotter( currentFinder );
-	spotter.spot( expr, args );
+				std::vector<ResolvExpr::AlternativeFinder> &args ) {
+		TupleAssignSpotter spotter( currentFinder );
+		spotter.spot( expr, args );
 	}
 
@@ -124,35 +128,79 @@
 		: currentFinder(f) {}
 
-	void TupleAssignSpotter::spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args ) {
-		std::list<ResolvExpr::AltList> possibilities;
-		combos( args.begin(), args.end(), back_inserter( possibilities ) );
-
+	void TupleAssignSpotter::spot( UntypedExpr * expr, 
+			std::vector<ResolvExpr::AlternativeFinder> &args ) {
 		if (  NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {
 			if ( CodeGen::isCtorDtorAssign( op->get_name() ) ) {
-                               fname = op->get_name();
-				PRINT( std::cerr << "TupleAssignment: " << fname << std::endl; )
-				for ( std::list<ResolvExpr::AltList>::const_iterator ali = possibilities.begin(); ali != possibilities.end(); ++ali ) {
-					if ( ali->size() == 0 ) continue; // AlternativeFinder will natrually handle this case, if it's legal
-					if ( ali->size() <= 1 && CodeGen::isAssignment( op->get_name() ) ) {
-						// what does it mean if an assignment takes 1 argument? maybe someone defined such a function, in which case AlternativeFinder will naturally handle it
-						continue;
+				fname = op->get_name();
+
+				// AlternativeFinder will naturally handle this case case, if it's legal
+				if ( args.size() == 0 ) return;
+
+				// if an assignment only takes 1 argument, that's odd, but maybe someone wrote 
+				// the function, in which case AlternativeFinder will handle it normally
+				if ( args.size() == 1 && CodeGen::isAssignment( fname ) ) return;
+
+				// look over all possible left-hand-sides
+				for ( ResolvExpr::Alternative& lhsAlt : args[0] ) {
+					// skip non-tuple LHS
+					if ( ! refToTuple(lhsAlt.expr) ) continue;
+
+					// explode is aware of casts - ensure every LHS expression is sent into explode 
+					// with a reference cast
+					// xxx - this seems to change the alternatives before the normal 
+					//  AlternativeFinder flow; maybe this is desired?
+					if ( ! dynamic_cast<CastExpr*>( lhsAlt.expr ) ) {
+						lhsAlt.expr = new CastExpr( lhsAlt.expr, 
+								new ReferenceType( Type::Qualifiers(), 
+									lhsAlt.expr->get_result()->clone() ) );
 					}
 
-					assert( ! ali->empty() );
-					// grab args 2-N and group into a TupleExpr
-					const ResolvExpr::Alternative & alt1 = ali->front();
-					auto begin = std::next(ali->begin(), 1), end = ali->end();
-					PRINT( std::cerr << "alt1 is " << alt1.expr << std::endl; )
-					if ( refToTuple(alt1.expr) ) {
-						PRINT( std::cerr << "and is reference to tuple" << std::endl; )
-						if ( isMultAssign( begin, end ) ) {
-							PRINT( std::cerr << "possible multiple assignment" << std::endl; )
-							matcher.reset( new MultipleAssignMatcher( *this, *ali ) );
-						} else {
-							// mass assignment
-							PRINT( std::cerr << "possible mass assignment" << std::endl; )
-							matcher.reset( new MassAssignMatcher( *this,  *ali ) );
+					// explode the LHS so that each field of a tuple-valued-expr is assigned
+					ResolvExpr::AltList lhs;
+					explode( lhsAlt, currentFinder.get_indexer(), back_inserter(lhs), true );
+					for ( ResolvExpr::Alternative& alt : lhs ) {
+						// each LHS value must be a reference - some come in with a cast expression, 
+						// if not just cast to reference here
+						if ( ! dynamic_cast<ReferenceType*>( alt.expr->get_result() ) ) {
+							alt.expr = new CastExpr( alt.expr, 
+								new ReferenceType( Type::Qualifiers(), 
+									alt.expr->get_result()->clone() ) );
 						}
+					}
+
+					if ( args.size() == 1 ) {
+						// mass default-initialization/destruction
+						ResolvExpr::AltList rhs{};
+						matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );
 						match();
+					} else if ( args.size() > 2 ) {
+						// expand all possible RHS possibilities
+						// TODO build iterative version of this instead of using combos
+						std::vector< ResolvExpr::AltList > rhsAlts;
+						combos( std::next(args.begin(), 1), args.end(), 
+							std::back_inserter( rhsAlts ) );
+						for ( const ResolvExpr::AltList& rhsAlt : rhsAlts ) {
+							// multiple assignment
+							ResolvExpr::AltList rhs;
+							explode( rhsAlt, currentFinder.get_indexer(), 
+								std::back_inserter(rhs), true );
+							matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );
+							match();
+						}
+					} else {
+						for ( const ResolvExpr::Alternative& rhsAlt : args[1] ) {
+							ResolvExpr::AltList rhs;
+							if ( isTuple(rhsAlt.expr) ) {
+								// multiple assignment
+								explode( rhsAlt, currentFinder.get_indexer(),  
+									std::back_inserter(rhs), true );
+								matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );
+							} else {
+								// mass assignment
+								rhs.push_back( rhsAlt );
+								matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );
+							}
+							match();
+						}
 					}
 				}
@@ -174,5 +222,6 @@
 		ResolvExpr::AltList current;
 		// now resolve new assignments
-		for ( std::list< Expression * >::iterator i = new_assigns.begin(); i != new_assigns.end(); ++i ) {
+		for ( std::list< Expression * >::iterator i = new_assigns.begin(); 
+				i != new_assigns.end(); ++i ) {
 			PRINT(
 				std::cerr << "== resolving tuple assign ==" << std::endl;
@@ -180,5 +229,6 @@
 			)
 
-			ResolvExpr::AlternativeFinder finder( currentFinder.get_indexer(), currentFinder.get_environ() );
+			ResolvExpr::AlternativeFinder finder{ currentFinder.get_indexer(), 
+				currentFinder.get_environ() };
 			try {
 				finder.findWithAdjustment(*i);
@@ -201,39 +251,15 @@
 		// combine assignment environments into combined expression environment
 		simpleCombineEnvironments( current.begin(), current.end(), matcher->compositeEnv );
-		currentFinder.get_alternatives().push_front( ResolvExpr::Alternative(new TupleAssignExpr(solved_assigns, matcher->tmpDecls), matcher->compositeEnv, ResolvExpr::sumCost( current  ) + matcher->baseCost ) );
-	}
-
-	TupleAssignSpotter::Matcher::Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList &alts ) : spotter(spotter), baseCost( ResolvExpr::sumCost( alts ) ) {
-		assert( ! alts.empty() );
-		// combine argument environments into combined expression environment
-		simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv );
-
-		ResolvExpr::Alternative lhsAlt = alts.front();
-		// explode is aware of casts - ensure every LHS expression is sent into explode with a reference cast
-		if ( ! dynamic_cast< CastExpr * >( lhsAlt.expr ) ) {
-			lhsAlt.expr = new CastExpr( lhsAlt.expr, new ReferenceType( Type::Qualifiers(), lhsAlt.expr->get_result()->clone() ) );
-		}
-
-		// explode the lhs so that each field of the tuple-valued-expr is assigned.
-		explode( lhsAlt, spotter.currentFinder.get_indexer(), back_inserter(lhs), true );
-
-		for ( ResolvExpr::Alternative & alt : lhs ) {
-			// every LHS value must be a reference - some come in with a cast expression, if it doesn't just cast to reference here.
-			if ( ! dynamic_cast< ReferenceType * >( alt.expr->get_result() ) ) {
-				alt.expr = new CastExpr( alt.expr, new ReferenceType( Type::Qualifiers(), alt.expr->get_result()->clone() ) );
-			}
-		}
-	}
-
-	TupleAssignSpotter::MassAssignMatcher::MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts ) : Matcher( spotter, alts ) {
-		assert( alts.size() == 1 || alts.size() == 2 );
-		if ( alts.size() == 2 ) {
-			rhs.push_back( alts.back() );
-		}
-	}
-
-	TupleAssignSpotter::MultipleAssignMatcher::MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts ) : Matcher( spotter, alts ) {
-		// explode the rhs so that each field of the tuple-valued-expr is assigned.
-		explode( std::next(alts.begin(), 1), alts.end(), spotter.currentFinder.get_indexer(), back_inserter(rhs), true );
+		currentFinder.get_alternatives().push_front( ResolvExpr::Alternative(
+			new TupleAssignExpr(solved_assigns, matcher->tmpDecls), matcher->compositeEnv, 
+			ResolvExpr::sumCost( current ) + matcher->baseCost ) );
+	}
+
+	TupleAssignSpotter::Matcher::Matcher( TupleAssignSpotter &spotter, 
+		const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs ) 
+	: lhs(lhs), rhs(rhs), spotter(spotter), 
+	  baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ) {
+		simpleCombineEnvironments( lhs.begin(), lhs.end(), compositeEnv );
+		simpleCombineEnvironments( rhs.begin(), rhs.end(), compositeEnv );
 	}
 
@@ -259,5 +285,5 @@
 
 	ObjectDecl * TupleAssignSpotter::Matcher::newObject( UniqueName & namer, Expression * expr ) {
-		assert( expr->result && ! expr->get_result()->isVoid() );
+		assert( expr->has_result() && ! expr->get_result()->isVoid() );
 		ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->get_result()->clone(), new SingleInit( expr->clone() ) );
 		// if expression type is a reference, don't need to construct anything, a simple initializer is sufficient.
@@ -269,5 +295,4 @@
 			ctorInit->accept( rm );
 		}
-		PRINT( std::cerr << "new object: " << ret << std::endl; )
 		return ret;
 	}
