Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/AST/Convert.cpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -321,4 +321,8 @@
 			get<Type>().accept1(node->base)
 		);
+		decl->data_constructors = get<StructDecl>().acceptL( node->data_constructors );
+		decl->data_union = get<UnionDecl>().accept1( node->data_union );
+		decl->tags = get<EnumDecl>().accept1( node->tag );
+		decl->tag_union = get<StructDecl>().accept1( node->tag_union );
 		return aggregatePostamble( decl, node );
 	}
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/AST/Decl.cpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -132,5 +132,5 @@
 
 // These must harmonize with the corresponding AggregateDecl::Aggregate enumerations.
-static const char * aggregateNames[] = { "struct", "union", "enum", "exception", "trait", "generator", "coroutine", "monitor", "thread", "NoAggregateName" };
+static const char * aggregateNames[] = { "struct", "union", "enum", "exception", "trait", "generator", "coroutine", "monitor", "thread", "NoAggregateName", "data" };
 
 const char * AggregateDecl::aggrString( AggregateDecl::Aggregate aggr ) {
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/AST/Decl.hpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -248,5 +248,5 @@
 class AggregateDecl : public Decl {
 public:
-	enum Aggregate { Struct, Union, Enum, Exception, Trait, Generator, Coroutine, Monitor, Thread, NoAggregate };
+	enum Aggregate { Struct, Union, Enum, Exception, Trait, Generator, Coroutine, Monitor, Thread, NoAggregate, ADT };
 	static const char * aggrString( Aggregate aggr );
 
@@ -286,4 +286,5 @@
 	bool is_monitor  () const { return kind == Monitor  ; }
 	bool is_thread   () const { return kind == Thread   ; }
+	bool is_adt		 () const { return kind == ADT		; }
 
 	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
@@ -320,7 +321,13 @@
 	enum class EnumHiding { Visible, Hide } hide;
 
+	std::vector<ptr<StructDecl>> data_constructors;
+	bool isData = false;
+	ptr<UnionDecl> data_union;
+	ptr<EnumDecl> tag;
+	ptr<StructDecl> tag_union;
+
 	EnumDecl( const CodeLocation& loc, const std::string& name, bool isTyped = false,
 		std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall,
-		Type const * base = nullptr, EnumHiding hide = EnumHiding::Hide,
+		Type const * base = nullptr, EnumHiding hide = EnumHiding::Visible,
 		std::unordered_map< std::string, long long > enumValues = std::unordered_map< std::string, long long >() )
 	: AggregateDecl( loc, name, std::move(attrs), linkage ), isTyped(isTyped), base(base), hide(hide), enumValues(enumValues) {}
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/AST/Pass.impl.hpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -693,4 +693,8 @@
 			maybe_accept( node, &EnumDecl::members    );
 			maybe_accept( node, &EnumDecl::attributes );
+			maybe_accept( node, &EnumDecl::data_constructors );
+			maybe_accept( node, &EnumDecl::data_union );
+			maybe_accept( node, &EnumDecl::tag );
+			maybe_accept( node, &EnumDecl::tag_union );
 		} else {
 			maybe_accept( node, &EnumDecl::base );
@@ -698,4 +702,8 @@
 			maybe_accept( node, &EnumDecl::members    );
 			maybe_accept( node, &EnumDecl::attributes );
+			maybe_accept( node, &EnumDecl::data_constructors );
+			maybe_accept( node, &EnumDecl::data_union );
+			maybe_accept( node, &EnumDecl::tag );
+			maybe_accept( node, &EnumDecl::tag_union );
 		}
 	}
Index: src/CodeGen/CodeGenerator.cc
===================================================================
--- src/CodeGen/CodeGenerator.cc	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/CodeGen/CodeGenerator.cc	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -295,6 +295,21 @@
 	}
 
+	void CodeGenerator::handleData( EnumDecl * dataDecl ) {
+		output << " /** data type */" << endl;
+		for ( StructDecl * decl : dataDecl->data_constructors ) {
+			postvisit(decl);
+			output << ";" << endl;
+		}
+		postvisit( dataDecl->data_union );
+		output << ";" << endl;
+		postvisit( dataDecl->tags );
+		output << ";" << endl;
+		postvisit( dataDecl->tag_union );
+		output << ";" << endl;
+	}
+
 	void CodeGenerator::postvisit( EnumDecl * enumDecl ) {
-		extension( enumDecl );
+		if ( enumDecl->data_constructors.size() > 0 ) return handleData( enumDecl );
+ 		extension( enumDecl );
 		std::list< Declaration* > &memb = enumDecl->get_members();
 		if (enumDecl->base && ! memb.empty()) {
Index: src/CodeGen/CodeGenerator.h
===================================================================
--- src/CodeGen/CodeGenerator.h	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/CodeGen/CodeGenerator.h	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -165,4 +165,6 @@
 		void handleTypedef( NamedTypeDecl *namedType );
 		std::string mangleName( DeclarationWithType * decl );
+
+		void handleData( EnumDecl * EnumDecl );
 	}; // CodeGenerator
 
Index: src/Common/PassVisitor.impl.h
===================================================================
--- src/Common/PassVisitor.impl.h	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/Common/PassVisitor.impl.h	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -754,5 +754,7 @@
 
 	// unlike structs, traits, and unions, enums inject their members into the global scope
-	// if ( node->base ) maybeAccept_impl( node->base, *this ); // Need this? Maybe not?
+	maybeAccept_impl( node->data_constructors, *this );
+	maybeAccept_impl( node->data_union, *this );
+	maybeAccept_impl( node->tags, *this );
 	maybeAccept_impl( node->parameters, *this );
 	maybeAccept_impl( node->members   , *this );
Index: src/Parser/DeclarationNode.cc
===================================================================
--- src/Parser/DeclarationNode.cc	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/Parser/DeclarationNode.cc	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -279,4 +279,12 @@
 } // DeclarationNode::newEnum
 
+DeclarationNode * DeclarationNode::newADT( const string * name, DeclarationNode * constructors ) {
+	DeclarationNode * newnode = newEnum( name, nullptr, true, false );
+	newnode->type->enumeration.isData = true;
+	newnode->type->enumeration.data_constructors = constructors;
+	return newnode;
+}
+
+
 DeclarationNode * DeclarationNode::newName( const string * name ) {
 	DeclarationNode * newnode = new DeclarationNode;
@@ -305,4 +313,9 @@
 	} // if
 } // DeclarationNode::newEnumValueGeneric
+
+DeclarationNode * DeclarationNode::newDataConstructor( const string * name ) {
+	DeclarationNode * newnode = newName(name);
+	return newnode;
+}
 
 DeclarationNode * DeclarationNode::newEnumInLine( const string name ) {
@@ -1083,4 +1096,92 @@
 	}
 	return nullptr;
+}
+
+void buildDataConstructors( DeclarationNode * firstNode, std::vector<ast::ptr<ast::StructDecl>> & outputList ) {
+	std::back_insert_iterator<std::vector<ast::ptr<ast::StructDecl>>> out( outputList );
+	for ( const DeclarationNode * cur = firstNode; cur; cur = strict_next( cur ) ) {
+		// td->kind == TypeData::Symbolic
+		assert( cur->type->kind == TypeData::Symbolic );
+		const std::string * name = cur->name;
+		auto ctor = new ast::StructDecl( cur->location,
+			std::string(*name),
+			ast::AggregateDecl::Aggregate::Struct
+		);
+		ctor->set_body(true);
+		TypeData * td = cur->type;
+		TypeData::Symbolic_t st = td->symbolic;
+		DeclarationNode * params = st.params;
+		
+		if ( params ) {
+			buildList( params, ctor->members );
+		}
+
+		for ( std::size_t i = 0; i < ctor->members.size(); ++i ) {
+			assert(ctor->members[i]->name == "");
+			ast::Decl * member = ctor->members[i].get_and_mutate();
+			member->name = "field_" + std::to_string(i);
+		}
+		*out++ = ctor;		
+	}
+}
+
+ast::UnionDecl * buildDataUnion( ast::EnumDecl * data, const std::vector<ast::ptr<ast::StructDecl>> & typeList ) {
+	ast::UnionDecl * out = new ast::UnionDecl( data->location, "temp_data_union" );
+	// size_t index = 0;
+	if ( typeList.size() > 0 ) out->set_body( true );
+	size_t i = 0;
+	for (const ast::ptr<ast::StructDecl> structDecl : typeList ) {
+		ast::StructInstType * inst = new ast::StructInstType(structDecl);
+		ast::ObjectDecl * instObj = new ast::ObjectDecl(
+			structDecl->location,
+			"option_" + std::to_string(i),
+			inst
+		);
+		i++;
+		out->members.push_back( instObj );
+
+	}
+	return out;
+}
+
+ast::EnumDecl * buildTag( ast::EnumDecl * data, const std::vector<ast::ptr<ast::StructDecl>> & typeList ) {
+	ast::EnumDecl * out = new ast::EnumDecl( data->location, "temp_data_tag" );
+	if ( typeList.size() > 0 ) out->set_body( true );
+	for ( const ast::ptr<ast::StructDecl> structDecl : typeList ) {
+		ast::EnumInstType * inst = new ast::EnumInstType( out );
+		assert( inst->base != nullptr );
+		ast::ObjectDecl * instObj = new ast::ObjectDecl(
+			structDecl->location,
+			structDecl->name,
+			inst
+		);
+		out->members.push_back( instObj );
+	}
+	return out;
+}
+
+ast::StructDecl * buildTaggedUnions( const ast::EnumDecl * data, const ast::EnumDecl * tags, const ast::UnionDecl * data_union ) {
+	assert( tags->members.size() == data_union->members.size() );
+	ast::StructDecl * out = new ast::StructDecl( data->location, data->name );
+	out->kind = ast::AggregateDecl::ADT;
+
+	out->set_body( true );
+
+	ast::EnumInstType * tag = new ast::EnumInstType( tags );
+	ast::ObjectDecl * tag_obj = new ast::ObjectDecl(
+		data->location,
+		"tag",
+		tag
+	);
+	ast::UnionInstType * value = new ast::UnionInstType( data_union );
+	ast::ObjectDecl * value_obj = new ast::ObjectDecl(
+		data->location,
+		"value",
+		value
+	);
+
+	out->members.push_back( value_obj );
+	out->members.push_back( tag_obj );
+	return out;
 }
 
Index: src/Parser/DeclarationNode.h
===================================================================
--- src/Parser/DeclarationNode.h	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/Parser/DeclarationNode.h	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -76,4 +76,9 @@
 	static DeclarationNode * newStaticAssert( ExpressionNode * condition, ast::Expr * message );
 
+	// Experimental algebric data type
+	static DeclarationNode * newADT( const std::string * name, DeclarationNode * constructors );
+	static DeclarationNode * newDataConstructor( const std::string * name );
+	// static DeclarationNode * newDataConstructor( const std::string * name, DeclarationNode * typeSpecifiers );
+
 	DeclarationNode();
 	~DeclarationNode();
@@ -156,4 +161,5 @@
 	ExpressionNode * bitfieldWidth = nullptr;
 	std::unique_ptr<ExpressionNode> enumeratorValue;
+
 	bool hasEllipsis = false;
 	ast::Linkage::Spec linkage;
@@ -210,4 +216,8 @@
 void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList );
 void buildTypeList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::Type>> & outputList );
+void buildDataConstructors( DeclarationNode * firstNode, std::vector<ast::ptr<ast::StructDecl>> & outputList );
+ast::UnionDecl * buildDataUnion( ast::EnumDecl * data, const std::vector<ast::ptr<ast::StructDecl>> & typeList );
+ast::EnumDecl * buildTag( ast::EnumDecl * data, const std::vector<ast::ptr<ast::StructDecl>> & typeList );
+ast::StructDecl * buildTaggedUnions( const ast::EnumDecl * data, const ast::EnumDecl * tags, const ast::UnionDecl * data_union );
 
 template<typename AstType, typename NodeType,
Index: src/Parser/TypeData.cc
===================================================================
--- src/Parser/TypeData.cc	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/Parser/TypeData.cc	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -1260,4 +1260,12 @@
 	);
 	buildList( td->enumeration.constants, ret->members );
+	if ( td->enumeration.data_constructors != nullptr ) {
+		buildDataConstructors( td->enumeration.data_constructors, ret->data_constructors );
+		ret->data_union = buildDataUnion( ret, ret->data_constructors );
+		ret->tag = buildTag( ret, ret->data_constructors );
+		ret->tag_union = buildTaggedUnions( ret, ret->tag.get(), ret->data_union.get() );
+	}
+
+	if ( ret->data_constructors.size() > 0 ) ret->isData = true;
 	auto members = ret->members.begin();
 	ret->hide = td->enumeration.hiding == EnumHiding::Hide ? ast::EnumDecl::EnumHiding::Hide : ast::EnumDecl::EnumHiding::Visible;
Index: src/Parser/TypeData.h
===================================================================
--- src/Parser/TypeData.h	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/Parser/TypeData.h	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -25,5 +25,5 @@
 struct TypeData {
 	enum Kind { Basic, Pointer, Reference, Array, Function, Aggregate, AggregateInst, Enum, EnumConstant, Symbolic,
-				SymbolicInst, Tuple, Basetypeof, Typeof, Vtable, Builtin, GlobalScope, Qualified, Unknown };
+				SymbolicInst, Tuple, Basetypeof, Typeof, Vtable, Builtin, GlobalScope, Qualified, ADT, Ctor, Unknown };
 
 	struct Aggregate_t {
@@ -58,4 +58,17 @@
 		bool typed;
 		EnumHiding hiding;
+		bool isData = false;
+
+		DeclarationNode * data_constructors = nullptr;
+	};
+
+	struct ADT_t {
+		const std::string * name = nullptr;
+		DeclarationNode * constructors;
+	};
+
+	struct Constructor_t {
+		const std::string * name;
+		DeclarationNode * type; // types?
 	};
 
@@ -98,4 +111,7 @@
 	Array_t array;
 	Enumeration_t enumeration;
+	ADT_t adt;
+	Constructor_t data_constructor;
+
 	Function_t function;
 	Symbolic_t symbolic;
Index: src/Parser/lex.ll
===================================================================
--- src/Parser/lex.ll	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/Parser/lex.ll	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -353,4 +353,5 @@
 with			{ KEYWORD_RETURN(WITH); }				// CFA
 zero_t			{ NUMERIC_RETURN(ZERO_T); }				// CFA
+_DATA_            { KEYWORD_RETURN(DATA); }				// Experimental
 
 				/* identifier */
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/Parser/parser.yy	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -339,5 +339,5 @@
 %token SIZEOF TYPEOF VA_LIST VA_ARG AUTO_TYPE			// GCC
 %token OFFSETOF BASETYPEOF TYPEID						// CFA
-%token ENUM STRUCT UNION
+%token ENUM STRUCT UNION DATA
 %token EXCEPTION										// CFA
 %token GENERATOR COROUTINE MONITOR THREAD				// CFA
@@ -453,4 +453,7 @@
 %type<decl> enumerator_list enum_type enum_type_nobody
 %type<init> enumerator_value_opt
+
+%type<decl> value_list
+%type<decl> data_constructor type_specifier_list
 
 %type<decl> external_definition external_definition_list external_definition_list_opt
@@ -2441,4 +2444,5 @@
 		}
 	| enum_type
+	/* | algebric_data_type */
 	;
 
@@ -2694,5 +2698,49 @@
 		}
 	| enum_type_nobody
-	;
+	| DATA identifier
+	{ typedefTable.makeTypedef( *$2 ); }
+	 '{' value_list '}'
+	 {
+		$$ = DeclarationNode::newADT( $2, $5 );
+	 }
+	;
+
+value_list:
+	data_constructor 
+	{
+		$$ = $1;
+	}
+	/* | identifier_or_type_name '(' type_specifier ')'
+	{
+		$$ = DeclarationNode::newEnumValueGeneric( $1, nullptr );
+	} */
+	/* | data_constructor '|' value_list   */
+	| value_list '|' data_constructor
+	{
+		 { $$ = $1->appendList( $3 ); }
+	}
+	;
+
+data_constructor:
+	identifier_or_type_name 
+	{
+		typedefTable.makeTypedef( *$1 );
+		$$ =  DeclarationNode::newTypeDecl( $1, nullptr );;
+	}
+	| identifier_or_type_name '(' type_specifier_list ')'
+	{
+		typedefTable.makeTypedef( *$1 );
+		$$ = DeclarationNode::newTypeDecl( $1, $3 );
+	}
+
+type_specifier_list:
+	type_specifier
+	/* | type_specifier ',' type_specifier_list  */
+	| type_specifier_list ',' type_specifier
+	{
+		$$ = $1->appendList($3);
+	}
+	;
+
 
 hide_opt:
Index: src/SynTree/AggregateDecl.cc
===================================================================
--- src/SynTree/AggregateDecl.cc	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/SynTree/AggregateDecl.cc	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -29,5 +29,5 @@
 
 // These must harmonize with the corresponding AggregateDecl::Aggregate enumerations.
-static const char * aggregateNames[] = { "struct", "union", "enum", "exception", "trait", "generator", "coroutine", "monitor", "thread", "NoAggregateName" };
+static const char * aggregateNames[] = { "struct", "union", "enum", "exception", "trait", "generator", "coroutine", "monitor", "thread", "NoAggregateName", "data" };
 
 const char * AggregateDecl::aggrString( AggregateDecl::Aggregate aggr ) {
Index: src/SynTree/Declaration.h
===================================================================
--- src/SynTree/Declaration.h	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/SynTree/Declaration.h	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -268,5 +268,5 @@
 	typedef Declaration Parent;
   public:
-	enum Aggregate { Struct, Union, Enum, Exception, Trait, Generator, Coroutine, Monitor, Thread, NoAggregate };
+	enum Aggregate { Struct, Union, Enum, Exception, Trait, Generator, Coroutine, Monitor, Thread, NoAggregate, ADT };
 	static const char * aggrString( Aggregate aggr );
 
@@ -341,4 +341,9 @@
 	Type * base;
 	enum EnumHiding { Visible, Hide } hide;
+
+	std::list<StructDecl*> data_constructors;
+	UnionDecl * data_union;
+	EnumDecl * tags;
+	StructDecl * tag_union;
 
 	EnumDecl( const std::string & name,
Index: src/Validate/Autogen.cpp
===================================================================
--- src/Validate/Autogen.cpp	(revision b110bcc1f3711112c2fbc182403e08383e1f4be0)
+++ src/Validate/Autogen.cpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -125,4 +125,6 @@
 	// Built-ins do not use autogeneration.
 	bool shouldAutogen() const final { return !decl->linkage.is_builtin && !structHasFlexibleArray(decl); }
+	void genADTFuncs();
+	void getADTFuncBody(const ast::ObjectDecl * lhs, ast::FunctionDecl * func);
 private:
 	void genFuncBody( ast::FunctionDecl * decl ) final;
@@ -193,5 +195,5 @@
 	}
 
-	bool shouldAutogen() const final { return true; }
+	bool shouldAutogen() const final { return !(decl->isData); }
 private:
 	void genFuncBody( ast::FunctionDecl * decl ) final;
@@ -238,11 +240,4 @@
 	if ( !enumDecl->body ) return;
 
-	// if ( auto enumBaseType = enumDecl->base ) {
-	// 	if ( auto enumBaseTypeAsStructInst = dynamic_cast<const ast::StructInstType *>(enumBaseType.get()) ) {
-	// 		const ast::StructDecl * structDecl = enumBaseTypeAsStructInst->base.get();
-	// 		this->previsit( structDecl );
-	// 	}
-	// }
-
 	ast::EnumInstType enumInst( enumDecl->name );
 	enumInst.base = enumDecl;
@@ -264,4 +259,6 @@
 	}
 	StructFuncGenerator gen( structDecl, &structInst, functionNesting );
+
+	gen.genADTFuncs();
 	gen.generateAndAppendFunctions( declsToAddAfter );
 }
@@ -475,4 +472,92 @@
 		}
 		produceDecl( decl );
+	}
+}
+
+void StructFuncGenerator::getADTFuncBody(
+		const ast::ObjectDecl * lhs,
+	 	ast::FunctionDecl * func
+	) {
+	const CodeLocation& location = func->location;
+	assert( decl->members.size() == 2 );
+	auto first = (decl->members[0]).as<ast::ObjectDecl>();
+	assert(first != nullptr);
+	auto firstType = first->type;
+	auto unionInstDecl = firstType.as<ast::UnionInstType>();
+	assert(unionInstDecl != nullptr);
+
+	auto unionDecl = unionInstDecl->base;
+	
+	const ast::ObjectDecl * dstParam =
+			func->params.front().strict_as<ast::ObjectDecl>();
+	const ast::ObjectDecl * srcParam = 
+			func->params.back().strict_as<ast::ObjectDecl>();
+	
+	ast::Expr * srcSelect = new ast::VariableExpr( location, srcParam );
+
+	ast::CompoundStmt * stmts = new ast::CompoundStmt( location );
+
+	InitTweak::InitExpander_new srcParamTweak( srcSelect );
+	ast::Expr * dstSelect = 
+	new ast::MemberExpr(
+		location,
+		lhs,
+		new ast::MemberExpr(
+			location,
+			first,
+			new ast::CastExpr(
+				location,
+				new ast::VariableExpr( location, dstParam ),
+				dstParam->type.strict_as<ast::ReferenceType>()->base
+			)
+		)
+	);
+	auto stmt = genImplicitCall(
+		srcParamTweak, dstSelect, location, func->name,
+		first, SymTab::LoopForward
+	);
+	stmts->push_back( stmt );
+	func->stmts = stmts;
+} 
+
+void StructFuncGenerator::genADTFuncs() {
+	if ( decl->kind != ast::AggregateDecl::ADT ) return;
+	assert( decl->members.size() == 2 );
+	auto first = (decl->members[0]).as<ast::ObjectDecl>();
+	assert(first != nullptr);
+	auto firstType = first->type;
+	auto unionInstDecl = firstType.as<ast::UnionInstType>();
+	assert(unionInstDecl != nullptr);
+	auto unionDecl = unionInstDecl->base;
+
+	// for (auto mem: unionDecl->members) {
+	for ( std::size_t i = 0; i < unionDecl->members.size(); ++i ) {
+		auto mem = unionDecl->members[i];
+		const ast::ObjectDecl * mem_as_obj = mem.as<ast::ObjectDecl>();
+		assert( mem_as_obj );
+		auto mem_type = mem_as_obj->type.as<ast::StructInstType>();
+		assert( mem_type );
+		auto location = getLocation();
+		ast::FunctionDecl * func = new ast::FunctionDecl(
+			getLocation(),
+			"?{}", // name
+			{}, //forall
+			{ dstParam(), new ast::ObjectDecl( getLocation(), "_src", ast::deepCopy( mem_type ) ) }, // params
+			{}, // returns
+			{}, // statements
+			// Use static storage if we are at the top level.
+			(0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
+			proto_linkage,
+			std::vector<ast::ptr<ast::Attribute>>(),
+			// Auto-generated routines are inline to avoid conflicts.
+			ast::Function::Specs( ast::Function::Inline )
+		);
+		getADTFuncBody(mem_as_obj, func);
+		func->fixUniqueId();
+		produceForwardDecl(func);
+		if ( CodeGen::isAssignment( func->name ) ) {
+			appendReturnThis( func );
+		}
+		produceDecl( func );
 	}
 }
