Index: src/CodeGen/CodeGenerator.cc
===================================================================
--- src/CodeGen/CodeGenerator.cc	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/CodeGen/CodeGenerator.cc	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -639,5 +639,5 @@
 	}
 
-	void CodeGenerator::visit( TupleExpr * tupleExpr ) {}
+	void CodeGenerator::visit( TupleExpr * tupleExpr ) { assert( false ); }
 
 	void CodeGenerator::visit( TypeExpr * typeExpr ) {}
@@ -655,8 +655,37 @@
 	}
 
+	void CodeGenerator::visit( CompoundLiteralExpr *compLitExpr ) {
+		assert( compLitExpr->get_type() && dynamic_cast< ListInit * > ( compLitExpr->get_initializer() ) );
+		output << "(" << genType( compLitExpr->get_type(), "" ) << ")";
+		compLitExpr->get_initializer()->accept( *this );
+	}
+
 	void CodeGenerator::visit( StmtExpr * stmtExpr ) {
-		output << "(";
-		stmtExpr->get_statements()->accept( *this );
-		output << ")";
+		std::list< Statement * > & stmts = stmtExpr->get_statements()->get_kids();
+		output << "({" << std::endl;
+		cur_indent += CodeGenerator::tabsize;
+		unsigned int numStmts = stmts.size();
+		unsigned int i = 0;
+		for ( Statement * stmt : stmts ) {
+			output << indent << printLabels( stmt->get_labels() );
+			if ( i+1 == numStmts ) {
+				// last statement in a statement expression needs to be handled specially -
+				// cannot cast to void, otherwise the expression statement has no value
+				if ( ExprStmt * exprStmt = dynamic_cast< ExprStmt * >( stmt ) ) {
+					exprStmt->get_expr()->accept( *this );
+					output << ";" << endl;
+					++i;
+					break;
+				}
+			}
+			stmt->accept( *this );
+			output << endl;
+			if ( wantSpacing( stmt ) ) {
+				output << endl;
+			} // if
+			++i;
+		}
+		cur_indent -= CodeGenerator::tabsize;
+		output << indent << "})";
 	}
 
Index: src/CodeGen/CodeGenerator.h
===================================================================
--- src/CodeGen/CodeGenerator.h	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/CodeGen/CodeGenerator.h	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -70,4 +70,5 @@
 		virtual void visit( ConditionalExpr *conditionalExpr );
 		virtual void visit( CommaExpr *commaExpr );
+		virtual void visit( CompoundLiteralExpr *compLitExpr );
 		virtual void visit( TupleExpr *tupleExpr );
 		virtual void visit( TypeExpr *typeExpr );
Index: src/CodeGen/GenType.cc
===================================================================
--- src/CodeGen/GenType.cc	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/CodeGen/GenType.cc	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -213,7 +213,4 @@
 			typeString = "_Atomic " + typeString;
 		} // if
-		if ( type->get_isAttribute() ) {
-			typeString = "__attribute(( )) " + typeString;
-		} // if
 	}
 } // namespace CodeGen
Index: src/Common/utility.h
===================================================================
--- src/Common/utility.h	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/Common/utility.h	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -158,4 +158,5 @@
 }
 
+// replace element of list with all elements of another list
 template< typename T >
 void replace( std::list< T > &org, typename std::list< T >::iterator pos, std::list< T > &with ) {
@@ -168,4 +169,11 @@
 
 	return;
+}
+
+// replace range of a list with a single element
+template< typename T >
+void replace( std::list< T > &org, typename std::list< T >::iterator begin, typename std::list< T >::iterator end, const T & with ) {
+	org.insert( begin, with );
+	org.erase( begin, end );
 }
 
Index: src/ResolvExpr/Alternative.cc
===================================================================
--- src/ResolvExpr/Alternative.cc	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/ResolvExpr/Alternative.cc	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -20,5 +20,5 @@
 
 namespace ResolvExpr {
-	Alternative::Alternative() : expr( 0 ) {}
+	Alternative::Alternative() : cost( Cost::zero ), cvtCost( Cost::zero ), expr( 0 ) {}
 
 	Alternative::Alternative( Expression *expr, const TypeEnvironment &env, const Cost& cost )
Index: src/ResolvExpr/Alternative.h
===================================================================
--- src/ResolvExpr/Alternative.h	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/ResolvExpr/Alternative.h	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Alternative.h -- 
+// Alternative.h --
 //
 // Author           : Richard C. Bilson
@@ -12,5 +12,5 @@
 // Last Modified On : Sat May 16 23:54:39 2015
 // Update Count     : 2
-// 
+//
 
 #ifndef ALTERNATIVE_H
@@ -33,9 +33,9 @@
 		Alternative &operator=( const Alternative &other );
 		~Alternative();
-  
+
 		void initialize( const Alternative &src, Alternative &dest );
-  
+
 		void print( std::ostream &os, int indent = 0 ) const;
-  
+
 		Cost cost;
 		Cost cvtCost;
@@ -43,4 +43,41 @@
 		TypeEnvironment env;
 	};
+
+	/// helper function used by explode
+	template< typename OutputIterator >
+	void explodeUnique( Expression * expr, const Alternative & alt, OutputIterator out ) {
+		Type * res = expr->get_result();
+		if ( TupleType * tupleType = dynamic_cast< TupleType * > ( res ) ) {
+			if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( alt.expr ) ) {
+				for ( Expression * expr : tupleExpr->get_exprs() ) {
+					explodeUnique( expr, alt, out );
+				}
+			} else {
+				UniqueExpr * unq = new UniqueExpr( expr->clone() );
+				for ( unsigned int i = 0; i < tupleType->size(); i++ ) {
+					TupleIndexExpr * idx = new TupleIndexExpr( unq->clone(), i );
+					explodeUnique( idx, alt, out );
+					delete idx;
+				}
+				delete unq;
+			}
+		} else {
+			*out++ = Alternative( expr->clone(), alt.env, alt.cost, alt.cvtCost );
+		}
+	}
+
+	/// expands a tuple-valued alternative into multiple alternatives, each with a non-tuple-type
+	template< typename OutputIterator >
+	void explode( Alternative &alt, OutputIterator out ) {
+		explodeUnique( alt.expr, alt, out );
+	}
+
+	// explode list of alternatives
+	template< typename OutputIterator >
+	void explode( AltList & alts, OutputIterator out ) {
+		for ( Alternative & alt : alts ) {
+			explode( alt, out );
+		}
+	}
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -380,4 +380,7 @@
 
 		std::list< DeclarationWithType* >::iterator formal = formals.begin();
+
+		AltList newActuals;
+		explode( actuals, back_inserter( newActuals ) );
 
 		std::list< Type * > formalTypes;
@@ -994,12 +997,5 @@
 			TupleExpr *newExpr = new TupleExpr;
 			makeExprList( *i, newExpr->get_exprs() );
-			TupleType *tupleType = new TupleType( Type::Qualifiers(true, true, true, true, true, true) );
-			Type::Qualifiers &qualifiers = tupleType->get_qualifiers();
-			for ( Expression * resultExpr : newExpr->get_exprs() ) {
-				Type * type = resultExpr->get_result()->clone();
-				tupleType->get_types().push_back( type );
-				qualifiers &= type->get_qualifiers();
-			} // for
-			newExpr->set_result( tupleType );
+			newExpr->set_result( Tuples::makeTupleType( newExpr->get_exprs() ) );
 
 			TypeEnvironment compositeEnv;
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/SymTab/Validate.cc	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -23,6 +23,6 @@
 // - All enumeration constants have type EnumInstType.
 //
-// - The type "void" never occurs in lists of function parameter or return types; neither do tuple types.  A function
-//   taking no arguments has no argument types, and tuples are flattened.
+// - The type "void" never occurs in lists of function parameter or return types.  A function
+//   taking no arguments has no argument types.
 //
 // - No context instances exist; they are all replaced by the set of declarations signified by the context, instantiated
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/SynTree/Expression.cc	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -522,8 +522,9 @@
 
 CompoundLiteralExpr::CompoundLiteralExpr( Type * type, Initializer * initializer ) : type( type ), initializer( initializer ) {
+	assert( type && initializer );
 	set_result( type->clone() );
 }
 
-CompoundLiteralExpr::CompoundLiteralExpr( const CompoundLiteralExpr &other ) : Expression( other ), type( maybeClone( other.type ) ), initializer( maybeClone( other.initializer ) ) {}
+CompoundLiteralExpr::CompoundLiteralExpr( const CompoundLiteralExpr &other ) : Expression( other ), type( other.type->clone() ), initializer( other.initializer->clone() ) {}
 
 CompoundLiteralExpr::~CompoundLiteralExpr() {
@@ -534,6 +535,8 @@
 void CompoundLiteralExpr::print( std::ostream &os, int indent ) const {
 	os << "Compound Literal Expression: " << std::endl;
-	if ( type ) type->print( os, indent + 2 );
-	if ( initializer ) initializer->print( os, indent + 2 );
+	os << std::string( indent+2, ' ' );
+	type->print( os, indent + 2 );
+	os << std::string( indent+2, ' ' );
+	initializer->print( os, indent + 2 );
 }
 
@@ -549,7 +552,7 @@
 
 RangeExpr::RangeExpr( Expression *low, Expression *high ) : low( low ), high( high ) {}
-RangeExpr::RangeExpr( const RangeExpr &other ) : low( other.low->clone() ), high( other.high->clone() ) {}
+RangeExpr::RangeExpr( const RangeExpr &other ) : Expression( other ), low( other.low->clone() ), high( other.high->clone() ) {}
 void RangeExpr::print( std::ostream &os, int indent ) const {
-	os << std::string( indent, ' ' ) << "Range Expression: ";
+	os << "Range Expression: ";
 	low->print( os, indent );
 	os << " ... ";
@@ -566,11 +569,30 @@
 	}
 }
-StmtExpr::StmtExpr( const StmtExpr &other ) : statements( other.statements->clone() ) {}
+StmtExpr::StmtExpr( const StmtExpr &other ) : Expression( other ), statements( other.statements->clone() ) {}
 StmtExpr::~StmtExpr() {
 	delete statements;
 }
 void StmtExpr::print( std::ostream &os, int indent ) const {
-	os << std::string( indent, ' ' ) << "Statement Expression: " << std::endl;
+	os << "Statement Expression: " << std::endl << std::string( indent, ' ' );
 	statements->print( os, indent+2 );
+}
+
+
+UniqueExpr::UniqueExpr( Expression *expr ) : expr( new Expression* ) {
+	set_expr( expr );
+	assert( expr );
+	assert( expr->has_result() );
+	set_result( expr->get_result()->clone() );
+}
+UniqueExpr::UniqueExpr( const UniqueExpr &other ) : Expression( other ), expr( other.expr ) {
+}
+UniqueExpr::~UniqueExpr() {
+	if ( expr.unique() ) {
+		delete *expr;
+	}
+}
+void UniqueExpr::print( std::ostream &os, int indent ) const {
+	os << "Unique Expression: " << std::endl << std::string( indent+2, ' ' );
+	get_expr()->print( os, indent+2 );
 }
 
Index: src/SynTree/Expression.h
===================================================================
--- src/SynTree/Expression.h	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/SynTree/Expression.h	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -639,5 +639,5 @@
 class TupleExpr : public Expression {
   public:
-	TupleExpr( Expression *_aname = nullptr );
+	TupleExpr( const std::list< Expression * > & exprs = std::list< Expression * >(), Expression *_aname = nullptr );
 	TupleExpr( const TupleExpr &other );
 	virtual ~TupleExpr();
@@ -733,4 +733,21 @@
 };
 
+class UniqueExpr : public Expression {
+public:
+	UniqueExpr( Expression * expr );
+	UniqueExpr( const UniqueExpr & other );
+	~UniqueExpr();
+
+	Expression * get_expr() const { return *expr; }
+	UniqueExpr * set_expr( Expression * newValue ) { *expr = newValue; return this; }
+
+	virtual UniqueExpr *clone() const { return new UniqueExpr( *this ); }
+	virtual void accept( Visitor &v ) { v.visit( this ); }
+	virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
+	virtual void print( std::ostream &os, int indent = 0 ) const;
+private:
+	std::shared_ptr< Expression * > expr;
+};
+
 std::ostream & operator<<( std::ostream & out, const Expression * expr );
 
Index: src/SynTree/Mutator.cc
===================================================================
--- src/SynTree/Mutator.cc	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/SynTree/Mutator.cc	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -384,4 +384,10 @@
 }
 
+Expression *Mutator::mutate( UniqueExpr *uniqueExpr ) {
+	uniqueExpr->set_result( maybeMutate( uniqueExpr->get_result(), *this ) );
+	uniqueExpr->set_expr( maybeMutate( uniqueExpr->get_expr(), *this ) );
+	return uniqueExpr;
+}
+
 Type *Mutator::mutate( VoidType *voidType ) {
 	mutateAll( voidType->get_forall(), *this );
Index: src/SynTree/Mutator.h
===================================================================
--- src/SynTree/Mutator.h	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/SynTree/Mutator.h	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -83,4 +83,5 @@
 	virtual Expression* mutate( TupleAssignExpr *assignExpr );
 	virtual Expression* mutate( StmtExpr * stmtExpr );
+	virtual Expression* mutate( UniqueExpr * uniqueExpr );
 
 	virtual Type* mutate( VoidType *basicType );
Index: src/SynTree/SynTree.h
===================================================================
--- src/SynTree/SynTree.h	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/SynTree/SynTree.h	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -88,4 +88,5 @@
 class TupleAssignExpr;
 class StmtExpr;
+class UniqueExpr;
 
 class Type;
Index: src/SynTree/TupleExpr.cc
===================================================================
--- src/SynTree/TupleExpr.cc	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/SynTree/TupleExpr.cc	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -18,6 +18,12 @@
 #include "Type.h"
 #include "Declaration.h"
+#include "Tuples/Tuples.h"
 
-TupleExpr::TupleExpr( Expression *_aname ) : Expression( _aname ) {
+TupleExpr::TupleExpr( const std::list< Expression * > & exprs, Expression *_aname ) : Expression( _aname ), exprs( exprs ) {
+	if ( ! exprs.empty() ) {
+		if ( std::all_of( exprs.begin(), exprs.end(), [](Expression * expr) { return expr->get_result(); } ) ) {
+			set_result( Tuples::makeTupleType( exprs ) );
+		}
+	}
 }
 
@@ -36,8 +42,8 @@
 }
 
-TupleIndexExpr::TupleIndexExpr( Expression * tuple, unsigned int index ) {
+TupleIndexExpr::TupleIndexExpr( Expression * tuple, unsigned int index ) : tuple( tuple ), index( index )  {
 	TupleType * type = safe_dynamic_cast< TupleType * >( tuple->get_result() );
-	assert( type->size() >= index );
-	set_result( *std::next( type->get_types().begin(), index ) );
+	assert( type->size() > index );
+	set_result( (*std::next( type->get_types().begin(), index ))->clone() );
 }
 
@@ -51,4 +57,5 @@
 void TupleIndexExpr::print( std::ostream &os, int indent ) const {
 	os << "Tuple Index Expression, with tuple:" << std::endl;
+	os << std::string( indent+2, ' ' );
 	tuple->print( os, indent+2 );
 	os << std::string( indent+2, ' ' ) << "with index: " << index << std::endl;
@@ -70,6 +77,8 @@
 void MemberTupleExpr::print( std::ostream &os, int indent ) const {
 	os << "Member Tuple Expression, with aggregate:" << std::endl;
+	os << std::string( indent+2, ' ' );
 	aggregate->print( os, indent+2 );
 	os << std::string( indent+2, ' ' ) << "with member: " << std::endl;
+	os << std::string( indent+2, ' ' );
 	member->print( os, indent+2 );
 	Expression::print( os, indent );
@@ -97,5 +106,5 @@
 
 void TupleAssignExpr::print( std::ostream &os, int indent ) const {
-	os << std::string( indent, ' ' ) << "Tuple Assignment Expression, with temporaries:" << std::endl;
+	os << "Tuple Assignment Expression, with temporaries:" << std::endl;
 	printAll( tempDecls, os, indent+4 );
 	os << std::string( indent+2, ' ' ) << "with assignments: " << std::endl;
Index: src/SynTree/Visitor.cc
===================================================================
--- src/SynTree/Visitor.cc	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/SynTree/Visitor.cc	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -326,4 +326,9 @@
 }
 
+void Visitor::visit( UniqueExpr *uniqueExpr ) {
+	maybeAccept( uniqueExpr->get_result(), *this );
+	maybeAccept( uniqueExpr->get_expr(), *this );
+}
+
 void Visitor::visit( VoidType *voidType ) {
 	acceptAll( voidType->get_forall(), *this );
Index: src/SynTree/Visitor.h
===================================================================
--- src/SynTree/Visitor.h	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/SynTree/Visitor.h	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -83,4 +83,5 @@
 	virtual void visit( TupleAssignExpr *assignExpr );
 	virtual void visit( StmtExpr * stmtExpr );
+	virtual void visit( UniqueExpr * uniqueExpr );
 
 	virtual void visit( VoidType *basicType );
Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/Tuples/TupleAssignment.cc	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -39,22 +39,11 @@
 	  private:
 		void match();
-		// records for assignment generation
-		struct Options {
-			void print( std::ostream & );
-			int size() const { return options.size(); }
-			bool empty() const { return options.empty(); }
-			typedef std::list< ResolvExpr::AltList >::iterator iterator;
-			iterator begin() { return options.begin(); }
-			iterator end() { return options.end(); }
-
-			std::list< ResolvExpr::AltList > options;
-		};
 
 		struct Matcher {
 		  public:
-			Matcher( TupleAssignSpotter &spotter, Expression *_lhs, Expression *_rhs );
+			Matcher( TupleAssignSpotter &spotter, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs );
 			virtual ~Matcher() {}
 			virtual void match( std::list< Expression * > &out ) = 0;
-			std::list< Expression * > lhs, rhs;
+			ResolvExpr::AltList lhs, rhs;
 			TupleAssignSpotter &spotter;
 			std::list< ObjectDecl * > tmpDecls;
@@ -63,7 +52,5 @@
 		struct MassAssignMatcher : public Matcher {
 		  public:
-			MassAssignMatcher( TupleAssignSpotter &spotter, Expression *lhs, Expression *rhs ) : Matcher( spotter, lhs, rhs ) {
-				this->rhs.push_back( rhs );
-			}
+			MassAssignMatcher( TupleAssignSpotter &spotter, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs );
 			virtual void match( std::list< Expression * > &out );
 		};
@@ -71,5 +58,5 @@
 		struct MultipleAssignMatcher : public Matcher {
 		  public:
-			MultipleAssignMatcher( TupleAssignSpotter &spot, Expression *lhs, Expression *rhs );
+			MultipleAssignMatcher( TupleAssignSpotter &spot, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs );
 			virtual void match( std::list< Expression * > &out );
 		};
@@ -78,10 +65,5 @@
 		// Expression *rhs, *lhs;
 		Matcher *matcher = nullptr;
-		Options options;
 	};
-
-	bool isTupleVar( DeclarationWithType *decl ) {
-		return dynamic_cast< TupleType * >( decl->get_type() );
-	}
 
 	/// true if expr is an expression of tuple type, i.e. a tuple expression, tuple variable, or MRV (multiple-return-value) function
@@ -89,5 +71,4 @@
 		if ( ! expr ) return false;
 		assert( expr->has_result() );
-		// xxx - used to include cast to varExpr and call to isTupleVar, but this doesn't seem like it should be necessary
 		return dynamic_cast<TupleExpr *>(expr) || expr->get_result()->size() > 1;
 	}
@@ -101,9 +82,4 @@
 	}
 
-	bool isTupleExpr( Expression *expr ) {
-		assert( expr->has_result() );
-		return expr->get_result()->size() > 1;
-	}
-
 	void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr, std::list<ResolvExpr::AltList> &possibilities ) {
 		TupleAssignSpotter spotter( currentFinder );
@@ -116,13 +92,13 @@
 	void TupleAssignSpotter::spot( UntypedExpr * expr, std::list<ResolvExpr::AltList> &possibilities ) {
 		if (  NameExpr *assgnop = dynamic_cast< NameExpr * >(expr->get_function()) ) {
-			if ( assgnop->get_name() == std::string("?=?") ) {
+			if ( assgnop->get_name() == "?=?" ) {
 				for ( std::list<ResolvExpr::AltList>::iterator ali = possibilities.begin(); ali != possibilities.end(); ++ali ) {
-					assert( ali->size() == 2 );
-					ResolvExpr::Alternative op1 = ali->front(), op2 = ali->back();
-
-					MultipleAssignMatcher multiMatcher( *this, op1.expr, op2.expr );
-					MassAssignMatcher massMatcher( *this, op1.expr, op2.expr );
-					if ( pointsToTuple(op1.expr) ) { // also handles tuple vars
-						if ( isTuple( op2.expr ) ) {
+					if ( ali->size() != 2 ) continue; // what does it mean if an assignment takes >2 arguments? grab args 2-N and group into a TupleExpr, then proceed?
+					ResolvExpr::Alternative & alt1 = ali->front(), & alt2 = ali->back();
+
+					if ( pointsToTuple(alt1.expr) ) {
+						MultipleAssignMatcher multiMatcher( *this, alt1, alt2 );
+						MassAssignMatcher massMatcher( *this,  alt1, alt2 );
+						if ( isTuple( alt2.expr ) ) {
 							matcher = &multiMatcher;
 						} else {
@@ -131,5 +107,5 @@
 						}
 						match();
-					} else if ( isTuple( op2.expr ) ) {
+					} else if ( isTuple( alt2.expr ) ) {
 						throw SemanticError("Cannot assign a tuple value into a non-tuple lvalue.", expr);
 					}
@@ -170,15 +146,22 @@
 	}
 
-	TupleAssignSpotter::Matcher::Matcher( TupleAssignSpotter &spotter, Expression *lhs, Expression *rhs ) : spotter(spotter) {
-		// xxx - shouldn't need to be &<tuple-expr>, just &<lvalue-tuple-type>
-		if (AddressExpr *addr = dynamic_cast<AddressExpr *>(lhs) )
-			if ( TupleExpr *tuple = dynamic_cast<TupleExpr *>(addr->get_arg()) )
-				std::copy( tuple->get_exprs().begin(), tuple->get_exprs().end(), back_inserter(this->lhs) );
-	}
-
-	TupleAssignSpotter::MultipleAssignMatcher::MultipleAssignMatcher( TupleAssignSpotter &spotter, Expression *lhs, Expression *rhs ) : Matcher( spotter, lhs, rhs ) {
-
-		if ( TupleExpr *tuple = dynamic_cast<TupleExpr *>(rhs) )
-			std::copy( tuple->get_exprs().begin(), tuple->get_exprs().end(), back_inserter(this->rhs) );
+	TupleAssignSpotter::Matcher::Matcher( TupleAssignSpotter &spotter, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs ) : spotter(spotter) {
+		if (AddressExpr *addr = dynamic_cast<AddressExpr *>(lhs.expr) ) {
+			// xxx - not every assignment NEEDS to have the first argument as address-taken, e.g. a manual call to assignment. What to do in this case? skip it as a possibility for TupleAssignment, since the type will always be T*, where T can never be a tuple? Is this true?
+
+			// explode the lhs so that each field of the tuple-valued-expr is assigned.
+			ResolvExpr::Alternative lhsAlt( addr->get_arg()->clone(), lhs.env, lhs.cost, lhs.cvtCost );
+			explode( lhsAlt, back_inserter(this->lhs) );
+		}
+	}
+
+	TupleAssignSpotter::MassAssignMatcher::MassAssignMatcher( TupleAssignSpotter &spotter, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs ) : Matcher( spotter, lhs, rhs ) {
+		this->rhs.push_back( rhs );
+	}
+
+	TupleAssignSpotter::MultipleAssignMatcher::MultipleAssignMatcher( TupleAssignSpotter &spotter, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs ) : Matcher( spotter, lhs, rhs ) {
+
+		// explode the rhs so that each field of the tuple-valued-expr is assigned.
+		explode( rhs, back_inserter(this->rhs) );
 	}
 
@@ -201,7 +184,7 @@
 		assert ( ! lhs.empty() && rhs.size() == 1);
 
-		ObjectDecl * rtmp = newObject( rhsNamer, rhs.front() );
-		for ( Expression * l : lhs ) {
-			ObjectDecl * ltmp = newObject( lhsNamer, new AddressExpr( l ) );
+		ObjectDecl * rtmp = newObject( rhsNamer, rhs.front().expr );
+		for ( ResolvExpr::Alternative & lhsAlt : lhs ) {
+			ObjectDecl * ltmp = newObject( lhsNamer, new AddressExpr( lhsAlt.expr ) );
 			out.push_back( createAssgn( ltmp, rtmp ) );
 			tmpDecls.push_back( ltmp );
@@ -217,9 +200,9 @@
 			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( lhs.begin(), lhs.end(), back_inserter( ltmp ), []( ResolvExpr::Alternative & alt ){
+				return newObject( lhsNamer, new AddressExpr( alt.expr ) );
 			});
-			std::transform( rhs.begin(), rhs.end(), back_inserter( rtmp ), []( Expression * expr ){
-				return newObject( rhsNamer, expr );
+			std::transform( rhs.begin(), rhs.end(), back_inserter( rtmp ), []( ResolvExpr::Alternative & alt ){
+				return newObject( rhsNamer, alt.expr );
 			});
 			zipWith( ltmp.begin(), ltmp.end(), rtmp.begin(), rtmp.end(), back_inserter(out), createAssgn );
@@ -227,14 +210,4 @@
 			tmpDecls.splice( tmpDecls.end(), rtmp );
 		}
-	}
-
-	void TupleAssignSpotter::Options::print( std::ostream &ostr ) {
-		for ( ResolvExpr::AltList & l : options ) {
-			for ( ResolvExpr::Alternative & alt : l ) {
-				alt.print( ostr );
-				ostr << " ";
-			}
-			ostr << std::endl;
-		} // for
 	}
 } // namespace Tuples
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/Tuples/TupleExpansion.cc	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -23,49 +23,95 @@
 #include "SynTree/Declaration.h"
 #include "SynTree/Type.h"
+#include "SynTree/Expression.h"
+#include "SynTree/Initializer.h"
 #include "SymTab/Mangler.h"
 #include "Common/ScopedMap.h"
 
 namespace Tuples {
-	class TupleAssignExpander : public Mutator {
-	public:
-		virtual Expression * mutate( TupleAssignExpr * tupleExpr );
-	};
+	namespace {
+		class UniqueExprExpander : public GenPoly::DeclMutator {
+		public:
+			typedef GenPoly::DeclMutator Parent;
+			virtual Expression * mutate( UniqueExpr * unqExpr );
+			std::map< Expression *, ObjectDecl * > decls;
+		};
 
-	class TupleTypeReplacer : public GenPoly::DeclMutator {
-	  public:
-		typedef GenPoly::DeclMutator Parent;
+		class TupleAssignExpander : public Mutator {
+		public:
+			typedef Mutator Parent;
+			virtual Expression * mutate( TupleAssignExpr * tupleExpr );
+		};
 
-		virtual Type * mutate( TupleType * tupleType );
+		class TupleTypeReplacer : public GenPoly::DeclMutator {
+		  public:
+			typedef GenPoly::DeclMutator Parent;
 
-		virtual CompoundStmt * mutate( CompoundStmt * stmt ) {
-			typeMap.beginScope();
-			stmt = Parent::mutate( stmt );
-			typeMap.endScope();
-			return stmt;
-		}
-	  private:
-		ScopedMap< std::string, StructDecl * > typeMap;
-	};
+			virtual Type * mutate( TupleType * tupleType );
+
+			virtual CompoundStmt * mutate( CompoundStmt * stmt ) {
+				typeMap.beginScope();
+				stmt = Parent::mutate( stmt );
+				typeMap.endScope();
+				return stmt;
+			}
+		  private:
+			ScopedMap< std::string, StructDecl * > typeMap;
+		};
+
+		class TupleIndexExpander : public Mutator {
+		public:
+			typedef Mutator Parent;
+			virtual Expression * mutate( TupleIndexExpr * tupleExpr );
+		};
+
+		class TupleExprExpander : public Mutator {
+		public:
+			typedef Mutator Parent;
+			virtual Expression * mutate( TupleExpr * tupleExpr );
+		};
+	}
 
 	void expandTuples( std::list< Declaration * > & translationUnit ) {
-		TupleAssignExpander expander;
-		mutateAll( translationUnit, expander );
+		UniqueExprExpander unqExpander;
+		unqExpander.mutateDeclarationList( translationUnit );
+
+		TupleAssignExpander assnExpander;
+		mutateAll( translationUnit, assnExpander );
 
 		TupleTypeReplacer replacer;
 		replacer.mutateDeclarationList( translationUnit );
+
+		TupleIndexExpander idxExpander;
+		mutateAll( translationUnit, idxExpander );
+
+		TupleExprExpander exprExpander;
+		mutateAll( translationUnit, exprExpander );
 	}
 
-	Expression * TupleAssignExpander::mutate( TupleAssignExpr * tupleExpr ) {
+	Expression * UniqueExprExpander::mutate( UniqueExpr * unqExpr ) {
+		static UniqueName tempNamer( "_unq_expr_" );
+		unqExpr = safe_dynamic_cast< UniqueExpr * > ( Parent::mutate( unqExpr ) );
+		if ( ! decls.count( unqExpr->get_expr() ) ) {
+			// xxx - it's possible (likely?) that expressions can appear in the wrong order because of this. Need to ensure they're placed in the correct location.
+			ObjectDecl * decl = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, unqExpr->get_result()->clone(), new SingleInit( unqExpr->get_expr()->clone() ) );
+			decls[unqExpr->get_expr()] = decl;
+			addDeclaration( decl );
+		}
+		return new VariableExpr( decls[unqExpr->get_expr()] );
+	}
+
+	Expression * TupleAssignExpander::mutate( TupleAssignExpr * assnExpr ) {
+		// xxx - Parent::mutate?
 		CompoundStmt * compoundStmt = new CompoundStmt( noLabels );
 		std::list< Statement * > & stmts = compoundStmt->get_kids();
-		for ( ObjectDecl * obj : tupleExpr->get_tempDecls() ) {
+		for ( ObjectDecl * obj : assnExpr->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;
+		TupleExpr * tupleExpr = new TupleExpr( assnExpr->get_assigns() );
+		assert( tupleExpr->get_result() );
+		stmts.push_back( new ExprStmt( noLabels, tupleExpr ) );
+		assnExpr->get_tempDecls().clear();
+		assnExpr->get_assigns().clear();
+		delete assnExpr;
 		return new StmtExpr( compoundStmt );
 	}
@@ -90,4 +136,38 @@
 	}
 
+	Expression * TupleIndexExpander::mutate( TupleIndexExpr * tupleExpr ) {
+		Expression * tuple = maybeMutate( tupleExpr->get_tuple(), *this );
+		assert( tuple );
+		tupleExpr->set_tuple( nullptr );
+		unsigned int idx = tupleExpr->get_index();
+		delete tupleExpr;
+
+		StructInstType * type = safe_dynamic_cast< StructInstType * >( tuple->get_result() );
+		StructDecl * structDecl = type->get_baseStruct();
+		assert( structDecl->get_members().size() > idx );
+		Declaration * member = *std::next(structDecl->get_members().begin(), idx);
+		return new MemberExpr( safe_dynamic_cast< DeclarationWithType * >( member ), tuple );
+	}
+
+	Expression * TupleExprExpander::mutate( TupleExpr * tupleExpr ) {
+		assert( tupleExpr->get_result() );
+		std::list< Initializer * > inits;
+		for ( Expression * expr : tupleExpr->get_exprs() ) {
+			inits.push_back( new SingleInit( expr ) );
+		}
+		return new CompoundLiteralExpr( tupleExpr->get_result(), new ListInit( inits ) );
+	}
+
+	TupleType * makeTupleType( const std::list< Expression * > & exprs ) {
+		TupleType *tupleType = new TupleType( Type::Qualifiers(true, true, true, true, true, false) );
+		Type::Qualifiers &qualifiers = tupleType->get_qualifiers();
+		for ( Expression * expr : exprs ) {
+			assert( expr->get_result() );
+			Type * type = expr->get_result()->clone();
+			tupleType->get_types().push_back( type );
+			qualifiers &= type->get_qualifiers();
+		} // for
+		return tupleType;
+	}
 } // namespace Tuples
 
Index: src/Tuples/Tuples.h
===================================================================
--- src/Tuples/Tuples.h	(revision 12bc63ab6d1bb10cdf0105eb5df31eab3153a60b)
+++ src/Tuples/Tuples.h	(revision 3c13c03a94ca1d4baa7d03b64383f9d28bb7901f)
@@ -31,4 +31,6 @@
 	// TupleExpansion.cc
 	void expandTuples( std::list< Declaration * > & translationUnit );
+
+  TupleType * makeTupleType( const std::list< Expression * > & exprs );
 } // namespace Tuples
 
