Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/AST/Decl.cpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -169,4 +169,13 @@
 }
 
+const std::string EnumDecl::getUnmangeldArrayName( const ast::EnumAttribute attr ) const {
+		switch( attr ) {
+			case ast::EnumAttribute::Value: return "values_" + name ;
+			case ast::EnumAttribute::Label: return "labels_" + name;
+			default: /* Posn does not generate array */ 
+				return "";
+		}
+	}
+
 }
 
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/AST/Decl.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -303,4 +303,5 @@
 };
 
+enum class EnumAttribute{ Value, Posn, Label };
 /// enum declaration `enum Foo { ... };`
 class EnumDecl final : public AggregateDecl {
@@ -326,5 +327,5 @@
 	const char * typeString() const override { return aggrString( Enum ); }
 
-
+	const std::string getUnmangeldArrayName( const EnumAttribute attr ) const;
 private:
 	EnumDecl * clone() const override { return new EnumDecl{ *this }; }
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/AST/Fwd.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -133,5 +133,5 @@
 class OneType;
 class GlobalScopeType;
-class EnumPosType;
+class EnumAttrType;
 
 class Designation;
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/AST/Pass.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -222,5 +222,5 @@
 	const ast::Type *             visit( const ast::UnionInstType        * ) override final;
 	const ast::Type *             visit( const ast::EnumInstType         * ) override final;
-	const ast::Type *             visit( const ast::EnumPosType          * ) override final;
+	const ast::Type *             visit( const ast::EnumAttrType         * ) override final;
 	const ast::Type *             visit( const ast::TraitInstType        * ) override final;
 	const ast::Type *             visit( const ast::TypeInstType         * ) override final;
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/AST/Pass.impl.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -1986,9 +1986,8 @@
 
 //--------------------------------------------------------------------------
-// EnumPosType
-template< typename core_t >
-const ast::Type * ast::Pass< core_t >::visit( const ast::EnumPosType * node ) {
-	VISIT_START( node );
-
+// EnumAttrType
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::EnumAttrType * node ) {
+	VISIT_START( node );
 	VISIT_END( Type, node );
 }
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/AST/Print.cpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -1576,7 +1576,14 @@
 	}
 
-	virtual const ast::Type * visit( const ast::EnumPosType * node ) override final {
-		preprint( node );
-		os << "enum pos with ";
+	virtual const ast::Type * visit( const ast::EnumAttrType * node ) override final {
+		preprint( node );
+		os << "enum attr ";
+        if ( node->attr == ast::EnumAttribute::Label ) {
+            os << "Label ";
+        } else if ( node->attr == ast::EnumAttribute::Value ) {
+            os << "Value ";
+        } else {
+            os << "Posn ";
+        }
 		(*(node->instance)).accept( *this );
 		return node;
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/AST/Type.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -362,12 +362,17 @@
 using EnumInstType = SueInstType<EnumDecl>;
 
-class EnumPosType final : public Type {
+class EnumAttrType final : public Type {
 public:
 	readonly<EnumInstType> instance;
-	const Type * accept( Visitor & v ) const override { return v.visit( this ); }
-	EnumPosType( const EnumInstType * instance ): instance(instance) {}
+    EnumAttribute attr;
+	const Type * accept( Visitor & v ) const override { return v.visit( this ); }
+	EnumAttrType( const EnumInstType * instance, EnumAttribute attr = EnumAttribute::Posn )
+		: instance(instance), attr(attr) {}
 	
-private:
-	EnumPosType * clone() const override { return new EnumPosType{ *this }; }
+    bool match( const ast::EnumAttrType * other) const {
+        return instance->base->name == other->instance->base->name && attr == other->attr;
+    }
+private:
+	EnumAttrType * clone() const override { return new EnumAttrType{ *this }; }
 	MUTATE_FRIEND
 };
Index: src/AST/Visitor.hpp
===================================================================
--- src/AST/Visitor.hpp	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/AST/Visitor.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -119,5 +119,5 @@
     virtual const ast::Type *             visit( const ast::OneType              * ) = 0;
     virtual const ast::Type *             visit( const ast::GlobalScopeType      * ) = 0;
-    virtual const ast::Type *             visit( const ast::EnumPosType          * ) = 0;
+    virtual const ast::Type *             visit( const ast::EnumAttrType         * ) = 0;
     virtual const ast::Designation *      visit( const ast::Designation          * ) = 0;
     virtual const ast::Init *             visit( const ast::SingleInit           * ) = 0;
Index: src/CodeGen/GenType.cc
===================================================================
--- src/CodeGen/GenType.cc	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/CodeGen/GenType.cc	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -46,5 +46,5 @@
 	void postvisit( ast::UnionInstType const * type );
 	void postvisit( ast::EnumInstType const * type );
-	void postvisit( ast::EnumPosType const * type );
+	void postvisit( ast::EnumAttrType const * type );
 	void postvisit( ast::TypeInstType const * type );
 	void postvisit( ast::TupleType const * type );
@@ -240,5 +240,5 @@
 }
 
-void GenType::postvisit( ast::EnumPosType const * type ) {
+void GenType::postvisit( ast::EnumAttrType const * type ) {
 	postvisit( type->instance );
 }
Index: src/Common/CodeLocationTools.cpp
===================================================================
--- src/Common/CodeLocationTools.cpp	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/Common/CodeLocationTools.cpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -188,5 +188,5 @@
     macro(UnionInstType, Type) \
     macro(EnumInstType, Type) \
-    macro(EnumPosType, Type) \
+    macro(EnumAttrType, Type) \
     macro(TraitInstType, Type) \
     macro(TypeInstType, Type) \
Index: src/GenPoly/Lvalue.cpp
===================================================================
--- src/GenPoly/Lvalue.cpp	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/GenPoly/Lvalue.cpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -133,18 +133,4 @@
 			return func->linkage == ast::Linkage::Intrinsic
 				&& lvalueFunctions.count( func->name );
-		}
-	}
-	return false;
-}
-
-bool isGeneratedInstrinct( ast::Expr const * expr ) {
-	if ( auto app = dynamic_cast<ast::ApplicationExpr const *>( expr ) ) {
-		if ( app->args.size() == 2 && ast::getFunction( app )->name == "?[?]" ) {
-			auto param_1 = dynamic_cast<ast::VariableExpr const *>(app->args.front().get());
-			if ( param_1 ) {
-				auto param_1_as_obj = param_1->var.as<ast::ObjectDecl>();
-				return ( param_1_as_obj->name.find( "values_") != std::string::npos
-					||  param_1_as_obj->name.find( "labels_" ) != std::string::npos );
-			}
 		}
 	}
@@ -176,5 +162,5 @@
 		ast::ApplicationExpr const * expr ) {
 
-	if ( skip == SkipInProgress || !isIntrinsicReference( expr ) || isGeneratedInstrinct( expr ) ) {
+	if ( skip == SkipInProgress || !isIntrinsicReference( expr ) ) {
 		return expr;
 	}
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -285,5 +285,5 @@
 		const CodeLocation & location,
 		const ast::Type * paramType, const ast::Init * init, const ExplodedArgs & args,
-		std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
+		std::vector< ArgPack > & results, std::size_t & genStart, const ResolveContext & context,
 		unsigned nTuples = 0
 	) {
@@ -295,5 +295,5 @@
 				// ^^^ need to handle the case where a tuple has a default argument
 				if ( ! instantiateArgument( location,
-					type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
+					type, nullptr, args, results, genStart, context, nTuples ) ) return false;
 				nTuples = 0;
 			}
@@ -510,9 +510,30 @@
 
 				// attempt to unify types
-				if ( unify( paramType, argType, env, need, have, open ) ) {
+				ast::ptr<ast::Type> common;
+				if ( unify( paramType, argType, env, need, have, open, common ) ) {
 					// add new result
-					results.emplace_back(
-						i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
-						nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
+					assert( common );
+					// auto attrType = common.as<ast::EnumAttrType>();
+					// if ( attrType && ( attrType->attr == ast::EnumAttribute::Value ) ) {
+					// 	auto callExpr = new ast::UntypedExpr(
+					// 		expr->location, new ast::NameExpr( expr->location, "valueE"), {expr} );
+					// 	CandidateFinder finder( context, env );
+					// 	finder.find( callExpr );
+					// 	CandidateList winners = findMinCost( finder.candidates );
+					// 	if (winners.size() != 1) {
+					// 		SemanticError( callExpr, "Ambiguous expression in valueE" );
+					// 	}
+					// 	CandidateRef & choice = winners.front();
+					// 	choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
+
+					// 	results.emplace_back(
+					// 		i, choice->expr, 
+					// 		std::move( env ), std::move( need ), std::move( have ), std::move( open ),
+					// 		nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
+					// } else {
+						results.emplace_back(
+							i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
+							nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
+					//}
 				}
 			}
@@ -786,5 +807,5 @@
 					auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();
 					if ( !instantiateArgument( location,
-						funcType->params[i], obj->init, args, results, genStart, symtab)) return;
+						funcType->params[i], obj->init, args, results, genStart, context)) return;
 				}
 				goto endMatch;
@@ -796,5 +817,5 @@
 			// no default args for indirect calls
 			if ( !instantiateArgument( location,
-				param, nullptr, args, results, genStart, symtab ) ) return;
+				param, nullptr, args, results, genStart, context ) ) return;
 		}
 
@@ -891,62 +912,21 @@
 		} else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
 			addAggMembers( unionInst, aggrExpr, *cand, Cost::unsafe, "" );
-		} 
-		else if ( auto enumInst = aggrExpr->result.as< ast::EnumInstType >() ) {
-			if (enumInst->base && enumInst->base->base) {
-            const CodeLocation &location = cand->expr->location;
-
-            CandidateFinder funcFinder(context, tenv);
-            auto nameExpr = new ast::NameExpr(location, "valueE");
-            ResolveMode mode = {true, false, selfFinder.candidates.empty()};
-            funcFinder.find( nameExpr, mode );
-
-            // make variableExpr itself the candidate for the value Call
-            ExplodedArgs argExpansions;
-            argExpansions.emplace_back();
-            auto &argE = argExpansions.back();
-
-            argE.emplace_back(*cand, symtab); // Use the typed name expr as param for value
-
-            CandidateList found;
-            SemanticErrorException errors;
-
-            for (CandidateRef &func : funcFinder) {
-                try {
-                    const ast::Type *funcResult =
-                        func->expr->result->stripReferences();
-                    if (auto pointer = dynamic_cast<const ast::PointerType *>(
-                            funcResult)) {
-                        if (auto function =
-                                pointer->base.as<ast::FunctionType>()) {
-                            CandidateRef newFunc{new Candidate{*func}};
-                            newFunc->expr = referenceToRvalueConversion(
-                                newFunc->expr, newFunc->cost);
-                            makeFunctionCandidates( location,
-                                                   newFunc, function,
-                                                   argExpansions, found );
-                        }
-                    }
-                } catch (SemanticErrorException &e) {
-                    std::cerr
-                        << "Resolving value function should cause an error"
-                        << std::endl;
-                    errors.append(e);
-                }
-            }
-
-            if (found.empty()) {
-                std::cerr << "Resolve value function should always success"
-                          << std::endl;
-            }
-
-            for (CandidateRef &withFunc : found) {
-                withFunc->cost.incSafe();
-                Cost cvtCost =
-                    computeApplicationConversionCost(withFunc, symtab);
-                assert(cvtCost != Cost::infinity);
-
-                candidates.emplace_back(std::move(withFunc));
-            }
-        }
+		} else if ( auto enumInst = aggrExpr->result.as< ast::EnumInstType >() ) {
+			if ( enumInst->base->base ) {
+				CandidateFinder finder( context, tenv );
+				auto location = aggrExpr->location;
+				auto callExpr = new ast::UntypedExpr(
+					location, new ast::NameExpr( location, "valueE" ), {aggrExpr}
+				);
+				finder.find( callExpr );
+				CandidateList winners = findMinCost( finder.candidates );
+				if (winners.size() != 1) {
+					SemanticError( callExpr, "Ambiguous expression in valueE" );
+				}
+				CandidateRef & choice = winners.front();
+				// choice->cost.incSafe();
+				candidates.emplace_back( std::move(choice) );
+			}
+
 		}
 	}
@@ -1415,6 +1395,13 @@
 			ast::Expr * newExpr = data.combine( nameExpr->location, cost );
 
+			bool bentConversion = false;
+			if ( auto inst = newExpr->result.as<ast::EnumInstType>() ) {
+				if ( inst->base && inst->base->base ) {
+					bentConversion = true;
+				}
+			}
+			
 			CandidateRef newCand = std::make_shared<Candidate>(
-				newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
+				newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, bentConversion? Cost::safe: Cost::zero,
 				cost );
 
@@ -1449,64 +1436,4 @@
         auto cand = new Candidate(variableExpr, tenv);
         candidates.emplace_back(cand);
-
-        if (auto enumInst = dynamic_cast<const ast::EnumInstType *>(
-                variableExpr->var->get_type())) {
-            if (enumInst->base && enumInst->base->base) {
-                const CodeLocation &location = cand->expr->location;
-
-                CandidateFinder funcFinder(context, tenv);
-                auto nameExpr = new ast::NameExpr(location, "valueE");
-                ResolveMode mode = {true, false, selfFinder.candidates.empty()};
-                funcFinder.find( nameExpr, mode );
-
-                // make variableExpr itself the candidate for the value Call
-                ExplodedArgs argExpansions;
-                argExpansions.emplace_back();
-                auto &argE = argExpansions.back();
-
-                argE.emplace_back(*cand, symtab);
-
-                CandidateList found;
-                SemanticErrorException errors;
-
-                for (CandidateRef &func : funcFinder) {
-                    try {
-                    const ast::Type *funcResult =
-                        func->expr->result->stripReferences();
-                    if (auto pointer = dynamic_cast<const ast::PointerType *>(
-                            funcResult)) {
-                        if (auto function =
-                                pointer->base.as<ast::FunctionType>()) {
-                            CandidateRef newFunc{new Candidate{*func}};
-                            newFunc->expr = referenceToRvalueConversion(
-                                newFunc->expr, newFunc->cost);
-                            makeFunctionCandidates(variableExpr->location,
-                                                   newFunc, function,
-                                                   argExpansions, found);
-                        }
-                    }
-                    } catch (SemanticErrorException &e) {
-                        std::cerr
-                            << "Resolving value function should cause an error"
-                            << std::endl;
-                        errors.append(e);
-                    }
-                }
-
-                if (found.empty()) {
-                    std::cerr << "Resolve value function should always success"
-                            << std::endl;
-                }
-
-                for (CandidateRef &withFunc : found) {
-                    withFunc->cost.incSafe();
-                    Cost cvtCost =
-                        computeApplicationConversionCost(withFunc, symtab);
-                    assert(cvtCost != Cost::infinity);
-
-                    candidates.emplace_back(std::move(withFunc));
-                }
-            }
-        }
     }
 
@@ -1840,5 +1767,6 @@
 
 				// unification run for side-effects
-				bool canUnify = unify( toType, cand->expr->result, env, need, have, open );
+				ast::ptr<ast::Type> common;
+				bool canUnify = unify( toType, cand->expr->result, env, need, have, open, common );
 				(void) canUnify;
 				Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
@@ -1865,16 +1793,39 @@
 					// ambiguous case, still output candidates to print in error message
 					if ( cand->cost == minExprCost && thisCost == minCastCost ) {
-						CandidateRef newCand = std::make_shared<Candidate>(
-							new ast::InitExpr{
-								initExpr->location,
-								restructureCast( cand->expr, toType ),
-								initAlt.designation },
-							std::move(env), std::move( open ), std::move( need ), cand->cost + thisCost );
-						// currently assertions are always resolved immediately so this should have no effect.
-						// if this somehow changes in the future (e.g. delayed by indeterminate return type)
-						// we may need to revisit the logic.
-						inferParameters( newCand, matches );
-					}
-				}
+						auto commonAsEnumAttr = common.as<ast::EnumAttrType>();
+						if ( commonAsEnumAttr && commonAsEnumAttr->attr == ast::EnumAttribute::Value ) {
+							
+							auto callExpr = new ast::UntypedExpr(
+								cand->expr->location, new ast::NameExpr( cand->expr->location, "valueE"), {cand->expr} );
+							CandidateFinder finder( context, env );
+							finder.find( callExpr );
+							CandidateList winners = findMinCost( finder.candidates );
+							if (winners.size() != 1) {
+								SemanticError( callExpr, "Ambiguous expression in valueE" );
+							}
+							CandidateRef & choice = winners.front();
+							// assert( valueCall->result );
+							CandidateRef newCand = std::make_shared<Candidate>(
+								new ast::InitExpr{
+									initExpr->location,
+									// restructureCast( cand->expr, toType ),
+									choice->expr,
+									initAlt.designation },
+								std::move(env), std::move( open ), std::move( need ), cand->cost + thisCost );
+								inferParameters( newCand, matches );
+						} else {
+							CandidateRef newCand = std::make_shared<Candidate>(
+								new ast::InitExpr{
+									initExpr->location,
+									restructureCast( cand->expr, toType ),
+									initAlt.designation },
+								std::move(env), std::move( open ), std::move( need ), cand->cost + thisCost );
+							// currently assertions are always resolved immediately so this should have no effect.
+							// if this somehow changes in the future (e.g. delayed by indeterminate return type)
+							// we may need to revisit the logic.
+							inferParameters( newCand, matches );	
+						}
+					}			
+				}	
 			}
 		}
@@ -1901,5 +1852,5 @@
 						std::make_shared<Candidate>(
 							newExpr, copy( tenv ), ast::OpenVarSet{},
-							ast::AssertionSet{}, Cost::zero, cost
+							ast::AssertionSet{}, Cost::safe, cost
 						);
 
@@ -2201,4 +2152,21 @@
 }
 
+// get the valueE(...) ApplicationExpr that returns the enum value
+const ast::Expr * getValueEnumCall( 
+	const ast::Expr * expr, 
+	const ResolvExpr::ResolveContext & context, const ast::TypeEnvironment & env ) {
+		auto callExpr = new ast::UntypedExpr(
+			expr->location, new ast::NameExpr( expr->location, "valueE"), {expr} );
+		CandidateFinder finder( context, env );
+		finder.find( callExpr );
+		CandidateList winners = findMinCost( finder.candidates );
+		if (winners.size() != 1) {
+			SemanticError( callExpr, "Ambiguous expression in valueE" );
+		}
+		CandidateRef & choice = winners.front();
+		return choice->expr;
+		// return std::move( choice->expr.get() );
+}
+
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/CandidateFinder.hpp
===================================================================
--- src/ResolvExpr/CandidateFinder.hpp	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/ResolvExpr/CandidateFinder.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -70,4 +70,7 @@
 	const ast::Expr * expr, Cost & cost );
 
+const ast::Expr * getValueEnumCall(const ast::Expr * expr,
+	const ResolvExpr::ResolveContext & context, const ast::TypeEnvironment & env );
+
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/CommonType.cc
===================================================================
--- src/ResolvExpr/CommonType.cc	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/ResolvExpr/CommonType.cc	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -385,7 +385,5 @@
 		} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
 			const ast::EnumDecl* enumDecl = enumInst->base;
-			if ( enumDecl->base ) {
-				result = enumDecl->base.get();
-			} else {
+			if ( !enumDecl->base ) {
 				ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ];
 				if (
@@ -398,14 +396,16 @@
 				}
 			}
-		} else if ( dynamic_cast< const ast::EnumPosType * >( type2 ) ) {
-			ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ];
-			if (
-				( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
-					|| widen.first )
-				&& ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
-					|| widen.second )
-			) {
-				result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
-			}
+		} else if ( auto type2AsAttr = dynamic_cast< const ast::EnumAttrType * >( type2 ) ) {
+            if ( type2AsAttr->attr == ast::EnumAttribute::Posn ) {
+			    ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ];
+			    if (
+				    ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
+					    || widen.first )
+				    && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
+					    || widen.second )
+			    ) {
+				    result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
+			    }
+            }
 		}
 	}
@@ -426,17 +426,4 @@
 		result = voidPtr;
 		add_qualifiers( result, oPtr->qualifiers );
-	}
-
-	// For a typed enum, we want to unify type1 with the base type of the enum
-	bool tryResolveWithTypedEnum( const ast::Type * type1 ) {
-		if (auto enumInst = dynamic_cast<const ast::EnumInstType *> (type2) ) {
-			ast::OpenVarSet newOpen{ open };
-			if (enumInst->base->base
-				&& unifyExact(type1, enumInst->base->base, tenv, need, have, newOpen, widen)) {
-					result = type1;
-				return true;
-			}
-		}
-		return false;
 	}
 
@@ -607,13 +594,8 @@
 			result = pointer;
 			add_qualifiers( result, type2->qualifiers );
-		} else {
-			tryResolveWithTypedEnum( pointer );
-		}
-	}
-
-	void postvisit( const ast::ArrayType * arr ) {
-		// xxx - does it make sense?
-		tryResolveWithTypedEnum( arr );
-	}
+		}
+	}
+
+	void postvisit( const ast::ArrayType * arr ) {}
 
 	void postvisit( const ast::ReferenceType * ref ) {
@@ -659,36 +641,18 @@
 	}
 
-	void postvisit( const ast::FunctionType * func) {
-		tryResolveWithTypedEnum( func );
-	}
-
-	void postvisit( const ast::StructInstType * inst ) {
-		tryResolveWithTypedEnum( inst );
-	}
-
-	void postvisit( const ast::UnionInstType * inst ) {
-		tryResolveWithTypedEnum( inst );
-	}
+	void postvisit( const ast::FunctionType * func) {}
+
+	void postvisit( const ast::StructInstType * inst ) {}
+
+	void postvisit( const ast::UnionInstType * inst ) {}
 
 	void postvisit( const ast::EnumInstType * enumInst ) {
-		// if ( dynamic_cast<const ast::EnumPosType *>(enumInst) ) {
-		// 	result = enumInst;
-		// } else 
-		if (!dynamic_cast<const ast::EnumInstType *>(type2)) {
-			result = commonType( type2, enumInst, tenv, need, have, open, widen);
-		}
-	}
-
-	void postvisit( const ast::EnumPosType * enumPos ) {
-		if ( auto type2AsPos = dynamic_cast<const ast::EnumPosType *>(type2) ) {
-			// result = commonType( type2AsPos->instance, enumPos->instance, tenv, need, have, open, widen );
-			// result = enumPos;
-			if ( enumPos->instance->base->name == type2AsPos->instance->base->name ) {
-				result = type2;
-			}
-		} else if ( dynamic_cast<const ast::BasicType *>(type2) ) {
-			result = type2;
-		}
-	}
+		if ( enumInst->base && !enumInst->base->base ) {
+			auto basicType = new ast::BasicType( ast::BasicType::UnsignedInt );
+			result = commonType( basicType, type2, tenv, need, have, open, widen);
+		}
+	}
+
+	void postvisit( const ast::EnumAttrType * ) {}
 
 	void postvisit( const ast::TraitInstType * ) {}
@@ -696,7 +660,5 @@
 	void postvisit( const ast::TypeInstType * ) {}
 
-	void postvisit( const ast::TupleType * tuple ) {
-		tryResolveWithTypedEnum( tuple );
-	}
+	void postvisit( const ast::TupleType * tuple ) {}
 
 	void postvisit( const ast::VarArgsType * ) {}
@@ -715,8 +677,5 @@
 		} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
 			const ast::EnumDecl * enumDecl = enumInst->base;
-			if ( enumDecl->base ) {
-				if ( tryResolveWithTypedEnum( zero ) )
-					add_qualifiers( result, zero->qualifiers );
-			} else {
+			if ( !enumDecl->base ) {
 				if ( widen.second || zero->qualifiers <= type2->qualifiers ) {
 					result = type2;
@@ -738,9 +697,6 @@
 				ast::BasicType::SignedInt, one->qualifiers | type2->qualifiers };
 		} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
-			const ast::EnumDecl * enumBase = enumInst->base;
-			if ( enumBase->base ) {
-				if ( tryResolveWithTypedEnum( one ))
-					add_qualifiers( result, one->qualifiers );
-			} else {
+			const ast::EnumDecl * enumDecl = enumInst->base;
+			if ( !enumDecl->base ) {
 				if ( widen.second || one->qualifiers <= type2->qualifiers ) {
 					result = type2;
Index: src/ResolvExpr/ConversionCost.cc
===================================================================
--- src/ResolvExpr/ConversionCost.cc	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/ResolvExpr/ConversionCost.cc	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -278,17 +278,12 @@
 	if ( const ast::BasicType * dstAsBasic = dynamic_cast< const ast::BasicType * >( dst ) ) {
 		conversionCostFromBasicToBasic( basicType, dstAsBasic );
-	} 
-	else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( dst ) ) {
-		auto enumDecl = enumInst->base;
-		if ( enumDecl->base.get() ) {
-			// cost = costCalc( basicType, baseType, srcIsLvalue, symtab, env );
-			// cost.incUnsafe();
-			cost = Cost::infinity;
-		} else {
-            cost = Cost::unsafe;
-		}
-	} else if ( dynamic_cast< const ast::EnumPosType *>(dst) ) {
+	} else if ( dynamic_cast< const ast::EnumAttrType *>(dst) ) {
 		static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
 		cost = costCalc( basicType, integer, srcIsLvalue, symtab, env );
+	} else if ( auto dstAsEnumInst = dynamic_cast< const ast::EnumInstType * >( dst ) ) {
+		if ( dstAsEnumInst->base && !dstAsEnumInst->base->base ) {
+			cost = Cost::zero;
+			cost.incUnsafe();
+		}
 	}
 }
@@ -366,5 +361,27 @@
 }
 
-void ConversionCost::postvisit( const ast::EnumInstType * ) {
+void ConversionCost::postvisit( const ast::EnumInstType * inst ) {
+	if ( inst->base && inst->base->base ) {
+		if ( auto dstAsAttr = dynamic_cast<const ast::EnumAttrType *>( dst ) ) {
+			auto instAsAttr = ast::EnumAttrType( inst, dstAsAttr->attr );
+			if ( instAsAttr.match(dstAsAttr) ) {
+				cost.incUnsafe();
+			}
+
+		} else if ( auto dstAsInst = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
+			if (inst->base && dstAsInst->base) {
+				if (inst->base == dstAsInst->base) {
+					cost.incUnsafe();
+				}
+			}
+		} else {
+			auto instAsVal = ast::EnumAttrType( inst, ast::EnumAttribute::Value );
+			cost = costCalc( &instAsVal, dst, srcIsLvalue, symtab, env );
+			if ( cost < Cost::infinity ) {
+				cost.incUnsafe();
+			}
+		}
+		return;
+	} 
 	static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
 	cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
@@ -374,20 +391,33 @@
 }
 
-void ConversionCost::postvisit( const ast::EnumPosType * src ) {
-	if ( dynamic_cast<const ast::EnumPosType *>( dst ) ) {
-		// cost = costCalc( src->instance, dstBase->instance, srcIsLvalue, symtab, env );
-		// if ( cost < Cost::unsafe ) cost.incSafe();
-		cost = Cost::zero;
-	} else if ( auto dstBase = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
-		cost = costCalc( src->instance, dstBase, srcIsLvalue, symtab, env );
-		if ( cost < Cost::unsafe ) cost.incSafe();
-	} else {
-		static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
-		cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
-		if ( cost < Cost::unsafe ) {
-			cost.incSafe();
-		}
-	}
-
+void ConversionCost::postvisit( const ast::EnumAttrType * src ) {
+    auto dstAsEnumAttrType = dynamic_cast<const ast::EnumAttrType *>(dst);
+    if ( src->attr == ast::EnumAttribute::Label ) {
+        if ( dstAsEnumAttrType && dstAsEnumAttrType->attr == ast::EnumAttribute::Label ) {
+            cost = costCalc( src->instance, dstAsEnumAttrType->instance, srcIsLvalue, symtab, env );
+        } 
+        // Add Conversion To String
+    } else if ( src->attr == ast::EnumAttribute::Value ) {
+        if ( dstAsEnumAttrType && dstAsEnumAttrType->attr == ast::EnumAttribute::Value) {
+            cost = costCalc( src->instance, dstAsEnumAttrType->instance, srcIsLvalue, symtab, env );
+        } else {
+            auto baseType = src->instance->base->base;
+            cost = costCalc( baseType, dst, srcIsLvalue, symtab, env );
+			if ( cost < Cost::infinity ) {
+				cost.incUnsafe();
+			}
+        }
+    } else { // ast::EnumAttribute::Posn
+        if ( auto dstBase = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
+		    cost = costCalc( src->instance, dstBase, srcIsLvalue, symtab, env );
+		    if ( cost < Cost::unsafe ) cost.incSafe();
+	    } else {
+		    static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
+		    cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
+		    if ( cost < Cost::unsafe ) {
+			    cost.incSafe();
+		    }
+	    }
+    }
 }
 
@@ -466,4 +496,9 @@
 		cost.incSafe( maxIntCost + 2 );
 		// assuming 0p is supposed to be used for pointers?
+	} else if ( auto dstAsEnumInst = dynamic_cast< const ast::EnumInstType * >( dst ) ) {
+		if ( dstAsEnumInst->base && !dstAsEnumInst->base->base ) {
+			cost = Cost::zero;
+			cost.incUnsafe();
+		}
 	}
 }
@@ -483,4 +518,9 @@
 			cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
 		}
+	} else if ( auto dstAsEnumInst = dynamic_cast< const ast::EnumInstType * >( dst ) ) {
+		if ( dstAsEnumInst->base && !dstAsEnumInst->base->base ) {
+			cost = Cost::zero;
+			cost.incUnsafe();
+		}
 	}
 }
Index: src/ResolvExpr/ConversionCost.h
===================================================================
--- src/ResolvExpr/ConversionCost.h	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/ResolvExpr/ConversionCost.h	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -72,5 +72,5 @@
 	void postvisit( const ast::ZeroType * zeroType );
 	void postvisit( const ast::OneType * oneType );
-	void postvisit( const ast::EnumPosType * posType );
+	void postvisit( const ast::EnumAttrType * posType );
 private:
 	// refactor for code resue
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/ResolvExpr/Unify.cc	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -274,6 +274,8 @@
 		void previsit( const ast::Node * ) { visit_children = false; }
 
-		void postvisit( const ast::VoidType * ) {
-			result = dynamic_cast< const ast::VoidType * >( type2 );
+		void postvisit( const ast::VoidType * vt) {
+			result = dynamic_cast< const ast::VoidType * >( type2 )
+				|| tryToUnifyWithEnumValue(vt, type2, tenv, need, have, open, noWiden());
+			;
 		}
 
@@ -282,4 +284,5 @@
 				result = basic->kind == basic2->kind;
 			}
+			result = result || tryToUnifyWithEnumValue(basic, type2, tenv, need, have, open, noWiden());
 		}
 
@@ -290,4 +293,5 @@
 					noWiden());
 			}
+			result = result || tryToUnifyWithEnumValue(pointer, type2, tenv, need, have, open, noWiden());
 		}
 
@@ -307,5 +311,6 @@
 
 			result = unifyExact(
-				array->base, array2->base, tenv, need, have, open, noWiden());
+				array->base, array2->base, tenv, need, have, open, noWiden())
+				|| tryToUnifyWithEnumValue(array, type2, tenv, need, have, open, noWiden());
 		}
 
@@ -399,4 +404,18 @@
 		}
 
+		bool tryToUnifyWithEnumValue( const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
+			ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
+			WidenMode widen) {
+			if ( auto attrType2 = dynamic_cast<const ast::EnumAttrType *>(type2)) {
+				if (attrType2->attr == ast::EnumAttribute::Value) {
+					return unifyExact( type1, attrType2->instance->base->base, env, need, have, open,
+						widen);
+				} else if (attrType2->attr == ast::EnumAttribute::Posn) {
+					return unifyExact( type1, attrType2->instance, env, need, have, open, widen );
+				}
+			}
+			return false;
+		}
+
 	public:
 		void postvisit( const ast::FunctionType * func ) {
@@ -507,25 +526,29 @@
 		void postvisit( const ast::StructInstType * aggrType ) {
 			handleGenericRefType( aggrType, type2 );
+			result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
 		}
 
 		void postvisit( const ast::UnionInstType * aggrType ) {
 			handleGenericRefType( aggrType, type2 );
+			result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
 		}
 
 		void postvisit( const ast::EnumInstType * aggrType ) {
 			handleRefType( aggrType, type2 );
-		}
-
-		void postvisit( const ast::EnumPosType * posType ) {
+			result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
+		}
+
+		void postvisit( const ast::EnumAttrType * enumAttr ) {
 			// Lazy approach for now
-			auto otherPos = dynamic_cast< const ast::EnumPosType *>(type2);
-			if ( otherPos ) {
-				if ( otherPos->instance->base->name == posType->instance->base->name )
-					result = otherPos;
-			}
+			if ( auto otherPos = dynamic_cast< const ast::EnumAttrType *>(type2) ) {
+			    if ( enumAttr->match(otherPos) ) {
+				    result = otherPos;
+			    }
+            }  
 		}
 
 		void postvisit( const ast::TraitInstType * aggrType ) {
 			handleRefType( aggrType, type2 );
+			result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
 		}
 
@@ -536,4 +559,5 @@
 				this->result = otherInst;
 			}
+			result = result || tryToUnifyWithEnumValue(typeInst, type2, tenv, need, have, open, noWiden());
 		}
 
@@ -610,17 +634,21 @@
 			auto types2 = flatten( flat2 );
 
-			result = unifyList( types, types2, tenv, need, have, open );
-		}
-
-		void postvisit( const ast::VarArgsType * ) {
-			result = dynamic_cast< const ast::VarArgsType * >( type2 );
-		}
-
-		void postvisit( const ast::ZeroType * ) {
-			result = dynamic_cast< const ast::ZeroType * >( type2 );
-		}
-
-		void postvisit( const ast::OneType * ) {
-			result = dynamic_cast< const ast::OneType * >( type2 );
+			result = unifyList( types, types2, tenv, need, have, open )
+				|| tryToUnifyWithEnumValue(tuple, type2, tenv, need, have, open, noWiden());
+		}
+
+		void postvisit( const ast::VarArgsType * vat) {
+			result = dynamic_cast< const ast::VarArgsType * >( type2 )
+				|| tryToUnifyWithEnumValue(vat, type2, tenv, need, have, open, noWiden());
+		}
+
+		void postvisit( const ast::ZeroType * zt) {
+			result = dynamic_cast< const ast::ZeroType * >( type2 )
+				|| tryToUnifyWithEnumValue(zt, type2, tenv, need, have, open, noWiden());
+		}
+
+		void postvisit( const ast::OneType * ot) {
+			result = dynamic_cast< const ast::OneType * >( type2 )
+				|| tryToUnifyWithEnumValue(ot, type2, tenv, need, have, open, noWiden());
 		}
 	};
Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/SymTab/Mangler.cc	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -58,6 +58,5 @@
 	void postvisit( const ast::OneType * oneType );
 	void postvisit( const ast::QualifiedType * qualType );
-
-	void postvisit( const ast::EnumPosType * posType );
+	void postvisit( const ast::EnumAttrType * posType );
 
 	/// The result is the current constructed mangled name.
@@ -281,7 +280,20 @@
 }
 
-void Mangler::postvisit( const ast::EnumPosType * pos ) {
-	postvisit( pos->instance );
-	mangleName += "_pos";
+void Mangler::postvisit( const ast::EnumAttrType * enumAttr ) {
+	postvisit( enumAttr->instance );
+	// mangleName += "_pos";
+    switch ( enumAttr->attr )
+    {
+        case ast::EnumAttribute::Label:
+            mangleName += "_label_";
+            break;
+        case ast::EnumAttribute::Posn:
+			mangleName += "_posn_";
+            break;
+        case ast::EnumAttribute::Value:
+            mangleName += "_value_";
+            break;
+    }
+
 }
 
Index: src/Validate/Autogen.cpp
===================================================================
--- src/Validate/Autogen.cpp	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/Validate/Autogen.cpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -196,22 +196,8 @@
 
 	bool shouldAutogen() const final { return true; }
-	void genAttrFuncForward();
-	void genPosFunctions();
 private:
 	void genFuncBody( ast::FunctionDecl * decl ) final;
 	void genFieldCtors() final;
 	const ast::Decl * getDecl() const final { return decl; }
-
-	ast::FunctionDecl * genPosProto() const;
-	ast::FunctionDecl * genLabelProto() const;
-	ast::FunctionDecl * genValueProto() const;
-	ast::FunctionDecl * genSuccProto() const;
-	ast::FunctionDecl * genPredProto() const;
-
-	ast::FunctionDecl * genSuccPosProto() const;
-	ast::FunctionDecl * genPredPosProto() const;
-
-	ast::FunctionDecl * genSuccPredFunc( bool succ );
-	// ast::FunctionDecl * genPredFunc();
 };
 
@@ -256,8 +242,4 @@
 	enumInst.base = enumDecl;
 	EnumFuncGenerator gen( enumDecl, &enumInst, functionNesting );
-	if ( enumDecl->base ) {
-		gen.genAttrFuncForward();
-		gen.genPosFunctions();
-	}
 	gen.generateAndAppendFunctions( declsToAddAfter );
 }
@@ -418,5 +400,5 @@
 }
 
-/// Use the current type T to create `void ?{}(T & _dst)`.
+/// Use the current type T to create `void ^?{}(T & _dst)`.
 ast::FunctionDecl * FuncGenerator::genDtorProto() const {
 	// The destructor must be mutex on a concurrent type.
@@ -777,131 +759,4 @@
 }
 
-ast::FunctionDecl * EnumFuncGenerator::genPosProto() const {
-	return genProto( "posE", 
-		{ new ast::ObjectDecl( getLocation(), "_i", 
-		new ast::EnumInstType( decl ) )}, 
-		{ new ast::ObjectDecl( getLocation(), "_ret", 
-		new ast::BasicType{ ast::BasicType::UnsignedInt } )} );
-}
-
-ast::FunctionDecl * EnumFuncGenerator::genLabelProto() const {
-	return genProto( "labelE",
-		{ new ast::ObjectDecl( getLocation(), "_i", 
-		new ast::EnumInstType( decl ) ) },
-		{ new ast::ObjectDecl( getLocation(), "_ret", 
-		new ast::PointerType( new ast::BasicType{ ast::BasicType::Char } ) ) } );
-}
-
-ast::FunctionDecl * EnumFuncGenerator::genValueProto() const {
-	return genProto( "valueE", 
-		{ new ast::ObjectDecl( getLocation(), "_i", new ast::EnumInstType( decl ) )},
-		{ new ast::ObjectDecl( getLocation(), "_ret", ast::deepCopy( decl->base ) ) } );
-}
-
-ast::FunctionDecl * EnumFuncGenerator::genSuccProto() const {
-	return genProto( "succ",
-		{ new ast::ObjectDecl( getLocation(), "_i", new ast::EnumInstType( decl ) )},
-		{ new ast::ObjectDecl( getLocation(), "_ret", new ast::EnumInstType( decl ))} ); 
-}
-
-ast::FunctionDecl * EnumFuncGenerator::genPredProto() const {
-	return genProto( "pred",
-		{ new ast::ObjectDecl( getLocation(), "_i", new ast::EnumInstType( decl ))},
-		{ new ast::ObjectDecl( getLocation(), "_ret", new ast::EnumInstType( decl ))} );
-}
-
-ast::FunctionDecl * EnumFuncGenerator::genSuccPosProto() const {
-	return genProto( "_successor_",
-		{ new ast::ObjectDecl( getLocation(), "_i", 
-			new ast::EnumPosType( new ast::EnumInstType( decl ) ) )},
-		{ 
-			new ast::ObjectDecl( getLocation(), "_ret", 
-			new ast::EnumPosType( new ast::EnumInstType( decl ) ) )
-		} ); 
-}
-
-ast::FunctionDecl * EnumFuncGenerator::genPredPosProto() const {
-	return genProto( "_predessor_",
-		{ new ast::ObjectDecl( getLocation(), "_i", 
-			new ast::EnumPosType( new ast::EnumInstType( decl ) ) )},
-		{ 
-			new ast::ObjectDecl( getLocation(), "_ret", 
-			new ast::EnumPosType( new ast::EnumInstType( decl ) ) )
-		} ); 
-}
-
-ast::FunctionDecl * EnumFuncGenerator::genSuccPredFunc( bool succ ) {
-	ast::FunctionDecl * decl = succ? genSuccPosProto(): genPredPosProto();
-	produceForwardDecl( decl );
-
-	const CodeLocation& location = getLocation();
-
-	auto & params = decl->params;
-	assert( params.size() == 1 );
-	auto param = params.front().strict_as<ast::ObjectDecl>();
-
-	auto newReturn = new ast::ObjectDecl( location, "_returns",
-		new ast::BasicType{ ast::BasicType::SignedInt} );
-	
-
-	ast::UntypedExpr * addOneExpr = new ast::UntypedExpr( location,
-		new ast::NameExpr( location, succ? "?+?": "?-?" )
-	);
-	addOneExpr->args.push_back( 
-		new ast::CastExpr( location, 
-			new ast::VariableExpr( location, param ),
-			new ast::BasicType{ ast::BasicType::SignedInt }
-		)
-	);
-	addOneExpr->args.push_back( 
-		ast::ConstantExpr::from_int( location, 1 )
-	);
-
-	ast::UntypedExpr * assignExpr = new ast::UntypedExpr( location,
-		new ast::NameExpr( location, "?=?" )
-	);
-	assignExpr->args.push_back(	
-		new ast::VariableExpr( location, newReturn )
-	);
-	assignExpr->args.push_back(
-		addOneExpr
-	);
-
-	decl->stmts = new ast::CompoundStmt( location, 
-		{
-			new ast::DeclStmt( location, newReturn ),
-			new ast::ExprStmt( location, assignExpr ),
-			new ast::ReturnStmt( location, 
-				new ast::VariableExpr( location, newReturn )) 
-		} );
-	
-	return decl;
-}
-
-void EnumFuncGenerator::genAttrFuncForward() {	
-	if ( decl->base ) {
-		ast::FunctionDecl *(EnumFuncGenerator::*attrProtos[5])() const = {
-			&EnumFuncGenerator::genPosProto, &EnumFuncGenerator::genLabelProto, 
-			&EnumFuncGenerator::genValueProto, &EnumFuncGenerator::genSuccProto,
-			&EnumFuncGenerator::genPredProto
-			// ,&EnumFuncGenerator::genSuccPosProto,
-			// &EnumFuncGenerator::genPredPosProto
-		};
-		for ( auto & generator : attrProtos ) {
-			produceForwardDecl( (this->*generator)() );
-		}
-	}
-}
-
-void EnumFuncGenerator::genPosFunctions() {
-	if ( decl->base ) {
-		ast::FunctionDecl * succ = genSuccPredFunc( true );
-		ast::FunctionDecl * pred = genSuccPredFunc( false );
-		produceDecl( succ );
-		produceDecl( pred );
-	}
-
-}
-
 void TypeFuncGenerator::genFieldCtors() {
 	// Opaque types do not have field constructors.
Index: src/Validate/ImplementEnumFunc.cpp
===================================================================
--- src/Validate/ImplementEnumFunc.cpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ src/Validate/ImplementEnumFunc.cpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -0,0 +1,537 @@
+#include "AST/Create.hpp"
+#include "AST/Pass.hpp"
+#include "AST/TranslationUnit.hpp"
+#include "CodeGen/OperatorTable.h"  // for isCtorDtor, isCtorDtorAssign
+#include "InitTweak/InitTweak.h"    // for isAssignment, isCopyConstructor
+namespace Validate {
+
+namespace {
+class EnumAttrFuncGenerator {
+    const ast::EnumDecl* decl;
+    const ast::EnumInstType* instType;
+    // const ast::EnumAttrType* attrType;
+    unsigned int functionNesting;
+    ast::Linkage::Spec proto_linkage;
+
+   public:
+    std::list<ast::ptr<ast::Decl>> forwards;
+    std::list<ast::ptr<ast::Decl>> definitions;
+
+    void generateAndAppendFunctions(std::list<ast::ptr<ast::Decl>>&);
+
+    EnumAttrFuncGenerator(const ast::EnumDecl* decl,
+                          const ast::EnumInstType* instType,
+                          // const ast::EnumAttrType* enumAttrType,
+                          unsigned int functionNesting)
+        : decl(decl),
+          instType{instType},
+          // attrType{enumAttrType},
+          functionNesting{functionNesting},
+          proto_linkage{ast::Linkage::Cforall} {}
+
+    void genAttrFunctions();
+    void genSuccPredPosn();
+    void genSuccPredDecl();
+
+    void appendReturnThis(ast::FunctionDecl* decl) {
+        assert(1 <= decl->params.size());
+        assert(1 == decl->returns.size());
+        assert(decl->stmts);
+
+        const CodeLocation& location = (decl->stmts->kids.empty())
+                                           ? decl->stmts->location
+                                           : decl->stmts->kids.back()->location;
+        const ast::DeclWithType* thisParam = decl->params.front();
+        decl->stmts.get_and_mutate()->push_back(new ast::ReturnStmt(
+            location, new ast::VariableExpr(location, thisParam)));
+    }
+    void genAttrStandardFuncs() {
+        ast::FunctionDecl* (EnumAttrFuncGenerator::*standardProtos[4])()
+            const = {&EnumAttrFuncGenerator::genCtorProto,
+                     &EnumAttrFuncGenerator::genCopyProto,
+                     &EnumAttrFuncGenerator::genDtorProto,
+                     &EnumAttrFuncGenerator::genAssignProto};
+        for (auto& generator : standardProtos) {
+            ast::FunctionDecl* decl = (this->*generator)();
+            produceForwardDecl(decl);
+            genFuncBody(decl);
+            if (CodeGen::isAssignment(decl->name)) {
+                appendReturnThis(decl);
+            }
+            produceDecl(decl);
+        }
+    }
+
+   private:
+    const CodeLocation& getLocation() const { return decl->location; }
+
+    ast::FunctionDecl* genProto(
+        std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
+        std::vector<ast::ptr<ast::DeclWithType>>&& returns) const;
+
+    void produceDecl(const ast::FunctionDecl* decl);
+    void produceForwardDecl(const ast::FunctionDecl* decl);
+
+    const ast::Decl* getDecl() const { return decl; }
+
+    ast::FunctionDecl* genPosnProto() const;
+    ast::FunctionDecl* genLabelProto() const;
+    ast::FunctionDecl* genValueProto() const;
+    ast::FunctionDecl* genSuccProto() const;
+    ast::FunctionDecl* genPredProto() const;
+
+    ast::FunctionDecl* genSuccPosProto() const;
+    ast::FunctionDecl* genPredPosProto() const;
+
+    // ---------------------------------------------------
+    // ast::FunctionDecl* genAttrCtorProto() const;
+    /// Changes the node inside a pointer so that it has the unused attribute.
+    void addUnusedAttribute(ast::ptr<ast::DeclWithType>& declPtr) {
+        ast::DeclWithType* decl = declPtr.get_and_mutate();
+        decl->attributes.push_back(new ast::Attribute("unused"));
+    }
+
+    ast::ObjectDecl* dstParam() const {
+        return new ast::ObjectDecl(getLocation(), "_dst",
+                                   new ast::ReferenceType(new ast::EnumAttrType(
+                                       ast::deepCopy(instType))));
+    }
+
+    ast::ObjectDecl* srcParam() const {
+        return new ast::ObjectDecl(
+            getLocation(), "_src",
+            new ast::EnumAttrType(ast::deepCopy(instType)));
+    }
+
+    /// E = EnumAttrType<T>`
+    /// `void ?{}(E & _dst)`.
+    ast::FunctionDecl* genCtorProto() const {
+        return genProto("?{}", {dstParam()}, {});
+    }
+
+    /// void ?{}(E & _dst, E _src)`.
+    ast::FunctionDecl* genCopyProto() const {
+        return genProto("?{}", {dstParam(), srcParam()}, {});
+    }
+
+    ///`void ^?{}(E & _dst)`.
+    ast::FunctionDecl* genDtorProto() const {
+        // The destructor must be mutex on a concurrent type.
+        return genProto("^?{}", {dstParam()}, {});
+    }
+
+    /// `E ?{}(E & _dst, E _src)`.
+    ast::FunctionDecl* genAssignProto() const {
+        // Only the name is different, so just reuse the generation function.
+        auto retval = srcParam();
+        retval->name = "_ret";
+        return genProto("?=?", {dstParam(), srcParam()}, {retval});
+    }
+
+    void genFuncBody(ast::FunctionDecl* func) {
+        const CodeLocation& location = func->location;
+        auto& params = func->params;
+        if (InitTweak::isCopyConstructor(func) ||
+            InitTweak::isAssignment(func)) {
+            assert(2 == params.size());
+            auto dstParam = params.front().strict_as<ast::ObjectDecl>();
+            auto srcParam = params.back().strict_as<ast::ObjectDecl>();
+            func->stmts = genCopyBody(location, dstParam, srcParam);
+        } else {
+            assert(1 == params.size());
+            // Default constructor and destructor is empty.
+            func->stmts = new ast::CompoundStmt(location);
+            // Add unused attribute to parameter to silence warnings.
+            addUnusedAttribute(params.front());
+
+            // Just an extra step to make the forward and declaration match.
+            if (forwards.empty()) return;
+            ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
+                forwards.back().get_and_mutate());
+            addUnusedAttribute(fwd->params.front());
+        }
+    }
+
+    const ast::CompoundStmt* genCopyBody(const CodeLocation& location,
+                                         const ast::ObjectDecl* dstParam,
+                                         const ast::ObjectDecl* srcParam) {
+        // const CodeLocation& location = func->location;
+        // auto& params = func->params;
+        // assert(2 == params.size());
+        // auto dstParam = params.front().strict_as<ast::ObjectDecl>();
+        // auto srcParam = params.back().strict_as<ast::ObjectDecl>();
+        return new ast::CompoundStmt(
+            location,
+            {new ast::ExprStmt(
+                location,
+                new ast::UntypedExpr(
+                    location, new ast::NameExpr(location, "__builtin_memcpy"),
+                    {
+                        new ast::AddressExpr(location, new ast::VariableExpr(
+                                                           location, dstParam)),
+                        new ast::AddressExpr(location, new ast::VariableExpr(
+                                                           location, srcParam)),
+                        new ast::SizeofExpr(location, srcParam->type),
+                    }))});
+    }
+
+    void genDtorBody(ast::FunctionDecl* func) {
+        const CodeLocation& location = func->location;
+        auto& params = func->params;
+        assert(1 == params.size());
+        func->stmts = new ast::CompoundStmt(location);
+        addUnusedAttribute(params.front());
+
+        // Just an extra step to make the forward and declaration match.
+        if (forwards.empty()) return;
+        ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
+            forwards.back().get_and_mutate());
+        addUnusedAttribute(fwd->params.front());
+    }
+
+    // ast::FunctionDecl*
+    // ----------------------------------------------------
+
+    ast::FunctionDecl* genSuccPredFunc(bool succ);
+
+    const ast::Init* getAutoInit(const ast::Init* prev) const;
+
+    std::vector<ast::ptr<ast::Init>> genLabelInit() const;
+
+    std::vector<ast::ptr<ast::Init>> genValueInit() const;
+    ast::ObjectDecl* genAttrArrayProto(
+        const ast::EnumAttribute attr, const CodeLocation& location,
+        std::vector<ast::ptr<ast::Init>>& inits) const;
+    void genValueOrLabelBody(ast::FunctionDecl* func,
+                             ast::ObjectDecl* arrDecl) const;
+    void genPosnBody(ast::FunctionDecl* func) const;
+    void genAttributesDecls(const ast::EnumAttribute attr);
+};
+
+std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
+    std::vector<ast::ptr<ast::Init>> inits;
+    for (size_t i = 0; i < decl->members.size(); i++) {
+        ast::ptr<ast::Decl> mem = decl->members.at(i);
+        auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
+        assert(memAsObjectDecl);
+        inits.emplace_back(new ast::SingleInit(
+            mem->location,
+            ast::ConstantExpr::from_string(mem->location, mem->name)));
+    }
+    return inits;
+}
+
+std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() const {
+    std::vector<ast::ptr<ast::Init>> inits;
+    for (size_t i = 0; i < decl->members.size(); i++) {
+        ast::ptr<ast::Decl> mem = decl->members.at(i);
+        auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
+        assert(memAsObjectDecl);
+        if (memAsObjectDecl->init) {
+            inits.emplace_back(memAsObjectDecl->init);
+        } else {
+            const CodeLocation& location = mem->location;
+            if (i == 0) {
+                inits.emplace_back(new ast::SingleInit(
+                    location, ast::ConstantExpr::from_int(mem->location, 0)));
+            } else {
+                inits.emplace_back(getAutoInit(inits.at(i - 1)));
+            }
+        }
+    }
+    return inits;
+}
+const ast::Init* EnumAttrFuncGenerator::getAutoInit(
+    const ast::Init* prev) const {
+    if (prev == nullptr) {
+        return new ast::SingleInit(
+            getLocation(), ast::ConstantExpr::from_int(getLocation(), 0));
+    }
+    auto prevInit = dynamic_cast<const ast::SingleInit*>(prev);
+    assert(prevInit);
+    auto prevInitExpr = prevInit->value;
+    if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
+        // Assume no string literal for now
+        return new ast::SingleInit(
+            getLocation(), ast::ConstantExpr::from_int(
+                               getLocation(), constInit->intValue() + 1));
+    } else {
+        auto untypedThisInit = new ast::UntypedExpr(
+            getLocation(), new ast::NameExpr(getLocation(), "?++"),
+            {prevInitExpr});
+        return new ast::SingleInit(getLocation(), untypedThisInit);
+    }
+}
+
+ast::FunctionDecl* EnumAttrFuncGenerator::genProto(
+    std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
+    std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
+    ast::FunctionDecl* decl = new ast::FunctionDecl(
+        // Auto-generated routines use the type declaration's location.
+        getLocation(), std::move(name), {}, {}, std::move(params),
+        std::move(returns),
+        // Only a prototype, no body.
+        nullptr,
+        // 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));
+    decl->fixUniqueId();
+    return decl;
+}
+
+void EnumAttrFuncGenerator::produceDecl(const ast::FunctionDecl* decl) {
+    assert(nullptr != decl->stmts);
+
+    definitions.push_back(decl);
+}
+
+void EnumAttrFuncGenerator::produceForwardDecl(const ast::FunctionDecl* decl) {
+    if (0 != functionNesting) return;
+    ast::FunctionDecl* fwd =
+        (decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
+    fwd->fixUniqueId();
+    forwards.push_back(fwd);
+}
+
+ast::FunctionDecl* EnumAttrFuncGenerator::genPosnProto() const {
+    return genProto(
+        "posE",
+        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
+        {new ast::ObjectDecl(getLocation(), "_ret",
+                             new ast::EnumAttrType(new ast::EnumInstType(decl),
+                                                   ast::EnumAttribute::Posn))});
+}
+
+ast::FunctionDecl* EnumAttrFuncGenerator::genLabelProto() const {
+    return genProto(
+        "labelE",
+        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
+        {new ast::ObjectDecl(
+            getLocation(), "_ret",
+            new ast::PointerType(new ast::BasicType{ast::BasicType::Char}))});
+}
+
+ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
+    return genProto(
+        "valueE",
+        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
+        {new ast::ObjectDecl(getLocation(), "_ret",
+                             ast::deepCopy(decl->base))});
+}
+
+ast::FunctionDecl* EnumAttrFuncGenerator::genSuccProto() const {
+    return genProto(
+        "succ",
+        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
+        {new ast::ObjectDecl(getLocation(), "_ret",
+                             new ast::EnumInstType(decl))});
+}
+
+ast::FunctionDecl* EnumAttrFuncGenerator::genPredProto() const {
+    return genProto(
+        "pred",
+        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
+        {new ast::ObjectDecl(getLocation(), "_ret",
+                             new ast::EnumInstType(decl))});
+}
+
+inline ast::EnumAttrType * getPosnType( const ast::EnumDecl * decl ) {
+    return new ast::EnumAttrType(new ast::EnumInstType(decl), ast::EnumAttribute::Posn);
+}
+
+ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPosProto() const {
+    return genProto(
+        "_successor_",
+        {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
+        {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
+    );
+}
+
+ast::FunctionDecl* EnumAttrFuncGenerator::genPredPosProto() const {
+    return genProto(
+        "_predessor_",
+        {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
+        {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
+    );
+}
+
+ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
+    const ast::EnumAttribute attr, const CodeLocation& location,
+    std::vector<ast::ptr<ast::Init>>& inits) const {
+    ast::ArrayType* arrT = new ast::ArrayType(
+        attr == ast::EnumAttribute::Value
+            ? decl->base
+            : new ast::PointerType(new ast::BasicType{ast::BasicType::Char}),
+        ast::ConstantExpr::from_int(decl->location, decl->members.size()),
+        ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
+
+    ast::ObjectDecl* objDecl =
+        new ast::ObjectDecl(decl->location, decl->getUnmangeldArrayName(attr),
+                            arrT, new ast::ListInit(location, std::move(inits)),
+                            ast::Storage::Static, ast::Linkage::AutoGen);
+
+    return objDecl;
+}
+
+void EnumAttrFuncGenerator::genValueOrLabelBody(
+    ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
+    ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
+        func->location, "?[?]",
+        {new ast::NameExpr(func->location, arrDecl->name),
+         new ast::CastExpr(
+             func->location,
+             new ast::VariableExpr(func->location, func->params.front()),
+             new ast::EnumAttrType(new ast::EnumInstType(decl),
+                                   ast::EnumAttribute::Posn))});
+    func->stmts = new ast::CompoundStmt(
+        func->location, {new ast::ReturnStmt(func->location, untyped)});
+}
+
+void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
+    auto castExpr = new ast::CastExpr(
+        func->location,
+        new ast::VariableExpr(func->location, func->params.front()),
+        new ast::EnumAttrType(new ast::EnumInstType(decl),
+                              ast::EnumAttribute::Posn));
+    func->stmts = new ast::CompoundStmt(
+        func->location, {new ast::ReturnStmt(func->location, castExpr)});
+}
+
+void EnumAttrFuncGenerator::genAttributesDecls(const ast::EnumAttribute attr) {
+    if (attr == ast::EnumAttribute::Value ||
+        attr == ast::EnumAttribute::Label) {
+        std::vector<ast::ptr<ast::Init>> inits =
+            attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
+        ast::ObjectDecl* arrayProto =
+            genAttrArrayProto(attr, getLocation(), inits);
+        forwards.push_back(arrayProto);
+
+        ast::FunctionDecl* funcProto = attr == ast::EnumAttribute::Value
+                                           ? genValueProto()
+                                           : genLabelProto();
+        produceForwardDecl(funcProto);
+        genValueOrLabelBody(funcProto, arrayProto);
+        produceDecl(funcProto);
+    } else {
+        ast::FunctionDecl* funcProto = genPosnProto();
+        produceForwardDecl(funcProto);
+        genPosnBody(funcProto);
+        produceDecl(funcProto);
+    }
+}
+
+ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPredFunc(bool succ) {
+    ast::FunctionDecl* funcDecl = succ ? genSuccPosProto() : genPredPosProto();
+    produceForwardDecl(funcDecl);
+
+    const CodeLocation& location = getLocation();
+
+    auto& params = funcDecl->params;
+    assert(params.size() == 1);
+    auto param = params.front().strict_as<ast::ObjectDecl>();
+
+
+    auto rets = funcDecl->returns;
+    assert(params.size() == 1);
+    auto ret = rets.front().strict_as<ast::ObjectDecl>();
+    auto retType = ret->type.strict_as<ast::EnumAttrType>();
+
+    auto addOneExpr = ast::UntypedExpr::createCall( location,
+        "?+?",
+        {new ast::VariableExpr(location, param),
+        ast::ConstantExpr::from_int(location, 1)}
+    );
+
+    funcDecl->stmts = new ast::CompoundStmt(
+        location, {
+            new ast::ReturnStmt(
+                location, 
+                new ast::CastExpr(location, addOneExpr, retType) 
+            )
+        }
+    );
+
+    return funcDecl;
+}
+
+void EnumAttrFuncGenerator::genAttrFunctions() {
+    if (decl->base) {
+        genAttributesDecls(ast::EnumAttribute::Value);
+        genAttributesDecls(ast::EnumAttribute::Label);
+        genAttributesDecls(ast::EnumAttribute::Posn);
+    }
+}
+
+void EnumAttrFuncGenerator::genSuccPredDecl() {
+    if (decl->base) {
+        auto succProto = genSuccProto();
+        auto predProto = genPredProto();
+
+        produceForwardDecl(succProto);
+        produceForwardDecl(predProto);
+    }
+}
+
+void EnumAttrFuncGenerator::genSuccPredPosn() {
+    if (decl->base) {
+        ast::FunctionDecl* succ = genSuccPredFunc(true);
+        ast::FunctionDecl* pred = genSuccPredFunc(false);
+
+        produceDecl(succ);
+        produceDecl(pred);
+    }
+}
+
+void EnumAttrFuncGenerator::generateAndAppendFunctions(
+    std::list<ast::ptr<ast::Decl>>& decls) {
+    // Generate the functions (they go into forwards and definitions).
+    genAttrStandardFuncs();
+    genAttrFunctions();
+    genSuccPredDecl();
+    genSuccPredPosn(); // Posn
+    // Now export the lists contents.
+    decls.splice(decls.end(), forwards);
+    decls.splice(decls.end(), definitions);
+}
+
+// ---------------------------------------------------------
+
+struct ImplementEnumFunc final : public ast::WithDeclsToAdd<>,
+                                 public ast::WithShortCircuiting {
+    void previsit(const ast::EnumDecl* enumDecl);
+    void previsit(const ast::FunctionDecl* functionDecl);
+    void postvisit(const ast::FunctionDecl* functionDecl);
+
+   private:
+    // Current level of nested functions.
+    unsigned int functionNesting = 0;
+};
+
+void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
+    if (!enumDecl->body) return;
+    if (!enumDecl->base) return;
+
+    ast::EnumInstType enumInst(enumDecl->name);
+    enumInst.base = enumDecl;
+    // ast::EnumAttrType attr = ast::EnumAttrType(&enumInst);
+    // EnumAttrFuncGenerator gen(enumDecl, &enumInst functionNesting);
+    EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
+    gen.generateAndAppendFunctions(declsToAddAfter);
+}
+
+void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
+    functionNesting += 1;
+}
+
+void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
+    functionNesting -= 1;
+}
+
+}  // namespace
+
+void implementEnumFunc(ast::TranslationUnit& translationUnit) {
+    ast::Pass<ImplementEnumFunc>::run(translationUnit);
+}
+}  // namespace Validate
Index: src/Validate/ImplementEnumFunc.hpp
===================================================================
--- src/Validate/ImplementEnumFunc.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ src/Validate/ImplementEnumFunc.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -0,0 +1,9 @@
+#pragma once
+
+namespace ast {
+    class TranslationUnit;
+}
+
+namespace Validate {
+    void implementEnumFunc( ast::TranslationUnit & translationUnit );
+}
Index: src/Validate/ReplacePseudoFunc.cpp
===================================================================
--- src/Validate/ReplacePseudoFunc.cpp	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/Validate/ReplacePseudoFunc.cpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -16,324 +16,4 @@
 
 namespace {
-
-std::set<std::string> queryLabels;
-std::set<std::string> queryValues;
-
-struct ReplaceEnumInstWithPos final : public ast::WithShortCircuiting {
-    const ast::ObjectDecl* postvisit(const ast::ObjectDecl* decl) {
-        auto enumInst = decl->type.strict_as<ast::EnumInstType>();
-        auto enumPos = new ast::EnumPosType(enumInst);
-        auto ret = ast::mutate_field(decl, &ast::ObjectDecl::type, enumPos);
-        ret = ast::mutate_field(ret, &ast::ObjectDecl::mangleName,
-                                Mangle::mangle(ret));
-        return ret;
-    }
-};
-
-const inline std::string getValueArrayName(std::string enumName) {
-    return "values_" + enumName;
-}
-
-// struct AutoInit {
-//     ast::EnumDecl const* postvisit( const ast::EnumDecl* expr );
-// };
-
-struct WrapEnumValueExpr final : public ast::WithShortCircuiting,
-                                 public ast::WithSymbolTable,
-                                 public ast::WithConstTranslationUnit {
-    void previsit(const ast::DeclStmt* expr);
-    void previsit(const ast::ApplicationExpr* expr);
-    void previsit(const ast::CastExpr* expr);
-    void previsit(const ast::VariableExpr*) { visit_children = false; }
-
-    ast::Expr const* postvisit(const ast::VariableExpr* expr);
-};
-
-struct FindGenEnumArray final : public ast::WithShortCircuiting {
-    void previsit(const ast::ApplicationExpr* enumDecl);
-};
-
-struct PseudoFuncGenerateRoutine final : public ast::WithDeclsToAdd<>,
-                                         public ast::WithSymbolTable,
-                                         public ast::WithShortCircuiting,
-                                         public ast::WithConstTranslationUnit {
-    void previsit(const ast::EnumDecl* enumDecl);
-};
-
-struct ReplacePseudoFuncCore : public ast::WithShortCircuiting,
-                               public ast::WithSymbolTable,
-                               public ast::WithConstTranslationUnit {
-    ast::Expr const* postvisit(ast::ApplicationExpr const* decl);
-};
-
-// ast::EnumDecl const * AutoInit::postvisit( const ast::EnumDecl * expr ) {
-//     for ( size_t i = 0; i < expr->members.size(); i++ ) {
-//         auto mem = expr->members[i].as<ast::ObjectDecl>();
-//         assert( mem );
-//         if ( mem->init )
-//     }
-//     return expr;
-// }
-
-void WrapEnumValueExpr::previsit(const ast::ApplicationExpr* expr) {
-    auto varExpr = expr->func.as<ast::VariableExpr>();
-    auto fname = ast::getFunctionName(expr);
-    if (!varExpr || varExpr->var->linkage == ast::Linkage::Intrinsic) {
-        if (fname == "?{}" || fname == "?=?") visit_children = false;
-    }
-
-    if (fname == "labelE" || fname == "valueE" || fname == "posE" ||
-        fname == "pred" || fname == "succ") {
-        visit_children = false;
-    }
-}
-
-void WrapEnumValueExpr::previsit(const ast::DeclStmt*) {
-    visit_children = false;
-}
-
-void WrapEnumValueExpr::previsit(const ast::CastExpr* expr) {
-    if (expr->result && expr->result.as<ast::ReferenceType>()) {
-        visit_children = false;
-    }
-}
-
-ast::Expr const* WrapEnumValueExpr::postvisit(const ast::VariableExpr* expr) {
-    if (!expr->result) {
-        return expr;
-    }
-    if (auto enumInst = expr->result.as<ast::EnumInstType>()) {
-        if (enumInst->base && enumInst->base->base) {
-            auto untyped = new ast::UntypedExpr(
-                expr->location, new ast::NameExpr(expr->location, "valueE"),
-                {std::move(expr)});
-            ResolvExpr::ResolveContext context{symtab, transUnit().global};
-            auto result = ResolvExpr::findVoidExpression(untyped, context);
-            ast::ptr<ast::ApplicationExpr> ret =
-                result.strict_as<ast::ApplicationExpr>();
-            return ast::deepCopy(ret);
-        }
-    }
-    return expr;
-}
-
-void FindGenEnumArray::previsit(const ast::ApplicationExpr* expr) {
-    auto fname = ast::getFunctionName(expr);
-    if (fname == "labelE" || fname == "valueE") {
-        if (expr->args.size() != 1) {
-            SemanticError(expr, "Position Expression only take one parameter");
-        }
-        const ast::VariableExpr* arg =
-            expr->args.front().as<const ast::VariableExpr>();
-        if (!arg) {
-            SemanticError(expr, "Unimplement Pseudo Function Cases");
-        }
-        const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>();
-        const std::string referredName = argAsVar->name;
-        const ast::EnumInstType* argType =
-            argAsVar->type.as<const ast::EnumInstType>();
-        if (!argType) {
-            SemanticError(
-                argAsVar,
-                "Position can only be used on an enumeration instance");
-        }
-        ast::ptr<ast::EnumDecl> base = argType->base;
-        assert(base);
-        if (fname == "labelE") queryLabels.insert(base->name);
-        if (fname == "valueE") queryValues.insert(base->name);
-    }
-}
-
-const ast::Init* getAutoInit(const CodeLocation& location,
-                             const ast::Type* type,
-                             ResolvExpr::ResolveContext context,
-                             const ast::Init* prev) {
-    if (auto prevInit = dynamic_cast<const ast::SingleInit*>(prev)) {
-        auto prevInitExpr = prevInit->value;
-        if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
-            // Assume no string literal for now
-            return new ast::SingleInit(
-                location, ast::ConstantExpr::from_int(
-                              location, constInit->intValue() + 1));
-        } else {
-            auto untypedThisInit = new ast::UntypedExpr(
-                location, new ast::NameExpr(location, "?++"), {prevInitExpr});
-            auto typedInit = ResolvExpr::findSingleExpression(untypedThisInit,
-                                                              type, context);
-            return new ast::SingleInit(location, typedInit);
-        }
-    }
-    SemanticError(prev, "Auto Init a List is not implemented");
-    return prev;
-}
-
-void PseudoFuncGenerateRoutine::previsit(const ast::EnumDecl* enumDecl) {
-    visit_children = false;
-    const CodeLocation& location = enumDecl->location;
-    if (enumDecl->members.size() == 0 || !enumDecl->base) return;
-
-    std::vector<ast::ptr<ast::Init>> inits;
-    std::vector<ast::ptr<ast::Init>> labels;
-    auto type = enumDecl->base;
-
-    for (size_t i = 0; i < enumDecl->members.size(); i++) {
-        ast::ptr<ast::Decl> mem = enumDecl->members.at(i);
-        auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
-        assert(memAsObjectDecl);
-        if (memAsObjectDecl->init) {
-            inits.emplace_back(memAsObjectDecl->init);
-        } else {
-            const CodeLocation& location = mem->location;
-            if (i == 0) {
-                inits.emplace_back(new ast::SingleInit(
-                    location, ast::ConstantExpr::from_int(mem->location, 0)));
-            } else {
-                inits.emplace_back(getAutoInit(
-                    location, enumDecl->base,
-                    ResolvExpr::ResolveContext{symtab, transUnit().global},
-                    inits.at(i - 1).as<ast::SingleInit>()));
-            }
-        }
-        labels.emplace_back(new ast::SingleInit(
-            location, ast::ConstantExpr::from_string(location, mem->name)));
-    }
-    if (queryValues.count(enumDecl->name)) {
-        auto init = new ast::ListInit(location, std::move(inits));
-        const ast::ArrayType* arrT = new ast::ArrayType(
-            enumDecl->base,
-            ast::ConstantExpr::from_int(location, enumDecl->members.size()),
-            ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
-        ast::ObjectDecl* values = new ast::ObjectDecl(
-            location, "values_" + enumDecl->name, arrT, init,
-            ast::Storage::Static, ast::Linkage::AutoGen);
-        symtab.addId(values);
-        values->mangleName = Mangle::mangle(values);
-        declsToAddAfter.push_back(values);
-    }
-    if (queryLabels.count(enumDecl->name)) {
-        auto label_strings = new ast::ListInit(location, std::move(labels));
-        auto labels = new ast::ObjectDecl(
-            location, "labels_" + enumDecl->name,
-            new ast::ArrayType(
-                new ast::PointerType(new ast::BasicType{ast::BasicType::Char}),
-                ast::ConstantExpr::from_int(location, enumDecl->members.size()),
-                ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim),
-            label_strings, ast::Storage::Static, ast::Linkage::AutoGen);
-        symtab.addId(labels);
-        labels->mangleName = Mangle::mangle(labels);
-        declsToAddAfter.push_back(labels);
-    }
-}
-
-ast::ApplicationExpr const* resolveAttributeFunctions(
-    const CodeLocation location, ResolvExpr::ResolveContext context,
-    const ast::VariableExpr* arg, const ast::EnumDecl* base,
-    const std::string& name) {
-    ast::Expr* toResolve = new ast::NameExpr(location, name + base->name);
-    // Find the request arrary
-    auto arr = ResolvExpr::findVoidExpression(toResolve, context);
-    assert(arr.get());
-    auto arrAsVar = arr.strict_as<ast::VariableExpr>();
-    // change EnumInstType to EnumPosType to avoid recursive resolution
-    auto argAsDecl = arg->var.as<ast::ObjectDecl>();
-    if (argAsDecl->type.as<ast::EnumInstType>()) {
-        ast::Pass<ReplaceEnumInstWithPos> replacer;
-        auto rep = argAsDecl->accept(replacer);
-        auto mutatedArg = ast::mutate_field(arg, &ast::VariableExpr::var, rep);
-        mutatedArg = ast::mutate_field(mutatedArg, &ast::VariableExpr::result,
-                                       mutatedArg->var->get_type());
-        auto untyped =
-            new ast::UntypedExpr(location, new ast::NameExpr(location, "?[?]"),
-                                 {std::move(arrAsVar), mutatedArg});
-        auto typedResult = ResolvExpr::findVoidExpression(untyped, context);
-        ast::ptr<ast::ApplicationExpr> ret =
-            typedResult.strict_as<ast::ApplicationExpr>();
-        return ast::deepCopy(ret);
-    } else {
-        auto untyped =
-            new ast::UntypedExpr(location, new ast::NameExpr(location, "?[?]"),
-                                 {std::move(arrAsVar), arg});
-        auto typedResult = ResolvExpr::findVoidExpression(untyped, context);
-
-        ast::ptr<ast::ApplicationExpr> ret =
-            typedResult.strict_as<ast::ApplicationExpr>();
-        return ast::deepCopy(ret);
-    }
-}
-
-ast::Expr const* ReplacePseudoFuncCore::postvisit(
-    ast::ApplicationExpr const* expr) {
-    auto fname = ast::getFunctionName(expr);
-    auto location = expr->location;
-    if (fname == "posE" || fname == "valueE" || fname == "labelE") {
-        if (expr->args.size() != 1) {
-            SemanticError(expr,
-                          "Pseudo Enum Expression only take one parameter");
-        }
-        ast::ptr<ast::VariableExpr> arg =
-            expr->args.front().as<const ast::VariableExpr>();
-        if (!arg) {
-            SemanticError(expr, "Unimplement Pseudo Function Cases");
-        }
-        const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>();
-        const std::string referredName = argAsVar->name;
-
-        if (const ast::EnumInstType* argTypeAsEnumInst =
-                argAsVar->type.as<const ast::EnumInstType>()) {
-            const ast::EnumDecl* base = argTypeAsEnumInst->base;
-            ResolvExpr::ResolveContext context{symtab, transUnit().global};
-            // If resolvable as constant
-            for (size_t i = 0; i < base->members.size(); i++) {
-                if (base->members[i]->name == referredName) {
-                    if (fname == "posE")
-                        return ast::ConstantExpr::from_int(expr->location, i);
-                    else if (fname == "labelE")
-                        return ast::ConstantExpr::from_string(expr->location,
-                                                              referredName);
-                    else {
-                        return resolveAttributeFunctions(
-                            location, context, arg.get(), base, "values_");
-                    }
-                }
-            }
-
-            if (fname == "labelE") {
-                if (auto labelExpr = resolveAttributeFunctions(
-                        location, context, arg.get(), base, "labels_")) {
-                    return labelExpr;
-                }
-            } else if (fname == "valueE") {
-                if (auto valueExpr = resolveAttributeFunctions(
-                        location, context, arg.get(), base, "values_")) {
-                    return valueExpr;
-                }
-            } else {  // it is position; replace itself
-                return std::move(arg.get());
-            }
-        } else if (const ast::EnumPosType* argTypeAsPos =
-                       argAsVar->type.as<const ast::EnumPosType>()) {
-            const ast::EnumDecl* base = argTypeAsPos->instance->base;
-            ResolvExpr::ResolveContext context{symtab, transUnit().global};
-            if (fname == "labelE") {
-                if (auto labelExpr = resolveAttributeFunctions(
-                        location, context, arg.get(), base, "labels_")) {
-                    return labelExpr;
-                }
-            } else if (fname == "valueE") {
-                if (auto valueExpr = resolveAttributeFunctions(
-                        location, context, arg.get(), base, "values_")) {
-                    return valueExpr;
-                }
-            } else {  // it is position; replace itself
-                return std::move(arg.get());
-            }
-        } else {
-            SemanticError(argAsVar,
-                          "Pseudo Enum Expression can only be used on an "
-                          "enumeration instance");
-        }
-    }
-    return expr;
-}
 
 ast::ptr<ast::Expr> reduceCastExpr(ast::ptr<ast::Expr> expr) {
@@ -357,5 +37,6 @@
                     if (auto enumInst =
                             argAsDecl->type.as<ast::EnumInstType>()) {
-                        auto castTo = new ast::EnumPosType(enumInst);
+                        auto castTo = new ast::EnumAttrType(
+                            enumInst, ast::EnumAttribute::Posn);
                         auto castExpr =
                             new ast::CastExpr(param->location, param, castTo);
@@ -375,42 +56,6 @@
                         return ast::deepCopy(ret);
                     } else if (auto posType =
-                                   argAsDecl->type.as<ast::EnumPosType>()) {
-                        // Very nasty fix. Must be revisit
-                        if (auto paramAsVar = param.as<ast::VariableExpr>()) {
-                            if (paramAsVar->result.as<ast::EnumInstType>()) {
-                                auto paramToUse = ast::mutate_field(
-                                    paramAsVar, &ast::VariableExpr::result,
-                                    posType);
-                                auto untyped = new ast::UntypedExpr(
-                                    expr->location,
-                                    new ast::NameExpr(location,
-                                                      fname == "succ"
-                                                          ? "_successor_"
-                                                          : "_predessor_"),
-                                    {paramToUse});
-                                ResolvExpr::ResolveContext context{
-                                    symtab, transUnit().global};
-                                auto typedResult =
-                                    ResolvExpr::findVoidExpression(untyped,
-                                                                   context);
-                                ast::ptr<ast::ApplicationExpr> ret =
-                                    typedResult
-                                        .strict_as<ast::ApplicationExpr>();
-                                return ast::deepCopy(ret);
-                            }
-                        }
-                        auto untyped = new ast::UntypedExpr(
-                            expr->location,
-                            new ast::NameExpr(location, fname == "succ"
-                                                            ? "_successor_"
-                                                            : "_predessor_"),
-                            {param});
-                        ResolvExpr::ResolveContext context{symtab,
-                                                           transUnit().global};
-                        auto typedResult =
-                            ResolvExpr::findVoidExpression(untyped, context);
-                        ast::ptr<ast::ApplicationExpr> ret =
-                            typedResult.strict_as<ast::ApplicationExpr>();
-                        return ast::deepCopy(ret);
+                                   argAsDecl->type.as<ast::EnumAttrType>()) {
+                        std::cerr << "PseudoFunc: succ/pred should not be applied on EnumAttrType directly" << std::endl;
                     }
                 }
@@ -424,10 +69,4 @@
 
 void replacePseudoFunc(ast::TranslationUnit& translationUnit) {
-    ast::Pass<WrapEnumValueExpr>::run(translationUnit);
-    ast::Pass<FindGenEnumArray>::run(translationUnit);
-
-    ast::Pass<PseudoFuncGenerateRoutine>::run(translationUnit);
-    ast::Pass<ReplacePseudoFuncCore>::run(translationUnit);
-
     ast::Pass<ReplaceSuccAndPred>::run(translationUnit);
 }
Index: src/Validate/module.mk
===================================================================
--- src/Validate/module.mk	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/Validate/module.mk	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -54,5 +54,7 @@
 	Validate/VerifyCtorDtorAssign.hpp \
 	Validate/ReplacePseudoFunc.cpp \
-	Validate/ReplacePseudoFunc.hpp
+	Validate/ReplacePseudoFunc.hpp \
+	Validate/ImplementEnumFunc.cpp \
+	Validate/ImplementEnumFunc.hpp
 
 SRCDEMANGLE += $(SRC_VALIDATE)
Index: src/main.cc
===================================================================
--- src/main.cc	(revision d9bad5125c27fa032a8711a3c60c7d6c14d7d39e)
+++ src/main.cc	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -66,5 +66,5 @@
 #include "Tuples/Tuples.h"                  // for expandMemberTuples, expan...
 #include "Validate/Autogen.hpp"             // for autogenerateRoutines
-// #include "Validate/ImplementEnumFunc.hpp"   // for implementEnumFunc
+#include "Validate/ImplementEnumFunc.hpp"   // for implementEnumFunc
 #include "Validate/CompoundLiteral.hpp"     // for handleCompoundLiterals
 #include "Validate/EliminateTypedef.hpp"    // for eliminateTypedef
@@ -333,5 +333,5 @@
 
 		PASS( "Generate Autogen Routines", Validate::autogenerateRoutines, transUnit );
-		// PASS( "Generate Enum Attributes Functions", Validate::implementEnumFunc, transUnit );
+		PASS( "Generate Enum Attributes Functions", Validate::implementEnumFunc, transUnit );
 
 		PASS( "Implement Actors", Concurrency::implementActors, transUnit );
@@ -383,5 +383,5 @@
 		PASS( "Replace Pseudo Func", Validate::replacePseudoFunc, transUnit );
 		DUMP( reppseu, std::move( transUnit ) );
-		PASS( "Fix Init", InitTweak::fix, transUnit, buildingLibrary() );
+		PASS( "Fix Init", InitTweak::fix, transUnit, buildingLibrary() ); // Here
 		PASS( "Erase With", ResolvExpr::eraseWith, transUnit );
 
