Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision db6cdc0f7e39fa424be65d849107ecd0c1e8e90b)
+++ src/AST/Decl.cpp	(revision ddcaff6dd92af1fcf2b1037d2c2eea3374254f99)
@@ -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 db6cdc0f7e39fa424be65d849107ecd0c1e8e90b)
+++ src/AST/Decl.hpp	(revision ddcaff6dd92af1fcf2b1037d2c2eea3374254f99)
@@ -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 db6cdc0f7e39fa424be65d849107ecd0c1e8e90b)
+++ src/AST/Type.cpp	(revision ddcaff6dd92af1fcf2b1037d2c2eea3374254f99)
@@ -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 db6cdc0f7e39fa424be65d849107ecd0c1e8e90b)
+++ src/AST/Type.hpp	(revision ddcaff6dd92af1fcf2b1037d2c2eea3374254f99)
@@ -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 db6cdc0f7e39fa424be65d849107ecd0c1e8e90b)
+++ src/AST/TypeEnvironment.cpp	(revision ddcaff6dd92af1fcf2b1037d2c2eea3374254f99)
@@ -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 db6cdc0f7e39fa424be65d849107ecd0c1e8e90b)
+++ src/AST/TypeEnvironment.hpp	(revision ddcaff6dd92af1fcf2b1037d2c2eea3374254f99)
@@ -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 db6cdc0f7e39fa424be65d849107ecd0c1e8e90b)
+++ src/AST/TypeSubstitution.cpp	(revision ddcaff6dd92af1fcf2b1037d2c2eea3374254f99)
@@ -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 db6cdc0f7e39fa424be65d849107ecd0c1e8e90b)
+++ src/AST/TypeSubstitution.hpp	(revision ddcaff6dd92af1fcf2b1037d2c2eea3374254f99)
@@ -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;
 
