Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision f6964efac123e363d6c06c0a069704a6b0ac40d7)
+++ src/AST/Convert.cpp	(revision d1487780c1f67242d6e2063860a40cc32c2395ee)
@@ -16,4 +16,6 @@
 #include "Convert.hpp"
 
+#include <unordered_map>
+
 #include "AST/Attribute.hpp"
 #include "AST/Decl.hpp"
@@ -42,4 +44,5 @@
 class ConverterNewToOld : public ast::Visitor {
 	BaseSyntaxNode * node = nullptr;
+	std::unordered_map< ast::Node *, BaseSyntaxNode * > cache;
 
 	template<typename T>
@@ -49,4 +52,5 @@
 		template<typename U>
 		T * accept1( const ast::ptr<U> & ptr ) {
+			if ( ! ptr ) return nullptr;
 			ptr->accept( visitor );
 			T * ret = strict_dynamic_cast< T * >( visitor.node );
@@ -85,4 +89,15 @@
 		}
 		return ret;
+	}
+
+	/// get new qualifiers from old type
+	Type::Qualifiers cv( const ast::Type * ty ) { return { ty->qualifiers.val }; }
+
+	template<typename NewT, typename OldT>
+	NewT * cached( OldT * old ) {
+		auto it = cache.find( old );
+		// doesn't update cache, that should be handled by the accept function
+		ast::Node * nw = it == cache.end() ? getAccept1< NewT >( old ) : it->second;
+		return strict_dynamic_cast< NewT * >( nw );
 	}
 
@@ -598,35 +613,58 @@
 
 	const ast::Type * visit( const ast::VoidType * node ) override final {
-		(void)node;
+		this->node = new VoidType{ cv( node ) };
 		return nullptr;
 	}
 
 	const ast::Type * visit( const ast::BasicType * node ) override final {
-		(void)node;
+		this->node = new BasicType{ cv( node ), (BasicType::Kind)(unsigned)node->kind };
 		return nullptr;
 	}
 
 	const ast::Type * visit( const ast::PointerType * node ) override final {
-		(void)node;
+		this->node = new PointerType{
+			cv( node ),
+			get<Type>().accept1( node->base ),
+			get<Expression>().accept1( node->dimension ),
+			node->isVarLen,
+			node->isStatic
+		};
 		return nullptr;
 	}
 
 	const ast::Type * visit( const ast::ArrayType * node ) override final {
-		(void)node;
+		this->node = new ArrayType{
+			cv( node ),
+			get<Type>().accept1( node->base ),
+			get<Expression>().accept1( node->dimension ),
+			node->isVarLen,
+			node->isStatic
+		};
 		return nullptr;
 	}
 
 	const ast::Type * visit( const ast::ReferenceType * node ) override final {
-		(void)node;
+		this->node = new ReferenceType{
+			cv( node ),
+			get<Type>().accept1( node->base )
+		};
 		return nullptr;
 	}
 
 	const ast::Type * visit( const ast::QualifiedType * node ) override final {
-		(void)node;
+		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 {
-		(void)node;
+		auto ty = new FunctionType { cv( node ), node->isVarArgs };
+		ty->returnVals = get<DeclarationWithType>().acceptL( node->returns );
+		ty->parameters = get<DeclarationWithType>().acceptL( node->params );
+		ty->forall = get<TypeDecl>().acceptL( node->forall );
+		node = ty;
 		return nullptr;
 	}
@@ -736,5 +774,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 +783,5 @@
 	template<typename NewT, typename OldT>
 	NewT * getAccept1( OldT old ) {
+		if ( ! old ) return nullptr;
 		old->accept(*this);
 		return strict_dynamic_cast< NewT * >( node );
@@ -782,4 +824,14 @@
 #	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 }; }
+
+	template<typename NewT, typename OldT>
+	NewT * cached( OldT * old ) {
+		auto it = cache.find( old );
+		// doesn't update cache, that should be handled by the accept function
+		ast::Node * nw = it == cache.end() ? getAccept1< NewT >( old ) : it->second;
+		return strict_dynamic_cast< NewT * >( nw );
+	}
 
 	// Now all the visit functions:
@@ -1359,50 +1411,112 @@
 	}
 
-	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( 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 {
+		auto ty = new ast::StructInstType{
+			cached< ast::StructDecl >( old->baseStruct ),
+			cv( old ),
+			GET_ACCEPT_V( attributes, Attribute )
+		};
+		postvisit( old, ty );
+		this->node = ty;
+	}
+
+	virtual void visit( UnionInstType * old ) override final {
+		auto ty = new ast::UnionInstType{
+			cached< ast::UnionDecl >( old->baseUnion ),
+			cv( old ),
+			GET_ACCEPT_V( attributes, Attribute )
+		};
+		postvisit( old, ty );
+		this->node = ty;
+	}
+
+	virtual void visit( EnumInstType * old ) override final {
+		auto ty = new ast::EnumInstType{
+			cached< ast::EnumDecl >( old->baseEnum ),
+			cv( old ),
+			GET_ACCEPT_V( attributes, Attribute )
+		};
+		postvisit( old, ty );
+		this->node = ty;
+	}
+
+	virtual void visit( TraitInstType * old ) override final {
+		auto ty = new ast::TraitInstType{
+			cached< ast::TraitDecl >( old->baseTrait ),
+			cv( old ),
+			GET_ACCEPT_V( attributes, Attribute )
+		};
+		postvisit( old, ty );
+		this->node = ty;
+	}
+
+	virtual void visit( TypeInstType * old ) override final {
+		auto ty = new ast::TypeInstType{
+			cached< ast::TypeDecl >( old->baseStruct ),
+			cv( old ),
+			GET_ACCEPT_V( attributes, Attribute )
+		};
+		postvisit( old, ty );
+		this->node = ty;
 	}
 
