Index: src/AST/Copy.hpp
===================================================================
--- src/AST/Copy.hpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
+++ src/AST/Copy.hpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -0,0 +1,126 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Copy.hpp -- Provides functions to copy the AST.
+//
+// Author           : Andrew Beach
+// Created On       : Wed Jul 10 16:13:00 2019
+// Last Modified By : Andrew Beach
+// Last Modified On : Thr Jul 11 10:38:00 2019
+// Update Count     : 0
+//
+
+#include "Decl.hpp"
+#include "Expr.hpp"
+#include "Pass.hpp"
+#include "Stmt.hpp"
+#include "Type.hpp"
+
+namespace ast {
+
+template<typename node_t>
+const node_t * shallowCopy( const node_t * node ) {
+/* Create a shallow copy of the node given.
+ *
+ * The new node has all the same primitive field values and points to the
+ * same children nodes as the parent.
+ */
+
+template<typename node_t>
+node_t * deepCopy( node_t const * localRoot );
+/* Create a deep copy of the tree rooted at localRoot.
+ *
+ * This creates a copy of every node in the sub-tree (reachable by strong
+ * reference from local_root) and updates any readonly pointers on those nodes
+ * that point to another node in the sub-tree to the new version of that node.
+ */
+
+class DeepCopyCore {
+	std::unordered_map< const Node *, const Node * > nodeCache;
+	std::unordered_set< readonly<Node> * > readonlyCache;
+
+public:
+	template<typename node_t>
+	const node_t * previsit( const node_t * node ) {
+		const node_t * copy = shallowCopy( node );
+		nodeCache.insert( std::make_pair( node, copy ) );
+		return copy;
+	}
+
+	void postvisit( const AggregateDecl * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->parent );
+	}
+
+	void postvisit( const StructInstType * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->base );
+	}
+
+	void postvisit( const UnionInstType * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->base );
+	}
+
+	void postvisit( const EnumInstType * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->base );
+	}
+
+	void postvisit( const TraitInstType * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->base );
+	}
+
+	void postvisit( const TypeInstType * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->base );
+	}
+
+	void postvisit( const ImplicitCtorDtorStmt * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->callStmt );
+	}
+
+	void postvisit( const MemberExpr * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->member );
+	}
+
+	void postvisit( const VariableExpr * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->var );
+	}
+
+	void postvisit( const OffsetofExpr * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->member );
+	}
+
+	void postvisit( const DeletedExpr * node ) {
+		readonlyCache.insert( (readonly<Node> *) & node->deleteStmt );
+	}
+
+	void readonlyUpdates() {
+		for ( readonly<Node> * ptr : readonlyCache ) {
+			auto it = nodeCache.find( ptr->get() );
+			if ( nodeCache.end() != it ) {
+				*ptr = it->second;
+			}
+		}
+	}
+};
+
+template<typename node_t>
+node_t * shallowCopy( node_t const * localRoot ) {
+	return localRoot->clone();
+}
+
+template<typename node_t>
+node_t * deepCopy( node_t const * localRoot ) {
+	Pass< DeepCopyCore > dc;
+	node_t const * newRoot = localRoot->accept( dc );
+	dc.pass.readonlyUpdates();
+	return const_cast< node_t * >( newRoot );
+}
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision e67991fd01d5341ea7ee45736431dbe64851911e)
+++ src/AST/Decl.cpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -52,5 +52,7 @@
 
 const Type * FunctionDecl::get_type() const { return type.get(); }
-void FunctionDecl::set_type(Type * t) { type = strict_dynamic_cast< FunctionType* >( t ); }
+void FunctionDecl::set_type( const Type * t ) {
+	type = strict_dynamic_cast< const FunctionType * >( t );
+}
 
 // --- TypeDecl
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision e67991fd01d5341ea7ee45736431dbe64851911e)
+++ src/AST/Decl.hpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -87,5 +87,5 @@
 	virtual const Type * get_type() const = 0;
 	/// Set type of this declaration. May be verified by subclass
-	virtual void set_type(Type *) = 0;
+	virtual void set_type( const Type * ) = 0;
 
 	const DeclWithType * accept( Visitor & v ) const override = 0;
@@ -110,5 +110,5 @@
 
 	const Type* get_type() const override { return type; }
-	void set_type( Type * ty ) override { type = ty; }
+	void set_type( const Type * ty ) override { type = ty; }
 
 	const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); }
@@ -132,5 +132,5 @@
 
 	const Type * get_type() const override;
-	void set_type(Type * t) override;
+	void set_type( const Type * t ) override;
 
 	bool has_body() const { return stmts; }
@@ -149,6 +149,7 @@
 	std::vector<ptr<DeclWithType>> assertions;
 
-	NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
-		Type* b, Linkage::Spec spec = Linkage::Cforall )
+	NamedTypeDecl( 
+		const CodeLocation & loc, const std::string & name, Storage::Classes storage,
+		const Type * b, Linkage::Spec spec = Linkage::Cforall )
 	: Decl( loc, name, storage, spec ), base( b ), params(), assertions() {}
 
@@ -185,6 +186,7 @@
 	};
 
-	TypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, Type* b,
-		TypeVar::Kind k, bool s, Type* i = nullptr )
+	TypeDecl( 
+		const CodeLocation & loc, const std::string & name, Storage::Classes storage, 
+		const Type * b, TypeVar::Kind k, bool s, const Type * i = nullptr )
 	: NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == TypeVar::Ttype || s ),
 	  init( i ) {}
Index: src/AST/Eval.hpp
===================================================================
--- src/AST/Eval.hpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
+++ src/AST/Eval.hpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -0,0 +1,37 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Eval.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Fri Jun 28 14:00:00 2019
+// Last Modified By : Aaron B. Moss
+// Created On       : Fri Jun 28 14:00:00 2019
+// Update Count     : 1
+//
+
+#include <string>
+#include <utility>
+
+#include "Expr.hpp"
+
+namespace ast {
+
+/// Create a new UntypedExpr with the given arguments
+template< typename... Args >
+UntypedExpr * call( const CodeLocation & loc, const std::string & name, Args &&... args ) {
+	return new UntypedExpr { 
+		loc, new NameExpr { loc, name }, 
+		std::vector< ptr< Expr > > { std::forward< Args >( args )... } };
+}
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision e67991fd01d5341ea7ee45736431dbe64851911e)
+++ src/AST/Expr.cpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -20,4 +20,5 @@
 #include <vector>
 
+#include "Eval.hpp"                // for call
 #include "GenericSubstitution.hpp"
 #include "Stmt.hpp"
@@ -51,7 +52,5 @@
 	assert( arg );
 
-	UntypedExpr * ret = new UntypedExpr{
-		loc, new NameExpr{loc, "*?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ arg } }
-	};
+	UntypedExpr * ret = call( loc, "*?", arg );
 	if ( const Type * ty = arg->result ) {
 		const Type * base = InitTweak::getPointerBase( ty );
@@ -74,7 +73,5 @@
 	assert( lhs && rhs );
 
-	UntypedExpr * ret = new UntypedExpr{
-		loc, new NameExpr{loc, "?=?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ lhs }, ptr<Expr>{ rhs } }
-	};
+	UntypedExpr * ret = call( loc, "?=?", lhs, rhs );
 	if ( lhs->result && rhs->result ) {
 		// if both expressions are typed, assumes that this assignment is a C bitwise assignment,
Index: src/AST/ForallSubstitutionTable.cpp
===================================================================
--- src/AST/ForallSubstitutionTable.cpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
+++ src/AST/ForallSubstitutionTable.cpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -0,0 +1,54 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ForallSubstitutionTable.cpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Thu Jun 27 14:00:00 2019
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Thu Jun 27 14:00:00 2019
+// Update Count     : 1
+//
+
+#include "ForallSubstitutionTable.hpp"
+
+#include <cassert>
+#include <vector>
+
+#include "Decl.hpp"
+#include "Node.hpp"
+#include "Type.hpp"
+#include "Visitor.hpp"
+
+namespace ast {
+
+std::vector< ptr< TypeDecl > > ForallSubstitutionTable::clone( 
+	const std::vector< ptr< TypeDecl > > & forall, Visitor & v 
+) {
+	std::vector< ptr< TypeDecl > > new_forall;
+	new_forall.reserve( forall.size() );
+
+	for ( const ast::TypeDecl * d : forall ) {
+		// create cloned type decl and insert into substitution map before further mutation
+		auto new_d = new ast::TypeDecl{
+			d->location, d->name, d->storage, d->base, d->kind, d->sized, d->init };
+		decls.insert( d, new_d );
+		// perform other mutations and add to output
+		auto newer_d = v.visit( new_d );
+		assert( new_d == newer_d && "Newly cloned TypeDecl must retain identity" );
+		new_forall.emplace_back( new_d );
+	}
+
+	return new_forall;
+}
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/ForallSubstitutionTable.hpp
===================================================================
--- src/AST/ForallSubstitutionTable.hpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
+++ src/AST/ForallSubstitutionTable.hpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -0,0 +1,57 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ForallSubstitutionTable.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Thu Jun 27 14:00:00 2019
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Thu Jun 27 14:00:00 2019
+// Update Count     : 1
+//
+
+#pragma once
+
+#include <vector>
+
+#include "Node.hpp"  // for ptr
+#include "Common/ScopedMap.h"
+
+namespace ast {
+
+class TypeDecl;
+class Visitor;
+
+/// Wrapper for TypeDecl substitution table
+class ForallSubstitutionTable {
+	ScopedMap< const TypeDecl *, const TypeDecl * > decls;
+
+public:
+	/// Replaces given declaration with value in the table, if present, otherwise returns argument
+	const TypeDecl * replace( const TypeDecl * d ) {
+		auto it = decls.find( d );
+		if ( it != decls.end() ) return it->second;
+		return d;
+	}
+
+	/// Builds a new forall list mutated according to the given visitor
+	std::vector< ptr< TypeDecl > > clone( 
+		const std::vector< ptr< TypeDecl > > & forall, Visitor & v );
+
+	/// Introduces a new lexical scope
+	void beginScope() { decls.beginScope(); }
+
+	/// Concludes a lexical scope
+	void endScope() { decls.endScope(); }
+};
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/ForallSubstitutor.hpp
===================================================================
--- src/AST/ForallSubstitutor.hpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
+++ src/AST/ForallSubstitutor.hpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -0,0 +1,58 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ForallSubstitutor.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Wed Jun 26 15:00:00 2019
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Wed Jun 26 15:00:00 2019
+// Update Count     : 1
+//
+
+#include "Pass.hpp"
+
+namespace ast {
+
+class Expr;
+
+/// Visitor that correctly substitutes TypeDecl while maintaining TypeInstType bindings.
+/// Also has some convenience methods to mutate fields.
+struct ForallSubstitutor : public WithForallSubstitutor, public WithVisitorRef<ForallSubstitutor> {
+	/// Substitute TypeInstType base type
+	readonly< TypeDecl > operator() ( const readonly< TypeDecl > & o ) {
+		return subs.replace( o );
+	}
+	
+	/// Make new forall-list clone
+	ParameterizedType::ForallList operator() ( const ParameterizedType::ForallList & o ) {
+		return subs.clone( o, *visitor );
+	}
+
+	/// Substitute parameter/return type
+	std::vector< ptr< DeclWithType > > operator() ( const std::vector< ptr< DeclWithType > > & o ) {
+		std::vector< ptr< DeclWithType > > n;
+		n.reserve( o.size() );
+		for ( const DeclWithType * d : o ) { n.emplace_back( d->accept( *visitor ) ); }
+		return n;
+	}
+
+	/// Substitute type parameter list
+	std::vector< ptr< Expr > > operator() ( const std::vector< ptr< Expr > > & o ) {
+		std::vector< ptr< Expr > > n;
+		n.reserve( o.size() );
+		for ( const Expr * d : o ) { n.emplace_back( d->accept( *visitor ) ); }
+		return n;
+	}
+};
+
+} // namespace ast
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/Node.cpp
===================================================================
--- src/AST/Node.cpp	(revision e67991fd01d5341ea7ee45736431dbe64851911e)
+++ src/AST/Node.cpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -17,4 +17,5 @@
 #include "Fwd.hpp"
 
+#include <csignal>  // MEMORY DEBUG -- for raise
 #include <iostream>
 
@@ -29,12 +30,33 @@
 #include "Print.hpp"
 
-template< typename node_t, enum ast::Node::ref_type ref_t >
-void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { node->increment(ref_t); }
-
-template< typename node_t, enum ast::Node::ref_type ref_t >
-void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node ) { node->decrement(ref_t); }
-
-template< typename node_t, enum ast::Node::ref_type ref_t >
-void ast::ptr_base<node_t, ref_t>::_check() const { if(node) assert(node->was_ever_strong == false || node->strong_count > 0); }
+/// MEMORY DEBUG -- allows breaking on ref-count changes of dynamically chosen object.
+/// Process to use in GDB:
+///   break ast::Node::_trap()
+///   run
+///   set variable MEM_TRAP_OBJ = <target>
+///   disable <first breakpoint>
+///   continue
+void * MEM_TRAP_OBJ = nullptr;
+
+void _trap( const void * node ) {
+	if ( node == MEM_TRAP_OBJ ) std::raise(SIGTRAP);
+}
+
+template< typename node_t, enum ast::Node::ref_type ref_t >
+void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) {
+	node->increment(ref_t);
+	_trap( node );
+}
+
+template< typename node_t, enum ast::Node::ref_type ref_t >
+void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node, bool do_delete ) {
+	_trap( node );
+	node->decrement(ref_t, do_delete );
+}
+
+template< typename node_t, enum ast::Node::ref_type ref_t >
+void ast::ptr_base<node_t, ref_t>::_check() const { 
+	// if(node) assert(node->was_ever_strong == false || node->strong_count > 0);
+}
 
 template< typename node_t, enum ast::Node::ref_type ref_t >
Index: src/AST/Node.hpp
===================================================================
--- src/AST/Node.hpp	(revision e67991fd01d5341ea7ee45736431dbe64851911e)
+++ src/AST/Node.hpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -38,5 +38,5 @@
 	Node& operator= (const Node&) = delete;
 	Node& operator= (Node&&) = delete;
-	virtual ~Node() = default;
+	virtual ~Node() {}
 
 	virtual const Node * accept( Visitor & v ) const = 0;
@@ -69,5 +69,5 @@
 	}
 
-	void decrement(ast::Node::ref_type ref) const {
+	void decrement(ast::Node::ref_type ref, bool do_delete = true) const {
 		switch (ref) {
 			case ref_type::strong: strong_count--; break;
@@ -75,5 +75,5 @@
 		}
 
-		if(!strong_count && !weak_count) {
+		if( do_delete && !strong_count && !weak_count) {
 			delete this;
 		}
@@ -123,4 +123,13 @@
 	(ret->*field)[i] = std::forward< field_t >( val );
 	return ret;
+}
+
+/// Mutate an entire indexed collection by cloning to accepted value
+template<typename node_t, typename parent_t, typename coll_t>
+const node_t * mutate_each( const node_t * node, coll_t parent_t::* field, Visitor & v ) {
+	for ( unsigned i = 0; i < (node->*field).size(); ++i ) {
+		node = mutate_field_index( node, field, i, (node->*field)[i]->accept( v ) );
+	}
+	return node;
 }
 
@@ -219,4 +228,13 @@
 	operator const node_t * () const { _check(); return node; }
 
+	const node_t * release() {
+		const node_t * ret = node;
+		if ( node ) {
+			_dec(node, false);
+			node = nullptr;
+		}
+		return ret;
+	}
+
 	/// wrapper for convenient access to dynamic_cast
 	template<typename o_node_t>
@@ -244,5 +262,5 @@
 
 	void _inc( const node_t * other );
-	void _dec( const node_t * other );
+	void _dec( const node_t * other, bool do_delete = true );
 	void _check() const;
 
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision e67991fd01d5341ea7ee45736431dbe64851911e)
+++ src/AST/Pass.hpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -35,4 +35,6 @@
 #include "AST/SymbolTable.hpp"
 
+#include "AST/ForallSubstitutionTable.hpp"
+
 // Private prelude header, needed for some of the magic tricks this class pulls off
 #include "AST/Pass.proto.hpp"
@@ -46,20 +48,21 @@
 //
 // Several additional features are available through inheritance
-// | WithTypeSubstitution - provides polymorphic const TypeSubstitution * env for the
-//                          current expression
-// | WithStmtsToAdd       - provides the ability to insert statements before or after the current
-//                          statement by adding new statements into stmtsToAddBefore or
-//                          stmtsToAddAfter respectively.
-// | WithDeclsToAdd       - provides the ability to insert declarations before or after the current
-//                          declarations by adding new DeclStmt into declsToAddBefore or
-//                          declsToAddAfter respectively.
-// | WithShortCircuiting  - provides the ability to skip visiting child nodes; set visit_children
-//                          to false in pre{visit,visit} to skip visiting children
-// | WithGuards           - provides the ability to save/restore data like a LIFO stack; to save,
-//                          call GuardValue with the variable to save, the variable will
-//                          automatically be restored to its previous value after the corresponding
-//                          postvisit/postmutate teminates.
-// | WithVisitorRef       - provides an pointer to the templated visitor wrapper
-// | WithSymbolTable      - provides symbol table functionality
+// | WithTypeSubstitution  - provides polymorphic const TypeSubstitution * env for the
+//                           current expression
+// | WithStmtsToAdd        - provides the ability to insert statements before or after the current
+//                           statement by adding new statements into stmtsToAddBefore or
+//                           stmtsToAddAfter respectively.
+// | WithDeclsToAdd        - provides the ability to insert declarations before or after the
+//                           current declarations by adding new DeclStmt into declsToAddBefore or
+//                           declsToAddAfter respectively.
+// | WithShortCircuiting   - provides the ability to skip visiting child nodes; set visit_children
+//                           to false in pre{visit,visit} to skip visiting children
+// | WithGuards            - provides the ability to save/restore data like a LIFO stack; to save,
+//                           call GuardValue with the variable to save, the variable will
+//                           automatically be restored to its previous value after the
+//                           corresponding postvisit/postmutate teminates.
+// | WithVisitorRef        - provides an pointer to the templated visitor wrapper
+// | WithSymbolTable       - provides symbol table functionality
+// | WithForallSubstitutor - maintains links between TypeInstType and TypeDecl under mutation
 //-------------------------------------------------------------------------------------------------
 template< typename pass_t >
@@ -201,4 +204,8 @@
 	container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container );
 
+	/// Mutate forall-list, accounting for presence of type substitution map
+	template<typename node_t>
+	void mutate_forall( const node_t *& );
+
 public:
 	/// Logic to call the accept and mutate the parent if needed, delegates call to accept
@@ -209,6 +216,6 @@
 	/// Internal RAII guard for symbol table features
 	struct guard_symtab {
-		guard_symtab( Pass<pass_t> & pass ): pass( pass ) { __pass::symtab::enter(pass, 0); }
-		~guard_symtab()                                   { __pass::symtab::leave(pass, 0); }
+		guard_symtab( Pass<pass_t> & pass ): pass( pass ) { __pass::symtab::enter(pass.pass, 0); }
+		~guard_symtab()                                   { __pass::symtab::leave(pass.pass, 0); }
 		Pass<pass_t> & pass;
 	};
@@ -216,7 +223,16 @@
 	/// Internal RAII guard for scope features
 	struct guard_scope {
-		guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass, 0); }
-		~guard_scope()                                   { __pass::scope::leave(pass, 0); }
+		guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass.pass, 0); }
+		~guard_scope()                                   { __pass::scope::leave(pass.pass, 0); }
 		Pass<pass_t> & pass;
+	};
+
+	/// Internal RAII guard for forall substitutions
+	struct guard_forall_subs {
+		guard_forall_subs( Pass<pass_t> & pass, const ParameterizedType * type )
+		: pass( pass ), type( type ) { __pass::forall::enter(pass.pass, 0, type ); }
+		~guard_forall_subs()         { __pass::forall::leave(pass.pass, 0, type ); }
+		Pass<pass_t> & pass;
+		const ParameterizedType * type;
 	};
 
@@ -313,4 +329,10 @@
 	SymbolTable symtab;
 };
+
+/// Use when the templated visitor needs to keep TypeInstType instances properly linked to TypeDecl
+struct WithForallSubstitutor {
+	ForallSubstitutionTable subs;
+};
+
 }
 
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision e67991fd01d5341ea7ee45736431dbe64851911e)
+++ src/AST/Pass.impl.hpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -127,8 +127,7 @@
 			, decltype( node->accept(*this) )
 		>::type
-
 	{
 		__pedantic_pass_assert( __visit_children() );
-		__pedantic_pass_assert( expr );
+		__pedantic_pass_assert( node );
 
 		static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR");
@@ -323,4 +322,20 @@
 	}
 
+
+	template< typename pass_t >
+	template< typename node_t >
+	void ast::Pass< pass_t >::mutate_forall( const node_t *& node ) {
+		if ( auto subs = __pass::forall::subs( pass, 0 ) ) {
+			// tracking TypeDecl substitution, full clone
+			if ( node->forall.empty() ) return;
+
+			node_t * mut = mutate( node );
+			mut->forall = subs->clone( node->forall, *this );
+			node = mut;
+		} else {
+			// not tracking TypeDecl substitution, just mutate
+			maybe_accept( node, &node_t::forall );
+		}
+	}
 }
 
@@ -429,12 +444,12 @@
 			guard_symtab guard { *this };
 			// implicit add __func__ identifier as specified in the C manual 6.4.2.2
-			static ast::ObjectDecl func(
-				node->location, "__func__",
-				new ast::ArrayType(
-					new ast::BasicType( ast::BasicType::Char, ast::CV::Qualifiers( ast::CV::Const ) ),
+			static ast::ptr< ast::ObjectDecl > func{ new ast::ObjectDecl{ 
+				CodeLocation{}, "__func__",
+				new ast::ArrayType{
+					new ast::BasicType{ ast::BasicType::Char, ast::CV::Const },
 					nullptr, VariableLen, DynamicDim
-				)
-			);
-			__pass::symtab::addId( pass, 0, &func );
+				}
+			} };
+			__pass::symtab::addId( pass, 0, func );
 			VISIT(
 				maybe_accept( node, &FunctionDecl::type );
@@ -610,8 +625,8 @@
 	VISIT({
 		// do not enter a new scope if inFunction is true - needs to check old state before the assignment
-		auto guard1 = makeFuncGuard( [this, inFunction = this->inFunction]() {
-			if ( ! inFunction ) __pass::symtab::enter(pass, 0);
-		}, [this, inFunction = this->inFunction]() {
-			if ( ! inFunction ) __pass::symtab::leave(pass, 0);
+		auto guard1 = makeFuncGuard( [this, inFunctionCpy = this->inFunction]() {
+			if ( ! inFunctionCpy ) __pass::symtab::enter(pass, 0);
+		}, [this, inFunctionCpy = this->inFunction]() {
+			if ( ! inFunctionCpy ) __pass::symtab::leave(pass, 0);
 		});
 		ValueGuard< bool > guard2( inFunction );
@@ -1667,9 +1682,10 @@
 	VISIT_START( node );
 
-	VISIT(
-		maybe_accept( node, &FunctionType::forall  );
+	VISIT({
+		guard_forall_subs forall_guard { *this, node };
+		mutate_forall( node );
 		maybe_accept( node, &FunctionType::returns );
 		maybe_accept( node, &FunctionType::params  );
-	)
+	})
 
 	VISIT_END( Type, node );
@@ -1686,5 +1702,6 @@
 	VISIT({
 		guard_symtab guard { *this };
-		maybe_accept( node, &StructInstType::forall );
+		guard_forall_subs forall_guard { *this, node };
+		mutate_forall( node );
 		maybe_accept( node, &StructInstType::params );
 	})
@@ -1699,11 +1716,12 @@
 	VISIT_START( node );
 
-	__pass::symtab::addStruct( pass, 0, node->name );
-
-	{
+	__pass::symtab::addUnion( pass, 0, node->name );
+
+	VISIT({
 		guard_symtab guard { *this };
-		maybe_accept( node, &UnionInstType::forall );
+		guard_forall_subs forall_guard { *this, node };
+		mutate_forall( node );
 		maybe_accept( node, &UnionInstType::params );
-	}
+	})
 
 	VISIT_END( Type, node );
@@ -1716,8 +1734,9 @@
 	VISIT_START( node );
 
-	VISIT(
-		maybe_accept( node, &EnumInstType::forall );
+	VISIT({
+		guard_forall_subs forall_guard { *this, node };
+		mutate_forall( node );
 		maybe_accept( node, &EnumInstType::params );
-	)
+	})
 
 	VISIT_END( Type, node );
@@ -1730,8 +1749,9 @@
 	VISIT_START( node );
 
-	VISIT(
-		maybe_accept( node, &TraitInstType::forall );
+	VISIT({
+		guard_forall_subs forall_guard { *this, node };
+		mutate_forall( node );
 		maybe_accept( node, &TraitInstType::params );
-	)
+	})
 
 	VISIT_END( Type, node );
@@ -1745,6 +1765,11 @@
 
 	VISIT(
-		maybe_accept( node, &TypeInstType::forall );
-		maybe_accept( node, &TypeInstType::params );
+		{
+			guard_forall_subs forall_guard { *this, node };
+			mutate_forall( node );
+			maybe_accept( node, &TypeInstType::params );
+		}
+		// ensure that base re-bound if doing substitution
+		__pass::forall::replace( pass, 0, node );
 	)
 
@@ -1895,5 +1920,5 @@
 				guard_symtab guard { *this };
 				auto new_node = p.second->accept( *this );
-				if (new_node != p.second) mutated = false;
+				if (new_node != p.second) mutated = true;
 				new_map.insert({ p.first, new_node });
 			}
@@ -1911,5 +1936,5 @@
 				guard_symtab guard { *this };
 				auto new_node = p.second->accept( *this );
-				if (new_node != p.second) mutated = false;
+				if (new_node != p.second) mutated = true;
 				new_map.insert({ p.first, new_node });
 			}
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision e67991fd01d5341ea7ee45736431dbe64851911e)
+++ src/AST/Pass.proto.hpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -263,12 +263,12 @@
 		template<typename pass_t>
 		static inline void leave( pass_t &, long ) {}
-	};
-
-	// Finally certain pass desire an up to date symbol table automatically
+	} // namespace scope
+
+	// Certain passes desire an up to date symbol table automatically
 	// detect the presence of a member name `symtab` and call all the members appropriately
 	namespace symtab {
 		// Some simple scoping rules
 		template<typename pass_t>
-		static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab.enterScope(), void() ) {
+		static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab, void() ) {
 			pass.symtab.enterScope();
 		}
@@ -278,5 +278,5 @@
 
 		template<typename pass_t>
-		static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab.leaveScope(), void() ) {
+		static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab, void() ) {
 			pass.symtab.leaveScope();
 		}
@@ -356,5 +356,49 @@
 		#undef SYMTAB_FUNC1
 		#undef SYMTAB_FUNC2
-	};
-};
-};
+	} // namespace symtab
+
+	// Some passes need to mutate TypeDecl and properly update their pointing TypeInstType.
+	// Detect the presence of a member name `subs` and call all members appropriately
+	namespace forall {
+		// Some simple scoping rules
+		template<typename pass_t>
+		static inline auto enter( pass_t & pass, int, const ast::ParameterizedType * type ) 
+		-> decltype( pass.subs, void() ) {
+			if ( ! type->forall.empty() ) pass.subs.beginScope();
+		}
+
+		template<typename pass_t>
+		static inline auto enter( pass_t &, long, const ast::ParameterizedType * ) {}
+
+		template<typename pass_t>
+		static inline auto leave( pass_t & pass, int, const ast::ParameterizedType * type ) 
+		-> decltype( pass.subs, void() ) {
+			if ( ! type->forall.empty() ) { pass.subs.endScope(); }
+		}
+
+		template<typename pass_t>
+		static inline auto leave( pass_t &, long, const ast::ParameterizedType * ) {}
+
+		// Get the substitution table, if present
+		template<typename pass_t>
+		static inline auto subs( pass_t & pass, int ) -> decltype( &pass.subs ) {
+			return &pass.subs;
+		}
+		
+		template<typename pass_t>
+		static inline ast::ForallSubstitutionTable * subs( pass_t &, long ) { return nullptr; }
+
+		// Replaces a TypeInstType's base TypeDecl according to the table
+		template<typename pass_t>
+		static inline auto replace( pass_t & pass, int, const ast::TypeInstType *& inst ) 
+		-> decltype( pass.subs, void() ) {
+			inst = ast::mutate_field( 
+				inst, &ast::TypeInstType::base, pass.subs.replace( inst->base ) );
+		}
+
+		template<typename pass_t>
+		static inline auto replace( pass_t &, long, const ast::TypeInstType *& ) {}
+
+	} // namespace forall
+} // namespace __pass
+} // namespace ast
Index: src/AST/Type.cpp
===================================================================
--- src/AST/Type.cpp	(revision e67991fd01d5341ea7ee45736431dbe64851911e)
+++ src/AST/Type.cpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -21,5 +21,7 @@
 
 #include "Decl.hpp"
+#include "ForallSubstitutor.hpp" // for substituteForall
 #include "Init.hpp"
+#include "Common/utility.h"      // for copy, move
 #include "InitTweak/InitTweak.h" // for getPointerBase
 #include "Tuples/Tuples.h"       // for isTtype
@@ -91,5 +93,22 @@
 );
 
+// --- ParameterizedType
+
+void ParameterizedType::initWithSub( 
+	const ParameterizedType & o, Pass< ForallSubstitutor > & sub 
+) {
+	forall = sub.pass( o.forall );
+}
+
 // --- FunctionType
+
+FunctionType::FunctionType( const FunctionType & o )
+: ParameterizedType( o.qualifiers, copy( o.attributes ) ), returns(), params(), 
+  isVarArgs( o.isVarArgs ) {
+	Pass< ForallSubstitutor > sub;
+	initWithSub( o, sub );           // initialize substitution map
+	returns = sub.pass( o.returns ); // apply to return and parameter types
+	params = sub.pass( o.params );
+}
 
 namespace {
@@ -107,4 +126,17 @@
 
 // --- ReferenceToType
+
+void ReferenceToType::initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub ) {
+	ParameterizedType::initWithSub( o, sub ); // initialize substitution
+	params = sub.pass( o.params );            // apply to parameters
+}
+
+ReferenceToType::ReferenceToType( const ReferenceToType & o )
+: ParameterizedType( o.qualifiers, copy( o.attributes ) ), params(), name( o.name ), 
+  hoistType( o.hoistType ) {
+	Pass< ForallSubstitutor > sub;
+	initWithSub( o, sub );
+}
+
 std::vector<readonly<Decl>> ReferenceToType::lookup( const std::string& name ) const {
 	assertf( aggr(), "Must have aggregate to perform lookup" );
@@ -119,7 +151,7 @@
 // --- StructInstType
 
-StructInstType::StructInstType( const StructDecl * b, CV::Qualifiers q,
-	std::vector<ptr<Attribute>>&& as )
-: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
+StructInstType::StructInstType( 
+	const StructDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
+: ReferenceToType( b->name, q, move(as) ), base( b ) {}
 
 bool StructInstType::isComplete() const { return base ? base->body : false; }
@@ -127,7 +159,7 @@
 // --- UnionInstType
 
-UnionInstType::UnionInstType( const UnionDecl * b, CV::Qualifiers q,
-	std::vector<ptr<Attribute>>&& as )
-: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
+UnionInstType::UnionInstType( 
+	const UnionDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
+: ReferenceToType( b->name, q, move(as) ), base( b ) {}
 
 bool UnionInstType::isComplete() const { return base ? base->body : false; }
@@ -135,7 +167,7 @@
 // --- EnumInstType
 
-EnumInstType::EnumInstType( const EnumDecl * b, CV::Qualifiers q,
-	std::vector<ptr<Attribute>>&& as )
-: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
+EnumInstType::EnumInstType( 
+	const EnumDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
+: ReferenceToType( b->name, q, move(as) ), base( b ) {}
 
 bool EnumInstType::isComplete() const { return base ? base->body : false; }
@@ -143,9 +175,16 @@
 // --- TraitInstType
 
-TraitInstType::TraitInstType( const TraitDecl * b, CV::Qualifiers q,
-	std::vector<ptr<Attribute>>&& as )
-: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
+TraitInstType::TraitInstType( 
+	const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
+: ReferenceToType( b->name, q, move(as) ), base( b ) {}
 
 // --- TypeInstType
+
+TypeInstType::TypeInstType( const TypeInstType & o ) 
+: ReferenceToType( o.name, o.qualifiers, copy( o.attributes ) ), base(), kind( o.kind ) {
+	Pass< ForallSubstitutor > sub;
+	initWithSub( o, sub );      // initialize substitution
+	base = sub.pass( o.base );  // apply to base type
+}
 
 void TypeInstType::set_base( const TypeDecl * b ) {
@@ -159,5 +198,5 @@
 
 TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
-: Type( q ), types( std::move(ts) ), members() {
+: Type( q ), types( move(ts) ), members() {
 	// This constructor is awkward. `TupleType` needs to contain objects so that members can be
 	// named, but members without initializer nodes end up getting constructors, which breaks
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision e67991fd01d5341ea7ee45736431dbe64851911e)
+++ src/AST/Type.hpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -33,4 +33,8 @@
 
 namespace ast {
+
+template< typename T > class Pass;
+
+struct ForallSubstitutor;
 
 class Type : public Node {
@@ -164,5 +168,5 @@
 	static const char *typeNames[];
 
-	BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 
+	BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: Type(q, std::move(as)), kind(k) {}
 
@@ -266,4 +270,7 @@
 /// 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>>;
@@ -277,4 +284,11 @@
 	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:
@@ -302,4 +316,6 @@
 	: ParameterizedType(q), returns(), params(), isVarArgs(va) {}
 
+	FunctionType( const FunctionType & o );
+
 	/// true if either the parameters or return values contain a tttype
 	bool isTtype() const;
@@ -315,4 +331,7 @@
 /// base class for types that refer to types declared elsewhere (aggregates and typedefs)
 class ReferenceToType : public ParameterizedType {
+protected:
+	/// Initializes forall and parameters based on substitutor
+	void initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub );
 public:
 	std::vector<ptr<Expr>> params;
@@ -320,7 +339,9 @@
 	bool hoistType = false;
 
-	ReferenceToType( const std::string& n, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
+	ReferenceToType(
+		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: ParameterizedType(q, std::move(as)), params(), name(n) {}
+
+	ReferenceToType( const ReferenceToType & o );
 
 	/// Gets aggregate declaration this type refers to
@@ -339,9 +360,10 @@
 	readonly<StructDecl> base;
 
-	StructInstType( const std::string& n, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
+	StructInstType(
+		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: ReferenceToType( n, q, std::move(as) ), base() {}
-	StructInstType( const StructDecl * b, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} );
+
+	StructInstType(
+		const StructDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
 
 	bool isComplete() const override;
@@ -360,9 +382,10 @@
 	readonly<UnionDecl> base;
 
-	UnionInstType( const std::string& n, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
+	UnionInstType(
+		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: ReferenceToType( n, q, std::move(as) ), base() {}
-	UnionInstType( const UnionDecl * b, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} );
+
+	UnionInstType(
+		const UnionDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
 
 	bool isComplete() const override;
@@ -381,9 +404,10 @@
 	readonly<EnumDecl> base;
 
-	EnumInstType( const std::string& n, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
+	EnumInstType(
+		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: ReferenceToType( n, q, std::move(as) ), base() {}
-	EnumInstType( const EnumDecl * b, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} );
+
+	EnumInstType(
+		const EnumDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
 
 	bool isComplete() const override;
@@ -402,9 +426,10 @@
 	readonly<TraitDecl> base;
 
-	TraitInstType( const std::string& n, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
+	TraitInstType(
+		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: ReferenceToType( n, q, std::move(as) ), base() {}
-	TraitInstType( const TraitDecl * b, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} );
+
+	TraitInstType(
+		const TraitDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
 
 	// not meaningful for TraitInstType
@@ -425,10 +450,15 @@
 	TypeVar::Kind kind;
 
-	TypeInstType( const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
+	TypeInstType(
+		const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
 		std::vector<ptr<Attribute>> && as = {} )
 	: ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {}
-	TypeInstType( const std::string& n, TypeVar::Kind k, CV::Qualifiers q = {},
+
+	TypeInstType(
+		const std::string& n, TypeVar::Kind k, CV::Qualifiers q = {},
 		std::vector<ptr<Attribute>> && as = {} )
 	: ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {}
+
+	TypeInstType( const TypeInstType & o );
 
 	/// sets `base`, updating `kind` correctly
Index: src/AST/TypeSubstitution.cpp
===================================================================
--- src/AST/TypeSubstitution.cpp	(revision e67991fd01d5341ea7ee45736431dbe64851911e)
+++ src/AST/TypeSubstitution.cpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -92,5 +92,5 @@
 namespace {
 	struct EnvTrimmer {
-		ptr<TypeSubstitution> env;
+		const TypeSubstitution * env;
 		TypeSubstitution * newEnv;
 		EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
@@ -108,11 +108,6 @@
 	if ( env ) {
 		TypeSubstitution * newEnv = new TypeSubstitution();
-#if TIME_TO_CONVERT_PASSES
 		Pass<EnvTrimmer> trimmer( env, newEnv );
 		expr->accept( trimmer );
-#else
-		(void)expr;
-		(void)env;
-#endif
 		return newEnv;
 	}
@@ -121,19 +116,15 @@
 
 void TypeSubstitution::normalize() {
-#if TIME_TO_CONVERT_PASSES
-	PassVisitor<Substituter> sub( *this, true );
+	Pass<Substituter> sub( *this, true );
 	do {
 		sub.pass.subCount = 0;
 		sub.pass.freeOnly = true;
 		for ( TypeEnvType::iterator i = typeEnv.begin(); i != typeEnv.end(); ++i ) {
-			i->second = i->second->acceptMutator( sub );
+			i->second = i->second->accept( sub );
 		}
 	} while ( sub.pass.subCount );
-#endif
-}
-
-#if TIME_TO_CONVERT_PASSES
-
-Type * TypeSubstitution::Substituter::postmutate( TypeInstType *inst ) {
+}
+
+const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) {
 	BoundVarsType::const_iterator bound = boundVars.find( inst->name );
 	if ( bound != boundVars.end() ) return inst;
@@ -146,5 +137,5 @@
 		// Note: this does not prevent cycles in the general case, so it may be necessary to do something more sophisticated here.
 		// TODO: investigate preventing type variables from being bound to themselves in the first place.
-		if ( TypeInstType * replacement = i->second.as<TypeInstType>() ) {
+		if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) {
 			if ( inst->name == replacement->name ) {
 				return inst;
@@ -153,13 +144,14 @@
 		// std::cerr << "found " << inst->name << ", replacing with " << i->second << std::endl;
 		subCount++;
-		Type * newtype = i->second->clone();
-		newtype->get_qualifiers() |= inst->get_qualifiers();
-		delete inst;
-		// Note: need to recursively apply substitution to the new type because normalize does not substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
-		return newtype->acceptMutator( *visitor );
-	} // if
-}
-
-Expression * TypeSubstitution::Substituter::postmutate( NameExpr * nameExpr ) {
+		ptr<Type> newType = i->second; // force clone if needed
+		add_qualifiers( newType, inst->qualifiers );
+		// Note: need to recursively apply substitution to the new type because normalize does not 
+		// substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
+		newType = newType->accept( *visitor );
+		return newType.release();
+	} // if
+}
+
+const Expr * TypeSubstitution::Substituter::postvisit( const NameExpr * nameExpr ) {
 	VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name );
 	if ( i == sub.varEnv.end() ) {
@@ -168,45 +160,43 @@
 		subCount++;
 		delete nameExpr;
-		return i->second->clone();
-	} // if
-}
-
-void TypeSubstitution::Substituter::premutate( Type * type ) {
+		return i->second;
+	} // if
+}
+
+void TypeSubstitution::Substituter::previsit( const ParameterizedType * ptype ) {
 	GuardValue( boundVars );
 	// bind type variables from forall-qualifiers
 	if ( freeOnly ) {
-		for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
-			boundVars.insert( (*tyvar)->name );
+		for ( const TypeDecl * tyvar : ptype->forall ) {
+				boundVars.insert( tyvar->name );
 		} // for
 	} // if
 }
 
-template< typename TypeClass >
-void TypeSubstitution::Substituter::handleAggregateType( TypeClass * type ) {
+void TypeSubstitution::Substituter::handleAggregateType( const ReferenceToType * type ) {
 	GuardValue( boundVars );
 	// bind type variables from forall-qualifiers
 	if ( freeOnly ) {
-		for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
-			boundVars.insert( (*tyvar)->name );
+		for ( const TypeDecl * tyvar : type->forall ) {
+			boundVars.insert( tyvar->name );
 		} // for
 		// bind type variables from generic type instantiations
-		std::list< TypeDecl* > *baseParameters = type->get_baseParameters();
-		if ( baseParameters && ! type->parameters.empty() ) {
-			for ( std::list< TypeDecl* >::const_iterator tyvar = baseParameters->begin(); tyvar != baseParameters->end(); ++tyvar ) {
-				boundVars.insert( (*tyvar)->name );
-			} // for
-		} // if
-	} // if
-}
-
-void TypeSubstitution::Substituter::premutate( StructInstType * aggregateUseType ) {
+		if ( auto decl = type->aggr() ) {
+			if ( ! type->params.empty() ) {
+				for ( const TypeDecl * tyvar : decl->params ) {
+					boundVars.insert( tyvar->name );
+				} // for
+			} // if
+		}
+	} // if
+}
+
+void TypeSubstitution::Substituter::previsit( const StructInstType * aggregateUseType ) {
 	handleAggregateType( aggregateUseType );
 }
 
-void TypeSubstitution::Substituter::premutate( UnionInstType *aggregateUseType ) {
+void TypeSubstitution::Substituter::previsit( const UnionInstType *aggregateUseType ) {
 	handleAggregateType( aggregateUseType );
 }
-
-#endif
 
 } // namespace ast
Index: src/AST/TypeSubstitution.hpp
===================================================================
--- src/AST/TypeSubstitution.hpp	(revision e67991fd01d5341ea7ee45736431dbe64851911e)
+++ src/AST/TypeSubstitution.hpp	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -155,18 +155,14 @@
 		Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
 
-#if TIME_TO_CONVERT_PASSES
-
-		Type * postmutate( TypeInstType * aggregateUseType );
-		Expression * postmutate( NameExpr * nameExpr );
+		const Type * postvisit( const TypeInstType * aggregateUseType );
+		const Expr * postvisit( const NameExpr * nameExpr );
 
 		/// Records type variable bindings from forall-statements
-		void premutate( Type * type );
+		void previsit( const ParameterizedType * type );
 		/// Records type variable bindings from forall-statements and instantiations of generic types
-		template< typename TypeClass > void handleAggregateType( TypeClass * type );
-
-		void premutate( StructInstType * aggregateUseType );
-		void premutate( UnionInstType * aggregateUseType );
-
-#endif
+		void handleAggregateType( const ReferenceToType * type );
+
+		void previsit( const StructInstType * aggregateUseType );
+		void previsit( const UnionInstType * aggregateUseType );
 
 		const TypeSubstitution & sub;
Index: src/AST/module.mk
===================================================================
--- src/AST/module.mk	(revision e67991fd01d5341ea7ee45736431dbe64851911e)
+++ src/AST/module.mk	(revision f53acdf88f0790f441b622ba4624c865224726a7)
@@ -22,4 +22,5 @@
 	AST/DeclReplacer.cpp \
 	AST/Expr.cpp \
+	AST/ForallSubstitutionTable.cpp \
 	AST/GenericSubstitution.cpp \
 	AST/Init.cpp \
