Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision 0f5e8cdba2bacf645f79f523a3a2c2aa393e7d17)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -513,8 +513,25 @@
 					// add new result
 					assert( common );
-						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 );
-					//}
+
+					auto paramAsEnum = dynamic_cast<const ast::EnumInstType *>(paramType);
+					auto argAsEnum =dynamic_cast<const ast::EnumInstType *>(argType);
+					if (paramAsEnum && argAsEnum) {
+						if (paramAsEnum->base->name != argAsEnum->base->name) {
+							Cost c = castCost(argType, paramType, expr, context.symtab, env);
+							if (c < Cost::infinity) {
+								CandidateFinder subFinder( context, env );
+								expr = subFinder.makeEnumOffsetCast(argAsEnum, paramAsEnum, expr, c);
+								results.emplace_back(
+									i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
+									nextArg + 1, nTuples, expl.cost + c, expl.exprs.size() == 1 ? 0 : 1, j );
+								continue;
+							} else {
+								std::cerr << "Cannot instantiate " << paramAsEnum->base->name <<  " with " << argAsEnum->base->name << std::endl;
+							}
+						}
+					}
+					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 );
 				}
 			}
@@ -632,4 +649,8 @@
 			const ast::BaseInstType * aggrInst, const ast::Expr * expr,
 			const Candidate & cand, const Cost & addedCost, const std::string & name
+		);
+
+		void addEnumValueAsCandidate(const ast::EnumInstType * instType, const ast::Expr * expr,
+			const Cost & addedCost
 		);
 
@@ -676,4 +697,8 @@
 		void postvisit( const ast::QualifiedNameExpr * qualifiedExpr );
 
+		const ast::Expr * makeEnumOffsetCast( const ast::EnumInstType * src, 
+			const ast::EnumInstType * dst
+			, const ast::Expr * expr, Cost minCost );
+
 		void postvisit( const ast::InitExpr * ) {
 			assertf( false, "CandidateFinder should never see a resolved InitExpr." );
@@ -876,4 +901,25 @@
 	}
 
+	void Finder::addEnumValueAsCandidate( const ast::EnumInstType * enumInst, const ast::Expr * expr,
+		const Cost & addedCost
+	) {
+		if ( enumInst->base->base ) {
+			CandidateFinder finder( context, tenv );
+			auto location = expr->location;
+			auto callExpr = new ast::UntypedExpr(
+				location, new ast::NameExpr( location, "valueE" ), {expr}
+			);
+			finder.find( callExpr );
+			CandidateList winners = findMinCost( finder.candidates );
+			if (winners.size() != 1) {
+				SemanticError( callExpr, "Ambiguous expression in valueE..." );
+			}
+			CandidateRef & choice = winners.front();
+			choice->cost += addedCost;
+			addAnonConversions(choice);
+			candidates.emplace_back( std::move(choice) );
+		}
+	}
+
 	/// Adds implicit struct-conversions to the alternative list
 	void Finder::addAnonConversions( const CandidateRef & cand ) {
@@ -894,22 +940,8 @@
 			addAggMembers( unionInst, aggrExpr, *cand, Cost::unsafe, "" );
 		} 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 = Cost::unsafe;
-				candidates.emplace_back( std::move(choice) );
-			}
-
-		}
-	}
+			addEnumValueAsCandidate(enumInst, aggrExpr, Cost::unsafe);
+		}
+	}
+	
 
 	/// Adds aggregate member interpretations
@@ -1180,4 +1212,47 @@
 	}
 
+	// src is a subset of dst
+	const ast::Expr * Finder::makeEnumOffsetCast( const ast::EnumInstType * src, 
+		const ast::EnumInstType * dst,
+		const ast::Expr * expr,
+		Cost minCost ) {
+		
+		auto srcDecl = src->base;
+		auto dstDecl = dst->base;
+
+		if (srcDecl->name == dstDecl->name) return expr;
+
+		for (auto& dstChild: dstDecl->inlinedDecl) {
+			Cost c = castCost(src, dstChild, false, symtab, tenv);
+			ast::CastExpr * castToDst;
+			if (c<minCost) {
+				unsigned offset = dstDecl->calChildOffset(dstChild.get());
+				if (offset > 0) {
+					auto untyped = ast::UntypedExpr::createCall(
+						expr->location, 
+						"?+?", 
+						{ new ast::CastExpr( expr, new ast::BasicType(ast::BasicKind::SignedInt) ),
+						ast::ConstantExpr::from_int(expr->location, offset)});
+					CandidateFinder finder(context, tenv);
+					finder.find( untyped );
+					CandidateList winners = findMinCost( finder.candidates );
+					CandidateRef & choice = winners.front();
+					// choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
+					choice->expr = new ast::CastExpr(expr->location, choice->expr, dstChild, ast::GeneratedFlag::ExplicitCast);
+					// castToDst = new ast::CastExpr(choice->expr, dstChild);
+					castToDst = new ast::CastExpr( 
+						makeEnumOffsetCast( src, dstChild, choice->expr, minCost ),
+					 dst);
+
+				} else {
+					castToDst = new ast::CastExpr( expr, dst );
+				}
+				return castToDst;
+			}
+		}
+		SemanticError(expr, src->base->name + " is not a subtype of " + dst->base->name);
+		return nullptr;
+	}
+
 	void Finder::postvisit( const ast::CastExpr * castExpr ) {
 		ast::ptr< ast::Type > toType = castExpr->result;
@@ -1229,4 +1304,12 @@
 					? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
 					: castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
+			
+			// Redefine enum cast
+			auto argAsEnum = cand->expr->result.as<ast::EnumInstType>();
+			auto toAsEnum = toType.as<ast::EnumInstType>();
+			if ( argAsEnum && toAsEnum && argAsEnum->name != toAsEnum->name ) {	
+				ast::ptr<ast::Expr> offsetExpr = makeEnumOffsetCast(argAsEnum, toAsEnum, cand->expr, thisCost);
+				cand->expr = offsetExpr;
+			}
 
 			PRINT(
@@ -1246,8 +1329,6 @@
 					minCastCost = thisCost;
 					matches.clear();
-
-
-				}
-				// ambiguous case, still output candidates to print in error message
+				}
+				// ambigious case, still output candidates to print in error message
 				if ( cand->cost == minExprCost && thisCost == minCastCost ) {
 					CandidateRef newCand = std::make_shared<Candidate>(
@@ -1264,5 +1345,4 @@
 		}
 		candidates = std::move(matches);
-
 		//CandidateList minArgCost = findMinCost( matches );
 		//promoteCvtCost( minArgCost );
@@ -1374,5 +1454,5 @@
 			}
 		} else {
-			declList = symtab.lookupId( nameExpr->name );
+			declList = symtab.lookupIdIgnoreHidden( nameExpr->name );
 		}
 		PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
@@ -1386,14 +1466,4 @@
 			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{}, bentConversion? Cost::safe: Cost::zero,
-			// 	cost );
 			CandidateRef newCand = std::make_shared<Candidate>(
 				newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
@@ -1813,12 +1883,8 @@
 			if ( const ast::EnumInstType * enumInstType =
 				dynamic_cast<const ast::EnumInstType *>( t ) ) {
-				if ( enumInstType->base->name == expr->type_decl->name ) {
+				if ( (enumInstType->base->name == expr->type_name)
+					|| (expr->type_decl && enumInstType->base->name == expr->type_decl->name) ) {
 					Cost cost = Cost::zero;
 					ast::Expr * newExpr = data.combine( expr->location, cost );
-					// CandidateRef newCand =
-					// 	std::make_shared<Candidate>(
-					// 		newExpr, copy( tenv ), ast::OpenVarSet{},
-					// 		ast::AssertionSet{}, Cost::safe, cost
-					// 	);
 					CandidateRef newCand =
 						std::make_shared<Candidate>(
@@ -2096,4 +2162,43 @@
 
 	return expr;
+}
+
+const ast::Expr * CandidateFinder::makeEnumOffsetCast( const ast::EnumInstType * src, 
+	const ast::EnumInstType * dst,
+	const ast::Expr * expr,
+	Cost minCost ) {
+	
+	auto srcDecl = src->base;
+	auto dstDecl = dst->base;
+
+	if (srcDecl->name == dstDecl->name) return expr;
+
+	for (auto& dstChild: dstDecl->inlinedDecl) {
+		Cost c = castCost(src, dstChild, false, context.symtab, env);
+		ast::CastExpr * castToDst;
+		if (c<minCost) {
+			unsigned offset = dstDecl->calChildOffset(dstChild.get());
+			if (offset > 0) {
+				auto untyped = ast::UntypedExpr::createCall(
+					expr->location, 
+					"?+?", 
+					{ new ast::CastExpr( expr, new ast::BasicType(ast::BasicKind::SignedInt) ),
+					ast::ConstantExpr::from_int(expr->location, offset)});
+				CandidateFinder finder(context, env);
+				finder.find( untyped );
+				CandidateList winners = findMinCost( finder.candidates );
+				CandidateRef & choice = winners.front();
+				choice->expr = new ast::CastExpr(expr->location, choice->expr, dstChild, ast::GeneratedFlag::ExplicitCast);
+				castToDst = new ast::CastExpr( 
+					makeEnumOffsetCast( src, dstChild, choice->expr, minCost ),
+					dst);
+			} else {
+				castToDst = new ast::CastExpr( expr, dst );
+			}
+			return castToDst;
+		}
+	}
+	SemanticError(expr, src->base->name + " is not a subtype of " + dst->base->name);
+	return nullptr;
 }
 
