Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision e61207e7b1f6fa896f900ac3b84bd28c9bfb5ffe)
+++ src/AST/Convert.cpp	(revision 41b24c88e3b9a228864050167f32e8ca015b0f9d)
@@ -135,5 +135,5 @@
 		decl->parent = parent;
 		decl->body   = old->body;
-		decl->parameters = params;
+		decl->params = params;
 		decl->members    = members;
 		decl->extension  = old->extension;
@@ -592,4 +592,9 @@
 
 	}
+
+	virtual void visit( AttrExpr * ) override final {
+
+		assert( 0 );
+	}
 };
 
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision e61207e7b1f6fa896f900ac3b84bd28c9bfb5ffe)
+++ src/AST/Decl.hpp	(revision 41b24c88e3b9a228864050167f32e8ca015b0f9d)
@@ -30,4 +30,7 @@
 #include "Parser/ParseNode.h"  // for DeclarationNode::Aggregate
 
+// Must be included in *all* AST classes; should be #undef'd at the end of the file
+#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
+
 namespace ast {
 
@@ -55,4 +58,5 @@
 private:
 	Decl * clone() const override = 0;
+	MUTATE_FRIEND
 };
 
@@ -87,4 +91,5 @@
 private:
 	DeclWithType * clone() const override = 0;
+	MUTATE_FRIEND
 };
 
@@ -108,8 +113,5 @@
 private:
 	ObjectDecl * clone() const override { return new ObjectDecl{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	MUTATE_FRIEND
 };
 
@@ -135,8 +137,5 @@
 private:
 	FunctionDecl * clone() const override { return new FunctionDecl( *this ); }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	MUTATE_FRIEND
 };
 
@@ -157,4 +156,5 @@
 private:
 	NamedTypeDecl* clone() const override = 0;
+	MUTATE_FRIEND
 };
 
@@ -198,8 +198,5 @@
 private:
 	TypeDecl * clone() const override { return new TypeDecl{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	MUTATE_FRIEND
 };
 
@@ -216,8 +213,5 @@
 private:
 	TypedefDecl * clone() const override { return new TypedefDecl{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	MUTATE_FRIEND
 };
 
@@ -238,4 +232,8 @@
 	AggregateDecl* set_body( bool b ) { body = b; return this; }
 
+private:
+	AggregateDecl * clone() const override = 0;
+	MUTATE_FRIEND
+
 protected:
 	/// Produces a name for the kind of aggregate
@@ -260,8 +258,5 @@
 private:
 	StructDecl * clone() const override { return new StructDecl{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	MUTATE_FRIEND
 
 	std::string typeString() const override { return "struct"; }
@@ -278,8 +273,5 @@
 private:
 	UnionDecl * clone() const override { return new UnionDecl{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	MUTATE_FRIEND
 
 	std::string typeString() const override { return "union"; }
@@ -299,8 +291,5 @@
 private:
 	EnumDecl * clone() const override { return new EnumDecl{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	MUTATE_FRIEND
 
 	std::string typeString() const override { return "enum"; }
@@ -320,8 +309,5 @@
 private:
 	TraitDecl * clone() const override { return new TraitDecl{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	MUTATE_FRIEND
 
 	std::string typeString() const override { return "trait"; }
@@ -338,8 +324,5 @@
 private:
 	AsmDecl *clone() const override { return new AsmDecl( *this ); }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	MUTATE_FRIEND
 };
 
@@ -355,11 +338,10 @@
 private:
 	StaticAssertDecl * clone() const override { return new StaticAssertDecl( *this ); }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	MUTATE_FRIEND
 };
 
 }
+
+#undef MUTATE_FRIEND
 
 // Local Variables: //
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision e61207e7b1f6fa896f900ac3b84bd28c9bfb5ffe)
+++ src/AST/Expr.hpp	(revision 41b24c88e3b9a228864050167f32e8ca015b0f9d)
@@ -27,4 +27,7 @@
 #include "Visitor.hpp"
 
+// Must be included in *all* AST classes; should be #undef'd at the end of the file
+#define MUTATE_FRIEND template<typename node_t> friend auto mutate(const node_t * node);
+
 namespace ast {
 
@@ -127,4 +130,5 @@
 private:
 	Expr * clone() const override = 0;
+	MUTATE_FRIEND
 };
 
@@ -141,4 +145,5 @@
 private:
 	ApplicationExpr * clone() const override { return new ApplicationExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -160,4 +165,5 @@
 private:
 	UntypedExpr * clone() const override { return new UntypedExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -173,4 +179,5 @@
 private:
 	NameExpr * clone() const override { return new NameExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -185,4 +192,5 @@
 private:
 	AddressExpr * clone() const override { return new AddressExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -198,4 +206,5 @@
 private:
 	LabelAddressExpr * clone() const override { return new LabelAddressExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -217,4 +226,5 @@
 private:
 	CastExpr * clone() const override { return new CastExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -234,4 +244,5 @@
 private:
 	KeywordCastExpr * clone() const override { return new KeywordCastExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -247,4 +258,5 @@
 private:
 	VirtualCastExpr * clone() const override { return new VirtualCastExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -261,4 +273,5 @@
 private:
 	UntypedMemberExpr * clone() const override { return new UntypedMemberExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -274,4 +287,5 @@
 private:
 	MemberExpr * clone() const override { return new MemberExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -289,4 +303,5 @@
 private:
 	VariableExpr * clone() const override { return new VariableExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -332,4 +347,5 @@
 private:
 	ConstantExpr * clone() const override { return new ConstantExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -347,4 +363,5 @@
 private:
 	SizeofExpr * clone() const override { return new SizeofExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -362,4 +379,5 @@
 private:
 	AlignofExpr * clone() const override { return new AlignofExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -376,4 +394,5 @@
 private:
 	UntypedOffsetofExpr * clone() const override { return new UntypedOffsetofExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -389,4 +408,5 @@
 private:
 	OffsetofExpr * clone() const override { return new OffsetofExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -401,4 +421,5 @@
 private:
 	OffsetPackExpr * clone() const override { return new OffsetPackExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -418,4 +439,5 @@
 private:
 	LogicalExpr * clone() const override { return new LogicalExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -433,4 +455,5 @@
 private:
 	ConditionalExpr * clone() const override { return new ConditionalExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -447,4 +470,5 @@
 private:
 	CommaExpr * clone() const override { return new CommaExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -459,4 +483,5 @@
 private:
 	TypeExpr * clone() const override { return new TypeExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -470,4 +495,6 @@
 
 }
+
+#undef MUTATE_FRIEND
 
 // Local Variables: //
Index: src/AST/Init.hpp
===================================================================
--- src/AST/Init.hpp	(revision e61207e7b1f6fa896f900ac3b84bd28c9bfb5ffe)
+++ src/AST/Init.hpp	(revision 41b24c88e3b9a228864050167f32e8ca015b0f9d)
@@ -23,4 +23,7 @@
 #include "Visitor.hpp"
 
+// Must be included in *all* AST classes; should be #undef'd at the end of the file
+#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
+
 namespace ast {
 
@@ -40,4 +43,5 @@
 private:
 	Designation* clone() const override { return new Designation{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -55,4 +59,5 @@
 private:
 	Init * clone() const override = 0;
+	MUTATE_FRIEND
 };
 
@@ -69,8 +74,5 @@
 private:
 	SingleInit * clone() const override { return new SingleInit{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	MUTATE_FRIEND
 };
 
@@ -97,8 +99,5 @@
 private:
 	ListInit * clone() const override { return new ListInit{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	MUTATE_FRIEND
 };
 
@@ -120,11 +119,10 @@
 private:
 	ConstructorInit * clone() const override { return new ConstructorInit{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	MUTATE_FRIEND
 };
 
 }
+
+#undef MUTATE_FRIEND
 
 // Local Variables: //
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision e61207e7b1f6fa896f900ac3b84bd28c9bfb5ffe)
+++ src/AST/Pass.impl.hpp	(revision 41b24c88e3b9a228864050167f32e8ca015b0f9d)
@@ -19,4 +19,6 @@
 #include <type_traits>
 #include <unordered_map>
+
+#include "AST/TypeSubstitution.hpp"
 
 #define VISIT_START( node ) \
Index: src/AST/Stmt.hpp
===================================================================
--- src/AST/Stmt.hpp	(revision e61207e7b1f6fa896f900ac3b84bd28c9bfb5ffe)
+++ src/AST/Stmt.hpp	(revision 41b24c88e3b9a228864050167f32e8ca015b0f9d)
@@ -26,4 +26,7 @@
 #include "Common/CodeLocation.h"
 
+// Must be included in *all* AST classes; should be #undef'd at the end of the file
+#define MUTATE_FRIEND template<typename node_t> friend auto mutate(const node_t * node);
+
 namespace ast {
 
@@ -35,12 +38,13 @@
 	std::vector<Label> labels;
 
-	Stmt( const CodeLocation& loc, std::vector<Label>&& labels = {} )
+	Stmt( const CodeLocation & loc, std::vector<Label> && labels = {} )
 	: ParseNode(loc), labels(std::move(labels)) {}
 
 	Stmt(const Stmt& o) : ParseNode(o), labels(o.labels) {}
 
-	const Stmt* accept( Visitor& v ) const override = 0;
-private:
-	Stmt* clone() const override = 0;
+	const Stmt * accept( Visitor & v ) const override = 0;
+private:
+	Stmt * clone() const override = 0;
+	MUTATE_FRIEND
 };
 
@@ -50,5 +54,5 @@
 	std::list<ptr<Stmt>> kids;
 
-	CompoundStmt(const CodeLocation& loc, std::list<ptr<Stmt>>&& ks = {} )
+	CompoundStmt(const CodeLocation & loc, std::list<ptr<Stmt>> && ks = {} )
 	: Stmt(loc), kids(std::move(ks)) {}
 
@@ -56,14 +60,11 @@
 	CompoundStmt( CompoundStmt&& o ) = default;
 
-	void push_back( Stmt* s ) { kids.emplace_back( s ); }
-	void push_front( Stmt* s ) { kids.emplace_front( s ); }
-
-	const CompoundStmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	CompoundStmt* clone() const override { return new CompoundStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	void push_back( Stmt * s ) { kids.emplace_back( s ); }
+	void push_front( Stmt * s ) { kids.emplace_front( s ); }
+
+	const CompoundStmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	CompoundStmt * clone() const override { return new CompoundStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -71,14 +72,11 @@
 class NullStmt final : public Stmt {
 public:
-	NullStmt( const CodeLocation& loc, std::vector<Label>&& labels = {} )
+	NullStmt( const CodeLocation & loc, std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)) {}
 
-	const NullStmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	NullStmt* clone() const override { return new NullStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const NullStmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	NullStmt * clone() const override { return new NullStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -90,11 +88,8 @@
 	ExprStmt( const CodeLocation & loc, const Expr * e ) : Stmt(loc), expr(e) {}
 
-	const Stmt * accept( Visitor& v ) const override { return v.visit( this ); }
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
 private:
 	ExprStmt * clone() const override { return new ExprStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	MUTATE_FRIEND
 };
 
@@ -107,19 +102,16 @@
 	std::vector<Label> gotoLabels;
 
-	AsmStmt( const CodeLocation& loc, bool isVolatile, const Expr * instruction,
-		std::vector<ptr<Expr>>&& output, std::vector<ptr<Expr>>&& input,
-		std::vector<ptr<ConstantExpr>>&& clobber, std::vector<Label>&& gotoLabels,
-		std::vector<Label>&& labels = {})
+	AsmStmt( const CodeLocation & loc, bool isVolatile, const Expr * instruction,
+		std::vector<ptr<Expr>> && output, std::vector<ptr<Expr>> && input,
+		std::vector<ptr<ConstantExpr>> && clobber, std::vector<Label> && gotoLabels,
+		std::vector<Label> && labels = {})
 	: Stmt(loc, std::move(labels)), isVolatile(isVolatile), instruction(instruction),
 	  output(std::move(output)), input(std::move(input)), clobber(std::move(clobber)),
 	  gotoLabels(std::move(gotoLabels)) {}
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	AsmStmt* clone() const override { return new AsmStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	AsmStmt * clone() const override { return new AsmStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -128,15 +120,12 @@
 	std::string directive;
 
-	DirectiveStmt( const CodeLocation& loc, const std::string & directive,
-		std::vector<Label>&& labels = {} )
+	DirectiveStmt( const CodeLocation & loc, const std::string & directive,
+		std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)), directive(directive) {}
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	DirectiveStmt* clone() const override { return new DirectiveStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	DirectiveStmt * clone() const override { return new DirectiveStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -148,17 +137,14 @@
 	std::vector<ptr<Stmt>> inits;
 
-	IfStmt( const CodeLocation& loc, const Expr* cond, const Stmt* thenPart,
-		Stmt * const elsePart, std::vector<ptr<Stmt>>&& inits,
-		std::vector<Label>&& labels = {} )
+	IfStmt( const CodeLocation & loc, const Expr * cond, const Stmt * thenPart,
+		Stmt * const elsePart, std::vector<ptr<Stmt>> && inits,
+		std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)), cond(cond), thenPart(thenPart), elsePart(elsePart),
 	  inits(std::move(inits)) {}
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	IfStmt* clone() const override { return new IfStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	IfStmt * clone() const override { return new IfStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -168,15 +154,12 @@
 	std::vector<ptr<Stmt>> stmts;
 
-	SwitchStmt( const CodeLocation& loc, const Expr* cond, std::vector<ptr<Stmt>>&& stmts,
-		std::vector<Label>&& labels = {} )
+	SwitchStmt( const CodeLocation & loc, const Expr * cond, std::vector<ptr<Stmt>> && stmts,
+		std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)), cond(cond), stmts(std::move(stmts)) {}
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	SwitchStmt* clone() const override { return new SwitchStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	SwitchStmt * clone() const override { return new SwitchStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -186,17 +169,14 @@
 	std::vector<ptr<Stmt>> stmts;
 
-    CaseStmt( const CodeLocation& loc, const Expr* cond, std::vector<ptr<Stmt>>&& stmts,
-        std::vector<Label>&& labels = {} )
-    : Stmt(loc, std::move(labels)), cond(cond), stmts(std::move(stmts)) {}
+	CaseStmt( const CodeLocation & loc, const Expr * cond, std::vector<ptr<Stmt>> && stmts,
+		std::vector<Label> && labels = {} )
+	: Stmt(loc, std::move(labels)), cond(cond), stmts(std::move(stmts)) {}
 
 	bool isDefault() { return !cond; }
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	CaseStmt* clone() const override { return new CaseStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	CaseStmt * clone() const override { return new CaseStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -208,16 +188,13 @@
 	bool isDoWhile;
 
-	WhileStmt( const CodeLocation& loc, const Expr* cond, const Stmt* body,
-		std::vector<ptr<Stmt>>&& inits, bool isDoWhile = false, std::vector<Label>&& labels = {} )
+	WhileStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body,
+		std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)), cond(cond), body(body), inits(std::move(inits)),
 	  isDoWhile(isDoWhile) {}
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	WhileStmt* clone() const override { return new WhileStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	WhileStmt * clone() const override { return new WhileStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -229,16 +206,13 @@
 	ptr<Stmt> body;
 
-	ForStmt( const CodeLocation& loc, std::vector<ptr<Stmt>>&& inits, const Expr* cond,
-		const Expr* inc, const Stmt* body, std::vector<Label>&& labels = {} )
+	ForStmt( const CodeLocation & loc, std::vector<ptr<Stmt>> && inits, const Expr * cond,
+		const Expr * inc, const Stmt * body, std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)), inits(std::move(inits)), cond(cond), inc(inc),
 	  body(body) {}
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	ForStmt* clone() const override { return new ForStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	ForStmt * clone() const override { return new ForStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -253,8 +227,8 @@
 	Kind kind;
 
-	BranchStmt( const CodeLocation& loc, Kind kind, Label target,
-		std::vector<Label>&& labels = {} );
-	BranchStmt( const CodeLocation& loc, const Expr* computedTarget,
-		std::vector<Label>&& labels = {} )
+	BranchStmt( const CodeLocation & loc, Kind kind, Label target,
+		std::vector<Label> && labels = {} );
+	BranchStmt( const CodeLocation & loc, const Expr * computedTarget,
+		std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)), originalTarget(loc), target(loc),
 	  computedTarget(computedTarget), kind(Goto) {}
@@ -262,11 +236,8 @@
 	const char * kindName() { return kindNames[kind]; }
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	BranchStmt* clone() const override { return new BranchStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	BranchStmt * clone() const override { return new BranchStmt{ *this }; }
+	MUTATE_FRIEND
 
 	static const char * kindNames[kindEnd];
@@ -277,14 +248,11 @@
 	ptr<Expr> expr;
 
-	ReturnStmt( const CodeLocation& loc, const Expr* expr, std::vector<Label>&& labels = {} )
+	ReturnStmt( const CodeLocation & loc, const Expr * expr, std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)), expr(expr) {}
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	ReturnStmt* clone() const override { return new ReturnStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	ReturnStmt * clone() const override { return new ReturnStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -297,15 +265,12 @@
 	Kind kind;
 
-	ThrowStmt( const CodeLocation& loc, Kind kind, const Expr* expr, const Expr* target,
-		std::vector<Label>&& labels = {} )
+	ThrowStmt( const CodeLocation & loc, Kind kind, const Expr * expr, const Expr * target,
+		std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)), expr(expr), target(target), kind(kind) {}
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	ThrowStmt* clone() const override { return new ThrowStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	ThrowStmt * clone() const override { return new ThrowStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -316,16 +281,13 @@
 	ptr<FinallyStmt> finally;
 
-	TryStmt( const CodeLocation& loc, const CompoundStmt* body,
-		std::vector<ptr<CatchStmt>>&& handlers, const FinallyStmt* finally,
-		std::vector<Label>&& labels = {} )
+	TryStmt( const CodeLocation & loc, const CompoundStmt * body,
+		std::vector<ptr<CatchStmt>> && handlers, const FinallyStmt * finally,
+		std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)), body(body), handlers(std::move(handlers)), finally(finally) {}
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	TryStmt* clone() const override { return new TryStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	TryStmt * clone() const override { return new TryStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -339,15 +301,12 @@
 	Kind kind;
 
-	CatchStmt( const CodeLocation& loc, Kind kind, const Decl* decl, const Expr* cond,
-		const Stmt* body, std::vector<Label>&& labels = {} )
+	CatchStmt( const CodeLocation & loc, Kind kind, const Decl * decl, const Expr * cond,
+		const Stmt * body, std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)), decl(decl), cond(cond), body(body), kind(kind) {}
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	CatchStmt* clone() const override { return new CatchStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	CatchStmt * clone() const override { return new CatchStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -356,15 +315,12 @@
 	ptr<CompoundStmt> body;
 
-	FinallyStmt( const CodeLocation& loc, const CompoundStmt* body,
-		std::vector<Label>&& labels = {} )
+	FinallyStmt( const CodeLocation & loc, const CompoundStmt * body,
+		std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)), body(body) {}
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	FinallyStmt* clone() const override { return new FinallyStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	FinallyStmt * clone() const override { return new FinallyStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -397,14 +353,11 @@
 	OrElse orElse;
 
-	WaitForStmt( const CodeLocation& loc, std::vector<Label>&& labels = {} )
+	WaitForStmt( const CodeLocation & loc, std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)) {}
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	WaitForStmt* clone() const override { return new WaitForStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	WaitForStmt * clone() const override { return new WaitForStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -414,15 +367,12 @@
 	ptr<Stmt> stmt;
 
-	WithStmt( const CodeLocation& loc, std::vector<ptr<Expr>>&& exprs, const Stmt* stmt,
-		std::vector<Label>&& labels = {} )
+	WithStmt( const CodeLocation & loc, std::vector<ptr<Expr>> && exprs, const Stmt * stmt,
+		std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)), exprs(std::move(exprs)), stmt(stmt) {}
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	WithStmt* clone() const override { return new WithStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	WithStmt * clone() const override { return new WithStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -431,14 +381,11 @@
 	ptr<Decl> decl;
 
-	DeclStmt( const CodeLocation& loc, const Decl* decl, std::vector<Label>&& labels = {} )
+	DeclStmt( const CodeLocation & loc, const Decl * decl, std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)), decl(decl) {}
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	DeclStmt* clone() const override { return new DeclStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	DeclStmt * clone() const override { return new DeclStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -447,18 +394,17 @@
 	readonly<Stmt> callStmt;
 
-	ImplicitCtorDtorStmt( const CodeLocation& loc, const Stmt* callStmt,
-		std::vector<Label>&& labels = {} )
+	ImplicitCtorDtorStmt( const CodeLocation & loc, const Stmt * callStmt,
+		std::vector<Label> && labels = {} )
 	: Stmt(loc, std::move(labels)), callStmt(callStmt) {}
 
-	const Stmt* accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	ImplicitCtorDtorStmt* clone() const override { return new ImplicitCtorDtorStmt{ *this }; }
-
-	/// Must be copied in ALL derived classes
-	template<typename node_t>
-	friend node_t * mutate(const node_t * node);
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	ImplicitCtorDtorStmt * clone() const override { return new ImplicitCtorDtorStmt{ *this }; }
+	MUTATE_FRIEND
 };
 
 }
+
+#undef MUTATE_FRIEND
 
 // Local Variables: //
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision e61207e7b1f6fa896f900ac3b84bd28c9bfb5ffe)
+++ src/AST/Type.hpp	(revision 41b24c88e3b9a228864050167f32e8ca015b0f9d)
@@ -29,4 +29,7 @@
 #include "Visitor.hpp"
 
+// Must be included in *all* AST classes; should be #undef'd at the end of the file
+#define MUTATE_FRIEND template<typename node_t> friend auto mutate(const node_t * node);
+
 namespace ast {
 
@@ -70,4 +73,5 @@
 private:
 	virtual Type * clone() const override = 0;
+	MUTATE_FRIEND
 };
 
@@ -84,4 +88,5 @@
 private:
 	VoidType * clone() const override { return new VoidType{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -146,4 +151,5 @@
 private:
 	BasicType * clone() const override { return new BasicType{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -176,4 +182,5 @@
 private:
 	PointerType * clone() const override { return new PointerType{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -197,4 +204,5 @@
 private:
 	ArrayType * clone() const override { return new ArrayType{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -216,4 +224,5 @@
 private:
 	ReferenceType * clone() const override { return new ReferenceType{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -230,4 +239,5 @@
 private:
 	QualifiedType * clone() const override { return new QualifiedType{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -245,4 +255,5 @@
 private:
 	virtual ParameterizedType * clone() const override = 0;
+	MUTATE_FRIEND
 };
 
@@ -274,4 +285,5 @@
 private:
 	FunctionType * clone() const override { return new FunctionType{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -295,4 +307,5 @@
 private:
 	virtual ReferenceToType * clone() const override = 0;
+	MUTATE_FRIEND
 
 protected:
@@ -319,4 +332,5 @@
 private:
 	StructInstType * clone() const override { return new StructInstType{ *this }; }
+	MUTATE_FRIEND
 
 	std::string typeString() const override { return "struct"; }
@@ -341,4 +355,5 @@
 private:
 	UnionInstType * clone() const override { return new UnionInstType{ *this }; }
+	MUTATE_FRIEND
 
 	std::string typeString() const override { return "union"; }
@@ -363,4 +378,5 @@
 private:
 	EnumInstType * clone() const override { return new EnumInstType{ *this }; }
+	MUTATE_FRIEND
 
 	std::string typeString() const override { return "enum"; }
@@ -386,4 +402,5 @@
 private:
 	TraitInstType * clone() const override { return new TraitInstType{ *this }; }
+	MUTATE_FRIEND
 
 	std::string typeString() const override { return "trait"; }
@@ -414,4 +431,5 @@
 private:
 	TypeInstType * clone() const override { return new TypeInstType{ *this }; }
+	MUTATE_FRIEND
 
 	std::string typeString() const override { return "type"; }
@@ -442,4 +460,5 @@
 private:
 	TupleType * clone() const override { return new TupleType{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -456,4 +475,5 @@
 private:
 	TypeofType * clone() const override { return new TypeofType{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -466,4 +486,5 @@
 private:
 	VarArgsType * clone() const override { return new VarArgsType{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -476,4 +497,5 @@
 private:
 	ZeroType * clone() const override { return new ZeroType{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -486,4 +508,5 @@
 private:
 	OneType * clone() const override { return new OneType{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -496,7 +519,10 @@
 private:
 	GlobalScopeType * clone() const override { return new GlobalScopeType{ *this }; }
+	MUTATE_FRIEND
 };
 
 }
+
+#undef MUTATE_FRIEND
 
 // Local Variables: //
Index: src/AST/TypeSubstitution.cpp
===================================================================
--- src/AST/TypeSubstitution.cpp	(revision 41b24c88e3b9a228864050167f32e8ca015b0f9d)
+++ src/AST/TypeSubstitution.cpp	(revision 41b24c88e3b9a228864050167f32e8ca015b0f9d)
@@ -0,0 +1,221 @@
+//
+// 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.
+//
+// TypeSubstitution.cc --
+//
+// Author           : Richard C. Bilson
+// Created On       : Mon May 18 07:44:20 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Thu Mar 16 15:54:35 2017
+// Update Count     : 4
+//
+
+#include "Type.hpp"   // for TypeInstType, Type, StructInstType, UnionInstType
+#include "TypeSubstitution.hpp"
+
+namespace ast {
+
+TypeSubstitution::TypeSubstitution() {
+}
+
+TypeSubstitution::TypeSubstitution( const TypeSubstitution &other ) : Node() {
+	initialize( other, *this );
+}
+
+TypeSubstitution::~TypeSubstitution() {
+	for ( TypeEnvType::iterator i = typeEnv.begin(); i != typeEnv.end(); ++i ) {
+		delete( i->second );
+	}
+	for ( VarEnvType::iterator i = varEnv.begin(); i != varEnv.end(); ++i ) {
+		delete( i->second );
+	}
+}
+
+TypeSubstitution &TypeSubstitution::operator=( const TypeSubstitution &other ) {
+	if ( this == &other ) return *this;
+	initialize( other, *this );
+	return *this;
+}
+
+void TypeSubstitution::initialize( const TypeSubstitution &src, TypeSubstitution &dest ) {
+	dest.typeEnv.clear();
+	dest.varEnv.clear();
+	dest.add( src );
+}
+
+void TypeSubstitution::add( const TypeSubstitution &other ) {
+	for ( TypeEnvType::const_iterator i = other.typeEnv.begin(); i != other.typeEnv.end(); ++i ) {
+		typeEnv[ i->first ] = i->second;
+	} // for
+	for ( VarEnvType::const_iterator i = other.varEnv.begin(); i != other.varEnv.end(); ++i ) {
+		varEnv[ i->first ] = i->second;
+	} // for
+}
+
+void TypeSubstitution::add( std::string formalType, const Type *actualType ) {
+	typeEnv[ formalType ] = actualType;
+}
+
+void TypeSubstitution::remove( std::string formalType ) {
+	TypeEnvType::iterator i = typeEnv.find( formalType );
+	if ( i != typeEnv.end() ) {
+		typeEnv.erase( formalType );
+	} // if
+}
+
+const Type *TypeSubstitution::lookup( std::string formalType ) const {
+	TypeEnvType::const_iterator i = typeEnv.find( formalType );
+
+	// break on not in substitution set
+	if ( i == typeEnv.end() ) return 0;
+
+	// attempt to transitively follow TypeInstType links.
+	while ( const TypeInstType *actualType = i->second.as<TypeInstType>()) {
+		const std::string& typeName = actualType->name;
+
+		// break cycles in the transitive follow
+		if ( formalType == typeName ) break;
+
+		// Look for the type this maps to, returning previous mapping if none-such
+		i = typeEnv.find( typeName );
+		if ( i == typeEnv.end() ) return actualType;
+	}
+
+	// return type from substitution set
+	return i->second;
+}
+
+bool TypeSubstitution::empty() const {
+	return typeEnv.empty() && varEnv.empty();
+}
+
+namespace {
+	struct EnvTrimmer {
+		ptr<TypeSubstitution> env;
+		TypeSubstitution * newEnv;
+		EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
+		void previsit( TypeDecl * tyDecl ) {
+			// transfer known bindings for seen type variables
+			if ( const Type * t = env->lookup( tyDecl->name ) ) {
+				newEnv->add( tyDecl->name, t );
+			}
+		}
+	};
+} // namespace
+
+/// reduce environment to just the parts that are referenced in a given expression
+TypeSubstitution * TypeSubstitution::newFromExpr( const Expr * expr, const TypeSubstitution * env ) {
+	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;
+	}
+	return nullptr;
+}
+
+void TypeSubstitution::normalize() {
+#if TIME_TO_CONVERT_PASSES
+	PassVisitor<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 );
+		}
+	} while ( sub.pass.subCount );
+#endif
+}
+
+#if TIME_TO_CONVERT_PASSES
+
+Type * TypeSubstitution::Substituter::postmutate( TypeInstType *inst ) {
+	BoundVarsType::const_iterator bound = boundVars.find( inst->name );
+	if ( bound != boundVars.end() ) return inst;
+
+	TypeEnvType::const_iterator i = sub.typeEnv.find( inst->name );
+	if ( i == sub.typeEnv.end() ) {
+		return inst;
+	} else {
+		// cut off infinite loop for the case where a type is bound to itself.
+		// 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 ( inst->name == replacement->name ) {
+				return inst;
+			}
+		}
+		// 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 ) {
+	VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name );
+	if ( i == sub.varEnv.end() ) {
+		return nameExpr;
+	} else {
+		subCount++;
+		delete nameExpr;
+		return i->second->clone();
+	} // if
+}
+
+void TypeSubstitution::Substituter::premutate( Type * 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
+	} // if
+}
+
+template< typename TypeClass >
+void TypeSubstitution::Substituter::handleAggregateType( TypeClass * 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
+		// 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 ) {
+	handleAggregateType( aggregateUseType );
+}
+
+void TypeSubstitution::Substituter::premutate( UnionInstType *aggregateUseType ) {
+	handleAggregateType( aggregateUseType );
+}
+
+#endif
+
+} // namespace ast
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/TypeSubstitution.hpp
===================================================================
--- src/AST/TypeSubstitution.hpp	(revision 41b24c88e3b9a228864050167f32e8ca015b0f9d)
+++ src/AST/TypeSubstitution.hpp	(revision 41b24c88e3b9a228864050167f32e8ca015b0f9d)
@@ -0,0 +1,205 @@
+//
+// 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.
+//
+// TypeSubstitution.h --
+//
+// Author           : Richard C. Bilson
+// Created On       : Mon May 18 07:44:20 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Tue Apr 30 22:52:47 2019
+// Update Count     : 9
+//
+
+#pragma once
+
+#include <cassert>                 // for assert
+#include <list>                    // for list<>::iterator, _List_iterator
+#include <unordered_map>
+#include <unordered_set>
+#include <string>                  // for string, operator!=
+#include <utility>                 // for pair
+
+#include "Fwd.hpp"        // for UniqueId
+#include "ParseNode.hpp"
+#include "Type.hpp"       // for ptr<Type>
+#include "Common/SemanticError.h"  // for SemanticError
+#include "Visitor.hpp"
+#include "Decl.hpp"
+#include "Expr.hpp"
+
+namespace ast {
+
+class TypeSubstitution : public Node {
+  public:
+	TypeSubstitution();
+	template< typename FormalIterator, typename ActualIterator >
+	TypeSubstitution( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin );
+	TypeSubstitution( const TypeSubstitution &other );
+	virtual ~TypeSubstitution();
+
+	TypeSubstitution &operator=( const TypeSubstitution &other );
+
+	template< typename SynTreeClass > int apply( SynTreeClass *&input ) const;
+	template< typename SynTreeClass > int applyFree( SynTreeClass *&input ) const;
+
+	void add( std::string formalType, const Type *actualType );
+	void add( const TypeSubstitution &other );
+	void remove( std::string formalType );
+	const Type *lookup( std::string formalType ) const;
+	bool empty() const;
+
+	template< typename FormalIterator, typename ActualIterator >
+	void add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin );
+
+	/// create a new TypeSubstitution using bindings from env containing all of the type variables in expr
+	static TypeSubstitution * newFromExpr( const Expr * expr, const TypeSubstitution * env );
+
+	void normalize();
+
+	const TypeSubstitution * accept( Visitor & v ) const override { return v.visit( this ); }
+
+	TypeSubstitution * clone() const override { return new TypeSubstitution( *this ); }
+
+  private:
+
+	// Mutator that performs the substitution
+	struct Substituter;
+
+	// TODO: worry about traversing into a forall-qualified function type or type decl with assertions
+
+	void initialize( const TypeSubstitution &src, TypeSubstitution &dest );
+
+	template<typename pass_type>
+	friend class Pass;
+
+	typedef std::unordered_map< std::string, ptr<Type> > TypeEnvType;
+	typedef std::unordered_map< std::string, ptr<Expr> > VarEnvType;
+	TypeEnvType typeEnv;
+	VarEnvType varEnv;
+
+  public:
+	// has to come after declaration of typeEnv
+	auto begin()       -> decltype( typeEnv.begin() ) { return typeEnv.begin(); }
+	auto   end()       -> decltype( typeEnv.  end() ) { return typeEnv.  end(); }
+	auto begin() const -> decltype( typeEnv.begin() ) { return typeEnv.begin(); }
+	auto   end() const -> decltype( typeEnv.  end() ) { return typeEnv.  end(); }
+};
+
+template< typename FormalIterator, typename ActualIterator >
+void TypeSubstitution::add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) {
+	// FormalIterator points to a TypeDecl
+	// ActualIterator points to a Type
+	FormalIterator formalIt = formalBegin;
+	ActualIterator actualIt = actualBegin;
+	for ( ; formalIt != formalEnd; ++formalIt, ++actualIt ) {
+		if ( const TypeDecl *formal = formalIt->template as<TypeDecl>() ) {
+			if ( const TypeExpr *actual = actualIt->template as<TypeExpr>() ) {
+				if ( formal->name != "" ) {
+					typeEnv[ formal->name ] = actual->type;
+				} // if
+			} else {
+				SemanticError( formal, toString( "Attempt to provide non-type parameter: ", toString( *actualIt ).c_str(), " for type parameter " ) );
+			} // if
+		} else {
+			// TODO: type check the formal and actual parameters
+			if ( (*formalIt)->name != "" ) {
+				varEnv[ (*formalIt)->name ] = *actualIt;
+			} // if
+		} // if
+	} // for
+}
+
+template< typename FormalIterator, typename ActualIterator >
+TypeSubstitution::TypeSubstitution( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) {
+	add( formalBegin, formalEnd, actualBegin );
+}
+
+} // namespace ast
+
+// include needs to happen after TypeSubstitution is defined so that both TypeSubstitution and
+// PassVisitor are defined before PassVisitor implementation accesses TypeSubstitution internals.
+#include "Pass.hpp"
+
+namespace ast {
+
+// definitition must happen after PassVisitor is included so that WithGuards can be used
+struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> {
+
+		Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
+
+#if TIME_TO_CONVERT_PASSES
+
+		Type * postmutate( TypeInstType * aggregateUseType );
+		Expression * postmutate( NameExpr * nameExpr );
+
+		/// Records type variable bindings from forall-statements
+		void premutate( Type * 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
+
+		const TypeSubstitution & sub;
+		int subCount = 0;
+		bool freeOnly;
+		typedef std::unordered_set< std::string > BoundVarsType;
+		BoundVarsType boundVars;
+
+};
+
+template< typename SynTreeClass >
+int TypeSubstitution::apply( SynTreeClass *&input ) const {
+	assert( input );
+	Pass<Substituter> sub( *this, false );
+	input = dynamic_cast< SynTreeClass * >( input->acceptMutator( sub ) );
+	assert( input );
+///	std::cerr << "substitution result is: ";
+///	newType->print( std::cerr );
+///	std::cerr << std::endl;
+	return sub.pass.subCount;
+}
+
+template< typename SynTreeClass >
+int TypeSubstitution::applyFree( SynTreeClass *&input ) const {
+	assert( input );
+	Pass<Substituter> sub( *this, true );
+	input = dynamic_cast< SynTreeClass * >( input->acceptMutator( sub ) );
+	assert( input );
+///	std::cerr << "substitution result is: ";
+///	newType->print( std::cerr );
+///	std::cerr << std::endl;
+	return sub.pass.subCount;
+}
+
+/// Instantiate each member of the context given the actual parameters specified, and store the
+/// instantiations for use by the indexer
+template< typename FormalIterator, typename ActualIterator, typename MemberIterator, typename OutputIterator >
+void applySubstitution( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actual, MemberIterator memberBegin, MemberIterator memberEnd, OutputIterator out ) {
+	TypeSubstitution sub = TypeSubstitution( formalBegin, formalEnd, actual );
+	for ( auto i = memberBegin; i != memberEnd; ++i ) {
+		sub.apply( *i );
+		*out++ = *i;
+	} // for
+}
+
+//=================================================================================================
+/// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
+/// remove only if there is a better solution
+/// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
+/// forward declarations
+inline void increment( const class TypeSubstitution * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class TypeSubstitution * node, Node::ref_type ref ) { node->decrement(ref); }
+
+} // namespace ast
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
