Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/Convert.cpp	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -1217,5 +1217,4 @@
 
 	const ast::Type * postvisit( const ast::BaseInstType * old, ReferenceToType * ty ) {
-		ty->forall = get<TypeDecl>().acceptL( old->forall );
 		ty->parameters = get<Expression>().acceptL( old->params );
 		ty->hoistType = old->hoistType;
@@ -2616,5 +2615,4 @@
 
 	void postvisit( const ReferenceToType * old, ast::BaseInstType * ty ) {
-		ty->forall = GET_ACCEPT_V( forall, TypeDecl );
 		ty->params = GET_ACCEPT_V( parameters, Expr );
 		ty->hoistType = old->hoistType;
Index: src/AST/ForallSubstitutor.hpp
===================================================================
--- src/AST/ForallSubstitutor.hpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/ForallSubstitutor.hpp	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -29,5 +29,5 @@
 	
 	/// Make new forall-list clone
-	ParameterizedType::ForallList operator() ( const ParameterizedType::ForallList & o ) {
+	FunctionType::ForallList operator() ( const FunctionType::ForallList & o ) {
 		return subs.clone( o, *visitor );
 	}
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/Pass.hpp	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -287,9 +287,9 @@
 	/// Internal RAII guard for forall substitutions
 	struct guard_forall_subs {
-		guard_forall_subs( Pass<core_t> & pass, const ParameterizedType * type )
+		guard_forall_subs( Pass<core_t> & pass, const FunctionType * type )
 		: pass( pass ), type( type ) { __pass::forall::enter(pass.core, 0, type ); }
 		~guard_forall_subs()         { __pass::forall::leave(pass.core, 0, type ); }
 		Pass<core_t> & pass;
-		const ParameterizedType * type;
+		const FunctionType * type;
 	};
 
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/Pass.impl.hpp	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -1777,6 +1777,4 @@
 	VISIT({
 		guard_symtab guard { *this };
-		guard_forall_subs forall_guard { *this, node };
-		mutate_forall( node );
 		maybe_accept( node, &StructInstType::params );
 	})
@@ -1795,6 +1793,4 @@
 	VISIT({
 		guard_symtab guard { *this };
-		guard_forall_subs forall_guard { *this, node };
-		mutate_forall( node );
 		maybe_accept( node, &UnionInstType::params );
 	})
@@ -1810,6 +1806,4 @@
 
 	VISIT({
-		guard_forall_subs forall_guard { *this, node };
-		mutate_forall( node );
 		maybe_accept( node, &EnumInstType::params );
 	})
@@ -1825,6 +1819,4 @@
 
 	VISIT({
-		guard_forall_subs forall_guard { *this, node };
-		mutate_forall( node );
 		maybe_accept( node, &TraitInstType::params );
 	})
@@ -1841,6 +1833,4 @@
 	VISIT(
 		{
-			guard_forall_subs forall_guard { *this, node };
-			mutate_forall( node );
 			maybe_accept( node, &TypeInstType::params );
 		}
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/Pass.proto.hpp	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -396,5 +396,5 @@
 		// Some simple scoping rules
 		template<typename core_t>
-		static inline auto enter( core_t & core, int, const ast::ParameterizedType * type )
+		static inline auto enter( core_t & core, int, const ast::FunctionType * type )
 		-> decltype( core.subs, void() ) {
 			if ( ! type->forall.empty() ) core.subs.beginScope();
@@ -402,8 +402,8 @@
 
 		template<typename core_t>
-		static inline auto enter( core_t &, long, const ast::ParameterizedType * ) {}
-
-		template<typename core_t>
-		static inline auto leave( core_t & core, int, const ast::ParameterizedType * type )
+		static inline auto enter( core_t &, long, const ast::FunctionType * ) {}
+
+		template<typename core_t>
+		static inline auto leave( core_t & core, int, const ast::FunctionType * type )
 		-> decltype( core.subs, void() ) {
 			if ( ! type->forall.empty() ) { core.subs.endScope(); }
@@ -411,5 +411,5 @@
 
 		template<typename core_t>
-		static inline auto leave( core_t &, long, const ast::ParameterizedType * ) {}
+		static inline auto leave( core_t &, long, const ast::FunctionType * ) {}
 
 		// Get the substitution table, if present
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/Print.cpp	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -146,5 +146,5 @@
 	}
 
-	void print( const ast::ParameterizedType::ForallList & forall ) {
+	void print( const ast::FunctionType::ForallList & forall ) {
 		if ( forall.empty() ) return;
 		os << "forall" << endl;
@@ -259,5 +259,5 @@
 	}
 
-	void preprint( const ast::ParameterizedType * node ) {
+	void preprint( const ast::FunctionType * node ) {
 		print( node->forall );
 		print( node->qualifiers );
@@ -265,5 +265,4 @@
 
 	void preprint( const ast::BaseInstType * node ) {
-		print( node->forall );
 		print( node->attributes );
 		print( node->qualifiers );
Index: src/AST/Type.cpp
===================================================================
--- src/AST/Type.cpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/Type.cpp	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -94,6 +94,6 @@
 // --- ParameterizedType
 
-void ParameterizedType::initWithSub(
-	const ParameterizedType & o, Pass< ForallSubstitutor > & sub
+void FunctionType::initWithSub(
+	const FunctionType & o, Pass< ForallSubstitutor > & sub
 ) {
 	forall = sub.core( o.forall );
@@ -104,5 +104,5 @@
 
 FunctionType::FunctionType( const FunctionType & o )
-: ParameterizedType( o.qualifiers, copy( o.attributes ) ), returns(), params(),
+: Type( o.qualifiers, copy( o.attributes ) ), returns(), params(),
   isVarArgs( o.isVarArgs ) {
 	Pass< ForallSubstitutor > sub;
@@ -125,18 +125,4 @@
 }
 
-// --- BaseInstType
-
-void BaseInstType::initWithSub( const BaseInstType & o, Pass< ForallSubstitutor > & sub ) {
-	ParameterizedType::initWithSub( o, sub ); // initialize substitution
-	params = sub.core( o.params );            // apply to parameters
-}
-
-BaseInstType::BaseInstType( const BaseInstType & o )
-: ParameterizedType( o.qualifiers, copy( o.attributes ) ), params(), name( o.name ),
-  hoistType( o.hoistType ) {
-	Pass< ForallSubstitutor > sub;
-	initWithSub( o, sub );
-}
-
 std::vector<readonly<Decl>> BaseInstType::lookup( const std::string& name ) const {
 	assertf( aggr(), "Must have aggregate to perform lookup" );
@@ -176,13 +162,4 @@
 	const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
 : BaseInstType( b->name, q, move(as) ), base( b ) {}
-
-// --- TypeInstType
-
-TypeInstType::TypeInstType( const TypeInstType & o )
-: BaseInstType( o.name, o.qualifiers, copy( o.attributes ) ), base(), kind( o.kind ) {
-	Pass< ForallSubstitutor > sub;
-	initWithSub( o, sub );      // initialize substitution
-	base = sub.core( o.base );  // apply to base type
-}
 
 void TypeInstType::set_base( const TypeDecl * b ) {
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/Type.hpp	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -267,39 +267,16 @@
 };
 
-/// Base type for potentially forall-qualified types
-class ParameterizedType : public Type {
-protected:
-	/// initializes forall with substitutor
-	void initWithSub( const ParameterizedType & o, Pass< ForallSubstitutor > & sub );
-public:
-	using ForallList = std::vector<ptr<TypeDecl>>;
-
-	ForallList forall;
-
-	ParameterizedType( ForallList&& fs = {}, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
-	: Type(q, std::move(as)), forall(std::move(fs)) {}
-
-	ParameterizedType( CV::Qualifiers q, std::vector<ptr<Attribute>> && as = {} )
-	: Type(q, std::move(as)), forall() {}
-
-	// enforce use of ForallSubstitutor to copy parameterized type
-	ParameterizedType( const ParameterizedType & ) = delete;
-
-	ParameterizedType( ParameterizedType && ) = default;
-
-	// no need to change destructor, and operator= deleted in Node
-
-private:
-	virtual ParameterizedType * clone() const override = 0;
-	MUTATE_FRIEND
-};
-
 /// Function variable arguments flag
 enum ArgumentFlag { FixedArgs, VariableArgs };
 
 /// Type of a function `[R1, R2](*)(P1, P2, P3)`
-class FunctionType final : public ParameterizedType {
-public:
+class FunctionType final : public Type {
+	protected:
+	/// initializes forall with substitutor
+	void initWithSub( const FunctionType & o, Pass< ForallSubstitutor > & sub );
+public:
+	using ForallList = std::vector<ptr<TypeDecl>>;
+	ForallList forall;
+
 	std::vector<ptr<Type>> returns;
 	std::vector<ptr<Type>> params;
@@ -313,5 +290,5 @@
 
 	FunctionType( ArgumentFlag va = FixedArgs, CV::Qualifiers q = {} )
-	: ParameterizedType(q), returns(), params(), isVarArgs(va) {}
+	: Type(q), returns(), params(), isVarArgs(va) {}
 
 	FunctionType( const FunctionType & o );
@@ -329,8 +306,5 @@
 
 /// base class for types that refer to types declared elsewhere (aggregates and typedefs)
-class BaseInstType : public ParameterizedType {
-protected:
-	/// Initializes forall and parameters based on substitutor
-	void initWithSub( const BaseInstType & o, Pass< ForallSubstitutor > & sub );
+class BaseInstType : public Type {
 public:
 	std::vector<ptr<Expr>> params;
@@ -340,12 +314,12 @@
 	BaseInstType(
 		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
-	: ParameterizedType(q, std::move(as)), params(), name(n) {}
+	: Type(q, std::move(as)), params(), name(n) {}
 
 	BaseInstType(
 		const std::string& n, std::vector<ptr<Expr>> && params,
 		CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
-	: ParameterizedType(q, std::move(as)), params(std::move(params)), name(n) {}
-
-	BaseInstType( const BaseInstType & o );
+	: Type(q, std::move(as)), params(std::move(params)), name(n) {}
+
+	BaseInstType( const BaseInstType & o ) = default;
 
 	/// Gets aggregate declaration this type refers to
@@ -433,5 +407,5 @@
 	: BaseInstType( n, q, std::move(as) ), base(), kind( k ) {}
 
-	TypeInstType( const TypeInstType & o );
+	TypeInstType( const TypeInstType & o ) = default;
 
 	/// sets `base`, updating `kind` correctly
Index: src/AST/TypeEnvironment.cpp
===================================================================
--- src/AST/TypeEnvironment.cpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/TypeEnvironment.cpp	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -105,5 +105,5 @@
 }
 
-void TypeEnvironment::add( const ParameterizedType::ForallList & tyDecls ) {
+void TypeEnvironment::add( const FunctionType::ForallList & tyDecls ) {
 	for ( const TypeDecl * tyDecl : tyDecls ) {
 		env.emplace_back( tyDecl );
Index: src/AST/TypeEnvironment.hpp
===================================================================
--- src/AST/TypeEnvironment.hpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/TypeEnvironment.hpp	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -134,5 +134,5 @@
 
 	/// Add a new equivalence class for each type variable
-	void add( const ParameterizedType::ForallList & tyDecls );
+	void add( const FunctionType::ForallList & tyDecls );
 
 	/// Add a new equivalence class for each branch of the substitution, checking for conflicts
Index: src/AST/TypeSubstitution.cpp
===================================================================
--- src/AST/TypeSubstitution.cpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/TypeSubstitution.cpp	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -166,5 +166,5 @@
 }
 
-void TypeSubstitution::Substituter::previsit( const ParameterizedType * ptype ) {
+void TypeSubstitution::Substituter::previsit( const FunctionType * ptype ) {
 	GuardValue( boundVars );
 	// bind type variables from forall-qualifiers
@@ -180,7 +180,4 @@
 	// bind type variables from forall-qualifiers
 	if ( freeOnly ) {
-		for ( const TypeDecl * tyvar : type->forall ) {
-			boundVars.insert( tyvar->name );
-		} // for
 		// bind type variables from generic type instantiations
 		if ( auto decl = type->aggr() ) {
Index: src/AST/TypeSubstitution.hpp
===================================================================
--- src/AST/TypeSubstitution.hpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/TypeSubstitution.hpp	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -167,5 +167,5 @@
 
 		/// Records type variable bindings from forall-statements
-		void previsit( const ParameterizedType * type );
+		void previsit( const FunctionType * type );
 		/// Records type variable bindings from forall-statements and instantiations of generic types
 		void handleAggregateType( const BaseInstType * type );
Index: src/GenPoly/GenPoly.cc
===================================================================
--- src/GenPoly/GenPoly.cc	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/GenPoly/GenPoly.cc	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -567,5 +567,5 @@
 
 	void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap) {
-		if (auto ptype = dynamic_cast<const ast::ParameterizedType *>(type)) {
+		if (auto ptype = dynamic_cast<const ast::FunctionType *>(type)) {
  			for (auto & tyVar : ptype->forall) {
 				assert (tyVar);
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -220,5 +220,5 @@
 
 	void makeUnifiableVars(
-		const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars,
+		const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,
 		ast::AssertionSet & need
 	) {
Index: src/ResolvExpr/CastCost.cc
===================================================================
--- src/ResolvExpr/CastCost.cc	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/ResolvExpr/CastCost.cc	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -165,5 +165,5 @@
 				} else {
 					ast::TypeEnvironment newEnv{ env };
-					if ( auto wParams = pointerType->base.as< ast::ParameterizedType >() ) {
+					if ( auto wParams = pointerType->base.as< ast::FunctionType >() ) {
 						newEnv.add( wParams->forall );
 					}
Index: src/ResolvExpr/RenameVars.cc
===================================================================
--- src/ResolvExpr/RenameVars.cc	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/ResolvExpr/RenameVars.cc	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -93,6 +93,5 @@
 		}
 
-		template<typename NodeT>
-		const NodeT * openLevel( const NodeT * type ) {
+		const ast::FunctionType * openLevel( const ast::FunctionType * type ) {
 			if ( type->forall.empty() ) return type;
 
@@ -100,7 +99,8 @@
 
 			// Load new names from this forall clause and perform renaming.
-			NodeT * mutType = ast::mutate( type );
+			auto mutType = ast::mutate( type );
 			assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
 			for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
+				assertf(dynamic_cast<ast::FunctionType *>(mutType), "renaming vars in non-function type");
 				std::ostringstream output;
 				output << "_" << resetCount << "_" << level << "_" << td->name;
@@ -119,5 +119,5 @@
 		}
 
-		void closeLevel( const ast::ParameterizedType * type ) {
+		void closeLevel( const ast::FunctionType * type ) {
 			if ( type->forall.empty() ) return;
 
@@ -149,4 +149,6 @@
 			return renaming.openLevel( type );
 		}
+
+		/*
 		const ast::StructInstType * previsit( const ast::StructInstType * type ) {
 			return renaming.openLevel( type );
@@ -158,8 +160,10 @@
 			return renaming.openLevel( type );
 		}
+		*/
+
 		const ast::TypeInstType * previsit( const ast::TypeInstType * type ) {
-			return renaming.rename( renaming.openLevel( type ) );
+			return renaming.rename( type );
 		}
-		void postvisit( const ast::ParameterizedType * type ) {
+		void postvisit( const ast::FunctionType * type ) {
 			renaming.closeLevel( type );
 		}
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/ResolvExpr/Resolver.cc	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -976,6 +976,11 @@
 			}
 
-			void previsit( const ast::Expr * ) {
+			void previsit( const ast::Expr * expr ) {
 				if ( result ) { visit_children = false; }
+				if (expr->inferred.hasParams()) {
+					for (auto & imp : expr->inferred.inferParams() ) {
+						previsit(imp.second.expr);
+					}
+				}
 			}
 		};
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/ResolvExpr/Unify.cc	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -898,5 +898,5 @@
 		static void markAssertions(
 			ast::AssertionSet & assn1, ast::AssertionSet & assn2,
-			const ast::ParameterizedType * type
+			const ast::FunctionType * type
 		) {
 			for ( const auto & tyvar : type->forall ) {
Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/SymTab/Mangler.cc	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -666,5 +666,5 @@
 			// skip if not including qualifiers
 			if ( typeMode ) return;
-			if ( auto ptype = dynamic_cast< const ast::ParameterizedType * >(type) ) {
+			if ( auto ptype = dynamic_cast< const ast::FunctionType * >(type) ) {
 				if ( ! ptype->forall.empty() ) {
 					std::list< std::string > assertionNames;
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/SymTab/Validate.cc	(revision 361bf012e550db91b38f772bfbc7cb7ed2e49033)
@@ -1793,5 +1793,5 @@
 		static const node_t * forallFixer(
 			const CodeLocation & loc, const node_t * node,
-			ast::ParameterizedType::ForallList parent_t::* forallField
+			ast::FunctionType::ForallList parent_t::* forallField
 		) {
 			for ( unsigned i = 0; i < (node->* forallField).size(); ++i ) {
