Index: src/Tuples/Explode.h
===================================================================
--- src/Tuples/Explode.h	(revision c92c09c3c8670e9a320f63ffae0dfeaa24c6c14d)
+++ src/Tuples/Explode.h	(revision 92360603d942184e66e5f92706ecc75c6b04f121)
@@ -26,26 +26,8 @@
 
 namespace Tuples {
-	/// helper function used by explode to properly distribute
-	/// '&' across a tuple expression
-	Expression * distributeAddr( Expression * expr );
-
 	/// 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 AddressExprs to be recursively exploded to easily get at all of the components
-			if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( expr ) ) {
-				ResolvExpr::AltList alts;
-				explodeUnique( addrExpr->get_arg(), alt, indexer, back_inserter( alts ), isTupleAssign );
-				for ( ResolvExpr::Alternative & alt : alts ) {
-					// distribute '&' over all components
-					alt.expr = distributeAddr( 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();
+		Type * res = expr->get_result()->stripReferences();
 		if ( TupleType * tupleType = dynamic_cast< TupleType * > ( res ) ) {
 			if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ) {
@@ -55,6 +37,12 @@
 				}
 			} else {
-				// tuple type, but not tuple expr - recursively index into its components
+				// tuple type, but not tuple expr - recursively index into its components.
+				// 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 ) ) {
 					// expressions which may contain side effects require a single unique instance of the expression.
Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision c92c09c3c8670e9a320f63ffae0dfeaa24c6c14d)
+++ src/Tuples/TupleAssignment.cc	(revision 92360603d942184e66e5f92706ecc75c6b04f121)
@@ -22,4 +22,5 @@
 #include "Explode.h"
 #include "Common/SemanticError.h"
+#include "CodeGen/OperatorTable.h"
 #include "InitTweak/InitTweak.h"
 #include "InitTweak/GenInit.h"
@@ -77,5 +78,5 @@
 		if ( ! expr ) return false;
 		assert( expr->has_result() );
-		return dynamic_cast< TupleType * >( expr->get_result() );
+		return dynamic_cast< TupleType * >( expr->get_result()->stripReferences() );
 	}
 
@@ -89,10 +90,11 @@
 	}
 
-	bool pointsToTuple( Expression *expr ) {
+	bool refToTuple( Expression *expr ) {
+		assert( expr->get_result() );
 		// also check for function returning tuple of reference types
 		if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
-			return pointsToTuple( castExpr->get_arg() );
-		} else if ( AddressExpr *addr = dynamic_cast< AddressExpr * >( expr) ) {
-			return isTuple( addr->get_arg() );
+			return refToTuple( castExpr->get_arg() );
+		} else {
+			return isTuple( expr );
 		}
 		return false;
@@ -109,9 +111,9 @@
 	void TupleAssignSpotter::spot( UntypedExpr * expr, const std::list<ResolvExpr::AltList> &possibilities ) {
 		if (  NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {
-			if ( InitTweak::isCtorDtorAssign( op->get_name() ) ) {
+			if ( CodeGen::isCtorDtorAssign( op->get_name() ) ) {
 				fname = op->get_name();
 				for ( std::list<ResolvExpr::AltList>::const_iterator ali = possibilities.begin(); ali != possibilities.end(); ++ali ) {
 					if ( ali->size() == 0 ) continue; // AlternativeFinder will natrually handle this case, if it's legal
-					if ( ali->size() <= 1 && InitTweak::isAssignment( op->get_name() ) ) {
+					if ( ali->size() <= 1 && CodeGen::isAssignment( op->get_name() ) ) {
 						// what does it mean if an assignment takes 1 argument? maybe someone defined such a function, in which case AlternativeFinder will naturally handle it
 						continue;
@@ -122,5 +124,5 @@
 					const ResolvExpr::Alternative & alt1 = ali->front();
 					auto begin = std::next(ali->begin(), 1), end = ali->end();
-					if ( pointsToTuple(alt1.expr) ) {
+					if ( refToTuple(alt1.expr) ) {
 						if ( isMultAssign( begin, end ) ) {
 							matcher.reset( new MultipleAssignMatcher( *this, *ali ) );
@@ -196,10 +198,15 @@
 			for ( ResolvExpr::Alternative & alt : lhs ) {
 				Expression *& expr = alt.expr;
-				Type * castType = expr->get_result()->clone();
-				Type * type = InitTweak::getPointerBase( castType );
-				assert( type );
+				Type * type = expr->get_result()->clone();
 				type->get_qualifiers() -= Type::Qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic );
-				type->set_lvalue( true ); // xxx - might not need this
-				expr = new CastExpr( expr, castType );
+				expr = new CastExpr( expr, new ReferenceType( Type::Qualifiers(), type ) );
+			}
+		}
+
+		for ( ResolvExpr::Alternative & alt : lhs ) {
+			// every LHS value must be a reference - some come in with a cast expression, if it doesn't just cast to reference here.
+			// TODO: can this somehow be merge with the cast code directly above?
+			if ( ! dynamic_cast< ReferenceType * >( alt.expr->get_result() ) ) {
+				alt.expr = new CastExpr( alt.expr, new ReferenceType( Type::Qualifiers(), alt.expr->get_result()->clone() ) );
 			}
 		}
@@ -221,5 +228,5 @@
 		assert( left );
 		std::list< Expression * > args;
-		args.push_back( new AddressExpr( UntypedExpr::createDeref( new VariableExpr( left ) ) ) );
+		args.push_back( new VariableExpr( left ) );
 		// args.push_back( new AddressExpr( new VariableExpr( left ) ) );
 		if ( right ) args.push_back( new VariableExpr( right ) );
@@ -241,9 +248,12 @@
 		assert( expr->has_result() && ! expr->get_result()->isVoid() );
 		ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->get_result()->clone(), new SingleInit( expr->clone() ) );
-		ConstructorInit * ctorInit = InitTweak::genCtorInit( ret );
-		ret->set_init( ctorInit );
-		ResolvExpr::resolveCtorInit( ctorInit, spotter.currentFinder.get_indexer() ); // resolve ctor/dtors for the new object
-		EnvRemover rm; // remove environments from subexpressions of StmtExprs
-		ctorInit->accept( rm );
+		// if expression type is a reference, don't need to construct anything, a simple initializer is sufficient.
+		if ( ! dynamic_cast< ReferenceType * >( expr->get_result() ) ) {
+			ConstructorInit * ctorInit = InitTweak::genCtorInit( ret );
+			ret->set_init( ctorInit );
+			ResolvExpr::resolveCtorInit( ctorInit, spotter.currentFinder.get_indexer() ); // resolve ctor/dtors for the new object
+			EnvRemover rm; // remove environments from subexpressions of StmtExprs
+			ctorInit->accept( rm );
+		}
 		return ret;
 	}
