Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision d1487780c1f67242d6e2063860a40cc32c2395ee)
+++ src/AST/Convert.cpp	(revision a83044fb86cf36e20d6c0f6fbc995d0b814fe1d7)
@@ -10,6 +10,6 @@
 // Created On       : Thu May 09 15::37::05 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Fri May 17 16:01:00 2019
-// Update Count     : 4
+// Last Modified On : Tue May 21 15:30:00 2019
+// Update Count     : 5
 //
 
@@ -108,56 +108,162 @@
 
 private:
+	void declPostamble( Declaration * decl, const ast::Decl * node ) {
+		decl->location = node->location;
+		// name comes from constructor
+		// linkage comes from constructor
+		decl->extension = node->extension;
+		decl->uniqueId = node->uniqueId;
+		// storageClasses comes from constructor
+		this->node = decl;
+	}
+
+	const ast::DeclWithType * declWithTypePostamble (
+			DeclarationWithType * decl, const ast::DeclWithType * node ) {
+		declPostamble( decl, node );
+		decl->mangleName = node->mangleName;
+		decl->scopeLevel = node->scopeLevel;
+		decl->asmName = get<Expression>().accept1( node->asmName );
+		// attributes comes from constructor
+		decl->isDeleted = node->isDeleted;
+		// fs comes from constructor
+		return nullptr;
+	}
+
 	const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final {
-		(void)node;
-		return nullptr;
+		auto decl = new ObjectDecl(
+			node->name,
+			Type::StorageClasses( node->storage.val ),
+			LinkageSpec::Spec( node->linkage.val ),
+			get<Expression>().accept1( node->bitfieldWidth ),
+			get<Type>().accept1( node->type ),
+			get<Initializer>().accept1( node->init ),
+			get<Attribute>().acceptL( node->attributes ),
+			Type::FuncSpecifiers( node->funcSpec.val )
+		);
+		return declWithTypePostamble( decl, node );
 	}
 
 	const ast::DeclWithType * visit( const ast::FunctionDecl * node ) override final {
-		(void)node;
+		auto decl = new FunctionDecl(
+			node->name,
+			Type::StorageClasses( node->storage.val ),
+			LinkageSpec::Spec( node->linkage.val ),
+			get<FunctionType>().accept1( node->type ),
+			get<CompoundStmt>().accept1( node->stmts ),
+			get<Attribute>().acceptL( node->attributes ),
+			Type::FuncSpecifiers( node->funcSpec.val )
+		);
+		decl->withExprs = get<Expression>().acceptL( node->withExprs );
+		return declWithTypePostamble( decl, node );
+	}
+
+	// NamedTypeDecl
+	const ast::Decl * namedTypePostamble( NamedTypeDecl * decl, const ast::NamedTypeDecl * node ) {
+		declPostamble( decl, node );
+		// base comes from constructor
+		decl->parameters = get<TypeDecl>().acceptL( node->params );
+		decl->assertions = get<DeclarationWithType>().acceptL( node->assertions );
+		return nullptr;
+	}
+
+	const ast::Decl * visit( const ast::TypeDecl * node ) override final {
+		TypeDecl::Kind kind;
+		switch (node->kind) {
+		case ast::TypeVar::Dtype:
+			kind = TypeDecl::Dtype;
+			break;
+		case ast::TypeVar::Ftype:
+			kind = TypeDecl::Ftype;
+			break;
+		case ast::TypeVar::Ttype:
+			kind = TypeDecl::Ttype;
+			break;
+		default:
+			assertf(false, "Invalid ast::TypeVar::Kind: %d\n", node->kind);
+		};
+		auto decl = new TypeDecl(
+			node->name,
+			Type::StorageClasses( node->storage.val ),
+			get<Type>().accept1( node->base ),
+			kind,
+			node->sized,
+			get<Type>().accept1( node->init )
+		);
+		return namedTypePostamble( decl, node );
+	}
+
+	const ast::Decl * visit( const ast::TypedefDecl * node ) override final {
+		auto decl = new TypedefDecl(
+			node->name,
+			node->location,
+			Type::StorageClasses( node->storage.val ),
+            get<Type>().accept1( node->base ),
+			LinkageSpec::Spec( node->linkage.val )
+		);
+		return namedTypePostamble( decl, node );
+	}
+
+	const ast::Decl * aggregatePostamble( AggregateDecl * decl, const ast::AggregateDecl * node ) {
+		decl->members = get<Declaration>().acceptL( node->members );
+		decl->parameters = get<TypeDecl>().acceptL( node->params );
+		decl->body = node->body;
+		// attributes come from constructor
+		// TODO: Need caching for: decl->parent = node->parent;
 		return nullptr;
 	}
 
 	const ast::Decl * visit( const ast::StructDecl * node ) override final {
-		(void)node;
-		return nullptr;
+		auto decl = new StructDecl(
+			node->name,
+			node->kind,
+			get<Attribute>().acceptL( node->attributes ),
+			LinkageSpec::Spec( node->linkage.val )
+		);
+		return aggregatePostamble( decl, node );
 	}
 
 	const ast::Decl * visit( const ast::UnionDecl * node ) override final {
-		(void)node;
-		return nullptr;
+		auto decl = new UnionDecl(
+			node->name,
+			get<Attribute>().acceptL( node->attributes ),
+			LinkageSpec::Spec( node->linkage.val )
+		);
+		return aggregatePostamble( decl, node );
 	}
 
 	const ast::Decl * visit( const ast::EnumDecl * node ) override final {
-		(void)node;
-		return nullptr;
+		auto decl = new EnumDecl(
+			node->name,
+			get<Attribute>().acceptL( node->attributes ),
+			LinkageSpec::Spec( node->linkage.val )
+		);
+		return aggregatePostamble( decl, node );
 	}
 
 	const ast::Decl * visit( const ast::TraitDecl * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Decl * visit( const ast::TypeDecl * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Decl * visit( const ast::TypedefDecl * node ) override final {
-		(void)node;
-		return nullptr;
+		auto decl = new TraitDecl(
+			node->name,
+			{},
+			LinkageSpec::Spec( node->linkage.val )
+		);
+		return aggregatePostamble( decl, node );
 	}
 
 	const ast::AsmDecl * visit( const ast::AsmDecl * node ) override final {
-		(void)node;
+		auto decl = new AsmDecl( get<AsmStmt>().accept1( node->stmt ) );
+		declPostamble( decl, node );
 		return nullptr;
 	}
 
 	const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::CompoundStmt * visit( const ast::CompoundStmt * node ) override final {
-		auto stmt = new CompoundStmt( get<Statement>().acceptL( node->kids ) );
+		auto decl = new StaticAssertDecl(
+			get<Expression>().accept1( node->cond ),
+			get<ConstantExpr>().accept1( node->msg )
+		);
+		declPostamble( decl, node );
+		return nullptr;
+	}
+
+	const ast::Stmt * stmtPostamble( Statement * stmt, const ast::Stmt * node ) {
 		stmt->location = node->location;
 		stmt->labels = makeLabelL( stmt, node->labels );
@@ -166,10 +272,13 @@
 	}
 
+	const ast::CompoundStmt * visit( const ast::CompoundStmt * node ) override final {
+		auto stmt = new CompoundStmt( get<Statement>().acceptL( node->kids ) );
+		stmtPostamble( stmt, node );
+		return nullptr;
+	}
+
 	const ast::Stmt * visit( const ast::ExprStmt * node ) override final {
 		auto stmt = new ExprStmt( get<Expression>().accept1( node->expr ) );
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
@@ -183,16 +292,10 @@
 			makeLabelL( nullptr, node->gotoLabels ) // What are these labelling?
 		);
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
 	const ast::Stmt * visit( const ast::DirectiveStmt * node ) override final {
 		auto stmt = new DirectiveStmt( node->directive );
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
@@ -204,8 +307,5 @@
 			get<Statement>().acceptL( node->inits )
 		);
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
@@ -215,8 +315,5 @@
 			get<Statement>().acceptL( node->stmts )
 		);
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
@@ -227,8 +324,5 @@
 			node->isDefault()
 		);
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
@@ -241,8 +335,5 @@
 			node->isDoWhile
 		);
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
@@ -254,8 +345,5 @@
 			get<Statement>().accept1( node->body )
 		);
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
@@ -286,16 +374,10 @@
 			stmt->target = makeLabel( stmt, node->target );
 		}
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
 	const ast::Stmt * visit( const ast::ReturnStmt * node ) override final {
 		auto stmt = new ReturnStmt( get<Expression>().accept1( node->expr ) );
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
@@ -317,8 +399,5 @@
 			get<Expression>().accept1( node->target )
 		);
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
@@ -330,8 +409,5 @@
 			get<FinallyStmt>().accept1( node->finally )
 		);
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
@@ -354,16 +430,10 @@
 			get<Statement>().accept1( node->body )
 		);
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
 	const ast::Stmt * visit( const ast::FinallyStmt * node ) override final {
 		auto stmt = new FinallyStmt( get<CompoundStmt>().accept1( node->body ) );
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
@@ -373,6 +443,6 @@
 		for ( auto clause : node->clauses ) {
 			stmt->clauses.push_back({{
-					get<Expression>().accept1( clause.target.function ),
-					get<Expression>().acceptL( clause.target.arguments ),
+					get<Expression>().accept1( clause.target.func ),
+					get<Expression>().acceptL( clause.target.args ),
 				},
 				get<Statement>().accept1( clause.stmt ),
@@ -389,8 +459,5 @@
 			get<Expression>().accept1( node->orElse.cond ),
 		};
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
@@ -400,15 +467,10 @@
 			get<Statement>().accept1( node->stmt )
 		);
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
 	const ast::NullStmt * visit( const ast::NullStmt * node ) override final {
 		auto stmt = new NullStmt();
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
+		stmtPostamble( stmt, node );
 		return nullptr;
 	}
@@ -416,8 +478,5 @@
 	const ast::Stmt * visit( const ast::DeclStmt * node ) override final {
 		auto stmt = new DeclStmt( get<Declaration>().accept1( node->decl ) );
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
-		return nullptr;
+		return stmtPostamble( stmt, node );
 	}
 
@@ -427,16 +486,88 @@
 	}
 
+	TypeSubstitution * convertTypeSubstitution(const ast::TypeSubstitution * src) {
+
+		TypeSubstitution *rslt = new TypeSubstitution();
+
+		for (decltype(src->begin()) src_i = src->begin(); src_i != src->end(); src_i++) {
+			rslt->add( src_i->first,
+			           get<Type>().accept1(src_i->second) );
+		}
+
+		for (decltype(src->beginVar()) src_i = src->beginVar(); src_i != src->endVar(); src_i++) {
+			rslt->addVar( src_i->first,
+			              get<Expression>().accept1(src_i->second) );
+		}
+
+		return rslt;
+	}
+
+	void convertInferUnion(std::map<UniqueId,ParamEntry> &tgtInferParams,
+						   std::vector<UniqueId>         &tgtResnSlots,
+						   const ast::Expr::InferUnion   &srcInferred ) {
+
+		assert( tgtInferParams.empty() );
+		assert( tgtResnSlots.empty() );
+
+		if ( srcInferred.mode == ast::Expr::InferUnion::Params ) {
+			const ast::InferredParams &srcParams = srcInferred.inferParamsConst();
+			for (auto srcParam : srcParams) {
+				tgtInferParams[srcParam.first] = ParamEntry(
+					srcParam.second.decl,
+					get<Type>().accept1(srcParam.second.actualType),
+					get<Type>().accept1(srcParam.second.formalType),
+					get<Expression>().accept1(srcParam.second.expr)
+				);
+			}
+		} else if ( srcInferred.mode == ast::Expr::InferUnion::Slots  ) {
+			const ast::ResnSlots &srcSlots = srcInferred.resnSlotsConst();
+			for (auto srcSlot : srcSlots) {
+				tgtResnSlots.push_back(srcSlot);
+			}
+		}
+	}
+
+	Expression * visitBaseExpr(const ast::Expr * src, Expression * tgt) {
+
+		tgt->location = src->location;
+
+		tgt->result = get<Type>().accept1(src->result);
+		tgt->env    = convertTypeSubstitution(src->env);
+
+		tgt->extension = src->extension;
+		convertInferUnion(tgt->inferParams, tgt->resnSlots, src->inferred);
+
+		return tgt;
+	}
+
 	const ast::Expr * visit( const ast::ApplicationExpr * node ) override final {
-		(void)node;
+		auto expr = visitBaseExpr( node,
+			new ApplicationExpr(
+				get<Expression>().accept1(node->func),
+				get<Expression>().acceptL(node->args)
+			)
+		);
+		this->node = expr;
 		return nullptr;
 	}
 
 	const ast::Expr * visit( const ast::UntypedExpr * node ) override final {
-		(void)node;
+		auto expr = visitBaseExpr( node,
+			new UntypedExpr(
+				get<Expression>().accept1(node->func),
+				get<Expression>().acceptL(node->args)
+			)
+		);
+		this->node = expr;
 		return nullptr;
 	}
 
 	const ast::Expr * visit( const ast::NameExpr * node ) override final {
-		(void)node;
+		auto expr = visitBaseExpr( node,
+			new NameExpr(
+				node->name
+			)
+		);
+		this->node = expr;
 		return nullptr;
 	}
@@ -1236,13 +1367,31 @@
 			              getAccept1<ast::Expr>(old_i->second) );
 		}
-	}
-
-	void convertInferUnion(ast::Expr::InferUnion &nwInferred, InferredParams oldInferParams, const std::vector<UniqueId> &oldResnSlots) {
-		
-		(void) nwInferred;
-		(void) oldInferParams;
-		(void) oldResnSlots;
-		
-		// TODO
+
+		return rslt;
+	}
+
+	void convertInferUnion(ast::Expr::InferUnion               &newInferred,
+						   const std::map<UniqueId,ParamEntry> &oldInferParams,
+						   const std::vector<UniqueId>         &oldResnSlots) {
+
+		assert( oldInferParams.empty() || oldResnSlots.empty() );
+		assert( newInferred.mode == ast::Expr::InferUnion::Empty );
+
+		if ( !oldInferParams.empty() ) {
+			ast::InferredParams &tgt = newInferred.inferParams();
+			for (auto old : oldInferParams) {
+				tgt[old.first] = ast::ParamEntry(
+					old.second.decl,
+					getAccept1<ast::Type>(old.second.actualType),
+					getAccept1<ast::Type>(old.second.formalType),
+					getAccept1<ast::Expr>(old.second.expr)
+				);
+			}
+		} else if ( !oldResnSlots.empty() ) {
+			ast::ResnSlots &tgt = newInferred.resnSlots();
+			for (auto old : oldResnSlots) {
+				tgt.push_back(old);
+			}
+		}
 	}
 
@@ -1258,10 +1407,22 @@
 	}
 
-	virtual void visit( ApplicationExpr * ) override final {
-		// TODO
-	}
-
-	virtual void visit( UntypedExpr * ) override final {
-		// TODO
+	virtual void visit( ApplicationExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::ApplicationExpr(
+				old->location,
+				GET_ACCEPT_1(function, Expr),
+				GET_ACCEPT_V(args, Expr)
+			)
+		);
+	}
+
+	virtual void visit( UntypedExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::UntypedExpr(
+				old->location,
+				GET_ACCEPT_1(function, Expr),
+				GET_ACCEPT_V(args, Expr)
+			)
+		);
 	}
 
@@ -1275,6 +1436,12 @@
 	}
 
-	virtual void visit( CastExpr * ) override final {
-		// TODO ... (rest)
+	virtual void visit( CastExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::CastExpr(
+				old->location,
+				nullptr, // cast's "to" type is expr's result type; converted in visitBaseExpr
+				old->isGenerated ? ast::GeneratedCast : ast::ExplicitCast
+			)
+		);
 	}
 
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision d1487780c1f67242d6e2063860a40cc32c2395ee)
+++ src/AST/Decl.cpp	(revision a83044fb86cf36e20d6c0f6fbc995d0b814fe1d7)
@@ -81,5 +81,5 @@
 				auto result = eval( init->value );
 				if ( ! result.second ) {
-					SemanticError( init->location, toString( "Non-constexpr in initialization of "
+					SemanticError( init->location, ::toString( "Non-constexpr in initialization of "
 						"enumerator: ", field ) );
 				}
@@ -87,5 +87,5 @@
 			}
 			if ( enumValues.count( field->name ) != 0 ) {
-				SemanticError( location, toString( "Enum ", name, " has multiple members with the " 	"name ", field->name ) );
+				SemanticError( location, ::toString( "Enum ", name, " has multiple members with the " 	"name ", field->name ) );
 			}
 			enumValues[ field->name ] = crntVal;
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision d1487780c1f67242d6e2063860a40cc32c2395ee)
+++ src/AST/Decl.hpp	(revision a83044fb86cf36e20d6c0f6fbc995d0b814fe1d7)
@@ -329,9 +329,9 @@
 class StaticAssertDecl : public Decl {
 public:
-	ptr<Expr> condition;
+	ptr<Expr> cond;
 	ptr<ConstantExpr> msg;   // string literal
 
 	StaticAssertDecl( const CodeLocation & loc, const Expr * condition, const ConstantExpr * msg )
-	: Decl( loc, "", {}, {} ), condition( condition ), msg( msg ) {}
+	: Decl( loc, "", {}, {} ), cond( condition ), msg( msg ) {}
 
 	const StaticAssertDecl * accept( Visitor &v ) const override { return v.visit( this ); }
Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision d1487780c1f67242d6e2063860a40cc32c2395ee)
+++ src/AST/Expr.cpp	(revision a83044fb86cf36e20d6c0f6fbc995d0b814fe1d7)
@@ -22,4 +22,5 @@
 #include "Stmt.hpp"
 #include "Type.hpp"
+#include "Common/utility.h"
 #include "Common/SemanticError.h"
 #include "GenPoly/Lvalue.h"        // for referencesPermissable
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision d1487780c1f67242d6e2063860a40cc32c2395ee)
+++ src/AST/Expr.hpp	(revision a83044fb86cf36e20d6c0f6fbc995d0b814fe1d7)
@@ -106,4 +106,13 @@
 			case Params: assert(!"Cannot return to resnSlots from Params");
 			}
+			return *((ResnSlots*)nullptr);
+		}
+
+		const ResnSlots& resnSlotsConst() const {
+			if (mode == Slots) {
+				return data.resnSlots;
+			}
+			assert(!"Mode was not already resnSlots");
+			return *((ResnSlots*)nullptr);
 		}
 
@@ -114,4 +123,13 @@
 			case Params: return data.inferParams;
 			}
+			return *((InferredParams*)nullptr);
+		}
+
+		const InferredParams& inferParamsConst() const {
+			if (mode == Params) {
+				return data.inferParams;
+			}
+			assert(!"Mode was not already Params");
+			return *((InferredParams*)nullptr);
 		}
 	};
@@ -503,5 +521,5 @@
 };
 
-/// The application of a function to a set of parameters, along with a set of copy constructor 
+/// The application of a function to a set of parameters, along with a set of copy constructor
 /// calls, one for each argument
 class ImplicitCopyCtorExpr final : public Expr {
@@ -603,6 +621,6 @@
 };
 
-/// A multiple- or mass-assignment operation, or a tuple ctor/dtor expression. 
-/// multiple-assignment: both sides of the assignment have tuple type, 
+/// A multiple- or mass-assignment operation, or a tuple ctor/dtor expression.
+/// multiple-assignment: both sides of the assignment have tuple type,
 ///     e.g. `[a, b, c] = [d, e, f];`
 /// mass-assignment: left-hand side has tuple type and right-hand side does not:
@@ -612,8 +630,8 @@
 	ptr<StmtExpr> stmtExpr;
 
-	TupleAssignExpr( 
-		const CodeLocation & loc, std::vector<ptr<Expr>> && assigns, 
+	TupleAssignExpr(
+		const CodeLocation & loc, std::vector<ptr<Expr>> && assigns,
 		std::vector<ptr<ObjectDecl>> && tempDecls );
-	
+
 	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
 private:
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision d1487780c1f67242d6e2063860a40cc32c2395ee)
+++ src/AST/Fwd.hpp	(revision a83044fb86cf36e20d6c0f6fbc995d0b814fe1d7)
@@ -131,9 +131,4 @@
 class TypeSubstitution;
 
-std::string toString( const Node * );
-
-template < typename ... Params >
-std::string toString( const Params & ... params );
-
 typedef unsigned int UniqueId;
 
Index: src/AST/Node.cpp
===================================================================
--- src/AST/Node.cpp	(revision d1487780c1f67242d6e2063860a40cc32c2395ee)
+++ src/AST/Node.cpp	(revision a83044fb86cf36e20d6c0f6fbc995d0b814fe1d7)
@@ -16,4 +16,6 @@
 #include "Node.hpp"
 #include "Fwd.hpp"
+
+#include <iostream>
 
 #include "Attribute.hpp"
@@ -42,4 +44,11 @@
 	assign( r );
 	return r;
+}
+
+std::ostream & ast::operator<< ( std::ostream & out, const ast::Node * node ) {
+	(void)node;
+	#warning unimplemented
+	assertf(false, "Unimplemented");
+	return out;
 }
 
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision d1487780c1f67242d6e2063860a40cc32c2395ee)
+++ src/AST/Pass.impl.hpp	(revision a83044fb86cf36e20d6c0f6fbc995d0b814fe1d7)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Pass.impl.hpp --
+// ast::Pass.impl.hpp --
 //
 // Author           : Thierry Delisle
@@ -121,5 +121,5 @@
 	template< typename pass_t >
 	template< typename node_t >
-	auto Pass< pass_t >::call_accept( const node_t * node )
+	auto ast::Pass< pass_t >::call_accept( const node_t * node )
 		-> typename std::enable_if<
 				!std::is_base_of<ast::Expr, node_t>::value &&
@@ -139,5 +139,5 @@
 
 	template< typename pass_t >
-	const ast::Expr * Pass< pass_t >::call_accept( const ast::Expr * expr ) {
+	const ast::Expr * ast::Pass< pass_t >::call_accept( const ast::Expr * expr ) {
 		__pedantic_pass_assert( __visit_children() );
 		__pedantic_pass_assert( expr );
@@ -152,5 +152,5 @@
 
 	template< typename pass_t >
-	const ast::Stmt * Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {
+	const ast::Stmt * ast::Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {
 		__pedantic_pass_assert( __visit_children() );
 		__pedantic_pass_assert( stmt );
@@ -204,5 +204,5 @@
 	template< typename pass_t >
 	template< template <class...> class container_t >
-	container_t< ptr<Stmt> > Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
+	container_t< ptr<Stmt> > ast::Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
 		__pedantic_pass_assert( __visit_children() );
 		if( statements.empty() ) return {};
@@ -270,5 +270,5 @@
 	template< typename pass_t >
 	template< template <class...> class container_t, typename node_t >
-	container_t< ast::ptr<node_t> > Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
+	container_t< ast::ptr<node_t> > ast::Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
 		__pedantic_pass_assert( __visit_children() );
 		if( container.empty() ) return {};
@@ -301,5 +301,5 @@
 	template< typename pass_t >
 	template<typename node_t, typename parent_t, typename child_t>
-	void Pass< pass_t >::maybe_accept(
+	void ast::Pass< pass_t >::maybe_accept(
 		const node_t * & parent,
 		child_t parent_t::*child
@@ -571,5 +571,5 @@
 	__pass::indexer::addType( pass, 0, node );
 
-	maybe_accept( node, &TypedefDecl::assertions );
+	VISIT( maybe_accept( node, &TypedefDecl::assertions ); )
 
 	VISIT_END( Decl, node );
@@ -596,6 +596,6 @@
 
 	VISIT(
-		maybe_accept( node, &StaticAssertDecl::condition );
-		maybe_accept( node, &StaticAssertDecl::msg       );
+		maybe_accept( node, &StaticAssertDecl::cond );
+		maybe_accept( node, &StaticAssertDecl::msg  );
 	)
 
@@ -626,5 +626,5 @@
 // ExprStmt
 template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ExprStmt * node ) {
+const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ExprStmt * node ) {
 	VISIT_START( node );
 
@@ -666,4 +666,5 @@
 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::IfStmt * node ) {
 	VISIT_START( node );
+
 	VISIT({
 		// if statements introduce a level of scope (for the initialization)
@@ -674,4 +675,5 @@
 		maybe_accept( node, &IfStmt::elsePart );
 	})
+
 	VISIT_END( Stmt, node );
 }
@@ -680,5 +682,5 @@
 // WhileStmt
 template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const WhileStmt * node ) {
+const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WhileStmt * node ) {
 	VISIT_START( node );
 
@@ -832,4 +834,37 @@
 		// 	maybeAccept_impl( clause.condition, *this );
 		// }
+
+	VISIT({
+		std::vector<WaitForStmt::Clause> new_clauses;
+		new_clauses.reserve( node->clauses.size() );
+		bool mutated = false;
+		for( const auto & clause : node->clauses ) {
+
+			Expr * func = clause.target.func ? clause.target.func->accept(*this) : nullptr;
+			if(func != clause.target.func) mutated = true;
+
+			std::vector<ptr<Expr>> new_args;
+			new_args.reserve(clause.target.args.size());
+			for( const auto & arg : clause.target.args ) {
+				auto a = arg->accept(*this);
+				new_args.push_back( a );
+				if( a != arg ) mutated = true;
+			}
+
+			Stmt * stmt = clause.stmt ? clause.stmt->accept(*this) : nullptr;
+			if(stmt != clause.stmt) mutated = true;
+
+			Expr * cond = clause.cond ? clause.cond->accept(*this) : nullptr;
+			if(cond != clause.cond) mutated = true;
+
+			new_clauses.push_back( WaitForStmt::Clause{ {func, std::move(new_args) }, stmt, cond } );
+		}
+
+		if(mutated) {
+			auto n = mutate(node);
+			n->clauses = std::move( new_clauses );
+			node = n;
+		}
+	})
 
 	#define maybe_accept(field) \
@@ -910,8 +945,888 @@
 }
 
-
-
-
-
+//--------------------------------------------------------------------------
+// ApplicationExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::ApplicationExpr * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		{
+			guard_indexer guard { *this };
+			maybe_accept( node, &ApplicationExpr::result );
+		}
+		maybe_accept( node, &ApplicationExpr::func );
+		maybe_accept( node, &ApplicationExpr::args );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// UntypedExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedExpr * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		{
+			guard_indexer guard { *this };
+			maybe_accept( node, &UntypedExpr::result );
+		}
+
+		maybe_accept( node, &UntypedExpr::args );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// NameExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::NameExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+		guard_indexer guard { *this };
+		maybe_accept( node, &NameExpr::result );
+	})
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// CastExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::CastExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &CastExpr::result );
+		}
+		maybe_accept( node, &CastExpr::arg );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// KeywordCastExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::KeywordCastExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &KeywordCastExpr::result );
+		}
+		maybe_accept( node, &KeywordCastExpr::arg );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// VirtualCastExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::VirtualCastExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &VirtualCastExpr::result );
+		}
+		maybe_accept( node, &VirtualCastExpr::arg );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// AddressExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::AddressExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &AddressExpr::result );
+		}
+		maybe_accept( node, &AddressExpr::arg );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// LabelAddressExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::LabelAddressExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+		guard_indexer guard { *this };
+		maybe_accept( node, &LabelAddressExpr::result );
+	})
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// UntypedMemberExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedMemberExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &UntypedMemberExpr::result );
+		}
+		maybe_accept( node, &UntypedMemberExpr::aggregate );
+		maybe_accept( node, &UntypedMemberExpr::member    );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// MemberExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::MemberExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &MemberExpr::result );
+		}
+		maybe_accept( node, &MemberExpr::aggregate );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// VariableExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::VariableExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+		guard_indexer guard { *this };
+		maybe_accept( node, &VariableExpr::result );
+	})
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// ConstantExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstantExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+		guard_indexer guard { *this };
+		maybe_accept( node, &ConstantExpr::result );
+	})
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// SizeofExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::SizeofExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &SizeofExpr::result );
+		}
+		if ( node->type ) {
+			maybe_accept( node, &SizeofExpr::type );
+		} else {
+			maybe_accept( node, &SizeofExpr::expr );
+		}
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// AlignofExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::AlignofExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &AlignofExpr::result );
+		}
+		if ( node->type ) {
+			maybe_accept( node, &AlignofExpr::type );
+		} else {
+			maybe_accept( node, &AlignofExpr::expr );
+		}
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// UntypedOffsetofExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedOffsetofExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &UntypedOffsetofExpr::result );
+		}
+		maybe_accept( node, &UntypedOffsetofExpr::type   );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// OffsetofExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetofExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &OffsetofExpr::result );
+		}
+		maybe_accept( node, &OffsetofExpr::type   );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// OffsetPackExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetPackExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &OffsetPackExpr::result );
+		}
+		maybe_accept( node, &OffsetPackExpr::type   );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// LogicalExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::LogicalExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &LogicalExpr::result );
+		}
+		maybe_accept( node, &LogicalExpr::arg1 );
+		maybe_accept( node, &LogicalExpr::arg2 );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// ConditionalExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConditionalExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &ConditionalExpr::result );
+		}
+		maybe_accept( node, &ConditionalExpr::arg1 );
+		maybe_accept( node, &ConditionalExpr::arg2 );
+		maybe_accept( node, &ConditionalExpr::arg3 );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// CommaExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::CommaExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &CommaExpr::result );
+		}
+		maybe_accept( node, &CommaExpr::arg1 );
+		maybe_accept( node, &CommaExpr::arg2 );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// TypeExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::TypeExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &TypeExpr::result );
+		}
+		maybe_accept( node, &TypeExpr::type );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// AsmExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::AsmExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &AsmExpr::result );
+		}
+		maybe_accept( node, &AsmExpr::inout      );
+		maybe_accept( node, &AsmExpr::constraint );
+		maybe_accept( node, &AsmExpr::operand    );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// ImplicitCopyCtorExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &ImplicitCopyCtorExpr::result );
+		}
+		maybe_accept( node, &ImplicitCopyCtorExpr::callExpr    );
+		maybe_accept( node, &ImplicitCopyCtorExpr::tempDecls   );
+		maybe_accept( node, &ImplicitCopyCtorExpr::returnDecls );
+		maybe_accept( node, &ImplicitCopyCtorExpr::dtors       );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// ConstructorExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstructorExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &ConstructorExpr::result );
+		}
+		maybe_accept( node, &ConstructorExpr::callExpr );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// CompoundLiteralExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::CompoundLiteralExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &CompoundLiteralExpr::result );
+		}
+		maybe_accept( node, &CompoundLiteralExpr::init );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// RangeExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::RangeExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &RangeExpr::result );
+		}
+		maybe_accept( node, &RangeExpr::low    );
+		maybe_accept( node, &RangeExpr::high   );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// UntypedTupleExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedTupleExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &UntypedTupleExpr::result );
+		}
+		maybe_accept( node, &UntypedTupleExpr::exprs  );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// TupleExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &TupleExpr::result );
+		}
+		maybe_accept( node, &TupleExpr::exprs  );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// TupleIndexExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleIndexExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &TupleIndexExpr::result );
+		}
+		maybe_accept( node, &TupleIndexExpr::tuple  );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// TupleAssignExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleAssignExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &TupleAssignExpr::result );
+		}
+		maybe_accept( node, &TupleAssignExpr::stmtExpr );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// StmtExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::StmtExpr * node ) {
+	VISIT_START( node );
+
+	VISIT(// don't want statements from outer CompoundStmts to be added to this StmtExpr
+		// get the stmts that will need to be spliced in
+		auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
+		auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
+
+		// These may be modified by subnode but most be restored once we exit this statemnet.
+		ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::env( pass, 0) );
+		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
+		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
+
+		{
+			guard_indexer guard { *this };
+			maybe_accept( node, &StmtExpr::result );
+		}
+		maybe_accept( node, &StmtExpr::stmts       );
+		maybe_accept( node, &StmtExpr::returnDecls );
+		maybe_accept( node, &StmtExpr::dtors       );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// UniqueExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::UniqueExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &UniqueExpr::result );
+		}
+		maybe_accept( node, &UniqueExpr::expr   );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// UntypedInitExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedInitExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &UntypedInitExpr::result );
+		}
+		maybe_accept( node, &UntypedInitExpr::expr   );
+		// not currently visiting initAlts, but this doesn't matter since this node is only used in the resolver.
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// InitExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::InitExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &InitExpr::result );
+		}
+		maybe_accept( node, &InitExpr::expr   );
+		maybe_accept( node, &InitExpr::designation );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// DeletedExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::DeletedExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &DeletedExpr::result );
+		}
+		maybe_accept( node, &DeletedExpr::expr );
+		// don't visit deleteStmt, because it is a pointer to somewhere else in the tree.
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// DefaultArgExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::DefaultArgExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &DefaultArgExpr::result );
+		}
+		maybe_accept( node, &DefaultArgExpr::expr );
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// GenericExpr
+template< typename pass_t >
+const ast::Expr * ast::Pass< pass_t >::visit( const ast::GenericExpr * node ) {
+	VISIT_START( node );
+
+	VISIT({
+			guard_indexer guard { *this };
+			maybe_accept( node, &GenericExpr::result );
+		}
+		maybe_accept( node, &GenericExpr::control );
+
+		std::vector<GenericExpr::Association> new_kids;
+		new_kids.reserve(node->associations.size());
+		bool mutated = false;
+		for( const auto & assoc : node->associations ) {
+			Type * type = nullptr;
+			if( assoc.type ) {
+				guard_indexer guard { *this };
+				type = assoc.type->accept( *this );
+				if( type != assoc.type ) mutated = true;
+			}
+			Expr * expr = nullptr;
+			if( assoc.expr ) {
+				expr = assoc.expr->accept( *this );
+				if( expr != assoc.expr ) mutated = true;
+			}
+			new_kids.emplace_back( type, expr );
+		}
+
+		if(mutated) {
+			auto n = mutate(node);
+			n->associations = std::move( new_kids );
+			node = n;
+		}
+	)
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
+// VoidType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::VoidType * node ) {
+	VISIT_START( node );
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// BasicType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::BasicType * node ) {
+	VISIT_START( node );
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// PointerType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::PointerType * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		// xxx - should PointerType visit/mutate dimension?
+		maybe_accept( node, &PointerType::base );
+	)
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// ArrayType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::ArrayType * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &ArrayType::dimension );
+		maybe_accept( node, &ArrayType::base );
+	)
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// ReferenceType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::ReferenceType * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &ReferenceType::base );
+	)
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// QualifiedType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::QualifiedType * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &QualifiedType::parent );
+		maybe_accept( node, &QualifiedType::child );
+	)
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// FunctionType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::FunctionType * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &FunctionType::forall  );
+		maybe_accept( node, &FunctionType::returns );
+		maybe_accept( node, &FunctionType::params  );
+	)
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// StructInstType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::StructInstType * node ) {
+	VISIT_START( node );
+
+	__pass::indexer::addStruct( node->name, 0, pass );
+
+	VISIT({
+		guard_indexer guard { *this };
+		maybe_accept( node, &StructInstType::forall );
+		maybe_accept( node, &StructInstType::params );
+	})
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// UnionInstType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::UnionInstType * node ) {
+	VISIT_START( node );
+
+	__pass::indexer::addStruct( node->name, 0, pass );
+
+	{
+		guard_indexer guard { *this };
+		maybe_accept( node, &UnionInstType::forall );
+		maybe_accept( node, &UnionInstType::params );
+	}
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// EnumInstType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::EnumInstType * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &EnumInstType::forall );
+		maybe_accept( node, &EnumInstType::params );
+	)
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// TraitInstType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::TraitInstType * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &TraitInstType::forall );
+		maybe_accept( node, &TraitInstType::params );
+	)
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// TypeInstType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeInstType * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &TypeInstType::forall );
+		maybe_accept( node, &TypeInstType::params );
+	)
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// TupleType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::TupleType * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &TupleType::types );
+		maybe_accept( node, &TupleType::members );
+	)
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// TypeofType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeofType * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &TypeofType::expr );
+	)
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// VarArgsType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::VarArgsType * node ) {
+	VISIT_START( node );
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// ZeroType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::ZeroType * node ) {
+	VISIT_START( node );
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// OneType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::OneType * node ) {
+	VISIT_START( node );
+
+	VISIT_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// GlobalScopeType
+template< typename pass_t >
+const ast::Type * ast::Pass< pass_t >::visit( const ast::GlobalScopeType * node ) {
+	VISIT_START( node );
+
+	VISIT_END( Type, node );
+}
+
+
+//--------------------------------------------------------------------------
+// Designation
+template< typename pass_t >
+const ast::Designation * ast::Pass< pass_t >::visit( const ast::Designation * node ) {
+	VISIT_START( node );
+
+	VISIT( maybe_accept( node, &Designation::designators ); )
+
+	VISIT_END( Designation, node );
+}
 
 //--------------------------------------------------------------------------
@@ -970,46 +1885,46 @@
 }
 
-//--------------------------------------------------------------------------
-// TypeSubstitution
-template< typename pass_t >
-const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {
-	VISIT_START( node );
-
-	VISIT(
-		{
-			bool mutated = false;
-			std::unordered_map< std::string, ast::ptr< ast::Type > > new_map;
-			for ( const auto & p : node->typeEnv ) {
-				guard_indexer guard { *this };
-				auto new_node = p.second->accept( *this );
-				if (new_node != p.second) mutated = false;
-				new_map.insert({ p.first, new_node });
-			}
-			if (mutated) {
-				auto new_node = mutate( node );
-				new_node->typeEnv.swap( new_map );
-				node = new_node;
-			}
-		}
-
-		{
-			bool mutated = false;
-			std::unordered_map< std::string, ast::ptr< ast::Expr > > new_map;
-			for ( const auto & p : node->varEnv ) {
-				guard_indexer guard { *this };
-				auto new_node = p.second->accept( *this );
-				if (new_node != p.second) mutated = false;
-				new_map.insert({ p.first, new_node });
-			}
-			if (mutated) {
-				auto new_node = mutate( node );
-				new_node->varEnv.swap( new_map );
-				node = new_node;
-			}
-		}
-	)
-
-	VISIT_END( TypeSubstitution, node );
-}
+// //--------------------------------------------------------------------------
+// // TypeSubstitution
+// template< typename pass_t >
+// const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {
+// 	VISIT_START( node );
+
+// 	VISIT(
+// 		{
+// 			bool mutated = false;
+// 			std::unordered_map< std::string, ast::ptr< ast::Type > > new_map;
+// 			for ( const auto & p : node->typeEnv ) {
+// 				guard_indexer guard { *this };
+// 				auto new_node = p.second->accept( *this );
+// 				if (new_node != p.second) mutated = false;
+// 				new_map.insert({ p.first, new_node });
+// 			}
+// 			if (mutated) {
+// 				auto new_node = mutate( node );
+// 				new_node->typeEnv.swap( new_map );
+// 				node = new_node;
+// 			}
+// 		}
+
+// 		{
+// 			bool mutated = false;
+// 			std::unordered_map< std::string, ast::ptr< ast::Expr > > new_map;
+// 			for ( const auto & p : node->varEnv ) {
+// 				guard_indexer guard { *this };
+// 				auto new_node = p.second->accept( *this );
+// 				if (new_node != p.second) mutated = false;
+// 				new_map.insert({ p.first, new_node });
+// 			}
+// 			if (mutated) {
+// 				auto new_node = mutate( node );
+// 				new_node->varEnv.swap( new_map );
+// 				node = new_node;
+// 			}
+// 		}
+// 	)
+
+// 	VISIT_END( TypeSubstitution, node );
+// }
 
 #undef VISIT_START
Index: src/AST/Stmt.hpp
===================================================================
--- src/AST/Stmt.hpp	(revision d1487780c1f67242d6e2063860a40cc32c2395ee)
+++ src/AST/Stmt.hpp	(revision a83044fb86cf36e20d6c0f6fbc995d0b814fe1d7)
@@ -330,6 +330,6 @@
 public:
 	struct Target {
-		ptr<Expr> function;
-		std::vector<ptr<Expr>> arguments;
+		ptr<Expr> func;
+		std::vector<ptr<Expr>> args;
 	};
 
Index: src/AST/module.mk
===================================================================
--- src/AST/module.mk	(revision d1487780c1f67242d6e2063860a40cc32c2395ee)
+++ src/AST/module.mk	(revision a83044fb86cf36e20d6c0f6fbc995d0b814fe1d7)
@@ -1,4 +1,3 @@
-######################### -*- Mode: Makefile-Gmake -*-
-########################
+######################### -*- Mode: Makefile-Gmake -*- ########################
 ##
 ## Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
@@ -17,7 +16,15 @@
 
 SRC_AST = \
-     AST/Convert.cpp \
-     AST/Node.cpp \
-     AST/TypeSubstitution.cpp 
+	AST/Attribute.cpp \
+	AST/Convert.cpp \
+	AST/Decl.cpp \
+	AST/DeclReplacer.cpp \
+	AST/Expr.cpp \
+	AST/Init.cpp \
+	AST/LinkageSpec.cpp \
+	AST/Node.cpp \
+	AST/Stmt.cpp \
+	AST/Type.cpp \
+	AST/TypeSubstitution.cpp
 
 
@@ -25,3 +32,2 @@
 SRC += $(SRC_AST)
 SRCDEMANGLE += $(SRC_AST)
-
