Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 514a79107bae98b4aa4636858232b2de8a8a0ee3)
+++ src/AST/Convert.cpp	(revision b869ec5003199dfa8bcbc3e90cae94d2d8ad1127)
@@ -44,5 +44,6 @@
 class ConverterNewToOld : public ast::Visitor {
 	BaseSyntaxNode * node = nullptr;
-	std::unordered_map< ast::Node *, BaseSyntaxNode * > cache;
+	using Cache = std::unordered_map< const ast::Node *, BaseSyntaxNode * >;
+	Cache cache;
 
 	template<typename T>
@@ -94,13 +95,10 @@
 	Type::Qualifiers cv( const ast::Type * ty ) { return { ty->qualifiers.val }; }
 
-	template<typename NewT, typename OldT>
-	NewT * cached( const OldT & old ) {
-		auto it = cache.find( old.get() );
-		if ( it == cache.end() ) {
-			// doesn't update cache, that should be handled by the accept function
-			return get< NewT >().accept1( old );
-		} else {
-			return strict_dynamic_cast< NewT * >( it->second );
-		}
+	/// 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;
 	}
 
@@ -130,8 +128,10 @@
 		decl->isDeleted = node->isDeleted;
 		// fs comes from constructor
+		cache.emplace( node, decl );
 		return nullptr;
 	}
 
 	const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto decl = new ObjectDecl(
 			node->name,
@@ -148,4 +148,5 @@
 
 	const ast::DeclWithType * visit( const ast::FunctionDecl * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto decl = new FunctionDecl(
 			node->name,
@@ -171,26 +172,14 @@
 
 	const ast::Decl * visit( const ast::TypeDecl * node ) override final {
-		TypeDecl::Kind kind;
-		switch (node->kind) {
-		case ast::TypeVar::Dtype:
-			kind = TypeDecl::Dtype;
-			break;
-		case ast::TypeVar::Ftype:
-			kind = TypeDecl::Ftype;
-			break;
-		case ast::TypeVar::Ttype:
-			kind = TypeDecl::Ttype;
-			break;
-		default:
-			assertf(false, "Invalid ast::TypeVar::Kind: %d\n", node->kind);
-		};
+		if ( inCache( node ) ) return nullptr;
 		auto decl = new TypeDecl(
 			node->name,
 			Type::StorageClasses( node->storage.val ),
 			get<Type>().accept1( node->base ),
-			kind,
+			(TypeDecl::Kind)(unsigned)node->kind,
 			node->sized,
 			get<Type>().accept1( node->init )
 		);
+		cache.emplace( node, decl );
 		return namedTypePostamble( decl, node );
 	}
@@ -212,9 +201,11 @@
 		decl->body = node->body;
 		// attributes come from constructor
-		// TODO: Need caching for: decl->parent = node->parent;
+		decl->parent = get<AggregateDecl>().accept1( node->parent );
+		cache.emplace( node, decl );
 		return nullptr;
 	}
 
 	const ast::Decl * visit( const ast::StructDecl * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto decl = new StructDecl(
 			node->name,
@@ -227,4 +218,5 @@
 
 	const ast::Decl * visit( const ast::UnionDecl * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto decl = new UnionDecl(
 			node->name,
@@ -236,4 +228,5 @@
 
 	const ast::Decl * visit( const ast::EnumDecl * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto decl = new EnumDecl(
 			node->name,
@@ -245,4 +238,5 @@
 
 	const ast::Decl * visit( const ast::TraitDecl * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto decl = new TraitDecl(
 			node->name,
@@ -804,26 +798,109 @@
 	}
 
+	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 {
-		(void)node;
+		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 {
-		(void)node;
+		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 {
-		(void)node;
+		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 {
-		(void)node;
+		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 {
-		(void)node;
+		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;
 	}
@@ -961,10 +1038,10 @@
 	static ast::CV::Qualifiers cv( Type * ty ) { return { ty->get_qualifiers().val }; }
 
-	template<typename NewT, typename OldT>
-	NewT * cached( OldT * old ) {
+	/// returns true and sets `node` if in cache
+	bool inCache( BaseSyntaxNode * 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 );
+		if ( it == cache.end() ) return false;
+		node = it->second;
+		return true;
 	}
 
@@ -972,4 +1049,5 @@
 
 	virtual void visit( ObjectDecl * old ) override final {
+		if ( inCache( old ) ) return;
 		auto decl = new ast::ObjectDecl(
 			old->location,
@@ -988,13 +1066,18 @@
 		decl->uniqueId   = old->uniqueId;
 		decl->extension  = old->extension;
+		cache.emplace( old, decl );
 
 		this->node = decl;
 	}
 
-	virtual void visit( FunctionDecl * ) override final {
-
+	virtual void visit( FunctionDecl * old ) override final {
+		if ( inCache( old ) ) return;
+		// TODO
+		auto decl = (ast::FunctionDecl *)nullptr;
+		cache.emplace( old, decl );
 	}
 
 	virtual void visit( StructDecl * old ) override final {
+		if ( inCache( old ) ) return;
 		auto decl = new ast::StructDecl(
 			old->location,
@@ -1011,4 +1094,5 @@
 		decl->uniqueId   = old->uniqueId;
 		decl->storage    = { old->storageClasses.val };
+		cache.emplace( old, decl );
 
 		this->node = decl;
@@ -1016,4 +1100,5 @@
 
 	virtual void visit( UnionDecl * old ) override final {
+		if ( inCache( old ) ) return;
 		auto decl = new ast::UnionDecl(
 			old->location,
@@ -1029,4 +1114,5 @@
 		decl->uniqueId   = old->uniqueId;
 		decl->storage    = { old->storageClasses.val };
+		cache.emplace( old, decl );
 
 		this->node = decl;
@@ -1034,4 +1120,5 @@
 
 	virtual void visit( EnumDecl * old ) override final {
+		if ( inCache( old ) ) return;
 		auto decl = new ast::UnionDecl(
 			old->location,
@@ -1047,4 +1134,5 @@
 		decl->uniqueId   = old->uniqueId;
 		decl->storage    = { old->storageClasses.val };
+		cache.emplace( old, decl );
 
 		this->node = decl;
@@ -1052,4 +1140,5 @@
 
 	virtual void visit( TraitDecl * old ) override final {
+		if ( inCache( old ) ) return;
 		auto decl = new ast::UnionDecl(
 			old->location,
@@ -1065,10 +1154,14 @@
 		decl->uniqueId   = old->uniqueId;
 		decl->storage    = { old->storageClasses.val };
+		cache.emplace( old, decl );
 
 		this->node = decl;
 	}
 
-	virtual void visit( TypeDecl * ) override final {
-
+	virtual void visit( TypeDecl * old ) override final {
+		if ( inCache( old ) ) return;
+		// TODO
+		auto decl = (ast::TypeDecl *)nullptr;
+		cache.emplace( old, decl );
 	}
 
@@ -1642,9 +1735,18 @@
 
 	virtual void visit( StructInstType * old ) override final {
-		auto ty = new ast::StructInstType{
-			cached< ast::StructDecl >( old->baseStruct ),
-			cv( old ),
-			GET_ACCEPT_V( attributes, Attribute )
-		};
+		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;
@@ -1652,9 +1754,18 @@
 
 	virtual void visit( UnionInstType * old ) override final {
-		auto ty = new ast::UnionInstType{
-			cached< ast::UnionDecl >( old->baseUnion ),
-			cv( old ),
-			GET_ACCEPT_V( attributes, Attribute )
-		};
+		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;
@@ -1662,9 +1773,18 @@
 
 	virtual void visit( EnumInstType * old ) override final {
-		auto ty = new ast::EnumInstType{
-			cached< ast::EnumDecl >( old->baseEnum ),
-			cv( old ),
-			GET_ACCEPT_V( attributes, Attribute )
-		};
+		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;
@@ -1672,9 +1792,18 @@
 
 	virtual void visit( TraitInstType * old ) override final {
-		auto ty = new ast::TraitInstType{
-			cached< ast::TraitDecl >( old->baseTrait ),
-			cv( old ),
-			GET_ACCEPT_V( attributes, Attribute )
-		};
+		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;
@@ -1686,5 +1815,5 @@
 			ty = new ast::TypeInstType{
 				old->name,
-				cached< ast::TypeDecl >( old->baseType ),
+				GET_ACCEPT_1( baseType, TypeDecl ),
 				cv( old ),
 				GET_ACCEPT_V( attributes, Attribute )
