Index: doc/proposals/vtable.md
===================================================================
--- doc/proposals/vtable.md	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ doc/proposals/vtable.md	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -220,5 +220,5 @@
     trait iterator(otype T, otype Item) {
         bool has_next(T const &);
-        Item get_next(T const *);
+        Item get_next(T &);
     }
 
Index: libcfa/src/iostream.cfa
===================================================================
--- libcfa/src/iostream.cfa	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ libcfa/src/iostream.cfa	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun May 19 10:48:27 2019
-// Update Count     : 654
+// Last Modified On : Tue May 21 13:01:26 2019
+// Update Count     : 674
 //
 
@@ -154,17 +154,21 @@
 	} // ?|?
 
-	static void checkDecPt( ostype & os, const char * buf, int len ) {
-		for ( int i = 0;; i += 1 ) {
-			if ( i == len ) { fmt( os, "." ); break; }
-			if ( buf[i] == '.' ) break;
-		} // for
-	} // checkDecPt
+	#define PrintWithDP( os, format, val, ... ) \
+		{ \
+			enum { size = 48 }; \
+			char buf[size]; \
+			int len = snprintf( buf, size, format, ##__VA_ARGS__, val ); \
+			fmt( os, "%s", buf ); \
+			if ( isfinite( val ) ) {					/* if number, always print decimal point */ \
+				for ( int i = 0;; i += 1 ) { \
+					if ( i == len ) { fmt( os, "." ); break; } \
+					if ( buf[i] == '.' ) break; \
+				} /* for */ \
+			} /* if */ \
+		}
 
 	ostype & ?|?( ostype & os, float f ) {
 		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
-		char buf[48];
-		int len = snprintf( buf, 48, "%g", f );
-		fmt( os, "%s", buf );
-		if ( isfinite( f ) ) checkDecPt( os, buf, len ); // always print decimal point
+		PrintWithDP( os, "%g", f );
 		return os;
 	} // ?|?
@@ -175,8 +179,5 @@
 	ostype & ?|?( ostype & os, double d ) {
 		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
-		char buf[48];
-		int len = snprintf( buf, 48, "%.*lg", DBL_DIG, d );
-		fmt( os, "%s", buf );
-		if ( isfinite( d ) ) checkDecPt( os, buf, len ); // always print decimal point
+		PrintWithDP( os, "%.*lg", d, DBL_DIG );
 		return os;
 	} // ?|?
@@ -187,8 +188,5 @@
 	ostype & ?|?( ostype & os, long double ld ) {
 		if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
-		char buf[48];
-		int len = snprintf( buf, 48, "%.*Lg", LDBL_DIG, ld );
-		fmt( os, "%s", buf );
-		if ( isfinite( ld ) ) checkDecPt( os, buf, len ); // always print decimal point
+		PrintWithDP( os, "%.*Lg", ld, LDBL_DIG );
 		return os;
 	} // ?|?
@@ -201,12 +199,7 @@
 //		os | crealf( fc ) | nonl;
 		float f = crealf( fc );
-		char buf[48];
-		int len = snprintf( buf, 48, "%g", f );
-		fmt( os, "%s", buf );
-		if ( isfinite( f ) ) checkDecPt( os, buf, len ); // always print decimal point
+		PrintWithDP( os, "%g", f );
 		f = cimagf( fc );
-		len = snprintf( buf, 48, "%+g", f );
-		fmt( os, "%s", buf );
-		if ( isfinite( f ) ) checkDecPt( os, buf, len ); // always print decimal point
+		PrintWithDP( os, "%+g", f );
 		fmt( os, "i" );
 		return os;
@@ -220,12 +213,7 @@
 //		os | creal( dc ) | nonl;
 		double d = creal( dc );
-		char buf[48];
-		int len = snprintf( buf, 48, "%.*lg", DBL_DIG, d );
-		fmt( os, "%s", buf );
-		if ( isfinite( d ) ) checkDecPt( os, buf, len ); // always print decimal point
+		PrintWithDP( os, "%.*lg", d, DBL_DIG );
 		d = cimag( dc );
-		len = snprintf( buf, 48, "%+.*lg", DBL_DIG, d );
-		fmt( os, "%s", buf );
-		if ( isfinite( d ) ) checkDecPt( os, buf, len ); // always print decimal point
+		PrintWithDP( os, "%+.*lg", d, DBL_DIG );
 		fmt( os, "i" );
 		return os;
@@ -239,12 +227,7 @@
 //		os | creall( ldc ) || nonl;
 		long double ld = creall( ldc );
-		char buf[48];
-		int len = snprintf( buf, 48, "%.*Lg", LDBL_DIG, ld );
-		fmt( os, "%s", buf );
-		if ( isfinite( ld ) ) checkDecPt( os, buf, len ); // always print decimal point
+		PrintWithDP( os, "%.*Lg", ld, LDBL_DIG );
 		ld = cimagl( ldc );
-		len = snprintf( buf, 48, "%+.*Lg", LDBL_DIG, ld );
-		fmt( os, "%s", buf );
-		if ( isfinite( ld ) ) checkDecPt( os, buf, len ); // always print decimal point
+		PrintWithDP( os, "%+.*Lg", ld, LDBL_DIG );
 		fmt( os, "i" );
 		return os;
Index: src/AST/Attribute.cpp
===================================================================
--- src/AST/Attribute.cpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Attribute.cpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -28,5 +28,5 @@
 	auto end = name.find_last_not_of('_');
 	if ( begin == std::string::npos || end == std::string::npos ) return "";
-	
+
 	// convert to lowercase
 	std::string ret;
Index: src/AST/Attribute.hpp
===================================================================
--- src/AST/Attribute.hpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Attribute.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -30,8 +30,8 @@
 public:
 	std::string name;
-	std::vector<ptr<Expr>> parameters;
+	std::vector<ptr<Expr>> params;
 
 	Attribute( const std::string & name = "", std::vector<ptr<Expr>> && params = {})
-	: name( name ), parameters( params ) {}
+	: name( name ), params( params ) {}
 	virtual ~Attribute() = default;
 
Index: src/AST/Bitfield.hpp
===================================================================
--- src/AST/Bitfield.hpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Bitfield.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -57,19 +57,13 @@
 };
 
-/// Adds default printing operator to a bitfield type.
-/// Include in definition to add print function, requires other bitfield operators.
-/// @param N  Number of bits in bitfield
-#define MakeBitfieldPrint( N ) \
-	static const char* Names[]; \
- \
-	void print( std::ostream & os ) const { \
-		if ( (*this).any() ) { \
-			for ( unsigned int i = 0; i < N; i += 1 ) { \
-				if ( (*this)[i] ) { \
-					os << Names[i] << ' '; \
-				} \
-			} \
-		} \
-	}
+template<typename T>
+inline bool operator== ( const bitfield<T> & a, const bitfield<T> & b ) {
+	return a.val == b.val;
+}
+
+template<typename T>
+inline bool operator!= ( const bitfield<T> & a, const bitfield<T> & b ) {
+	return !(a == b);
+}
 
 // Local Variables: //
Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Convert.cpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -10,9 +10,11 @@
 // 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 : Thu May 23 16:59:00 2019
+// Update Count     : 6
 //
 
 #include "Convert.hpp"
+
+#include <unordered_map>
 
 #include "AST/Attribute.hpp"
@@ -42,4 +44,6 @@
 class ConverterNewToOld : public ast::Visitor {
 	BaseSyntaxNode * node = nullptr;
+	using Cache = std::unordered_map< const ast::Node *, BaseSyntaxNode * >;
+	Cache cache;
 
 	template<typename T>
@@ -47,6 +51,7 @@
 		ConverterNewToOld & visitor;
 
-		template<typename U>
-		T * accept1( const ast::ptr<U> & ptr ) {
+		template<typename U, enum ast::Node::ref_type R>
+		T * accept1( const ast::ptr_base<U, R> & ptr ) {
+			if ( ! ptr ) return nullptr;
 			ptr->accept( visitor );
 			T * ret = strict_dynamic_cast< T * >( visitor.node );
@@ -87,4 +92,15 @@
 	}
 
+	/// get new qualifiers from old type
+	Type::Qualifiers cv( const ast::Type * ty ) { return { ty->qualifiers.val }; }
+
+	/// returns true and sets `node` if in cache
+	bool inCache( const ast::Node * node ) {
+		auto it = cache.find( node );
+		if ( it == cache.end() ) return false;
+		this->node = it->second;
+		return true;
+	}
+
 public:
 	Declaration * decl( const ast::Decl * declNode ) {
@@ -93,56 +109,159 @@
 
 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 ) {
+		cache.emplace( node, decl );
+		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
+		declPostamble( decl, node );
+		return nullptr;
+	}
+
 	const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final {
-		(void)node;
-		return nullptr;
+		if ( inCache( 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;
+		if ( inCache( node ) ) return nullptr;
+		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 );
+	}
+
+	const ast::Decl * namedTypePostamble( NamedTypeDecl * decl, const ast::NamedTypeDecl * node ) {
+		// base comes from constructor
+		decl->parameters = get<TypeDecl>().acceptL( node->params );
+		decl->assertions = get<DeclarationWithType>().acceptL( node->assertions );
+		declPostamble( decl, node );
+		return nullptr;
+	}
+
+	const ast::Decl * visit( const ast::TypeDecl * node ) override final {
+		if ( inCache( node ) ) return nullptr;
+		auto decl = new TypeDecl(
+			node->name,
+			Type::StorageClasses( node->storage.val ),
+			get<Type>().accept1( node->base ),
+			(TypeDecl::Kind)(unsigned)node->kind,
+			node->sized,
+			get<Type>().accept1( node->init )
+		);
+		cache.emplace( node, decl );
+		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 ) {
+		cache.emplace( node, decl );
+		decl->members = get<Declaration>().acceptL( node->members );
+		decl->parameters = get<TypeDecl>().acceptL( node->params );
+		decl->body = node->body;
+		// attributes come from constructor
+		decl->parent = get<AggregateDecl>().accept1( node->parent );
+		declPostamble( decl, node );
 		return nullptr;
 	}
 
 	const ast::Decl * visit( const ast::StructDecl * node ) override final {
-		(void)node;
-		return nullptr;
+		if ( inCache( 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;
+		if ( inCache( 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;
+		if ( inCache( 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;
+		if ( inCache( 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 ) {
+		cache.emplace( node, stmt );
 		stmt->location = node->location;
 		stmt->labels = makeLabelL( stmt, node->labels );
@@ -151,13 +270,21 @@
 	}
 
+	const ast::CompoundStmt * visit( const ast::CompoundStmt * node ) override final {
+		if ( inCache( node ) ) return nullptr;
+		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;
+		if ( inCache( node ) ) return nullptr;
+		auto stmt = new ExprStmt( nullptr );
+		cache.emplace( node, stmt );
+		stmt->expr = get<Expression>().accept1( node->expr );
+		return stmtPostamble( stmt, node );
 	}
 
 	const ast::Stmt * visit( const ast::AsmStmt * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto stmt = new AsmStmt(
 			node->isVolatile,
@@ -168,19 +295,15 @@
 			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 {
+		if ( inCache( node ) ) return nullptr;
 		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 );
 	}
 
 	const ast::Stmt * visit( const ast::IfStmt * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto stmt = new IfStmt(
 			get<Expression>().accept1( node->cond ),
@@ -189,22 +312,18 @@
 			get<Statement>().acceptL( node->inits )
 		);
-		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::SwitchStmt * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto stmt = new SwitchStmt(
 			get<Expression>().accept1( node->cond ),
 			get<Statement>().acceptL( node->stmts )
 		);
-		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::CaseStmt * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto stmt = new CaseStmt(
 			get<Expression>().accept1( node->cond ),
@@ -212,11 +331,9 @@
 			node->isDefault()
 		);
-		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::WhileStmt * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto inits = get<Statement>().acceptL( node->inits );
 		auto stmt = new WhileStmt(
@@ -226,11 +343,9 @@
 			node->isDoWhile
 		);
-		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::ForStmt * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto stmt = new ForStmt(
 			get<Statement>().acceptL( node->inits ),
@@ -239,11 +354,9 @@
 			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::BranchStmt * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		BranchStmt * stmt;
 		if (node->computedTarget) {
@@ -271,19 +384,15 @@
 			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 {
+		if ( inCache( node ) ) return nullptr;
 		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 );
 	}
 
 	const ast::Stmt * visit( const ast::ThrowStmt * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		ThrowStmt::Kind kind;
 		switch (node->kind) {
@@ -302,11 +411,9 @@
 			get<Expression>().accept1( 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::TryStmt * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto handlers = get<CatchStmt>().acceptL( node->handlers );
 		auto stmt = new TryStmt(
@@ -315,11 +422,9 @@
 			get<FinallyStmt>().accept1( node->finally )
 		);
-		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::CatchStmt * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		CatchStmt::Kind kind;
 		switch (node->kind) {
@@ -339,25 +444,21 @@
 			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 {
+		if ( inCache( node ) ) return nullptr;
 		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 );
 	}
 
 	const ast::Stmt * visit( const ast::WaitForStmt * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto stmt = new WaitForStmt;
 		stmt->clauses.reserve( node->clauses.size() );
 		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 ),
@@ -374,354 +475,843 @@
 			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 );
 	}
 
 	const ast::Stmt * visit( const ast::WithStmt * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto stmt = new WithStmt(
 			get<Expression>().acceptL( node->exprs ),
 			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 {
+		if ( inCache( node ) ) return nullptr;
 		auto stmt = new NullStmt();
-		stmt->location = node->location;
-		stmt->labels = makeLabelL( stmt, node->labels );
-		this->node = stmt;
+		stmtPostamble( stmt, node );
 		return nullptr;
 	}
 
 	const ast::Stmt * visit( const ast::DeclStmt * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		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 );
 	}
 
 	const ast::Stmt * visit( const ast::ImplicitCtorDtorStmt * node ) override final {
+		if ( inCache( node ) ) return nullptr;
+		auto stmt = new ImplicitCtorDtorStmt{
+			get<Statement>().accept1( node->callStmt )
+		};
+		return stmtPostamble( stmt, node );
+	}
+
+	TypeSubstitution * convertTypeSubstitution(const ast::TypeSubstitution * src) {
+
+		if (!src) return nullptr;
+
+		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_skipResultType(const ast::Expr * src, Expression * tgt) {
+
+		tgt->location  = src->location;
+		tgt->env       = convertTypeSubstitution(src->env);
+		tgt->extension = src->extension;
+
+		convertInferUnion(tgt->inferParams, tgt->resnSlots, src->inferred);
+		return tgt;
+	}
+
+	Expression * visitBaseExpr(const ast::Expr * src, Expression * tgt) {
+
+		tgt->result = get<Type>().accept1(src->result);
+		return visitBaseExpr_skipResultType(src, tgt);
+	}
+
+	const ast::Expr * visit( const ast::ApplicationExpr * node ) override final {
+		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 {
+		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 {
+		auto expr = visitBaseExpr( node,
+			new NameExpr(
+				node->name
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::AddressExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new AddressExpr(
+				get<Expression>().accept1(node->arg)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::LabelAddressExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new LabelAddressExpr(
+				makeLabel(nullptr, node->arg)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::CastExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new CastExpr(
+				get<Expression>().accept1(node->arg),
+				(node->isGenerated == ast::GeneratedCast)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::KeywordCastExpr * node ) override final {
+		KeywordCastExpr::Target castTarget = KeywordCastExpr::NUMBER_OF_TARGETS;
+		switch (node->target) {
+			case ast::KeywordCastExpr::Coroutine:
+				castTarget = KeywordCastExpr::Coroutine;
+				break;
+			case ast::KeywordCastExpr::Thread:
+				castTarget = KeywordCastExpr::Thread;
+				break;
+			case ast::KeywordCastExpr::Monitor:
+				castTarget = KeywordCastExpr::Monitor;
+				break;
+			default:
+				break;
+		}
+		assert ( castTarget < KeywordCastExpr::NUMBER_OF_TARGETS );
+		auto expr = visitBaseExpr( node,
+			new KeywordCastExpr(
+				get<Expression>().accept1(node->arg),
+				castTarget
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::VirtualCastExpr * node ) override final {
+		auto expr = visitBaseExpr_skipResultType( node,
+			new VirtualCastExpr(
+				get<Expression>().accept1(node->arg),
+				get<Type>().accept1(node->result)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::UntypedMemberExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new UntypedMemberExpr(
+				get<Expression>().accept1(node->member),
+				get<Expression>().accept1(node->aggregate)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::MemberExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new MemberExpr(
+				inCache(node->member) ?
+					dynamic_cast<DeclarationWithType *>(this->node) :
+					get<DeclarationWithType>().accept1(node->member),
+				get<Expression>().accept1(node->aggregate)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::VariableExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new VariableExpr(
+				inCache(node->var) ?
+					dynamic_cast<DeclarationWithType *>(this->node) :
+					get<DeclarationWithType>().accept1(node->var)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::ConstantExpr * node ) override final {
+		ConstantExpr *rslt = nullptr;
+		switch ( node->kind ) {
+		case ast::ConstantExpr::Integer:
+			rslt = new ConstantExpr{Constant{
+				get<Type>().accept1( node->result ),
+				node->rep,
+				(unsigned long long) node->intValue()
+			}};
+			break;
+		case ast::ConstantExpr::FloatingPoint:
+			rslt = new ConstantExpr{Constant{
+				get<Type>().accept1(node->result),
+				node->rep,
+				(double) node->floatValue()
+			}};
+			break;
+		case ast::ConstantExpr::String:
+			rslt = new ConstantExpr{Constant::from_string( node->rep )};
+			break;
+		}
+		assert(rslt);
+		auto expr = visitBaseExpr( node, rslt );
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::SizeofExpr * node ) override final {
+		assert (node->expr || node->type);
+		assert (! (node->expr && node->type));
+		SizeofExpr *rslt;
+		if (node->expr) {
+			rslt = new SizeofExpr(
+				get<Expression>().accept1(node->expr)
+			);
+			assert (!rslt->isType);
+		}
+		if (node->type) {
+			rslt = new SizeofExpr(
+				get<Type>().accept1(node->type)
+			);
+			assert (rslt->isType);
+		}
+		auto expr = visitBaseExpr( node, rslt );
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::AlignofExpr * node ) override final {
+		assert (node->expr || node->type);
+		assert (! (node->expr && node->type));
+		AlignofExpr *rslt;
+		if (node->expr) {
+			rslt = new AlignofExpr(
+				get<Expression>().accept1(node->expr)
+			);
+			assert (!rslt->isType);
+		}
+		if (node->type) {
+			rslt = new AlignofExpr(
+				get<Type>().accept1(node->type)
+			);
+			assert (rslt->isType);
+		}
+		auto expr = visitBaseExpr( node, rslt );
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::UntypedOffsetofExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new UntypedOffsetofExpr(
+				get<Type>().accept1(node->type),
+				node->member
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::OffsetofExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new OffsetofExpr(
+				get<Type>().accept1(node->type),
+				inCache(node->member) ?
+					dynamic_cast<DeclarationWithType *>(this->node) :
+					get<DeclarationWithType>().accept1(node->member)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::OffsetPackExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new OffsetPackExpr(
+				get<StructInstType>().accept1(node->type)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::LogicalExpr * node ) override final {
+		assert (node->isAnd == ast::LogicalFlag::AndExpr ||
+				node->isAnd == ast::LogicalFlag::OrExpr	);
+		auto expr = visitBaseExpr( node,
+			new LogicalExpr(
+				get<Expression>().accept1(node->arg1),
+				get<Expression>().accept1(node->arg2),
+				(node->isAnd == ast::LogicalFlag::AndExpr)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::ConditionalExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new ConditionalExpr(
+				get<Expression>().accept1(node->arg1),
+				get<Expression>().accept1(node->arg2),
+				get<Expression>().accept1(node->arg3)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::CommaExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new CommaExpr(
+				get<Expression>().accept1(node->arg1),
+				get<Expression>().accept1(node->arg2)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::TypeExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new TypeExpr(
+				get<Type>().accept1(node->type)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::AsmExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new AsmExpr(
+				get<Expression>().accept1(node->inout),
+				get<Expression>().accept1(node->constraint),
+				get<Expression>().accept1(node->operand)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::ImplicitCopyCtorExpr * node ) override final {
+		auto rslt = new ImplicitCopyCtorExpr(
+			get<ApplicationExpr>().accept1(node->callExpr)
+		);
+
+		auto expr = visitBaseExpr( node, rslt );
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::ConstructorExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new ConstructorExpr(
+				get<Expression>().accept1(node->callExpr)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::CompoundLiteralExpr * node ) override final {
+		auto expr = visitBaseExpr_skipResultType( node,
+			new CompoundLiteralExpr(
+				get<Type>().accept1(node->result),
+				get<Initializer>().accept1(node->init)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::RangeExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new RangeExpr(
+				get<Expression>().accept1(node->low),
+				get<Expression>().accept1(node->high)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::UntypedTupleExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new UntypedTupleExpr(
+				get<Expression>().acceptL(node->exprs)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::TupleExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new UntypedTupleExpr(
+				get<Expression>().acceptL(node->exprs)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::TupleIndexExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new TupleIndexExpr(
+				get<Expression>().accept1(node->tuple),
+				node->index
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::TupleAssignExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new TupleAssignExpr(
+				get<StmtExpr>().accept1(node->stmtExpr)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::StmtExpr * node ) override final {
+		auto rslt = new StmtExpr(
+			get<CompoundStmt>().accept1(node->stmts)
+		);
+
+		rslt->returnDecls = get<ObjectDecl>().acceptL(node->returnDecls);
+		rslt->dtors       = get<Expression>().acceptL(node->dtors);
+
+		auto expr = visitBaseExpr( node, rslt );
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::UniqueExpr * node ) override final {
+		auto rslt = new UniqueExpr(
+			get<Expression>().accept1(node->expr)
+		);
+
+		rslt->object = get<ObjectDecl>  ().accept1(node->object);
+		rslt->var    = get<VariableExpr>().accept1(node->var);
+
+		auto expr = visitBaseExpr( node, rslt );
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::UntypedInitExpr * node ) override final {
+		std::list<InitAlternative> initAlts;
+		for (auto ia : node->initAlts) {
+			initAlts.push_back(InitAlternative(
+				get<Type>       ().accept1(ia.type),
+				get<Designation>().accept1(ia.designation)
+			));
+		}
+		auto expr = visitBaseExpr( node,
+			new UntypedInitExpr(
+				get<Expression>().accept1(node->expr),
+				initAlts
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::InitExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new InitExpr(
+				get<Expression>().accept1(node->expr),
+				get<Designation>().accept1(node->designation)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::DeletedExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new DeletedExpr(
+				get<Expression>().accept1(node->expr),
+				inCache(node->deleteStmt) ?
+					this->node :
+					get<BaseSyntaxNode>().accept1(node->deleteStmt)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::DefaultArgExpr * node ) override final {
+		auto expr = visitBaseExpr( node,
+			new DefaultArgExpr(
+				get<Expression>().accept1(node->expr)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Expr * visit( const ast::GenericExpr * node ) override final {
+		std::list<GenericExpr::Association> associations;
+		for (auto association : node->associations) {
+			associations.push_back(GenericExpr::Association(
+				get<Type>      ().accept1(association.type),
+				get<Expression>().accept1(association.expr)
+			));
+		}
+		auto expr = visitBaseExpr( node,
+			new GenericExpr(
+				get<Expression>().accept1(node->control),
+				associations
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::VoidType * node ) override final {
+		this->node = new VoidType{ cv( node ) };
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::BasicType * node ) override final {
+		this->node = new BasicType{ cv( node ), (BasicType::Kind)(unsigned)node->kind };
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::PointerType * node ) override final {
+		this->node = new PointerType{
+			cv( node ),
+			get<Type>().accept1( node->base ),
+			get<Expression>().accept1( node->dimension ),
+			(bool)node->isVarLen,
+			(bool)node->isStatic
+		};
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::ArrayType * node ) override final {
+		this->node = new ArrayType{
+			cv( node ),
+			get<Type>().accept1( node->base ),
+			get<Expression>().accept1( node->dimension ),
+			(bool)node->isVarLen,
+			(bool)node->isStatic
+		};
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::ReferenceType * node ) override final {
+		this->node = new ReferenceType{
+			cv( node ),
+			get<Type>().accept1( node->base )
+		};
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::QualifiedType * node ) override final {
+		this->node = new QualifiedType{
+			cv( node ),
+			get<Type>().accept1( node->parent ),
+			get<Type>().accept1( node->child )
+		};
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::FunctionType * node ) override final {
+		auto ty = new FunctionType {
+			cv( node ),
+			(bool)node->isVarArgs
+		};
+		ty->returnVals = get<DeclarationWithType>().acceptL( node->returns );
+		ty->parameters = get<DeclarationWithType>().acceptL( node->params );
+		ty->forall = get<TypeDecl>().acceptL( node->forall );
+		this->node = ty;
+		return nullptr;
+	}
+
+	void postvisit( const ast::ReferenceToType * old, ReferenceToType * ty ) {
+		ty->forall = get<TypeDecl>().acceptL( old->forall );
+		ty->parameters = get<Expression>().acceptL( old->params );
+		ty->hoistType = old->hoistType;
+	}
+
+	const ast::Type * visit( const ast::StructInstType * node ) override final {
+		StructInstType * ty;
+		if ( node->base ) {
+			ty = new StructInstType{
+				cv( node ),
+				get<StructDecl>().accept1( node->base ),
+				get<Attribute>().acceptL( node->attributes )
+			};
+		} else {
+			ty = new StructInstType{
+				cv( node ),
+				node->name,
+				get<Attribute>().acceptL( node->attributes )
+			};
+		}
+		postvisit( node, ty );
+		this->node = ty;
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::UnionInstType * node ) override final {
+		UnionInstType * ty;
+		if ( node->base ) {
+			ty = new UnionInstType{
+				cv( node ),
+				get<UnionDecl>().accept1( node->base ),
+				get<Attribute>().acceptL( node->attributes )
+			};
+		} else {
+			ty = new UnionInstType{
+				cv( node ),
+				node->name,
+				get<Attribute>().acceptL( node->attributes )
+			};
+		}
+		postvisit( node, ty );
+		this->node = ty;
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::EnumInstType * node ) override final {
+		EnumInstType * ty;
+		if ( node->base ) {
+			ty = new EnumInstType{
+				cv( node ),
+				get<EnumDecl>().accept1( node->base ),
+				get<Attribute>().acceptL( node->attributes )
+			};
+		} else {
+			ty = new EnumInstType{
+				cv( node ),
+				node->name,
+				get<Attribute>().acceptL( node->attributes )
+			};
+		}
+		postvisit( node, ty );
+		this->node = ty;
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::TraitInstType * node ) override final {
+		TraitInstType * ty;
+		if ( node->base ) {
+			ty = new TraitInstType{
+				cv( node ),
+				get<TraitDecl>().accept1( node->base ),
+				get<Attribute>().acceptL( node->attributes )
+			};
+		} else {
+			ty = new TraitInstType{
+				cv( node ),
+				node->name,
+				get<Attribute>().acceptL( node->attributes )
+			};
+		}
+		postvisit( node, ty );
+		this->node = ty;
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::TypeInstType * node ) override final {
+		TypeInstType * ty;
+		if ( node->base ) {
+			ty = new TypeInstType{
+				cv( node ),
+				node->name,
+				get<TypeDecl>().accept1( node->base ),
+				get<Attribute>().acceptL( node->attributes )
+			};
+		} else {
+			ty = new TypeInstType{
+				cv( node ),
+				node->name,
+				node->kind == ast::TypeVar::Ftype,
+				get<Attribute>().acceptL( node->attributes )
+			};
+		}
+		postvisit( node, ty );
+		this->node = ty;
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::TupleType * node ) override final {
+		this->node = new TupleType{
+			cv( node ),
+			get<Type>().acceptL( node->types )
+			// members generated by TupleType c'tor
+		};
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::TypeofType * node ) override final {
+		this->node = new TypeofType{
+			cv( node ),
+			get<Expression>().accept1( node->expr ),
+			(bool)node->kind
+		};
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::VarArgsType * node ) override final {
+		this->node = new VarArgsType{ cv( node ) };
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::ZeroType * node ) override final {
+		this->node = new ZeroType{ cv( node ) };
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::OneType * node ) override final {
+		this->node = new OneType{ cv( node ) };
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::GlobalScopeType * ) override final {
+		this->node = new GlobalScopeType{};
+		return nullptr;
+	}
+
+	const ast::Designation * visit( const ast::Designation * node ) override final {
+		auto designation = new Designation( get<Expression>().acceptL( node->designators ) );
+		designation->location = node->location;
+		this->node = designation;
+		return nullptr;
+	}
+
+	const ast::Init * visit( const ast::SingleInit * node ) override final {
+		auto init = new SingleInit(
+			get<Expression>().accept1( node->value ),
+			ast::MaybeConstruct == node->maybeConstructed
+		);
+		init->location = node->location;
+		this->node = init;
+		return nullptr;
+	}
+
+	const ast::Init * visit( const ast::ListInit * node ) override final {
+		auto init = new ListInit(
+			get<Initializer>().acceptL( node->initializers ),
+			get<Designation>().acceptL( node->designations ),
+			ast::MaybeConstruct == node->maybeConstructed
+		);
+		init->location = node->location;
+		this->node = init;
+		return nullptr;
+	}
+
+	const ast::Init * visit( const ast::ConstructorInit * node ) override final {
+		auto init = new ConstructorInit(
+			get<Statement>().accept1( node->ctor ),
+			get<Statement>().accept1( node->dtor ),
+			get<Initializer>().accept1( node->init )
+		);
+		init->location = node->location;
+		this->node = init;
+		return nullptr;
+	}
+
+	const ast::Attribute * visit( const ast::Attribute * node ) override final {
+		auto attr = new Attribute(
+			node->name,
+			get<Expression>().acceptL(node->params)
+		);
+		this->node = attr;
+		return nullptr;
+	}
+
+	const ast::TypeSubstitution * visit( const ast::TypeSubstitution * node ) override final {
+		// Handled by convertTypeSubstitution helper instead.
+		// TypeSubstitution is not a node in the old model, so the conversion result wouldn't fit in this->node.
+		assert( 0 );
 		(void)node;
 		return nullptr;
 	}
-
-	const ast::Expr * visit( const ast::ApplicationExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::UntypedExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::NameExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::AddressExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::LabelAddressExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::CastExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::KeywordCastExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::VirtualCastExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::UntypedMemberExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::MemberExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::VariableExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::ConstantExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::SizeofExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::AlignofExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::UntypedOffsetofExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::OffsetofExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::OffsetPackExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::LogicalExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::ConditionalExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::CommaExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::TypeExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::AsmExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::ImplicitCopyCtorExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::ConstructorExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::CompoundLiteralExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::RangeExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::UntypedTupleExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::TupleExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::TupleIndexExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::TupleAssignExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::StmtExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::UniqueExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::UntypedInitExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::InitExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::DeletedExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::DefaultArgExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Expr * visit( const ast::GenericExpr * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::VoidType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::BasicType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::PointerType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::ArrayType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::ReferenceType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::QualifiedType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::FunctionType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::StructInstType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::UnionInstType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::EnumInstType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::TraitInstType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::TypeInstType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::TupleType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::TypeofType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::VarArgsType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::ZeroType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::OneType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Type * visit( const ast::GlobalScopeType * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Designation * visit( const ast::Designation * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Init * visit( const ast::SingleInit * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Init * visit( const ast::ListInit * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Init * visit( const ast::ConstructorInit * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::Attribute * visit( const ast::Attribute * node ) override final {
-		(void)node;
-		return nullptr;
-	}
-
-	const ast::TypeSubstitution * visit( const ast::TypeSubstitution * node ) override final {
-		(void)node;
-		return nullptr;
-	}
 };
 
-std::list< Declaration * > convert( std::list< ast::ptr< ast::Decl > > && translationUnit ) {
+std::list< Declaration * > convert( const std::list< ast::ptr< ast::Decl > > && translationUnit ) {
 	ConverterNewToOld c;
 	std::list< Declaration * > decls;
 	for(auto d : translationUnit) {
 		decls.emplace_back( c.decl( d ) );
-		delete d;
 	}
 	return decls;
@@ -736,5 +1326,8 @@
 	}
 private:
+	/// conversion output
 	ast::Node * node;
+	/// cache of nodes that might be referenced by readonly<> for de-duplication
+	std::unordered_map< BaseSyntaxNode *, ast::Node * > cache;
 
 	// Local Utilities:
@@ -742,4 +1335,5 @@
 	template<typename NewT, typename OldT>
 	NewT * getAccept1( OldT old ) {
+		if ( ! old ) return nullptr;
 		old->accept(*this);
 		return strict_dynamic_cast< NewT * >( node );
@@ -783,7 +1377,18 @@
 		to<std::vector>::from( make_labels( std::move( labels ) ) )
 
+	static ast::CV::Qualifiers cv( Type * ty ) { return { ty->get_qualifiers().val }; }
+
+	/// returns true and sets `node` if in cache
+	bool inCache( BaseSyntaxNode * old ) {
+		auto it = cache.find( old );
+		if ( it == cache.end() ) return false;
+		node = it->second;
+		return true;
+	}
+
 	// Now all the visit functions:
 
 	virtual void visit( ObjectDecl * old ) override final {
+		if ( inCache( old ) ) return;
 		auto decl = new ast::ObjectDecl(
 			old->location,
@@ -797,4 +1402,5 @@
 			{ old->get_funcSpec().val }
 		);
+		cache.emplace( old, decl );
 		decl->scopeLevel = old->scopeLevel;
 		decl->mangleName = old->mangleName;
@@ -806,9 +1412,28 @@
 	}
 
-	virtual void visit( FunctionDecl * ) override final {
-
+	virtual void visit( FunctionDecl * old ) override final {
+		if ( inCache( old ) ) return;
+		auto decl = new ast::FunctionDecl{
+			old->location,
+			old->name,
+			GET_ACCEPT_1(type, FunctionType),
+			GET_ACCEPT_1(statements, CompoundStmt),
+			{ old->storageClasses.val },
+			{ old->linkage.val },
+			GET_ACCEPT_V(attributes, Attribute),
+			{ old->get_funcSpec().val }
+		};
+		cache.emplace( old, decl );
+		decl->scopeLevel = old->scopeLevel;
+		decl->mangleName = old->mangleName;
+		decl->isDeleted  = old->isDeleted;
+		decl->uniqueId   = old->uniqueId;
+		decl->extension  = old->extension;
+
+		this->node = decl;
 	}
 
 	virtual void visit( StructDecl * old ) override final {
+		if ( inCache( old ) ) return;
 		auto decl = new ast::StructDecl(
 			old->location,
@@ -818,4 +1443,5 @@
 			{ old->linkage.val }
 		);
+		cache.emplace( old, decl );
 		decl->parent = GET_ACCEPT_1(parent, AggregateDecl);
 		decl->body   = old->body;
@@ -830,4 +1456,5 @@
 
 	virtual void visit( UnionDecl * old ) override final {
+		if ( inCache( old ) ) return;
 		auto decl = new ast::UnionDecl(
 			old->location,
@@ -836,4 +1463,5 @@
 			{ old->linkage.val }
 		);
+		cache.emplace( old, decl );
 		decl->parent = GET_ACCEPT_1(parent, AggregateDecl);
 		decl->body   = old->body;
@@ -848,4 +1476,5 @@
 
 	virtual void visit( EnumDecl * old ) override final {
+		if ( inCache( old ) ) return;
 		auto decl = new ast::UnionDecl(
 			old->location,
@@ -854,4 +1483,5 @@
 			{ old->linkage.val }
 		);
+		cache.emplace( old, decl );
 		decl->parent = GET_ACCEPT_1(parent, AggregateDecl);
 		decl->body   = old->body;
@@ -866,4 +1496,5 @@
 
 	virtual void visit( TraitDecl * old ) override final {
+		if ( inCache( old ) ) return;
 		auto decl = new ast::UnionDecl(
 			old->location,
@@ -872,4 +1503,5 @@
 			{ old->linkage.val }
 		);
+		cache.emplace( old, decl );
 		decl->parent = GET_ACCEPT_1(parent, AggregateDecl);
 		decl->body   = old->body;
@@ -883,6 +1515,22 @@
 	}
 
-	virtual void visit( TypeDecl * ) override final {
-
+	virtual void visit( TypeDecl * old ) override final {
+		if ( inCache( old ) ) return;
+		auto decl = new ast::TypeDecl{
+			old->location,
+			old->name,
+			{ old->storageClasses.val },
+			GET_ACCEPT_1(base, Type),
+			(ast::TypeVar::Kind)(unsigned)old->kind,
+			old->sized,
+			GET_ACCEPT_1(init, Type)
+		};
+		cache.emplace( old, decl );
+		decl->assertions = GET_ACCEPT_V(assertions, DeclWithType);
+		decl->params     = GET_ACCEPT_V(parameters, TypeDecl);
+		decl->extension  = old->extension;
+		decl->uniqueId   = old->uniqueId;
+
+		this->node = decl;
 	}
 
@@ -904,13 +1552,31 @@
 	}
 
-	virtual void visit( AsmDecl * ) override final {
-
-	}
-
-	virtual void visit( StaticAssertDecl * ) override final {
-
+	virtual void visit( AsmDecl * old ) override final {
+		auto decl = new ast::AsmDecl{
+			old->location,
+			GET_ACCEPT_1(stmt, AsmStmt)
+		};
+		decl->extension  = old->extension;
+		decl->uniqueId   = old->uniqueId;
+		decl->storage    = { old->storageClasses.val };
+
+		this->node = decl;
+	}
+
+	virtual void visit( StaticAssertDecl * old ) override final {
+		auto decl = new ast::StaticAssertDecl{
+			old->location,
+			GET_ACCEPT_1(condition, Expr),
+			GET_ACCEPT_1(message, ConstantExpr)
+		};
+		decl->extension  = old->extension;
+		decl->uniqueId   = old->uniqueId;
+		decl->storage    = { old->storageClasses.val };
+
+		this->node = decl;
 	}
 
 	virtual void visit( CompoundStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		auto stmt = new ast::CompoundStmt(
 			old->location,
@@ -920,7 +1586,9 @@
 
 		this->node = stmt;
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( ExprStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		this->node = new ast::ExprStmt(
 			old->location,
@@ -928,7 +1596,9 @@
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( AsmStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		this->node = new ast::AsmStmt(
 			old->location,
@@ -941,7 +1611,9 @@
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( DirectiveStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		this->node = new ast::DirectiveStmt(
 			old->location,
@@ -949,7 +1621,9 @@
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( IfStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		this->node = new ast::IfStmt(
 			old->location,
@@ -960,7 +1634,9 @@
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( SwitchStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		this->node = new ast::SwitchStmt(
 			old->location,
@@ -969,7 +1645,9 @@
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( CaseStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		this->node = new ast::CaseStmt(
 			old->location,
@@ -978,7 +1656,9 @@
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( WhileStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		this->node = new ast::WhileStmt(
 			old->location,
@@ -989,7 +1669,9 @@
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( ForStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		this->node = new ast::ForStmt(
 			old->location,
@@ -1000,7 +1682,9 @@
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( BranchStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		if (old->computedTarget) {
 			this->node = new ast::BranchStmt(
@@ -1036,7 +1720,9 @@
 			this->node = stmt;
 		}
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( ReturnStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		this->node = new ast::ReturnStmt(
 			old->location,
@@ -1044,7 +1730,9 @@
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( ThrowStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		ast::ThrowStmt::Kind kind;
 		switch (old->kind) {
@@ -1066,7 +1754,9 @@
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( TryStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		this->node = new ast::TryStmt(
 			old->location,
@@ -1076,7 +1766,9 @@
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( CatchStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		ast::CatchStmt::Kind kind;
 		switch (old->kind) {
@@ -1099,7 +1791,9 @@
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( FinallyStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		this->node = new ast::FinallyStmt(
 			old->location,
@@ -1107,7 +1801,9 @@
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( WaitForStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		ast::WaitForStmt * stmt = new ast::WaitForStmt(
 			old->location,
@@ -1137,7 +1833,9 @@
 
 		this->node = stmt;
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( WithStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		this->node = new ast::WithStmt(
 			old->location,
@@ -1146,14 +1844,18 @@
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( NullStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		this->node = new ast::NullStmt(
 			old->location,
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( DeclStmt * old ) override final {
+		if ( inCache( old ) ) return;
 		this->node = new ast::DeclStmt(
 			old->location,
@@ -1161,15 +1863,22 @@
 			GET_LABELS_V(old->labels)
 		);
+		cache.emplace( old, this->node );
 	}
 
 	virtual void visit( ImplicitCtorDtorStmt * old ) override final {
-		this->node = new ast::ImplicitCtorDtorStmt(
-			old->location,
-			GET_ACCEPT_1(callStmt, Stmt),
+		if ( inCache( old ) ) return;
+		auto stmt = new ast::ImplicitCtorDtorStmt(
+			old->location,
+			nullptr,
 			GET_LABELS_V(old->labels)
 		);
+		this->node = stmt;
+		cache.emplace( old, this->node );
+		stmt->callStmt = GET_ACCEPT_1(callStmt, Stmt);
 	}
 
 	ast::TypeSubstitution * convertTypeSubstitution(const TypeSubstitution * old) {
+
+		if (!old) return nullptr;
 
 		ast::TypeSubstitution *rslt = new ast::TypeSubstitution();
@@ -1184,18 +1893,35 @@
 			              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
-	}
-
-	ast::Expr * visitBaseExpr(Expression * old, ast::Expr * nw) {
-
-		nw->result = GET_ACCEPT_1(result, Type);
+
+		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);
+			}
+		}
+	}
+
+	ast::Expr * visitBaseExpr_SkipResultType(Expression * old, ast::Expr * nw) {
+
 		nw->env    = convertTypeSubstitution(old->env);
 
@@ -1206,10 +1932,28 @@
 	}
 
-	virtual void visit( ApplicationExpr * ) override final {
-		// TODO
-	}
-
-	virtual void visit( UntypedExpr * ) override final {
-		// TODO
+	ast::Expr * visitBaseExpr(Expression * old, ast::Expr * nw) {
+
+		nw->result = GET_ACCEPT_1(result, Type);
+		return visitBaseExpr_SkipResultType(old, nw);;
+	}
+
+	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)
+			)
+		);
 	}
 
@@ -1223,243 +1967,693 @@
 	}
 
-	virtual void visit( CastExpr * ) override final {
-		// TODO ... (rest)
-	}
-
-	virtual void visit( KeywordCastExpr * ) override final {
-
-	}
-
-	virtual void visit( VirtualCastExpr * ) override final {
-
-	}
-
-	virtual void visit( AddressExpr * ) override final {
-
-	}
-
-	virtual void visit( LabelAddressExpr * ) override final {
-
-	}
-
-	virtual void visit( UntypedMemberExpr * ) override final {
-
-	}
-
-	virtual void visit( MemberExpr * ) override final {
-
-	}
-
-	virtual void visit( VariableExpr * ) override final {
-
-	}
-
-	virtual void visit( ConstantExpr * ) override final {
-
-	}
-
-	virtual void visit( SizeofExpr * ) override final {
-
-	}
-
-	virtual void visit( AlignofExpr * ) override final {
-
-	}
-
-	virtual void visit( UntypedOffsetofExpr * ) override final {
-
-	}
-
-	virtual void visit( OffsetofExpr * ) override final {
-
-	}
-
-	virtual void visit( OffsetPackExpr * ) override final {
-
-	}
-
-	virtual void visit( LogicalExpr * ) override final {
-
-	}
-
-	virtual void visit( ConditionalExpr * ) override final {
-
-	}
-
-	virtual void visit( CommaExpr * ) override final {
-
-	}
-
-	virtual void visit( TypeExpr * ) override final {
-
-	}
-
-	virtual void visit( AsmExpr * ) override final {
-
-	}
-
-	virtual void visit( ImplicitCopyCtorExpr * ) override final {
-
-	}
-
-	virtual void visit( ConstructorExpr *  ) override final {
-
-	}
-
-	virtual void visit( CompoundLiteralExpr * ) override final {
-
-	}
-
-	virtual void visit( RangeExpr * ) override final {
-
-	}
-
-	virtual void visit( UntypedTupleExpr * ) override final {
-
-	}
-
-	virtual void visit( TupleExpr * ) override final {
-
-	}
-
-	virtual void visit( TupleIndexExpr * ) override final {
-
-	}
-
-	virtual void visit( TupleAssignExpr * ) override final {
-
-	}
-
-	virtual void visit( StmtExpr *  ) override final {
-
-	}
-
-	virtual void visit( UniqueExpr *  ) override final {
-
-	}
-
-	virtual void visit( UntypedInitExpr *  ) override final {
-
-	}
-
-	virtual void visit( InitExpr *  ) override final {
-
-	}
-
-	virtual void visit( DeletedExpr * ) override final {
-
-	}
-
-	virtual void visit( DefaultArgExpr * ) override final {
-
-	}
-
-	virtual void visit( GenericExpr * ) override final {
-
-	}
-
-	virtual void visit( VoidType * ) override final {
-
-	}
-
-	virtual void visit( BasicType * ) override final {
-
-	}
-
-	virtual void visit( PointerType * ) override final {
-
-	}
-
-	virtual void visit( ArrayType * ) override final {
-
-	}
-
-	virtual void visit( ReferenceType * ) override final {
-
-	}
-
-	virtual void visit( QualifiedType * ) override final {
-
-	}
-
-	virtual void visit( FunctionType * ) override final {
-
-	}
-
-	virtual void visit( StructInstType * ) override final {
-
-	}
-
-	virtual void visit( UnionInstType * ) override final {
-
-	}
-
-	virtual void visit( EnumInstType * ) override final {
-
-	}
-
-	virtual void visit( TraitInstType * ) override final {
-
-	}
-
-	virtual void visit( TypeInstType * ) override final {
-
-	}
-
-	virtual void visit( TupleType * ) override final {
-
-	}
-
-	virtual void visit( TypeofType * ) override final {
-
+	virtual void visit( CastExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::CastExpr(
+				old->location,
+				GET_ACCEPT_1(arg, Expr),
+				old->isGenerated ? ast::GeneratedCast : ast::ExplicitCast
+			)
+		);
+	}
+
+	virtual void visit( KeywordCastExpr * old) override final {
+		ast::KeywordCastExpr::Target castTarget = ast::KeywordCastExpr::NUMBER_OF_TARGETS;
+		switch (old->target) {
+			case KeywordCastExpr::Coroutine:
+				castTarget = ast::KeywordCastExpr::Coroutine;
+				break;
+			case KeywordCastExpr::Thread:
+				castTarget = ast::KeywordCastExpr::Thread;
+				break;
+			case KeywordCastExpr::Monitor:
+				castTarget = ast::KeywordCastExpr::Monitor;
+				break;
+			default:
+				break;
+		}
+		assert ( castTarget < ast::KeywordCastExpr::NUMBER_OF_TARGETS );
+		this->node = visitBaseExpr( old,
+			new ast::KeywordCastExpr(
+				old->location,
+				GET_ACCEPT_1(arg, Expr),
+				castTarget
+			)
+		);
+	}
+
+	virtual void visit( VirtualCastExpr * old ) override final {
+		this->node = visitBaseExpr_SkipResultType( old,
+			new ast::VirtualCastExpr(
+				old->location,
+				GET_ACCEPT_1(arg, Expr),
+				GET_ACCEPT_1(result, Type)
+			)
+		);
+	}
+
+	virtual void visit( AddressExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::AddressExpr(
+				old->location,
+				GET_ACCEPT_1(arg, Expr)
+			)
+		);
+	}
+
+	virtual void visit( LabelAddressExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::LabelAddressExpr(
+				old->location,
+				make_label(&old->arg)
+			)
+		);
+	}
+
+	virtual void visit( UntypedMemberExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::UntypedMemberExpr(
+				old->location,
+				GET_ACCEPT_1(member, Expr),
+				GET_ACCEPT_1(aggregate, Expr)
+			)
+		);
+	}
+
+	virtual void visit( MemberExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::MemberExpr(
+				old->location,
+				inCache(old->member) ?
+					dynamic_cast<ast::DeclWithType *>(this->node) :
+					GET_ACCEPT_1(member, DeclWithType),
+				GET_ACCEPT_1(aggregate, Expr)
+			)
+		);
+	}
+
+	virtual void visit( VariableExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::VariableExpr(
+				old->location,
+				inCache(old->var) ?
+					dynamic_cast<ast::DeclWithType *>(this->node) :
+					GET_ACCEPT_1(var, DeclWithType)
+			)
+		);
+	}
+
+	bool isIntlikeConstantType(const Type *t) {
+		if ( const BasicType * basicType = dynamic_cast< const BasicType * >( t ) ) {
+			if ( basicType->isInteger() ) {
+				return true;
+			}
+		} else if ( dynamic_cast< const OneType * >( t ) ) {
+			return true;
+		} else if ( dynamic_cast< const ZeroType * >( t ) ) {
+			return true;
+		} else if ( dynamic_cast< const PointerType * >( t ) ) {
+			// null pointer constants, with zero int-values
+			return true;
+		}
+		return false;
+	}
+
+	int isFloatlikeConstantType(const Type *t) {
+		if ( const BasicType * bty = dynamic_cast< const BasicType * >( t ) ) {
+			if ( ! bty->isInteger() ) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	int isStringlikeConstantType(const Type *t) {
+		if ( const ArrayType * aty = dynamic_cast< const ArrayType * >( t ) ) {
+			if ( const BasicType * bty = dynamic_cast< const BasicType * >( aty->base ) ) {
+			   if ( bty->kind == BasicType::Kind::Char ) {
+				   return true;
+			   }
+			}
+		}
+		return false;
+	}
+
+	virtual void visit( ConstantExpr * old ) override final {
+		ast::ConstantExpr *rslt = nullptr;
+		if (isIntlikeConstantType(old->result)) {
+			rslt = new ast::ConstantExpr(
+				old->location,
+				GET_ACCEPT_1(result, Type),
+				old->constant.get_value(),
+				(unsigned long long) old->intValue()
+			);
+		} else if (isFloatlikeConstantType(old->result)) {
+			rslt = new ast::ConstantExpr(
+				old->location,
+				GET_ACCEPT_1(result, Type),
+				old->constant.get_value(),
+				(double) old->constant.get_dval()
+			);
+		} else if (isStringlikeConstantType(old->result)) {
+			rslt = ast::ConstantExpr::from_string(
+				old->location,
+				old->constant.get_value()
+			);
+		}
+		assert(rslt);
+		this->node = visitBaseExpr( old, rslt );
+	}
+
+	virtual void visit( SizeofExpr * old ) override final {
+		assert (old->expr || old->type);
+		assert (! (old->expr && old->type));
+		ast::SizeofExpr *rslt;
+		if (old->expr) {
+			assert(!old->isType);
+			rslt = new ast::SizeofExpr(
+				old->location,
+				GET_ACCEPT_1(expr, Expr)
+			);
+		}
+		if (old->type) {
+			assert(old->isType);
+			rslt = new ast::SizeofExpr(
+				old->location,
+				GET_ACCEPT_1(type, Type)
+			);
+		}
+		this->node = visitBaseExpr( old, rslt );
+	}
+
+	virtual void visit( AlignofExpr * old ) override final {
+		assert (old->expr || old->type);
+		assert (! (old->expr && old->type));
+		ast::AlignofExpr *rslt;
+		if (old->expr) {
+			assert(!old->isType);
+			rslt = new ast::AlignofExpr(
+				old->location,
+				GET_ACCEPT_1(expr, Expr)
+			);
+		}
+		if (old->type) {
+			assert(old->isType);
+			rslt = new ast::AlignofExpr(
+				old->location,
+				GET_ACCEPT_1(type, Type)
+			);
+		}
+		this->node = visitBaseExpr( old, rslt );
+	}
+
+	virtual void visit( UntypedOffsetofExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::UntypedOffsetofExpr(
+				old->location,
+				GET_ACCEPT_1(type, Type),
+				old->member
+			)
+		);
+	}
+
+	virtual void visit( OffsetofExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::OffsetofExpr(
+				old->location,
+				GET_ACCEPT_1(type, Type),
+				inCache(old->member) ?
+					dynamic_cast<ast::DeclWithType *>(this->node) :
+					GET_ACCEPT_1(member, DeclWithType)
+			)
+		);
+	}
+
+	virtual void visit( OffsetPackExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::OffsetPackExpr(
+				old->location,
+				GET_ACCEPT_1(type, StructInstType)
+			)
+		);
+	}
+
+	virtual void visit( LogicalExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::LogicalExpr(
+				old->location,
+				GET_ACCEPT_1(arg1, Expr),
+				GET_ACCEPT_1(arg2, Expr),
+				old->get_isAnd() ?
+					ast::LogicalFlag::AndExpr :
+					ast::LogicalFlag::OrExpr
+			)
+		);
+	}
+
+	virtual void visit( ConditionalExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::ConditionalExpr(
+				old->location,
+				GET_ACCEPT_1(arg1, Expr),
+				GET_ACCEPT_1(arg2, Expr),
+				GET_ACCEPT_1(arg3, Expr)
+			)
+		);
+	}
+
+	virtual void visit( CommaExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::CommaExpr(
+				old->location,
+				GET_ACCEPT_1(arg1, Expr),
+				GET_ACCEPT_1(arg2, Expr)
+			)
+		);
+	}
+
+	virtual void visit( TypeExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::TypeExpr(
+				old->location,
+				GET_ACCEPT_1(type, Type)
+			)
+		);
+	}
+
+	virtual void visit( AsmExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::AsmExpr(
+				old->location,
+				GET_ACCEPT_1(inout, Expr),
+				GET_ACCEPT_1(constraint, Expr),
+				GET_ACCEPT_1(operand, Expr)
+			)
+		);
+	}
+
+	virtual void visit( ImplicitCopyCtorExpr * old ) override final {
+		auto rslt = new ast::ImplicitCopyCtorExpr(
+			old->location,
+			GET_ACCEPT_1(callExpr, ApplicationExpr)
+		);
+
+		this->node = visitBaseExpr( old, rslt );
+	}
+
+	virtual void visit( ConstructorExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::ConstructorExpr(
+				old->location,
+				GET_ACCEPT_1(callExpr, Expr)
+			)
+		);
+	}
+
+	virtual void visit( CompoundLiteralExpr * old ) override final {
+		this->node = visitBaseExpr_SkipResultType( old,
+			new ast::CompoundLiteralExpr(
+				old->location,
+				GET_ACCEPT_1(result, Type),
+				GET_ACCEPT_1(initializer, Init)
+			)
+		);
+	}
+
+	virtual void visit( RangeExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::RangeExpr(
+				old->location,
+				GET_ACCEPT_1(low, Expr),
+				GET_ACCEPT_1(high, Expr)
+			)
+		);
+	}
+
+	virtual void visit( UntypedTupleExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::UntypedTupleExpr(
+				old->location,
+				GET_ACCEPT_V(exprs, Expr)
+			)
+		);
+	}
+
+	virtual void visit( TupleExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::TupleExpr(
+				old->location,
+				GET_ACCEPT_V(exprs, Expr)
+			)
+		);
+	}
+
+	virtual void visit( TupleIndexExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::TupleIndexExpr(
+				old->location,
+				GET_ACCEPT_1(tuple, Expr),
+				old->index
+			)
+		);
+	}
+
+	virtual void visit( TupleAssignExpr * old ) override final {
+		this->node = visitBaseExpr_SkipResultType( old,
+			new ast::TupleAssignExpr(
+				old->location,
+				GET_ACCEPT_1(result, Type),
+				GET_ACCEPT_1(stmtExpr, StmtExpr)
+			)
+		);
+	}
+
+	virtual void visit( StmtExpr * old ) override final {
+		auto rslt = new ast::StmtExpr(
+			old->location,
+			GET_ACCEPT_1(statements, CompoundStmt)
+		);
+		rslt->returnDecls = GET_ACCEPT_V(returnDecls, ObjectDecl);
+		rslt->dtors       = GET_ACCEPT_V(dtors      , Expr);
+
+		this->node = visitBaseExpr_SkipResultType( old, rslt );
+	}
+
+	virtual void visit( UniqueExpr * old ) override final {
+		auto rslt = new ast::UniqueExpr(
+			old->location,
+			GET_ACCEPT_1(expr, Expr)
+		);
+		rslt->object = GET_ACCEPT_1(object, ObjectDecl);
+		rslt->var    = GET_ACCEPT_1(var   , VariableExpr);
+
+		this->node = visitBaseExpr( old, rslt );
+	}
+
+	virtual void visit( UntypedInitExpr * old ) override final {
+		std::vector<ast::InitAlternative> initAlts;
+		for (auto ia : old->initAlts) {
+			initAlts.push_back(ast::InitAlternative(
+				getAccept1< ast::Type, Type * >( ia.type ),
+				getAccept1< ast::Designation, Designation * >( ia.designation )
+			));
+		}
+		this->node = visitBaseExpr( old,
+			new ast::UntypedInitExpr(
+				old->location,
+				GET_ACCEPT_1(expr, Expr),
+				std::move(initAlts)
+			)
+		);
+	}
+
+	virtual void visit( InitExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::InitExpr(
+				old->location,
+				GET_ACCEPT_1(expr, Expr),
+				GET_ACCEPT_1(designation, Designation)
+			)
+		);
+	}
+
+	virtual void visit( DeletedExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::DeletedExpr(
+				old->location,
+				GET_ACCEPT_1(expr, Expr),
+				inCache(old->deleteStmt) ?
+					this->node :
+					GET_ACCEPT_1(deleteStmt, Node)
+			)
+		);
+	}
+
+	virtual void visit( DefaultArgExpr * old ) override final {
+		this->node = visitBaseExpr( old,
+			new ast::DefaultArgExpr(
+				old->location,
+				GET_ACCEPT_1(expr, Expr)
+			)
+		);
+	}
+
+	virtual void visit( GenericExpr * old ) override final {
+		std::vector<ast::GenericExpr::Association> associations;
+		for (auto association : old->associations) {
+			associations.push_back(ast::GenericExpr::Association(
+				getAccept1< ast::Type, Type * >( association.type ),
+				getAccept1< ast::Expr, Expression * >( association.expr )
+			));
+		}
+		this->node = visitBaseExpr( old,
+			new ast::GenericExpr(
+				old->location,
+				GET_ACCEPT_1(control, Expr),
+				std::move(associations)
+			)
+		);
+	}
+
+	virtual void visit( VoidType * old ) override final {
+		this->node = new ast::VoidType{ cv( old ) };
+	}
+
+	virtual void visit( BasicType * old ) override final {
+		this->node = new ast::BasicType{ (ast::BasicType::Kind)(unsigned)old->kind, cv( old ) };
+	}
+
+	virtual void visit( PointerType * old ) override final {
+		this->node = new ast::PointerType{
+			GET_ACCEPT_1( base, Type ),
+			GET_ACCEPT_1( dimension, Expr ),
+			(ast::LengthFlag)old->isVarLen,
+			(ast::DimensionFlag)old->isStatic,
+			cv( old )
+		};
+	}
+
+	virtual void visit( ArrayType * old ) override final {
+		this->node = new ast::ArrayType{
+			GET_ACCEPT_1( base, Type ),
+			GET_ACCEPT_1( dimension, Expr ),
+			(ast::LengthFlag)old->isVarLen,
+			(ast::DimensionFlag)old->isStatic,
+			cv( old )
+		};
+	}
+
+	virtual void visit( ReferenceType * old ) override final {
+		this->node = new ast::ReferenceType{
+			GET_ACCEPT_1( base, Type ),
+			cv( old )
+		};
+	}
+
+	virtual void visit( QualifiedType * old ) override final {
+		this->node = new ast::QualifiedType{
+			GET_ACCEPT_1( parent, Type ),
+			GET_ACCEPT_1( child, Type ),
+			cv( old )
+		};
+	}
+
+	virtual void visit( FunctionType * old ) override final {
+		auto ty = new ast::FunctionType {
+			(ast::ArgumentFlag)old->isVarArgs,
+			cv( old )
+		};
+		ty->returns = GET_ACCEPT_V( returnVals, DeclWithType );
+		ty->params = GET_ACCEPT_V( parameters, DeclWithType );
+		ty->forall = GET_ACCEPT_V( forall, TypeDecl );
+		this->node = ty;
+	}
+
+	void postvisit( ReferenceToType * old, ast::ReferenceToType * ty ) {
+		ty->forall = GET_ACCEPT_V( forall, TypeDecl );
+		ty->params = GET_ACCEPT_V( parameters, Expr );
+		ty->hoistType = old->hoistType;
+	}
+
+	virtual void visit( StructInstType * old ) override final {
+		ast::StructInstType * ty;
+		if ( old->baseStruct ) {
+			ty = new ast::StructInstType{
+				GET_ACCEPT_1( baseStruct, StructDecl ),
+				cv( old ),
+				GET_ACCEPT_V( attributes, Attribute )
+			};
+		} else {
+			ty = new ast::StructInstType{
+				old->name,
+				cv( old ),
+				GET_ACCEPT_V( attributes, Attribute )
+			};
+		}
+		postvisit( old, ty );
+		this->node = ty;
+	}
+
+	virtual void visit( UnionInstType * old ) override final {
+		ast::UnionInstType * ty;
+		if ( old->baseUnion ) {
+			ty = new ast::UnionInstType{
+				GET_ACCEPT_1( baseUnion, UnionDecl ),
+				cv( old ),
+				GET_ACCEPT_V( attributes, Attribute )
+			};
+		} else {
+			ty = new ast::UnionInstType{
+				old->name,
+				cv( old ),
+				GET_ACCEPT_V( attributes, Attribute )
+			};
+		}
+		postvisit( old, ty );
+		this->node = ty;
+	}
+
+	virtual void visit( EnumInstType * old ) override final {
+		ast::EnumInstType * ty;
+		if ( old->baseEnum ) {
+			ty = new ast::EnumInstType{
+				GET_ACCEPT_1( baseEnum, EnumDecl ),
+				cv( old ),
+				GET_ACCEPT_V( attributes, Attribute )
+			};
+		} else {
+			ty = new ast::EnumInstType{
+				old->name,
+				cv( old ),
+				GET_ACCEPT_V( attributes, Attribute )
+			};
+		}
+		postvisit( old, ty );
+		this->node = ty;
+	}
+
+	virtual void visit( TraitInstType * old ) override final {
+		ast::TraitInstType * ty;
+		if ( old->baseTrait ) {
+			ty = new ast::TraitInstType{
+				GET_ACCEPT_1( baseTrait, TraitDecl ),
+				cv( old ),
+				GET_ACCEPT_V( attributes, Attribute )
+			};
+		} else {
+			ty = new ast::TraitInstType{
+				old->name,
+				cv( old ),
+				GET_ACCEPT_V( attributes, Attribute )
+			};
+		}
+		postvisit( old, ty );
+		this->node = ty;
+	}
+
+	virtual void visit( TypeInstType * old ) override final {
+		ast::TypeInstType * ty;
+		if ( old->baseType ) {
+			ty = new ast::TypeInstType{
+				old->name,
+				GET_ACCEPT_1( baseType, TypeDecl ),
+				cv( old ),
+				GET_ACCEPT_V( attributes, Attribute )
+			};
+		} else {
+			ty = new ast::TypeInstType{
+				old->name,
+				old->isFtype ? ast::TypeVar::Ftype : ast::TypeVar::Dtype,
+				cv( old ),
+				GET_ACCEPT_V( attributes, Attribute )
+			};
+		}
+		postvisit( old, ty );
+		this->node = ty;
+	}
+
+	virtual void visit( TupleType * old ) override final {
+		this->node = new ast::TupleType{
+			GET_ACCEPT_V( types, Type ),
+			// members generated by TupleType c'tor
+			cv( old )
+		};
+	}
+
+	virtual void visit( TypeofType * old ) override final {
+		this->node = new ast::TypeofType{
+			GET_ACCEPT_1( expr, Expr ),
+			(ast::TypeofType::Kind)old->is_basetypeof,
+			cv( old )
+		};
 	}
 
 	virtual void visit( AttrType * ) override final {
-
-	}
-
-	virtual void visit( VarArgsType * ) override final {
-
-	}
-
-	virtual void visit( ZeroType * ) override final {
-
-	}
-
-	virtual void visit( OneType * ) override final {
-
+		assertf( false, "AttrType deprecated in new AST." );
+	}
+
+	virtual void visit( VarArgsType * old ) override final {
+		this->node = new ast::VarArgsType{ cv( old ) };
+	}
+
+	virtual void visit( ZeroType * old ) override final {
+		this->node = new ast::ZeroType{ cv( old ) };
+	}
+
+	virtual void visit( OneType * old ) override final {
+		this->node = new ast::OneType{ cv( old ) };
 	}
 
 	virtual void visit( GlobalScopeType * ) override final {
-
-	}
-
-	virtual void visit( Designation * ) override final {
-
-	}
-
-	virtual void visit( SingleInit * ) override final {
-
-	}
-
-	virtual void visit( ListInit * ) override final {
-
-	}
-
-	virtual void visit( ConstructorInit * ) override final {
-
+		this->node = new ast::GlobalScopeType{};
+	}
+
+	virtual void visit( Designation * old ) override final {
+		this->node = new ast::Designation(
+			old->location,
+			GET_ACCEPT_V(designators, Expr)
+		);
+	}
+
+	virtual void visit( SingleInit * old ) override final {
+		this->node = new ast::SingleInit(
+			old->location,
+			GET_ACCEPT_1(value, Expr),
+			(old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::DoConstruct
+		);
+	}
+
+	virtual void visit( ListInit * old ) override final {
+		this->node = new ast::ListInit(
+			old->location,
+			GET_ACCEPT_V(initializers, Init),
+			GET_ACCEPT_V(designations, Designation),
+			(old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::DoConstruct
+		);
+	}
+
+	virtual void visit( ConstructorInit * old ) override final {
+		this->node = new ast::ConstructorInit(
+			old->location,
+			GET_ACCEPT_1(ctor, Stmt),
+			GET_ACCEPT_1(dtor, Stmt),
+			GET_ACCEPT_1(init, Init)
+		);
 	}
 
 	virtual void visit( Constant * ) override final {
-
-	}
-
-	virtual void visit( Attribute * ) override final {
-
+		// Handled in visit( ConstantEpxr * ).
+		// In the new tree, Constant fields are inlined into containing ConstantExpression.
+		assert( 0 );
+	}
+
+	virtual void visit( Attribute * old ) override final {
+		this->node = new ast::Attribute(
+			old->name,
+			GET_ACCEPT_V( parameters, Expr )
+		);
 	}
 
 	virtual void visit( AttrExpr * ) override final {
-
-		assert( 0 );
+		assertf( false, "AttrExpr deprecated in new AST." );
 	}
 };
@@ -1475,6 +2669,6 @@
 		d->accept( c );
 		decls.emplace_back( c.decl() );
-		delete d;
-	}
+	}
+	deleteAll(translationUnit);
 	return decls;
 }
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Decl.cpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -72,8 +72,8 @@
 // --- EnumDecl
 
-bool EnumDecl::valueOf( Decl* enumerator, long long& value ) const {
+bool EnumDecl::valueOf( const Decl * enumerator, long long& value ) const {
 	if ( enumValues.empty() ) {
 		long long crntVal = 0;
-		for ( const Decl* member : members ) {
+		for ( const Decl * member : members ) {
 			const ObjectDecl* field = strict_dynamic_cast< const ObjectDecl* >( member );
 			if ( field->init ) {
@@ -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 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Decl.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -232,11 +232,10 @@
 	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
 	virtual std::string typeString() const = 0;
+
+private:
+	AggregateDecl * clone() const override = 0;
+	MUTATE_FRIEND
 };
 
@@ -256,9 +255,10 @@
 
 	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+
+	std::string typeString() const override { return "struct"; }
+
 private:
 	StructDecl * clone() const override { return new StructDecl{ *this }; }
 	MUTATE_FRIEND
-
-	std::string typeString() const override { return "struct"; }
 };
 
@@ -271,9 +271,10 @@
 
 	const Decl * accept( Visitor& v ) const override { return v.visit( this ); }
+
+	std::string typeString() const override { return "union"; }
+
 private:
 	UnionDecl * clone() const override { return new UnionDecl{ *this }; }
 	MUTATE_FRIEND
-
-	std::string typeString() const override { return "union"; }
 };
 
@@ -286,12 +287,13 @@
 
 	/// gets the integer value for this enumerator, returning true iff value found
-	bool valueOf( Decl* enumerator, long long& value ) const;
-
-	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+	bool valueOf( const Decl * enumerator, long long& value ) const;
+
+	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+
+	std::string typeString() const override { return "enum"; }
+
 private:
 	EnumDecl * clone() const override { return new EnumDecl{ *this }; }
 	MUTATE_FRIEND
-
-	std::string typeString() const override { return "enum"; }
 
 	/// Map from names to enumerator values; kept private for lazy initialization
@@ -307,9 +309,10 @@
 
 	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+
+	std::string typeString() const override { return "trait"; }
+
 private:
 	TraitDecl * clone() const override { return new TraitDecl{ *this }; }
 	MUTATE_FRIEND
-
-	std::string typeString() const override { return "trait"; }
 };
 
@@ -329,9 +332,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/DeclReplacer.cpp
===================================================================
--- src/AST/DeclReplacer.cpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/DeclReplacer.cpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -14,5 +14,82 @@
 //
 
-#warning unimplemented
+#include "DeclReplacer.hpp"
+#include "Expr.hpp"
+#include "Type.hpp"
+
+#include "Pass.hpp"
+
+namespace ast {
+
+namespace DeclReplacer {
+	namespace {
+		struct DeclReplacer {
+		private:
+			const DeclMap & declMap;
+			const TypeMap & typeMap;
+			bool debug;
+
+		public:
+			DeclReplacer(const DeclMap & declMap, const TypeMap & typeMap, bool debug)
+				: declMap( declMap ), typeMap( typeMap ), debug( debug )
+			{}
+
+			const ast::VariableExpr * previsit( const ast::VariableExpr * );
+			const ast::TypeInstType * previsit( const ast::TypeInstType * );
+		};
+	}
+
+	const ast::Node * replace( const ast::Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug ) {
+		if(!node) return nullptr;
+		Pass<DeclReplacer> replacer = { declMap, typeMap, debug };
+		return node->accept( replacer );
+	}
+
+	const ast::Node * replace( const ast::Node * node, const DeclMap & declMap, bool debug ) {
+		TypeMap typeMap;
+		return replace( node, declMap, typeMap, debug );
+	}
+
+	const ast::Node * replace( const ast::Node * node, const TypeMap & typeMap, bool debug ) {
+		DeclMap declMap;
+		return replace( node, declMap, typeMap, debug );
+	}
+
+	namespace {
+		// replace variable with new node from decl map
+		const ast::VariableExpr * DeclReplacer::previsit( const VariableExpr * varExpr ) {
+			// xxx - assertions and parameters aren't accounted for in this... (i.e. they aren't inserted into the map when it's made, only DeclStmts are)
+			if ( !declMap.count( varExpr->var ) ) return varExpr;
+
+			auto replacement = declMap.at( varExpr->var );
+			if ( debug ) {
+				std::cerr << "replacing variable reference: "
+					<< (void*)varExpr->var.get() << " " << varExpr->var
+					<< " with " << (void*)replacement << " " << replacement
+					<< std::endl;
+			}
+			auto nexpr = mutate(varExpr);
+			nexpr->var = replacement;
+			return nexpr;
+		}
+
+		const TypeInstType * DeclReplacer::previsit( const TypeInstType * inst ) {
+			if ( !typeMap.count( inst->base ) ) return inst;
+
+			auto replacement = typeMap.at( inst->base );
+			if ( debug ) {
+				std::cerr << "replacing type reference: "
+					<< (void*)inst->base.get() << " " << inst->base
+					<< " with " << (void*)replacement << " " << replacement
+					<< std::endl;
+			}
+			auto ninst = mutate(inst);
+			ninst->base = replacement;
+			return ninst;
+		}
+	}
+}
+
+}
 
 // Local Variables: //
Index: src/AST/DeclReplacer.hpp
===================================================================
--- src/AST/DeclReplacer.hpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/DeclReplacer.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -25,10 +25,10 @@
 
 	namespace DeclReplacer {
-		using DeclMap = std::unordered_map< DeclWithType*, DeclWithType* >;
-		using TypeMap = std::unordered_map< TypeDecl*, TypeDecl* >;
+		using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >;
+		using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >;
 
-		void replace( Node* node, const DeclMap& declMap );
-		void replace( Node* node, const TypeMap& typeMap );
-		void replace( Node* node, const DeclMap& declMap, const TypeMap& typeMap );
+		const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false );
+		const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false );
+		const Node * replace( const Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false );
 	}
 }
Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Expr.cpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -20,6 +20,9 @@
 #include <vector>
 
+#include "GenericSubstitution.hpp"
 #include "Stmt.hpp"
 #include "Type.hpp"
+#include "TypeSubstitution.hpp"
+#include "Common/utility.h"
 #include "Common/SemanticError.h"
 #include "GenPoly/Lvalue.h"        // for referencesPermissable
@@ -156,5 +159,10 @@
 	assert( aggregate->result );
 
-	assert(!"unimplemented; need TypeSubstitution, genericSubstitution");
+	// take ownership of member type
+	result = mem->get_type();
+	// substitute aggregate generic parameters into member type
+	genericSubsitution( aggregate->result ).apply( result );
+	// ensure lvalue and appropriate restrictions from aggregate type
+	result.get_and_mutate()->qualifiers |= aggregate->result->qualifiers | CV::Lvalue;
 }
 
@@ -233,5 +241,6 @@
 			FixedLen, DynamicDim },
 		std::string{"\""} + s + "\"",
-		(unsigned long long)0 };
+		(unsigned long long)0,
+		ConstantExpr::String };
 }
 
@@ -332,4 +341,10 @@
 	stmts.emplace_back( new ExprStmt{ loc, tupleExpr } );
 	stmtExpr = new StmtExpr{ loc, new CompoundStmt{ loc, std::move(stmts) } };
+}
+
+TupleAssignExpr::TupleAssignExpr(
+	const CodeLocation & loc, const Type * result, const StmtExpr * s )
+: Expr( loc, result ), stmtExpr() {
+	stmtExpr = s;
 }
 
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Expr.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -30,4 +30,6 @@
 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
 
+class ConverterOldToNew;
+
 namespace ast {
 
@@ -106,4 +108,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 +125,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);
 		}
 	};
@@ -317,10 +337,12 @@
 public:
 	std::string rep;
+	enum Kind { Integer, FloatingPoint, String } kind;
 
 	ConstantExpr(
-		const CodeLocation & loc, const Type * ty, const std::string & r, unsigned long long v )
-	: Expr( loc, ty ), val( v ), rep( r ) {}
+		const CodeLocation & loc, const Type * ty, const std::string & r, unsigned long long v,
+		Kind k = Integer )
+	: Expr( loc, ty ), val( v ), rep( r ), kind( k ) {}
 	ConstantExpr( const CodeLocation & loc, const Type * ty, const std::string & r, double v )
-	: Expr( loc, ty ), val( v ), rep( r ) {}
+	: Expr( loc, ty ), val( v ), rep( r ), kind( FloatingPoint ) {}
 
 	/// Gets the value of this constant as an integer
@@ -503,15 +525,12 @@
 };
 
-/// 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 {
 public:
 	ptr<ApplicationExpr> callExpr;
-	std::vector<ptr<ObjectDecl>> tempDecls;
-	std::vector<ptr<ObjectDecl>> returnDecls;
-	std::vector<ptr<ObjectDecl>> dtors;
 
 	ImplicitCopyCtorExpr( const CodeLocation& loc, const ApplicationExpr * call )
-	: Expr( loc, call->result ), tempDecls(), returnDecls(), dtors() { assert( call ); }
+	: Expr( loc, call->result ) { assert( call ); }
 
 	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
@@ -603,6 +622,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,11 +631,16 @@
 	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 ); }
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+
+	friend class ::ConverterOldToNew;
+
 private:
 	TupleAssignExpr * clone() const override { return new TupleAssignExpr{ *this }; }
+    TupleAssignExpr( const CodeLocation & loc, const Type * result, const StmtExpr * s );
+
 	MUTATE_FRIEND
 };
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Fwd.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -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/GenericSubstitution.cpp
===================================================================
--- src/AST/GenericSubstitution.cpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
+++ src/AST/GenericSubstitution.cpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -0,0 +1,63 @@
+//
+// 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.
+//
+// GenericSubstitution.cpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Wed May 22 14:15:00 2019
+// Last Modified By : Aaron B. Moss
+// Created On       : Wed May 22 14:15:00 2019
+// Update Count     : 1
+//
+
+#include "GenericSubstitution.hpp"
+
+#include <cassert>
+#include <utility>               // for move
+
+#include "Decl.hpp"
+#include "Node.hpp"              // for maybe_accept
+#include "Pass.hpp"
+#include "Type.hpp"
+#include "TypeSubstitution.hpp"
+
+namespace ast {
+
+namespace {
+	struct GenericSubstitutionBuilder : public WithShortCircuiting {
+		TypeSubstitution sub;
+
+		void previsit( const Type * ty ) {
+			assertf( false, "Attempted generic substitution for non-aggregate type: %s",
+				toString( ty ).c_str() );
+		}
+
+		void previsit( const ReferenceType * ) {
+			// do nothing; allows substitution from base type
+		}
+
+		void previsit( const ReferenceToType * ty ) {
+			visit_children = false;
+			// build substitution from base parameters
+			const AggregateDecl * aggr = ty->aggr();
+			sub = TypeSubstitution{ aggr->params.begin(), aggr->params.end(), ty->params.begin() };
+		}
+	};
+}
+
+TypeSubstitution genericSubsitution( const Type * ty ) {
+	Pass<GenericSubstitutionBuilder> builder;
+	maybe_accept( ty, builder );
+	return std::move(builder.pass.sub);
+}
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/GenericSubstitution.hpp
===================================================================
--- src/AST/GenericSubstitution.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
+++ src/AST/GenericSubstitution.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -0,0 +1,32 @@
+//
+// 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.
+//
+// GenericSubstitution.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Wed May 22 14:15:00 2019
+// Last Modified By : Aaron B. Moss
+// Created On       : Wed May 22 14:15:00 2019
+// Update Count     : 1
+//
+
+#pragma once
+
+#include "TypeSubstitution.hpp"
+
+namespace ast {
+
+class Type;
+
+TypeSubstitution genericSubsitution( const Type * );
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/Label.hpp
===================================================================
--- src/AST/Label.hpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Label.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -39,5 +39,5 @@
 
 	operator std::string () const { return name; }
-	bool empty() { return name.empty(); }
+	bool empty() const { return name.empty(); }
 };
 
Index: src/AST/Node.cpp
===================================================================
--- src/AST/Node.cpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Node.cpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -16,4 +16,6 @@
 #include "Node.hpp"
 #include "Fwd.hpp"
+
+#include <iostream>
 
 #include "Attribute.hpp"
@@ -25,4 +27,6 @@
 #include "TypeSubstitution.hpp"
 
+#include "Print.hpp"
+
 template< typename node_t, enum ast::Node::ref_type ref_t >
 void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { node->increment(ref_t); }
@@ -31,10 +35,6 @@
 void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node ) { node->decrement(ref_t); }
 
-/// Sets this pointer to a mutated version of a pointer (possibly) owned elsehere.
-/// Returns a mutable version of the pointer in this node.
-template< typename node_t, enum ast::Node::ref_type ref_t >
-node_t * ast::ptr_base<node_t, ref_t>::set_and_mutate( const node_t * n ) {
-	// ensure ownership of `n` by this node to avoid spurious single-owner mutates
-	assign( n );
+template< typename node_t, enum ast::Node::ref_type ref_t >
+node_t * ast::ptr_base<node_t, ref_t>::get_and_mutate() {
 	// get mutable version of `n`
 	auto r = mutate( node );
@@ -42,4 +42,17 @@
 	assign( r );
 	return r;
+}
+
+template< typename node_t, enum ast::Node::ref_type ref_t >
+node_t * ast::ptr_base<node_t, ref_t>::set_and_mutate( const node_t * n ) {
+	// ensure ownership of `n` by this node to avoid spurious single-owner mutates
+	assign( n );
+	// return mutable version
+	return get_and_mutate();
+}
+
+std::ostream & ast::operator<< ( std::ostream & out, const ast::Node * node ) {
+	print(out, node);
+	return out;
 }
 
Index: src/AST/Node.hpp
===================================================================
--- src/AST/Node.hpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Node.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 8 10:27:04 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed May 15 16:02:00 2019
-// Update Count     : 3
+// Last Modified On : Thu May 23 16:00:00 2019
+// Update Count     : 4
 //
 
@@ -94,4 +94,10 @@
 std::ostream& operator<< ( std::ostream& out, const Node * node );
 
+/// Call a visitor on a possibly-null node
+template<typename node_t>
+auto maybe_accept( const node_t * n, Visitor & v ) -> decltype( n->accept(v) ) {
+	return n ? n->accept( v ) : nullptr;
+}
+
 /// Base class for the smart pointer types
 /// should never really be used.
@@ -103,4 +109,12 @@
 	~ptr_base() { if( node ) _dec(node); }
 
+	ptr_base( const ptr_base & o ) : node(o.node) {
+		if( node ) _inc(node);
+	}
+
+	ptr_base( ptr_base && o ) : node(o.node) {
+		if( node ) _inc(node);
+	}
+
 	template< enum Node::ref_type o_ref_t >
 	ptr_base( const ptr_base<node_t, o_ref_t> & o ) : node(o.node) {
@@ -115,5 +129,15 @@
 	template<typename o_node_t>
 	ptr_base & operator=( const o_node_t * node ) {
-		assign(strict_dynamic_cast<const node_t *>(node));
+		assign( node ? strict_dynamic_cast<const node_t *>(node) : nullptr );
+		return *this;
+	}
+
+	ptr_base & operator=( const ptr_base & o ) {
+		assign(o.node);
+		return *this;
+	}
+
+	ptr_base & operator=( ptr_base && o ) {
+		assign(o.node);
 		return *this;
 	}
@@ -141,4 +165,7 @@
 	const o_node_t * as() const { return dynamic_cast<const o_node_t *>(node); }
 
+	/// Returns a mutable version of the pointer in this node.
+	node_t * get_and_mutate();
+
 	/// Sets this pointer to a mutated version of a pointer (possibly) owned elsehere.
 	/// Returns a mutable version of the pointer in this node.
Index: src/AST/Pass.cpp
===================================================================
--- src/AST/Pass.cpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
+++ src/AST/Pass.cpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -0,0 +1,23 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Pass.cpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Wed May 22 15:00:33 2019
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#include "Pass.hpp"
+
+namespace ast {
+
+PassVisitorStats pass_visitor_stats;
+// Stats::Counters::SimpleCounter * BaseSyntaxNode::new_nodes = nullptr;
+
+};
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Pass.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -178,5 +178,6 @@
 	const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) override final;
 
-	friend void acceptAll( std::list< ptr<Decl> > & decls, Pass<pass_t>& visitor );
+	template<typename pass_type>
+	friend void acceptAll( std::list< ptr<Decl> > & decls, Pass<pass_type>& visitor );
 private:
 
@@ -223,4 +224,5 @@
 };
 
+/// Apply a pass to an entire translation unit
 template<typename pass_t>
 void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<pass_t> & visitor );
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Pass.impl.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -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 ) {
+
+			const 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;
+			}
+
+			const Stmt * stmt = clause.stmt ? clause.stmt->accept(*this) : nullptr;
+			if(stmt != clause.stmt) mutated = true;
+
+			const 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,885 @@
 }
 
-
-
-
-
+//--------------------------------------------------------------------------
+// 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    );
+	)
+
+	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 ) {
+			const Type * type = nullptr;
+			if( assoc.type ) {
+				guard_indexer guard { *this };
+				type = assoc.type->accept( *this );
+				if( type != assoc.type ) mutated = true;
+			}
+			const 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( pass, 0, node->name );
+
+	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( pass, 0, node->name );
+
+	{
+		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 );
+}
 
 //--------------------------------------------------------------------------
@@ -964,5 +1876,5 @@
 
 	VISIT(
-		maybe_accept( node, &Attribute::parameters );
+		maybe_accept( node, &Attribute::params );
 	)
 
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Pass.proto.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -107,4 +107,60 @@
 		bool     * m_prev;
 		bool_ref * m_ref;
+	};
+
+	/// "Short hand" to check if this is a valid previsit function
+	/// Mostly used to make the static_assert look (and print) prettier
+	template<typename pass_t, typename node_t>
+	struct is_valid_previsit {
+		using ret_t = decltype( ((pass_t*)nullptr)->previsit( (const node_t *)nullptr ) );
+
+		static constexpr bool value = std::is_void< ret_t >::value ||
+			std::is_base_of<const node_t, typename std::remove_pointer<ret_t>::type >::value;
+	};
+
+	/// Used by previsit implementation
+	/// We need to reassign the result to 'node', unless the function
+	/// returns void, then we just leave 'node' unchanged
+	template<bool is_void>
+	struct __assign;
+
+	template<>
+	struct __assign<true> {
+		template<typename pass_t, typename node_t>
+		static inline void result( pass_t & pass, const node_t * & node ) {
+			pass.previsit( node );
+		}
+	};
+
+	template<>
+	struct __assign<false> {
+		template<typename pass_t, typename node_t>
+		static inline void result( pass_t & pass, const node_t * & node ) {
+			node = pass.previsit( node );
+			assertf(node, "Previsit must not return NULL");
+		}
+	};
+
+	/// Used by postvisit implementation
+	/// We need to return the result unless the function
+	/// returns void, then we just return the original node
+	template<bool is_void>
+	struct __return;
+
+	template<>
+	struct __return<true> {
+		template<typename pass_t, typename node_t>
+		static inline const node_t * result( pass_t & pass, const node_t * & node ) {
+			pass.postvisit( node );
+			return node;
+		}
+	};
+
+	template<>
+	struct __return<false> {
+		template<typename pass_t, typename node_t>
+		static inline auto result( pass_t & pass, const node_t * & node ) {
+			return pass.postvisit( node );
+		}
 	};
 
@@ -126,6 +182,14 @@
 	template<typename pass_t, typename node_t>
 	static inline auto previsit( pass_t & pass, const node_t * & node, int ) -> decltype( pass.previsit( node ), void() ) {
-		node = pass.previsit( node );
-		assert(node);
+		static_assert(
+			is_valid_previsit<pass_t, node_t>::value,
+			"Previsit may not change the type of the node. It must return its paremeter or void."
+		);
+
+		__assign<
+			std::is_void<
+				decltype( pass.previsit( node ) )
+			>::value
+		>::result( pass, node );
 	}
 
@@ -135,6 +199,12 @@
 	// PostVisit : never mutates the passed pointer but may return a different node
 	template<typename pass_t, typename node_t>
-	static inline auto postvisit( pass_t & pass, const node_t * node, int ) -> decltype( pass.postvisit( node ), (const node_t *)nullptr ) {
-		return pass.postvisit( node );
+	static inline auto postvisit( pass_t & pass, const node_t * node, int ) ->
+		decltype( pass.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
+	{
+		return __return<
+			std::is_void<
+				decltype( pass.postvisit( node ) )
+			>::value
+		>::result( pass, node );
 	}
 
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
+++ src/AST/Print.cpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -0,0 +1,1384 @@
+//
+// 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.
+//
+// Print.cpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Tue May 21 16:20:15 2019
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#include "Print.hpp"
+
+#include "Decl.hpp"
+#include "Expr.hpp"
+#include "Stmt.hpp"
+#include "Type.hpp"
+#include "TypeSubstitution.hpp"
+
+#include "Common/utility.h" // for group_iterate
+
+using namespace std;
+
+namespace ast {
+
+template <typename C, typename... T>
+constexpr auto make_array(T&&... values) ->
+	array<C,sizeof...(T)>
+{
+	return array<C,sizeof...(T)>{
+		forward<T>(values)...
+	};
+}
+
+class Printer : public Visitor {
+public:
+	ostream & os;
+	Indenter indent;
+	bool short_mode;
+
+	Printer(ostream & os, Indenter indent, bool short_mode) : os( os ), indent( indent ), short_mode(short_mode) {}
+
+private:
+	template< typename C >
+	void printAll( const C & c ) {
+		for ( const auto & i : c ) {
+			if ( i ) {
+				os << indent;
+				i->accept( *this );
+				// need an endl after each element because it's not
+				// easy to know when each individual item should end
+				os << endl;
+			} // if
+		} // for
+	}
+
+	/// call if mandatory field is missing
+	void undefined() {
+		os << "UNDEFINED";
+	}
+
+	/// call for fields that should be mandatory
+	void safe_print( const ast::Node * n ) {
+		if ( n ) n->accept( *this );
+		else undefined();
+	}
+
+	/// call to print short form. Incorporates features of safe_print()
+	void short_print( const ast::Node * n ) {
+		if ( ! n ) { undefined(); return; }
+		bool old_short = short_mode; short_mode = true;
+		n->accept( *this );
+		short_mode = old_short;
+	}
+
+
+	static const char* Names[];
+
+	struct Names {
+		static constexpr auto FuncSpecifiers = make_array<const char*>(
+			"inline", "_Noreturn", "fortran"
+		);
+
+		static constexpr auto StorageClasses = make_array<const char*>(
+			"extern", "static", "auto", "register", "_Thread_local"
+		);
+
+		static constexpr auto Qualifiers = make_array<const char*>(
+			"const", "restrict", "volatile", "lvalue", "mutex", "_Atomic"
+		);
+	};
+
+	template<typename storage_t, size_t N>
+	void print(const storage_t & storage, const array<const char *, N> & Names ) {
+		if ( storage.any() ) {
+			for ( size_t i = 0; i < Names.size(); i += 1 ) {
+				if ( storage[i] ) {
+					os << Names[i] << ' ';
+				}
+			}
+		}
+	}
+
+	void print( const ast::Function::Specs & specs ) {
+		print(specs, Names::FuncSpecifiers);
+	}
+
+	void print( const ast::Storage::Classes & storage ) {
+		print(storage, Names::StorageClasses);
+	}
+
+	void print( const ast::CV::Qualifiers & qualifiers ) {
+		print(qualifiers, Names::Qualifiers);
+	}
+
+	void print( const std::vector<ast::Label> & labels ) {
+		if ( labels.empty() ) return;
+		os << indent << "... Labels: {";
+		bool isFirst = true;
+		for ( const Label & l : labels ) {
+			if ( isFirst ) { isFirst = false; } else { os << ","; }
+			os << l;
+		}
+		os << "}" << endl;
+	}
+
+	void print( const ast::Expr::InferUnion & inferred, unsigned level = 0 ) {
+		switch ( inferred.mode ) {
+		case ast::Expr::InferUnion::Empty: return;
+		case ast::Expr::InferUnion::Slots: {
+			os << indent << "with " << inferred.data.resnSlots.size()
+			   << " pending inference slots" << endl;
+			return;
+		}
+		case ast::Expr::InferUnion::Params: {
+			os << indent << "with inferred parameters " << level << ":" << endl;
+			++indent;
+			for ( const auto & i : inferred.data.inferParams ) {
+				os << indent;
+				short_print( Decl::fromId( i.second.decl ) );
+				os << endl;
+				print( i.second.expr->inferred, level+1 );
+			}
+			--indent;
+			return;
+		}
+		}
+	}
+
+	void print( const ast::ParameterizedType::ForallList & forall ) {
+		if ( forall.empty() ) return;
+		os << "forall" << endl;
+		++indent;
+		printAll( forall );
+		os << indent;
+		--indent;
+	}
+
+	void print( const std::vector<ptr<Attribute>> & attrs ) {
+		if ( attrs.empty() ) return;
+		os << "with attributes" << endl;
+		++indent;
+		printAll( attrs );
+		--indent;
+	}
+
+	void print( const std::vector<ptr<Expr>> & params ) {
+		if ( params.empty() ) return;
+		os << endl << indent << "... with parameters" << endl;
+		++indent;
+		printAll( params );
+		--indent;
+	}
+
+	void print( const ast::AggregateDecl * node ) {
+		os << node->typeString() << " " << node->name << ":";
+		if ( node->linkage != Linkage::Cforall ) {
+			os << " " << Linkage::name( node->linkage );
+		} // if
+		os << " with body : " << (node->body ? "yes " : "no ");
+
+		if ( ! node->params.empty() ) {
+			os << endl << indent << "... with parameters" << endl;
+			++indent;
+			printAll( node->params );
+			--indent;
+		} // if
+		if ( ! node->members.empty() ) {
+			os << endl << indent << "... with members" << endl;
+			++indent;
+			printAll( node->members );
+			--indent;
+		} // if
+		if ( ! node->attributes.empty() ) {
+			os << endl << indent << "... with attributes" << endl;
+			++indent;
+			printAll( node->attributes );
+			--indent;
+		} // if
+		os << endl;
+	}
+
+	void print( const ast::NamedTypeDecl * node ) {
+		if ( !node->name.empty() ) os << node->name << ": ";
+
+		if ( node->linkage != Linkage::Cforall ) {
+			os << Linkage::name( node->linkage ) << " ";
+		} // if
+		print( node->storage );
+		os << node->typeString();
+		if ( node->base ) {
+			os << " for ";
+			++indent;
+			node->base->accept( *this );
+			--indent;
+		} // if
+		if ( ! node->params.empty() ) {
+			os << endl << indent << "... with parameters" << endl;
+			++indent;
+			printAll( node->params );
+			--indent;
+		} // if
+		if ( ! node->assertions.empty() ) {
+			os << endl << indent << "... with assertions" << endl;
+			++indent;
+			printAll( node->assertions );
+			--indent;
+		} // if
+	}
+
+	void postprint( const ast::Expr * node ) {
+		print( node->inferred );
+
+		if ( node->env ) {
+			os << endl << indent << "... with environment:" << endl;
+			++indent;
+			node->env->accept( *this );
+			--indent;
+		}
+
+		if ( node->extension ) {
+			os << endl << indent << "... with extension";
+		}
+	}
+
+	void preprint( const ast::Type * node ) {
+		print( node->qualifiers );
+	}
+
+	void preprint( const ast::ParameterizedType * node ) {
+		print( node->forall );
+		print( node->qualifiers );
+	}
+
+	void preprint( const ast::ReferenceToType * node ) {
+		print( node->forall );
+		print( node->attributes );
+		print( node->qualifiers );
+	}
+
+public:
+	virtual const ast::DeclWithType * visit( const ast::ObjectDecl * node ) {
+		if ( !node->name.empty() ) os << node->name << ": ";
+
+		if ( node->linkage != Linkage::Cforall ) {
+			os << Linkage::name( node->linkage ) << " ";
+		} // if
+
+		print( node->storage );
+
+		if ( node->type ) {
+			node->type->accept( *this );
+		} else {
+			os << "untyped entity";
+		} // if
+
+		if ( node->init ) {
+			os << " with initializer (" << (
+				node->init->maybeConstructed
+					? "maybe constructed"
+					: "not constructed"
+				) << ")" << endl << indent+1;
+
+			++indent;
+			node->init->accept( *this );
+			--indent;
+			os << endl;
+		} // if
+
+		if ( ! node->attributes.empty() ) {
+			os << endl << indent << "... with attributes:" << endl;
+			++indent;
+			printAll( node->attributes );
+			--indent;
+		}
+
+		if ( node->bitfieldWidth ) {
+			os << indent << " with bitfield width ";
+			node->bitfieldWidth->accept( *this );
+		} // if
+		return node;
+	}
+
+	virtual const ast::DeclWithType * visit( const ast::FunctionDecl * node ) {
+		if ( !node->name.empty() ) {
+			os << node->name << ": ";
+		} // if
+		if ( node->linkage != Linkage::Cforall ) {
+			os << Linkage::name( node->linkage ) << " ";
+		} // if
+
+		printAll( node->attributes );
+
+		print( node->storage );
+		print( node->funcSpec );
+
+		if ( node->type ) {
+			node->type->accept( *this );
+		} else {
+			os << "untyped entity";
+		} // if
+
+		if ( node->stmts ) {
+			os << indent << "... with body" << endl << indent+1;
+			++indent;
+			node->stmts->accept( *this );
+			--indent;
+		} // if
+		return node;
+	}
+
+	virtual const ast::Decl * visit( const ast::StructDecl * node ) {
+		print(node);
+		return node;
+	}
+
+	virtual const ast::Decl * visit( const ast::UnionDecl * node ) {
+		print(node);
+		return node;
+	}
+
+	virtual const ast::Decl * visit( const ast::EnumDecl * node ) {
+		print(node);
+		return node;
+	}
+
+	virtual const ast::Decl * visit( const ast::TraitDecl * node ) {
+		print(node);
+		return node;
+	}
+
+	virtual const ast::Decl * visit( const ast::TypeDecl * node ) {
+		print( node );
+		if ( node->init ) {
+			os << endl << indent << "with type initializer: ";
+			++indent;
+			node->init->accept( *this );
+			--indent;
+		}
+		return node;
+	}
+
+	virtual const ast::Decl * visit( const ast::TypedefDecl * node ) {
+		print( node );
+		return node;
+	}
+
+	virtual const ast::AsmDecl * visit( const ast::AsmDecl * node ) {
+		node->stmt->accept( *this );
+		return node;
+	}
+
+	virtual const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl * node ) {
+		os << "Static Assert with condition: ";
+		++indent;
+		node->cond->accept( *this );
+		--indent;
+		os << endl << indent << "and message: ";
+		++indent;
+		node->msg->accept( *this );
+		--indent;
+		os << endl;
+		return node;
+	}
+
+	virtual const ast::CompoundStmt * visit( const ast::CompoundStmt * node ) {
+		os << "Compound Statement:" << endl;
+		++indent;
+		printAll( node->kids );
+		--indent;
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::ExprStmt * node ) {
+		++indent;
+		os << "Expression Statement:" << endl << indent;
+		safe_print( node->expr );
+		--indent;
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::AsmStmt * node ) {
+		os << "Assembler Statement:" << endl;
+		++indent;
+		os << indent-1 << "instruction:" << endl << indent;
+		safe_print( node->instruction );
+		if ( ! node->output.empty() ) {
+			os << endl << indent << "output:" << endl;
+			printAll( node->output );
+		} // if
+		if ( ! node->input.empty() ) {
+			os << indent << "input:" << endl;
+			printAll( node->input );
+		} // if
+		if ( ! node->clobber.empty() ) {
+			os << indent << "clobber:" << endl;
+			printAll( node->clobber );
+		} // if
+		--indent;
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::DirectiveStmt * node ) {
+		os << "GCC Directive: " << node->directive << endl;
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::IfStmt * node ) {
+		os << "If on condition:" << endl;
+		++indent;
+		os << indent;
+		safe_print( node->cond );
+		--indent;
+
+		if ( ! node->inits.empty() ) {
+			os << indent << "... with initialization:" << endl;
+			++indent;
+			for ( const ast::Stmt * stmt : node->inits ) {
+				os << indent;
+				safe_print( stmt );
+			}
+			--indent;
+			os << endl;
+		}
+
+		os << indent << "... then:" << endl;
+
+		++indent;
+		os << indent;
+		safe_print( node->thenPart );
+		--indent;
+
+		if ( node->elsePart != 0 ) {
+			os << indent << "... else:" << endl;
+			++indent;
+			os << indent;
+			node->elsePart->accept( *this );
+			--indent;
+		} // if
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::WhileStmt * node ) {
+		if ( node->isDoWhile ) { os << "Do-"; }
+		os << "While on condition:" << endl;
+		++indent;
+		safe_print( node->cond );
+		os << indent-1 << "... with body:" << endl;
+		safe_print( node->body );
+
+		if ( ! node->inits.empty() ) {
+			os << indent-1 << "... with inits:" << endl;
+			printAll( node->inits );
+		}
+		--indent;
+
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::ForStmt * node ) {
+		os << "For Statement" << endl;
+
+		if ( ! node->inits.empty() ) {
+			os << indent << "... initialization:" << endl;
+			++indent;
+			for ( const ast::Stmt * stmt : node->inits ) {
+				os << indent+1;
+				safe_print( stmt );
+			}
+			--indent;
+		}
+
+		if ( node->cond ) {
+			os << indent << "... condition:" << endl;
+			++indent;
+			os << indent;
+			node->cond->accept( *this );
+			--indent;
+		}
+
+		if ( node->inc ) {
+			os << indent << "... increment:" << endl;
+			++indent;
+			os << indent;
+			node->inc->accept( *this );
+			--indent;
+		}
+
+		if ( node->body ) {
+			os << indent << "... with body:" << endl;
+			++indent;
+			os << indent;
+			node->body->accept( *this );
+			--indent;
+		}
+		os << endl;
+		print( node->labels );
+
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::SwitchStmt * node ) {
+		os << "Switch on condition: ";
+		safe_print( node->cond );
+		os << endl;
+
+		++indent;
+		for ( const ast::Stmt * stmt : node->stmts ) {
+			stmt->accept( *this );
+		}
+		--indent;
+
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::CaseStmt * node ) {
+		if ( node->isDefault() ) {
+			os << indent << "Default ";
+		} else {
+			os << indent << "Case ";
+			safe_print( node->cond );
+		} // if
+		os << endl;
+
+		++indent;
+		for ( const ast::Stmt * stmt : node->stmts ) {
+			os << indent;
+			stmt->accept( *this );
+		}
+		--indent;
+
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::BranchStmt * node ) {
+		os << "Branch (" << node->kindName() << ")" << endl;
+		++indent;
+		if ( ! node->target.empty() ) {
+			os << indent << "with target: " << node->target << endl;
+		}
+
+		if ( ! node->originalTarget.empty() ) {
+			os << indent << "with original target: " << node->originalTarget << endl;
+		}
+
+		if ( node->computedTarget ) {
+			os << indent << "with computed target: ";
+			node->computedTarget->accept( *this );
+			os << endl;
+		}
+		--indent;
+
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::ReturnStmt * node ) {
+		os << "Return Statement, returning";
+		if ( node->expr ) {
+			++indent;
+			os << ":" << endl << indent;
+			node->expr->accept( *this );
+			--indent;
+		} else {
+			os << " void";
+		}
+		os << endl;
+
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::ThrowStmt * node ) {
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::TryStmt * node ) {
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::CatchStmt * node ) {
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::FinallyStmt * node ) {
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::WaitForStmt * node ) {
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::WithStmt * node ) {
+		return node;
+	}
+
+	virtual const ast::NullStmt * visit( const ast::NullStmt * node ) {
+		os << "Null Statement" << endl;
+		print( node->labels );
+
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::DeclStmt * node ) {
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::ImplicitCtorDtorStmt * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::ApplicationExpr * node ) {
+		++indent;
+		os << "Application of" << endl << indent;
+		safe_print( node->func );
+		os << endl;
+		if ( ! node->args.empty() ) {
+			os << indent << "... to arguments" << endl;
+			printAll( node->args );
+		}
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::UntypedExpr * node ) {
+		++indent;
+		os << "Applying untyped:" << endl;
+		os << indent;
+		safe_print( node->func );
+		os << endl << indent-1 << "...to:" << endl;
+		printAll( node->args );
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::NameExpr * node ) {
+		os << "Name: " << node->name;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::AddressExpr * node ) {
+		os << "Address of:" << endl;
+		++indent;
+		os << indent;
+		safe_print( node->arg );
+
+		--indent;
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::LabelAddressExpr * node ) {
+		os << "Address of label:" << node->arg;
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::CastExpr * node ) {
+		++indent;
+		os << (node->isGenerated ? "Generated" : "Explicit") << " cast of:" << endl << indent;
+		safe_print( node->arg );
+		os << endl << indent-1 << "... to:";
+		if ( ! node->result ) {
+			os << " ";
+			undefined();
+		} else if ( node->result->isVoid() ) {
+			os << " nothing";
+		} else {
+			os << endl << indent;
+			node->result->accept( *this );
+		} // if
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::KeywordCastExpr * node ) {
+		++indent;
+		os << "Keyword Cast of:" << endl << indent;
+		safe_print( node->arg );
+		--indent;
+		os << endl << indent << "... to: " << node->targetString();
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::VirtualCastExpr * node ) {
+		++indent;
+		os << "Virtual Cast of:" << endl << indent;
+		safe_print( node->arg );
+		os << endl << indent-1 << "... to:";
+		if ( ! node->result ) {
+			os << " unknown";
+		} else {
+			os << endl << indent;
+			node->result->accept( *this );
+		}
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::UntypedMemberExpr * node ) {
+		++indent;
+		os << "Untyped Member Expression, with field: " << endl << indent;
+		safe_print( node->member );
+		os << indent-1 << "... from aggregate:" << endl << indent;
+		safe_print( node->aggregate );
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::MemberExpr * node ) {
+		++indent;
+		os << "Member Expression, with field:" << endl << indent;
+		safe_print( node->member );
+		os << endl << indent-1 << "... from aggregate:" << endl << indent;
+		safe_print( node->aggregate );
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::VariableExpr * node ) {
+		os << "Variable Expression: ";
+		short_print( node->var );
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::ConstantExpr * node ) {
+		os << "Constant Expression (" << node->rep;
+		if ( node->result ) {
+			os << ": ";
+			node->result->accept( *this );
+		}
+		os << ")";
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::SizeofExpr * node ) {
+		os << "Sizeof Expression on: ";
+		++indent;
+		if ( node->type ) node->type->accept( *this );
+		else safe_print( node->expr );
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::AlignofExpr * node ) {
+		os << "Alignof Expression on: ";
+		++indent;
+		if ( node->type ) node->type->accept( *this );
+		else safe_print( node->expr );
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::UntypedOffsetofExpr * node ) {
+		os << "Untyped Offsetof Expression on member " << node->member << " of ";
+		++indent;
+		safe_print( node->type );
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::OffsetofExpr * node ) {
+		os << "Offsetof Expression on member " << node->member->name << " of ";
+		++indent;
+		safe_print( node->type );
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::OffsetPackExpr * node ) {
+		os << "Offset Pack Expression on: ";
+		++indent;
+		safe_print( node->type );
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::LogicalExpr * node ) {
+		os << "Short-circuited operation (" << (node->isAnd ? "and" : "or") << ") on: ";
+		safe_print( node->arg1 );
+		os << " and ";
+		safe_print( node->arg2 );
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::ConditionalExpr * node ) {
+		++indent;
+		os << "Conditional expression on:" << endl << indent;
+		safe_print( node->arg1 );
+		os << indent-1 << "First alternative:" << endl << indent;
+		safe_print( node->arg2 );
+		os << indent-1 << "Second alternative:" << endl << indent;
+		safe_print( node->arg3 );
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::CommaExpr * node ) {
+		++indent;
+		os << "Comma Expression:" << endl << indent;
+		safe_print( node->arg1 );
+		os << endl << indent;
+		safe_print( node->arg2 );
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::TypeExpr * node ) {
+		safe_print( node->type );
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::AsmExpr * node ) {
+		os << "Asm Expression:" << endl;
+		++indent;
+		if ( node->inout ) node->inout->accept( *this );
+		if ( node->constraint ) node->constraint->accept( *this );
+		if ( node->operand ) node->operand->accept( *this );
+		--indent;
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::ImplicitCopyCtorExpr * node ) {
+		++indent;
+		os << "Implicit Copy Constructor Expression:" << endl << indent;
+		safe_print( node->callExpr );
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::ConstructorExpr * node ) {
+		os <<  "Constructor Expression:" << endl << indent+1;
+		indent += 2;
+		safe_print( node->callExpr );
+		indent -= 2;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::CompoundLiteralExpr * node ) {
+		++indent;
+		os << "Compound Literal Expression: " << endl << indent;
+		safe_print( node->result );
+		os << indent;
+		safe_print( node->init );
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::RangeExpr * node ) {
+		os << "Range Expression: ";
+		safe_print( node->low );
+		os << " ... ";
+		safe_print( node->high );
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::UntypedTupleExpr * node ) {
+		os << "Untyped Tuple:" << endl;
+		++indent;
+		printAll( node->exprs );
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::TupleExpr * node ) {
+		os << "Tuple:" << endl;
+		++indent;
+		printAll( node->exprs );
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::TupleIndexExpr * node ) {
+		os << "Tuple Index Expression, with tuple:" << endl;
+		++indent;
+		os << indent;
+		safe_print( node->tuple );
+		os << indent << "with index: " << node->index << endl;
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::TupleAssignExpr * node ) {
+		os << "Tuple Assignment Expression, with stmt expr:" << endl;
+		++indent;
+		os << indent;
+		safe_print( node->stmtExpr );
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::StmtExpr * node ) {
+		++indent;
+		os << "Statement Expression:" << endl << indent;
+		safe_print( node->stmts );
+		if ( ! node->returnDecls.empty() ) {
+			os << indent << "... with returnDecls: ";
+			printAll( node->returnDecls );
+		}
+		if ( ! node->dtors.empty() ) {
+			os << indent << "... with dtors: ";
+			printAll( node->dtors );
+		}
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::UniqueExpr * node ) {
+		++indent;
+		os << "Unique Expression with id: " << node->id << endl << indent;
+		safe_print( node->expr );
+		if ( node->object ) {
+			os << indent-1 << "... with decl: ";
+			short_print( node->object );
+		}
+		--indent;
+		postprint( node );
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::UntypedInitExpr * node ) {
+		++indent;
+		os << "Untyped Init Expression" << endl << indent;
+		safe_print( node->expr );
+		if ( ! node->initAlts.empty() ) {
+			for ( const InitAlternative & alt : node->initAlts ) {
+				os << indent <<  "InitAlternative: ";
+				safe_print( alt.type );
+				safe_print( alt.designation );
+			}
+		}
+		--indent;
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::InitExpr * node ) {
+		++indent;
+		os << "Init Expression" << endl << indent;
+		safe_print( node->expr );
+		os << indent << "... with designation: ";
+		safe_print( node->designation );
+		--indent;
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::DeletedExpr * node ) {
+		++indent;
+		os << "Deleted Expression" << endl << indent;
+		safe_print( node->expr );
+		os << endl << indent << "... deleted by: ";
+		safe_print( node->deleteStmt );
+		--indent;
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::DefaultArgExpr * node ) {
+		++indent;
+		os << "Default Argument Expression" << endl << indent;
+		safe_print( node->expr );
+		--indent;
+
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::GenericExpr * node ) {
+		++indent;
+		os << "C11 _Generic Expression" << endl << indent;
+		safe_print( node->control );
+		os << endl << indent << "... with associations:" << endl;
+		for ( const auto & assoc : node->associations ) {
+			os << indent;
+			if ( assoc.type ) {
+				os << "... type: ";
+				assoc.type->accept( *this );
+				os << endl << indent << "... expression: ";
+				safe_print( assoc.expr );
+			} else {
+				os << "... default: ";
+				safe_print( assoc.expr );
+			}
+			os << endl;
+		}
+		--indent;
+
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::VoidType * node ) {
+		preprint( node );
+		os << "void";
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::BasicType * node ) {
+		preprint( node );
+		os << ast::BasicType::typeNames[ node->kind ];
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::PointerType * node ) {
+		preprint( node );
+		if ( ! node->isArray() ) {
+			os << "pointer to ";
+		} else {
+			os << "decayed ";
+			if ( node->isStatic ) {
+				os << "static ";
+			}
+
+			if ( node->isVarLen ) {
+				os << "variable length array of ";
+			} else if ( node->dimension ) {
+				os << "array of ";
+				node->dimension->accept( *this );
+				os << " ";
+			}
+		}
+		safe_print( node->base );
+
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::ArrayType * node ) {
+		preprint( node );
+		if ( node->isStatic ) {
+			os << "static ";
+		}
+
+		if ( node->isVarLen ) {
+			os << "variable length array of ";
+		} else if ( node->dimension ) {
+			os << "array of ";
+		} else {
+			os << "open array of ";
+		}
+
+		safe_print( node->base );
+
+		if ( node->dimension ) {
+			os << " with dimension of ";
+			node->dimension->accept( *this );
+		}
+
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::ReferenceType * node ) {
+		preprint( node );
+		os << "reference to ";
+		safe_print( node->base );
+
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::QualifiedType * node ) {
+		preprint( node );
+		++indent;
+		os << "Qualified Type:" << endl << indent;
+		safe_print( node->parent );
+		os << endl << indent;
+		safe_print( node->child );
+		os << endl;
+		--indent;
+
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::FunctionType * node ) {
+		preprint( node );
+
+		os << "function" << endl;
+		if ( ! node->params.empty() ) {
+			os << indent << "... with parameters" << endl;
+			++indent;
+			printAll( node->params );
+			if ( node->isVarArgs ) {
+				os << indent << "and a variable number of other arguments" << endl;
+			}
+			--indent;
+		} else if ( node->isVarArgs ) {
+			os << indent+1 << "accepting unspecified arguments" << endl;
+		}
+
+		os << indent << "... returning";
+		if ( node->returns.empty() ) {
+			os << " nothing" << endl;
+		} else {
+			os << endl;
+			++indent;
+			printAll( node->returns );
+			--indent;
+		}
+
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::StructInstType * node ) {
+		preprint( node );
+		os << "instance of struct " << node->name;
+		if ( node->base ) {
+			os << " " << ( node->base->body ? "with" : "without" ) << " body";
+		}
+		print( node->params );
+
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::UnionInstType * node ) {
+		preprint( node );
+		os << "instance of union " << node->name;
+		if ( node->base ) {
+			os << " " << ( node->base->body ? "with" : "without" ) << " body";
+		}
+		print( node->params );
+
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::EnumInstType * node ) {
+		preprint( node );
+		os << "instance of enum " << node->name;
+		if ( node->base ) {
+			os << " " << ( node->base->body ? "with" : "without" ) << " body";
+		}
+		print( node->params );
+
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::TraitInstType * node ) {
+		preprint( node );
+		os << "instance of trait " << node->name;
+		print( node->params );
+
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::TypeInstType * node ) {
+		preprint( node );
+		os << "instance of type " << node->name
+		   << " (" << (node->kind == ast::TypeVar::Ftype ? "" : "not ") << "function type)";
+		print( node->params );
+
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::TupleType * node ) {
+		preprint( node );
+		os << "tuple of types" << endl;
+		++indent;
+		printAll( node->types );
+		--indent;
+
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::TypeofType * node ) {
+		preprint( node );
+		if ( node->kind == ast::TypeofType::Basetypeof ) { os << "base-"; }
+		os << "type-of expression ";
+		safe_print( node->expr );
+
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::VarArgsType * node ) {
+		preprint( node );
+		os << "builtin var args pack";
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::ZeroType * node ) {
+		preprint( node );
+		os << "zero_t";
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::OneType * node ) {
+		preprint( node );
+		os << "one_t";
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::GlobalScopeType * node ) {
+		preprint( node );
+		os << "Global Scope Type";
+		return node;
+	}
+
+	virtual const ast::Designation * visit( const ast::Designation * node ) {
+		if ( node->designators.empty() ) return node;
+		os << "... designated by: " << endl;
+		++indent;
+		for ( const ast::Expr * d : node->designators ) {
+			os << indent;
+			d->accept( *this );
+			os << endl;
+		}
+		--indent;
+		return node;
+	}
+
+	virtual const ast::Init * visit( const ast::SingleInit * node ) {
+		os << "Simple Initializer: ";
+		safe_print( node->value );
+		return node;
+	}
+
+	virtual const ast::Init * visit( const ast::ListInit * node ) {
+		os << "Compound initializer: " << endl;
+		++indent;
+		for ( auto p : group_iterate( node->designations, node->initializers ) ) {
+			const ast::Designation * d = std::get<0>(p);
+			const ast::Init * init = std::get<1>(p);
+			os << indent;
+			init->accept( *this );
+			os << endl;
+			if ( ! d->designators.empty() ) {
+				os << indent;
+				d->accept( *this );
+			}
+		}
+		--indent;
+		return node;
+	}
+
+	virtual const ast::Init * visit( const ast::ConstructorInit * node ) {
+		os << "Constructor initializer: " << endl;
+		if ( node->ctor ) {
+			os << indent << "... initially constructed with ";
+			++indent;
+			node->ctor->accept( *this );
+			--indent;
+		}
+
+		if ( node->dtor ) {
+			os << indent << "... destructed with ";
+			++indent;
+			node->dtor->accept( *this );
+			--indent;
+		}
+
+		if ( node->init ) {
+			os << indent << "... with fallback C-style initializer: ";
+			++indent;
+			node->init->accept( *this );
+			--indent;
+		}
+		return node;
+	}
+
+	virtual const ast::Attribute * visit( const ast::Attribute * node ) {
+		if ( node->empty() ) return node;
+		os << "Attribute with name: " << node->name;
+		if ( node->params.empty() ) return node;
+		os << " with parameters: " << endl;
+		++indent;
+		printAll( node->params );
+		--indent;
+		return node;
+	}
+
+	virtual const ast::TypeSubstitution * visit( const ast::TypeSubstitution * node ) {
+		os << indent << "Types:" << endl;
+		for ( const auto& i : *node ) {
+			os << indent+1 << i.first << " -> ";
+			indent += 2;
+			safe_print( i.second );
+			indent -= 2;
+			os << endl;
+		}
+		os << indent << "Non-types:" << endl;
+		for ( auto i = node->beginVar(); i != node->endVar(); ++i ) {
+			os << indent+1 << i->first << " -> ";
+			indent += 2;
+			safe_print( i->second );
+			indent -= 2;
+			os << endl;
+		}
+		return node;
+	}
+
+};
+
+void print( ostream & os, const ast::Node * node, Indenter indent ) {
+	Printer printer { os, indent, false };
+	node->accept(printer);
+}
+
+void printShort( ostream & os, const ast::Node * node, Indenter indent ) {
+	Printer printer { os, indent, true };
+	node->accept(printer);
+}
+
+// Annoyingly these needed to be defined out of line to avoid undefined references.
+// The size here needs to be explicit but at least the compiler will produce an error
+// if the wrong size is specified
+constexpr array<const char*, 3> Printer::Names::FuncSpecifiers;
+constexpr array<const char*, 5> Printer::Names::StorageClasses;
+constexpr array<const char*, 6> Printer::Names::Qualifiers;
+}
Index: src/AST/Print.hpp
===================================================================
--- src/AST/Print.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
+++ src/AST/Print.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -0,0 +1,31 @@
+//
+// 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.
+//
+// Print.hpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Tue May 21 16:20:15 2019
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#pragma once
+
+#include <iosfwd>
+
+#include "AST/Node.hpp"
+#include "Common/Indenter.h"
+
+namespace ast {
+
+void print( std::ostream & os, const ast::Node * node, Indenter indent = {} );
+
+inline void print( std::ostream & os, const ast::Node * node, unsigned int indent ) {
+    print( os, node, Indenter{ Indenter::tabsize, indent });
+}
+
+}
Index: src/AST/Stmt.cpp
===================================================================
--- src/AST/Stmt.cpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Stmt.cpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -16,11 +16,41 @@
 #include "Stmt.hpp"
 
+
 #include "DeclReplacer.hpp"
+#include "Type.hpp"
 
 namespace ast {
 
 // --- CompoundStmt
-CompoundStmt::CompoundStmt( const CompoundStmt& o ) : Stmt(o), kids(o.kids) {
-	assert(!"implemented");
+CompoundStmt::CompoundStmt( const CompoundStmt& other ) : Stmt(other), kids(other.kids) {
+	// when cloning a compound statement, we may end up cloning declarations which
+	// are referred to by VariableExprs throughout the block. Cloning a VariableExpr
+	// does a shallow copy, so the VariableExpr will end up pointing to the original
+	// declaration. If the original declaration is deleted, e.g. because the original
+	// CompoundStmt is deleted, then we have a dangling pointer. To avoid this case,
+	// find all DeclarationWithType nodes (since a VariableExpr must point to a
+	// DeclarationWithType) in the original CompoundStmt and map them to the cloned
+	// node in the new CompoundStmt ('this'), then replace the Declarations referred to
+	// by each VariableExpr according to the constructed map. Note that only the declarations
+	// in the current level are collected into the map, because child CompoundStmts will
+	// recursively execute this routine. There may be more efficient ways of doing
+	// this.
+	DeclReplacer::DeclMap declMap;
+	auto origit = other.kids.begin();
+	for ( const Stmt * s : kids ) {
+		assert( origit != other.kids.end() );
+		const Stmt * origStmt = *origit++;
+		if ( const DeclStmt * declStmt = dynamic_cast< const DeclStmt * >( s ) ) {
+			const DeclStmt * origDeclStmt = strict_dynamic_cast< const DeclStmt * >( origStmt );
+			if ( const DeclWithType * dwt = dynamic_cast< const DeclWithType * > ( declStmt->decl.get() ) ) {
+				const DeclWithType * origdwt = strict_dynamic_cast< const DeclWithType * > ( origDeclStmt->decl.get() );
+				assert( dwt->name == origdwt->name );
+				declMap[ origdwt ] = dwt;
+			} else assert( ! dynamic_cast< const DeclWithType * > ( origDeclStmt->decl.get() ) );
+		} else assert( ! dynamic_cast< const DeclStmt * > ( s ) );
+	}
+	if ( ! declMap.empty() ) {
+		DeclReplacer::replace( this, declMap );
+	}
 }
 
Index: src/AST/Stmt.hpp
===================================================================
--- src/AST/Stmt.hpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Stmt.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -96,4 +96,5 @@
 };
 
+/// Assembly statement `asm ... ( "..." : ... )`
 class AsmStmt final : public Stmt {
 public:
@@ -118,4 +119,5 @@
 };
 
+/// C-preprocessor directive `#...`
 class DirectiveStmt final : public Stmt {
 public:
@@ -132,4 +134,5 @@
 };
 
+/// If conditional statement `if (...) ... else ...`
 class IfStmt final : public Stmt {
 public:
@@ -151,4 +154,5 @@
 };
 
+/// Switch or choose conditional statement `switch (...) { ... }`
 class SwitchStmt final : public Stmt {
 public:
@@ -166,4 +170,5 @@
 };
 
+/// Case label `case ...:` `default:`
 class CaseStmt final : public Stmt {
 public:
@@ -183,4 +188,5 @@
 };
 
+/// While loop `while (...) ...` `do ... while (...);
 class WhileStmt final : public Stmt {
 public:
@@ -201,4 +207,5 @@
 };
 
+/// For loop `for (... ; ... ; ...) ...`
 class ForStmt final : public Stmt {
 public:
@@ -219,4 +226,5 @@
 };
 
+/// Branch control flow statement `goto ...` `break` `continue` `fallthru`
 class BranchStmt final : public Stmt {
 public:
@@ -236,5 +244,5 @@
 	  computedTarget(computedTarget), kind(Goto) {}
 
-	const char * kindName() { return kindNames[kind]; }
+	const char * kindName() const { return kindNames[kind]; }
 
 	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
@@ -246,4 +254,5 @@
 };
 
+/// Return statement `return ...`
 class ReturnStmt final : public Stmt {
 public:
@@ -259,4 +268,5 @@
 };
 
+/// Throw statement `throw ...`
 class ThrowStmt final : public Stmt {
 public:
@@ -277,4 +287,5 @@
 };
 
+/// Try statement `try { ... } ...`
 class TryStmt final : public Stmt {
 public:
@@ -294,4 +305,5 @@
 };
 
+/// Catch clause of try statement
 class CatchStmt final : public Stmt {
 public:
@@ -313,4 +325,5 @@
 };
 
+/// Finally clause of try statement
 class FinallyStmt final : public Stmt {
 public:
@@ -327,9 +340,10 @@
 };
 
+/// Wait for concurrency statement `when (...) waitfor (... , ...) ... timeout(...) ... else ...`
 class WaitForStmt final : public Stmt {
 public:
 	struct Target {
-		ptr<Expr> function;
-		std::vector<ptr<Expr>> arguments;
+		ptr<Expr> func;
+		std::vector<ptr<Expr>> args;
 	};
 
@@ -364,4 +378,5 @@
 };
 
+/// With statement `with (...) ...`
 class WithStmt final : public Stmt {
 public:
@@ -379,4 +394,5 @@
 };
 
+/// Any declaration in a (compound) statement.
 class DeclStmt final : public Stmt {
 public:
@@ -392,4 +408,5 @@
 };
 
+/// Represents an implicit application of a constructor or destructor.
 class ImplicitCtorDtorStmt final : public Stmt {
 public:
Index: src/AST/Type.cpp
===================================================================
--- src/AST/Type.cpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Type.cpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -141,4 +141,10 @@
 bool EnumInstType::isComplete() const { return base ? base->body : false; }
 
+// --- TraitInstType
+
+TraitInstType::TraitInstType( const TraitDecl * b, CV::Qualifiers q,
+	std::vector<ptr<Attribute>>&& as )
+: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
+
 // --- TypeInstType
 
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/Type.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -47,9 +47,9 @@
 	bool is_atomic() const { return qualifiers.is_atomic; }
 
-	void set_const( bool v ) { qualifiers.is_const = v; }
-	void set_restrict( bool v ) { qualifiers.is_restrict = v; }
-	void set_lvalue( bool v ) { qualifiers.is_lvalue = v; }
-	void set_mutex( bool v ) { qualifiers.is_mutex = v; }
-	void set_atomic( bool v ) { qualifiers.is_atomic = v; }
+	Type * set_const( bool v ) { qualifiers.is_const = v; return this; }
+	Type * set_restrict( bool v ) { qualifiers.is_restrict = v; return this; }
+	Type * set_lvalue( bool v ) { qualifiers.is_lvalue = v; return this; }
+	Type * set_mutex( bool v ) { qualifiers.is_mutex = v; return this; }
+	Type * set_atomic( bool v ) { qualifiers.is_atomic = v; return this; }
 
 	/// How many elemental types are represented by this type
@@ -308,8 +308,4 @@
 	virtual ReferenceToType * clone() const override = 0;
 	MUTATE_FRIEND
-
-protected:
-	/// Name for the kind of type this is
-	virtual std::string typeString() const = 0;
 };
 
@@ -333,6 +329,4 @@
 	StructInstType * clone() const override { return new StructInstType{ *this }; }
 	MUTATE_FRIEND
-
-	std::string typeString() const override { return "struct"; }
 };
 
@@ -356,6 +350,4 @@
 	UnionInstType * clone() const override { return new UnionInstType{ *this }; }
 	MUTATE_FRIEND
-
-	std::string typeString() const override { return "union"; }
 };
 
@@ -379,6 +371,4 @@
 	EnumInstType * clone() const override { return new EnumInstType{ *this }; }
 	MUTATE_FRIEND
-
-	std::string typeString() const override { return "enum"; }
 };
 
@@ -403,6 +393,4 @@
 	TraitInstType * clone() const override { return new TraitInstType{ *this }; }
 	MUTATE_FRIEND
-
-	std::string typeString() const override { return "trait"; }
 };
 
@@ -432,6 +420,4 @@
 	TypeInstType * clone() const override { return new TypeInstType{ *this }; }
 	MUTATE_FRIEND
-
-	std::string typeString() const override { return "type"; }
 };
 
@@ -514,5 +500,5 @@
 class GlobalScopeType final : public Type {
 public:
-	GlobalScopeType( CV::Qualifiers q = {} ) : Type( q ) {}
+	GlobalScopeType() : Type() {}
 
 	const Type * accept( Visitor & v ) const override { return v.visit( this ); }
Index: src/AST/TypeSubstitution.hpp
===================================================================
--- src/AST/TypeSubstitution.hpp	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/TypeSubstitution.hpp	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -25,9 +25,10 @@
 #include "Fwd.hpp"        // for UniqueId
 #include "ParseNode.hpp"
-#include "Type.hpp"       // for ptr<Type>
+#include "Type.hpp"
 #include "Common/SemanticError.h"  // for SemanticError
 #include "Visitor.hpp"
 #include "Decl.hpp"
 #include "Expr.hpp"
+#include "Node.hpp"
 
 namespace ast {
@@ -43,6 +44,22 @@
 	TypeSubstitution &operator=( const TypeSubstitution &other );
 
-	template< typename SynTreeClass > int apply( SynTreeClass *&input ) const;
-	template< typename SynTreeClass > int applyFree( SynTreeClass *&input ) const;
+	template< typename SynTreeClass > int apply( const SynTreeClass *& input ) const;
+	template< typename SynTreeClass > int applyFree( const SynTreeClass *& input ) const;
+
+	template< typename node_t, enum Node::ref_type ref_t >
+	int apply( ptr_base< node_t, ref_t > & input ) const {
+		const node_t * p = input.get();
+		int ret = apply(p);
+		input = p;
+		return ret;
+	}
+
+	template< typename node_t, enum Node::ref_type ref_t >
+	int applyFree( ptr_base< node_t, ref_t > & input ) const {
+		const node_t * p = input.get();
+		int ret = applyFree(p);
+		input = p;
+		return ret;
+	}
 
 	void add( std::string formalType, const Type *actualType );
@@ -162,9 +179,8 @@
 
 template< typename SynTreeClass >
-int TypeSubstitution::apply( SynTreeClass *&input ) const {
+int TypeSubstitution::apply( const SynTreeClass *& input ) const {
 	assert( input );
 	Pass<Substituter> sub( *this, false );
-	input = dynamic_cast< SynTreeClass * >( input->acceptMutator( sub ) );
-	assert( input );
+	input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
 ///	std::cerr << "substitution result is: ";
 ///	newType->print( std::cerr );
@@ -174,9 +190,8 @@
 
 template< typename SynTreeClass >
-int TypeSubstitution::applyFree( SynTreeClass *&input ) const {
+int TypeSubstitution::applyFree( const SynTreeClass *& input ) const {
 	assert( input );
 	Pass<Substituter> sub( *this, true );
-	input = dynamic_cast< SynTreeClass * >( input->acceptMutator( sub ) );
-	assert( input );
+	input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
 ///	std::cerr << "substitution result is: ";
 ///	newType->print( std::cerr );
Index: src/AST/module.mk
===================================================================
--- src/AST/module.mk	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/module.mk	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -1,4 +1,3 @@
-######################### -*- Mode: Makefile-Gmake -*-
-########################
+######################### -*- Mode: Makefile-Gmake -*- ########################
 ##
 ## Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
@@ -17,7 +16,18 @@
 
 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/GenericSubstitution.cpp \
+	AST/Init.cpp \
+	AST/LinkageSpec.cpp \
+	AST/Node.cpp \
+	AST/Pass.cpp \
+	AST/Print.cpp \
+	AST/Stmt.cpp \
+	AST/Type.cpp \
+	AST/TypeSubstitution.cpp
 
 
@@ -25,3 +35,2 @@
 SRC += $(SRC_AST)
 SRCDEMANGLE += $(SRC_AST)
-
Index: src/AST/porting.md
===================================================================
--- src/AST/porting.md	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/AST/porting.md	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -38,7 +38,5 @@
 
 `N->print(std::ostream&)` is a visitor now, port these methods to `ast::Print` class
-* **TODO** write this visitor
-* **TODO** write `std::ostream& operator<< ( std::ostream& out, const Node* node )` in `Node.hpp` in terms of `ast::Print`
-* `Declaration::printShort` should also be integrated
+* **TODO** `Declaration::printShort` should also be integrated
 
 `clone` is private to `Node` now
@@ -112,4 +110,7 @@
 
 ## Specific Nodes ##
+`Attribute`
+* `parameters` => `params`
+
 `Decl`
 * `storageClasses` => `storage`
@@ -208,7 +209,4 @@
 
 `CompoundStmt`
-* **TODO** port copy operator
-  * Needs to be an almost-shallow clone, where the declarations are cloned only if needed
-  * **TODO** port `DeclReplacer`
 * Still a `std::list` for children, rather than `std::vector`
   * allows more-efficient splicing for purposes of later code generation
@@ -229,5 +227,5 @@
   * `getAggr()` => `aggr()`
     * also now returns `const AggregateDecl *`
-* `genericSubstitution()` moved to own visitor in `AST/GenericSubstitution.hpp` **TODO** write
+* `genericSubstitution()` moved to own visitor in `AST/GenericSubstitution.hpp`
 
 `BasicType`
Index: src/Common/Eval.cc
===================================================================
--- src/Common/Eval.cc	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/Common/Eval.cc	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -17,8 +17,11 @@
 
 #include "Common/PassVisitor.h"
+#include "AST/Pass.hpp"
 #include "InitTweak/InitTweak.h"
 #include "SynTree/Expression.h"
 
-struct Eval : public WithShortCircuiting {
+//-------------------------------------------------------------
+// Old AST
+struct EvalOld : public WithShortCircuiting {
 	long long int value = 0;
 	bool valid = true;
@@ -80,6 +83,78 @@
 };
 
+//-------------------------------------------------------------
+// New AST
+struct EvalNew : public ast::WithShortCircuiting {
+	long long int value = 0;
+	bool valid = true;
+
+	void previsit( const ast::Node * ) { visit_children = false; }
+	void postvisit( const ast::Node * ) { valid = false; }
+
+	void postvisit( const ast::ConstantExpr * expr ) {
+		value = expr->intValue();
+	}
+
+	void postvisit( const ast::CastExpr * expr ) {
+		auto arg = eval(expr->arg);
+		valid = arg.second;
+		value = arg.first;
+		// TODO: perform type conversion on value if valid
+	}
+
+	void postvisit( const ast::VariableExpr * expr ) {
+		if ( const ast::EnumInstType * inst = dynamic_cast<const ast::EnumInstType *>(expr->result.get()) ) {
+			if ( const ast::EnumDecl * decl = inst->base ) {
+				if ( decl->valueOf( expr->var, value ) ) { // value filled by valueOf
+					return;
+				}
+			}
+		}
+		valid = false;
+	}
+
+	void postvisit( const ast::ApplicationExpr * expr ) {
+		const ast::DeclWithType * function = InitTweak::getFunction(expr);
+		if ( ! function || function->linkage != ast::Linkage::Intrinsic ) { valid = false; return; }
+		const std::string & fname = function->name;
+		assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() );
+		std::pair<long long int, bool> arg1, arg2;
+		arg1 = eval(expr->args.front());
+		valid = valid && arg1.second;
+		if ( ! valid ) return;
+		if ( expr->args.size() == 2 ) {
+			arg2 = eval(expr->args.back());
+			valid = valid && arg2.second;
+			if ( ! valid ) return;
+		}
+		if (fname == "?+?") {
+			value = arg1.first + arg2.first;
+		} else if (fname == "?-?") {
+			value = arg1.first - arg2.first;
+		} else if (fname == "?*?") {
+			value = arg1.first * arg2.first;
+		} else if (fname == "?/?") {
+			value = arg1.first / arg2.first;
+		} else if (fname == "?%?") {
+			value = arg1.first % arg2.first;
+		} else {
+			valid = false;
+		}
+		// TODO: implement other intrinsic functions
+	}
+};
+
 std::pair<long long int, bool> eval(Expression * expr) {
-	PassVisitor<Eval> ev;
+	PassVisitor<EvalOld> ev;
+	if (expr) {
+		expr->accept(ev);
+		return std::make_pair(ev.pass.value, ev.pass.valid);
+	} else {
+		return std::make_pair(0, false);
+	}
+}
+
+std::pair<long long int, bool> eval(const ast::Expr * expr) {
+	ast::Pass<EvalNew> ev;
 	if (expr) {
 		expr->accept(ev);
Index: src/Common/PassVisitor.impl.h
===================================================================
--- src/Common/PassVisitor.impl.h	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/Common/PassVisitor.impl.h	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -23,21 +23,4 @@
 	assert( __return ); \
 	return __return;
-
-
-#define VISIT_BODY( node )          \
-	VISIT_START( node );          \
-	if( children_guard ) {        \
-		Visitor::visit( node ); \
-	}                             \
-	VISIT_END( node );            \
-
-
-#define MUTATE_BODY( type, node )    \
-	MUTATE_START( node );          \
-	if( children_guard ) {         \
-		Mutator::mutate( node ); \
-	}                              \
-	MUTATE_END( type, node );      \
-
 
 
@@ -2756,2 +2739,8 @@
 	MUTATE_END( TypeSubstitution, node );
 }
+
+#undef VISIT_START
+#undef VISIT_END
+
+#undef MUTATE_START
+#undef MUTATE_END
Index: src/Common/utility.h
===================================================================
--- src/Common/utility.h	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/Common/utility.h	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -74,7 +74,7 @@
 
 template< typename Container >
-void deleteAll( Container &container ) {
-	for ( typename Container::iterator i = container.begin(); i != container.end(); ++i ) {
-		delete *i;
+void deleteAll( const Container &container ) {
+	for ( const auto &i : container ) {
+		delete i;
 	} // for
 }
Index: src/InitTweak/InitTweak.cc
===================================================================
--- src/InitTweak/InitTweak.cc	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/InitTweak/InitTweak.cc	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -346,4 +346,5 @@
 	namespace {
 		DeclarationWithType * getCalledFunction( Expression * expr );
+		const ast::DeclWithType * getCalledFunction( const ast::Expr * expr );
 
 		template<typename CallExpr>
@@ -355,4 +356,14 @@
 			return getCalledFunction( expr->get_args().front() );
 		}
+
+		template<typename CallExpr>
+		const ast::DeclWithType * handleDerefCalledFunction( const CallExpr * expr ) {
+			// (*f)(x) => should get "f"
+			std::string name = getFunctionName( expr );
+			assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );
+			assertf( ! expr->args.empty(), "Cannot get called function from dereference with no arguments" );
+			return getCalledFunction( expr->args.front() );
+		}
+
 
 		DeclarationWithType * getCalledFunction( Expression * expr ) {
@@ -375,4 +386,24 @@
 			return nullptr;
 		}
+
+		const ast::DeclWithType * getCalledFunction( const ast::Expr * expr ) {
+			assert( expr );
+			if ( const ast::VariableExpr * varExpr = dynamic_cast< const ast::VariableExpr * >( expr ) ) {
+				return varExpr->var;
+			} else if ( const ast::MemberExpr * memberExpr = dynamic_cast< const ast::MemberExpr * >( expr ) ) {
+				return memberExpr->member;
+			} else if ( const ast::CastExpr * castExpr = dynamic_cast< const ast::CastExpr * >( expr ) ) {
+				return getCalledFunction( castExpr->arg );
+			} else if ( const ast::UntypedExpr * untypedExpr = dynamic_cast< const ast::UntypedExpr * >( expr ) ) {
+				return handleDerefCalledFunction( untypedExpr );
+			} else if ( const ast::ApplicationExpr * appExpr = dynamic_cast< const ast::ApplicationExpr * > ( expr ) ) {
+				return handleDerefCalledFunction( appExpr );
+			} else if ( const ast::AddressExpr * addrExpr = dynamic_cast< const ast::AddressExpr * >( expr ) ) {
+				return getCalledFunction( addrExpr->arg );
+			} else if ( const ast::CommaExpr * commaExpr = dynamic_cast< const ast::CommaExpr * >( expr ) ) {
+				return getCalledFunction( commaExpr->arg2 );
+			}
+			return nullptr;
+		}
 	}
 
@@ -382,4 +413,13 @@
 		} else if ( UntypedExpr * untyped = dynamic_cast< UntypedExpr * > ( expr ) ) {
 			return getCalledFunction( untyped->get_function() );
+		}
+		assertf( false, "getFunction received unknown expression: %s", toString( expr ).c_str() );
+	}
+
+	const ast::DeclWithType * getFunction( const ast::Expr * expr ) {
+		if ( const ast::ApplicationExpr * appExpr = dynamic_cast< const ast::ApplicationExpr * >( expr ) ) {
+			return getCalledFunction( appExpr->func );
+		} else if ( const ast::UntypedExpr * untyped = dynamic_cast< const ast::UntypedExpr * > ( expr ) ) {
+			return getCalledFunction( untyped->func );
 		}
 		assertf( false, "getFunction received unknown expression: %s", toString( expr ).c_str() );
@@ -434,16 +474,16 @@
 		}
 
-		// template<typename CallExpr>
-		// const ast::Expr * callArg( const CallExpr * call, unsigned int pos ) {
-		// 	if( pos >= call->args.size() ) {
-		// 		assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.",
-		// 			pos, toString( call ).c_str() );
-		// 	}
-		// 	for ( const ast::Expr * arg : call->args ) {
-		// 		if ( pos == 0 ) return arg;
-		// 		--pos;
-		// 	}
-		// 	assert( false );
-		// }
+		template<typename CallExpr>
+		const ast::Expr * callArg( const CallExpr * call, unsigned int pos ) {
+			if( pos >= call->args.size() ) {
+				assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.",
+					pos, toString( call ).c_str() );
+			}
+			for ( const ast::Expr * arg : call->args ) {
+				if ( pos == 0 ) return arg;
+				--pos;
+			}
+			assert( false );
+		}
 	}
 
@@ -466,30 +506,28 @@
 		}
 	}
+
 	const ast::Expr * getCallArg( const ast::Expr * call, unsigned pos ) {
-		(void)call;
-		(void)pos;
-		#warning unimplemented; needs to build AST/Expr.cpp
-		assertf(false, "unimplemented; needs to build AST/Expr.cpp");
-		// if ( auto app = dynamic_cast< const ast::ApplicationExpr * >( call ) ) {
-		// 	return callArg( app, pos );
-		// } else if ( auto untyped = dynamic_cast< const ast::UntypedExpr * >( call ) ) {
-		// 	return callArg( untyped, pos );
-		// } else if ( auto tupleAssn = dynamic_cast< const ast::TupleAssignExpr * >( call ) ) {
-		// 	const std::list<ast::ptr<ast::Stmt>>& stmts = tupleAssn->stmtExpr->stmts->kids;
-		// 	assertf( ! stmts.empty(), "TupleAssignExpr missing statements." );
-		// 	const ExprStmt * stmt = strict_dynamic_cast< const ast::ExprStmt * >( stmts.back() );
-		// 	const TupleExpr * tuple = strict_dynamic_cast< const ast::TupleExpr * >( stmt->expr );
-		// 	assertf( ! tuple->exprs.empty(), "TupleAssignExpr has empty tuple expr.");
-		// 	return getCallArg( tuple->exprs.front(), pos );
-		// } else if ( auto ctor = dynamic_cast< const ast::ImplicitCopyCtorExpr * >( call ) ) {
-		// 	return getCallArg( ctor->callExpr, pos );
-		// } else {
-		// 	assertf( false, "Unexpected expression type passed to getCallArg: %s",
-		// 		toString( call ).c_str() );
-		// }
+		if ( auto app = dynamic_cast< const ast::ApplicationExpr * >( call ) ) {
+			return callArg( app, pos );
+		} else if ( auto untyped = dynamic_cast< const ast::UntypedExpr * >( call ) ) {
+			return callArg( untyped, pos );
+		} else if ( auto tupleAssn = dynamic_cast< const ast::TupleAssignExpr * >( call ) ) {
+			const std::list<ast::ptr<ast::Stmt>>& stmts = tupleAssn->stmtExpr->stmts->kids;
+			assertf( ! stmts.empty(), "TupleAssignExpr missing statements." );
+			auto stmt  = strict_dynamic_cast< const ast::ExprStmt * >( stmts.back().get() );
+			auto tuple = strict_dynamic_cast< const ast::TupleExpr * >( stmt->expr.get() );
+			assertf( ! tuple->exprs.empty(), "TupleAssignExpr has empty tuple expr.");
+			return getCallArg( tuple->exprs.front(), pos );
+		} else if ( auto ctor = dynamic_cast< const ast::ImplicitCopyCtorExpr * >( call ) ) {
+			return getCallArg( ctor->callExpr, pos );
+		} else {
+			assertf( false, "Unexpected expression type passed to getCallArg: %s",
+				toString( call ).c_str() );
+		}
 	}
 
 	namespace {
 		std::string funcName( Expression * func );
+		std::string funcName( const ast::Expr * func );
 
 		template<typename CallExpr>
@@ -500,4 +538,13 @@
 			assertf( ! expr->get_args().empty(), "Cannot get function name from dereference with no arguments" );
 			return funcName( expr->get_args().front() );
+		}
+
+		template<typename CallExpr>
+		std::string handleDerefName( const CallExpr * expr ) {
+			// (*f)(x) => should get name "f"
+			std::string name = getFunctionName( expr );
+			assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );
+			assertf( ! expr->args.empty(), "Cannot get function name from dereference with no arguments" );
+			return funcName( expr->args.front() );
 		}
 
@@ -523,4 +570,26 @@
 			}
 		}
+
+		std::string funcName( const ast::Expr * func ) {
+			if ( const ast::NameExpr * nameExpr = dynamic_cast< const ast::NameExpr * >( func ) ) {
+				return nameExpr->name;
+			} else if ( const ast::VariableExpr * varExpr = dynamic_cast< const ast::VariableExpr * >( func ) ) {
+				return varExpr->var->name;
+			}	else if ( const ast::CastExpr * castExpr = dynamic_cast< const ast::CastExpr * >( func ) ) {
+				return funcName( castExpr->arg );
+			} else if ( const ast::MemberExpr * memberExpr = dynamic_cast< const ast::MemberExpr * >( func ) ) {
+				return memberExpr->member->name;
+			} else if ( const ast::UntypedMemberExpr * memberExpr = dynamic_cast< const ast::UntypedMemberExpr * > ( func ) ) {
+				return funcName( memberExpr->member );
+			} else if ( const ast::UntypedExpr * untypedExpr = dynamic_cast< const ast::UntypedExpr * >( func ) ) {
+				return handleDerefName( untypedExpr );
+			} else if ( const ast::ApplicationExpr * appExpr = dynamic_cast< const ast::ApplicationExpr * >( func ) ) {
+				return handleDerefName( appExpr );
+			} else if ( const ast::ConstructorExpr * ctorExpr = dynamic_cast< const ast::ConstructorExpr * >( func ) ) {
+				return funcName( getCallArg( ctorExpr->callExpr, 0 ) );
+			} else {
+				assertf( false, "Unexpected expression type being called as a function in call expression: %s", toString( func ).c_str() );
+			}
+		}
 	}
 
@@ -539,4 +608,18 @@
 	}
 
+	std::string getFunctionName( const ast::Expr * expr ) {
+		// there's some unforunate overlap here with getCalledFunction. Ideally this would be able to use getCalledFunction and
+		// return the name of the DeclarationWithType, but this needs to work for NameExpr and UntypedMemberExpr, where getCalledFunction
+		// can't possibly do anything reasonable.
+		if ( const ast::ApplicationExpr * appExpr = dynamic_cast< const ast::ApplicationExpr * >( expr ) ) {
+			return funcName( appExpr->func );
+		} else if ( const ast::UntypedExpr * untypedExpr = dynamic_cast< const ast::UntypedExpr * > ( expr ) ) {
+			return funcName( untypedExpr->func );
+		} else {
+			std::cerr << expr << std::endl;
+			assertf( false, "Unexpected expression type passed to getFunctionName" );
+		}
+	}
+
 	Type * getPointerBase( Type * type ) {
 		if ( PointerType * ptrType = dynamic_cast< PointerType * >( type ) ) {
@@ -551,14 +634,11 @@
 	}
 	const ast::Type* getPointerBase( const ast::Type* t ) {
-		(void)t;
-		#warning needs to build Type.cpp before inclusion
-		assertf(false, "needs to build Type.cpp before inclusion");
-		// if ( const auto * p = dynamic_cast< const ast::PointerType * >( t ) ) {
-		// 	return p->base;
-		// } else if ( const auto * a = dynamic_cast< const ast::ArrayType * >( t ) ) {
-		// 	return a->base;
-		// } else if ( const auto * r = dynamic_cast< const ast::ReferenceType * >( t ) ) {
-		// 	return r->base;
-		// } else return nullptr;
+		if ( const auto * p = dynamic_cast< const ast::PointerType * >( t ) ) {
+			return p->base;
+		} else if ( const auto * a = dynamic_cast< const ast::ArrayType * >( t ) ) {
+			return a->base;
+		} else if ( const auto * r = dynamic_cast< const ast::ReferenceType * >( t ) ) {
+			return r->base;
+		} else return nullptr;
 	}
 
Index: src/InitTweak/InitTweak.h
===================================================================
--- src/InitTweak/InitTweak.h	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/InitTweak/InitTweak.h	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -58,4 +58,5 @@
 	/// returns the declaration of the function called by the expr (must be ApplicationExpr or UntypedExpr)
 	DeclarationWithType * getFunction( Expression * expr );
+	const ast::DeclWithType * getFunction( const ast::Expr * expr );
 
 	/// Non-Null if expr is a call expression whose target function is intrinsic
@@ -78,4 +79,5 @@
 	/// returns the name of the function being called
 	std::string getFunctionName( Expression * expr );
+	std::string getFunctionName( const ast::Expr * expr );
 
 	/// returns the argument to a call expression in position N indexed from 0
Index: src/Makefile.am
===================================================================
--- src/Makefile.am	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/Makefile.am	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -37,4 +37,5 @@
 endif
 
+include AST/module.mk
 include CodeGen/module.mk
 include CodeTools/module.mk
Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/Makefile.in	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -16,4 +16,7 @@
 
 ######################## -*- Mode: Makefile-Automake -*- ######################
+###############################################################################
+
+######################### -*- Mode: Makefile-Gmake -*- ########################
 ###############################################################################
 
@@ -162,18 +165,25 @@
 libdemangle_a_LIBADD =
 am__dirstamp = $(am__leading_dot)dirstamp
-am__objects_1 = CodeGen/CodeGenerator.$(OBJEXT) \
+am__objects_1 = AST/Attribute.$(OBJEXT) AST/Convert.$(OBJEXT) \
+	AST/Decl.$(OBJEXT) AST/DeclReplacer.$(OBJEXT) \
+	AST/Expr.$(OBJEXT) AST/GenericSubstitution.$(OBJEXT) \
+	AST/Init.$(OBJEXT) AST/LinkageSpec.$(OBJEXT) \
+	AST/Node.$(OBJEXT) AST/Pass.$(OBJEXT) AST/Print.$(OBJEXT) \
+	AST/Stmt.$(OBJEXT) AST/Type.$(OBJEXT) \
+	AST/TypeSubstitution.$(OBJEXT)
+am__objects_2 = CodeGen/CodeGenerator.$(OBJEXT) \
 	CodeGen/FixMain.$(OBJEXT) CodeGen/GenType.$(OBJEXT) \
 	CodeGen/OperatorTable.$(OBJEXT)
-am__objects_2 = Common/Assert.$(OBJEXT) Common/Eval.$(OBJEXT) \
+am__objects_3 = Common/Assert.$(OBJEXT) Common/Eval.$(OBJEXT) \
 	Common/PassVisitor.$(OBJEXT) Common/SemanticError.$(OBJEXT) \
 	Common/Stats/Counter.$(OBJEXT) Common/Stats/Heap.$(OBJEXT) \
 	Common/Stats/Stats.$(OBJEXT) Common/Stats/Time.$(OBJEXT) \
 	Common/UniqueName.$(OBJEXT)
-am__objects_3 = ControlStruct/ForExprMutator.$(OBJEXT) \
+am__objects_4 = ControlStruct/ForExprMutator.$(OBJEXT) \
 	ControlStruct/LabelFixer.$(OBJEXT) \
 	ControlStruct/LabelGenerator.$(OBJEXT) \
 	ControlStruct/MLEMutator.$(OBJEXT) \
 	ControlStruct/Mutate.$(OBJEXT)
-am__objects_4 = ResolvExpr/AdjustExprType.$(OBJEXT) \
+am__objects_5 = ResolvExpr/AdjustExprType.$(OBJEXT) \
 	ResolvExpr/Alternative.$(OBJEXT) \
 	ResolvExpr/AlternativeFinder.$(OBJEXT) \
@@ -193,8 +203,8 @@
 	ResolvExpr/TypeEnvironment.$(OBJEXT) \
 	ResolvExpr/Unify.$(OBJEXT)
-am__objects_5 = SymTab/Autogen.$(OBJEXT) SymTab/FixFunction.$(OBJEXT) \
+am__objects_6 = SymTab/Autogen.$(OBJEXT) SymTab/FixFunction.$(OBJEXT) \
 	SymTab/Indexer.$(OBJEXT) SymTab/Mangler.$(OBJEXT) \
 	SymTab/ManglerCommon.$(OBJEXT) SymTab/Validate.$(OBJEXT)
-am__objects_6 = SynTree/Type.$(OBJEXT) SynTree/VoidType.$(OBJEXT) \
+am__objects_7 = SynTree/Type.$(OBJEXT) SynTree/VoidType.$(OBJEXT) \
 	SynTree/BasicType.$(OBJEXT) SynTree/PointerType.$(OBJEXT) \
 	SynTree/ArrayType.$(OBJEXT) SynTree/ReferenceType.$(OBJEXT) \
@@ -216,26 +226,26 @@
 	SynTree/TypeSubstitution.$(OBJEXT) SynTree/Attribute.$(OBJEXT) \
 	SynTree/DeclReplacer.$(OBJEXT)
-am__objects_7 = CompilationState.$(OBJEXT) $(am__objects_1) \
-	Concurrency/Keywords.$(OBJEXT) $(am__objects_2) \
-	$(am__objects_3) GenPoly/GenPoly.$(OBJEXT) \
+am__objects_8 = CompilationState.$(OBJEXT) $(am__objects_1) \
+	$(am__objects_2) Concurrency/Keywords.$(OBJEXT) \
+	$(am__objects_3) $(am__objects_4) GenPoly/GenPoly.$(OBJEXT) \
 	GenPoly/Lvalue.$(OBJEXT) InitTweak/GenInit.$(OBJEXT) \
 	InitTweak/InitTweak.$(OBJEXT) Parser/LinkageSpec.$(OBJEXT) \
-	$(am__objects_4) $(am__objects_5) SymTab/Demangle.$(OBJEXT) \
-	$(am__objects_6) Tuples/TupleAssignment.$(OBJEXT) \
+	$(am__objects_5) $(am__objects_6) SymTab/Demangle.$(OBJEXT) \
+	$(am__objects_7) Tuples/TupleAssignment.$(OBJEXT) \
 	Tuples/TupleExpansion.$(OBJEXT) Tuples/Explode.$(OBJEXT) \
 	Validate/HandleAttributes.$(OBJEXT) \
 	Validate/FindSpecialDecls.$(OBJEXT)
-am_libdemangle_a_OBJECTS = $(am__objects_7)
+am_libdemangle_a_OBJECTS = $(am__objects_8)
 libdemangle_a_OBJECTS = $(am_libdemangle_a_OBJECTS)
 am__installdirs = "$(DESTDIR)$(cfa_cpplibdir)"
 PROGRAMS = $(cfa_cpplib_PROGRAMS)
-am__objects_8 = main.$(OBJEXT) MakeLibCfa.$(OBJEXT) \
-	CompilationState.$(OBJEXT) $(am__objects_1) \
+am__objects_9 = main.$(OBJEXT) MakeLibCfa.$(OBJEXT) \
+	CompilationState.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
 	CodeGen/Generate.$(OBJEXT) CodeGen/FixNames.$(OBJEXT) \
 	CodeTools/DeclStats.$(OBJEXT) \
 	CodeTools/ResolvProtoDump.$(OBJEXT) \
 	CodeTools/TrackLoc.$(OBJEXT) Concurrency/Keywords.$(OBJEXT) \
-	Concurrency/Waitfor.$(OBJEXT) $(am__objects_2) \
-	Common/DebugMalloc.$(OBJEXT) $(am__objects_3) \
+	Concurrency/Waitfor.$(OBJEXT) $(am__objects_3) \
+	Common/DebugMalloc.$(OBJEXT) $(am__objects_4) \
 	ControlStruct/ExceptTranslate.$(OBJEXT) GenPoly/Box.$(OBJEXT) \
 	GenPoly/GenPoly.$(OBJEXT) GenPoly/ScrubTyVars.$(OBJEXT) \
@@ -251,6 +261,6 @@
 	Parser/InitializerNode.$(OBJEXT) Parser/TypeData.$(OBJEXT) \
 	Parser/LinkageSpec.$(OBJEXT) Parser/parserutility.$(OBJEXT) \
-	$(am__objects_4) ResolvExpr/AlternativePrinter.$(OBJEXT) \
-	$(am__objects_5) $(am__objects_6) \
+	$(am__objects_5) ResolvExpr/AlternativePrinter.$(OBJEXT) \
+	$(am__objects_6) $(am__objects_7) \
 	Tuples/TupleAssignment.$(OBJEXT) \
 	Tuples/TupleExpansion.$(OBJEXT) Tuples/Explode.$(OBJEXT) \
@@ -258,5 +268,5 @@
 	Validate/FindSpecialDecls.$(OBJEXT) \
 	Virtual/ExpandCasts.$(OBJEXT)
-am____driver_cfa_cpp_OBJECTS = $(am__objects_8)
+am____driver_cfa_cpp_OBJECTS = $(am__objects_9)
 ___driver_cfa_cpp_OBJECTS = $(am____driver_cfa_cpp_OBJECTS)
 am__DEPENDENCIES_1 =
@@ -368,5 +378,5 @@
 ETAGS = etags
 CTAGS = ctags
-am__DIST_COMMON = $(srcdir)/CodeGen/module.mk \
+am__DIST_COMMON = $(srcdir)/AST/module.mk $(srcdir)/CodeGen/module.mk \
 	$(srcdir)/CodeTools/module.mk $(srcdir)/Common/module.mk \
 	$(srcdir)/Concurrency/module.mk \
@@ -528,25 +538,26 @@
 AUTOMAKE_OPTIONS = foreign subdir-objects
 ACLOCAL_AMFLAGS = -I automake
-SRC = main.cc MakeLibCfa.cc CompilationState.cc $(SRC_CODEGEN) \
-	CodeGen/Generate.cc CodeGen/FixNames.cc CodeTools/DeclStats.cc \
-	CodeTools/ResolvProtoDump.cc CodeTools/TrackLoc.cc \
-	Concurrency/Keywords.cc Concurrency/Waitfor.cc $(SRC_COMMON) \
-	Common/DebugMalloc.cc $(SRC_CONTROLSTRUCT) \
-	ControlStruct/ExceptTranslate.cc GenPoly/Box.cc \
-	GenPoly/GenPoly.cc GenPoly/ScrubTyVars.cc GenPoly/Lvalue.cc \
-	GenPoly/Specialize.cc GenPoly/FindFunction.cc \
-	GenPoly/InstantiateGeneric.cc InitTweak/GenInit.cc \
-	InitTweak/FixInit.cc InitTweak/FixGlobalInit.cc \
-	InitTweak/InitTweak.cc Parser/parser.yy Parser/lex.ll \
-	Parser/TypedefTable.cc Parser/ParseNode.cc \
-	Parser/DeclarationNode.cc Parser/ExpressionNode.cc \
-	Parser/StatementNode.cc Parser/InitializerNode.cc \
-	Parser/TypeData.cc Parser/LinkageSpec.cc \
-	Parser/parserutility.cc $(SRC_RESOLVEXPR) \
-	ResolvExpr/AlternativePrinter.cc $(SRC_SYMTAB) $(SRC_SYNTREE) \
-	Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc \
-	Tuples/Explode.cc Validate/HandleAttributes.cc \
-	Validate/FindSpecialDecls.cc Virtual/ExpandCasts.cc
-SRCDEMANGLE = CompilationState.cc $(SRC_CODEGEN) \
+SRC = main.cc MakeLibCfa.cc CompilationState.cc $(SRC_AST) \
+	$(SRC_CODEGEN) CodeGen/Generate.cc CodeGen/FixNames.cc \
+	CodeTools/DeclStats.cc CodeTools/ResolvProtoDump.cc \
+	CodeTools/TrackLoc.cc Concurrency/Keywords.cc \
+	Concurrency/Waitfor.cc $(SRC_COMMON) Common/DebugMalloc.cc \
+	$(SRC_CONTROLSTRUCT) ControlStruct/ExceptTranslate.cc \
+	GenPoly/Box.cc GenPoly/GenPoly.cc GenPoly/ScrubTyVars.cc \
+	GenPoly/Lvalue.cc GenPoly/Specialize.cc \
+	GenPoly/FindFunction.cc GenPoly/InstantiateGeneric.cc \
+	InitTweak/GenInit.cc InitTweak/FixInit.cc \
+	InitTweak/FixGlobalInit.cc InitTweak/InitTweak.cc \
+	Parser/parser.yy Parser/lex.ll Parser/TypedefTable.cc \
+	Parser/ParseNode.cc Parser/DeclarationNode.cc \
+	Parser/ExpressionNode.cc Parser/StatementNode.cc \
+	Parser/InitializerNode.cc Parser/TypeData.cc \
+	Parser/LinkageSpec.cc Parser/parserutility.cc \
+	$(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc \
+	$(SRC_SYMTAB) $(SRC_SYNTREE) Tuples/TupleAssignment.cc \
+	Tuples/TupleExpansion.cc Tuples/Explode.cc \
+	Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc \
+	Virtual/ExpandCasts.cc
+SRCDEMANGLE = CompilationState.cc $(SRC_AST) $(SRC_CODEGEN) \
 	Concurrency/Keywords.cc $(SRC_COMMON) $(SRC_CONTROLSTRUCT) \
 	GenPoly/GenPoly.cc GenPoly/Lvalue.cc InitTweak/GenInit.cc \
@@ -562,4 +573,20 @@
 @WITH_LIBTCMALLOC_TRUE@LIBTCMALLOC = -ltcmalloc
 @WITH_LIBTCMALLOC_TRUE@TCMALLOCFLAG = -DTCMALLOC
+SRC_AST = \
+	AST/Attribute.cpp \
+	AST/Convert.cpp \
+	AST/Decl.cpp \
+	AST/DeclReplacer.cpp \
+	AST/Expr.cpp \
+	AST/GenericSubstitution.cpp \
+	AST/Init.cpp \
+	AST/LinkageSpec.cpp \
+	AST/Node.cpp \
+	AST/Pass.cpp \
+	AST/Print.cpp \
+	AST/Stmt.cpp \
+	AST/Type.cpp \
+	AST/TypeSubstitution.cpp
+
 SRC_CODEGEN = \
 	CodeGen/CodeGenerator.cc \
@@ -670,6 +697,6 @@
 
 .SUFFIXES:
-.SUFFIXES: .cc .ll .lo .o .obj .yy
-$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(srcdir)/CodeGen/module.mk $(srcdir)/CodeTools/module.mk $(srcdir)/Concurrency/module.mk $(srcdir)/Common/module.mk $(srcdir)/ControlStruct/module.mk $(srcdir)/GenPoly/module.mk $(srcdir)/InitTweak/module.mk $(srcdir)/Parser/module.mk $(srcdir)/ResolvExpr/module.mk $(srcdir)/SymTab/module.mk $(srcdir)/SynTree/module.mk $(srcdir)/Tuples/module.mk $(srcdir)/Validate/module.mk $(srcdir)/Virtual/module.mk $(am__configure_deps)
+.SUFFIXES: .cc .cpp .ll .lo .o .obj .yy
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(srcdir)/AST/module.mk $(srcdir)/CodeGen/module.mk $(srcdir)/CodeTools/module.mk $(srcdir)/Concurrency/module.mk $(srcdir)/Common/module.mk $(srcdir)/ControlStruct/module.mk $(srcdir)/GenPoly/module.mk $(srcdir)/InitTweak/module.mk $(srcdir)/Parser/module.mk $(srcdir)/ResolvExpr/module.mk $(srcdir)/SymTab/module.mk $(srcdir)/SynTree/module.mk $(srcdir)/Tuples/module.mk $(srcdir)/Validate/module.mk $(srcdir)/Virtual/module.mk $(am__configure_deps)
 	@for dep in $?; do \
 	  case '$(am__configure_deps)' in \
@@ -691,5 +718,5 @@
 	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
 	esac;
-$(srcdir)/CodeGen/module.mk $(srcdir)/CodeTools/module.mk $(srcdir)/Concurrency/module.mk $(srcdir)/Common/module.mk $(srcdir)/ControlStruct/module.mk $(srcdir)/GenPoly/module.mk $(srcdir)/InitTweak/module.mk $(srcdir)/Parser/module.mk $(srcdir)/ResolvExpr/module.mk $(srcdir)/SymTab/module.mk $(srcdir)/SynTree/module.mk $(srcdir)/Tuples/module.mk $(srcdir)/Validate/module.mk $(srcdir)/Virtual/module.mk $(am__empty):
+$(srcdir)/AST/module.mk $(srcdir)/CodeGen/module.mk $(srcdir)/CodeTools/module.mk $(srcdir)/Concurrency/module.mk $(srcdir)/Common/module.mk $(srcdir)/ControlStruct/module.mk $(srcdir)/GenPoly/module.mk $(srcdir)/InitTweak/module.mk $(srcdir)/Parser/module.mk $(srcdir)/ResolvExpr/module.mk $(srcdir)/SymTab/module.mk $(srcdir)/SynTree/module.mk $(srcdir)/Tuples/module.mk $(srcdir)/Validate/module.mk $(srcdir)/Virtual/module.mk $(am__empty):
 
 $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
@@ -704,4 +731,30 @@
 clean-noinstLIBRARIES:
 	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+AST/$(am__dirstamp):
+	@$(MKDIR_P) AST
+	@: > AST/$(am__dirstamp)
+AST/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) AST/$(DEPDIR)
+	@: > AST/$(DEPDIR)/$(am__dirstamp)
+AST/Attribute.$(OBJEXT): AST/$(am__dirstamp) \
+	AST/$(DEPDIR)/$(am__dirstamp)
+AST/Convert.$(OBJEXT): AST/$(am__dirstamp) \
+	AST/$(DEPDIR)/$(am__dirstamp)
+AST/Decl.$(OBJEXT): AST/$(am__dirstamp) AST/$(DEPDIR)/$(am__dirstamp)
+AST/DeclReplacer.$(OBJEXT): AST/$(am__dirstamp) \
+	AST/$(DEPDIR)/$(am__dirstamp)
+AST/Expr.$(OBJEXT): AST/$(am__dirstamp) AST/$(DEPDIR)/$(am__dirstamp)
+AST/GenericSubstitution.$(OBJEXT): AST/$(am__dirstamp) \
+	AST/$(DEPDIR)/$(am__dirstamp)
+AST/Init.$(OBJEXT): AST/$(am__dirstamp) AST/$(DEPDIR)/$(am__dirstamp)
+AST/LinkageSpec.$(OBJEXT): AST/$(am__dirstamp) \
+	AST/$(DEPDIR)/$(am__dirstamp)
+AST/Node.$(OBJEXT): AST/$(am__dirstamp) AST/$(DEPDIR)/$(am__dirstamp)
+AST/Pass.$(OBJEXT): AST/$(am__dirstamp) AST/$(DEPDIR)/$(am__dirstamp)
+AST/Print.$(OBJEXT): AST/$(am__dirstamp) AST/$(DEPDIR)/$(am__dirstamp)
+AST/Stmt.$(OBJEXT): AST/$(am__dirstamp) AST/$(DEPDIR)/$(am__dirstamp)
+AST/Type.$(OBJEXT): AST/$(am__dirstamp) AST/$(DEPDIR)/$(am__dirstamp)
+AST/TypeSubstitution.$(OBJEXT): AST/$(am__dirstamp) \
+	AST/$(DEPDIR)/$(am__dirstamp)
 CodeGen/$(am__dirstamp):
 	@$(MKDIR_P) CodeGen
@@ -1102,4 +1155,5 @@
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
+	-rm -f AST/*.$(OBJEXT)
 	-rm -f CodeGen/*.$(OBJEXT)
 	-rm -f CodeTools/*.$(OBJEXT)
@@ -1124,4 +1178,18 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MakeLibCfa.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Attribute.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Convert.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Decl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/DeclReplacer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Expr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/GenericSubstitution.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Init.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/LinkageSpec.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Node.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Pass.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Print.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Stmt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Type.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/TypeSubstitution.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@CodeGen/$(DEPDIR)/CodeGenerator.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@CodeGen/$(DEPDIR)/FixMain.Po@am__quote@
@@ -1267,4 +1335,28 @@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
 
+.cpp.o:
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@	$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
 .ll.cc:
 	$(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE)
@@ -1399,4 +1491,6 @@
 	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
 	-rm -f ../driver/$(am__dirstamp)
+	-rm -f AST/$(DEPDIR)/$(am__dirstamp)
+	-rm -f AST/$(am__dirstamp)
 	-rm -f CodeGen/$(DEPDIR)/$(am__dirstamp)
 	-rm -f CodeGen/$(am__dirstamp)
@@ -1444,5 +1538,5 @@
 
 distclean: distclean-am
-	-rm -rf ./$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Common/Stats/$(DEPDIR) Concurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR)
+	-rm -rf ./$(DEPDIR) AST/$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Common/Stats/$(DEPDIR) Concurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR)
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
@@ -1490,5 +1584,5 @@
 
 maintainer-clean: maintainer-clean-am
-	-rm -rf ./$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Common/Stats/$(DEPDIR) Concurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR)
+	-rm -rf ./$(DEPDIR) AST/$(DEPDIR) CodeGen/$(DEPDIR) CodeTools/$(DEPDIR) Common/$(DEPDIR) Common/Stats/$(DEPDIR) Concurrency/$(DEPDIR) ControlStruct/$(DEPDIR) GenPoly/$(DEPDIR) InitTweak/$(DEPDIR) Parser/$(DEPDIR) ResolvExpr/$(DEPDIR) SymTab/$(DEPDIR) SynTree/$(DEPDIR) Tuples/$(DEPDIR) Validate/$(DEPDIR) Virtual/$(DEPDIR)
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/ResolvExpr/Unify.cc	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -179,6 +179,6 @@
 				result = false;
 			} else {
-				result = env.bindVarToVar( 
-					var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions, 
+				result = env.bindVarToVar(
+					var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions,
 					haveAssertions, openVars, widenMode, indexer );
 			}
@@ -648,13 +648,12 @@
 
 	ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) {
-		assert(!"restore after AST added to build");
-		// if ( func->returns.empty() ) return new ast::VoidType{};
-		// if ( func->returns.size() == 1 ) return func->returns[0]->get_type();
-
-		// std::vector<ast::ptr<ast::Type>> tys;
-		// for ( const ast::DeclWithType * decl : func->returns ) {
-		// 	tys.emplace_back( decl->get_type() );
-		// }
-		// return new ast::TupleType{ std::move(tys) };
+		if ( func->returns.empty() ) return new ast::VoidType{};
+		if ( func->returns.size() == 1 ) return func->returns[0]->get_type();
+
+		std::vector<ast::ptr<ast::Type>> tys;
+		for ( const ast::DeclWithType * decl : func->returns ) {
+			tys.emplace_back( decl->get_type() );
+		}
+		return new ast::TupleType{ std::move(tys) };
 	}
 } // namespace ResolvExpr
Index: src/SynTree/Declaration.h
===================================================================
--- src/SynTree/Declaration.h	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/SynTree/Declaration.h	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -286,5 +286,5 @@
 	AggregateDecl * set_body( bool body ) { AggregateDecl::body = body; return this; }
 
-	virtual void print( std::ostream &os, Indenter indent = {} ) const override;
+	virtual void print( std::ostream &os, Indenter indent = {} ) const override final;
 	virtual void printShort( std::ostream &os, Indenter indent = {} ) const override;
   protected:
Index: src/SynTree/Expression.h
===================================================================
--- src/SynTree/Expression.h	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/SynTree/Expression.h	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -731,4 +731,8 @@
 	virtual Expression * acceptMutator( Mutator & m ) { return m.mutate( this ); }
 	virtual void print( std::ostream & os, Indenter indent = {} ) const;
+
+	friend class ConverterNewToOld;
+  private:
+    TupleAssignExpr( StmtExpr * stmts );
 };
 
Index: src/SynTree/TupleExpr.cc
===================================================================
--- src/SynTree/TupleExpr.cc	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/SynTree/TupleExpr.cc	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -105,4 +105,10 @@
 }
 
+TupleAssignExpr::TupleAssignExpr( 
+	StmtExpr * s )
+: Expression(), stmtExpr(s) {
+}
+
+
 TupleAssignExpr::~TupleAssignExpr() {
 	delete stmtExpr;
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/Tuples/TupleExpansion.cc	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -320,26 +320,23 @@
 	}
 	const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) {
-		(void) exprs;
-		#warning Not implemented; needs Type.cpp in build
-		assertf(false, "Not implemented; needs Type.cpp in build");
-		// // produce the TupleType which aggregates the types of the exprs
-		// std::vector<ast::ptr<ast::Type>> types;
-		// ast::CV::Qualifiers quals{
-		// 	ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Lvalue |
-		// 	ast::CV::Atomic | ast::CV::Mutex };
-
-		// for ( const ast::Expr * expr : exprs ) {
-		// 	assert( expr->result );
-		// 	// if the type of any expr is void, the type of the entire tuple is void
-		// 	if ( expr->result->isVoid() ) return new ast::VoidType{};
-
-		// 	// qualifiers on the tuple type are the qualifiers that exist on all components
-		// 	quals &= expr->result->qualifiers;
-
-		// 	types.emplace_back( expr->result );
-		// }
-
-		// if ( exprs.empty() ) { quals = ast::CV::Qualifiers{}; }
-		// return new ast::TupleType{ std::move(types), quals };
+		// produce the TupleType which aggregates the types of the exprs
+		std::vector<ast::ptr<ast::Type>> types;
+		ast::CV::Qualifiers quals{
+			ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Lvalue |
+			ast::CV::Atomic | ast::CV::Mutex };
+
+		for ( const ast::Expr * expr : exprs ) {
+			assert( expr->result );
+			// if the type of any expr is void, the type of the entire tuple is void
+			if ( expr->result->isVoid() ) return new ast::VoidType{};
+
+			// qualifiers on the tuple type are the qualifiers that exist on all components
+			quals &= expr->result->qualifiers;
+
+			types.emplace_back( expr->result );
+		}
+
+		if ( exprs.empty() ) { quals = ast::CV::Qualifiers{}; }
+		return new ast::TupleType{ std::move(types), quals };
 	}
 
@@ -347,4 +344,13 @@
 		if ( TypeInstType * inst = dynamic_cast< TypeInstType * >( type ) ) {
 			if ( inst->get_baseType() && inst->get_baseType()->get_kind() == TypeDecl::Ttype ) {
+				return inst;
+			}
+		}
+		return nullptr;
+	}
+
+	const ast::TypeInstType * isTtype( const ast::Type * type ) {
+		if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
+			if ( inst->base && inst->base->kind == ast::TypeVar::Ttype ) {
 				return inst;
 			}
Index: src/include/cassert
===================================================================
--- src/include/cassert	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/include/cassert	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -9,7 +9,7 @@
 // Author           : Peter A. Buhr
 // Created On       : Thu Aug 18 13:19:26 2016
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Aug  1 11:56:01 2017
-// Update Count     : 16
+// Last Modified By : Andrew Beach
+// Last Modified On : Thu May 23 15:30:00 2017
+// Update Count     : 17
 //
 
@@ -19,4 +19,9 @@
 
 #include_next <cassert>
+
+#include <string>
+
+template < typename ... Params >
+std::string toString( const Params & ... params );
 
 #ifdef NDEBUG
@@ -38,6 +43,12 @@
 #endif
 
-template<typename T, typename U>
+enum StrictAllowNull {NonNull, AllowNull};
+
+template<typename T, StrictAllowNull nullable = NonNull, typename U>
 static inline T strict_dynamic_cast( const U & src ) {
+	if (nullable == AllowNull && src == nullptr) {
+		return nullptr;
+	}
+	assert(src);
 	T ret = dynamic_cast<T>(src);
 	assertf(ret, "%s", toString(src).c_str());
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 933f32f2ae9703d54327e4727aceb5746433092d)
+++ src/main.cc	(revision d908563f67f11148f27b808eadf9cdd55d2df4e3)
@@ -40,5 +40,4 @@
 #include "Common/Stats.h"
 #include "Common/PassVisitor.h"
-// #include "AST/Pass.hpp"
 #include "Common/SemanticError.h"           // for SemanticError
 #include "Common/UnimplementedError.h"      // for UnimplementedError
