Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision 78de1e5e2ddae0963f8daf4eb79473dc16b5ef30)
+++ src/AST/Decl.cpp	(revision 93c10dee6eb516206f8cb00b620e8ee4abfb79f8)
@@ -125,5 +125,5 @@
 }
 
-std::ostream & operator<< ( std::ostream & out, const TypeDecl::Data & data ) {
+std::ostream & operator<< ( std::ostream & out, const TypeData & data ) {
 	return out << data.kind << ", " << data.isComplete;
 }
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision 78de1e5e2ddae0963f8daf4eb79473dc16b5ef30)
+++ src/AST/Decl.hpp	(revision 93c10dee6eb516206f8cb00b620e8ee4abfb79f8)
@@ -10,6 +10,6 @@
 // Created On       : Thu May 9 10:00:00 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Thu May  5 12:09:00 2022
-// Update Count     : 33
+// Last Modified On : Thu Nov 24  9:44:00 2022
+// Update Count     : 34
 //
 
@@ -191,19 +191,4 @@
 	ptr<Type> init;
 
-	/// Data extracted from a type decl
-	struct Data {
-		Kind kind;
-		bool isComplete;
-
-		Data() : kind( NUMBER_OF_KINDS ), isComplete( false ) {}
-		Data( const TypeDecl * d ) : kind( d->kind ), isComplete( d->sized ) {}
-		Data( Kind k, bool c ) : kind( k ), isComplete( c ) {}
-		Data( const Data & d1, const Data & d2 )
-			: kind( d1.kind ), isComplete( d1.isComplete || d2.isComplete ) {}
-
-		bool operator==( const Data & o ) const { return kind == o.kind && isComplete == o.isComplete; }
-		bool operator!=( const Data & o ) const { return !(*this == o); }
-	};
-
 	TypeDecl(
 		const CodeLocation & loc, const std::string & name, Storage::Classes storage,
@@ -225,5 +210,20 @@
 };
 
-std::ostream & operator<< ( std::ostream &, const TypeDecl::Data & );
+/// Data extracted from a TypeDecl.
+struct TypeData {
+	TypeDecl::Kind kind;
+	bool isComplete;
+
+	TypeData() : kind( TypeDecl::NUMBER_OF_KINDS ), isComplete( false ) {}
+	TypeData( const TypeDecl * d ) : kind( d->kind ), isComplete( d->sized ) {}
+	TypeData( TypeDecl::Kind k, bool c ) : kind( k ), isComplete( c ) {}
+	TypeData( const TypeData & d1, const TypeData & d2 )
+		: kind( d1.kind ), isComplete( d1.isComplete || d2.isComplete ) {}
+
+	bool operator==( const TypeData & o ) const { return kind == o.kind && isComplete == o.isComplete; }
+	bool operator!=( const TypeData & o ) const { return !(*this == o); }
+};
+
+std::ostream & operator<< ( std::ostream &, const TypeData & );
 
 /// C-style typedef `typedef Foo Bar`
Index: src/AST/Type.cpp
===================================================================
--- src/AST/Type.cpp	(revision 78de1e5e2ddae0963f8daf4eb79473dc16b5ef30)
+++ src/AST/Type.cpp	(revision 93c10dee6eb516206f8cb00b620e8ee4abfb79f8)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 13 15:00:00 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Thu Jul 23 14:16:00 2020
-// Update Count     : 5
+// Last Modified On : Thu Nov 24  9:49:00 2022
+// Update Count     : 6
 //
 
@@ -147,4 +147,7 @@
 // --- TypeInstType
 
+TypeInstType::TypeInstType( const TypeEnvKey & key )
+: BaseInstType(key.base->name), base(key.base), kind(key.base->kind), formal_usage(key.formal_usage), expr_id(key.expr_id) {}
+
 bool TypeInstType::operator==( const TypeInstType & other ) const {
 	return base == other.base
@@ -164,11 +167,11 @@
 bool TypeInstType::isComplete() const { return base->sized; }
 
-std::string TypeInstType::TypeEnvKey::typeString() const {
+std::string TypeEnvKey::typeString() const {
 	return std::string("_") + std::to_string(formal_usage)
 		+ "_" + std::to_string(expr_id) + "_" + base->name;
 }
 
-bool TypeInstType::TypeEnvKey::operator==(
-		const TypeInstType::TypeEnvKey & other ) const {
+bool TypeEnvKey::operator==(
+		const TypeEnvKey & other ) const {
 	return base == other.base
 		&& formal_usage == other.formal_usage
@@ -176,6 +179,6 @@
 }
 
-bool TypeInstType::TypeEnvKey::operator<(
-		const TypeInstType::TypeEnvKey & other ) const {
+bool TypeEnvKey::operator<(
+		const TypeEnvKey & other ) const {
 	// TypeEnvKey ordering is an arbitrary total ordering.
 	// It doesn't mean anything but allows for a sorting.
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision 78de1e5e2ddae0963f8daf4eb79473dc16b5ef30)
+++ src/AST/Type.hpp	(revision 93c10dee6eb516206f8cb00b620e8ee4abfb79f8)
@@ -10,6 +10,6 @@
 // Created On       : Thu May 9 10:00:00 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Jul 14 15:54:00 2021
-// Update Count     : 7
+// Last Modified On : Thu Nov 24  9:47:00 2022
+// Update Count     : 8
 //
 
@@ -390,4 +390,6 @@
 };
 
+struct TypeEnvKey;
+
 /// instance of named type alias (typedef or variable)
 class TypeInstType final : public BaseInstType {
@@ -401,20 +403,4 @@
 	int expr_id = 0;
 
-	// compact representation used for map lookups.
-	struct TypeEnvKey {
-		const TypeDecl * base = nullptr;
-		int formal_usage = 0;
-		int expr_id = 0;
-
-		TypeEnvKey() = default;
-		TypeEnvKey(const TypeDecl * base, int formal_usage = 0, int expr_id = 0)
-		: base(base), formal_usage(formal_usage), expr_id(expr_id) {}
-		TypeEnvKey(const TypeInstType & inst)
-		: base(inst.base), formal_usage(inst.formal_usage), expr_id(inst.expr_id) {}
-		std::string typeString() const;
-		bool operator==(const TypeEnvKey & other) const;
-		bool operator<(const TypeEnvKey & other) const;
-	};
-
 	bool operator==(const TypeInstType & other) const;
 
@@ -433,6 +419,5 @@
 	TypeInstType( const TypeInstType & o ) = default;
 
-	TypeInstType( const TypeEnvKey & key )
-	: BaseInstType(key.base->name), base(key.base), kind(key.base->kind), formal_usage(key.formal_usage), expr_id(key.expr_id) {}
+	TypeInstType( const TypeEnvKey & key );
 
 	/// sets `base`, updating `kind` correctly
@@ -453,4 +438,20 @@
 	TypeInstType * clone() const override { return new TypeInstType{ *this }; }
 	MUTATE_FRIEND
+};
+
+/// Compact representation of TypeInstType used for map lookups.
+struct TypeEnvKey {
+	const TypeDecl * base = nullptr;
+	int formal_usage = 0;
+	int expr_id = 0;
+
+	TypeEnvKey() = default;
+	TypeEnvKey(const TypeDecl * base, int formal_usage = 0, int expr_id = 0)
+	: base(base), formal_usage(formal_usage), expr_id(expr_id) {}
+	TypeEnvKey(const TypeInstType & inst)
+	: base(inst.base), formal_usage(inst.formal_usage), expr_id(inst.expr_id) {}
+	std::string typeString() const;
+	bool operator==(const TypeEnvKey & other) const;
+	bool operator<(const TypeEnvKey & other) const;
 };
 
@@ -560,6 +561,6 @@
 namespace std {
 	template<>
-	struct hash<typename ast::TypeInstType::TypeEnvKey> {
-		size_t operator() (const ast::TypeInstType::TypeEnvKey & x) const {
+	struct hash<typename ast::TypeEnvKey> {
+		size_t operator() (const ast::TypeEnvKey & x) const {
 			const size_t p = 1000007;
 			size_t res = reinterpret_cast<size_t>(x.base);
Index: src/AST/TypeEnvironment.cpp
===================================================================
--- src/AST/TypeEnvironment.cpp	(revision 78de1e5e2ddae0963f8daf4eb79473dc16b5ef30)
+++ src/AST/TypeEnvironment.cpp	(revision 93c10dee6eb516206f8cb00b620e8ee4abfb79f8)
@@ -82,5 +82,5 @@
 }
 
-const EqvClass * TypeEnvironment::lookup( const TypeInstType::TypeEnvKey & var ) const {
+const EqvClass * TypeEnvironment::lookup( const TypeEnvKey & var ) const {
 	for ( ClassList::const_iterator i = env.begin(); i != env.end(); ++i ) {
 		if ( i->vars.find( var ) != i->vars.end() ) return &*i;
@@ -122,5 +122,5 @@
 void TypeEnvironment::writeToSubstitution( TypeSubstitution & sub ) const {
 	for ( const auto & clz : env ) {
-		TypeInstType::TypeEnvKey clzRep;
+		TypeEnvKey clzRep;
 		bool first = true;
 		for ( const auto & var : clz.vars ) {
@@ -146,8 +146,8 @@
 	struct Occurs : public ast::WithVisitorRef<Occurs> {
 		bool result;
-		std::unordered_set< TypeInstType::TypeEnvKey > vars;
+		std::unordered_set< TypeEnvKey > vars;
 		const TypeEnvironment & tenv;
 
-		Occurs( const TypeInstType::TypeEnvKey & var, const TypeEnvironment & env )
+		Occurs( const TypeEnvKey & var, const TypeEnvironment & env )
 		: result( false ), vars(), tenv( env ) {
 			if ( const EqvClass * clz = tenv.lookup( var ) ) {
@@ -170,5 +170,5 @@
 
 	/// true if `var` occurs in `ty` under `env`
-	bool occurs( const Type * ty, const TypeInstType::TypeEnvKey & var, const TypeEnvironment & env ) {
+	bool occurs( const Type * ty, const TypeEnvKey & var, const TypeEnvironment & env ) {
 		Pass<Occurs> occur{ var, env };
 		maybe_accept( ty, occur );
@@ -258,5 +258,5 @@
 namespace {
 	/// true if the given type can be bound to the given type variable
-	bool tyVarCompatible( const TypeDecl::Data & data, const Type * type ) {
+	bool tyVarCompatible( const TypeData & data, const Type * type ) {
 		switch ( data.kind ) {
 		  case TypeDecl::Dtype:
@@ -279,5 +279,5 @@
 
 bool TypeEnvironment::bindVar(
-		const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data,
+		const TypeInstType * typeInst, const Type * bindTo, const TypeData & data,
 		AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen,
 		const SymbolTable & symtab
@@ -319,5 +319,5 @@
 
 bool TypeEnvironment::bindVarToVar(
-		const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data,
+		const TypeInstType * var1, const TypeInstType * var2, TypeData && data,
 		AssertionSet & need, AssertionSet & have, const OpenVarSet & open,
 		WidenMode widen, const SymbolTable & symtab
@@ -457,5 +457,5 @@
 }
 
-TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const TypeInstType::TypeEnvKey & var ) {
+TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const TypeEnvKey & var ) {
 	for ( ClassList::iterator i = env.begin(); i != env.end(); ++i ) {
 		if ( i->vars.count( var ) ) return i;
Index: src/AST/TypeEnvironment.hpp
===================================================================
--- src/AST/TypeEnvironment.hpp	(revision 78de1e5e2ddae0963f8daf4eb79473dc16b5ef30)
+++ src/AST/TypeEnvironment.hpp	(revision 93c10dee6eb516206f8cb00b620e8ee4abfb79f8)
@@ -79,5 +79,5 @@
 
 /// Set of open variables
-using OpenVarSet = std::unordered_map< TypeInstType::TypeEnvKey, TypeDecl::Data >;
+using OpenVarSet = std::unordered_map< TypeEnvKey, TypeData >;
 
 /// Merges one set of open vars into another
@@ -95,8 +95,8 @@
 /// they bind to.
 struct EqvClass {
-	std::unordered_set< TypeInstType::TypeEnvKey > vars;
+	std::unordered_set< TypeEnvKey > vars;
 	ptr<Type> bound;
 	bool allowWidening;
-	TypeDecl::Data data;
+	TypeData data;
 
 	EqvClass() : vars(), bound(), allowWidening( true ), data() {}
@@ -111,9 +111,9 @@
 
 	/// Singleton class constructor from substitution
-	EqvClass( const TypeInstType::TypeEnvKey & v, const Type * b )
+	EqvClass( const TypeEnvKey & v, const Type * b )
 	: vars{ v }, bound( b ), allowWidening( false ), data( TypeDecl::Dtype, false ) {}
 
 	/// Single-var constructor (strips qualifiers from bound type)
-	EqvClass( const TypeInstType::TypeEnvKey & v, const Type * b, bool w, const TypeDecl::Data & d )
+	EqvClass( const TypeEnvKey & v, const Type * b, bool w, const TypeData & d )
 	: vars{ v }, bound( b ), allowWidening( w ), data( d ) {
 		reset_qualifiers( bound );
@@ -121,5 +121,5 @@
 
 	/// Double-var constructor
-	EqvClass( const TypeInstType::TypeEnvKey & v, const TypeInstType::TypeEnvKey & u, bool w, const TypeDecl::Data & d )
+	EqvClass( const TypeEnvKey & v, const TypeEnvKey & u, bool w, const TypeData & d )
 	: vars{ v, u }, bound(), allowWidening( w ), data( d ) {}
 
@@ -137,5 +137,5 @@
 public:
 	/// Finds the equivalence class containing a variable; nullptr for none such
-	const EqvClass * lookup( const TypeInstType::TypeEnvKey & var ) const;
+	const EqvClass * lookup( const TypeEnvKey & var ) const;
 
 	/// Add a new equivalence class for each type variable
@@ -181,5 +181,5 @@
 	/// needed. Returns false on failure.
 	bool bindVar(
-		const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data,
+		const TypeInstType * typeInst, const Type * bindTo, const TypeData & data,
 		AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
 		ResolvExpr::WidenMode widen, const SymbolTable & symtab );
@@ -188,5 +188,5 @@
 	/// classes if needed. Returns false on failure.
 	bool bindVarToVar(
-		const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data,
+		const TypeInstType * var1, const TypeInstType * var2, TypeData && data,
 		AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
 		ResolvExpr::WidenMode widen, const SymbolTable & symtab );
@@ -213,5 +213,5 @@
 
 	/// Private lookup API; returns array index of string, or env.size() for not found
-	ClassList::iterator internal_lookup( const TypeInstType::TypeEnvKey & );
+	ClassList::iterator internal_lookup( const TypeEnvKey & );
 };
 
Index: src/AST/TypeSubstitution.cpp
===================================================================
--- src/AST/TypeSubstitution.cpp	(revision 78de1e5e2ddae0963f8daf4eb79473dc16b5ef30)
+++ src/AST/TypeSubstitution.cpp	(revision 93c10dee6eb516206f8cb00b620e8ee4abfb79f8)
@@ -52,5 +52,5 @@
 }
 
-void TypeSubstitution::add( const TypeInstType::TypeEnvKey & key, const Type * actualType) {
+void TypeSubstitution::add( const TypeEnvKey & key, const Type * actualType) {
 	typeMap[ key ] = actualType;
 }
@@ -64,5 +64,5 @@
 
 const Type *TypeSubstitution::lookup(
-		const TypeInstType::TypeEnvKey & formalType ) const {
+		const TypeEnvKey & formalType ) const {
 	TypeMap::const_iterator i = typeMap.find( formalType );
 
@@ -85,5 +85,5 @@
 
 const Type *TypeSubstitution::lookup( const TypeInstType * formalType ) const {
-	return lookup( ast::TypeInstType::TypeEnvKey( *formalType ) );
+	return lookup( ast::TypeEnvKey( *formalType ) );
 }
 
Index: src/AST/TypeSubstitution.hpp
===================================================================
--- src/AST/TypeSubstitution.hpp	(revision 78de1e5e2ddae0963f8daf4eb79473dc16b5ef30)
+++ src/AST/TypeSubstitution.hpp	(revision 93c10dee6eb516206f8cb00b620e8ee4abfb79f8)
@@ -72,8 +72,8 @@
 
 	void add( const TypeInstType * formalType, const Type *actualType );
-	void add( const TypeInstType::TypeEnvKey & key, const Type *actualType );
+	void add( const TypeEnvKey & key, const Type *actualType );
 	void add( const TypeSubstitution &other );
 	void remove( const TypeInstType * formalType );
-	const Type *lookup( const TypeInstType::TypeEnvKey & formalType ) const;
+	const Type *lookup( const TypeEnvKey & formalType ) const;
 	const Type *lookup( const TypeInstType * formalType ) const;
 	bool empty() const;
@@ -105,5 +105,5 @@
 	friend class Pass;
 
-	typedef std::unordered_map< TypeInstType::TypeEnvKey, ptr<Type> > TypeMap;
+	typedef std::unordered_map< TypeEnvKey, ptr<Type> > TypeMap;
 	TypeMap typeMap;
 
@@ -184,5 +184,5 @@
 		int subCount = 0;
 		bool freeOnly;
-		typedef std::unordered_set< TypeInstType::TypeEnvKey > BoundVarsType;
+		typedef std::unordered_set< TypeEnvKey > BoundVarsType;
 		BoundVarsType boundVars;
 
Index: src/GenPoly/GenPoly.cc
===================================================================
--- src/GenPoly/GenPoly.cc	(revision 78de1e5e2ddae0963f8daf4eb79473dc16b5ef30)
+++ src/GenPoly/GenPoly.cc	(revision 93c10dee6eb516206f8cb00b620e8ee4abfb79f8)
@@ -783,5 +783,5 @@
 	const ast::FunctionType * function = getFunctionType( expr->func->result );
 	assertf( function, "ApplicationExpr has non-function type: %s", toString( expr->func->result ).c_str() );
-	TypeVarMap exprTyVars = { ast::TypeDecl::Data() };
+	TypeVarMap exprTyVars = { ast::TypeData() };
 	makeTypeVarMap( function, exprTyVars );
 	return needsBoxing( param, arg, exprTyVars, subst );
@@ -793,5 +793,5 @@
 
 void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ) {
-	typeVars.insert( *type, ast::TypeDecl::Data( type->base ) );
+	typeVars.insert( *type, ast::TypeData( type->base ) );
 }
 
Index: src/GenPoly/GenPoly.h
===================================================================
--- src/GenPoly/GenPoly.h	(revision 78de1e5e2ddae0963f8daf4eb79473dc16b5ef30)
+++ src/GenPoly/GenPoly.h	(revision 93c10dee6eb516206f8cb00b620e8ee4abfb79f8)
@@ -30,5 +30,5 @@
 
 	typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;
-	using TypeVarMap = ErasableScopedMap< ast::TypeInstType::TypeEnvKey, ast::TypeDecl::Data >;
+	using TypeVarMap = ErasableScopedMap< ast::TypeEnvKey, ast::TypeData >;
 
 	/// Replaces a TypeInstType by its referrent in the environment, if applicable
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision 78de1e5e2ddae0963f8daf4eb79473dc16b5ef30)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision 93c10dee6eb516206f8cb00b620e8ee4abfb79f8)
@@ -221,5 +221,5 @@
 	) {
 		for ( auto & tyvar : type->forall ) {
-			unifiableVars[ *tyvar ] = ast::TypeDecl::Data{ tyvar->base };
+			unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base };
 		}
 		for ( auto & assn : type->assertions ) {
Index: src/ResolvExpr/FindOpenVars.cc
===================================================================
--- src/ResolvExpr/FindOpenVars.cc	(revision 78de1e5e2ddae0963f8daf4eb79473dc16b5ef30)
+++ src/ResolvExpr/FindOpenVars.cc	(revision 93c10dee6eb516206f8cb00b620e8ee4abfb79f8)
@@ -113,5 +113,5 @@
 				if ( nextIsOpen ) {
 					for ( auto & decl : type->forall ) {
-						open[ *decl ] = ast::TypeDecl::Data{ decl->base };
+						open[ *decl ] = ast::TypeData{ decl->base };
 					}
 					for ( auto & assert : type->assertions ) {
@@ -120,5 +120,5 @@
 				} else {
 					for ( auto & decl : type->forall ) {
-						closed[ *decl ] = ast::TypeDecl::Data{ decl->base };	
+						closed[ *decl ] = ast::TypeData{ decl->base };
 					}
 					for ( auto & assert : type->assertions ) {
Index: src/ResolvExpr/RenameVars.cc
===================================================================
--- src/ResolvExpr/RenameVars.cc	(revision 78de1e5e2ddae0963f8daf4eb79473dc16b5ef30)
+++ src/ResolvExpr/RenameVars.cc	(revision 93c10dee6eb516206f8cb00b620e8ee4abfb79f8)
@@ -42,5 +42,5 @@
 		int next_usage_id = 1;
 		ScopedMap< std::string, std::string > nameMap;
-		ScopedMap< std::string, ast::TypeInstType::TypeEnvKey > idMap;
+		ScopedMap< std::string, ast::TypeEnvKey > idMap;
 	public:
 		void reset() {
@@ -121,6 +121,6 @@
 					assert(false);
 				}
-				idMap[ td->name ] = ast::TypeInstType::TypeEnvKey(*mut);
-				
+				idMap[ td->name ] = ast::TypeEnvKey( *mut );
+
 				td = mut;
 			}
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision 78de1e5e2ddae0963f8daf4eb79473dc16b5ef30)
+++ src/ResolvExpr/Unify.cc	(revision 93c10dee6eb516206f8cb00b620e8ee4abfb79f8)
@@ -1166,5 +1166,5 @@
 			if ( entry1->second.kind != entry2->second.kind ) return false;
 			return env.bindVarToVar(
-				var1, var2, ast::TypeDecl::Data{ entry1->second, entry2->second }, need, have,
+				var1, var2, ast::TypeData{ entry1->second, entry2->second }, need, have,
 				open, widen, symtab );
 		} else if ( isopen1 ) {
