Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 270fdcfad2b102b7af682964133ac21a99b20bac)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision d286cf68892dfb231fb65f0127f47f3d593ac9f1)
@@ -1099,5 +1099,5 @@
 			argExpansions.emplace_back();
 			auto& argE = argExpansions.back();
-			argE.reserve( arg.alternatives.size() );
+			// argE.reserve( arg.alternatives.size() );
 
 			for ( const Alternative& actual : arg ) {
Index: src/ResolvExpr/CommonType.cc
===================================================================
--- src/ResolvExpr/CommonType.cc	(revision 270fdcfad2b102b7af682964133ac21a99b20bac)
+++ src/ResolvExpr/CommonType.cc	(revision d286cf68892dfb231fb65f0127f47f3d593ac9f1)
@@ -24,5 +24,5 @@
 #include "SynTree/Type.h"                // for BasicType, BasicType::Kind::...
 #include "SynTree/Visitor.h"             // for Visitor
-#include "Unify.h"                       // for unifyExact, bindVar, WidenMode
+#include "Unify.h"                       // for unifyExact, WidenMode
 #include "typeops.h"                     // for isFtype
 
@@ -238,5 +238,5 @@
 				AssertionSet need, have;
 				WidenMode widen( widenFirst, widenSecond );
-				if ( entry != openVars.end() && ! bindVar(var, voidPointer->get_base(), entry->second, env, need, have, openVars, widen, indexer ) ) return;
+				if ( entry != openVars.end() && ! env.bindVar(var, voidPointer->get_base(), entry->second, need, have, openVars, widen, indexer ) ) return;
 			}
 		}
Index: src/ResolvExpr/ExplodedActual.h
===================================================================
--- src/ResolvExpr/ExplodedActual.h	(revision 270fdcfad2b102b7af682964133ac21a99b20bac)
+++ src/ResolvExpr/ExplodedActual.h	(revision d286cf68892dfb231fb65f0127f47f3d593ac9f1)
@@ -32,6 +32,7 @@
 
 		ExplodedActual() : env(), cost(Cost::zero), exprs() {}
-
 		ExplodedActual( const Alternative& actual, const SymTab::Indexer& indexer );
+		ExplodedActual(ExplodedActual&&) = default;
+		ExplodedActual& operator= (ExplodedActual&&) = default;
 	};
 }
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision 270fdcfad2b102b7af682964133ac21a99b20bac)
+++ src/ResolvExpr/Resolver.cc	(revision d286cf68892dfb231fb65f0127f47f3d593ac9f1)
@@ -582,8 +582,6 @@
 
 							// Make sure we don't widen any existing bindings
-							for ( auto & i : resultEnv ) {
-								i.allowWidening = false;
-							}
-
+							resultEnv.forbidWidening();
+							
 							// Find any unbound type variables
 							resultEnv.extractOpenVars( openVars );
Index: src/ResolvExpr/TypeEnvironment.cc
===================================================================
--- src/ResolvExpr/TypeEnvironment.cc	(revision 270fdcfad2b102b7af682964133ac21a99b20bac)
+++ src/ResolvExpr/TypeEnvironment.cc	(revision d286cf68892dfb231fb65f0127f47f3d593ac9f1)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 12:19:47 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sun May 17 12:23:36 2015
-// Update Count     : 3
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Mon Jun 18 11:58:00 2018
+// Update Count     : 4
 //
 
@@ -17,4 +17,5 @@
 #include <algorithm>                   // for copy, set_intersection
 #include <iterator>                    // for ostream_iterator, insert_iterator
+#include <memory>                      // for unique_ptr
 #include <utility>                     // for pair, move
 
@@ -22,5 +23,8 @@
 #include "SynTree/Type.h"              // for Type, FunctionType, Type::Fora...
 #include "SynTree/TypeSubstitution.h"  // for TypeSubstitution
+#include "Tuples/Tuples.h"             // for isTtype
 #include "TypeEnvironment.h"
+#include "typeops.h"                   // for occurs
+#include "Unify.h"                     // for unifyInexact
 
 namespace ResolvExpr {
@@ -65,4 +69,10 @@
 	}
 
+	EqvClass::EqvClass( EqvClass &&other ) 
+	: vars{std::move(other.vars)}, type{other.type}, 
+	  allowWidening{std::move(other.allowWidening)}, data{std::move(other.data)} {
+		  other.type = nullptr;
+	}
+
 	EqvClass &EqvClass::operator=( const EqvClass &other ) {
 		if ( this == &other ) return *this;
@@ -72,6 +82,25 @@
 	}
 
+	EqvClass &EqvClass::operator=( EqvClass &&other ) {
+		if ( this == &other ) return *this;
+		delete type;
+		
+		vars = std::move(other.vars);
+		type = other.type;
+		other.type = nullptr;
+		allowWidening = std::move(other.allowWidening);
+		data = std::move(other.data);
+
+		return *this;
+	}
+
 	EqvClass::~EqvClass() {
 		delete type;
+	}
+
+	void EqvClass::set_type( Type* ty ) {
+		if ( ty == type ) return;
+		delete type;
+		type = ty;
 	}
 
@@ -92,11 +121,5 @@
 	const EqvClass* TypeEnvironment::lookup( const std::string &var ) const {
 		for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i ) {
-			if ( i->vars.find( var ) != i->vars.end() ) {
-///       std::cout << var << " is in class ";
-///       i->print( std::cout );
-				return &*i;
-			}
-///     std::cout << var << " is not in class ";
-///     i->print( std::cout );
+			if ( i->vars.find( var ) != i->vars.end() ) return &*i;
 		} // for
 		return nullptr;
@@ -116,9 +139,4 @@
 	}
 
-	void TypeEnvironment::add( const EqvClass &eqvClass ) {
-		filterOverlappingClasses( env, eqvClass );
-		env.push_back( eqvClass );
-	}
-
 	void TypeEnvironment::add( EqvClass &&eqvClass ) {
 		filterOverlappingClasses( env, eqvClass );
@@ -131,5 +149,5 @@
 			newClass.vars.insert( (*i)->get_name() );
 			newClass.data = TypeDecl::Data{ (*i) };
-			env.push_back( newClass );
+			env.push_back( std::move(newClass) );
 		} // for
 	}
@@ -145,5 +163,5 @@
 			// transition to TypeSubstitution
 			newClass.data = TypeDecl::Data{ TypeDecl::Dtype, false };
-			add( newClass );
+			add( std::move(newClass) );
 		}
 	}
@@ -152,13 +170,8 @@
 		for ( std::list< EqvClass >::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) {
 			for ( std::set< std::string >::const_iterator theVar = theClass->vars.begin(); theVar != theClass->vars.end(); ++theVar ) {
-///       std::cerr << "adding " << *theVar;
 				if ( theClass->type ) {
-///         std::cerr << " bound to ";
-///         theClass->type->print( std::cerr );
-///         std::cerr << std::endl;
 					sub.add( *theVar, theClass->type );
 				} else if ( theVar != theClass->vars.begin() ) {
 					TypeInstType *newTypeInst = new TypeInstType( Type::Qualifiers(), *theClass->vars.begin(), theClass->data.kind == TypeDecl::Ftype );
-///         std::cerr << " bound to variable " << *theClass->vars.begin() << std::endl;
 					sub.add( *theVar, newTypeInst );
 					delete newTypeInst;
@@ -166,8 +179,4 @@
 			} // for
 		} // for
-///   std::cerr << "input env is:" << std::endl;
-///   print( std::cerr, 8 );
-///   std::cerr << "sub is:" << std::endl;
-///   sub.print( std::cerr, 8 );
 		sub.normalize();
 	}
@@ -181,7 +190,5 @@
 	std::list< EqvClass >::iterator TypeEnvironment::internal_lookup( const std::string &var ) {
 		for ( std::list< EqvClass >::iterator i = env.begin(); i != env.end(); ++i ) {
-			if ( i->vars.find( var ) == i->vars.end() ) {
-				return i;
-			} // if
+			if ( i->vars.count( var ) ) return i;
 		} // for
 		return env.end();
@@ -190,34 +197,4 @@
 	void TypeEnvironment::simpleCombine( const TypeEnvironment &second ) {
 		env.insert( env.end(), second.env.begin(), second.env.end() );
-	}
-
-	void TypeEnvironment::combine( const TypeEnvironment &second, Type *(*combineFunc)( Type*, Type* ) ) {
-		TypeEnvironment secondCopy( second );
-		for ( std::list< EqvClass >::iterator firstClass = env.begin(); firstClass != env.end(); ++firstClass ) {
-			EqvClass &newClass = *firstClass;
-			std::set< std::string > newVars;
-			for ( std::set< std::string >::const_iterator var = firstClass->vars.begin(); var != firstClass->vars.end(); ++var ) {
-				std::list< EqvClass >::iterator secondClass = secondCopy.internal_lookup( *var );
-				if ( secondClass != secondCopy.env.end() ) {
-					newVars.insert( secondClass->vars.begin(), secondClass->vars.end() );
-					if ( secondClass->type ) {
-						if ( newClass.type ) {
-							Type *newType = combineFunc( newClass.type, secondClass->type );
-							delete newClass.type;
-							newClass.type = newType;
-							newClass.allowWidening = newClass.allowWidening && secondClass->allowWidening;
-						} else {
-							newClass.type = secondClass->type->clone();
-							newClass.allowWidening = secondClass->allowWidening;
-						} // if
-					} // if
-					secondCopy.env.erase( secondClass );
-				} // if
-			} // for
-			newClass.vars.insert( newVars.begin(), newVars.end() );
-		} // for
-		for ( std::list< EqvClass >::iterator secondClass = secondCopy.env.begin(); secondClass != secondCopy.env.end(); ++secondClass ) {
-			env.push_back( *secondClass );
-		} // for
 	}
 
@@ -241,4 +218,152 @@
 	}
 
+	bool isFtype( Type *type ) {
+		if ( dynamic_cast< FunctionType* >( type ) ) {
+			return true;
+		} else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( type ) ) {
+			return typeInst->get_isFtype();
+		} // if
+		return false;
+	}
+
+	bool tyVarCompatible( const TypeDecl::Data & data, Type *type ) {
+		switch ( data.kind ) {
+		  case TypeDecl::Dtype:
+			// to bind to an object type variable, the type must not be a function type.
+			// if the type variable is specified to be a complete type then the incoming
+			// type must also be complete
+			// xxx - should this also check that type is not a tuple type and that it's not a ttype?
+			return ! isFtype( type ) && (! data.isComplete || type->isComplete() );
+		  case TypeDecl::Ftype:
+			return isFtype( type );
+		  case TypeDecl::Ttype:
+			// ttype unifies with any tuple type
+			return dynamic_cast< TupleType * >( type ) || Tuples::isTtype( type );
+		} // switch
+		return false;
+	}
+
+	bool TypeEnvironment::bindVar( TypeInstType *typeInst, Type *bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
+		
+		// remove references from other, so that type variables can only bind to value types
+		bindTo = bindTo->stripReferences();
+		OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() );
+		assert( tyvar != openVars.end() );
+		if ( ! tyVarCompatible( tyvar->second, bindTo ) ) {
+			return false;
+		} // if
+		if ( occurs( bindTo, typeInst->get_name(), *this ) ) {
+			return false;
+		} // if
+		auto curClass = internal_lookup( typeInst->get_name() );
+		if ( curClass != env.end() ) {
+			if ( curClass->type ) {
+				Type *common = 0;
+				// attempt to unify equivalence class type (which has qualifiers stripped, so they must be restored) with the type to bind to
+				std::unique_ptr< Type > newType( curClass->type->clone() );
+				newType->get_qualifiers() = typeInst->get_qualifiers();
+				if ( unifyInexact( newType.get(), bindTo, *this, need, have, openVars, widenMode & WidenMode( curClass->allowWidening, true ), indexer, common ) ) {
+					if ( common ) {
+						common->get_qualifiers() = Type::Qualifiers{};
+						curClass->set_type( common );
+					} // if
+				} else return false;
+			} else {
+				Type* newType = bindTo->clone();
+				newType->get_qualifiers() = Type::Qualifiers{};
+				curClass->set_type( newType );
+				curClass->allowWidening = widenMode.widenFirst && widenMode.widenSecond;
+			} // if
+		} else {
+			EqvClass newClass;
+			newClass.vars.insert( typeInst->get_name() );
+			newClass.type = bindTo->clone();
+			newClass.type->get_qualifiers() = Type::Qualifiers();
+			newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond;
+			newClass.data = data;
+			env.push_back( std::move(newClass) );
+		} // if
+		return true;
+	}
+
+	bool TypeEnvironment::bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
+
+		auto class1 = internal_lookup( var1->get_name() );
+		auto class2 = internal_lookup( var2->get_name() );
+		
+		// exit early if variables already bound together
+		if ( class1 != env.end() && class1 == class2 ) {
+			class1->allowWidening &= widenMode;
+			return true;
+		}
+
+		bool widen1 = false, widen2 = false;
+		const Type *type1 = nullptr, *type2 = nullptr;
+
+		// check for existing bindings, perform occurs check
+		if ( class1 != env.end() ) {
+			if ( class1->type ) {
+				if ( occurs( class1->type, var2->get_name(), *this ) ) return false;
+				type1 = class1->type;
+			} // if
+			widen1 = widenMode.widenFirst && class1->allowWidening;
+		} // if
+		if ( class2 != env.end() ) {
+			if ( class2->type ) {
+				if ( occurs( class2->type, var1->get_name(), *this ) ) return false;
+				type2 = class2->type;
+			} // if
+			widen2 = widenMode.widenSecond && class2->allowWidening;
+		} // if
+
+		if ( type1 && type2 ) {
+			// both classes bound, merge if bound types can be unified
+			std::unique_ptr<Type> newType1{ type1->clone() }, newType2{ type2->clone() };
+			WidenMode newWidenMode{ widen1, widen2 };
+			Type *common = 0;
+			if ( unifyInexact( newType1.get(), newType2.get(), *this, need, have, openVars, newWidenMode, indexer, common ) ) {
+				class1->vars.insert( class2->vars.begin(), class2->vars.end() );
+				class1->allowWidening = widen1 && widen2;
+				if ( common ) {
+					common->get_qualifiers() = Type::Qualifiers{};
+					class1->set_type( common );
+				}
+				env.erase( class2 );
+			} else return false;
+		} else if ( class1 != env.end() && class2 != env.end() ) {
+			// both classes exist, at least one unbound, merge unconditionally
+			if ( type1 ) {
+				class1->vars.insert( class2->vars.begin(), class2->vars.end() );
+				class1->allowWidening = widen1;
+				env.erase( class2 );
+			} else {
+				class2->vars.insert( class1->vars.begin(), class1->vars.end() );
+				class2->allowWidening = widen2;
+				env.erase( class1 );
+			} // if
+		} else if ( class1 != env.end() ) {
+			// var2 unbound, add to class1
+			class1->vars.insert( var2->get_name() );
+			class1->allowWidening = widen1;
+		} else if ( class2 != env.end() ) {
+			// var1 unbound, add to class2
+			class2->vars.insert( var1->get_name() );
+			class2->allowWidening = widen2;
+		} else {
+			// neither var bound, create new class
+			EqvClass newClass;
+			newClass.vars.insert( var1->get_name() );
+			newClass.vars.insert( var2->get_name() );
+			newClass.allowWidening = widen1 && widen2;
+			newClass.data = data;
+			env.push_back( std::move(newClass) );
+		} // if
+		return true;
+	}
+
+	void TypeEnvironment::forbidWidening() {
+		for ( EqvClass& c : env ) c.allowWidening = false;
+	}
+
 	std::ostream & operator<<( std::ostream & out, const TypeEnvironment & env ) {
 		env.print( out );
Index: src/ResolvExpr/TypeEnvironment.h
===================================================================
--- src/ResolvExpr/TypeEnvironment.h	(revision 270fdcfad2b102b7af682964133ac21a99b20bac)
+++ src/ResolvExpr/TypeEnvironment.h	(revision d286cf68892dfb231fb65f0127f47f3d593ac9f1)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 12:24:58 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:35:45 2017
-// Update Count     : 3
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Mon Jun 18 11:58:00 2018
+// Update Count     : 4
 //
 
@@ -21,4 +21,7 @@
 #include <set>                         // for set
 #include <string>                      // for string
+#include <utility>                     // for move, swap
+
+#include "WidenMode.h"                 // for WidenMode
 
 #include "SynTree/Declaration.h"       // for TypeDecl::Data, DeclarationWit...
@@ -77,7 +80,12 @@
 		EqvClass( const EqvClass &other );
 		EqvClass( const EqvClass &other, const Type *ty );
+		EqvClass( EqvClass &&other );
 		EqvClass &operator=( const EqvClass &other );
+		EqvClass &operator=( EqvClass &&other );
 		~EqvClass();
 		void print( std::ostream &os, Indenter indent = {} ) const;
+
+		/// Takes ownership of `ty`, freeing old `type`
+		void set_type(Type* ty);
 	};
 
@@ -85,6 +93,7 @@
 	  public:
 		const EqvClass* lookup( const std::string &var ) const;
-		void add( const EqvClass &eqvClass );
+	  private:
 		void add( EqvClass &&eqvClass  );
+	  public:
 		void add( const Type::ForallList &tyDecls );
 		void add( const TypeSubstitution & sub );
@@ -94,5 +103,5 @@
 		bool isEmpty() const { return env.empty(); }
 		void print( std::ostream &os, Indenter indent = {} ) const;
-		void combine( const TypeEnvironment &second, Type *(*combineFunc)( Type*, Type* ) );
+		// void combine( const TypeEnvironment &second, Type *(*combineFunc)( Type*, Type* ) );
 		void simpleCombine( const TypeEnvironment &second );
 		void extractOpenVars( OpenVarSet &openVars ) const;
@@ -103,12 +112,22 @@
 		void addActual( const TypeEnvironment& actualEnv, OpenVarSet& openVars );
 
-		typedef std::list< EqvClass >::iterator iterator;
-		iterator begin() { return env.begin(); }
-		iterator end() { return env.end(); }
-		typedef std::list< EqvClass >::const_iterator const_iterator;
-		const_iterator begin() const { return env.begin(); }
-		const_iterator end() const { return env.end(); }
+		/// Binds the type class represented by `typeInst` to the type `bindTo`; will add 
+		/// the class if needed. Returns false on failure.
+		bool bindVar( TypeInstType *typeInst, Type *bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );
+		
+		/// Binds the type classes represented by `var1` and `var2` together; will add 
+		/// one or both classes if needed. Returns false on failure.
+		bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );
+
+		/// Disallows widening for all bindings in the environment
+		void forbidWidening();
+
+		using iterator = std::list< EqvClass >::const_iterator;
+		iterator begin() const { return env.begin(); }
+		iterator end() const { return env.end(); }
+
 	  private:
 		std::list< EqvClass > env;
+		
 		std::list< EqvClass >::iterator internal_lookup( const std::string &var );
 	};
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision 270fdcfad2b102b7af682964133ac21a99b20bac)
+++ src/ResolvExpr/Unify.cc	(revision d286cf68892dfb231fb65f0127f47f3d593ac9f1)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 12:27:10 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Mar 16 16:22:54 2017
-// Update Count     : 42
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Mon Jun 18 11:58:00 2018
+// Update Count     : 43
 //
 
@@ -129,152 +129,4 @@
 	}
 
-	bool isFtype( Type *type ) {
-		if ( dynamic_cast< FunctionType* >( type ) ) {
-			return true;
-		} else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( type ) ) {
-			return typeInst->get_isFtype();
-		} // if
-		return false;
-	}
-
-	bool tyVarCompatible( const TypeDecl::Data & data, Type *type ) {
-		switch ( data.kind ) {
-		  case TypeDecl::Dtype:
-			// to bind to an object type variable, the type must not be a function type.
-			// if the type variable is specified to be a complete type then the incoming
-			// type must also be complete
-			// xxx - should this also check that type is not a tuple type and that it's not a ttype?
-			return ! isFtype( type ) && (! data.isComplete || type->isComplete() );
-		  case TypeDecl::Ftype:
-			return isFtype( type );
-		  case TypeDecl::Ttype:
-			// ttype unifies with any tuple type
-			return dynamic_cast< TupleType * >( type ) || Tuples::isTtype( type );
-		} // switch
-		return false;
-	}
-
-	bool bindVar( TypeInstType *typeInst, Type *other, const TypeDecl::Data & data, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
-		// remove references from other, so that type variables can only bind to value types
-		other = other->stripReferences();
-		OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() );
-		assert( tyvar != openVars.end() );
-		if ( ! tyVarCompatible( tyvar->second, other ) ) {
-			return false;
-		} // if
-		if ( occurs( other, typeInst->get_name(), env ) ) {
-			return false;
-		} // if
-		if ( const EqvClass *curClass = env.lookup( typeInst->get_name() ) ) {
-			if ( curClass->type ) {
-				Type *common = 0;
-				// attempt to unify equivalence class type (which has qualifiers stripped, so they must be restored) with the type to bind to
-				std::unique_ptr< Type > newType( curClass->type->clone() );
-				newType->get_qualifiers() = typeInst->get_qualifiers();
-				if ( unifyInexact( newType.get(), other, env, needAssertions, haveAssertions, openVars, widenMode & WidenMode( curClass->allowWidening, true ), indexer, common ) ) {
-					if ( common ) {
-						common->get_qualifiers() = Type::Qualifiers();
-						env.add( EqvClass{ *curClass, common } );
-					} // if
-					return true;
-				} else {
-					return false;
-				} // if
-			} else {
-				EqvClass newClass { *curClass, other };
-				newClass.type->get_qualifiers() = Type::Qualifiers();
-				newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond;
-				env.add( std::move(newClass) );
-			} // if
-		} else {
-			EqvClass newClass;
-			newClass.vars.insert( typeInst->get_name() );
-			newClass.type = other->clone();
-			newClass.type->get_qualifiers() = Type::Qualifiers();
-			newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond;
-			newClass.data = data;
-			env.add( newClass );
-		} // if
-		return true;
-	}
-
-	bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
-		bool result = true;
-		const EqvClass *class1 = env.lookup( var1->get_name() );
-		const EqvClass *class2 = env.lookup( var2->get_name() );
-		bool widen1 = false, widen2 = false;
-		Type *type1 = nullptr, *type2 = nullptr;
-
-		if ( class1 ) {
-			if ( class1->type ) {
-				if ( occurs( class1->type, var2->get_name(), env ) ) {
-					return false;
-				} // if
-				type1 = class1->type->clone();
-			} // if
-			widen1 = widenMode.widenFirst && class1->allowWidening;
-		} // if
-		if ( class2 ) {
-			if ( class2->type ) {
-				if ( occurs( class2->type, var1->get_name(), env ) ) {
-					return false;
-				} // if
-				type2 = class2->type->clone();
-			} // if
-			widen2 = widenMode.widenSecond && class2->allowWidening;
-		} // if
-
-		if ( type1 && type2 ) {
-//    std::cerr << "has type1 && type2" << std::endl;
-			WidenMode newWidenMode ( widen1, widen2 );
-			Type *common = 0;
-			if ( unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, newWidenMode, indexer, common ) ) {
-				EqvClass newClass1 = *class1;
-				newClass1.vars.insert( class2->vars.begin(), class2->vars.end() );
-				newClass1.allowWidening = widen1 && widen2;
-				if ( common ) {
-					common->get_qualifiers() = Type::Qualifiers();
-					delete newClass1.type;
-					newClass1.type = common;
-				} // if
-				env.add( std::move(newClass1) );
-			} else {
-				result = false;
-			} // if
-		} else if ( class1 && class2 ) {
-			if ( type1 ) {
-				EqvClass newClass1 = *class1;
-				newClass1.vars.insert( class2->vars.begin(), class2->vars.end() );
-				newClass1.allowWidening = widen1;
-				env.add( std::move(newClass1) );
-			} else {
-				EqvClass newClass2 = *class2;
-				newClass2.vars.insert( class1->vars.begin(), class1->vars.end() );
-				newClass2.allowWidening = widen2;
-				env.add( std::move(newClass2) );
-			} // if
-		} else if ( class1 ) {
-			EqvClass newClass1 = *class1;
-			newClass1.vars.insert( var2->get_name() );
-			newClass1.allowWidening = widen1;
-			env.add( std::move(newClass1) );
-		} else if ( class2 ) {
-			EqvClass newClass2 = *class2;
-			newClass2.vars.insert( var1->get_name() );
-			newClass2.allowWidening = widen2;
-			env.add( std::move(newClass2) );
-		} else {
-			EqvClass newClass;
-			newClass.vars.insert( var1->get_name() );
-			newClass.vars.insert( var2->get_name() );
-			newClass.allowWidening = widen1 && widen2;
-			newClass.data = data;
-			env.add( newClass );
-		} // if
-		delete type1;
-		delete type2;
-		return result;
-	}
-
 	bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
 		OpenVarSet closedVars;
@@ -321,9 +173,9 @@
 
 		if ( isopen1 && isopen2 && entry1->second == entry2->second ) {
-			result = bindVarToVar( var1, var2, entry1->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
+			result = env.bindVarToVar( var1, var2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer );
 		} else if ( isopen1 ) {
-			result = bindVar( var1, type2, entry1->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
+			result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer );
 		} else if ( isopen2 ) { // TODO: swap widenMode values in call, since type positions are flipped?
-			result = bindVar( var2, type1, entry2->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
+			result = env.bindVar( var2, type1, entry2->second, needAssertions, haveAssertions, openVars, widenMode, indexer );
 		} else {
 			PassVisitor<Unify> comparator( type2, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
Index: src/ResolvExpr/Unify.h
===================================================================
--- src/ResolvExpr/Unify.h	(revision 270fdcfad2b102b7af682964133ac21a99b20bac)
+++ src/ResolvExpr/Unify.h	(revision d286cf68892dfb231fb65f0127f47f3d593ac9f1)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 13:09:04 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Jul 21 23:09:34 2017
-// Update Count     : 3
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Mon Jun 18 11:58:00 2018
+// Update Count     : 4
 //
 
@@ -21,4 +21,5 @@
 #include "SynTree/Declaration.h"  // for TypeDecl, TypeDecl::Data
 #include "TypeEnvironment.h"      // for AssertionSet, OpenVarSet
+#include "WidenMode.h"            // for WidenMode
 
 class Type;
@@ -29,19 +30,8 @@
 
 namespace ResolvExpr {
-	struct WidenMode {
-		WidenMode( bool widenFirst, bool widenSecond ): widenFirst( widenFirst ), widenSecond( widenSecond ) {}
-		WidenMode &operator|=( const WidenMode &other ) { widenFirst |= other.widenFirst; widenSecond |= other.widenSecond; return *this; }
-		WidenMode &operator&=( const WidenMode &other ) { widenFirst &= other.widenFirst; widenSecond &= other.widenSecond; return *this; }
-		WidenMode operator|( const WidenMode &other ) { WidenMode newWM( *this ); newWM |= other; return newWM; }
-		WidenMode operator&( const WidenMode &other ) { WidenMode newWM( *this ); newWM &= other; return newWM; }
-		operator bool() { return widenFirst && widenSecond; }
-
-		bool widenFirst : 1, widenSecond : 1;
-	};
-
-	bool bindVar( TypeInstType *typeInst, Type *other, const TypeDecl::Data & data, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );
 	bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
 	bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType );
 	bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
+	bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer, Type *&common );
 
 	template< typename Iterator1, typename Iterator2 >
Index: src/ResolvExpr/WidenMode.h
===================================================================
--- src/ResolvExpr/WidenMode.h	(revision d286cf68892dfb231fb65f0127f47f3d593ac9f1)
+++ src/ResolvExpr/WidenMode.h	(revision d286cf68892dfb231fb65f0127f47f3d593ac9f1)
@@ -0,0 +1,35 @@
+//
+// 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.
+//
+// WidenMode.h --
+//
+// Author           : Aaron B. Moss
+// Created On       : Mon Jun 18 11:58:00 2018
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Mon Jun 18 11:58:00 2018
+// Update Count     : 1
+//
+
+#pragma once
+
+namespace ResolvExpr {
+	struct WidenMode {
+		WidenMode( bool widenFirst, bool widenSecond ): widenFirst( widenFirst ), widenSecond( widenSecond ) {}
+		WidenMode &operator|=( const WidenMode &other ) { widenFirst |= other.widenFirst; widenSecond |= other.widenSecond; return *this; }
+		WidenMode &operator&=( const WidenMode &other ) { widenFirst &= other.widenFirst; widenSecond &= other.widenSecond; return *this; }
+		WidenMode operator|( const WidenMode &other ) { WidenMode newWM( *this ); newWM |= other; return newWM; }
+		WidenMode operator&( const WidenMode &other ) { WidenMode newWM( *this ); newWM &= other; return newWM; }
+		operator bool() { return widenFirst && widenSecond; }
+
+		bool widenFirst : 1, widenSecond : 1;
+	};
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
