Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision 908cc8363706be83b8dd16ee55ff542200c85e4e)
+++ src/Tuples/TupleAssignment.cc	(revision 6eb89484ef2c58941d8905aad3ee756b10460cf9)
@@ -18,5 +18,6 @@
 #include "ResolvExpr/typeops.h"
 #include "SynTree/Expression.h"
-#include "TupleAssignment.h"
+#include "SynTree/Initializer.h"
+#include "Tuples.h"
 #include "Common/SemanticError.h"
 
@@ -40,5 +41,4 @@
 		// records for assignment generation
 		struct Options {
-			std::list< ResolvExpr::AltList > get_best();
 			void print( std::ostream & );
 			int size() const { return options.size(); }
@@ -51,17 +51,15 @@
 		};
 
-		class Matcher {
+		struct Matcher {
 		  public:
 			Matcher( TupleAssignSpotter &spotter, Expression *_lhs, Expression *_rhs );
 			virtual ~Matcher() {}
 			virtual void match( std::list< Expression * > &out ) = 0;
-			virtual void solve() = 0;
-			static UntypedExpr *createAssgn( Expression *left, Expression *right );
-		  protected:
 			std::list< Expression * > lhs, rhs;
 			TupleAssignSpotter &spotter;
-		};
-
-		class MassAssignMatcher : public Matcher {
+			std::list< ObjectDecl * > tmpDecls;
+		};
+
+		struct MassAssignMatcher : public Matcher {
 		  public:
 			MassAssignMatcher( TupleAssignSpotter &spotter, Expression *lhs, Expression *rhs ) : Matcher( spotter, lhs, rhs ) {
@@ -69,16 +67,14 @@
 			}
 			virtual void match( std::list< Expression * > &out );
-			virtual void solve();
-		};
-
-		class MultipleAssignMatcher : public Matcher {
+		};
+
+		struct MultipleAssignMatcher : public Matcher {
 		  public:
 			MultipleAssignMatcher( TupleAssignSpotter &spot, Expression *lhs, Expression *rhs );
 			virtual void match( std::list< Expression * > &out );
-			virtual void solve();
 		};
 
 		ResolvExpr::AlternativeFinder &currentFinder;
-		Expression *rhs, *lhs;
+		// Expression *rhs, *lhs;
 		Matcher *matcher = nullptr;
 		Options options;
@@ -149,5 +145,4 @@
 
 		if ( new_assigns.empty() ) return;
-		std::list< Expression * > solved_assigns;
 		ResolvExpr::AltList current;
 		// now resolve new assignments
@@ -161,7 +156,15 @@
 			current.push_back( alts.front() );
 		}
-		options.options.push_back( current );
-
-		matcher->solve();
+
+		// extract expressions from the assignment alternatives to produce a list of assignments that
+		// together form a single alternative
+		std::list< Expression *> solved_assigns;
+		for ( ResolvExpr::Alternative & alt : current ) {
+			solved_assigns.push_back( alt.expr->clone() );
+		}
+		// xxx - need to do this??
+		// TypeEnvironment compositeEnv;
+		// simpleCombineEnvironments( i->begin(), i->end(), compositeEnv );
+		currentFinder.get_alternatives().push_front( ResolvExpr::Alternative(new TupleAssignExpr(solved_assigns, matcher->tmpDecls), currentFinder.get_environ(), ResolvExpr::sumCost( current ) ) );
 	}
 
@@ -179,70 +182,56 @@
 	}
 
-	UntypedExpr *TupleAssignSpotter::Matcher::createAssgn( Expression *left, Expression *right ) {
+	UntypedExpr * createAssgn( ObjectDecl *left, ObjectDecl *right ) {
 		assert( left && right );
 		std::list< Expression * > args;
-		args.push_back( new AddressExpr( left->clone() ) );
-		args.push_back( right->clone() );
+		args.push_back( new AddressExpr( new UntypedExpr( new NameExpr("*?"), std::list< Expression * >{ new VariableExpr( left ) } ) ) );
+		args.push_back( new VariableExpr( right ) );
 		return new UntypedExpr( new NameExpr( "?=?" ), args );
 	}
 
+	ObjectDecl * newObject( UniqueName & namer, Expression * expr ) {
+		Type * type;
+		assert( expr->get_results().size() >= 1 );
+		if ( expr->get_results().size() > 1 ) {
+			TupleType * tt = new TupleType( Type::Qualifiers() );
+			cloneAll( expr->get_results(), tt->get_types() );
+			type = tt;
+		} else {
+			type = expr->get_results().front()->clone();
+		}
+		return new ObjectDecl( namer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, type, new SingleInit( expr->clone() ) );
+	}
+
 	void TupleAssignSpotter::MassAssignMatcher::match( std::list< Expression * > &out ) {
+		static UniqueName lhsNamer( "__massassign_L" );
+		static UniqueName rhsNamer( "__massassign_R" );
 		assert ( ! lhs.empty() && rhs.size() == 1);
 
+		ObjectDecl * rtmp = newObject( rhsNamer, rhs.front() );
 		for ( Expression * l : lhs ) {
-			out.push_back( createAssgn( l, rhs.front() ) );
-		}
-	}
-
-	void TupleAssignSpotter::MassAssignMatcher::solve() {
-		assert( ! spotter.options.empty() );
-		for ( std::list< ResolvExpr::AltList >::iterator i = spotter.options.begin(); i != spotter.options.end(); ++i ) {
-			// extract expressions from the alternatives to produce a list of assignments that
-			// together form a single alternative
-			std::list< Expression *> solved_assigns;
-			for ( ResolvExpr::Alternative & alt : *i ) {
-				solved_assigns.push_back( alt.expr );
-			}
-			spotter.currentFinder.get_alternatives().push_front( ResolvExpr::Alternative(new SolvedTupleExpr(solved_assigns), spotter.currentFinder.get_environ(), ResolvExpr::sumCost( *i ) ) );
-		}
+			ObjectDecl * ltmp = newObject( lhsNamer, new AddressExpr( l ) );
+			out.push_back( createAssgn( ltmp, rtmp ) );
+			tmpDecls.push_back( ltmp );
+		}
+		tmpDecls.push_back( rtmp );
 	}
 
 	void TupleAssignSpotter::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
+		static UniqueName lhsNamer( "__multassign_L" );
+		static UniqueName rhsNamer( "__multassign_R" );
 		// xxx - need more complicated matching?
 		if ( lhs.size() == rhs.size() ) {
-			zipWith( lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), back_inserter(out), TupleAssignSpotter::Matcher::createAssgn );
-		}
-	}
-
-	void TupleAssignSpotter::MultipleAssignMatcher::solve() {
-		// options.print( std::cerr );
-		std::list< ResolvExpr::AltList > best = spotter.options.get_best();
-		if ( best.size() == 1 ) {
-			std::list<Expression *> solved_assigns;
-			for ( ResolvExpr::AltList::iterator i = best.front().begin(); i != best.front().end(); ++i ) {
-				solved_assigns.push_back( i->expr );
-			}
-			/* assigning cost zero? */
-			spotter.currentFinder.get_alternatives().push_front( ResolvExpr::Alternative(new SolvedTupleExpr(solved_assigns), spotter.currentFinder.get_environ(), ResolvExpr::Cost() ) );
-		}
-	}
-
-	std::list< ResolvExpr::AltList > TupleAssignSpotter::Options::get_best() {
-		std::list< ResolvExpr::AltList > ret;
-		std::list< ResolvExpr::AltList > solns;
-		for ( ResolvExpr::AltList & i : options ) {
-			ResolvExpr::AltList current;
-			findMinCost( i.begin(), i.end(), back_inserter(current) );
-			solns.push_back( ResolvExpr::AltList(current.begin(), current.end()) );
-		}
-		// need to combine -- previously "lift_intersection", which
-		// did some madness involving, effectively, the intersection of
-		// a bunch of AltLists
-		std::list<ResolvExpr::AltList> result = solns;
-		if ( result.size() != 1 ) {
-			throw SemanticError("Ambiguous tuple expression");
-		}
-		ret.push_back( *result.begin() );
-		return ret;
+			std::list< ObjectDecl * > ltmp;
+			std::list< ObjectDecl * > rtmp;
+			std::transform( lhs.begin(), lhs.end(), back_inserter( ltmp ), []( Expression * expr ){
+				return newObject( lhsNamer, new AddressExpr( expr ) );
+			});
+			std::transform( rhs.begin(), rhs.end(), back_inserter( rtmp ), []( Expression * expr ){
+				return newObject( rhsNamer, expr );
+			});
+			zipWith( ltmp.begin(), ltmp.end(), rtmp.begin(), rtmp.end(), back_inserter(out), createAssgn );
+			tmpDecls.splice( tmpDecls.end(), ltmp );
+			tmpDecls.splice( tmpDecls.end(), rtmp );
+		}
 	}
 
