Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision aa8f9dfd89cb8d2df9f8a3892703dfc427bce64a)
+++ 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 aa8f9dfd89cb8d2df9f8a3892703dfc427bce64a)
+++ 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 aa8f9dfd89cb8d2df9f8a3892703dfc427bce64a)
+++ 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
 
