Index: src/Tuples/Explode.cc
===================================================================
--- src/Tuples/Explode.cc	(revision 5ccb10d750e81ef921035bdd254327997acd80ae)
+++ src/Tuples/Explode.cc	(revision 0b5d8710a6dbc15de5d91976d128755d05fc1f7d)
@@ -16,50 +16,75 @@
 #include "Explode.h"
 #include "SynTree/Mutator.h"
+#include "Common/PassVisitor.h"
 
 namespace Tuples {
 	namespace {
-		struct AddrExploder : public Mutator {
+		// remove one level of reference from a reference type -- may be useful elsewhere.
+		Type * getReferenceBase( Type * t ) {
+			if ( ReferenceType * refType = dynamic_cast<ReferenceType *>( t ) ) {
+				return refType->get_base();
+			} else {
+				// for the moment, I want to know immediately if a non-reference type is ever passed in here.
+				assertf( false, "getReferenceBase for non-ref: %s", toString( refType ).c_str() );
+				return nullptr;
+			}
+		}
+
+		struct CastExploder {
+			bool castAdded = false;
 			bool foundUniqueExpr = false;
-			Expression * applyAddr( Expression * expr, bool first = true ) {
+			Expression * applyCast( Expression * expr, bool first = true ) {
 				if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ){
 					foundUniqueExpr = true;
 					std::list< Expression * > exprs;
 					for ( Expression *& expr : tupleExpr->get_exprs() ) {
-						// move & into tuple exprs
-						exprs.push_back( applyAddr( expr, false ) );
+						// move cast into tuple exprs
+						exprs.push_back( applyCast( expr, false ) );
 					}
-					// want the top-level expression to be address-taken, but not nested
+					// want the top-level expression to be cast to reference type, but not nested
 					// tuple expressions
 					if ( first ) {
-						return new AddressExpr( new TupleExpr( exprs ) );
+						castAdded = true;
+						Expression * tupleExpr = new TupleExpr( exprs );
+						return new CastExpr( tupleExpr, new ReferenceType( Type::Qualifiers(), tupleExpr->result->clone() ) );
 					} else {
 						return new TupleExpr( exprs );
 					}
 				}
-				// anything else should be address-taken as normal
-				return new AddressExpr( expr->clone() );
+				if ( dynamic_cast<ReferenceType*>( expr->result ) ) {
+					// don't need to cast reference type to another reference type
+					return expr->clone();
+				} else {
+					// anything else should be cast to reference as normal
+					castAdded = true;
+					return new CastExpr( expr->clone(), new ReferenceType( Type::Qualifiers(), expr->result->clone() ) );
+				}
 			}
 
-			virtual Expression * mutate( UniqueExpr * uniqueExpr ) {
-				// move & into unique expr so that the unique expr has type T* rather than
+			Expression * postmutate( UniqueExpr * uniqueExpr ) {
+				// move cast into unique expr so that the unique expr has type T& rather than
 				// type T. In particular, this transformation helps with generating the
-				// correct code for address-taken member tuple expressions, since the result
-				// should now be a tuple of addresses rather than the address of a tuple.
+				// correct code for reference-cast member tuple expressions, since the result
+				// should now be a tuple of references rather than a reference to a tuple.
 				// Still, this code is a bit awkward, and could use some improvement.
-				if ( dynamic_cast< AddressExpr * > ( uniqueExpr->get_expr() ) ) {
-					// this unique expression has already been mutated or otherwise shouldn't be (can't take the address-of an address-of expression)
-					return uniqueExpr;
+				UniqueExpr * newUniqueExpr = new UniqueExpr( applyCast( uniqueExpr->get_expr() ), uniqueExpr->get_id() );
+				delete uniqueExpr;
+				if ( castAdded ) {
+					// if a cast was added by applyCast, then unique expr now has one more layer of reference
+					// than it had coming into this function. To ensure types still match correctly, need to cast
+					//  to reference base so that outer expressions are still correct.
+					castAdded = false;
+					Type * toType = getReferenceBase( newUniqueExpr->result );
+					return new CastExpr( newUniqueExpr, toType->clone() );
 				}
-				UniqueExpr * newUniqueExpr = new UniqueExpr( applyAddr( uniqueExpr->get_expr() ), uniqueExpr->get_id() );
-				delete uniqueExpr;
-				UntypedExpr * deref = UntypedExpr::createDeref( Mutator::mutate( newUniqueExpr ) );
-				return deref;
+				return newUniqueExpr;
 			}
 
-			virtual Expression * mutate( TupleIndexExpr * tupleExpr ) {
+
+			Expression * postmutate( TupleIndexExpr * tupleExpr ) {
 				// tuple index expr needs to be rebuilt to ensure that the type of the
 				// field is consistent with the type of the tuple expr, since the field
-				// may have changed from type T to T*.
-				Expression * expr = tupleExpr->get_tuple()->acceptMutator( *this );
+				// may have changed from type T to T&.
+				Expression * expr = tupleExpr->get_tuple();
 				tupleExpr->set_tuple( nullptr );
 				TupleIndexExpr * ret = new TupleIndexExpr( expr, tupleExpr->get_index() );
@@ -70,9 +95,10 @@
 	} // namespace
 
-	Expression * distributeAddr( Expression * expr ) {
-		AddrExploder addrExploder;
-		expr = expr->acceptMutator( addrExploder );
-		if ( ! addrExploder.foundUniqueExpr ) {
-			expr = new AddressExpr( expr );
+	Expression * distributeReference( Expression * expr ) {
+		PassVisitor<CastExploder> exploder;
+		expr = expr->acceptMutator( exploder );
+		if ( ! exploder.pass.foundUniqueExpr ) {
+			// if a UniqueExpr was found, then the cast has already been added inside the UniqueExpr as appropriate
+			expr = new CastExpr( expr, new ReferenceType( Type::Qualifiers(), expr->result->clone() ) );
 		}
 		return expr;
Index: src/Tuples/Explode.h
===================================================================
--- src/Tuples/Explode.h	(revision 5ccb10d750e81ef921035bdd254327997acd80ae)
+++ src/Tuples/Explode.h	(revision 0b5d8710a6dbc15de5d91976d128755d05fc1f7d)
@@ -26,7 +26,23 @@
 
 namespace Tuples {
+	Expression * distributeReference( Expression * );
+
 	/// helper function used by explode
 	template< typename OutputIterator >
 	void explodeUnique( Expression * expr, const ResolvExpr::Alternative & alt, const SymTab::Indexer & indexer, OutputIterator out, bool isTupleAssign ) {
+		if ( isTupleAssign ) {
+			// tuple assignment needs CastExprs to be recursively exploded to easily get at all of the components
+			if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
+				ResolvExpr::AltList alts;
+				explodeUnique( castExpr->get_arg(), alt, indexer, back_inserter( alts ), isTupleAssign );
+				for ( ResolvExpr::Alternative & alt : alts ) {
+					// distribute reference cast over all components
+					alt.expr = distributeReference( alt.expr );
+					*out++ = alt;
+				}
+				// in tuple assignment, still need to handle the other cases, but only if not already handled here (don't want to output too many alternatives)
+				return;
+			}
+		}
 		Type * res = expr->get_result()->stripReferences();
 		if ( TupleType * tupleType = dynamic_cast< TupleType * > ( res ) ) {
@@ -40,12 +56,11 @@
 				// if expr type is reference, convert to value type
 				Expression * arg = expr->clone();
-
-				if ( dynamic_cast<ReferenceType *>( arg->get_result() ) ) {
-					// TODO: does this go here (inside uniqueexpr) or outside uniqueexpr? I'm guessing probably should go after...
-					arg = new CastExpr( arg, tupleType->clone() );
-				}
-				if ( Tuples::maybeImpure( arg ) && ! dynamic_cast< UniqueExpr * >( arg ) ) {
+				if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
 					// expressions which may contain side effects require a single unique instance of the expression.
 					arg = new UniqueExpr( arg );
+				}
+				// cast reference to value type to facilitate further explosion
+				if ( dynamic_cast<ReferenceType *>( arg->get_result() ) ) {
+					arg = new CastExpr( arg, tupleType->clone() );
 				}
 				for ( unsigned int i = 0; i < tupleType->size(); i++ ) {
