Index: src/Tuples/Explode.cc
===================================================================
--- src/Tuples/Explode.cc	(revision 24d6572fc571b2a894d56a9335edd57899c448c0)
+++ src/Tuples/Explode.cc	(revision c6b4432f5c6c6679b981f5a6bded51ad30ac00d9)
@@ -15,96 +15,8 @@
 
 #include "Explode.h"
-#include <list>                  // for list
 
 #include "AST/Pass.hpp"          // for Pass
-#include "SynTree/Mutator.h"     // for Mutator
-#include "Common/PassVisitor.h"  // for PassVisitor
 
 namespace Tuples {
-	namespace {
-		// 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 * 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 cast into tuple exprs
-						exprs.push_back( applyCast( expr, false ) );
-					}
-					// want the top-level expression to be cast to reference type, but not nested
-					// tuple expressions
-					if ( first ) {
-						castAdded = true;
-						Expression * tupleExpr = new TupleExpr( exprs );
-						return new CastExpr( tupleExpr, new ReferenceType( Type::Qualifiers(), tupleExpr->result->clone() ) );
-					} else {
-						return new TupleExpr( exprs );
-					}
-				}
-				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() ) );
-				}
-			}
-
-			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 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.
-				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() );
-				}
-				return newUniqueExpr;
-			}
-
-
-			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();
-				tupleExpr->set_tuple( nullptr );
-				TupleIndexExpr * ret = new TupleIndexExpr( expr, tupleExpr->get_index() );
-				delete tupleExpr;
-				return ret;
-			}
-		};
-	} // namespace
-
-	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;
-	}
 
 namespace {
Index: src/Tuples/Explode.h
===================================================================
--- src/Tuples/Explode.h	(revision 24d6572fc571b2a894d56a9335edd57899c448c0)
+++ src/Tuples/Explode.h	(revision c6b4432f5c6c6679b981f5a6bded51ad30ac00d9)
@@ -20,10 +20,6 @@
 
 #include "AST/Expr.hpp"
-#include "ResolvExpr/Alternative.h"     // for Alternative, AltList
 #include "ResolvExpr/Candidate.hpp"     // for Candidate, CandidateList
-#include "ResolvExpr/ExplodedActual.h"  // for ExplodedActual
 #include "ResolvExpr/ExplodedArg.hpp"   // for ExplodedArg
-#include "SynTree/Expression.h"         // for Expression, UniqueExpr, AddressExpr
-#include "SynTree/Type.h"               // for TupleType, Type
 #include "Tuples.h"                     // for maybeImpure
 
@@ -32,109 +28,5 @@
 }
 
-namespace SymTab {
-class Indexer;
-}  // namespace SymTab
-
 namespace Tuples {
-	Expression * distributeReference( Expression * );
-
-	static inline CastExpr * isReferenceCast( Expression * expr ) {
-		if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
-			if ( dynamic_cast< ReferenceType * >( castExpr->result ) ) {
-				return castExpr;
-			}
-		}
-		return nullptr;
-	}
-
-	/// Append alternative to an OutputIterator of Alternatives
-	template<typename OutputIterator>
-	void append( OutputIterator out, Expression* expr, const ResolvExpr::TypeEnvironment& env,
-			const ResolvExpr::OpenVarSet& openVars, const ResolvExpr::AssertionList& need,
-			const ResolvExpr::Cost& cost, const ResolvExpr::Cost& cvtCost ) {
-		*out++ = ResolvExpr::Alternative{ expr, env, openVars, need, cost, cvtCost };
-	}
-
-	/// Append alternative to an ExplodedActual
-	static inline void append( ResolvExpr::ExplodedActual& ea, Expression* expr,
-			const ResolvExpr::TypeEnvironment&, const ResolvExpr::OpenVarSet&,
-			const ResolvExpr::AssertionList&, const ResolvExpr::Cost&, const ResolvExpr::Cost& ) {
-		ea.exprs.emplace_back( expr );
-		/// xxx -- merge environment, openVars, need, cost?
-	}
-
-	/// helper function used by explode
-	template< typename Output >
-	void explodeUnique( Expression * expr, const ResolvExpr::Alternative & alt,
-			const SymTab::Indexer & indexer, Output&& out, bool isTupleAssign ) {
-		if ( isTupleAssign ) {
-			// tuple assignment needs CastExprs to be recursively exploded to easily get at all of the components
-			if ( CastExpr * castExpr = isReferenceCast( 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
-					append( std::forward<Output>(out), distributeReference( alt.release_expr() ),
-						alt.env, alt.openVars, alt.need, alt.cost, alt.cvtCost );
-				}
-				// 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 ) ) {
-			if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ) {
-				// can open tuple expr and dump its exploded components
-				for ( Expression * expr : tupleExpr->get_exprs() ) {
-					explodeUnique( expr, alt, indexer, std::forward<Output>(out), isTupleAssign );
-				}
-			} else {
-				// 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 ( 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++ ) {
-					TupleIndexExpr * idx = new TupleIndexExpr( arg->clone(), i );
-					explodeUnique( idx, alt, indexer, std::forward<Output>(out), isTupleAssign );
-					delete idx;
-				}
-				delete arg;
-			}
-		} else {
-			// atomic (non-tuple) type - output a clone of the expression in a new alternative
-			append( std::forward<Output>(out), expr->clone(), alt.env, alt.openVars, alt.need,
-				alt.cost, alt.cvtCost );
-		}
-	}
-
-	/// expands a tuple-valued alternative into multiple alternatives, each with a non-tuple-type
-	template< typename Output >
-	void explode( const ResolvExpr::Alternative &alt, const SymTab::Indexer & indexer,
-			Output&& out, bool isTupleAssign = false ) {
-		explodeUnique( alt.expr, alt, indexer, std::forward<Output>(out), isTupleAssign );
-	}
-
-	// explode list of alternatives
-	template< typename AltIterator, typename Output >
-	void explode( AltIterator altBegin, AltIterator altEnd, const SymTab::Indexer & indexer,
-			Output&& out, bool isTupleAssign = false ) {
-		for ( ; altBegin != altEnd; ++altBegin ) {
-			explode( *altBegin, indexer, std::forward<Output>(out), isTupleAssign );
-		}
-	}
-
-	template< typename Output >
-	void explode( const ResolvExpr::AltList & alts, const SymTab::Indexer & indexer, Output&& out,
-			bool isTupleAssign = false ) {
-		explode( alts.begin(), alts.end(), indexer, std::forward<Output>(out), isTupleAssign );
-	}
 
 const ast::Expr * distributeReference( const ast::Expr * );
Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision 24d6572fc571b2a894d56a9335edd57899c448c0)
+++ src/Tuples/TupleAssignment.cc	(revision c6b4432f5c6c6679b981f5a6bded51ad30ac00d9)
@@ -28,5 +28,4 @@
 #include "AST/TypeEnvironment.hpp"
 #include "CodeGen/OperatorTable.h"
-#include "Common/PassVisitor.h"
 #include "Common/UniqueName.h"             // for UniqueName
 #include "Common/utility.h"                // for splice, zipWith
@@ -34,18 +33,7 @@
 #include "InitTweak/GenInit.h"             // for genCtorInit
 #include "InitTweak/InitTweak.h"           // for getPointerBase, isAssignment
-#include "ResolvExpr/Alternative.h"        // for AltList, Alternative
-#include "ResolvExpr/AlternativeFinder.h"  // for AlternativeFinder, simpleC...
 #include "ResolvExpr/Cost.h"               // for Cost
 #include "ResolvExpr/Resolver.h"           // for resolveCtorInit
-#include "ResolvExpr/TypeEnvironment.h"    // for TypeEnvironment
 #include "ResolvExpr/typeops.h"            // for combos
-#include "SynTree/LinkageSpec.h"           // for Cforall
-#include "SynTree/Declaration.h"           // for ObjectDecl
-#include "SynTree/Expression.h"            // for Expression, CastExpr, Name...
-#include "SynTree/Initializer.h"           // for ConstructorInit, SingleInit
-#include "SynTree/Statement.h"             // for ExprStmt
-#include "SynTree/Type.h"                  // for Type, Type::Qualifiers
-#include "SynTree/TypeSubstitution.h"      // for TypeSubstitution
-#include "SynTree/Visitor.h"               // for Visitor
 
 #if 0
@@ -56,330 +44,4 @@
 
 namespace Tuples {
-	class TupleAssignSpotter_old {
-	  public:
-		// dispatcher for Tuple (multiple and mass) assignment operations
-		TupleAssignSpotter_old( ResolvExpr::AlternativeFinder & );
-		void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args );
-
-	  private:
-		void match();
-
-		struct Matcher {
-		  public:
-			Matcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
-				const ResolvExpr::AltList& rhs );
-			virtual ~Matcher() {}
-
-			virtual void match( std::list< Expression * > &out ) = 0;
-			ObjectDecl * newObject( UniqueName & namer, Expression * expr );
-
-			void combineState( const ResolvExpr::Alternative& alt ) {
-				compositeEnv.simpleCombine( alt.env );
-				ResolvExpr::mergeOpenVars( openVars, alt.openVars );
-				cloneAll( alt.need, need );
-			}
-
-			void combineState( const ResolvExpr::AltList& alts ) {
-				for ( const ResolvExpr::Alternative& alt : alts ) { combineState( alt ); }
-			}
-
-			ResolvExpr::AltList lhs, rhs;
-			TupleAssignSpotter_old &spotter;
-			ResolvExpr::Cost baseCost;
-			std::list< ObjectDecl * > tmpDecls;
-			ResolvExpr::TypeEnvironment compositeEnv;
-			ResolvExpr::OpenVarSet openVars;
-			ResolvExpr::AssertionSet need;
-		};
-
-		struct MassAssignMatcher : public Matcher {
-		  public:
-			MassAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
-				const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
-			virtual void match( std::list< Expression * > &out );
-		};
-
-		struct MultipleAssignMatcher : public Matcher {
-		  public:
-			MultipleAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
-				const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
-			virtual void match( std::list< Expression * > &out );
-		};
-
-		ResolvExpr::AlternativeFinder &currentFinder;
-		std::string fname;
-		std::unique_ptr< Matcher > matcher;
-	};
-
-	/// true if expr is an expression of tuple type
-	bool isTuple( Expression *expr ) {
-		if ( ! expr ) return false;
-		assert( expr->result );
-		return dynamic_cast< TupleType * >( expr->get_result()->stripReferences() );
-	}
-
-	template< typename AltIter >
-	bool isMultAssign( AltIter begin, AltIter end ) {
-		// multiple assignment if more than one alternative in the range or if
-		// the alternative is a tuple
-		if ( begin == end ) return false;
-		if ( isTuple( begin->expr ) ) return true;
-		return ++begin != end;
-	}
-
-	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 refToTuple( castExpr->get_arg() );
-		} else {
-			return isTuple( expr );
-		}
-		return false;
-	}
-
-	void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr,
-				std::vector<ResolvExpr::AlternativeFinder> &args ) {
-		TupleAssignSpotter_old spotter( currentFinder );
-		spotter.spot( expr, args );
-	}
-
-	TupleAssignSpotter_old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f )
-		: currentFinder(f) {}
-
-	void TupleAssignSpotter_old::spot( UntypedExpr * expr,
-			std::vector<ResolvExpr::AlternativeFinder> &args ) {
-		if (  NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {
-			if ( CodeGen::isCtorDtorAssign( op->get_name() ) ) {
-				fname = op->get_name();
-
-				// AlternativeFinder will naturally handle this case case, if it's legal
-				if ( args.size() == 0 ) return;
-
-				// if an assignment only takes 1 argument, that's odd, but maybe someone wrote
-				// the function, in which case AlternativeFinder will handle it normally
-				if ( args.size() == 1 && CodeGen::isAssignment( fname ) ) return;
-
-				// look over all possible left-hand-sides
-				for ( ResolvExpr::Alternative& lhsAlt : args[0] ) {
-					// skip non-tuple LHS
-					if ( ! refToTuple(lhsAlt.expr) ) continue;
-
-					// explode is aware of casts - ensure every LHS expression is sent into explode
-					// with a reference cast
-					// xxx - this seems to change the alternatives before the normal
-					//  AlternativeFinder flow; maybe this is desired?
-					if ( ! dynamic_cast<CastExpr*>( lhsAlt.expr ) ) {
-						lhsAlt.expr = new CastExpr( lhsAlt.expr,
-								new ReferenceType( Type::Qualifiers(),
-									lhsAlt.expr->result->clone() ) );
-					}
-
-					// explode the LHS so that each field of a tuple-valued-expr is assigned
-					ResolvExpr::AltList lhs;
-					explode( lhsAlt, currentFinder.get_indexer(), back_inserter(lhs), true );
-					for ( ResolvExpr::Alternative& alt : lhs ) {
-						// each LHS value must be a reference - some come in with a cast expression,
-						// if not just cast to reference here
-						if ( ! dynamic_cast<ReferenceType*>( alt.expr->get_result() ) ) {
-							alt.expr = new CastExpr( alt.expr,
-								new ReferenceType( Type::Qualifiers(),
-									alt.expr->get_result()->clone() ) );
-						}
-					}
-
-					if ( args.size() == 1 ) {
-						// mass default-initialization/destruction
-						ResolvExpr::AltList rhs{};
-						matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );
-						match();
-					} else if ( args.size() > 2 ) {
-						// expand all possible RHS possibilities
-						// TODO build iterative version of this instead of using combos
-						std::vector< ResolvExpr::AltList > rhsAlts;
-						combos( std::next(args.begin(), 1), args.end(),
-							std::back_inserter( rhsAlts ) );
-						for ( const ResolvExpr::AltList& rhsAlt : rhsAlts ) {
-							// multiple assignment
-							ResolvExpr::AltList rhs;
-							explode( rhsAlt, currentFinder.get_indexer(),
-								std::back_inserter(rhs), true );
-							matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );
-							match();
-						}
-					} else {
-						for ( const ResolvExpr::Alternative& rhsAlt : args[1] ) {
-							ResolvExpr::AltList rhs;
-							if ( isTuple(rhsAlt.expr) ) {
-								// multiple assignment
-								explode( rhsAlt, currentFinder.get_indexer(),
-									std::back_inserter(rhs), true );
-								matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );
-							} else {
-								// mass assignment
-								rhs.push_back( rhsAlt );
-								matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );
-							}
-							match();
-						}
-					}
-				}
-			}
-		}
-	}
-
-	void TupleAssignSpotter_old::match() {
-		assert ( matcher != 0 );
-
-		std::list< Expression * > new_assigns;
-		matcher->match( new_assigns );
-
-		if ( ! matcher->lhs.empty() || ! matcher->rhs.empty() ) {
-			// if both lhs and rhs are empty then this is the empty tuple case, wherein it's okay for new_assigns to be empty.
-			// if not the empty tuple case, return early so that no new alternatives are generated.
-			if ( new_assigns.empty() ) return;
-		}
-		ResolvExpr::AltList current;
-		// now resolve new assignments
-		for ( std::list< Expression * >::iterator i = new_assigns.begin();
-				i != new_assigns.end(); ++i ) {
-			PRINT(
-				std::cerr << "== resolving tuple assign ==" << std::endl;
-				std::cerr << *i << std::endl;
-			)
-
-			ResolvExpr::AlternativeFinder finder{ currentFinder.get_indexer(),
-				matcher->compositeEnv };
-
-			try {
-				finder.findWithAdjustment(*i);
-			} catch (...) {
-				return; // no match should not mean failure, it just means this particular tuple assignment isn't valid
-			}
-			// prune expressions that don't coincide with
-			ResolvExpr::AltList alts = finder.get_alternatives();
-			assert( alts.size() == 1 );
-			assert( alts.front().expr != 0 );
-			current.push_back( alts.front() );
-		}
-
-		// extract expressions from the assignment alternatives to produce a list of assignments
-		// that together form a single alternative
-		std::list< Expression *> solved_assigns;
-		for ( ResolvExpr::Alternative & alt : current ) {
-			solved_assigns.push_back( alt.expr->clone() );
-			matcher->combineState( alt );
-		}
-
-		// xxx -- was push_front
-		currentFinder.get_alternatives().push_back( ResolvExpr::Alternative{
-			new TupleAssignExpr{ solved_assigns, matcher->tmpDecls }, matcher->compositeEnv,
-			matcher->openVars,
-			ResolvExpr::AssertionList( matcher->need.begin(), matcher->need.end() ),
-			ResolvExpr::sumCost( current ) + matcher->baseCost } );
-	}
-
-	TupleAssignSpotter_old::Matcher::Matcher( TupleAssignSpotter_old &spotter,
-		const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs )
-	: lhs(lhs), rhs(rhs), spotter(spotter),
-	  baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ) {
-		combineState( lhs );
-		combineState( rhs );
-	}
-
-	UntypedExpr * createFunc( const std::string &fname, ObjectDecl *left, ObjectDecl *right ) {
-		assert( left );
-		std::list< Expression * > args;
-		args.push_back( new VariableExpr( left ) );
-		// args.push_back( new AddressExpr( new VariableExpr( left ) ) );
-		if ( right ) args.push_back( new VariableExpr( right ) );
-		if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) {
-			args.front() = new AddressExpr( args.front() );
-			if ( right ) args.back() = new AddressExpr( args.back() );
-			return new UntypedExpr( new NameExpr( "?=?" ), args );
-		} else {
-			return new UntypedExpr( new NameExpr( fname ), args );
-		}
-	}
-
-	// removes environments from subexpressions within statement exprs, which could throw off later passes like those in Box which rely on PolyMutator, and adds the bindings to the compositeEnv
-	// xxx - maybe this should happen in alternative finder for every StmtExpr?
-	struct EnvRemover {
-		void previsit( ExprStmt * stmt ) {
-			assert( compositeEnv );
-			if ( stmt->expr->env ) {
-				compositeEnv->add( *stmt->expr->env );
-				delete stmt->expr->env;
-				stmt->expr->env = nullptr;
-			}
-		}
-
-		ResolvExpr::TypeEnvironment * compositeEnv = nullptr;
-	};
-
-	ObjectDecl * TupleAssignSpotter_old::Matcher::newObject( UniqueName & namer, Expression * expr ) {
-		assert( expr->result && ! expr->get_result()->isVoid() );
-		ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) );
-		// if expression type is a reference, don't need to construct anything, a simple initializer is sufficient.
-		if ( ! dynamic_cast< ReferenceType * >( expr->result ) ) {
-			ConstructorInit * ctorInit = InitTweak::genCtorInit( ret );
-			ret->init = ctorInit;
-			ResolvExpr::resolveCtorInit( ctorInit, spotter.currentFinder.get_indexer() ); // resolve ctor/dtors for the new object
-			PassVisitor<EnvRemover> rm; // remove environments from subexpressions of StmtExprs
-			rm.pass.compositeEnv = &compositeEnv;
-			ctorInit->accept( rm );
-		}
-		PRINT( std::cerr << "new object: " << ret << std::endl; )
-		return ret;
-	}
-
-	void TupleAssignSpotter_old::MassAssignMatcher::match( std::list< Expression * > &out ) {
-		static UniqueName lhsNamer( "__massassign_L" );
-		static UniqueName rhsNamer( "__massassign_R" );
-		// empty tuple case falls into this matcher, hence the second part of the assert
-		assert( (! lhs.empty() && rhs.size() <= 1) || (lhs.empty() && rhs.empty()) );
-
-		// xxx - may need to split this up into multiple declarations, because potential conversion to references
-		//  probably should not reference local variable - see MultipleAssignMatcher::match
-		ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;
-		for ( ResolvExpr::Alternative & lhsAlt : lhs ) {
-			// create a temporary object for each value in the lhs and create a call involving the rhs
-			ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr );
-			out.push_back( createFunc( spotter.fname, ltmp, rtmp ) );
-			tmpDecls.push_back( ltmp );
-		}
-		if ( rtmp ) tmpDecls.push_back( rtmp );
-	}
-
-	void TupleAssignSpotter_old::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
-		static UniqueName lhsNamer( "__multassign_L" );
-		static UniqueName rhsNamer( "__multassign_R" );
-
-		if ( lhs.size() == rhs.size() ) {
-			// produce a new temporary object for each value in the lhs and rhs and pairwise create the calls
-			std::list< ObjectDecl * > ltmp;
-			std::list< ObjectDecl * > rtmp;
-			for ( auto p : group_iterate( lhs, rhs ) ) {
-				ResolvExpr::Alternative & lhsAlt = std::get<0>(p);
-				ResolvExpr::Alternative & rhsAlt = std::get<1>(p);
-				// convert RHS to LHS type minus one reference -- important for the case where LHS is && and RHS is lvalue, etc.
-				ReferenceType * lhsType = strict_dynamic_cast<ReferenceType *>( lhsAlt.expr->result );
-				rhsAlt.expr = new CastExpr( rhsAlt.expr, lhsType->base->clone() );
-				ObjectDecl * lobj = newObject( lhsNamer, lhsAlt.expr );
-				ObjectDecl * robj = newObject( rhsNamer, rhsAlt.expr );
-				out.push_back( createFunc(spotter.fname, lobj, robj) );
-				ltmp.push_back( lobj );
-				rtmp.push_back( robj );
-
-				// resolve the cast expression so that rhsAlt return type is bound by the cast type as needed, and transfer the resulting environment
-				ResolvExpr::AlternativeFinder finder{ spotter.currentFinder.get_indexer(), compositeEnv };
-				finder.findWithAdjustment( rhsAlt.expr );
-				assert( finder.get_alternatives().size() == 1 );
-				compositeEnv = std::move( finder.get_alternatives().front().env );
-			}
-			tmpDecls.splice( tmpDecls.end(), ltmp );
-			tmpDecls.splice( tmpDecls.end(), rtmp );
-		}
-	}
 
 namespace {
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision 24d6572fc571b2a894d56a9335edd57899c448c0)
+++ src/Tuples/TupleExpansion.cc	(revision c6b4432f5c6c6679b981f5a6bded51ad30ac00d9)
@@ -23,300 +23,11 @@
 #include "AST/Node.hpp"
 #include "AST/Type.hpp"
-#include "Common/PassVisitor.h"   // for PassVisitor, WithDeclsToAdd, WithGu...
 #include "Common/ScopedMap.h"     // for ScopedMap
 #include "Common/utility.h"       // for CodeLocation
 #include "InitTweak/InitTweak.h"  // for getFunction
-#include "SynTree/LinkageSpec.h"  // for Spec, C, Intrinsic
-#include "SynTree/Constant.h"     // for Constant
-#include "SynTree/Declaration.h"  // for StructDecl, DeclarationWithType
-#include "SynTree/Expression.h"   // for UntypedMemberExpr, Expression, Uniq...
-#include "SynTree/Label.h"        // for operator==, Label
-#include "SynTree/Mutator.h"      // for Mutator
-#include "SynTree/Type.h"         // for Type, Type::Qualifiers, TupleType
-#include "SynTree/Visitor.h"      // for Visitor
 #include "Tuples.h"
 
-class CompoundStmt;
-class TypeSubstitution;
+namespace Tuples {
 
-namespace Tuples {
-	namespace {
-		struct MemberTupleExpander final : public WithShortCircuiting, public WithVisitorRef<MemberTupleExpander> {
-			void premutate( UntypedMemberExpr * ) { visit_children = false; }
-			Expression * postmutate( UntypedMemberExpr * memberExpr );
-		};
-
-		struct UniqueExprExpander final : public WithDeclsToAdd {
-			Expression * postmutate( UniqueExpr * unqExpr );
-
-			std::map< int, Expression * > decls; // not vector, because order added may not be increasing order
-
-			~UniqueExprExpander() {
-				for ( std::pair<const int, Expression *> & p : decls ) {
-					delete p.second;
-				}
-			}
-		};
-
-		struct TupleAssignExpander {
-			Expression * postmutate( TupleAssignExpr * tupleExpr );
-		};
-
-		struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithConstTypeSubstitution {
-			Type * postmutate( TupleType * tupleType );
-
-			void premutate( CompoundStmt * ) {
-				GuardScope( typeMap );
-			}
-		  private:
-			ScopedMap< int, StructDecl * > typeMap;
-		};
-
-		struct TupleIndexExpander {
-			Expression * postmutate( TupleIndexExpr * tupleExpr );
-		};
-
-		struct TupleExprExpander final {
-			Expression * postmutate( TupleExpr * tupleExpr );
-		};
-	}
-
-	void expandMemberTuples( std::list< Declaration * > & translationUnit ) {
-		PassVisitor<MemberTupleExpander> expander;
-		mutateAll( translationUnit, expander );
-	}
-
-	void expandUniqueExpr( std::list< Declaration * > & translationUnit ) {
-		PassVisitor<UniqueExprExpander> unqExpander;
-		mutateAll( translationUnit, unqExpander );
-	}
-
-	void expandTuples( std::list< Declaration * > & translationUnit ) {
-		PassVisitor<TupleAssignExpander> assnExpander;
-		mutateAll( translationUnit, assnExpander );
-
-		PassVisitor<TupleTypeReplacer> replacer;
-		mutateAll( translationUnit, replacer );
-
-		PassVisitor<TupleIndexExpander> idxExpander;
-		mutateAll( translationUnit, idxExpander );
-
-		PassVisitor<TupleExprExpander> exprExpander;
-		mutateAll( translationUnit, exprExpander );
-	}
-
-	namespace {
-		/// given a expression representing the member and an expression representing the aggregate,
-		/// reconstructs a flattened UntypedMemberExpr with the right precedence
-		Expression * reconstructMemberExpr( Expression * member, Expression * aggr, CodeLocation & loc ) {
-			if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( member ) ) {
-				// construct a new UntypedMemberExpr with the correct structure , and recursively
-				// expand that member expression.
-				PassVisitor<MemberTupleExpander> expander;
-				UntypedMemberExpr * inner = new UntypedMemberExpr( memberExpr->aggregate, aggr->clone() );
-				UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member, inner );
-				inner->location = newMemberExpr->location = loc;
-				memberExpr->member = nullptr;
-				memberExpr->aggregate = nullptr;
-				delete memberExpr;
-				return newMemberExpr->acceptMutator( expander );
-			} else {
-				// not a member expression, so there is nothing to do but attach and return
-				UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( member, aggr->clone() );
-				newMemberExpr->location = loc;
-				return newMemberExpr;
-			}
-		}
-	}
-
-	Expression * MemberTupleExpander::postmutate( UntypedMemberExpr * memberExpr ) {
-		if ( UntypedTupleExpr * tupleExpr = dynamic_cast< UntypedTupleExpr * > ( memberExpr->member ) ) {
-			Expression * aggr = memberExpr->aggregate->clone()->acceptMutator( *visitor );
-			// aggregate expressions which might be impure must be wrapped in unique expressions
-			if ( Tuples::maybeImpureIgnoreUnique( memberExpr->aggregate ) ) aggr = new UniqueExpr( aggr );
-			for ( Expression *& expr : tupleExpr->exprs ) {
-				expr = reconstructMemberExpr( expr, aggr, memberExpr->location );
-				expr->location = memberExpr->location;
-			}
-			delete aggr;
-			tupleExpr->location = memberExpr->location;
-			return tupleExpr;
-		} else {
-			// there may be a tuple expr buried in the aggregate
-			// xxx - this is a memory leak
-			UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member->clone(), memberExpr->aggregate->acceptMutator( *visitor ) );
-			newMemberExpr->location = memberExpr->location;
-			return newMemberExpr;
-		}
-	}
-
-	Expression * UniqueExprExpander::postmutate( UniqueExpr * unqExpr ) {
-		const int id = unqExpr->get_id();
-
-		// on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID,
-		// and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable.
-		if ( ! decls.count( id ) ) {
-			Expression * assignUnq;
-			Expression * var = unqExpr->get_var();
-			if ( unqExpr->get_object() ) {
-				// an object was generated to represent this unique expression -- it should be added to the list of declarations now
-				declsToAddBefore.push_back( unqExpr->get_object() );
-				unqExpr->set_object( nullptr );
-				// steal the expr from the unqExpr
-				assignUnq = UntypedExpr::createAssign( unqExpr->get_var()->clone(), unqExpr->get_expr() );
-				unqExpr->set_expr( nullptr );
-			} else {
-				// steal the already generated assignment to var from the unqExpr - this has been generated by FixInit
-				Expression * expr = unqExpr->get_expr();
-				CommaExpr * commaExpr = strict_dynamic_cast< CommaExpr * >( expr );
-				assignUnq = commaExpr->get_arg1();
-				commaExpr->set_arg1( nullptr );
-			}
-			ObjectDecl * finished = new ObjectDecl( toString( "_unq", id, "_finished_" ), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new BasicType( Type::Qualifiers(), BasicType::Bool ),
-													new SingleInit( new ConstantExpr( Constant::from_int( 0 ) ) ) );
-			declsToAddBefore.push_back( finished );
-			// (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N))
-			// This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code.
-			Expression * assignFinished = UntypedExpr::createAssign( new VariableExpr(finished), new ConstantExpr( Constant::from_int( 1 ) ) );
-			ConditionalExpr * condExpr = new ConditionalExpr( new VariableExpr( finished ), var->clone(),
-				new CommaExpr( new CommaExpr( assignUnq, assignFinished ), var->clone() ) );
-			condExpr->set_result( var->get_result()->clone() );
-			condExpr->set_env( maybeClone( unqExpr->get_env() ) );
-			decls[id] = condExpr;
-		}
-		delete unqExpr;
-		return decls[id]->clone();
-	}
-
-	Expression * TupleAssignExpander::postmutate( TupleAssignExpr * assnExpr ) {
-		StmtExpr * ret = assnExpr->get_stmtExpr();
-		assnExpr->set_stmtExpr( nullptr );
-		// move env to StmtExpr
-		ret->set_env( assnExpr->get_env() );
-		assnExpr->set_env( nullptr );
-		delete assnExpr;
-		return ret;
-	}
-
-	Type * TupleTypeReplacer::postmutate( TupleType * tupleType ) {
-		unsigned tupleSize = tupleType->size();
-		if ( ! typeMap.count( tupleSize ) ) {
-			// generate struct type to replace tuple type based on the number of components in the tuple
-			StructDecl * decl = new StructDecl( toString( "_tuple", tupleSize, "_" ) );
-			decl->location = tupleType->location;
-			decl->set_body( true );
-			for ( size_t i = 0; i < tupleSize; ++i ) {
-				TypeDecl * tyParam = new TypeDecl( toString( "tuple_param_", tupleSize, "_", i ), Type::StorageClasses(), nullptr, TypeDecl::Dtype, true );
-				decl->get_members().push_back( new ObjectDecl( toString("field_", i ), Type::StorageClasses(), LinkageSpec::C, nullptr, new TypeInstType( Type::Qualifiers(), tyParam->get_name(), tyParam ), nullptr ) );
-				decl->get_parameters().push_back( tyParam );
-			}
-			if ( tupleSize == 0 ) {
-				// empty structs are not standard C. Add a dummy field to empty tuples to silence warnings when a compound literal Tuple0 is created.
-				decl->get_members().push_back( new ObjectDecl( "dummy", Type::StorageClasses(), LinkageSpec::C, nullptr, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ) );
-			}
-			typeMap[tupleSize] = decl;
-			declsToAddBefore.push_back( decl );
-		}
-		Type::Qualifiers qualifiers = tupleType->get_qualifiers();
-
-		StructDecl * decl = typeMap[tupleSize];
-		StructInstType * newType = new StructInstType( qualifiers, decl );
-		for ( auto p : group_iterate( tupleType->get_types(), decl->get_parameters() ) ) {
-			Type * t = std::get<0>(p);
-			newType->get_parameters().push_back( new TypeExpr( t->clone() ) );
-		}
-		delete tupleType;
-		return newType;
-	}
-
-	Expression * TupleIndexExpander::postmutate( TupleIndexExpr * tupleExpr ) {
-		Expression * tuple = tupleExpr->tuple;
-		assert( tuple );
-		tupleExpr->tuple = nullptr;
-		unsigned int idx = tupleExpr->index;
-		TypeSubstitution * env = tupleExpr->env;
-		tupleExpr->env = nullptr;
-		delete tupleExpr;
-
-		if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * > ( tuple ) ) {
-			if ( ! maybeImpureIgnoreUnique( tupleExpr ) ) {
-				// optimization: definitely pure tuple expr => can reduce to the only relevant component.
-				assert( tupleExpr->exprs.size() > idx );
-				Expression *& expr = *std::next(tupleExpr->exprs.begin(), idx);
-				Expression * ret = expr;
-				ret->env = env;
-				expr = nullptr; // remove from list so it can safely be deleted
-				delete tupleExpr;
-				return ret;
-			}
-		}
-
-		StructInstType * type = strict_dynamic_cast< StructInstType * >( tuple->result );
-		StructDecl * structDecl = type->baseStruct;
-		assert( structDecl->members.size() > idx );
-		Declaration * member = *std::next(structDecl->members.begin(), idx);
-		MemberExpr * memExpr = new MemberExpr( strict_dynamic_cast< DeclarationWithType * >( member ), tuple );
-		memExpr->env = env;
-		return memExpr;
-	}
-
-	Expression * replaceTupleExpr( Type * result, const std::list< Expression * > & exprs, TypeSubstitution * env ) {
-		if ( result->isVoid() ) {
-			// void result - don't need to produce a value for cascading - just output a chain of comma exprs
-			assert( ! exprs.empty() );
-			std::list< Expression * >::const_iterator iter = exprs.begin();
-			Expression * expr = new CastExpr( *iter++ );
-			for ( ; iter != exprs.end(); ++iter ) {
-				expr = new CommaExpr( expr, new CastExpr( *iter ) );
-			}
-			expr->set_env( env );
-			return expr;
-		} else {
-			// typed tuple expression - produce a compound literal which performs each of the expressions
-			// as a distinct part of its initializer - the produced compound literal may be used as part of
-			// another expression
-			std::list< Initializer * > inits;
-			for ( Expression * expr : exprs ) {
-				inits.push_back( new SingleInit( expr ) );
-			}
-			Expression * expr = new CompoundLiteralExpr( result, new ListInit( inits ) );
-			expr->set_env( env );
-			return expr;
-		}
-	}
-
-	Expression * TupleExprExpander::postmutate( TupleExpr * tupleExpr ) {
-		Type * result = tupleExpr->get_result();
-		std::list< Expression * > exprs = tupleExpr->get_exprs();
-		assert( result );
-		TypeSubstitution * env = tupleExpr->get_env();
-
-		// remove data from shell and delete it
-		tupleExpr->set_result( nullptr );
-		tupleExpr->get_exprs().clear();
-		tupleExpr->set_env( nullptr );
-		delete tupleExpr;
-
-		return replaceTupleExpr( result, exprs, env );
-	}
-
-	Type * makeTupleType( const std::list< Expression * > & exprs ) {
-		// produce the TupleType which aggregates the types of the exprs
-		std::list< Type * > types;
-		Type::Qualifiers qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic | Type::Mutex );
-		for ( Expression * expr : exprs ) {
-			assert( expr->get_result() );
-			if ( expr->get_result()->isVoid() ) {
-				// if the type of any expr is void, the type of the entire tuple is void
-				return new VoidType( Type::Qualifiers() );
-			}
-			Type * type = expr->get_result()->clone();
-			types.push_back( type );
-			// the qualifiers on the tuple type are the qualifiers that exist on all component types
-			qualifiers &= type->get_qualifiers();
-		} // for
-		if ( exprs.empty() ) qualifiers = Type::Qualifiers();
-		return new TupleType( qualifiers, types );
-	}
 	const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) {
 		// produce the TupleType which aggregates the types of the exprs
@@ -341,22 +52,4 @@
 	}
 
-	TypeInstType * isTtype( Type * type ) {
-		if ( TypeInstType * inst = dynamic_cast< TypeInstType * >( type ) ) {
-			if ( inst->get_baseType() && inst->get_baseType()->get_kind() == TypeDecl::Ttype ) {
-				return inst;
-			}
-		}
-		return nullptr;
-	}
-
-	const TypeInstType * isTtype( const Type * type ) {
-		if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type ) ) {
-			if ( inst->baseType && inst->baseType->kind == TypeDecl::Ttype ) {
-				return inst;
-			}
-		}
-		return nullptr;
-	}
-
 	const ast::TypeInstType * isTtype( const ast::Type * type ) {
 		if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
Index: src/Tuples/Tuples.cc
===================================================================
--- src/Tuples/Tuples.cc	(revision 24d6572fc571b2a894d56a9335edd57899c448c0)
+++ src/Tuples/Tuples.cc	(revision c6b4432f5c6c6679b981f5a6bded51ad30ac00d9)
@@ -19,5 +19,4 @@
 #include "AST/Inspect.hpp"
 #include "AST/LinkageSpec.hpp"
-#include "Common/PassVisitor.h"
 #include "InitTweak/InitTweak.h"
 
@@ -25,52 +24,4 @@
 
 namespace {
-	/// Checks 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_old : public WithShortCircuiting {
-		bool const ignoreUnique;
-		bool maybeImpure;
-
-		ImpurityDetector_old( bool ignoreUnique ) :
-			ignoreUnique( ignoreUnique ), maybeImpure( false )
-		{}
-
-		void previsit( const ApplicationExpr * appExpr ) {
-			visit_children = false;
-			if ( const DeclarationWithType * function =
-					InitTweak::getFunction( appExpr ) ) {
-				if ( function->linkage == LinkageSpec::Intrinsic ) {
-					if ( function->name == "*?" || function->name == "?[?]" ) {
-						// intrinsic dereference, subscript are pure,
-						// but need to recursively look for impurity
-						visit_children = true;
-						return;
-					}
-				}
-			}
-			maybeImpure = true;
-		}
-
-		void previsit( const UntypedExpr * ) {
-			maybeImpure = true;
-			visit_children = false;
-		}
-
-		void previsit( const UniqueExpr * ) {
-			if ( ignoreUnique ) {
-				// bottom out at unique expression.
-				// The existence of a unique expression doesn't change the purity of an expression.
-				// That is, even if the wrapped expression is impure, the wrapper protects the rest of the expression.
-				visit_children = false;
-				return;
-			}
-		}
-	};
-
-	bool detectImpurity( const Expression * expr, bool ignoreUnique ) {
-		PassVisitor<ImpurityDetector_old> detector( ignoreUnique );
-		expr->accept( detector );
-		return detector.pass.maybeImpure;
-	}
 
 	/// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives
@@ -110,12 +61,4 @@
 }
 
-bool maybeImpure( const Expression * expr ) {
-	return detectImpurity( expr, false );
-}
-
-bool maybeImpureIgnoreUnique( const Expression * expr ) {
-	return detectImpurity( expr, true );
-}
-
 } // namespace Tuples
 
Index: src/Tuples/Tuples.h
===================================================================
--- src/Tuples/Tuples.h	(revision 24d6572fc571b2a894d56a9335edd57899c448c0)
+++ src/Tuples/Tuples.h	(revision c6b4432f5c6c6679b981f5a6bded51ad30ac00d9)
@@ -21,15 +21,8 @@
 #include "AST/Fwd.hpp"
 #include "AST/Node.hpp"
-#include "SynTree/Expression.h"
-#include "SynTree/Declaration.h"
-#include "SynTree/Type.h"
-
-#include "ResolvExpr/AlternativeFinder.h"
 #include "ResolvExpr/CandidateFinder.hpp"
 
 namespace Tuples {
 	// TupleAssignment.cc
-	void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,
-		std::vector< ResolvExpr::AlternativeFinder >& args );
 	void handleTupleAssignment(
 		ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
@@ -38,31 +31,23 @@
 	// TupleExpansion.cc
 	/// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate
-	void expandMemberTuples( std::list< Declaration * > & translationUnit );
 	void expandMemberTuples( ast::TranslationUnit & translationUnit );
 
 	/// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc.
-	void expandTuples( std::list< Declaration * > & translationUnit );
 	void expandTuples( ast::TranslationUnit & translaionUnit );
 
 	/// replaces UniqueExprs with a temporary variable and one call
-	void expandUniqueExpr( std::list< Declaration * > & translationUnit );
 	void expandUniqueExpr( ast::TranslationUnit & translationUnit );
 
 	/// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types
-	Type * makeTupleType( const std::list< Expression * > & exprs );
 	const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs );
 
 	/// returns a TypeInstType if `type` is a ttype, nullptr otherwise
-	TypeInstType * isTtype( Type * type );
-	const TypeInstType * isTtype( const Type * type );
 	const ast::TypeInstType * isTtype( const ast::Type * type );
 
 	/// returns true if the expression may contain side-effects.
-	bool maybeImpure( const Expression * expr );
 	bool maybeImpure( const ast::Expr * expr );
 
 	/// Returns true if the expression may contain side-effect,
 	/// ignoring the presence of unique expressions.
-	bool maybeImpureIgnoreUnique( const Expression * expr );
 	bool maybeImpureIgnoreUnique( const ast::Expr * expr );
 } // namespace Tuples
