Index: src/AST/Attribute.cpp
===================================================================
--- src/AST/Attribute.cpp	(revision b0ec9711a35db17d11fd4733884f1d7ba52d3b68)
+++ src/AST/Attribute.cpp	(revision 68c9165ba8977f22fd2ed8d7175c671e03359a1a)
@@ -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/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision b0ec9711a35db17d11fd4733884f1d7ba52d3b68)
+++ src/AST/Convert.cpp	(revision 68c9165ba8977f22fd2ed8d7175c671e03359a1a)
@@ -1130,5 +1130,5 @@
 	const ast::Type * visit( const ast::FunctionType * node ) override final {
 		auto ty = new FunctionType {
-			cv( node ), 
+			cv( node ),
 			(bool)node->isVarArgs
 		};
@@ -1338,4 +1338,5 @@
 		// 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;
 	}
@@ -1409,5 +1410,5 @@
 #	define GET_LABELS_V(labels) \
 		to<std::vector>::from( make_labels( std::move( labels ) ) )
-	
+
 	static ast::CV::Qualifiers cv( Type * ty ) { return { ty->get_qualifiers().val }; }
 
@@ -1549,5 +1550,5 @@
 
 	virtual void visit( TypeDecl * old ) override final {
-		if ( inCache( old ) ) return;	
+		if ( inCache( old ) ) return;
 		auto decl = new ast::TypeDecl{
 			old->location,
@@ -1587,5 +1588,5 @@
 	virtual void visit( AsmDecl * old ) override final {
 		auto decl = new ast::AsmDecl{
-			old->location, 
+			old->location,
 			GET_ACCEPT_1(stmt, AsmStmt)
 		};
@@ -2142,6 +2143,6 @@
 			rslt = new ast::ConstantExpr(
 				old->location,
-				GET_ACCEPT_1(result, Type), 
-				old->constant.get_value(), 
+				GET_ACCEPT_1(result, Type),
+				old->constant.get_value(),
 				(double) old->constant.get_dval()
 			);
@@ -2163,5 +2164,5 @@
 			assert(!old->isType);
 			rslt = new ast::SizeofExpr(
-				old->location, 
+				old->location,
 				GET_ACCEPT_1(expr, Expr)
 			);
@@ -2170,5 +2171,5 @@
 			assert(old->isType);
 			rslt = new ast::SizeofExpr(
-				old->location, 
+				old->location,
 				GET_ACCEPT_1(type, Type)
 			);
@@ -2184,5 +2185,5 @@
 			assert(!old->isType);
 			rslt = new ast::AlignofExpr(
-				old->location, 
+				old->location,
 				GET_ACCEPT_1(expr, Expr)
 			);
@@ -2191,5 +2192,5 @@
 			assert(old->isType);
 			rslt = new ast::AlignofExpr(
-				old->location, 
+				old->location,
 				GET_ACCEPT_1(type, Type)
 			);
@@ -2235,5 +2236,5 @@
 				GET_ACCEPT_1(arg1, Expr),
 				GET_ACCEPT_1(arg2, Expr),
-				old->get_isAnd() ? 
+				old->get_isAnd() ?
 					ast::LogicalFlag::AndExpr :
 					ast::LogicalFlag::OrExpr
Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision b0ec9711a35db17d11fd4733884f1d7ba52d3b68)
+++ src/AST/Expr.cpp	(revision 68c9165ba8977f22fd2ed8d7175c671e03359a1a)
@@ -159,13 +159,10 @@
 	assert( aggregate->result );
 
-	#warning Needs GenericSubsitution.cpp building to work correctly
-	result.set_and_mutate( mem->get_type() )->qualifiers |= aggregate->result->qualifiers | CV::Lvalue;  // FIXME temporary patch
-
-	// // 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;
+	// 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;
 }
 
@@ -345,5 +342,5 @@
 }
 
-TupleAssignExpr::TupleAssignExpr( 
+TupleAssignExpr::TupleAssignExpr(
 	const CodeLocation & loc, const Type * result, const StmtExpr * s )
 : Expr( loc, result ), stmtExpr() {
Index: src/AST/GenericSubstitution.cpp
===================================================================
--- src/AST/GenericSubstitution.cpp	(revision b0ec9711a35db17d11fd4733884f1d7ba52d3b68)
+++ src/AST/GenericSubstitution.cpp	(revision 68c9165ba8977f22fd2ed8d7175c671e03359a1a)
@@ -23,5 +23,5 @@
 #include "Pass.hpp"
 #include "Type.hpp"
-#include "TypeSubstitution.cpp"
+#include "TypeSubstitution.hpp"
 
 namespace ast {
@@ -32,9 +32,9 @@
 
 		void previsit( const Type * ty ) {
-			assertf( false, "Attempted generic substitution for non-aggregate type: %s", 
+			assertf( false, "Attempted generic substitution for non-aggregate type: %s",
 				toString( ty ).c_str() );
 		}
 
-		void previsit( const ReferenceType * ty ) {
+		void previsit( const ReferenceType * ) {
 			// do nothing; allows substitution from base type
 		}
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision b0ec9711a35db17d11fd4733884f1d7ba52d3b68)
+++ src/AST/Pass.hpp	(revision 68c9165ba8977f22fd2ed8d7175c671e03359a1a)
@@ -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:
 
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision b0ec9711a35db17d11fd4733884f1d7ba52d3b68)
+++ src/AST/Pass.proto.hpp	(revision 68c9165ba8977f22fd2ed8d7175c671e03359a1a)
@@ -115,4 +115,24 @@
 		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;
+	};
+
+	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");
+		}
 	};
 
@@ -138,10 +158,10 @@
 			"Previsit may not change the type of the node. It must return its paremeter or void."
 		);
-		if(std::is_void< decltype( pass.previsit(node) ) >::value) {
-			pass.previsit( node );
-		} else {
-			node = pass.previsit( node );
-			assert(node);
-		}
+
+		__assign<
+			std::is_void<
+				decltype( pass.previsit( node ) )
+			>::value
+		>::result( pass, node );
 	}
 
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision b0ec9711a35db17d11fd4733884f1d7ba52d3b68)
+++ src/AST/Print.cpp	(revision 68c9165ba8977f22fd2ed8d7175c671e03359a1a)
@@ -22,5 +22,7 @@
 #include "TypeSubstitution.hpp"
 
-#include "Common/utility.h"      // for group_iterate
+#include "Common/utility.h" // for group_iterate
+
+using namespace std;
 
 namespace ast {
@@ -28,8 +30,8 @@
 template <typename C, typename... T>
 constexpr auto make_array(T&&... values) ->
-	std::array<C,sizeof...(T)>
+	array<C,sizeof...(T)>
 {
-	return std::array<C,sizeof...(T)>{
-		std::forward<T>(values)...
+	return array<C,sizeof...(T)>{
+		forward<T>(values)...
 	};
 }
@@ -37,8 +39,9 @@
 class Printer : public Visitor {
 public:
-	std::ostream & os;
+	ostream & os;
 	Indenter indent;
-
-	Printer(std::ostream & os, Indenter indent) : os( os ), indent( indent ) {}
+	bool short_mode;
+
+	Printer(ostream & os, Indenter indent, bool short_mode) : os( os ), indent( indent ), short_mode(short_mode) {}
 
 private:
@@ -51,5 +54,5 @@
 				// need an endl after each element because it's not
 				// easy to know when each individual item should end
-				os << std::endl;
+				os << endl;
 			} // if
 		} // for
@@ -74,5 +77,5 @@
 
 	template<typename storage_t, size_t N>
-	void print(const storage_t & storage, const std::array<const char *, N> & Names ) {
+	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 ) {
@@ -135,8 +138,64 @@
 		print( node->qualifiers );
 	}
+	
+	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
+	}
 
 public:
-	virtual const ast::DeclWithType *     visit( const ast::ObjectDecl           * node ) {
-		if ( node->name != "" ) os << node->name << ": ";
+	virtual const ast::DeclWithType * visit( const ast::ObjectDecl * node ) {
+		if ( !node->name.empty() ) os << node->name << ": ";
 
 		if ( node->linkage != Linkage::Cforall ) {
@@ -157,14 +216,14 @@
 					? "maybe constructed"
 					: "not constructed"
-				) << ")" << std::endl << indent+1;
+				) << ")" << endl << indent+1;
 
 			++indent;
 			node->init->accept( *this );
 			--indent;
-			os << std::endl;
+			os << endl;
 		} // if
 
 		if ( ! node->attributes.empty() ) {
-			os << std::endl << indent << "... with attributes:" << std::endl;
+			os << endl << indent << "... with attributes:" << endl;
 			++indent;
 			printAll( node->attributes );
@@ -179,269 +238,372 @@
 	}
 
-	virtual const ast::DeclWithType *     visit( const ast::FunctionDecl         * node ) {
-		return node;
-	}
-
-	virtual const ast::Decl *             visit( const ast::StructDecl           * node ) {
-		return node;
-	}
-
-	virtual const ast::Decl *             visit( const ast::UnionDecl            * node ) {
-		return node;
-	}
-
-	virtual const ast::Decl *             visit( const ast::EnumDecl             * node ) {
-		return node;
-	}
-
-	virtual const ast::Decl *             visit( const ast::TraitDecl            * node ) {
-		return node;
-	}
-
-	virtual const ast::Decl *             visit( const ast::TypeDecl             * node ) {
-		return node;
-	}
-
-	virtual const ast::Decl *             visit( const ast::TypedefDecl          * node ) {
-		return node;
-	}
-
-	virtual const ast::AsmDecl *          visit( const ast::AsmDecl              * node ) {
-		return node;
-	}
-
-	virtual const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl     * node ) {
-		return node;
-	}
-
-	virtual const ast::CompoundStmt *     visit( const ast::CompoundStmt         * node ) {
-		return node;
-	}
-
-	virtual const ast::Stmt *             visit( const ast::ExprStmt             * node ) {
-		return node;
-	}
-
-	virtual const ast::Stmt *             visit( const ast::AsmStmt              * node ) {
-		return node;
-	}
-
-	virtual const ast::Stmt *             visit( const ast::DirectiveStmt        * node ) {
-		return node;
-	}
-
-	virtual const ast::Stmt *             visit( const ast::IfStmt               * node ) {
-		return node;
-	}
-
-	virtual const ast::Stmt *             visit( const ast::WhileStmt            * node ) {
-		return node;
-	}
-
-	virtual const ast::Stmt *             visit( const ast::ForStmt              * node ) {
-		return node;
-	}
-
-	virtual const ast::Stmt *             visit( const ast::SwitchStmt           * node ) {
-		return node;
-	}
-
-	virtual const ast::Stmt *             visit( const ast::CaseStmt             * node ) {
-		return node;
-	}
-
-	virtual const ast::Stmt *             visit( const ast::BranchStmt           * node ) {
-		return node;
-	}
-
-	virtual const ast::Stmt *             visit( const ast::ReturnStmt           * node ) {
-		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 ) {
-		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 ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::UntypedExpr          * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::NameExpr             * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::AddressExpr          * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::LabelAddressExpr     * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::CastExpr             * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::KeywordCastExpr      * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::VirtualCastExpr      * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::UntypedMemberExpr    * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::MemberExpr           * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::VariableExpr         * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::ConstantExpr         * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::SizeofExpr           * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::AlignofExpr          * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::UntypedOffsetofExpr  * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::OffsetofExpr         * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::OffsetPackExpr       * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::LogicalExpr          * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::ConditionalExpr      * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::CommaExpr            * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::TypeExpr             * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::AsmExpr              * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::ImplicitCopyCtorExpr * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::ConstructorExpr      * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::CompoundLiteralExpr  * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::RangeExpr            * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::UntypedTupleExpr     * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::TupleExpr            * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::TupleIndexExpr       * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::TupleAssignExpr      * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::StmtExpr             * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::UniqueExpr           * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::UntypedInitExpr      * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::InitExpr             * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::DeletedExpr          * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::DefaultArgExpr       * node ) {
-		return node;
-	}
-
-	virtual const ast::Expr *             visit( const ast::GenericExpr          * node ) {
-		return node;
-	}
-
-	virtual const ast::Type *             visit( const ast::VoidType             * 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 << "CompoundStmt" << endl;
+		++indent;
+		printAll( node->kids );
+		--indent;
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::ExprStmt * node ) {
+		++indent;
+		os << "Expression Statement:" << endl << indent;
+		node->expr->accept( *this );
+		--indent;
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::AsmStmt * node ) {
+		os << "Assembler Statement:" << endl;
+		++indent;
+		os << indent << "instruction: " << endl << indent;
+		node->instruction->accept( *this );
+		if ( ! node->output.empty() ) {
+			os << endl << indent+1 << "output: " << endl;
+			printAll( node->output );
+		} // if
+		if ( ! node->input.empty() ) {
+			os << indent+1 << "input: " << endl;
+			printAll( node->input );
+		} // if
+		if ( ! node->clobber.empty() ) {
+			os << indent+1 << "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;
+		os << indent+1;
+		++indent;
+		node->cond->accept( *this );
+		--indent;
+
+		if ( !node->inits.empty() ) {
+			os << indent << "... with initialization: \n";
+			++indent;
+			for ( const Stmt * stmt : node->inits ) {
+				os << indent;
+				stmt->accept( *this );
+			}
+			--indent;
+			os << endl;
+		}
+
+		os << indent << "... then: " << endl;
+
+		++indent;
+		os << indent;
+		node->thenPart->accept( *this );
+		--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 ) {
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::ForStmt * node ) {
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::SwitchStmt * node ) {
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::CaseStmt * node ) {
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::BranchStmt * node ) {
+		return node;
+	}
+
+	virtual const ast::Stmt * visit( const ast::ReturnStmt * node ) {
+		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 ) {
+		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 ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::UntypedExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::NameExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::AddressExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::LabelAddressExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::CastExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::KeywordCastExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::VirtualCastExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::UntypedMemberExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::MemberExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::VariableExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::ConstantExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::SizeofExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::AlignofExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::UntypedOffsetofExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::OffsetofExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::OffsetPackExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::LogicalExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::ConditionalExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::CommaExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::TypeExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::AsmExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::ImplicitCopyCtorExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::ConstructorExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::CompoundLiteralExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::RangeExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::UntypedTupleExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::TupleExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::TupleIndexExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::TupleAssignExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::StmtExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::UniqueExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::UntypedInitExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::InitExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::DeletedExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::DefaultArgExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Expr * visit( const ast::GenericExpr * node ) {
+		return node;
+	}
+
+	virtual const ast::Type * visit( const ast::VoidType * node ) {
 		preprint( node );
 		os << "void";
@@ -449,5 +611,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::BasicType            * node ) {
+	virtual const ast::Type * visit( const ast::BasicType * node ) {
 		preprint( node );
 		os << ast::BasicType::typeNames[ node->kind ];
@@ -455,5 +617,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::PointerType          * node ) {
+	virtual const ast::Type * visit( const ast::PointerType * node ) {
 		preprint( node );
 		if ( ! node->isArray() ) {
@@ -482,5 +644,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::ArrayType            * node ) {
+	virtual const ast::Type * visit( const ast::ArrayType * node ) {
 		preprint( node );
 		if ( node->isStatic ) {
@@ -510,5 +672,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::ReferenceType        * node ) {
+	virtual const ast::Type * visit( const ast::ReferenceType * node ) {
 		preprint( node );
 
@@ -523,5 +685,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::QualifiedType        * node ) {
+	virtual const ast::Type * visit( const ast::QualifiedType * node ) {
 		preprint( node );
 
@@ -537,5 +699,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::FunctionType         * node ) {
+	virtual const ast::Type * visit( const ast::FunctionType * node ) {
 		preprint( node );
 
@@ -566,5 +728,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::StructInstType       * node ) {
+	virtual const ast::Type * visit( const ast::StructInstType * node ) {
 		preprint( node );
 
@@ -578,5 +740,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::UnionInstType        * node ) {
+	virtual const ast::Type * visit( const ast::UnionInstType * node ) {
 		preprint( node );
 
@@ -590,5 +752,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::EnumInstType         * node ) {
+	virtual const ast::Type * visit( const ast::EnumInstType * node ) {
 		preprint( node );
 
@@ -602,5 +764,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::TraitInstType        * node ) {
+	virtual const ast::Type * visit( const ast::TraitInstType * node ) {
 		preprint( node );
 
@@ -611,5 +773,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::TypeInstType         * node ) {
+	virtual const ast::Type * visit( const ast::TypeInstType * node ) {
 		preprint( node );
 
@@ -621,5 +783,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::TupleType            * node ) {
+	virtual const ast::Type * visit( const ast::TupleType * node ) {
 		preprint( node );
 
@@ -632,5 +794,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::TypeofType           * node ) {
+	virtual const ast::Type * visit( const ast::TypeofType * node ) {
 		preprint( node );
 
@@ -646,5 +808,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::VarArgsType          * node ) {
+	virtual const ast::Type * visit( const ast::VarArgsType * node ) {
 		preprint( node );
 		os << "builtin var args pack";
@@ -652,5 +814,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::ZeroType             * node ) {
+	virtual const ast::Type * visit( const ast::ZeroType * node ) {
 		preprint( node );
 		os << "zero_t";
@@ -658,5 +820,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::OneType              * node ) {
+	virtual const ast::Type * visit( const ast::OneType * node ) {
 		preprint( node );
 		os << "one_t";
@@ -664,5 +826,5 @@
 	}
 
-	virtual const ast::Type *             visit( const ast::GlobalScopeType      * node ) {
+	virtual const ast::Type * visit( const ast::GlobalScopeType * node ) {
 		preprint( node );
 		os << "Global Scope Type";
@@ -670,5 +832,5 @@
 	}
 
-	virtual const ast::Designation *      visit( const ast::Designation          * node ) {
+	virtual const ast::Designation * visit( const ast::Designation * node ) {
 		if ( node->designators.empty() ) return node;
 		os << "... designated by: " << std::endl;
@@ -683,5 +845,5 @@
 	}
 
-	virtual const ast::Init *             visit( const ast::SingleInit           * node ) {
+	virtual const ast::Init * visit( const ast::SingleInit * node ) {
 		os << "Simple Initializer: ";
 		node->value->accept( *this );
@@ -689,5 +851,5 @@
 	}
 
-	virtual const ast::Init *             visit( const ast::ListInit             * node ) {
+	virtual const ast::Init * visit( const ast::ListInit * node ) {
 		os << "Compound initializer: " << std::endl;
 		++indent;
@@ -707,5 +869,5 @@
 	}
 
-	virtual const ast::Init *             visit( const ast::ConstructorInit      * node ) {
+	virtual const ast::Init * visit( const ast::ConstructorInit * node ) {
 		os << "Constructor initializer: " << std::endl;
 		if ( node->ctor ) {
@@ -732,5 +894,5 @@
 	}
 
-	virtual const ast::Attribute *        visit( const ast::Attribute            * node ) {
+	virtual const ast::Attribute * visit( const ast::Attribute * node ) {
 		if ( node->empty() ) return node;
 		os << "Attribute with name: " << node->name;
@@ -743,5 +905,5 @@
 	}
 
-	virtual const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * node ) {
+	virtual const ast::TypeSubstitution * visit( const ast::TypeSubstitution * node ) {
 		os << indent << "Types:" << std::endl;
 		for ( const auto& i : *node ) {
@@ -765,6 +927,11 @@
 };
 
-void print( std::ostream & os, const ast::Node * node, Indenter indent ) {
-	Printer printer { os, indent };
+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);
 }
@@ -773,6 +940,6 @@
 // The size here needs to be explicit but at least the compiler will produce an error
 // if the wrong size is specified
-constexpr std::array<const char*, 3> Printer::Names::FuncSpecifiers;
-constexpr std::array<const char*, 5> Printer::Names::StorageClasses;
-constexpr std::array<const char*, 6> Printer::Names::Qualifiers;
+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/TypeSubstitution.hpp
===================================================================
--- src/AST/TypeSubstitution.hpp	(revision b0ec9711a35db17d11fd4733884f1d7ba52d3b68)
+++ src/AST/TypeSubstitution.hpp	(revision 68c9165ba8977f22fd2ed8d7175c671e03359a1a)
@@ -25,5 +25,5 @@
 #include "Fwd.hpp"        // for UniqueId
 #include "ParseNode.hpp"
-#include "Type.hpp"       
+#include "Type.hpp"
 #include "Common/SemanticError.h"  // for SemanticError
 #include "Visitor.hpp"
Index: src/AST/module.mk
===================================================================
--- src/AST/module.mk	(revision b0ec9711a35db17d11fd4733884f1d7ba52d3b68)
+++ src/AST/module.mk	(revision 68c9165ba8977f22fd2ed8d7175c671e03359a1a)
@@ -21,4 +21,5 @@
 	AST/DeclReplacer.cpp \
 	AST/Expr.cpp \
+	AST/GenericSubstitution.cpp \
 	AST/Init.cpp \
 	AST/LinkageSpec.cpp \
Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(revision b0ec9711a35db17d11fd4733884f1d7ba52d3b68)
+++ src/Makefile.in	(revision 68c9165ba8977f22fd2ed8d7175c671e03359a1a)
@@ -167,8 +167,9 @@
 am__objects_1 = AST/Attribute.$(OBJEXT) AST/Convert.$(OBJEXT) \
 	AST/Decl.$(OBJEXT) AST/DeclReplacer.$(OBJEXT) \
-	AST/Expr.$(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)
+	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) \
@@ -574,4 +575,5 @@
 	AST/DeclReplacer.cpp \
 	AST/Expr.cpp \
+	AST/GenericSubstitution.cpp \
 	AST/Init.cpp \
 	AST/LinkageSpec.cpp \
@@ -739,4 +741,6 @@
 	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) \
@@ -1173,4 +1177,5 @@
 @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@
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision b0ec9711a35db17d11fd4733884f1d7ba52d3b68)
+++ src/ResolvExpr/Unify.cc	(revision 68c9165ba8977f22fd2ed8d7175c671e03359a1a)
@@ -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/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision b0ec9711a35db17d11fd4733884f1d7ba52d3b68)
+++ src/Tuples/TupleExpansion.cc	(revision 68c9165ba8977f22fd2ed8d7175c671e03359a1a)
@@ -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 };
 	}
 
@@ -354,5 +351,9 @@
 
 	const ast::TypeInstType * isTtype( const ast::Type * type ) {
-		#warning unimplemented
+		if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
+			if ( inst->base && inst->base->kind == ast::TypeVar::Ttype ) {
+				return inst;
+			}
+		}
 		return nullptr;
 	}
