Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision 8f7cea185385710ca47eaacdb8bc3a59fb752db5)
+++ 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 );
+		}
 	}
 
Index: src/Tuples/TupleAssignment.h
===================================================================
--- src/Tuples/TupleAssignment.h	(revision 8f7cea185385710ca47eaacdb8bc3a59fb752db5)
+++ 	(revision )
@@ -1,37 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// TupleAssignment.h --
-//
-// Author           : Rodolfo G. Esteves
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon May 18 15:04:02 2015
-// Update Count     : 2
-//
-
-#ifndef _TUPLE_ASSIGNMENT_H_
-#define _TUPLE_ASSIGNMENT_H_
-
-#include <string>
-#include <vector>
-#include "ResolvExpr/AlternativeFinder.h"
-
-#include "SynTree/Expression.h"
-#include "SynTree/Declaration.h"
-#include "SynTree/Type.h"
-
-namespace Tuples {
-	void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, std::list<ResolvExpr::AltList> & possibilities );
-} // namespace Tuples
-
-#endif // _TUPLE_ASSIGNMENT_H_
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision 6eb89484ef2c58941d8905aad3ee756b10460cf9)
+++ src/Tuples/TupleExpansion.cc	(revision 6eb89484ef2c58941d8905aad3ee756b10460cf9)
@@ -0,0 +1,56 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// TupleAssignment.cc --
+//
+// Author           : Rodolfo G. Esteves
+// Created On       : Mon May 18 07:44:20 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Mon May 18 15:02:53 2015
+// Update Count     : 2
+//
+
+#include <iterator>
+#include <iostream>
+#include <cassert>
+#include "Tuples.h"
+#include "GenPoly/PolyMutator.h"
+#include "SynTree/Statement.h"
+
+namespace Tuples {
+	class TupleAssignExpander : public GenPoly::PolyMutator {
+	public:
+		virtual Expression * mutate( TupleAssignExpr * tupleExpr );
+	};
+
+	void expandTuples( std::list< Declaration * > & translationUnit ) {
+		TupleAssignExpander expander;
+		mutateAll( translationUnit, expander );
+	}
+
+	Expression * TupleAssignExpander::mutate( TupleAssignExpr * tupleExpr ) {
+		CompoundStmt * compoundStmt = new CompoundStmt( noLabels );
+		std::list< Statement * > & stmts = compoundStmt->get_kids();
+		for ( ObjectDecl * obj : tupleExpr->get_tempDecls() ) {
+			stmts.push_back( new DeclStmt( noLabels, obj ) );
+		}
+		for ( Expression * assign : tupleExpr->get_assigns() ) {
+			stmts.push_back( new ExprStmt( noLabels, assign ) );
+		}
+		tupleExpr->get_tempDecls().clear();
+		tupleExpr->get_assigns().clear();
+		delete tupleExpr;
+		return new StmtExpr( compoundStmt );
+	}
+
+} // namespace Tuples
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
+
Index: src/Tuples/Tuples.h
===================================================================
--- src/Tuples/Tuples.h	(revision 6eb89484ef2c58941d8905aad3ee756b10460cf9)
+++ src/Tuples/Tuples.h	(revision 6eb89484ef2c58941d8905aad3ee756b10460cf9)
@@ -0,0 +1,41 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Tuples.h --
+//
+// Author           : Rodolfo G. Esteves
+// Created On       : Mon May 18 07:44:20 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Mon May 18 15:04:02 2015
+// Update Count     : 2
+//
+
+#ifndef _TUPLES_H_
+#define _TUPLE_H_
+
+#include <string>
+#include <vector>
+#include "ResolvExpr/AlternativeFinder.h"
+
+#include "SynTree/Expression.h"
+#include "SynTree/Declaration.h"
+#include "SynTree/Type.h"
+
+namespace Tuples {
+	// TupleAssignment.cc
+	void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, std::list<ResolvExpr::AltList> & possibilities );
+
+	// TupleExpansion.cc
+	void expandTuples( std::list< Declaration * > & translationUnit );
+} // namespace Tuples
+
+#endif // _TUPLE_ASSIGNMENT_H_
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Tuples/module.mk
===================================================================
--- src/Tuples/module.mk	(revision 8f7cea185385710ca47eaacdb8bc3a59fb752db5)
+++ src/Tuples/module.mk	(revision 6eb89484ef2c58941d8905aad3ee756b10460cf9)
@@ -15,3 +15,4 @@
 ###############################################################################
 
-SRC += 	Tuples/TupleAssignment.cc
+SRC += 	Tuples/TupleAssignment.cc \
+	Tuples/TupleExpansion.cc
