Index: src/ResolvExpr/Alternative.h
===================================================================
--- src/ResolvExpr/Alternative.h	(revision 335d81f9b08d35c3b2d0a6b92a2c05d61d2cd368)
+++ src/ResolvExpr/Alternative.h	(revision fd642d2c3aee132ffbce05c2d7092e4dac7fa8d0)
@@ -29,9 +29,9 @@
 	/// One assertion to resolve
 	struct AssertionItem {
-		DeclarationWithType* decl;
+		const DeclarationWithType* decl;
 		AssertionSetValue info;
-		
+
 		AssertionItem() = default;
-		AssertionItem( DeclarationWithType* decl, const AssertionSetValue& info ) 
+		AssertionItem( const DeclarationWithType* decl, const AssertionSetValue& info )
 		: decl(decl), info(info) {}
 		AssertionItem( const AssertionSet::value_type& e ) : decl(e.first), info(e.second) {}
Index: src/ResolvExpr/TypeEnvironment.cc
===================================================================
--- src/ResolvExpr/TypeEnvironment.cc	(revision 335d81f9b08d35c3b2d0a6b92a2c05d61d2cd368)
+++ src/ResolvExpr/TypeEnvironment.cc	(revision fd642d2c3aee132ffbce05c2d7092e4dac7fa8d0)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 12:19:47 2015
-// Last Modified By : Aaron B. Moss
-// Last Modified On : Mon Jun 18 11:58:00 2018
-// Update Count     : 4
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Jun 18 14:27:00 2019
+// Update Count     : 5
 //
 
@@ -315,5 +315,5 @@
 	}
 
-	bool isFtype( const Type *type ) {
+	bool isFtype( const Type * type ) {
 		if ( dynamic_cast< const FunctionType * >( type ) ) {
 			return true;
@@ -324,5 +324,5 @@
 	}
 
-	bool tyVarCompatible( const TypeDecl::Data & data, Type *type ) {
+	bool tyVarCompatible( const TypeDecl::Data & data, const Type * type ) {
 		switch ( data.kind ) {
 		  case TypeDecl::Dtype:
@@ -336,5 +336,5 @@
 		  case TypeDecl::Ttype:
 			// ttype unifies with any tuple type
-			return dynamic_cast< TupleType * >( type ) || Tuples::isTtype( type );
+			return dynamic_cast< const TupleType * >( type ) || Tuples::isTtype( type );
 		  default:
 			assertf(false, "Unhandled tyvar kind: %d", data.kind);
@@ -343,5 +343,5 @@
 	}
 
-	bool TypeEnvironment::bindVar( TypeInstType *typeInst, Type *bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {
+	bool TypeEnvironment::bindVar( const TypeInstType *typeInst, Type *bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {
 
 		// remove references from other, so that type variables can only bind to value types
@@ -361,5 +361,5 @@
 				// 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();
+				newType->tq = typeInst->tq;
 				if ( unifyInexact( newType.get(), bindTo, *this, need, have, openVars, widen & WidenMode( curClass->allowWidening, true ), indexer, common ) ) {
 					if ( common ) {
@@ -386,6 +386,6 @@
 	}
 
-	bool TypeEnvironment::bindVarToVar( TypeInstType *var1, TypeInstType *var2, 
-			TypeDecl::Data && data, AssertionSet &need, AssertionSet &have, 
+	bool TypeEnvironment::bindVarToVar( const TypeInstType * var1, const TypeInstType * var2,
+			TypeDecl::Data && data, AssertionSet &need, AssertionSet &have,
 			const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {
 
Index: src/ResolvExpr/TypeEnvironment.h
===================================================================
--- src/ResolvExpr/TypeEnvironment.h	(revision 335d81f9b08d35c3b2d0a6b92a2c05d61d2cd368)
+++ src/ResolvExpr/TypeEnvironment.h	(revision fd642d2c3aee132ffbce05c2d7092e4dac7fa8d0)
@@ -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 : Tue Apr 30 23:04:10 2019
-// Update Count     : 9
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Jul 19 17:00:10 2019
+// Update Count     : 10
 //
 
@@ -40,5 +40,5 @@
 	// declarations.
 	//
-	// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this 
+	// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this
 	// comparator.
 	//
@@ -46,12 +46,12 @@
 	// memory layout can alter compilation time in unpredictable ways. For example, the placement
 	// of a line directive can reorder type pointers with respect to each other so that assertions
-	// are seen in different orders, causing a potentially different number of unification calls 
-	// when resolving assertions. I've seen a TU go from 36 seconds to 27 seconds by reordering 
-	// line directives alone, so it would be nice to fix this comparison so that assertions compare 
-	// more consistently. I've tried to modify this to compare on mangle name instead of type as 
-	// the second comparator, but this causes some assertions to never be recorded. More 
+	// are seen in different orders, causing a potentially different number of unification calls
+	// when resolving assertions. I've seen a TU go from 36 seconds to 27 seconds by reordering
+	// line directives alone, so it would be nice to fix this comparison so that assertions compare
+	// more consistently. I've tried to modify this to compare on mangle name instead of type as
+	// the second comparator, but this causes some assertions to never be recorded. More
 	// investigation is needed.
 	struct AssertCompare {
-		bool operator()( DeclarationWithType * d1, DeclarationWithType * d2 ) const {
+		bool operator()( const DeclarationWithType * d1, const DeclarationWithType * d2 ) const {
 			int cmp = d1->get_name().compare( d2->get_name() );
 			return cmp < 0 ||
@@ -65,5 +65,5 @@
 		AssertionSetValue() : isUsed(false), resnSlot(0) {}
 	};
-	typedef std::map< DeclarationWithType *, AssertionSetValue, AssertCompare > AssertionSet;
+	typedef std::map< const DeclarationWithType *, AssertionSetValue, AssertCompare > AssertionSet;
 	typedef std::unordered_map< std::string, TypeDecl::Data > OpenVarSet;
 
@@ -78,5 +78,5 @@
 	struct EqvClass {
 		std::set< std::string > vars;
-		Type *type;
+		Type * type;
 		bool allowWidening;
 		TypeDecl::Data data;
@@ -111,5 +111,5 @@
 		bool isEmpty() const { return env.empty(); }
 		void print( std::ostream &os, Indenter indent = {} ) const;
-		
+
 		/// Simply concatenate the second environment onto this one; no safety checks performed
 		void simpleCombine( const TypeEnvironment &second );
@@ -126,5 +126,5 @@
 		/// Returns false if fails, but does NOT roll back partial changes.
 		bool combine( const TypeEnvironment& second, OpenVarSet& openVars, const SymTab::Indexer& indexer );
-		
+
 		void extractOpenVars( OpenVarSet &openVars ) const;
 		TypeEnvironment *clone() const { return new TypeEnvironment( *this ); }
@@ -134,11 +134,11 @@
 		void addActual( const TypeEnvironment& actualEnv, OpenVarSet& openVars );
 
-		/// Binds the type class represented by `typeInst` to the type `bindTo`; will add 
+		/// 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 widen, const SymTab::Indexer &indexer );
-		
-		/// Binds the type classes represented by `var1` and `var2` together; will add 
+		bool bindVar( const TypeInstType * typeInst, Type * bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widen, 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, TypeDecl::Data && data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
+		bool bindVarToVar( const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
 
 		/// Disallows widening for all bindings in the environment
@@ -151,5 +151,5 @@
 	  private:
 		ClassList env;
-		
+
 		ClassList::iterator internal_lookup( const std::string &var );
 	};
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision 335d81f9b08d35c3b2d0a6b92a2c05d61d2cd368)
+++ src/Tuples/TupleExpansion.cc	(revision fd642d2c3aee132ffbce05c2d7092e4dac7fa8d0)
@@ -350,4 +350,13 @@
 	}
 
+	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.h
===================================================================
--- src/Tuples/Tuples.h	(revision 335d81f9b08d35c3b2d0a6b92a2c05d61d2cd368)
+++ src/Tuples/Tuples.h	(revision fd642d2c3aee132ffbce05c2d7092e4dac7fa8d0)
@@ -52,4 +52,5 @@
 	/// 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 );
 
