Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 9d5089e3f418f8ae4795697294bf00b26fc226a7)
+++ src/AST/Convert.cpp	(revision ea05f8d9e191e5b5b531ace7a930e834148e7e96)
@@ -10,6 +10,6 @@
 // Created On       : Thu May 09 15::37::05 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Man Jun 10 11:51:00 2019
-// Update Count     : 11
+// Last Modified On : Mon Jun 17 16:44:00 2019
+// Update Count     : 12
 //
 
@@ -949,5 +949,5 @@
 	const ast::Expr * visit( const ast::TupleExpr * node ) override final {
 		auto expr = visitBaseExpr( node,
-			new UntypedTupleExpr(
+			new TupleExpr(
 				get<Expression>().acceptL(node->exprs)
 			)
@@ -1470,4 +1470,5 @@
 		decl->mangleName = old->mangleName;
 		decl->isDeleted  = old->isDeleted;
+		decl->asmName    = GET_ACCEPT_1(asmName, Expr);
 		decl->uniqueId   = old->uniqueId;
 		decl->extension  = old->extension;
@@ -1494,4 +1495,5 @@
 		decl->mangleName = old->mangleName;
 		decl->isDeleted  = old->isDeleted;
+		decl->asmName    = GET_ACCEPT_1(asmName, Expr);
 		decl->uniqueId   = old->uniqueId;
 		decl->extension  = old->extension;
Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(revision 9d5089e3f418f8ae4795697294bf00b26fc226a7)
+++ src/Makefile.in	(revision ea05f8d9e191e5b5b531ace7a930e834148e7e96)
@@ -239,5 +239,5 @@
 	$(am__objects_7) Tuples/TupleAssignment.$(OBJEXT) \
 	Tuples/TupleExpansion.$(OBJEXT) Tuples/Explode.$(OBJEXT) \
-	Validate/HandleAttributes.$(OBJEXT) \
+	Tuples/Tuples.$(OBJEXT) Validate/HandleAttributes.$(OBJEXT) \
 	Validate/FindSpecialDecls.$(OBJEXT)
 am_libdemangle_a_OBJECTS = $(am__objects_8)
@@ -270,5 +270,5 @@
 	Tuples/TupleAssignment.$(OBJEXT) \
 	Tuples/TupleExpansion.$(OBJEXT) Tuples/Explode.$(OBJEXT) \
-	Validate/HandleAttributes.$(OBJEXT) \
+	Tuples/Tuples.$(OBJEXT) Validate/HandleAttributes.$(OBJEXT) \
 	Validate/FindSpecialDecls.$(OBJEXT) \
 	Virtual/ExpandCasts.$(OBJEXT)
@@ -561,5 +561,5 @@
 	$(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc \
 	$(SRC_SYMTAB) $(SRC_SYNTREE) Tuples/TupleAssignment.cc \
-	Tuples/TupleExpansion.cc Tuples/Explode.cc \
+	Tuples/TupleExpansion.cc Tuples/Explode.cc Tuples/Tuples.cc \
 	Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc \
 	Virtual/ExpandCasts.cc
@@ -570,6 +570,6 @@
 	$(SRC_SYMTAB) SymTab/Demangle.cc $(SRC_SYNTREE) \
 	Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc \
-	Tuples/Explode.cc Validate/HandleAttributes.cc \
-	Validate/FindSpecialDecls.cc
+	Tuples/Explode.cc Tuples/Tuples.cc \
+	Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc
 MAINTAINERCLEANFILES = ${libdir}/${notdir ${cfa_cpplib_PROGRAMS}}
 MOSTLYCLEANFILES = Parser/lex.cc Parser/parser.cc Parser/parser.hh \
@@ -1030,4 +1030,6 @@
 	Tuples/$(DEPDIR)/$(am__dirstamp)
 Tuples/Explode.$(OBJEXT): Tuples/$(am__dirstamp) \
+	Tuples/$(DEPDIR)/$(am__dirstamp)
+Tuples/Tuples.$(OBJEXT): Tuples/$(am__dirstamp) \
 	Tuples/$(DEPDIR)/$(am__dirstamp)
 Validate/$(am__dirstamp):
@@ -1340,4 +1342,5 @@
 @AMDEP_TRUE@@am__include@ @am__quote@Tuples/$(DEPDIR)/TupleAssignment.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@Tuples/$(DEPDIR)/TupleExpansion.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@Tuples/$(DEPDIR)/Tuples.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@Validate/$(DEPDIR)/FindSpecialDecls.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@Validate/$(DEPDIR)/HandleAttributes.Po@am__quote@
Index: src/Tuples/Explode.cc
===================================================================
--- src/Tuples/Explode.cc	(revision 9d5089e3f418f8ae4795697294bf00b26fc226a7)
+++ src/Tuples/Explode.cc	(revision ea05f8d9e191e5b5b531ace7a930e834148e7e96)
@@ -9,7 +9,7 @@
 // Author           : Rob Schluntz
 // Created On       : Wed Nov 9 13:12:24 2016
-// Last Modified By : Rob Schluntz
-// Last Modified On : Wed Nov 9 13:20:24 2016
-// Update Count     : 2
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jun 12 16:40:00 2016
+// Update Count     : 3
 //
 
@@ -106,4 +106,87 @@
 		return expr;
 	}
+
+namespace {
+
+// Remove one level of reference from a reference type.
+const ast::Type * getReferenceBase( const ast::Type * t ) {
+	if ( const ast::ReferenceType * ref = dynamic_cast< const ast::ReferenceType * >( t ) ) {
+		return ref->base;
+	} else {
+		assertf( false, "getReferenceBase for non-ref: %s", toString( t ).c_str() );
+		return nullptr;
+	}
+}
+
+struct CastExploderCore {
+	bool castAdded = false;
+	bool foundUniqueExpr = false;
+	const ast::Expr * applyCast( const ast::Expr * expr, bool first = true ) {
+		// On tuple push the cast down.
+		if ( const ast::TupleExpr * tupleExpr = dynamic_cast< const ast::TupleExpr * >( expr ) ) {
+			foundUniqueExpr = true;
+			std::vector< ast::ptr< ast::Expr > > exprs;
+			for ( const ast::Expr * expr : tupleExpr->exprs ) {
+				exprs.emplace_back( applyCast( expr, false ) );
+				//exprs.emplace_back( ast::ptr< ast::Expr >( applyCast( expr, false ) ) );
+			}
+			if ( first ) {
+				castAdded = true;
+				const ast::Expr * tuple = new ast::TupleExpr(
+					tupleExpr->location, std::move( exprs ) );
+				return new ast::CastExpr( tuple->location,
+					tuple, new ast::ReferenceType( tuple->result.get(), ast::CV::Qualifiers() ) );
+			} else {
+				return new ast::TupleExpr( tupleExpr->location, std::move( exprs ) );
+			}
+		}
+		if ( dynamic_cast< const ast::ReferenceType * >( expr->result.get() ) ) {
+			return expr;
+		} else {
+			castAdded = true;
+			return new ast::CastExpr( expr->location, expr,
+				new ast::ReferenceType( expr->result, ast::CV::Qualifiers() ) );
+		}
+	}
+
+	const ast::Expr * postmutate( const ast::UniqueExpr * node ) {
+		// 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 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.
+		const ast::UniqueExpr * newNode = new ast::UniqueExpr( node->location,
+				applyCast( node->expr ), node->id );
+		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;
+			const ast::Type * newType = getReferenceBase( newNode->result );
+			return new ast::CastExpr( newNode->location, node, newType );
+		}
+		return newNode;
+	}
+
+	const ast::Expr * postmutate( const ast::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&.
+		return new ast::TupleIndexExpr( tupleExpr->location, tupleExpr->tuple, tupleExpr->index );
+	}
+};
+
+} // namespace
+
+const ast::Expr * distributeReference( const ast::Expr * expr ) {
+	ast::Pass<CastExploderCore> exploder;
+	expr = expr->accept( exploder );
+	if ( ! exploder.pass.foundUniqueExpr ) {
+		expr = new ast::CastExpr( expr->location, expr,
+			new ast::ReferenceType( expr->result, ast::CV::Qualifiers() ) );
+	}
+	return expr;
+}
+
 } // namespace Tuples
 
Index: src/Tuples/Explode.h
===================================================================
--- src/Tuples/Explode.h	(revision 9d5089e3f418f8ae4795697294bf00b26fc226a7)
+++ src/Tuples/Explode.h	(revision ea05f8d9e191e5b5b531ace7a930e834148e7e96)
@@ -9,7 +9,7 @@
 // Author           : Rob Schluntz
 // Created On       : Wed Nov 9 13:12:24 2016
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:55:16 2017
-// Update Count     : 3
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Jun 17 14:36:00 2019
+// Update Count     : 4
 //
 
@@ -138,19 +138,99 @@
 	}
 
+const ast::Expr * distributeReference( const ast::Expr * );
+
+/// Append candidate to an OutputIterator of Candidates.
+template<typename OutputIterator>
+void append( OutputIterator out, const ast::Expr * expr, const ast::TypeEnvironment & env,
+		const ast::OpenVarSet & open, const ast::AssertionList & need,
+		const ResolvExpr::Cost & cost, const ResolvExpr::Cost & cvtCost ) {
+	ast::TypeEnvironment copyEnv = env;
+	ast::OpenVarSet copyOpen = open;
+	ast::AssertionSet set;
+	mergeAssertionSet( set, need );
+	*out++ = std::make_shared<ResolvExpr::Candidate>( expr, std::move( copyEnv ),
+		std::move( copyOpen ), std::move( set ), cost, cvtCost );
+}
+
+/// Append candidate to an ExplodedArg.
+static inline void append( ResolvExpr::ExplodedArg& ea, const ast::Expr * expr,
+		const ast::TypeEnvironment&, const ast::OpenVarSet&,
+		const ast::AssertionList&, const ResolvExpr::Cost&, const ResolvExpr::Cost& ) {
+	// I'm not sure why most of the arguments are unused. But they were in the old version.
+	ea.exprs.emplace_back( expr );
+}
+
+/// Check if the expression is a cast to a reference type, return it if it is.
+static inline const ast::CastExpr * isReferenceCast( const ast::Expr * expr ) {
+	if ( const ast::CastExpr * cast = dynamic_cast< const ast::CastExpr * >( expr ) ) {
+		if ( dynamic_cast< const ast::ReferenceType * >( cast->result.get() ) ) {
+			return cast;
+		}
+	}
+	return nullptr;
+}
+
+/// helper function (indirectely) used by explode
+template< typename Output >
+void explodeRecursive(
+	const ast::CastExpr * expr, const ResolvExpr::Candidate & arg,
+	const ast::SymbolTable & symtab, Output && out
+) {
+}
+
 /// helper function used by explode
 template< typename Output >
-void explodeUnique( 
-	const ast::Expr * expr, const ResolvExpr::Candidate & arg, const ast::SymbolTable & symtab, 
-	Output && out, bool isTupleAssign
+void explodeUnique(
+	const ast::ptr< ast::Expr > & expr, const ResolvExpr::Candidate & arg,
+	const ast::SymbolTable & symtab, Output && out, bool isTupleAssign
 ) {
-	#warning unimplemented
-	(void)expr; (void)arg; (void)symtab; (void)out; (void)isTupleAssign;
-	assert(false);
+	// Tuple assignment can use a faster method if it is cast. Uses recursive exploding.
+	if ( isTupleAssign ) if ( const ast::CastExpr * castExpr = isReferenceCast( expr ) ) {
+		ResolvExpr::CandidateList candidates;
+		explodeUnique( castExpr->arg, arg, symtab, back_inserter( candidates ), true );
+		for ( ResolvExpr::CandidateRef & cand : candidates ) {
+			// Distribute the reference cast over all components of the candidate.
+			append( std::forward<Output>(out), distributeReference( cand->expr ), cand->env,
+				cand->open, cand->need, cand->cost, cand->cvtCost );
+		}
+		return;
+	}
+	const ast::Type * res = expr->result->stripReferences();
+	if ( const ast::TupleType * tupleType = dynamic_cast< const ast::TupleType * >( res ) ) {
+		if ( const ast::ptr< ast::TupleExpr > & tupleExpr = expr.as< ast::TupleExpr >() ) {
+			// Open the tuple expr and continue on its components.
+			for ( const ast::Expr * expr : tupleExpr->exprs ) {
+				explodeUnique( expr, arg, symtab, std::forward<Output>(out), isTupleAssign );
+			}
+		} else {
+			ast::ptr< ast::Expr > local = expr;
+			// Expressions which may have side effects require a single unique instance.
+			if ( Tuples::maybeImpureIgnoreUnique( local ) ) {
+				local = new ast::UniqueExpr( local->location, local );
+			}
+			// Cast a reference away to a value-type to allow further explosion.
+			if ( dynamic_cast< const ast::ReferenceType *>( local->result.get() ) ) {
+				local = new ast::CastExpr( local->location, local, tupleType );
+			}
+			// Now we have to go across the tuple via indexing.
+			for ( unsigned int i = 0 ; i < tupleType->size() ; ++i ) {
+				ast::TupleIndexExpr * idx = new ast::TupleIndexExpr( local->location, local, i );
+				explodeUnique( idx, arg, symtab, std::forward<Output>(out), isTupleAssign );
+				// TODO: We need more input to figure out the exact lifetimes of these types.
+				// delete idx;
+			}
+			// delete local;
+		}
+	} else {
+		// For atomic/non-tuple types, no explosion is used.
+		append( std::forward<Output>(out), expr, arg.env, arg.open, arg.need, arg.cost,
+			arg.cvtCost );
+	}
 }
 
 /// expands a tuple-valued candidate into multiple candidates, each with a non-tuple type
 template< typename Output >
-void explode( 
-	const ResolvExpr::Candidate & arg, const ast::SymbolTable & symtab, Output && out, 
+void explode(
+	const ResolvExpr::Candidate & arg, const ast::SymbolTable & symtab, Output && out,
 	bool isTupleAssign = false
 ) {
Index: src/Tuples/Tuples.cc
===================================================================
--- src/Tuples/Tuples.cc	(revision ea05f8d9e191e5b5b531ace7a930e834148e7e96)
+++ src/Tuples/Tuples.cc	(revision ea05f8d9e191e5b5b531ace7a930e834148e7e96)
@@ -0,0 +1,71 @@
+//
+// 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           : Andrew Beach
+// Created On       : Mon Jun 17 14:41:00 2019
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jun 12 15:43:00 2019
+// Update Count     : 0
+//
+
+#include "Tuples.h"
+
+#include "AST/Pass.hpp"
+#include "AST/LinkageSpec.hpp"
+#include "InitTweak/InitTweak.h"
+
+namespace Tuples {
+
+namespace {
+	/// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives
+	/// a very crude approximation, wherein any function call expression means the code may be
+	/// impure.
+    struct ImpurityDetector : public ast::WithShortCircuiting {
+		ImpurityDetector( bool ignoreUnique ) : ignoreUnique( ignoreUnique ) {}
+		bool maybeImpure = false;
+		bool ignoreUnique;
+
+		void previsit( ast::ApplicationExpr const * appExpr ) {
+			visit_children = false;
+			if ( ast::DeclWithType const * function = InitTweak::getFunction( appExpr ) ) {
+				if ( function->linkage == ast::Linkage::Intrinsic
+						&& ( function->name == "*?" || function->name == "?[?]" ) ) {
+					visit_children = true;
+					return;
+				}
+			}
+			maybeImpure = true;
+		}
+		void previsit( ast::UntypedExpr const * ) {
+			maybeImpure = true; visit_children = false;
+		}
+		void previsit( ast::UniqueExpr const * ) {
+			if ( ignoreUnique ) {
+				visit_children = false;
+			}
+		}
+	};
+
+	bool detectImpurity( const ast::Expr * expr, bool ignoreUnique ) {
+		ast::Pass<ImpurityDetector> detector( ignoreUnique );
+		expr->accept( detector );
+		return detector.pass.maybeImpure;
+	}
+} // namespace
+
+bool maybeImpureIgnoreUnique( const ast::Expr * expr ) {
+	return detectImpurity( expr, true );
+}
+
+} // namespace Tuples
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Tuples/Tuples.h
===================================================================
--- src/Tuples/Tuples.h	(revision 9d5089e3f418f8ae4795697294bf00b26fc226a7)
+++ src/Tuples/Tuples.h	(revision ea05f8d9e191e5b5b531ace7a930e834148e7e96)
@@ -9,7 +9,7 @@
 // Author           : Rodolfo G. Esteves
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:55:00 2017
-// Update Count     : 16
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jun 12 10:39:00 2017
+// Update Count     : 17
 //
 
@@ -57,6 +57,8 @@
 	bool maybeImpure( Expression * expr );
 
-	/// returns true if the expression may contain side-effect, ignoring the presence of unique expressions.
+	/// Returns true if the expression may contain side-effect,
+	/// ignoring the presence of unique expressions.
 	bool maybeImpureIgnoreUnique( Expression * expr );
+	bool maybeImpureIgnoreUnique( const ast::Expr * expr );
 } // namespace Tuples
 
Index: src/Tuples/module.mk
===================================================================
--- src/Tuples/module.mk	(revision 9d5089e3f418f8ae4795697294bf00b26fc226a7)
+++ src/Tuples/module.mk	(revision ea05f8d9e191e5b5b531ace7a930e834148e7e96)
@@ -15,4 +15,6 @@
 ###############################################################################
 
-SRC += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc
-SRCDEMANGLE += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc
+SRC += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc \
+	Tuples/Tuples.cc
+SRCDEMANGLE += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc \
+	Tuples/Tuples.cc
