Index: src/GenPoly/GenPoly.cc
===================================================================
--- src/GenPoly/GenPoly.cc	(revision 8c91088c3e562b46c9a7b971487a1d954e9f735a)
+++ src/GenPoly/GenPoly.cc	(revision c8837e5f0d9b9ee1ca54309ed7dd8ac35aeb40ff)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Sep 14  9:24:00 2022
-// Update Count     : 15
+// Last Modified On : Fri Oct  7 15:25:00 2022
+// Update Count     : 16
 //
 
@@ -64,13 +64,4 @@
 		}
 
-		__attribute__((unused))
-		bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TyVarMap & tyVars, const ast::TypeSubstitution * env) {
-			for (auto &param : params) {
-				auto paramType = param.strict_as<ast::TypeExpr>();
-				if (isPolyType(paramType->type, tyVars, env)) return true;
-			}
-			return false;
-		}
-
 		/// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present
 		bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
@@ -83,9 +74,12 @@
 		}
 
-		bool hasDynParams( const std::vector<ast::ptr<ast::Expr>> & params, const TyVarMap &tyVars, const ast::TypeSubstitution *typeSubs ) {
-			for ( ast::ptr<ast::Expr> const & param : params ) {
-				auto paramType = param.as<ast::TypeExpr>();
-				assertf( paramType, "Aggregate parameters should be type expressions." );
-				if ( isDynType( paramType->type, tyVars, typeSubs ) ) {
+		bool hasDynParams(
+				const std::vector<ast::ptr<ast::Expr>> & params,
+				const TypeVarMap & typeVars,
+				const ast::TypeSubstitution * subst ) {
+			for ( ast::ptr<ast::Expr> const & paramExpr : params ) {
+				auto param = paramExpr.as<ast::TypeExpr>();
+				assertf( param, "Aggregate parameters should be type expressions." );
+				if ( isDynType( param->type.get(), typeVars, subst ) ) {
 					return true;
 				}
@@ -195,4 +189,20 @@
 	}
 
+const ast::Type * isPolyType( const ast::Type * type,
+		const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) {
+	type = replaceTypeInst( type, subst );
+
+	if ( auto inst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
+		if ( typeVars.find( inst->typeString() ) != typeVars.end() ) return type;
+	} else if ( auto array = dynamic_cast< const ast::ArrayType * >( type ) ) {
+		return isPolyType( array->base, subst );
+	} else if ( auto sue = dynamic_cast< const ast::StructInstType * >( type ) ) {
+		if ( hasPolyParams( sue->params, subst ) ) return type;
+	} else if ( auto sue = dynamic_cast< const ast::UnionInstType * >( type ) ) {
+		if ( hasPolyParams( sue->params, subst ) ) return type;
+	}
+	return nullptr;
+}
+
 	ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
 		type = replaceTypeInst( type, env );
@@ -211,23 +221,25 @@
 	}
 
-	const ast::BaseInstType *isDynType( const ast::Type *type, const TyVarMap &tyVars, const ast::TypeSubstitution *typeSubs ) {
-		type = replaceTypeInst( type, typeSubs );
-
-		if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
-			auto var = tyVars.find( inst->name );
-			if ( var != tyVars.end() && var->second.isComplete ) {
-				return inst;
-			}
-		} else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
-			if ( hasDynParams( inst->params, tyVars, typeSubs ) ) {
-				return inst;
-			}
-		} else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
-			if ( hasDynParams( inst->params, tyVars, typeSubs ) ) {
-				return inst;
-			}
-		}
-		return nullptr;
-	}
+const ast::BaseInstType * isDynType(
+		const ast::Type * type, const TypeVarMap & typeVars,
+		const ast::TypeSubstitution * subst ) {
+	type = replaceTypeInst( type, subst );
+
+	if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
+		auto var = typeVars.find( inst->name );
+		if ( var != typeVars.end() && var->second.isComplete ) {
+
+		}
+	} else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
+		if ( hasDynParams( inst->params, typeVars, subst ) ) {
+			return inst;
+		}
+	} else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
+		if ( hasDynParams( inst->params, typeVars, subst ) ) {
+			return inst;
+		}
+	}
+	return nullptr;
+}
 
 	ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &forallTypes ) {
@@ -236,4 +248,11 @@
 		return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes );
 	}
+
+const ast::BaseInstType *isDynRet(
+		const ast::FunctionType * type, const TypeVarMap & typeVars ) {
+	if ( type->returns.empty() ) return nullptr;
+
+	return isDynType( type->returns.front(), typeVars );
+}
 
 	ReferenceToType *isDynRet( FunctionType *function ) {
@@ -260,4 +279,16 @@
 	}
 
+bool needsAdapter(
+		ast::FunctionType const * adaptee, const TypeVarMap & typeVars ) {
+	if ( isDynRet( adaptee, typeVars ) ) return true;
+
+	for ( auto param : adaptee->params ) {
+		if ( isDynType( param, typeVars ) ) {
+			return true;
+		}
+	}
+	return false;
+}
+
 	Type *isPolyPtr( Type *type, const TypeSubstitution *env ) {
 		type = replaceTypeInst( type, env );
@@ -311,4 +342,24 @@
 		return isPolyType( type, tyVars, env );
 	}
+
+ast::Type const * hasPolyBase(
+		ast::Type const * type, const TypeVarMap & typeVars,
+		int * levels, const ast::TypeSubstitution * subst ) {
+	int level_count = 0;
+
+	while ( true ) {
+		type = replaceTypeInst( type, subst );
+
+		if ( auto ptr = dynamic_cast<ast::PointerType const *>( type ) ) {
+			type = ptr->base;
+			++level_count;
+		} else {
+			break;
+		}
+	}
+
+	if ( nullptr != levels ) { *levels = level_count; }
+	return isPolyType( type, typeVars, subst );
+}
 
 	bool includesPolyType( Type *type, const TypeSubstitution *env ) {
@@ -685,12 +736,4 @@
 }
 
-	namespace {
-		// temporary hack to avoid re-implementing anything related to TyVarMap
-		// does this work? these two structs have identical definitions.
-		inline TypeDecl::Data convData(const ast::TypeDecl::Data & data) {
-			return *reinterpret_cast<const TypeDecl::Data *>(&data);
-		}
-	}
-
 	bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) {
 		// is parameter is not polymorphic, don't need to box
@@ -703,12 +746,17 @@
 	}
 
-	bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TyVarMap &exprTyVars, const ast::TypeSubstitution * env) {
-		// is parameter is not polymorphic, don't need to box
-		if ( ! isPolyType( param, exprTyVars ) ) return false;
-		ast::ptr<ast::Type> newType = arg;
-		if ( env ) env->apply( newType );
-		// if the argument's type is polymorphic, we don't need to box again!
-		return ! isPolyType( newType );
-	}
+bool needsBoxing( const ast::Type * param, const ast::Type * arg,
+		const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) {
+	// Don't need to box if the parameter is not polymorphic.
+	if ( !isPolyType( param, typeVars ) ) return false;
+
+	ast::ptr<ast::Type> newType = arg;
+	if ( subst ) {
+		int count = subst->apply( newType );
+		(void)count;
+	}
+	// Only need to box if the argument is not also polymorphic.
+	return !isPolyType( newType );
+}
 
 	bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) {
@@ -720,12 +768,14 @@
 	}
 
-	bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * appExpr, const ast::TypeSubstitution * env) {
-		const ast::FunctionType * function = getFunctionType(appExpr->func->result);
-		assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->func->result ).c_str() );
-		TyVarMap exprTyVars(TypeDecl::Data{});
-		makeTyVarMap(function, exprTyVars);
-		return needsBoxing(param, arg, exprTyVars, env);
-
-	}
+bool needsBoxing(
+		const ast::Type * param, const ast::Type * arg,
+		const ast::ApplicationExpr * expr,
+		const ast::TypeSubstitution * subst ) {
+	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() };
+	makeTypeVarMap( function, exprTyVars );
+	return needsBoxing( param, arg, exprTyVars, subst );
+}
 
 	void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) {
@@ -733,7 +783,7 @@
 	}
 
-	void addToTyVarMap( const ast::TypeInstType * tyVar, TyVarMap & tyVarMap) {
-		tyVarMap.insert(tyVar->typeString(), convData(ast::TypeDecl::Data{tyVar->base}));
-	}
+void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ) {
+	typeVars.insert( type->typeString(), ast::TypeDecl::Data( type->base ) );
+}
 
 	void makeTyVarMap( Type *type, TyVarMap &tyVarMap ) {
@@ -747,15 +797,15 @@
 	}
 
-	void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap) {
-		if (auto ptype = dynamic_cast<const ast::FunctionType *>(type)) {
- 			for (auto & tyVar : ptype->forall) {
-				assert (tyVar);
-				addToTyVarMap(tyVar, tyVarMap);
-			}
-		}
-		if (auto pointer = dynamic_cast<const ast::PointerType *>(type)) {
-			makeTyVarMap(pointer->base, tyVarMap);
-		}
-	}
+void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ) {
+	if ( auto func = dynamic_cast<ast::FunctionType const *>( type ) ) {
+		for ( auto & typeVar : func->forall ) {
+			assert( typeVar );
+			addToTypeVarMap( typeVar, typeVars );
+		}
+	}
+	if ( auto pointer = dynamic_cast<ast::PointerType const *>( type ) ) {
+		makeTypeVarMap( pointer->base, typeVars );
+	}
+}
 
 	void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ) {
@@ -766,4 +816,11 @@
 	}
 
+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 8c91088c3e562b46c9a7b971487a1d954e9f735a)
+++ src/GenPoly/GenPoly.h	(revision c8837e5f0d9b9ee1ca54309ed7dd8ac35aeb40ff)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Fri Aug 19 16:03:00 2022
-// Update Count     : 8
+// Last Modified On : Fri Oct  7 15:06:00 2022
+// Update Count     : 9
 //
 
@@ -20,5 +20,6 @@
 
 #include "ErasableScopedMap.h"    // for ErasableScopedMap
-#include "AST/Fwd.hpp"
+#include "AST/Decl.hpp"           // for TypeDecl::Data
+#include "AST/Fwd.hpp"            // for ApplicationExpr, BaseInstType, Func...
 #include "SymTab/Mangler.h"       // for Mangler
 #include "SynTree/Declaration.h"  // for TypeDecl::Data, AggregateDecl, Type...
@@ -29,4 +30,5 @@
 	// 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 >;
 
 	/// Replaces a TypeInstType by its referrent in the environment, if applicable
@@ -39,12 +41,13 @@
 	/// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided
 	Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
-	const ast::Type * isPolyType(const ast::Type * type, const TyVarMap & tyVars, const ast::TypeSubstitution * env = nullptr);
+	const ast::Type * isPolyType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = nullptr );
 
 	/// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided
 	ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
-	const ast::BaseInstType *isDynType( const ast::Type *type, const TyVarMap &tyVars, const ast::TypeSubstitution *typeSubs = 0 );
+	const ast::BaseInstType *isDynType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = 0 );
 
 	/// true iff function has dynamic-layout return type under the given type variable map
 	ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &tyVars );
+	const ast::BaseInstType *isDynRet( const ast::FunctionType * type, const TypeVarMap & typeVars );
 
 	/// true iff function has dynamic-layout return type under the type variable map generated from its forall-parameters
@@ -53,4 +56,5 @@
 	/// A function needs an adapter if it returns a dynamic-layout value or if any of its parameters have dynamic-layout type
 	bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVarr );
+	bool needsAdapter( ast::FunctionType const * adaptee, const TypeVarMap & typeVars );
 
 	/// returns polymorphic type if is pointer to polymorphic type, NULL otherwise; will look up substitution in env if provided
@@ -59,4 +63,5 @@
 	/// returns polymorphic type if is pointer to polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided
 	Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
+	const ast::Type * isPolyPtr( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * env = 0 );
 
 	/// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type, returns the base type, NULL otherwise;
@@ -67,4 +72,5 @@
 	/// N will be stored in levels, if provided, will look up substitution in env if provided
 	Type *hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels = 0, const TypeSubstitution *env = 0 );
+	const ast::Type * hasPolyBase( const ast::Type * type, const TypeVarMap & typeVars, int * levels = 0, const ast::TypeSubstitution * env = 0 );
 
 	/// true iff this type or some base of this type after dereferencing pointers is either polymorphic or a generic type with at least one
@@ -90,19 +96,21 @@
 	/// true if arg requires boxing given exprTyVars
 	bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env );
-	bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TyVarMap &exprTyVars, const ast::TypeSubstitution * env);
+	bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst );
 
 	/// true if arg requires boxing in the call to appExpr
 	bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env );
-	bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * appExpr, const ast::TypeSubstitution * env);
+	bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * expr, const ast::TypeSubstitution * subst );
 
 	/// Adds the type variable `tyVar` to `tyVarMap`
 	void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap );
+	void addToTypeVarMap( const ast::TypeDecl * type, TypeVarMap & typeVars );
 
 	/// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap`
 	void makeTyVarMap( Type *type, TyVarMap &tyVarMap );
-	void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap);
+	void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars );
 
 	/// 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().
Index: src/GenPoly/ScrubTyVars.cc
===================================================================
--- src/GenPoly/ScrubTyVars.cc	(revision 8c91088c3e562b46c9a7b971487a1d954e9f735a)
+++ src/GenPoly/ScrubTyVars.cc	(revision c8837e5f0d9b9ee1ca54309ed7dd8ac35aeb40ff)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Fri Aug 19 16:10:00 2022
-// Update Count     : 4
+// Last Modified On : Fri Oct  7 15:42:00 2022
+// Update Count     : 5
 //
 
@@ -128,5 +128,5 @@
 	public ast::WithVisitorRef<ScrubTypeVars> {
 
-	ScrubTypeVars( ScrubMode m, TyVarMap const * tv ) :
+	ScrubTypeVars( ScrubMode m, TypeVarMap const * tv ) :
 			mode ( m ), typeVars( tv ) {}
 
@@ -148,5 +148,5 @@
 	ScrubMode const mode;
 	/// Type varriables to scrub.
-	TyVarMap const * const typeVars;
+	TypeVarMap const * const typeVars;
 	/// Value cached by primeBaseScrub.
 	ast::Type const * dynType = nullptr;
@@ -255,5 +255,5 @@
 const ast::Node * scrubTypeVarsBase(
 		const ast::Node * target,
-		ScrubMode mode, const TyVarMap * typeVars ) {
+		ScrubMode mode, const TypeVarMap * typeVars ) {
 	if ( ScrubMode::All == mode ) {
 		assert( nullptr == typeVars );
@@ -266,4 +266,16 @@
 
 } // namespace
+
+template<>
+ast::Node const * scrubTypeVars<ast::Node>(
+        const ast::Node * target, const TypeVarMap & typeVars ) {
+	return scrubTypeVarsBase( target, ScrubMode::FromMap, &typeVars );
+}
+
+template<>
+ast::Node const * scrubTypeVarsDynamic<ast::Node>(
+        ast::Node const * target, const TypeVarMap & typeVars ) {
+	return scrubTypeVarsBase( target, ScrubMode::DynamicFromMap, &typeVars );
+}
 
 template<>
Index: src/GenPoly/ScrubTyVars.h
===================================================================
--- src/GenPoly/ScrubTyVars.h	(revision 8c91088c3e562b46c9a7b971487a1d954e9f735a)
+++ src/GenPoly/ScrubTyVars.h	(revision c8837e5f0d9b9ee1ca54309ed7dd8ac35aeb40ff)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Fri Aug 19 14:14:00 2022
-// Update Count     : 3
+// Last Modified On : Fri Oct  7 15:51:00 2022
+// Update Count     : 4
 //
 
@@ -109,10 +109,40 @@
 	}
 
+/// For all polymorphic types with type variables in `typeVars`,
+/// replaces generic types, dtypes, and ftypes with the appropriate void type,
+/// and sizeof/alignof expressions with the proper variable.
+template<typename node_t>
+node_t const * scrubTypeVars(
+		node_t const * target, const TypeVarMap & typeVars ) {
+	return strict_dynamic_cast<node_t const *>(
+			scrubTypeVars<ast::Node>( target ) );
+}
+
+/// For all dynamic-layout types with type variables in `typeVars`,
+/// replaces generic types, dtypes, and ftypes with the appropriate void type,
+/// and sizeof/alignof expressions with the proper variable.
+template<typename node_t>
+ast::Node const * scrubTypeVarsDynamic(
+		node_t const * target, const TypeVarMap & typeVars ) {
+	return strict_dynamic_cast<node_t const *>(
+			scrubTypeVarsDynamic<ast::Node>( target, typeVars ) );
+}
+
 /// For all polymorphic types, replaces generic types, with the appropriate
 /// void type, and sizeof/alignof expressions with the proper variable.
 template<typename node_t>
 node_t const * scrubAllTypeVars( node_t const * target ) {
-	return strict_dynamic_cast<node_t const *>( scrubAllTypeVars<ast::Node>( target ) );
+	return strict_dynamic_cast<node_t const *>(
+			scrubAllTypeVars<ast::Node>( target ) );
 }
+
+// We specialize for Node as a base case.
+template<>
+ast::Node const * scrubTypeVars<ast::Node>(
+		const ast::Node * target, const TypeVarMap & typeVars );
+
+template<>
+ast::Node const * scrubTypeVarsDynamic<ast::Node>(
+		ast::Node const * target, const TypeVarMap & typeVars );
 
 template<>
