Index: src/AST/Type.cpp
===================================================================
--- src/AST/Type.cpp	(revision a167c70c7fa1e05fd7fb5472f69e13eba33b22b7)
+++ src/AST/Type.cpp	(revision 63d1ebe7115e4450a16b96fb0ea497249a457c47)
@@ -147,4 +147,10 @@
 // --- TypeInstType
 
+bool TypeInstType::operator==( const TypeInstType & other ) const {
+	return base == other.base
+		&& formal_usage == other.formal_usage
+		&& expr_id == other.expr_id;
+}
+
 TypeInstType::TypeInstType( const TypeDecl * b,
 	CV::Qualifiers q, std::vector<ptr<Attribute>> && as )
@@ -157,4 +163,33 @@
 
 bool TypeInstType::isComplete() const { return base->sized; }
+
+std::string TypeInstType::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 {
+	return base == other.base
+		&& formal_usage == other.formal_usage
+		&& expr_id == other.expr_id;
+}
+
+bool TypeInstType::TypeEnvKey::operator<(
+		const TypeInstType::TypeEnvKey & other ) const {
+	// TypeEnvKey ordering is an arbitrary total ordering.
+	// It doesn't mean anything but allows for a sorting.
+	if ( base < other.base ) {
+		return true;
+	} else if ( other.base < base ) {
+		return false;
+	} else if ( formal_usage < other.formal_usage ) {
+		return true;
+	} else if ( other.formal_usage < formal_usage ) {
+		return false;
+	} else {
+		return expr_id < other.expr_id;
+	}
+}
 
 // --- TupleType
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision a167c70c7fa1e05fd7fb5472f69e13eba33b22b7)
+++ src/AST/Type.hpp	(revision 63d1ebe7115e4450a16b96fb0ea497249a457c47)
@@ -408,11 +408,14 @@
 
 		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 { return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + base->name; }
-		bool operator==(const TypeEnvKey & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }
+		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 { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }
+	bool operator==(const TypeInstType & other) const;
 
 	TypeInstType(
Index: src/GenPoly/GenPoly.cc
===================================================================
--- src/GenPoly/GenPoly.cc	(revision a167c70c7fa1e05fd7fb5472f69e13eba33b22b7)
+++ src/GenPoly/GenPoly.cc	(revision 63d1ebe7115e4450a16b96fb0ea497249a457c47)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Fri Oct  7 15:25:00 2022
-// Update Count     : 16
+// Last Modified On : Mon Oct 24 15:19:00 2022
+// Update Count     : 17
 //
 
@@ -194,5 +194,5 @@
 
 	if ( auto inst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
-		if ( typeVars.find( inst->typeString() ) != typeVars.end() ) return type;
+		if ( typeVars.find( *inst ) != typeVars.end() ) return type;
 	} else if ( auto array = dynamic_cast< const ast::ArrayType * >( type ) ) {
 		return isPolyType( array->base, subst );
@@ -227,5 +227,5 @@
 
 	if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
-		auto var = typeVars.find( inst->name );
+		auto var = typeVars.find( *inst );
 		if ( var != typeVars.end() && var->second.isComplete ) {
 
@@ -784,5 +784,5 @@
 
 void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ) {
-	typeVars.insert( type->typeString(), ast::TypeDecl::Data( type->base ) );
+	typeVars.insert( *type, ast::TypeDecl::Data( type->base ) );
 }
 
@@ -816,11 +816,4 @@
 	}
 
-void printTypeVarMap( std::ostream &os, const TypeVarMap & typeVars ) {
-	for ( auto const & pair : typeVars ) {
-		os << pair.first << " (" << pair.second << ") ";
-	} // for
-	os << std::endl;
-}
-
 } // namespace GenPoly
 
Index: src/GenPoly/GenPoly.h
===================================================================
--- src/GenPoly/GenPoly.h	(revision a167c70c7fa1e05fd7fb5472f69e13eba33b22b7)
+++ src/GenPoly/GenPoly.h	(revision 63d1ebe7115e4450a16b96fb0ea497249a457c47)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Fri Oct  7 15:06:00 2022
-// Update Count     : 9
+// Last Modified On : Mon Oct 24 15:18:00 2022
+// Update Count     : 11
 //
 
@@ -22,4 +22,5 @@
 #include "AST/Decl.hpp"           // for TypeDecl::Data
 #include "AST/Fwd.hpp"            // for ApplicationExpr, BaseInstType, Func...
+#include "AST/Type.hpp"           // for TypeInstType::TypeEnvKey
 #include "SymTab/Mangler.h"       // for Mangler
 #include "SynTree/Declaration.h"  // for TypeDecl::Data, AggregateDecl, Type...
@@ -28,10 +29,10 @@
 namespace GenPoly {
 
-	// TODO Via some tricks this works for ast::TypeDecl::Data as well.
 	typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;
-	using TypeVarMap = ErasableScopedMap< std::string, ast::TypeDecl::Data >;
+	using TypeVarMap = ErasableScopedMap< ast::TypeInstType::TypeEnvKey, ast::TypeDecl::Data >;
 
 	/// Replaces a TypeInstType by its referrent in the environment, if applicable
 	Type* replaceTypeInst( Type* type, const TypeSubstitution* env );
+	const ast::Type * replaceTypeInst( const ast::Type *, const ast::TypeSubstitution * );
 
 	/// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided
@@ -53,4 +54,5 @@
 	/// true iff function has dynamic-layout return type under the type variable map generated from its forall-parameters
 	ReferenceToType *isDynRet( FunctionType *function );
+	const ast::BaseInstType *isDynRet( const ast::FunctionType * func );
 
 	/// A function needs an adapter if it returns a dynamic-layout value or if any of its parameters have dynamic-layout type
@@ -112,5 +114,4 @@
 	/// Prints type variable map
 	void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap );
-	void printTypeVarMap( std::ostream &os, const TypeVarMap & typeVars );
 
 	/// Gets the mangled name of this type; alias for SymTab::Mangler::mangleType().
@@ -128,4 +129,7 @@
 	/// Gets the name of the layout function for a given aggregate type, given its declaration
 	inline std::string layoutofName( AggregateDecl *decl ) { return std::string( "_layoutof_" ) + decl->get_name(); }
+	inline std::string layoutofName( ast::AggregateDecl const * decl ) {
+		return std::string( "_layoutof_" ) + decl->name;
+	}
 
 } // namespace GenPoly
Index: src/GenPoly/ScrubTyVars.cc
===================================================================
--- src/GenPoly/ScrubTyVars.cc	(revision a167c70c7fa1e05fd7fb5472f69e13eba33b22b7)
+++ src/GenPoly/ScrubTyVars.cc	(revision 63d1ebe7115e4450a16b96fb0ea497249a457c47)
@@ -195,5 +195,5 @@
 	}
 
-	auto typeVar = typeVars->find( type->name );
+	auto typeVar = typeVars->find( *type );
 	if ( typeVar == typeVars->end() ) {
 		return type;
