Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 461046f67b90a0b92e6e17f2a07dbfc5f8b8198e)
+++ src/AST/Convert.cpp	(revision 3f840e371860ab44fa91a1a4d720ef11582eb23e)
@@ -16,4 +16,6 @@
 #include "Convert.hpp"
 
+#include <unordered_map>
+
 #include "AST/Attribute.hpp"
 #include "AST/Decl.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 );
@@ -85,4 +90,15 @@
 		}
 		return ret;
+	}
+
+	/// 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;
 	}
 
@@ -112,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,
@@ -130,4 +148,5 @@
 
 	const ast::DeclWithType * visit( const ast::FunctionDecl * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto decl = new FunctionDecl(
 			node->name,
@@ -153,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 );
 	}
@@ -194,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,
@@ -209,4 +218,5 @@
 
 	const ast::Decl * visit( const ast::UnionDecl * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto decl = new UnionDecl(
 			node->name,
@@ -218,4 +228,5 @@
 
 	const ast::Decl * visit( const ast::EnumDecl * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto decl = new EnumDecl(
 			node->name,
@@ -227,4 +238,5 @@
 
 	const ast::Decl * visit( const ast::TraitDecl * node ) override final {
+		if ( inCache( node ) ) return nullptr;
 		auto decl = new TraitDecl(
 			node->name,
@@ -559,85 +571,278 @@
 
 	const ast::Expr * visit( const ast::AddressExpr * node ) override final {
-		(void)node;
+		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 {
-		(void)node;
+		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 {
-		(void)node;
+		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 {
-		(void)node;
+		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 {
-		(void)node;
+		auto expr = visitBaseExpr( node,
+			new VirtualCastExpr(
+				get<Expression>().accept1(node->arg),
+				nullptr // cast's "to" type is expr's result type; converted in visitBaseExpr
+			)
+		);
+		this->node = expr;
 		return nullptr;
 	}
 
 	const ast::Expr * visit( const ast::UntypedMemberExpr * node ) override final {
-		(void)node;
+		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 {
-		(void)node;
+		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 {
-		(void)node;
-		return nullptr;
+		auto expr = visitBaseExpr( node,
+			new VariableExpr(
+				inCache(node->var) ?
+					dynamic_cast<DeclarationWithType *>(this->node) :
+					get<DeclarationWithType>().accept1(node->var)
+			)
+		);
+		this->node = expr;
+		return nullptr;
+	}
+
+	bool isIntlikeConstantType(const ast::Type *t) {
+		if ( const ast::BasicType * basicType = dynamic_cast< const ast::BasicType * >( t ) ) {
+			if ( basicType->isInteger() ) {
+				return true;
+			}
+		} else if ( dynamic_cast< const ast::OneType * >( t ) ) {
+			return true;
+		} else if ( dynamic_cast< const ast::ZeroType * >( t ) ) {
+			return true;
+		} else if ( dynamic_cast< const ast::PointerType * >( t ) ) {
+			// null pointer constants, with zero int-values
+			return true;
+		}
+		return false;
+	}
+
+	bool isFloatlikeConstantType(const ast::Type *t) {
+		if ( const ast::BasicType * bty = dynamic_cast< const ast::BasicType * >( t ) ) {
+			if ( ! bty->isInteger() ) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	bool isStringlikeConstantType(const ast::Type *t) {
+		if ( const ast::ArrayType * aty = dynamic_cast< const ast::ArrayType * >( t ) ) {
+			if ( const ast::BasicType * bty = aty->base.as<ast::BasicType>() ) {
+			   if ( bty->kind == ast::BasicType::Kind::Char ) {
+				   return true;
+			   }
+			}
+		}
+		return false;
 	}
 
 	const ast::Expr * visit( const ast::ConstantExpr * node ) override final {
-		(void)node;
+		ConstantExpr *rslt = nullptr;
+		if (isIntlikeConstantType(node->result)) {
+			rslt = new ConstantExpr(Constant(
+				get<Type>().accept1(node->result),
+				node->rep,
+				(unsigned long long) node->intValue()
+			));
+		} else if (isFloatlikeConstantType(node->result)) {
+			rslt = new ConstantExpr(Constant(
+				get<Type>().accept1(node->result),
+				node->rep,
+				(double) node->floatValue()
+			));
+		} else if (isStringlikeConstantType(node->result)) {
+			rslt = new ConstantExpr(Constant::from_string(
+				node->rep
+			));
+		}
+		assert(rslt);
+		auto expr = visitBaseExpr( node, rslt );
+		this->node = expr;
 		return nullptr;
 	}
 
 	const ast::Expr * visit( const ast::SizeofExpr * node ) override final {
-		(void)node;
+		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 {
-		(void)node;
+		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 {
-		(void)node;
+		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 {
-		(void)node;
+		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 {
-		(void)node;
+		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 {
-		(void)node;
+		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 {
-		(void)node;
+		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 {
-		(void)node;
+		auto expr = visitBaseExpr( node,
+			new CommaExpr(
+				get<Expression>().accept1(node->arg1),
+				get<Expression>().accept1(node->arg2)
+			)
+		);
+		this->node = expr;
 		return nullptr;
 	}
@@ -729,90 +934,207 @@
 
 	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 ),
+			(bool)node->isVarLen,
+			(bool)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 ),
+			(bool)node->isVarLen,
+			(bool)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;
-		return nullptr;
+		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 {
-		(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;
 	}
 
 	const ast::Type * visit( const ast::TupleType * node ) override final {
-		(void)node;
+		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 {
-		(void)node;
+		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 {
-		(void)node;
+		this->node = new VarArgsType{ cv( node ) };
 		return nullptr;
 	}
 
 	const ast::Type * visit( const ast::ZeroType * node ) override final {
-		(void)node;
+		this->node = new ZeroType{ cv( 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;
+		this->node = new OneType{ cv( node ) };
+		return nullptr;
+	}
+
+	const ast::Type * visit( const ast::GlobalScopeType * ) override final {
+		this->node = new GlobalScopeType{};
 		return nullptr;
 	}
@@ -867,5 +1189,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:
@@ -873,4 +1198,5 @@
 	template<typename NewT, typename OldT>
 	NewT * getAccept1( OldT old ) {
+		if ( ! old ) return nullptr;
 		old->accept(*this);
 		return strict_dynamic_cast< NewT * >( node );
@@ -913,8 +1239,19 @@
 #	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 }; }
+
+	/// 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,
@@ -933,13 +1270,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,
@@ -956,4 +1298,5 @@
 		decl->uniqueId   = old->uniqueId;
 		decl->storage    = { old->storageClasses.val };
+		cache.emplace( old, decl );
 
 		this->node = decl;
@@ -961,4 +1304,5 @@
 
 	virtual void visit( UnionDecl * old ) override final {
+		if ( inCache( old ) ) return;
 		auto decl = new ast::UnionDecl(
 			old->location,
@@ -974,4 +1318,5 @@
 		decl->uniqueId   = old->uniqueId;
 		decl->storage    = { old->storageClasses.val };
+		cache.emplace( old, decl );
 
 		this->node = decl;
@@ -979,4 +1324,5 @@
 
 	virtual void visit( EnumDecl * old ) override final {
+		if ( inCache( old ) ) return;
 		auto decl = new ast::UnionDecl(
 			old->location,
@@ -992,4 +1338,5 @@
 		decl->uniqueId   = old->uniqueId;
 		decl->storage    = { old->storageClasses.val };
+		cache.emplace( old, decl );
 
 		this->node = decl;
@@ -997,4 +1344,5 @@
 
 	virtual void visit( TraitDecl * old ) override final {
+		if ( inCache( old ) ) return;
 		auto decl = new ast::UnionDecl(
 			old->location,
@@ -1010,10 +1358,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 );
 	}
 
@@ -1388,5 +1740,5 @@
 			new ast::CastExpr(
 				old->location,
-				nullptr, // cast's "to" type is expr's result type; converted in visitBaseExpr
+				GET_ACCEPT_1(arg, Expr),
 				old->isGenerated ? ast::GeneratedCast : ast::ExplicitCast
 			)
@@ -1394,66 +1746,257 @@
 	}
 
-	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( 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( old,
+			new ast::VirtualCastExpr(
+				old->location,
+				GET_ACCEPT_1(arg, Expr),
+				nullptr // cast's "to" type is expr's result type; converted in visitBaseExpr
+			)
+		);
+	}
+
+	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)
+			)
+		);
 	}
 
@@ -1526,78 +2069,195 @@
 	}
 
-	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( 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 {
-
+		this->node = new ast::GlobalScopeType{};
 	}
 
Index: src/AST/Type.cpp
===================================================================
--- src/AST/Type.cpp	(revision 461046f67b90a0b92e6e17f2a07dbfc5f8b8198e)
+++ src/AST/Type.cpp	(revision 3f840e371860ab44fa91a1a4d720ef11582eb23e)
@@ -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 461046f67b90a0b92e6e17f2a07dbfc5f8b8198e)
+++ src/AST/Type.hpp	(revision 3f840e371860ab44fa91a1a4d720ef11582eb23e)
@@ -514,5 +514,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 ); }
