Index: src/ResolvExpr/AdjustExprType.cc
===================================================================
--- src/ResolvExpr/AdjustExprType.cc	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,89 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// AdjustExprType_old.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sat May 16 23:41:42 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Dec 11 21:43:56 2019
-// Update Count     : 6
-//
-
-#include "AST/Node.hpp"
-#include "AST/Pass.hpp"
-#include "AST/SymbolTable.hpp"
-#include "AST/Type.hpp"
-#include "AST/TypeEnvironment.hpp"
-
-namespace ResolvExpr {
-
-namespace {
-
-class AdjustExprType final : public ast::WithShortCircuiting {
-	const ast::SymbolTable & symtab;
-public:
-	const ast::TypeEnvironment & tenv;
-
-	AdjustExprType( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
-	: symtab( syms ), tenv( e ) {}
-
-	void previsit( const ast::VoidType * ) { visit_children = false; }
-	void previsit( const ast::BasicType * ) { visit_children = false; }
-	void previsit( const ast::PointerType * ) { visit_children = false; }
-	void previsit( const ast::ArrayType * ) { visit_children = false; }
-	void previsit( const ast::FunctionType * ) { visit_children = false; }
-	void previsit( const ast::StructInstType * ) { visit_children = false; }
-	void previsit( const ast::UnionInstType * ) { visit_children = false; }
-	void previsit( const ast::EnumInstType * ) { visit_children = false; }
-	void previsit( const ast::TraitInstType * ) { visit_children = false; }
-	void previsit( const ast::TypeInstType * ) { visit_children = false; }
-	void previsit( const ast::TupleType * ) { visit_children = false; }
-	void previsit( const ast::VarArgsType * ) { visit_children = false; }
-	void previsit( const ast::ZeroType * ) { visit_children = false; }
-	void previsit( const ast::OneType * ) { visit_children = false; }
-
-	const ast::Type * postvisit( const ast::ArrayType * at ) {
-		return new ast::PointerType( at->base, at->qualifiers );
-	}
-
-	const ast::Type * postvisit( const ast::FunctionType * ft ) {
-		return new ast::PointerType( ft );
-	}
-
-	const ast::Type * postvisit( const ast::TypeInstType * inst ) {
-		// replace known function-type-variables with pointer-to-function
-		if ( const ast::EqvClass * eqvClass = tenv.lookup( *inst ) ) {
-			if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
-				return new ast::PointerType( inst );
-			}
-		} else if ( const ast::NamedTypeDecl * ntDecl = symtab.lookupType( inst->name ) ) {
-			if ( auto tyDecl = dynamic_cast< const ast::TypeDecl * >( ntDecl ) ) {
-				if ( tyDecl->kind == ast::TypeDecl::Ftype ) {
-					return new ast::PointerType( inst );
-				}
-			}
-		}
-		return inst;
-	}
-};
-
-} // anonymous namespace
-
-const ast::Type * adjustExprType(
-	const ast::Type * type, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab
-) {
-	ast::Pass<AdjustExprType> adjuster{ env, symtab };
-	return type->accept( adjuster );
-}
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/AdjustExprType.cpp
===================================================================
--- src/ResolvExpr/AdjustExprType.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/AdjustExprType.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,89 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// AdjustExprType_old.cc --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sat May 16 23:41:42 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Wed Dec 11 21:43:56 2019
+// Update Count     : 6
+//
+
+#include "AST/Node.hpp"
+#include "AST/Pass.hpp"
+#include "AST/SymbolTable.hpp"
+#include "AST/Type.hpp"
+#include "AST/TypeEnvironment.hpp"
+
+namespace ResolvExpr {
+
+namespace {
+
+class AdjustExprType final : public ast::WithShortCircuiting {
+	const ast::SymbolTable & symtab;
+public:
+	const ast::TypeEnvironment & tenv;
+
+	AdjustExprType( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
+	: symtab( syms ), tenv( e ) {}
+
+	void previsit( const ast::VoidType * ) { visit_children = false; }
+	void previsit( const ast::BasicType * ) { visit_children = false; }
+	void previsit( const ast::PointerType * ) { visit_children = false; }
+	void previsit( const ast::ArrayType * ) { visit_children = false; }
+	void previsit( const ast::FunctionType * ) { visit_children = false; }
+	void previsit( const ast::StructInstType * ) { visit_children = false; }
+	void previsit( const ast::UnionInstType * ) { visit_children = false; }
+	void previsit( const ast::EnumInstType * ) { visit_children = false; }
+	void previsit( const ast::TraitInstType * ) { visit_children = false; }
+	void previsit( const ast::TypeInstType * ) { visit_children = false; }
+	void previsit( const ast::TupleType * ) { visit_children = false; }
+	void previsit( const ast::VarArgsType * ) { visit_children = false; }
+	void previsit( const ast::ZeroType * ) { visit_children = false; }
+	void previsit( const ast::OneType * ) { visit_children = false; }
+
+	const ast::Type * postvisit( const ast::ArrayType * at ) {
+		return new ast::PointerType( at->base, at->qualifiers );
+	}
+
+	const ast::Type * postvisit( const ast::FunctionType * ft ) {
+		return new ast::PointerType( ft );
+	}
+
+	const ast::Type * postvisit( const ast::TypeInstType * inst ) {
+		// replace known function-type-variables with pointer-to-function
+		if ( const ast::EqvClass * eqvClass = tenv.lookup( *inst ) ) {
+			if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
+				return new ast::PointerType( inst );
+			}
+		} else if ( const ast::NamedTypeDecl * ntDecl = symtab.lookupType( inst->name ) ) {
+			if ( auto tyDecl = dynamic_cast< const ast::TypeDecl * >( ntDecl ) ) {
+				if ( tyDecl->kind == ast::TypeDecl::Ftype ) {
+					return new ast::PointerType( inst );
+				}
+			}
+		}
+		return inst;
+	}
+};
+
+} // anonymous namespace
+
+const ast::Type * adjustExprType(
+	const ast::Type * type, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab
+) {
+	ast::Pass<AdjustExprType> adjuster{ env, symtab };
+	return type->accept( adjuster );
+}
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/Candidate.hpp
===================================================================
--- src/ResolvExpr/Candidate.hpp	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ src/ResolvExpr/Candidate.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -20,8 +20,8 @@
 #include <vector>
 
-#include "Cost.h"
+#include "Cost.hpp"
 #include "AST/Node.hpp"
 #include "AST/TypeEnvironment.hpp"
-#include "Common/Indenter.h"
+#include "Common/Indenter.hpp"
 
 namespace ast {
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -17,5 +17,5 @@
 
 #include <deque>
-#include <iterator>               // for back_inserter
+#include <iterator>                 // for back_inserter
 #include <sstream>
 #include <string>
@@ -25,18 +25,18 @@
 #include "AdjustExprType.hpp"
 #include "Candidate.hpp"
-#include "CastCost.hpp"           // for castCost
+#include "CastCost.hpp"             // for castCost
 #include "CompilationState.hpp"
-#include "ConversionCost.h"       // for conversionCast
-#include "Cost.h"
+#include "ConversionCost.hpp"       // for conversionCast
+#include "Cost.hpp"
 #include "ExplodedArg.hpp"
 #include "PolyCost.hpp"
-#include "RenameVars.h"           // for renameTyVars
-#include "Resolver.h"
-#include "ResolveTypeof.h"
+#include "RenameVars.hpp"           // for renameTyVars
+#include "Resolver.hpp"
+#include "ResolveTypeof.hpp"
 #include "SatisfyAssertions.hpp"
 #include "SpecCost.hpp"
-#include "typeops.h"              // for combos
-#include "Unify.h"
-#include "WidenMode.h"
+#include "Typeops.hpp"              // for combos
+#include "Unify.hpp"
+#include "WidenMode.hpp"
 #include "AST/Expr.hpp"
 #include "AST/Node.hpp"
@@ -45,10 +45,10 @@
 #include "AST/SymbolTable.hpp"
 #include "AST/Type.hpp"
-#include "Common/utility.h"       // for move, copy
-#include "SymTab/Mangler.h"
-#include "Tuples/Tuples.h"        // for handleTupleAssignment
-#include "InitTweak/InitTweak.h"  // for getPointerBase
-
-#include "Common/Stats/Counter.h"
+#include "Common/Utility.hpp"       // for move, copy
+#include "SymTab/Mangler.hpp"
+#include "Tuples/Tuples.hpp"        // for handleTupleAssignment
+#include "InitTweak/InitTweak.hpp"  // for getPointerBase
+
+#include "Common/Stats/Counter.hpp"
 
 #include "AST/Inspect.hpp"             // for getFunctionName
Index: src/ResolvExpr/CandidatePrinter.cpp
===================================================================
--- src/ResolvExpr/CandidatePrinter.cpp	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ src/ResolvExpr/CandidatePrinter.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -24,5 +24,5 @@
 #include "AST/TranslationUnit.hpp"
 #include "ResolvExpr/CandidateFinder.hpp"
-#include "ResolvExpr/Resolver.h"
+#include "ResolvExpr/Resolver.hpp"
 
 namespace ResolvExpr {
Index: src/ResolvExpr/CastCost.cc
===================================================================
--- src/ResolvExpr/CastCost.cc	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,174 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// CastCost.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 06:57:43 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Tue Oct  4 15:00:00 2019
-// Update Count     : 9
-//
-
-#include "CastCost.hpp"
-
-#include <cassert>                       // for assert
-
-#include "AST/Print.hpp"
-#include "AST/SymbolTable.hpp"
-#include "AST/Type.hpp"
-#include "AST/TypeEnvironment.hpp"
-#include "ConversionCost.h"              // for ConversionCost
-#include "Cost.h"                        // for Cost, Cost::infinity
-#include "ResolvExpr/ConversionCost.h"   // for conversionCost
-#include "ResolvExpr/PtrsCastable.hpp"   // for ptrsCastable
-#include "ResolvExpr/Unify.h"            // for typesCompatibleIgnoreQualifiers
-
-#if 0
-#define PRINT(x) x
-#else
-#define PRINT(x)
-#endif
-
-namespace ResolvExpr {
-
-namespace {
-	struct CastCost : public ConversionCost {
-		using ConversionCost::previsit;
-		using ConversionCost::postvisit;
-
-		CastCost(
-			const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
-			const ast::TypeEnvironment & env, CostCalculation costFunc )
-		: ConversionCost( dst, srcIsLvalue, symtab, env, costFunc ) {}
-
-		void postvisit( const ast::BasicType * basicType ) {
-			auto ptr = dynamic_cast< const ast::PointerType * >( dst );
-			if ( ptr && basicType->isInteger() ) {
-				// needed for, e.g. unsigned long => void *
-				cost = Cost::unsafe;
-			} else {
-				cost = conversionCost( basicType, dst, srcIsLvalue, symtab, env );
-				if ( Cost::unsafe < cost ) {
-					if (auto enumInst = dynamic_cast<const ast::EnumInstType *>(dst)) {
-						// Always explict cast only for typed enum
-						if (enumInst->base->isTyped) cost = Cost::unsafe;
-					}
-				}
-			}
-		}
-
-		void postvisit( const ast::ZeroType * zero ) {
-			cost = conversionCost( zero, dst, srcIsLvalue, symtab, env );
-			if ( Cost::unsafe < cost ) {
-				if (auto enumInst =  dynamic_cast<const ast::EnumInstType *>(dst)) {
-					if (enumInst->base->isTyped) cost = Cost::unsafe;
-				}
-			}
-		}
-
-		void postvisit( const ast::OneType * one ) {
-			cost = conversionCost( one, dst, srcIsLvalue, symtab, env );
-			if ( Cost::unsafe < cost ) {
-				if (auto enumInst = dynamic_cast<const ast::EnumInstType *>(dst)) {
-					if (enumInst->base->isTyped) cost = Cost::unsafe;
-				}
-			}
-		}
-
-		void postvisit( const ast::PointerType * pointerType ) {
-			if ( auto ptr = dynamic_cast< const ast::PointerType * >( dst ) ) {
-				if (
-					pointerType->qualifiers <= ptr->qualifiers
-					&& typesCompatibleIgnoreQualifiers( pointerType->base, ptr->base, env )
-				) {
-					cost = Cost::safe;
-				} else {
-					ast::TypeEnvironment newEnv{ env };
-					if ( auto wParams = pointerType->base.as< ast::FunctionType >() ) {
-						newEnv.add( wParams->forall );
-					}
-					int castResult = ptrsCastable( pointerType->base, ptr->base, symtab, newEnv );
-					if ( castResult > 0 ) {
-						cost = Cost::safe;
-					} else if ( castResult < 0 ) {
-						cost = Cost::infinity;
-					}
-				}
-			} else if ( auto basic = dynamic_cast< const ast::BasicType * >( dst ) ) {
-				if ( basic->isInteger() ) {
-					// necessary for, e.g. void * => unsigned long
-					cost = Cost::unsafe;
-				}
-			}
-		}
-
-		void postvist( const ast::EnumInstType * ) {
-			if ( auto basic = dynamic_cast< const ast::BasicType * >(dst) ) {
-				if ( basic->isInteger() ) cost = Cost::unsafe;
-			}
-		}
-	};
-
-} // anonymous namespace
-
-Cost castCost(
-	const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
-	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
-) {
-	if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
-		if ( const ast::EqvClass * eqvClass = env.lookup( *typeInst ) ) {
-			// check cast cost against bound type, if present
-			if ( eqvClass->bound ) {
-				return castCost( src, eqvClass->bound, srcIsLvalue, symtab, env );
-			} else {
-				return Cost::infinity;
-			}
-		} else if ( const ast::NamedTypeDecl * named = symtab.lookupType( typeInst->name ) ) {
-			// all typedefs should be gone by now
-			auto type = strict_dynamic_cast< const ast::TypeDecl * >( named );
-			if ( type->base ) {
-				return castCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
-			}
-		}
-	}
-
-	PRINT(
-		std::cerr << "castCost ::: src is ";
-		ast::print( std::cerr, src );
-		std::cerr << std::endl << "dest is ";
-		ast::print( std::cerr, dst );
-		std::cerr << std::endl << "env is" << std::endl;
-		ast::print( std::cerr, env, 2 );
-	)
-
-	if ( typesCompatibleIgnoreQualifiers( src, dst, env ) ) {
-		PRINT( std::cerr << "compatible!" << std::endl; )
-		if (dynamic_cast<const ast::ZeroType *>(dst) || dynamic_cast<const ast::OneType *>(dst)) {
-			return Cost::spec;
-		}
-		return Cost::zero;
-	} else if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
-		return Cost::safe;
-	} else if ( auto refType = dynamic_cast< const ast::ReferenceType * >( dst ) ) {
-		PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
-		return convertToReferenceCost(
-			src, refType, srcIsLvalue, symtab, env, ptrsCastable );
-	} else {
-		ast::Pass< CastCost > converter(
-			dst, srcIsLvalue, symtab, env, castCost );
-		src->accept( converter );
-		return converter.core.cost;
-	}
-}
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/CastCost.cpp
===================================================================
--- src/ResolvExpr/CastCost.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/CastCost.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,174 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// CastCost.cpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 06:57:43 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Oct  4 15:00:00 2019
+// Update Count     : 9
+//
+
+#include "CastCost.hpp"
+
+#include <cassert>                       // for assert
+
+#include "AST/Print.hpp"
+#include "AST/SymbolTable.hpp"
+#include "AST/Type.hpp"
+#include "AST/TypeEnvironment.hpp"
+#include "ConversionCost.hpp"            // for ConversionCost
+#include "Cost.hpp"                      // for Cost, Cost::infinity
+#include "ResolvExpr/ConversionCost.hpp" // for conversionCost
+#include "ResolvExpr/PtrsCastable.hpp"   // for ptrsCastable
+#include "ResolvExpr/Unify.hpp"          // for typesCompatibleIgnoreQualifiers
+
+#if 0
+#define PRINT(x) x
+#else
+#define PRINT(x)
+#endif
+
+namespace ResolvExpr {
+
+namespace {
+	struct CastCost : public ConversionCost {
+		using ConversionCost::previsit;
+		using ConversionCost::postvisit;
+
+		CastCost(
+			const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
+			const ast::TypeEnvironment & env, CostCalculation costFunc )
+		: ConversionCost( dst, srcIsLvalue, symtab, env, costFunc ) {}
+
+		void postvisit( const ast::BasicType * basicType ) {
+			auto ptr = dynamic_cast< const ast::PointerType * >( dst );
+			if ( ptr && basicType->isInteger() ) {
+				// needed for, e.g. unsigned long => void *
+				cost = Cost::unsafe;
+			} else {
+				cost = conversionCost( basicType, dst, srcIsLvalue, symtab, env );
+				if ( Cost::unsafe < cost ) {
+					if (auto enumInst = dynamic_cast<const ast::EnumInstType *>(dst)) {
+						// Always explict cast only for typed enum
+						if (enumInst->base->isTyped) cost = Cost::unsafe;
+					}
+				}
+			}
+		}
+
+		void postvisit( const ast::ZeroType * zero ) {
+			cost = conversionCost( zero, dst, srcIsLvalue, symtab, env );
+			if ( Cost::unsafe < cost ) {
+				if (auto enumInst =  dynamic_cast<const ast::EnumInstType *>(dst)) {
+					if (enumInst->base->isTyped) cost = Cost::unsafe;
+				}
+			}
+		}
+
+		void postvisit( const ast::OneType * one ) {
+			cost = conversionCost( one, dst, srcIsLvalue, symtab, env );
+			if ( Cost::unsafe < cost ) {
+				if (auto enumInst = dynamic_cast<const ast::EnumInstType *>(dst)) {
+					if (enumInst->base->isTyped) cost = Cost::unsafe;
+				}
+			}
+		}
+
+		void postvisit( const ast::PointerType * pointerType ) {
+			if ( auto ptr = dynamic_cast< const ast::PointerType * >( dst ) ) {
+				if (
+					pointerType->qualifiers <= ptr->qualifiers
+					&& typesCompatibleIgnoreQualifiers( pointerType->base, ptr->base, env )
+				) {
+					cost = Cost::safe;
+				} else {
+					ast::TypeEnvironment newEnv{ env };
+					if ( auto wParams = pointerType->base.as< ast::FunctionType >() ) {
+						newEnv.add( wParams->forall );
+					}
+					int castResult = ptrsCastable( pointerType->base, ptr->base, symtab, newEnv );
+					if ( castResult > 0 ) {
+						cost = Cost::safe;
+					} else if ( castResult < 0 ) {
+						cost = Cost::infinity;
+					}
+				}
+			} else if ( auto basic = dynamic_cast< const ast::BasicType * >( dst ) ) {
+				if ( basic->isInteger() ) {
+					// necessary for, e.g. void * => unsigned long
+					cost = Cost::unsafe;
+				}
+			}
+		}
+
+		void postvist( const ast::EnumInstType * ) {
+			if ( auto basic = dynamic_cast< const ast::BasicType * >(dst) ) {
+				if ( basic->isInteger() ) cost = Cost::unsafe;
+			}
+		}
+	};
+
+} // anonymous namespace
+
+Cost castCost(
+	const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
+	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
+) {
+	if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
+		if ( const ast::EqvClass * eqvClass = env.lookup( *typeInst ) ) {
+			// check cast cost against bound type, if present
+			if ( eqvClass->bound ) {
+				return castCost( src, eqvClass->bound, srcIsLvalue, symtab, env );
+			} else {
+				return Cost::infinity;
+			}
+		} else if ( const ast::NamedTypeDecl * named = symtab.lookupType( typeInst->name ) ) {
+			// all typedefs should be gone by now
+			auto type = strict_dynamic_cast< const ast::TypeDecl * >( named );
+			if ( type->base ) {
+				return castCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
+			}
+		}
+	}
+
+	PRINT(
+		std::cerr << "castCost ::: src is ";
+		ast::print( std::cerr, src );
+		std::cerr << std::endl << "dest is ";
+		ast::print( std::cerr, dst );
+		std::cerr << std::endl << "env is" << std::endl;
+		ast::print( std::cerr, env, 2 );
+	)
+
+	if ( typesCompatibleIgnoreQualifiers( src, dst, env ) ) {
+		PRINT( std::cerr << "compatible!" << std::endl; )
+		if (dynamic_cast<const ast::ZeroType *>(dst) || dynamic_cast<const ast::OneType *>(dst)) {
+			return Cost::spec;
+		}
+		return Cost::zero;
+	} else if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
+		return Cost::safe;
+	} else if ( auto refType = dynamic_cast< const ast::ReferenceType * >( dst ) ) {
+		PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
+		return convertToReferenceCost(
+			src, refType, srcIsLvalue, symtab, env, ptrsCastable );
+	} else {
+		ast::Pass< CastCost > converter(
+			dst, srcIsLvalue, symtab, env, castCost );
+		src->accept( converter );
+		return converter.core.cost;
+	}
+}
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/CastCost.hpp
===================================================================
--- src/ResolvExpr/CastCost.hpp	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ src/ResolvExpr/CastCost.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -16,6 +16,4 @@
 #pragma once
 
-#include "ResolvExpr/Cost.h"     // for Cost
-
 namespace ast {
 	class SymbolTable;
@@ -25,4 +23,6 @@
 
 namespace ResolvExpr {
+
+class Cost;
 
 Cost castCost(
Index: src/ResolvExpr/CommonType.cc
===================================================================
--- src/ResolvExpr/CommonType.cc	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,795 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// CommonType.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 06:59:27 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Feb 14 17:10:10 2019
-// Update Count     : 24
-//
-
-#include "CommonType.hpp"
-
-#include <cassert>                       // for strict_dynamic_cast
-#include <map>                           // for _Rb_tree_const_iterator
-#include <utility>                       // for pair
-
-#include "AST/Decl.hpp"
-#include "AST/Pass.hpp"
-#include "AST/Type.hpp"
-#include "Unify.h"                       // for unifyExact, WidenMode
-#include "typeops.h"                     // for isFtype
-#include "Tuples/Tuples.h"
-
-// #define DEBUG
-#ifdef DEBUG
-#define PRINT(x) x
-#else
-#define PRINT(x)
-#endif
-
-namespace ResolvExpr {
-
-namespace {
-
-	// GENERATED START, DO NOT EDIT
-	// GENERATED BY BasicTypes-gen.cpp
-	#define BT ast::BasicKind::
-	static const ast::BasicKind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor
-		/*		                        B                       C                      SC                      UC                      SI                     SUI
-				                        I                      UI                      LI                     LUI                     LLI                    LLUI
-				                       IB                     UIB                     _FH                     _FH                      _F                     _FC
-				                        F                      FC                     _FX                    _FXC                      FD                    _FDC
-				                        D                      DC                    F80X                   _FDXC                     F80                     _FB
-				                    _FLDC                      FB                      LD                     LDC                    _FBX                  _FLDXC
-				 */
-				  {
-		/*      B */                BT Bool,                BT Char,          BT SignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
-				             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
-				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*      C */                BT Char,                BT Char,          BT SignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
-				             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
-				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*     SC */          BT SignedChar,          BT SignedChar,          BT SignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
-				             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
-				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*     UC */        BT UnsignedChar,        BT UnsignedChar,        BT UnsignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
-				             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
-				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*     SI */      BT ShortSignedInt,      BT ShortSignedInt,      BT ShortSignedInt,      BT ShortSignedInt,      BT ShortSignedInt,    BT ShortUnsignedInt,
-				             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
-				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*    SUI */    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,
-				             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
-				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*      I */           BT SignedInt,           BT SignedInt,           BT SignedInt,           BT SignedInt,           BT SignedInt,           BT SignedInt,
-				             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
-				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*     UI */         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,
-				           BT UnsignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
-				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*     LI */       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,
-				         BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
-				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*    LUI */     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,
-				       BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
-				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*    LLI */   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,
-				     BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
-				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*   LLUI */ BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt,
-				   BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt,
-				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*     IB */        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,
-				          BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,
-				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*    UIB */      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,
-				        BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,
-				        BT UnsignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*    _FH */            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,
-				              BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,
-				              BT uFloat16,            BT uFloat16,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*    _FH */     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,
-				       BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,
-				       BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat32Complex,     BT uFloat32Complex,
-				          BT FloatComplex,        BT FloatComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
-				         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
-				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
-				  },
-				  {
-		/*     _F */            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,
-				              BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,
-				              BT uFloat32,            BT uFloat32,            BT uFloat32,     BT uFloat32Complex,            BT uFloat32,     BT uFloat32Complex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*    _FC */     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,
-				       BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,
-				       BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,
-				          BT FloatComplex,        BT FloatComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
-				         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
-				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
-				  },
-				  {
-		/*      F */               BT Float,               BT Float,               BT Float,               BT Float,               BT Float,               BT Float,
-				                 BT Float,               BT Float,               BT Float,               BT Float,               BT Float,               BT Float,
-				                 BT Float,               BT Float,               BT Float,        BT FloatComplex,               BT Float,        BT FloatComplex,
-				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*     FC */        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,
-				          BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,
-				          BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,
-				          BT FloatComplex,        BT FloatComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
-				         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
-				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
-				  },
-				  {
-		/*    _FX */           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,
-				             BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,
-				             BT uFloat32x,           BT uFloat32x,           BT uFloat32x,    BT uFloat32xComplex,           BT uFloat32x,    BT uFloat32xComplex,
-				             BT uFloat32x,    BT uFloat32xComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*   _FXC */    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,
-				      BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,
-				      BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,
-				      BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
-				         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
-				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
-				  },
-				  {
-		/*     FD */            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,
-				              BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,
-				              BT uFloat64,            BT uFloat64,            BT uFloat64,     BT uFloat64Complex,            BT uFloat64,     BT uFloat64Complex,
-				              BT uFloat64,     BT uFloat64Complex,            BT uFloat64,     BT uFloat64Complex,            BT uFloat64,     BT uFloat64Complex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*   _FDC */     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
-				       BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
-				       BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
-				       BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
-				         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
-				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
-				  },
-				  {
-		/*      D */              BT Double,              BT Double,              BT Double,              BT Double,              BT Double,              BT Double,
-				                BT Double,              BT Double,              BT Double,              BT Double,              BT Double,              BT Double,
-				                BT Double,              BT Double,              BT Double,       BT DoubleComplex,              BT Double,       BT DoubleComplex,
-				                BT Double,       BT DoubleComplex,              BT Double,       BT DoubleComplex,              BT Double,       BT DoubleComplex,
-				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*     DC */       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
-				         BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
-				         BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
-				         BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
-				         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
-				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
-				  },
-				  {
-		/*   F80X */           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,
-				             BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,
-				             BT uFloat64x,           BT uFloat64x,           BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,
-				             BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,
-				             BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*  _FDXC */    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
-				      BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
-				      BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
-				      BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
-				      BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
-				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
-				  },
-				  {
-		/*    F80 */           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,
-				             BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,
-				             BT uuFloat80,           BT uuFloat80,           BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,
-				             BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,
-				             BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*    _FB */           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,
-				             BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,
-				             BT uFloat128,           BT uFloat128,           BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,
-				             BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,
-				             BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,           BT uFloat128,           BT uFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*  _FLDC */    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
-				      BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
-				      BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
-				      BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
-				      BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
-				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
-				  },
-				  {
-		/*     FB */          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,
-				            BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,
-				            BT uuFloat128,          BT uuFloat128,          BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,
-				            BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,
-				            BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,          BT uuFloat128,
-				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*     LD */          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,
-				            BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,
-				            BT LongDouble,          BT LongDouble,          BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,
-				            BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,
-				            BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,          BT LongDouble,
-				     BT LongDoubleComplex,          BT LongDouble,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/*    LDC */   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
-				     BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
-				     BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
-				     BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
-				     BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
-				     BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
-				  },
-				  {
-		/*   _FBX */          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,
-				            BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,
-				            BT uFloat128x,          BT uFloat128x,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				            BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				            BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,          BT uFloat128x,
-				     BT uFloat128xComplex,          BT uFloat128x,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,
-				  },
-				  {
-		/* _FLDXC */   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
-				     BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
-				     BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
-				     BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
-				     BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
-				     BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
-				  },
-	}; // commonTypes
-	#undef BT
-	// GENERATED END
-	static_assert(
-		sizeof(commonTypes)/sizeof(commonTypes[0][0]) == ast::BasicKind::NUMBER_OF_BASIC_TYPES * ast::BasicKind::NUMBER_OF_BASIC_TYPES,
-		"Each basic type kind should have a corresponding row in the combined type matrix"
-	);
-
-class CommonType final : public ast::WithShortCircuiting {
-	const ast::Type * type2;
-	WidenMode widen;
-	ast::TypeEnvironment & tenv;
-	const ast::OpenVarSet & open;
-	ast::AssertionSet & need;
-	ast::AssertionSet & have;
-public:
-	static size_t traceId;
-	ast::ptr< ast::Type > result;
-
-	CommonType(
-		const ast::Type * t2, WidenMode w,
-		ast::TypeEnvironment & env, const ast::OpenVarSet & o,
-		ast::AssertionSet & need, ast::AssertionSet & have )
-	: type2( t2 ), widen( w ), tenv( env ), open( o ), need (need), have (have) ,result() {}
-
-	void previsit( const ast::Node * ) { visit_children = false; }
-
-	void postvisit( const ast::VoidType * ) {}
-
-	void postvisit( const ast::BasicType * basic ) {
-		if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
-			ast::BasicKind kind;
-			if (basic->kind != basic2->kind && !widen.first && !widen.second) return;
-			else if (!widen.first) kind = basic->kind; // widen.second
-			else if (!widen.second) kind = basic2->kind;
-			else kind = commonTypes[ basic->kind ][ basic2->kind ];
-			// xxx - what does qualifiers even do here??
-			if ( (basic->qualifiers >= basic2->qualifiers || widen.first)
-				&& (basic->qualifiers <= basic2->qualifiers || widen.second) ) {
-				result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers };
-			}
-		} else if (
-			dynamic_cast< const ast::ZeroType * >( type2 )
-			|| dynamic_cast< const ast::OneType * >( type2 )
-		) {
-			if (widen.second) {
-				result = new ast::BasicType{ basic->kind, basic->qualifiers | type2->qualifiers };
-			}
-		} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
-			const ast::EnumDecl* enumDecl = enumInst->base;
-			if ( !enumDecl->base ) {
-				ast::BasicKind kind = commonTypes[ basic->kind ][ ast::BasicKind::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::BasicKind kind = commonTypes[ basic->kind ][ ast::BasicKind::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 };
-				}
-			}
-		}
-	}
-
-private:
-	template< typename Pointer >
-	void getCommonWithVoidPointer( const Pointer * voidPtr, const Pointer * oPtr ) {
-		const ast::Type * base = oPtr->base;
-		if ( auto var = dynamic_cast< const ast::TypeInstType * >( base ) ) {
-			auto entry = open.find( *var );
-			if ( entry != open.end() ) {
-				ast::AssertionSet need, have;
-				if ( ! tenv.bindVar(
-					var, voidPtr->base, entry->second, need, have, open, widen )
-				) return;
-			}
-		}
-		result = voidPtr;
-		add_qualifiers( result, oPtr->qualifiers );
-	}
-
-public:
-	void postvisit( const ast::PointerType * pointer ) {
-		if ( auto pointer2 = dynamic_cast< const ast::PointerType * >( type2 ) ) {
-			if (
-				widen.first
-				&& pointer2->base.as< ast::VoidType >()
-				&& ! ast::isFtype( pointer->base )
-			) {
-				getCommonWithVoidPointer( pointer2, pointer );
-			} else if (
-				widen.second
-				&& pointer->base.as< ast::VoidType >()
-				&& ! ast::isFtype( pointer2->base )
-			) {
-				getCommonWithVoidPointer( pointer, pointer2 );
-			} else if (
-				( pointer->base->qualifiers >= pointer2->base->qualifiers || widen.first )
-				&& ( pointer->base->qualifiers <= pointer2->base->qualifiers || widen.second )
-			) {
-				ast::CV::Qualifiers q1 = pointer->base->qualifiers;
-				ast::CV::Qualifiers q2 = pointer2->base->qualifiers;
-
-				// force t{1,2} to be cloned if their qualifiers must be stripped, so that
-				// pointer{,2}->base are unchanged
-				ast::ptr< ast::Type > t1{ pointer->base }, t2{ pointer2->base };
-				reset_qualifiers( t1 );
-				reset_qualifiers( t2 );
-
-				ast::OpenVarSet newOpen{ open };
-				if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden() ) ) {
-					result = pointer;
-					if ( q1.val != q2.val ) {
-						// reset result->base->qualifiers to be union of two base qualifiers
-						strict_dynamic_cast< ast::PointerType * >(
-							result.get_and_mutate()
-						)->base.get_and_mutate()->qualifiers = q1 | q2;
-					}
-				} else if ( isFtype (t1) && isFtype (t2) ) {
-					auto f1 = t1.as<ast::FunctionType>();
-					if (!f1) return;
-					auto f2 = t2.strict_as<ast::FunctionType>();
-
-					assertf(f1->returns.size() <= 1, "Function return should not be a list");
-					assertf(f2->returns.size() <= 1, "Function return should not be a list");
-
-					if (
-						( f1->params.size() != f2->params.size() || f1->returns.size() != f2->returns.size() )
-						&& ! f1->isTtype()
-						&& ! f2->isTtype()
-					) return;
-
-					auto params1 = flattenList( f1->params, tenv );
-					auto params2 = flattenList( f2->params, tenv );
-
-					auto crnt1 = params1.begin();
-					auto crnt2 = params2.begin();
-					auto end1 = params1.end();
-					auto end2 = params2.end();
-
-					while (crnt1 != end1 && crnt2 != end2 ) {
-						const ast::Type * arg1 = *crnt1;
-						const ast::Type * arg2 = *crnt2;
-
-						bool isTuple1 = Tuples::isTtype( t1 );
-						bool isTuple2 = Tuples::isTtype( t2 );
-
-						// assumes here that ttype *must* be last parameter
-						if ( isTuple1 && ! isTuple2 ) {
-							// combine remainder of list2, then unify
-							if (unifyExact(
-								arg1, tupleFromTypes( crnt2, end2 ), tenv, need, have, open,
-								noWiden() )) {
-									break;
-							} else return;
-						} else if ( ! isTuple1 && isTuple2 ) {
-							// combine remainder of list1, then unify
-							if (unifyExact(
-								tupleFromTypes( crnt1, end1 ), arg2, tenv, need, have, open,
-								noWiden() )) {
-									break;
-							} else return;
-						}
-
-						// allow qualifiers of pointer and reference base to become more specific
-						if (auto ref1 = dynamic_cast<const ast::ReferenceType *> (arg1)) {
-							if (auto ref2 = dynamic_cast<const ast::ReferenceType *> (arg2)) {
-								ast::ptr<ast::Type> base1 = ref1->base;
-								ast::ptr<ast::Type> base2 = ref2->base;
-
-								// xxx - assume LHS is always the target type
-
-								if ( ! ((widen.second && ref2->qualifiers.is_mutex)
-								|| (ref1->qualifiers.is_mutex == ref2->qualifiers.is_mutex ))) return;
-
-								if ( (widen.second && base1->qualifiers <= base2->qualifiers ) || (base2->qualifiers == base1->qualifiers) ) {
-
-									reset_qualifiers(base1);
-									reset_qualifiers(base2);
-
-									if ( !unifyExact(
-										base1, base2, tenv, need, have, open, noWiden() )
-									) return;
-								}
-							} else return;
-						} else if (auto ptr1 = dynamic_cast<const ast::PointerType *> (arg1)) {
-							if (auto ptr2 = dynamic_cast<const ast::PointerType *> (arg2)) {
-								ast::ptr<ast::Type> base1 = ptr1->base;
-								ast::ptr<ast::Type> base2 = ptr2->base;
-
-								// xxx - assume LHS is always the target type
-								// a function accepting const can always be called by non-const arg
-
-								if ( (widen.second && base1->qualifiers <= base2->qualifiers ) || (base2->qualifiers == base1->qualifiers) ) {
-
-									reset_qualifiers(base1);
-									reset_qualifiers(base2);
-
-									if ( ! unifyExact(
-										base1, base2, tenv, need, have, open, noWiden() )
-									) return;
-								}
-							} else return;
-						} else if (! unifyExact(
-								arg1, arg2, tenv, need, have, open, noWiden() )) {
-							return;
-						}
-						++crnt1; ++crnt2;
-					}
-					if ( crnt1 != end1 ) {
-						// try unifying empty tuple with ttype
-						const ast::Type * t1 = *crnt1;
-						if (! Tuples::isTtype( t1 ) ) return;
-						if (! unifyExact(
-							t1, tupleFromTypes( crnt2, end2 ), tenv, need, have, open,
-							noWiden() )) return;
-					} else if ( crnt2 != end2 ) {
-						// try unifying empty tuple with ttype
-						const ast::Type * t2 = *crnt2;
-						if ( !Tuples::isTtype( t2 ) ) return;
-						if ( !unifyExact(
-							tupleFromTypes( crnt1, end1 ), t2, tenv, need, have, open,
-							noWiden() )) return;
-					}
-					if ((f1->returns.size() == 0 && f2->returns.size() == 0)
-					  || (f1->returns.size() == 1 && f2->returns.size() == 1 && unifyExact(f1->returns[0], f2->returns[0], tenv, need, have, open, noWiden()))) {
-						result = pointer;
-
-						for (auto & assn : f1->assertions) {
-							auto i = need.find(assn);
-							if (i != need.end()) i->second.isUsed = true;
-							auto j = have.find(assn);
-							if (j != have.end()) j->second.isUsed = true;
-						}
-
-						for (auto & assn : f2->assertions) {
-							auto i = need.find(assn);
-							if (i != need.end()) i->second.isUsed = true;
-							auto j = have.find(assn);
-							if (j != have.end()) j->second.isUsed = true;
-						}
-					}
-				} // if ftype
-			}
-		} else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) {
-			result = pointer;
-			add_qualifiers( result, type2->qualifiers );
-		}
-	}
-
-	void postvisit( const ast::ArrayType * ) {}
-
-	void postvisit( const ast::ReferenceType * ref ) {
-		if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) {
-			if (
-				widen.first && ref2->base.as< ast::VoidType >() && ! ast::isFtype( ref->base )
-			) {
-				getCommonWithVoidPointer( ref2, ref );
-			} else if (
-				widen.second && ref->base.as< ast::VoidType>() && ! ast::isFtype( ref2->base )
-			) {
-				getCommonWithVoidPointer( ref, ref2 );
-			} else if (
-				( ref->base->qualifiers >= ref2->base->qualifiers || widen.first )
-				&& ( ref->base->qualifiers <= ref2->base->qualifiers || widen.second )
-			) {
-				ast::CV::Qualifiers q1 = ref->base->qualifiers, q2 = ref2->base->qualifiers;
-
-				// force t{1,2} to be cloned if their qualifiers must be stripped, so that
-				// ref{,2}->base are unchanged
-				ast::ptr< ast::Type > t1{ ref->base }, t2{ ref2->base };
-				reset_qualifiers( t1 );
-				reset_qualifiers( t2 );
-
-				ast::OpenVarSet newOpen{ open };
-				if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden() ) ) {
-					result = ref;
-					if ( q1.val != q2.val ) {
-						// reset result->base->qualifiers to be union of two base qualifiers
-						strict_dynamic_cast< ast::ReferenceType * >(
-							result.get_and_mutate()
-						)->base.get_and_mutate()->qualifiers = q1 | q2;
-					}
-				}
-			}
-		} else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) {
-			result = ref;
-			add_qualifiers( result, type2->qualifiers );
-		} else {
-			if (!dynamic_cast<const ast::EnumInstType *>(type2))
-				result = commonType( type2, ref, tenv, need, have, open, widen );
-		}
-	}
-
-	void postvisit( const ast::FunctionType * ) {}
-
-	void postvisit( const ast::StructInstType * ) {}
-
-	void postvisit( const ast::UnionInstType * ) {}
-
-	void postvisit( const ast::EnumInstType * enumInst ) {
-		if ( enumInst->base && !enumInst->base->isTyped ) {
-			auto basicType = new ast::BasicType( ast::BasicKind::UnsignedInt );
-			result = commonType( basicType, type2, tenv, need, have, open, widen);
-		}
-	}
-
-	void postvisit( const ast::EnumAttrType * ) {}
-
-	void postvisit( const ast::TraitInstType * ) {}
-
-	void postvisit( const ast::TypeInstType * ) {}
-
-	void postvisit( const ast::TupleType * ) {}
-
-	void postvisit( const ast::VarArgsType * ) {}
-
-	void postvisit( const ast::ZeroType * zero ) {
-		if ( !widen.first ) return;
-		if ( dynamic_cast< const ast::BasicType * >( type2 )
-				|| dynamic_cast< const ast::PointerType * >( type2 ) ) {
-			if ( widen.second || zero->qualifiers <= type2->qualifiers ) {
-				result = type2;
-				add_qualifiers( result, zero->qualifiers );
-			}
-		} else if ( widen.second && dynamic_cast< const ast::OneType * >( type2 ) ) {
-			result = new ast::BasicType{
-				ast::BasicKind::SignedInt, zero->qualifiers | type2->qualifiers };
-		} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
-			const ast::EnumDecl * enumDecl = enumInst->base;
-			if ( !enumDecl->base ) {
-				if ( widen.second || zero->qualifiers <= type2->qualifiers ) {
-					result = type2;
-					add_qualifiers( result, zero->qualifiers );
-				}
-			}
-		}
-	}
-
-	void postvisit( const ast::OneType * one ) {
-		if ( !widen.first ) return;
-		if ( dynamic_cast< const ast::BasicType * >( type2 ) ) {
-			if ( widen.second || one->qualifiers <= type2->qualifiers ) {
-				result = type2;
-				add_qualifiers( result, one->qualifiers );
-			}
-		} else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) {
-			result = new ast::BasicType{
-				ast::BasicKind::SignedInt, one->qualifiers | type2->qualifiers };
-		} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
-			const ast::EnumDecl * enumDecl = enumInst->base;
-			if ( !enumDecl->base ) {
-				if ( widen.second || one->qualifiers <= type2->qualifiers ) {
-					result = type2;
-					add_qualifiers( result, one->qualifiers );
-				}
-			}
-		}
-	}
-};
-
-// size_t CommonType::traceId = Stats::Heap::new_stacktrace_id("CommonType");
-
-ast::ptr< ast::Type > handleReference(
-	const ast::ptr< ast::Type > & t1, const ast::ptr< ast::Type > & t2, WidenMode widen,
-	ast::TypeEnvironment & env,
-	const ast::OpenVarSet & open
-) {
-	ast::ptr<ast::Type> common;
-	ast::AssertionSet have, need;
-	ast::OpenVarSet newOpen( open );
-
-	// need unify to bind type variables
-	if ( unify( t1, t2, env, have, need, newOpen, common ) ) {
-		ast::CV::Qualifiers q1 = t1->qualifiers, q2 = t2->qualifiers;
-		PRINT(
-			std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
-		)
-		if ( ( widen.first || q2 <= q1 ) && ( widen.second || q1 <= q2 ) ) {
-			PRINT(
-				std::cerr << "widen okay" << std::endl;
-			)
-			add_qualifiers( common, q1 | q2 );
-			return common;
-		}
-	}
-
-	PRINT(
-		std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;
-	)
-	return { nullptr };
-}
-
-} // namespace
-
-ast::ptr< ast::Type > commonType(
-	const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2,
-	ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
-	const ast::OpenVarSet & open, WidenMode widen
-) {
-	unsigned depth1 = type1->referenceDepth();
-	unsigned depth2 = type2->referenceDepth();
-
-	if ( depth1 != depth2 ) {  // implies depth1 > 0 || depth2 > 0
-		PRINT(
-			std::cerr << "reference depth diff: " << (depth1-depth2) << std::endl;
-		)
-		ast::ptr< ast::Type > result;
-		const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >();
-		const ast::ReferenceType * ref2 = type2.as< ast::ReferenceType >();
-
-		if ( depth1 > depth2 ) {
-			assert( ref1 );
-			result = handleReference( ref1->base, type2, widen, env, open );
-		} else {  // Implies depth1 < depth2
-			assert( ref2 );
-			result = handleReference( type1, ref2->base, widen, env, open );
-		}
-
-		if ( result && ref1 ) {
-			// formal is reference, so result should be reference
-			PRINT(
-				std::cerr << "formal is reference; result should be reference" << std::endl;
-			)
-			result = new ast::ReferenceType{ result, ref1->qualifiers };
-		}
-
-		PRINT(
-			std::cerr << "common type of reference [" << type1 << "] and [" << type2 << "] is "
-			"[" << result << "]" << std::endl;
-		)
-		return result;
-	}
-	// otherwise both are reference types of the same depth and this is handled by the visitor
-	return ast::Pass<CommonType>::read( type1.get(),
-		type2, widen, env, open, need, have );
-}
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/CommonType.cpp
===================================================================
--- src/ResolvExpr/CommonType.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/CommonType.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,795 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// CommonType.cpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 06:59:27 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Thu Feb 14 17:10:10 2019
+// Update Count     : 24
+//
+
+#include "CommonType.hpp"
+
+#include <cassert>                       // for strict_dynamic_cast
+#include <map>                           // for _Rb_tree_const_iterator
+#include <utility>                       // for pair
+
+#include "AST/Decl.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Type.hpp"
+#include "Unify.hpp"                     // for unifyExact, WidenMode
+#include "Typeops.hpp"                   // for isFtype
+#include "Tuples/Tuples.hpp"
+
+// #define DEBUG
+#ifdef DEBUG
+#define PRINT(x) x
+#else
+#define PRINT(x)
+#endif
+
+namespace ResolvExpr {
+
+namespace {
+
+	// GENERATED START, DO NOT EDIT
+	// GENERATED BY BasicTypes-gen.cpp
+	#define BT ast::BasicKind::
+	static const ast::BasicKind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor
+		/*		                        B                       C                      SC                      UC                      SI                     SUI
+				                        I                      UI                      LI                     LUI                     LLI                    LLUI
+				                       IB                     UIB                     _FH                     _FH                      _F                     _FC
+				                        F                      FC                     _FX                    _FXC                      FD                    _FDC
+				                        D                      DC                    F80X                   _FDXC                     F80                     _FB
+				                    _FLDC                      FB                      LD                     LDC                    _FBX                  _FLDXC
+				 */
+				  {
+		/*      B */                BT Bool,                BT Char,          BT SignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
+				             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
+				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*      C */                BT Char,                BT Char,          BT SignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
+				             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
+				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*     SC */          BT SignedChar,          BT SignedChar,          BT SignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
+				             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
+				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*     UC */        BT UnsignedChar,        BT UnsignedChar,        BT UnsignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
+				             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
+				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*     SI */      BT ShortSignedInt,      BT ShortSignedInt,      BT ShortSignedInt,      BT ShortSignedInt,      BT ShortSignedInt,    BT ShortUnsignedInt,
+				             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
+				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*    SUI */    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,
+				             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
+				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*      I */           BT SignedInt,           BT SignedInt,           BT SignedInt,           BT SignedInt,           BT SignedInt,           BT SignedInt,
+				             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
+				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*     UI */         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,
+				           BT UnsignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
+				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*     LI */       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,
+				         BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
+				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*    LUI */     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,
+				       BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
+				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*    LLI */   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,
+				     BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
+				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*   LLUI */ BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt,
+				   BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt,
+				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*     IB */        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,
+				          BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,
+				          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*    UIB */      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,
+				        BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,
+				        BT UnsignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*    _FH */            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,
+				              BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,
+				              BT uFloat16,            BT uFloat16,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*    _FH */     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,
+				       BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,
+				       BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat32Complex,     BT uFloat32Complex,
+				          BT FloatComplex,        BT FloatComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
+				         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
+				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
+				  },
+				  {
+		/*     _F */            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,
+				              BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,
+				              BT uFloat32,            BT uFloat32,            BT uFloat32,     BT uFloat32Complex,            BT uFloat32,     BT uFloat32Complex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*    _FC */     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,
+				       BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,
+				       BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,
+				          BT FloatComplex,        BT FloatComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
+				         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
+				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
+				  },
+				  {
+		/*      F */               BT Float,               BT Float,               BT Float,               BT Float,               BT Float,               BT Float,
+				                 BT Float,               BT Float,               BT Float,               BT Float,               BT Float,               BT Float,
+				                 BT Float,               BT Float,               BT Float,        BT FloatComplex,               BT Float,        BT FloatComplex,
+				                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*     FC */        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,
+				          BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,
+				          BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,
+				          BT FloatComplex,        BT FloatComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
+				         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
+				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
+				  },
+				  {
+		/*    _FX */           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,
+				             BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,
+				             BT uFloat32x,           BT uFloat32x,           BT uFloat32x,    BT uFloat32xComplex,           BT uFloat32x,    BT uFloat32xComplex,
+				             BT uFloat32x,    BT uFloat32xComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*   _FXC */    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,
+				      BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,
+				      BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,
+				      BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
+				         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
+				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
+				  },
+				  {
+		/*     FD */            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,
+				              BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,
+				              BT uFloat64,            BT uFloat64,            BT uFloat64,     BT uFloat64Complex,            BT uFloat64,     BT uFloat64Complex,
+				              BT uFloat64,     BT uFloat64Complex,            BT uFloat64,     BT uFloat64Complex,            BT uFloat64,     BT uFloat64Complex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*   _FDC */     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
+				       BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
+				       BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
+				       BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
+				         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
+				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
+				  },
+				  {
+		/*      D */              BT Double,              BT Double,              BT Double,              BT Double,              BT Double,              BT Double,
+				                BT Double,              BT Double,              BT Double,              BT Double,              BT Double,              BT Double,
+				                BT Double,              BT Double,              BT Double,       BT DoubleComplex,              BT Double,       BT DoubleComplex,
+				                BT Double,       BT DoubleComplex,              BT Double,       BT DoubleComplex,              BT Double,       BT DoubleComplex,
+				                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*     DC */       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
+				         BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
+				         BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
+				         BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
+				         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
+				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
+				  },
+				  {
+		/*   F80X */           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,
+				             BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,
+				             BT uFloat64x,           BT uFloat64x,           BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,
+				             BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,
+				             BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*  _FDXC */    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
+				      BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
+				      BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
+				      BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
+				      BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
+				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
+				  },
+				  {
+		/*    F80 */           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,
+				             BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,
+				             BT uuFloat80,           BT uuFloat80,           BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,
+				             BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,
+				             BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*    _FB */           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,
+				             BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,
+				             BT uFloat128,           BT uFloat128,           BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,
+				             BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,
+				             BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,           BT uFloat128,           BT uFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*  _FLDC */    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
+				      BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
+				      BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
+				      BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
+				      BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
+				      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
+				  },
+				  {
+		/*     FB */          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,
+				            BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,
+				            BT uuFloat128,          BT uuFloat128,          BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,
+				            BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,
+				            BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,          BT uuFloat128,
+				      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*     LD */          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,
+				            BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,
+				            BT LongDouble,          BT LongDouble,          BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,
+				            BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,
+				            BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,          BT LongDouble,
+				     BT LongDoubleComplex,          BT LongDouble,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/*    LDC */   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
+				     BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
+				     BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
+				     BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
+				     BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
+				     BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
+				  },
+				  {
+		/*   _FBX */          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,
+				            BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,
+				            BT uFloat128x,          BT uFloat128x,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				            BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				            BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,          BT uFloat128x,
+				     BT uFloat128xComplex,          BT uFloat128x,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,
+				  },
+				  {
+		/* _FLDXC */   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
+				     BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
+				     BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
+				     BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
+				     BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
+				     BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
+				  },
+	}; // commonTypes
+	#undef BT
+	// GENERATED END
+	static_assert(
+		sizeof(commonTypes)/sizeof(commonTypes[0][0]) == ast::BasicKind::NUMBER_OF_BASIC_TYPES * ast::BasicKind::NUMBER_OF_BASIC_TYPES,
+		"Each basic type kind should have a corresponding row in the combined type matrix"
+	);
+
+class CommonType final : public ast::WithShortCircuiting {
+	const ast::Type * type2;
+	WidenMode widen;
+	ast::TypeEnvironment & tenv;
+	const ast::OpenVarSet & open;
+	ast::AssertionSet & need;
+	ast::AssertionSet & have;
+public:
+	static size_t traceId;
+	ast::ptr< ast::Type > result;
+
+	CommonType(
+		const ast::Type * t2, WidenMode w,
+		ast::TypeEnvironment & env, const ast::OpenVarSet & o,
+		ast::AssertionSet & need, ast::AssertionSet & have )
+	: type2( t2 ), widen( w ), tenv( env ), open( o ), need (need), have (have) ,result() {}
+
+	void previsit( const ast::Node * ) { visit_children = false; }
+
+	void postvisit( const ast::VoidType * ) {}
+
+	void postvisit( const ast::BasicType * basic ) {
+		if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
+			ast::BasicKind kind;
+			if (basic->kind != basic2->kind && !widen.first && !widen.second) return;
+			else if (!widen.first) kind = basic->kind; // widen.second
+			else if (!widen.second) kind = basic2->kind;
+			else kind = commonTypes[ basic->kind ][ basic2->kind ];
+			// xxx - what does qualifiers even do here??
+			if ( (basic->qualifiers >= basic2->qualifiers || widen.first)
+				&& (basic->qualifiers <= basic2->qualifiers || widen.second) ) {
+				result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers };
+			}
+		} else if (
+			dynamic_cast< const ast::ZeroType * >( type2 )
+			|| dynamic_cast< const ast::OneType * >( type2 )
+		) {
+			if (widen.second) {
+				result = new ast::BasicType{ basic->kind, basic->qualifiers | type2->qualifiers };
+			}
+		} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
+			const ast::EnumDecl* enumDecl = enumInst->base;
+			if ( !enumDecl->base ) {
+				ast::BasicKind kind = commonTypes[ basic->kind ][ ast::BasicKind::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::BasicKind kind = commonTypes[ basic->kind ][ ast::BasicKind::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 };
+				}
+			}
+		}
+	}
+
+private:
+	template< typename Pointer >
+	void getCommonWithVoidPointer( const Pointer * voidPtr, const Pointer * oPtr ) {
+		const ast::Type * base = oPtr->base;
+		if ( auto var = dynamic_cast< const ast::TypeInstType * >( base ) ) {
+			auto entry = open.find( *var );
+			if ( entry != open.end() ) {
+				ast::AssertionSet need, have;
+				if ( ! tenv.bindVar(
+					var, voidPtr->base, entry->second, need, have, open, widen )
+				) return;
+			}
+		}
+		result = voidPtr;
+		add_qualifiers( result, oPtr->qualifiers );
+	}
+
+public:
+	void postvisit( const ast::PointerType * pointer ) {
+		if ( auto pointer2 = dynamic_cast< const ast::PointerType * >( type2 ) ) {
+			if (
+				widen.first
+				&& pointer2->base.as< ast::VoidType >()
+				&& ! ast::isFtype( pointer->base )
+			) {
+				getCommonWithVoidPointer( pointer2, pointer );
+			} else if (
+				widen.second
+				&& pointer->base.as< ast::VoidType >()
+				&& ! ast::isFtype( pointer2->base )
+			) {
+				getCommonWithVoidPointer( pointer, pointer2 );
+			} else if (
+				( pointer->base->qualifiers >= pointer2->base->qualifiers || widen.first )
+				&& ( pointer->base->qualifiers <= pointer2->base->qualifiers || widen.second )
+			) {
+				ast::CV::Qualifiers q1 = pointer->base->qualifiers;
+				ast::CV::Qualifiers q2 = pointer2->base->qualifiers;
+
+				// force t{1,2} to be cloned if their qualifiers must be stripped, so that
+				// pointer{,2}->base are unchanged
+				ast::ptr< ast::Type > t1{ pointer->base }, t2{ pointer2->base };
+				reset_qualifiers( t1 );
+				reset_qualifiers( t2 );
+
+				ast::OpenVarSet newOpen{ open };
+				if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden() ) ) {
+					result = pointer;
+					if ( q1.val != q2.val ) {
+						// reset result->base->qualifiers to be union of two base qualifiers
+						strict_dynamic_cast< ast::PointerType * >(
+							result.get_and_mutate()
+						)->base.get_and_mutate()->qualifiers = q1 | q2;
+					}
+				} else if ( isFtype (t1) && isFtype (t2) ) {
+					auto f1 = t1.as<ast::FunctionType>();
+					if (!f1) return;
+					auto f2 = t2.strict_as<ast::FunctionType>();
+
+					assertf(f1->returns.size() <= 1, "Function return should not be a list");
+					assertf(f2->returns.size() <= 1, "Function return should not be a list");
+
+					if (
+						( f1->params.size() != f2->params.size() || f1->returns.size() != f2->returns.size() )
+						&& ! f1->isTtype()
+						&& ! f2->isTtype()
+					) return;
+
+					auto params1 = flattenList( f1->params, tenv );
+					auto params2 = flattenList( f2->params, tenv );
+
+					auto crnt1 = params1.begin();
+					auto crnt2 = params2.begin();
+					auto end1 = params1.end();
+					auto end2 = params2.end();
+
+					while (crnt1 != end1 && crnt2 != end2 ) {
+						const ast::Type * arg1 = *crnt1;
+						const ast::Type * arg2 = *crnt2;
+
+						bool isTuple1 = Tuples::isTtype( t1 );
+						bool isTuple2 = Tuples::isTtype( t2 );
+
+						// assumes here that ttype *must* be last parameter
+						if ( isTuple1 && ! isTuple2 ) {
+							// combine remainder of list2, then unify
+							if (unifyExact(
+								arg1, tupleFromTypes( crnt2, end2 ), tenv, need, have, open,
+								noWiden() )) {
+									break;
+							} else return;
+						} else if ( ! isTuple1 && isTuple2 ) {
+							// combine remainder of list1, then unify
+							if (unifyExact(
+								tupleFromTypes( crnt1, end1 ), arg2, tenv, need, have, open,
+								noWiden() )) {
+									break;
+							} else return;
+						}
+
+						// allow qualifiers of pointer and reference base to become more specific
+						if (auto ref1 = dynamic_cast<const ast::ReferenceType *> (arg1)) {
+							if (auto ref2 = dynamic_cast<const ast::ReferenceType *> (arg2)) {
+								ast::ptr<ast::Type> base1 = ref1->base;
+								ast::ptr<ast::Type> base2 = ref2->base;
+
+								// xxx - assume LHS is always the target type
+
+								if ( ! ((widen.second && ref2->qualifiers.is_mutex)
+								|| (ref1->qualifiers.is_mutex == ref2->qualifiers.is_mutex ))) return;
+
+								if ( (widen.second && base1->qualifiers <= base2->qualifiers ) || (base2->qualifiers == base1->qualifiers) ) {
+
+									reset_qualifiers(base1);
+									reset_qualifiers(base2);
+
+									if ( !unifyExact(
+										base1, base2, tenv, need, have, open, noWiden() )
+									) return;
+								}
+							} else return;
+						} else if (auto ptr1 = dynamic_cast<const ast::PointerType *> (arg1)) {
+							if (auto ptr2 = dynamic_cast<const ast::PointerType *> (arg2)) {
+								ast::ptr<ast::Type> base1 = ptr1->base;
+								ast::ptr<ast::Type> base2 = ptr2->base;
+
+								// xxx - assume LHS is always the target type
+								// a function accepting const can always be called by non-const arg
+
+								if ( (widen.second && base1->qualifiers <= base2->qualifiers ) || (base2->qualifiers == base1->qualifiers) ) {
+
+									reset_qualifiers(base1);
+									reset_qualifiers(base2);
+
+									if ( ! unifyExact(
+										base1, base2, tenv, need, have, open, noWiden() )
+									) return;
+								}
+							} else return;
+						} else if (! unifyExact(
+								arg1, arg2, tenv, need, have, open, noWiden() )) {
+							return;
+						}
+						++crnt1; ++crnt2;
+					}
+					if ( crnt1 != end1 ) {
+						// try unifying empty tuple with ttype
+						const ast::Type * t1 = *crnt1;
+						if (! Tuples::isTtype( t1 ) ) return;
+						if (! unifyExact(
+							t1, tupleFromTypes( crnt2, end2 ), tenv, need, have, open,
+							noWiden() )) return;
+					} else if ( crnt2 != end2 ) {
+						// try unifying empty tuple with ttype
+						const ast::Type * t2 = *crnt2;
+						if ( !Tuples::isTtype( t2 ) ) return;
+						if ( !unifyExact(
+							tupleFromTypes( crnt1, end1 ), t2, tenv, need, have, open,
+							noWiden() )) return;
+					}
+					if ((f1->returns.size() == 0 && f2->returns.size() == 0)
+					  || (f1->returns.size() == 1 && f2->returns.size() == 1 && unifyExact(f1->returns[0], f2->returns[0], tenv, need, have, open, noWiden()))) {
+						result = pointer;
+
+						for (auto & assn : f1->assertions) {
+							auto i = need.find(assn);
+							if (i != need.end()) i->second.isUsed = true;
+							auto j = have.find(assn);
+							if (j != have.end()) j->second.isUsed = true;
+						}
+
+						for (auto & assn : f2->assertions) {
+							auto i = need.find(assn);
+							if (i != need.end()) i->second.isUsed = true;
+							auto j = have.find(assn);
+							if (j != have.end()) j->second.isUsed = true;
+						}
+					}
+				} // if ftype
+			}
+		} else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) {
+			result = pointer;
+			add_qualifiers( result, type2->qualifiers );
+		}
+	}
+
+	void postvisit( const ast::ArrayType * ) {}
+
+	void postvisit( const ast::ReferenceType * ref ) {
+		if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) {
+			if (
+				widen.first && ref2->base.as< ast::VoidType >() && ! ast::isFtype( ref->base )
+			) {
+				getCommonWithVoidPointer( ref2, ref );
+			} else if (
+				widen.second && ref->base.as< ast::VoidType>() && ! ast::isFtype( ref2->base )
+			) {
+				getCommonWithVoidPointer( ref, ref2 );
+			} else if (
+				( ref->base->qualifiers >= ref2->base->qualifiers || widen.first )
+				&& ( ref->base->qualifiers <= ref2->base->qualifiers || widen.second )
+			) {
+				ast::CV::Qualifiers q1 = ref->base->qualifiers, q2 = ref2->base->qualifiers;
+
+				// force t{1,2} to be cloned if their qualifiers must be stripped, so that
+				// ref{,2}->base are unchanged
+				ast::ptr< ast::Type > t1{ ref->base }, t2{ ref2->base };
+				reset_qualifiers( t1 );
+				reset_qualifiers( t2 );
+
+				ast::OpenVarSet newOpen{ open };
+				if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden() ) ) {
+					result = ref;
+					if ( q1.val != q2.val ) {
+						// reset result->base->qualifiers to be union of two base qualifiers
+						strict_dynamic_cast< ast::ReferenceType * >(
+							result.get_and_mutate()
+						)->base.get_and_mutate()->qualifiers = q1 | q2;
+					}
+				}
+			}
+		} else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) {
+			result = ref;
+			add_qualifiers( result, type2->qualifiers );
+		} else {
+			if (!dynamic_cast<const ast::EnumInstType *>(type2))
+				result = commonType( type2, ref, tenv, need, have, open, widen );
+		}
+	}
+
+	void postvisit( const ast::FunctionType * ) {}
+
+	void postvisit( const ast::StructInstType * ) {}
+
+	void postvisit( const ast::UnionInstType * ) {}
+
+	void postvisit( const ast::EnumInstType * enumInst ) {
+		if ( enumInst->base && !enumInst->base->isTyped ) {
+			auto basicType = new ast::BasicType( ast::BasicKind::UnsignedInt );
+			result = commonType( basicType, type2, tenv, need, have, open, widen);
+		}
+	}
+
+	void postvisit( const ast::EnumAttrType * ) {}
+
+	void postvisit( const ast::TraitInstType * ) {}
+
+	void postvisit( const ast::TypeInstType * ) {}
+
+	void postvisit( const ast::TupleType * ) {}
+
+	void postvisit( const ast::VarArgsType * ) {}
+
+	void postvisit( const ast::ZeroType * zero ) {
+		if ( !widen.first ) return;
+		if ( dynamic_cast< const ast::BasicType * >( type2 )
+				|| dynamic_cast< const ast::PointerType * >( type2 ) ) {
+			if ( widen.second || zero->qualifiers <= type2->qualifiers ) {
+				result = type2;
+				add_qualifiers( result, zero->qualifiers );
+			}
+		} else if ( widen.second && dynamic_cast< const ast::OneType * >( type2 ) ) {
+			result = new ast::BasicType{
+				ast::BasicKind::SignedInt, zero->qualifiers | type2->qualifiers };
+		} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
+			const ast::EnumDecl * enumDecl = enumInst->base;
+			if ( !enumDecl->base ) {
+				if ( widen.second || zero->qualifiers <= type2->qualifiers ) {
+					result = type2;
+					add_qualifiers( result, zero->qualifiers );
+				}
+			}
+		}
+	}
+
+	void postvisit( const ast::OneType * one ) {
+		if ( !widen.first ) return;
+		if ( dynamic_cast< const ast::BasicType * >( type2 ) ) {
+			if ( widen.second || one->qualifiers <= type2->qualifiers ) {
+				result = type2;
+				add_qualifiers( result, one->qualifiers );
+			}
+		} else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) {
+			result = new ast::BasicType{
+				ast::BasicKind::SignedInt, one->qualifiers | type2->qualifiers };
+		} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
+			const ast::EnumDecl * enumDecl = enumInst->base;
+			if ( !enumDecl->base ) {
+				if ( widen.second || one->qualifiers <= type2->qualifiers ) {
+					result = type2;
+					add_qualifiers( result, one->qualifiers );
+				}
+			}
+		}
+	}
+};
+
+// size_t CommonType::traceId = Stats::Heap::new_stacktrace_id("CommonType");
+
+ast::ptr< ast::Type > handleReference(
+	const ast::ptr< ast::Type > & t1, const ast::ptr< ast::Type > & t2, WidenMode widen,
+	ast::TypeEnvironment & env,
+	const ast::OpenVarSet & open
+) {
+	ast::ptr<ast::Type> common;
+	ast::AssertionSet have, need;
+	ast::OpenVarSet newOpen( open );
+
+	// need unify to bind type variables
+	if ( unify( t1, t2, env, have, need, newOpen, common ) ) {
+		ast::CV::Qualifiers q1 = t1->qualifiers, q2 = t2->qualifiers;
+		PRINT(
+			std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
+		)
+		if ( ( widen.first || q2 <= q1 ) && ( widen.second || q1 <= q2 ) ) {
+			PRINT(
+				std::cerr << "widen okay" << std::endl;
+			)
+			add_qualifiers( common, q1 | q2 );
+			return common;
+		}
+	}
+
+	PRINT(
+		std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;
+	)
+	return { nullptr };
+}
+
+} // namespace
+
+ast::ptr< ast::Type > commonType(
+	const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2,
+	ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
+	const ast::OpenVarSet & open, WidenMode widen
+) {
+	unsigned depth1 = type1->referenceDepth();
+	unsigned depth2 = type2->referenceDepth();
+
+	if ( depth1 != depth2 ) {  // implies depth1 > 0 || depth2 > 0
+		PRINT(
+			std::cerr << "reference depth diff: " << (depth1-depth2) << std::endl;
+		)
+		ast::ptr< ast::Type > result;
+		const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >();
+		const ast::ReferenceType * ref2 = type2.as< ast::ReferenceType >();
+
+		if ( depth1 > depth2 ) {
+			assert( ref1 );
+			result = handleReference( ref1->base, type2, widen, env, open );
+		} else {  // Implies depth1 < depth2
+			assert( ref2 );
+			result = handleReference( type1, ref2->base, widen, env, open );
+		}
+
+		if ( result && ref1 ) {
+			// formal is reference, so result should be reference
+			PRINT(
+				std::cerr << "formal is reference; result should be reference" << std::endl;
+			)
+			result = new ast::ReferenceType{ result, ref1->qualifiers };
+		}
+
+		PRINT(
+			std::cerr << "common type of reference [" << type1 << "] and [" << type2 << "] is "
+			"[" << result << "]" << std::endl;
+		)
+		return result;
+	}
+	// otherwise both are reference types of the same depth and this is handled by the visitor
+	return ast::Pass<CommonType>::read( type1.get(),
+		type2, widen, env, open, need, have );
+}
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/CommonType.hpp
===================================================================
--- src/ResolvExpr/CommonType.hpp	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ src/ResolvExpr/CommonType.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -18,5 +18,5 @@
 #include "AST/Fwd.hpp"
 #include "AST/TypeEnvironment.hpp"  // for AssertionSet, OpenVarSet
-#include "WidenMode.h"              // for WidenMode
+#include "WidenMode.hpp"            // for WidenMode
 
 namespace ResolvExpr {
Index: src/ResolvExpr/ConversionCost.cc
===================================================================
--- src/ResolvExpr/ConversionCost.cc	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,517 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// ConversionCost.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 07:06:19 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Jul 29 16:11:00 2020
-// Update Count     : 28
-//
-
-#include "ConversionCost.h"
-
-#include <cassert>                       // for assert
-#include <list>                          // for list, list<>::const_iterator
-#include <string>                        // for operator==, string
-
-#include "ResolvExpr/Cost.h"             // for Cost
-#include "ResolvExpr/Unify.h"            // for typesCompatibleIgnoreQualifiers
-#include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable
-
-namespace ResolvExpr {
-
-#if 0
-#define PRINT(x) x
-#else
-#define PRINT(x)
-#endif
-
-namespace {
-
-	// GENERATED START, DO NOT EDIT
-	// GENERATED BY BasicTypes-gen.cpp
-	/* EXTENDED INTEGRAL RANK HIERARCHY (root to leaves)
-	                         _Bool
-	char                signed char         unsigned char
-	          signed short int         unsigned short int
-	          signed int               unsigned int
-	          signed long int          unsigned long int
-	          signed long long int     unsigned long long int
-	          __int128                 unsigned __int128
-	          _Float16                 _Float16 _Complex
-	          _Float32                 _Float32 _Complex
-	          float                    float _Complex
-	          _Float32x                _Float32x _Complex
-	          _Float64                 _Float64 _Complex
-	          double                   double _Complex
-	          _Float64x                _Float64x _Complex
-	                     __float80
-	          _Float128                _Float128 _Complex
-	                    __float128
-	          long double              long double _Complex
-	          _Float128x               _Float128x _Complex
-	*/
-	// GENERATED END
-
-	// GENERATED START, DO NOT EDIT
-	// GENERATED BY BasicTypes-gen.cpp
-	static const int costMatrix[ast::BasicKind::NUMBER_OF_BASIC_TYPES][ast::BasicKind::NUMBER_OF_BASIC_TYPES] = { // path length from root to node
-		/*               B    C   SC   UC   SI  SUI    I   UI   LI  LUI  LLI LLUI   IB  UIB  _FH  _FH   _F  _FC    F   FC  _FX _FXC   FD _FDC    D   DC F80X_FDXC  F80  _FB_FLDC   FB   LD  LDC _FBX_FLDXC */
-		/*      B */ {   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  15,  16,  17,  16,  18,  17, },
-		/*      C */ {  -1,   0,   1,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  16,  15,  17,  16, },
-		/*     SC */ {  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  16,  15,  17,  16, },
-		/*     UC */ {  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  16,  15,  17,  16, },
-		/*     SI */ {  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  15,  14,  16,  15, },
-		/*    SUI */ {  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  15,  14,  16,  15, },
-		/*      I */ {  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  14,  13,  15,  14, },
-		/*     UI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  14,  13,  15,  14, },
-		/*     LI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  13,  12,  14,  13, },
-		/*    LUI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  13,  12,  14,  13, },
-		/*    LLI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  12,  11,  13,  12, },
-		/*   LLUI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  12,  11,  13,  12, },
-		/*     IB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  11,  10,  12,  11, },
-		/*    UIB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  11,  10,  12,  11, },
-		/*    _FH */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,  10,   9,  11,  10, },
-		/*    _FH */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   4,  -1,   5,  -1,   6,  -1,  -1,   7,  -1,  -1,   8,  -1,   9, },
-		/*     _F */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   9,   8,  10,   9, },
-		/*    _FC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   4,  -1,   5,  -1,  -1,   6,  -1,  -1,   7,  -1,   8, },
-		/*      F */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   8,   7,   9,   8, },
-		/*     FC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   4,  -1,  -1,   5,  -1,  -1,   6,  -1,   7, },
-		/*    _FX */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   7,   6,   8,   7, },
-		/*   _FXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,  -1,   4,  -1,  -1,   5,  -1,   6, },
-		/*     FD */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   6,   5,   7,   6, },
-		/*   _FDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,  -1,   3,  -1,  -1,   4,  -1,   5, },
-		/*      D */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   5,   4,   6,   5, },
-		/*     DC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,  -1,   2,  -1,  -1,   3,  -1,   4, },
-		/*   F80X */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   4,   3,   5,   4, },
-		/*  _FDXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   1,  -1,  -1,   2,  -1,   3, },
-		/*    F80 */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   1,   0,   1,   2,   2,   3,   3,   4,   4, },
-		/*    _FB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3, },
-		/*  _FLDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   1,  -1,   2, },
-		/*     FB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   1,   0,   1,   2,   2,   3, },
-		/*     LD */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2, },
-		/*    LDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1, },
-		/*   _FBX */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1, },
-		/* _FLDXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0, },
-	}; // costMatrix
-	static const int maxIntCost = 15;
-	// GENERATED END
-	static_assert(
-		sizeof(costMatrix)/sizeof(costMatrix[0][0]) == ast::BasicKind::NUMBER_OF_BASIC_TYPES * ast::BasicKind::NUMBER_OF_BASIC_TYPES,
-		"Missing row in the cost matrix"
-	);
-
-	// GENERATED START, DO NOT EDIT
-	// GENERATED BY BasicTypes-gen.cpp
-	static const int signMatrix[ast::BasicKind::NUMBER_OF_BASIC_TYPES][ast::BasicKind::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion
-		/*               B    C   SC   UC   SI  SUI    I   UI   LI  LUI  LLI LLUI   IB  UIB  _FH  _FH   _F  _FC    F   FC  _FX _FXC   FD _FDC    D   DC F80X_FDXC  F80  _FB_FLDC   FB   LD  LDC _FBX_FLDXC */
-		/*      B */ {   0,   0,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*      C */ {  -1,   0,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*     SC */ {  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*     UC */ {  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*     SI */ {  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*    SUI */ {  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*      I */ {  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*     UI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*     LI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*    LUI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*    LLI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*   LLUI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*     IB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*    UIB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*    _FH */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*    _FH */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
-		/*     _F */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*    _FC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
-		/*      F */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*     FC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
-		/*    _FX */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*   _FXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
-		/*     FD */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*   _FDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
-		/*      D */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*     DC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
-		/*   F80X */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*  _FDXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
-		/*    F80 */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
-		/*    _FB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0, },
-		/*  _FLDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
-		/*     FB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0, },
-		/*     LD */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0, },
-		/*    LDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0, },
-		/*   _FBX */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0, },
-		/* _FLDXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0, },
-	}; // signMatrix
-	// GENERATED END
-	static_assert(
-		sizeof(signMatrix)/sizeof(signMatrix[0][0]) == ast::BasicKind::NUMBER_OF_BASIC_TYPES * ast::BasicKind::NUMBER_OF_BASIC_TYPES,
-		"Missing row in the sign matrix"
-	);
-
-	int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
-			const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
-		return ptrsAssignable( t1, t2, env );
-	}
-}
-
-Cost conversionCost(
-	const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
-	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
-) {
-	if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
-		if ( const ast::EqvClass * eqv = env.lookup( *inst ) ) {
-			if ( eqv->bound ) {
-				return conversionCost(src, eqv->bound, srcIsLvalue, symtab, env );
-			} else {
-				return Cost::infinity;
-			}
-		} else if ( const ast::NamedTypeDecl * named = symtab.lookupType( inst->name ) ) {
-			const ast::TypeDecl * type = dynamic_cast< const ast::TypeDecl * >( named );
-			assertf( type, "Unexpected typedef." );
-			if ( type->base ) {
-				return conversionCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
-			}
-		}
-	}
-	if ( typesCompatibleIgnoreQualifiers( src, dst, env ) ) {
-		return Cost::zero;
-	} else if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
-		return Cost::safe;
-	} else if ( const ast::ReferenceType * refType =
-			 dynamic_cast< const ast::ReferenceType * >( dst ) ) {
-		return convertToReferenceCost( src, refType, srcIsLvalue, symtab, env, localPtrsAssignable );
-	} else {
-		return ast::Pass<ConversionCost>::read( src, dst, srcIsLvalue, symtab, env, conversionCost );
-	}
-}
-
-static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
-		int diff, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
-		PtrsCalculation func ) {
-	if ( 0 < diff ) {
-		Cost cost = convertToReferenceCost(
-			strict_dynamic_cast< const ast::ReferenceType * >( src )->base, dst,
-			srcIsLvalue, (diff - 1), symtab, env, func );
-		cost.incReference();
-		return cost;
-	} else if ( diff < -1 ) {
-		Cost cost = convertToReferenceCost(
-			src, strict_dynamic_cast< const ast::ReferenceType * >( dst )->base,
-			srcIsLvalue, (diff + 1), symtab, env, func );
-		cost.incReference();
-		return cost;
-	} else if ( 0 == diff ) {
-		const ast::ReferenceType * srcAsRef = dynamic_cast< const ast::ReferenceType * >( src );
-		const ast::ReferenceType * dstAsRef = dynamic_cast< const ast::ReferenceType * >( dst );
-		if ( srcAsRef && dstAsRef ) {
-			ast::CV::Qualifiers tq1 = srcAsRef->base->qualifiers;
-			ast::CV::Qualifiers tq2 = dstAsRef->base->qualifiers;
-			if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers(
-					srcAsRef->base, dstAsRef->base, env ) ) {
-				if ( tq1 == tq2 ) {
-					return Cost::zero;
-				} else {
-					return Cost::safe;
-				}
-			} else {
-				int assignResult = func( srcAsRef->base, dstAsRef->base, symtab, env );
-				if ( 0 < assignResult ) {
-					return Cost::safe;
-				} else if ( assignResult < 0 ) {
-					return Cost::unsafe;
-				}
-			}
-		} else {
-			return ast::Pass<ConversionCost>::read( src, dst, srcIsLvalue, symtab, env, conversionCost );
-		}
-	} else {
-		assert( -1 == diff );
-		const ast::ReferenceType * dstAsRef = dynamic_cast< const ast::ReferenceType * >( dst );
-		assert( dstAsRef );
-		if ( typesCompatibleIgnoreQualifiers( src, dstAsRef->base, env ) ) {
-			if ( srcIsLvalue ) {
-				if ( src->qualifiers == dstAsRef->base->qualifiers ) {
-					return Cost::reference;
-				} else if ( src->qualifiers < dstAsRef->base->qualifiers ) {
-					return Cost::safe;
-				} else {
-					return Cost::unsafe;
-				}
-			} else if ( dstAsRef->base->is_const() ) {
-				return Cost::safe;
-			} else {
-				return Cost::unsafe;
-			}
-		}
-	}
-	return Cost::infinity;
-}
-
-Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dst,
-		bool srcIsLvalue, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
-		PtrsCalculation func ) {
-	int sdepth = src->referenceDepth(), ddepth = dst->referenceDepth();
-	return convertToReferenceCost( src, dst, srcIsLvalue, sdepth - ddepth, symtab, env, func );
-}
-
-void ConversionCost::postvisit( const ast::VoidType * voidType ) {
-	(void)voidType;
-	cost = Cost::infinity;
-}
-
-void ConversionCost::conversionCostFromBasicToBasic( const ast::BasicType * src, const ast::BasicType* dest ) {
-	int tableResult = costMatrix[ src->kind ][ dest->kind ];
-	if ( tableResult == -1 ) {
-		cost = Cost::unsafe;
-	} else {
-		cost = Cost::zero;
-		cost.incSafe( tableResult );
-		cost.incSign( signMatrix[ src->kind ][ dest->kind ] );
-	}
-}
-
-void ConversionCost::postvisit( const ast::BasicType * basicType ) {
-	if ( const ast::BasicType * dstAsBasic = dynamic_cast< const ast::BasicType * >( dst ) ) {
-		conversionCostFromBasicToBasic( basicType, dstAsBasic );
-	} else if ( dynamic_cast< const ast::EnumAttrType *>(dst) ) {
-		static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicKind::SignedInt ) };
-		cost = costCalc( basicType, integer, srcIsLvalue, symtab, env );
-	} else if ( auto dstAsEnumInst = dynamic_cast< const ast::EnumInstType * >( dst ) ) {
-		if ( dstAsEnumInst->base && !dstAsEnumInst->base->isTyped ) {
-			cost = Cost::unsafe;
-		}
-	}
-}
-
-void ConversionCost::postvisit( const ast::PointerType * pointerType ) {
-	if ( const ast::PointerType * dstAsPtr = dynamic_cast< const ast::PointerType * >( dst ) ) {
-		ast::CV::Qualifiers tq1 = pointerType->base->qualifiers;
-		ast::CV::Qualifiers tq2 = dstAsPtr->base->qualifiers;
-		if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers(
-				pointerType->base, dstAsPtr->base, env ) ) {
-			if ( tq1 == tq2 ) {
-				cost = Cost::zero;
-			} else {
-				cost = Cost::safe;
-			}
-		}
-		/*
-		else if ( const ast::FunctionType * dstFunc = dstAsPtr->base.as<ast::FunctionType>()) {
-			if (const ast::FunctionType * srcFunc = pointerType->base.as<ast::FunctionType>()) {
-				if (dstFunc->params.empty() && dstFunc->isVarArgs ) {
-					cost = Cost::unsafe; // assign any function to variadic fptr
-				}
-			}
-			else {
-				ast::AssertionSet need, have; // unused
-				ast::OpenVarSet open;
-				env.extractOpenVars(open);
-				ast::TypeEnvironment tenv = env;
-				if ( unify(dstAsPtr->base, pointerType->base, tenv, need, have, open, symtab) ) {
-					cost = Cost::safe;
-				}
-			}
-			// else infinity
-		}
-		*/
-		else {
-			int assignResult = ptrsAssignable( pointerType->base, dstAsPtr->base, env );
-			if ( 0 < assignResult && tq1 <= tq2 ) {
-				if ( tq1 == tq2 ) {
-					cost = Cost::safe;
-				} else {
-					cost = Cost::safe + Cost::safe;
-				}
-			} else if ( assignResult < 0 ) {
-				cost = Cost::unsafe;
-			} // else Cost::infinity
-		}
-	}
-}
-
-void ConversionCost::postvisit( const ast::ArrayType * arrayType ) {
-	(void)arrayType;
-}
-
-void ConversionCost::postvisit( const ast::ReferenceType * refType ) {
-	assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) );
-
-	cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env );
-
-	// xxx - should qualifiers be considered in pass-by-value?
-	/*
-	if ( refType->base->qualifiers == dst->qualifiers ) {
-		cost.incReference();
-	} else if ( refType->base->qualifiers < dst->qualifiers ) {
-		cost.incSafe();
-	} else {
-		cost.incUnsafe();
-	}
-	*/
-	cost.incReference();
-}
-
-void ConversionCost::postvisit( const ast::FunctionType * functionType ) {
-	(void)functionType;
-}
-
-void ConversionCost::postvisit( const ast::EnumInstType * inst ) {
-	if ( auto dstAsInst = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
-		if (inst->base && dstAsInst->base) {
-			if (inst->base->name == dstAsInst->base->name) {
-				cost = Cost::zero;
-				return;
-			}
-		}
-		return;
-	}
-	static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicKind::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);
-	assert( src->attr != ast::EnumAttribute::Label );
-	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::BasicKind::SignedInt ) };
-			cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
-			if ( cost < Cost::unsafe ) {
-				cost.incSafe();
-			}
-		}
-	}
-}
-
-void ConversionCost::postvisit( const ast::TraitInstType * traitInstType ) {
-	(void)traitInstType;
-}
-
-void ConversionCost::postvisit( const ast::TypeInstType * typeInstType ) {
-	if ( const ast::EqvClass * eqv = env.lookup( *typeInstType ) ) {
-		cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env );
-	} else if ( const ast::TypeInstType * dstAsInst =
-			dynamic_cast< const ast::TypeInstType * >( dst ) ) {
-		if ( *typeInstType == *dstAsInst ) {
-			cost = Cost::zero;
-		}
-	} else if ( const ast::NamedTypeDecl * namedType = symtab.lookupType( typeInstType->name ) ) {
-		const ast::TypeDecl * type = dynamic_cast< const ast::TypeDecl * >( namedType );
-		assertf( type, "Unexpected typedef.");
-		if ( type->base ) {
-			cost = costCalc( type->base, dst, srcIsLvalue, symtab, env ) + Cost::safe;
-		}
-	}
-}
-
-void ConversionCost::postvisit( const ast::TupleType * tupleType ) {
-	Cost c = Cost::zero;
-	if ( const ast::TupleType * dstAsTuple = dynamic_cast< const ast::TupleType * >( dst ) ) {
-		auto srcIt = tupleType->types.begin();
-		auto dstIt = dstAsTuple->types.begin();
-		auto srcEnd = tupleType->types.end();
-		auto dstEnd = dstAsTuple->types.end();
-		while ( srcIt != srcEnd && dstIt != dstEnd ) {
-			Cost newCost = costCalc( * srcIt++, * dstIt++, srcIsLvalue, symtab, env );
-			if ( newCost == Cost::infinity ) {
-				return;
-			}
-			c += newCost;
-		}
-		if ( dstIt != dstEnd ) {
-			cost = Cost::infinity;
-		} else {
-			cost = c;
-		}
-	}
-}
-
-void ConversionCost::postvisit( const ast::VarArgsType * varArgsType ) {
-	(void)varArgsType;
-	if ( dynamic_cast< const ast::VarArgsType * >( dst ) ) {
-		cost = Cost::zero;
-	}
-}
-
-void ConversionCost::postvisit( const ast::ZeroType * zeroType ) {
-	(void)zeroType;
-	if ( dynamic_cast< const ast::ZeroType * >( dst ) ) {
-		cost = Cost::zero;
-	} else if ( const ast::BasicType * dstAsBasic =
-			dynamic_cast< const ast::BasicType * >( dst ) ) {
-		int tableResult = costMatrix[ ast::BasicKind::SignedInt ][ dstAsBasic->kind ];
-		if ( -1 == tableResult ) {
-			cost = Cost::unsafe;
-		} else {
-			cost = Cost::zero;
-			cost.incSafe( tableResult + 1 );
-			cost.incSign( signMatrix[ ast::BasicKind::SignedInt ][ dstAsBasic->kind ] );
-		}
-		// this has the effect of letting any expr such as x+0, x+1 to be typed
-		// the same as x, instead of at least int. are we willing to sacrifice this little
-		// bit of coherence with C?
-		// TODO: currently this does not work when no zero/one overloads exist. Find a fix for it.
-		// cost = Cost::zero;
-	} else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
-		cost = Cost::zero;
-		// +1 for zero_t ->, +1 for disambiguation
-		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->isTyped ) {
-			cost = Cost::unsafe;
-		}
-	}
-}
-
-void ConversionCost::postvisit( const ast::OneType * oneType ) {
-	(void)oneType;
-	if ( dynamic_cast< const ast::OneType * >( dst ) ) {
-		cost = Cost::zero;
-	} else if ( const ast::BasicType * dstAsBasic =
-			dynamic_cast< const ast::BasicType * >( dst ) ) {
-		int tableResult = costMatrix[ ast::BasicKind::SignedInt ][ dstAsBasic->kind ];
-		if ( -1 == tableResult ) {
-			cost = Cost::unsafe;
-		} else {
-			cost = Cost::zero;
-			cost.incSafe( tableResult + 1 );
-			cost.incSign( signMatrix[ ast::BasicKind::SignedInt ][ dstAsBasic->kind ] );
-		}
-	} else if ( auto dstAsEnumInst = dynamic_cast< const ast::EnumInstType * >( dst ) ) {
-		if ( dstAsEnumInst->base && !dstAsEnumInst->base->isTyped ) {
-			cost = Cost::unsafe;
-		}
-	}
-}
-
-// size_t ConversionCost::traceId = Stats::Heap::new_stacktrace_id("ConversionCost");
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/ConversionCost.cpp
===================================================================
--- src/ResolvExpr/ConversionCost.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/ConversionCost.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,517 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ConversionCost.cpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 07:06:19 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jul 29 16:11:00 2020
+// Update Count     : 28
+//
+
+#include "ConversionCost.hpp"
+
+#include <cassert>                       // for assert
+#include <list>                          // for list, list<>::const_iterator
+#include <string>                        // for operator==, string
+
+#include "ResolvExpr/Cost.hpp"           // for Cost
+#include "ResolvExpr/Unify.hpp"          // for typesCompatibleIgnoreQualifiers
+#include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable
+
+namespace ResolvExpr {
+
+#if 0
+#define PRINT(x) x
+#else
+#define PRINT(x)
+#endif
+
+namespace {
+
+	// GENERATED START, DO NOT EDIT
+	// GENERATED BY BasicTypes-gen.cpp
+	/* EXTENDED INTEGRAL RANK HIERARCHY (root to leaves)
+	                         _Bool
+	char                signed char         unsigned char
+	          signed short int         unsigned short int
+	          signed int               unsigned int
+	          signed long int          unsigned long int
+	          signed long long int     unsigned long long int
+	          __int128                 unsigned __int128
+	          _Float16                 _Float16 _Complex
+	          _Float32                 _Float32 _Complex
+	          float                    float _Complex
+	          _Float32x                _Float32x _Complex
+	          _Float64                 _Float64 _Complex
+	          double                   double _Complex
+	          _Float64x                _Float64x _Complex
+	                     __float80
+	          _Float128                _Float128 _Complex
+	                    __float128
+	          long double              long double _Complex
+	          _Float128x               _Float128x _Complex
+	*/
+	// GENERATED END
+
+	// GENERATED START, DO NOT EDIT
+	// GENERATED BY BasicTypes-gen.cpp
+	static const int costMatrix[ast::BasicKind::NUMBER_OF_BASIC_TYPES][ast::BasicKind::NUMBER_OF_BASIC_TYPES] = { // path length from root to node
+		/*               B    C   SC   UC   SI  SUI    I   UI   LI  LUI  LLI LLUI   IB  UIB  _FH  _FH   _F  _FC    F   FC  _FX _FXC   FD _FDC    D   DC F80X_FDXC  F80  _FB_FLDC   FB   LD  LDC _FBX_FLDXC */
+		/*      B */ {   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  15,  16,  17,  16,  18,  17, },
+		/*      C */ {  -1,   0,   1,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  16,  15,  17,  16, },
+		/*     SC */ {  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  16,  15,  17,  16, },
+		/*     UC */ {  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  16,  15,  17,  16, },
+		/*     SI */ {  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  15,  14,  16,  15, },
+		/*    SUI */ {  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  15,  14,  16,  15, },
+		/*      I */ {  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  14,  13,  15,  14, },
+		/*     UI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  14,  13,  15,  14, },
+		/*     LI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  13,  12,  14,  13, },
+		/*    LUI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  13,  12,  14,  13, },
+		/*    LLI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  12,  11,  13,  12, },
+		/*   LLUI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  12,  11,  13,  12, },
+		/*     IB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  11,  10,  12,  11, },
+		/*    UIB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  11,  10,  12,  11, },
+		/*    _FH */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,  10,   9,  11,  10, },
+		/*    _FH */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   4,  -1,   5,  -1,   6,  -1,  -1,   7,  -1,  -1,   8,  -1,   9, },
+		/*     _F */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   9,   8,  10,   9, },
+		/*    _FC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   4,  -1,   5,  -1,  -1,   6,  -1,  -1,   7,  -1,   8, },
+		/*      F */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   8,   7,   9,   8, },
+		/*     FC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   4,  -1,  -1,   5,  -1,  -1,   6,  -1,   7, },
+		/*    _FX */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   7,   6,   8,   7, },
+		/*   _FXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,  -1,   4,  -1,  -1,   5,  -1,   6, },
+		/*     FD */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   6,   5,   7,   6, },
+		/*   _FDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,  -1,   3,  -1,  -1,   4,  -1,   5, },
+		/*      D */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   5,   4,   6,   5, },
+		/*     DC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,  -1,   2,  -1,  -1,   3,  -1,   4, },
+		/*   F80X */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   4,   3,   5,   4, },
+		/*  _FDXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   1,  -1,  -1,   2,  -1,   3, },
+		/*    F80 */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   1,   0,   1,   2,   2,   3,   3,   4,   4, },
+		/*    _FB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3, },
+		/*  _FLDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   1,  -1,   2, },
+		/*     FB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   1,   0,   1,   2,   2,   3, },
+		/*     LD */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2, },
+		/*    LDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1, },
+		/*   _FBX */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1, },
+		/* _FLDXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0, },
+	}; // costMatrix
+	static const int maxIntCost = 15;
+	// GENERATED END
+	static_assert(
+		sizeof(costMatrix)/sizeof(costMatrix[0][0]) == ast::BasicKind::NUMBER_OF_BASIC_TYPES * ast::BasicKind::NUMBER_OF_BASIC_TYPES,
+		"Missing row in the cost matrix"
+	);
+
+	// GENERATED START, DO NOT EDIT
+	// GENERATED BY BasicTypes-gen.cpp
+	static const int signMatrix[ast::BasicKind::NUMBER_OF_BASIC_TYPES][ast::BasicKind::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion
+		/*               B    C   SC   UC   SI  SUI    I   UI   LI  LUI  LLI LLUI   IB  UIB  _FH  _FH   _F  _FC    F   FC  _FX _FXC   FD _FDC    D   DC F80X_FDXC  F80  _FB_FLDC   FB   LD  LDC _FBX_FLDXC */
+		/*      B */ {   0,   0,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*      C */ {  -1,   0,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*     SC */ {  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*     UC */ {  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*     SI */ {  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*    SUI */ {  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*      I */ {  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*     UI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*     LI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*    LUI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*    LLI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*   LLUI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*     IB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*    UIB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*    _FH */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*    _FH */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
+		/*     _F */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*    _FC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
+		/*      F */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*     FC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
+		/*    _FX */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*   _FXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
+		/*     FD */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*   _FDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
+		/*      D */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*     DC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
+		/*   F80X */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*  _FDXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
+		/*    F80 */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
+		/*    _FB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0, },
+		/*  _FLDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
+		/*     FB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0, },
+		/*     LD */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0, },
+		/*    LDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0, },
+		/*   _FBX */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0, },
+		/* _FLDXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0, },
+	}; // signMatrix
+	// GENERATED END
+	static_assert(
+		sizeof(signMatrix)/sizeof(signMatrix[0][0]) == ast::BasicKind::NUMBER_OF_BASIC_TYPES * ast::BasicKind::NUMBER_OF_BASIC_TYPES,
+		"Missing row in the sign matrix"
+	);
+
+	int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
+			const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
+		return ptrsAssignable( t1, t2, env );
+	}
+}
+
+Cost conversionCost(
+	const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
+	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
+) {
+	if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
+		if ( const ast::EqvClass * eqv = env.lookup( *inst ) ) {
+			if ( eqv->bound ) {
+				return conversionCost(src, eqv->bound, srcIsLvalue, symtab, env );
+			} else {
+				return Cost::infinity;
+			}
+		} else if ( const ast::NamedTypeDecl * named = symtab.lookupType( inst->name ) ) {
+			const ast::TypeDecl * type = dynamic_cast< const ast::TypeDecl * >( named );
+			assertf( type, "Unexpected typedef." );
+			if ( type->base ) {
+				return conversionCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
+			}
+		}
+	}
+	if ( typesCompatibleIgnoreQualifiers( src, dst, env ) ) {
+		return Cost::zero;
+	} else if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
+		return Cost::safe;
+	} else if ( const ast::ReferenceType * refType =
+			 dynamic_cast< const ast::ReferenceType * >( dst ) ) {
+		return convertToReferenceCost( src, refType, srcIsLvalue, symtab, env, localPtrsAssignable );
+	} else {
+		return ast::Pass<ConversionCost>::read( src, dst, srcIsLvalue, symtab, env, conversionCost );
+	}
+}
+
+static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
+		int diff, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
+		PtrsCalculation func ) {
+	if ( 0 < diff ) {
+		Cost cost = convertToReferenceCost(
+			strict_dynamic_cast< const ast::ReferenceType * >( src )->base, dst,
+			srcIsLvalue, (diff - 1), symtab, env, func );
+		cost.incReference();
+		return cost;
+	} else if ( diff < -1 ) {
+		Cost cost = convertToReferenceCost(
+			src, strict_dynamic_cast< const ast::ReferenceType * >( dst )->base,
+			srcIsLvalue, (diff + 1), symtab, env, func );
+		cost.incReference();
+		return cost;
+	} else if ( 0 == diff ) {
+		const ast::ReferenceType * srcAsRef = dynamic_cast< const ast::ReferenceType * >( src );
+		const ast::ReferenceType * dstAsRef = dynamic_cast< const ast::ReferenceType * >( dst );
+		if ( srcAsRef && dstAsRef ) {
+			ast::CV::Qualifiers tq1 = srcAsRef->base->qualifiers;
+			ast::CV::Qualifiers tq2 = dstAsRef->base->qualifiers;
+			if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers(
+					srcAsRef->base, dstAsRef->base, env ) ) {
+				if ( tq1 == tq2 ) {
+					return Cost::zero;
+				} else {
+					return Cost::safe;
+				}
+			} else {
+				int assignResult = func( srcAsRef->base, dstAsRef->base, symtab, env );
+				if ( 0 < assignResult ) {
+					return Cost::safe;
+				} else if ( assignResult < 0 ) {
+					return Cost::unsafe;
+				}
+			}
+		} else {
+			return ast::Pass<ConversionCost>::read( src, dst, srcIsLvalue, symtab, env, conversionCost );
+		}
+	} else {
+		assert( -1 == diff );
+		const ast::ReferenceType * dstAsRef = dynamic_cast< const ast::ReferenceType * >( dst );
+		assert( dstAsRef );
+		if ( typesCompatibleIgnoreQualifiers( src, dstAsRef->base, env ) ) {
+			if ( srcIsLvalue ) {
+				if ( src->qualifiers == dstAsRef->base->qualifiers ) {
+					return Cost::reference;
+				} else if ( src->qualifiers < dstAsRef->base->qualifiers ) {
+					return Cost::safe;
+				} else {
+					return Cost::unsafe;
+				}
+			} else if ( dstAsRef->base->is_const() ) {
+				return Cost::safe;
+			} else {
+				return Cost::unsafe;
+			}
+		}
+	}
+	return Cost::infinity;
+}
+
+Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dst,
+		bool srcIsLvalue, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
+		PtrsCalculation func ) {
+	int sdepth = src->referenceDepth(), ddepth = dst->referenceDepth();
+	return convertToReferenceCost( src, dst, srcIsLvalue, sdepth - ddepth, symtab, env, func );
+}
+
+void ConversionCost::postvisit( const ast::VoidType * voidType ) {
+	(void)voidType;
+	cost = Cost::infinity;
+}
+
+void ConversionCost::conversionCostFromBasicToBasic( const ast::BasicType * src, const ast::BasicType* dest ) {
+	int tableResult = costMatrix[ src->kind ][ dest->kind ];
+	if ( tableResult == -1 ) {
+		cost = Cost::unsafe;
+	} else {
+		cost = Cost::zero;
+		cost.incSafe( tableResult );
+		cost.incSign( signMatrix[ src->kind ][ dest->kind ] );
+	}
+}
+
+void ConversionCost::postvisit( const ast::BasicType * basicType ) {
+	if ( const ast::BasicType * dstAsBasic = dynamic_cast< const ast::BasicType * >( dst ) ) {
+		conversionCostFromBasicToBasic( basicType, dstAsBasic );
+	} else if ( dynamic_cast< const ast::EnumAttrType *>(dst) ) {
+		static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicKind::SignedInt ) };
+		cost = costCalc( basicType, integer, srcIsLvalue, symtab, env );
+	} else if ( auto dstAsEnumInst = dynamic_cast< const ast::EnumInstType * >( dst ) ) {
+		if ( dstAsEnumInst->base && !dstAsEnumInst->base->isTyped ) {
+			cost = Cost::unsafe;
+		}
+	}
+}
+
+void ConversionCost::postvisit( const ast::PointerType * pointerType ) {
+	if ( const ast::PointerType * dstAsPtr = dynamic_cast< const ast::PointerType * >( dst ) ) {
+		ast::CV::Qualifiers tq1 = pointerType->base->qualifiers;
+		ast::CV::Qualifiers tq2 = dstAsPtr->base->qualifiers;
+		if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers(
+				pointerType->base, dstAsPtr->base, env ) ) {
+			if ( tq1 == tq2 ) {
+				cost = Cost::zero;
+			} else {
+				cost = Cost::safe;
+			}
+		}
+		/*
+		else if ( const ast::FunctionType * dstFunc = dstAsPtr->base.as<ast::FunctionType>()) {
+			if (const ast::FunctionType * srcFunc = pointerType->base.as<ast::FunctionType>()) {
+				if (dstFunc->params.empty() && dstFunc->isVarArgs ) {
+					cost = Cost::unsafe; // assign any function to variadic fptr
+				}
+			}
+			else {
+				ast::AssertionSet need, have; // unused
+				ast::OpenVarSet open;
+				env.extractOpenVars(open);
+				ast::TypeEnvironment tenv = env;
+				if ( unify(dstAsPtr->base, pointerType->base, tenv, need, have, open, symtab) ) {
+					cost = Cost::safe;
+				}
+			}
+			// else infinity
+		}
+		*/
+		else {
+			int assignResult = ptrsAssignable( pointerType->base, dstAsPtr->base, env );
+			if ( 0 < assignResult && tq1 <= tq2 ) {
+				if ( tq1 == tq2 ) {
+					cost = Cost::safe;
+				} else {
+					cost = Cost::safe + Cost::safe;
+				}
+			} else if ( assignResult < 0 ) {
+				cost = Cost::unsafe;
+			} // else Cost::infinity
+		}
+	}
+}
+
+void ConversionCost::postvisit( const ast::ArrayType * arrayType ) {
+	(void)arrayType;
+}
+
+void ConversionCost::postvisit( const ast::ReferenceType * refType ) {
+	assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) );
+
+	cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env );
+
+	// xxx - should qualifiers be considered in pass-by-value?
+	/*
+	if ( refType->base->qualifiers == dst->qualifiers ) {
+		cost.incReference();
+	} else if ( refType->base->qualifiers < dst->qualifiers ) {
+		cost.incSafe();
+	} else {
+		cost.incUnsafe();
+	}
+	*/
+	cost.incReference();
+}
+
+void ConversionCost::postvisit( const ast::FunctionType * functionType ) {
+	(void)functionType;
+}
+
+void ConversionCost::postvisit( const ast::EnumInstType * inst ) {
+	if ( auto dstAsInst = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
+		if (inst->base && dstAsInst->base) {
+			if (inst->base->name == dstAsInst->base->name) {
+				cost = Cost::zero;
+				return;
+			}
+		}
+		return;
+	}
+	static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicKind::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);
+	assert( src->attr != ast::EnumAttribute::Label );
+	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::BasicKind::SignedInt ) };
+			cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
+			if ( cost < Cost::unsafe ) {
+				cost.incSafe();
+			}
+		}
+	}
+}
+
+void ConversionCost::postvisit( const ast::TraitInstType * traitInstType ) {
+	(void)traitInstType;
+}
+
+void ConversionCost::postvisit( const ast::TypeInstType * typeInstType ) {
+	if ( const ast::EqvClass * eqv = env.lookup( *typeInstType ) ) {
+		cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env );
+	} else if ( const ast::TypeInstType * dstAsInst =
+			dynamic_cast< const ast::TypeInstType * >( dst ) ) {
+		if ( *typeInstType == *dstAsInst ) {
+			cost = Cost::zero;
+		}
+	} else if ( const ast::NamedTypeDecl * namedType = symtab.lookupType( typeInstType->name ) ) {
+		const ast::TypeDecl * type = dynamic_cast< const ast::TypeDecl * >( namedType );
+		assertf( type, "Unexpected typedef.");
+		if ( type->base ) {
+			cost = costCalc( type->base, dst, srcIsLvalue, symtab, env ) + Cost::safe;
+		}
+	}
+}
+
+void ConversionCost::postvisit( const ast::TupleType * tupleType ) {
+	Cost c = Cost::zero;
+	if ( const ast::TupleType * dstAsTuple = dynamic_cast< const ast::TupleType * >( dst ) ) {
+		auto srcIt = tupleType->types.begin();
+		auto dstIt = dstAsTuple->types.begin();
+		auto srcEnd = tupleType->types.end();
+		auto dstEnd = dstAsTuple->types.end();
+		while ( srcIt != srcEnd && dstIt != dstEnd ) {
+			Cost newCost = costCalc( * srcIt++, * dstIt++, srcIsLvalue, symtab, env );
+			if ( newCost == Cost::infinity ) {
+				return;
+			}
+			c += newCost;
+		}
+		if ( dstIt != dstEnd ) {
+			cost = Cost::infinity;
+		} else {
+			cost = c;
+		}
+	}
+}
+
+void ConversionCost::postvisit( const ast::VarArgsType * varArgsType ) {
+	(void)varArgsType;
+	if ( dynamic_cast< const ast::VarArgsType * >( dst ) ) {
+		cost = Cost::zero;
+	}
+}
+
+void ConversionCost::postvisit( const ast::ZeroType * zeroType ) {
+	(void)zeroType;
+	if ( dynamic_cast< const ast::ZeroType * >( dst ) ) {
+		cost = Cost::zero;
+	} else if ( const ast::BasicType * dstAsBasic =
+			dynamic_cast< const ast::BasicType * >( dst ) ) {
+		int tableResult = costMatrix[ ast::BasicKind::SignedInt ][ dstAsBasic->kind ];
+		if ( -1 == tableResult ) {
+			cost = Cost::unsafe;
+		} else {
+			cost = Cost::zero;
+			cost.incSafe( tableResult + 1 );
+			cost.incSign( signMatrix[ ast::BasicKind::SignedInt ][ dstAsBasic->kind ] );
+		}
+		// this has the effect of letting any expr such as x+0, x+1 to be typed
+		// the same as x, instead of at least int. are we willing to sacrifice this little
+		// bit of coherence with C?
+		// TODO: currently this does not work when no zero/one overloads exist. Find a fix for it.
+		// cost = Cost::zero;
+	} else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
+		cost = Cost::zero;
+		// +1 for zero_t ->, +1 for disambiguation
+		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->isTyped ) {
+			cost = Cost::unsafe;
+		}
+	}
+}
+
+void ConversionCost::postvisit( const ast::OneType * oneType ) {
+	(void)oneType;
+	if ( dynamic_cast< const ast::OneType * >( dst ) ) {
+		cost = Cost::zero;
+	} else if ( const ast::BasicType * dstAsBasic =
+			dynamic_cast< const ast::BasicType * >( dst ) ) {
+		int tableResult = costMatrix[ ast::BasicKind::SignedInt ][ dstAsBasic->kind ];
+		if ( -1 == tableResult ) {
+			cost = Cost::unsafe;
+		} else {
+			cost = Cost::zero;
+			cost.incSafe( tableResult + 1 );
+			cost.incSign( signMatrix[ ast::BasicKind::SignedInt ][ dstAsBasic->kind ] );
+		}
+	} else if ( auto dstAsEnumInst = dynamic_cast< const ast::EnumInstType * >( dst ) ) {
+		if ( dstAsEnumInst->base && !dstAsEnumInst->base->isTyped ) {
+			cost = Cost::unsafe;
+		}
+	}
+}
+
+// size_t ConversionCost::traceId = Stats::Heap::new_stacktrace_id("ConversionCost");
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/ConversionCost.h
===================================================================
--- src/ResolvExpr/ConversionCost.h	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,86 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// ConversionCost.h --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 09:37:28 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Jul 29 16:12:00 2020
-// Update Count     : 7
-//
-
-#pragma once
-
-#include <functional>         // for function
-
-#include "Cost.h"             // for Cost
-
-#include "AST/Fwd.hpp"
-#include "AST/Pass.hpp"       // for WithShortCircuiting
-
-namespace ResolvExpr {
-
-// Some function pointer types, differ in return type.
-using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *, bool,
-	const ast::SymbolTable &, const ast::TypeEnvironment &)>;
-using PtrsCalculation = std::function<int(const ast::Type *, const ast::Type *,
-	const ast::SymbolTable &, const ast::TypeEnvironment &)>;
-
-Cost conversionCost(
-	const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
-	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
-
-Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dest,
-	bool srcIsLvalue, const ast::SymbolTable & indexer, const ast::TypeEnvironment & env,
-	PtrsCalculation func );
-
-class ConversionCost : public ast::WithShortCircuiting {
-protected:
-	const ast::Type * dst;
-	bool srcIsLvalue;
-	const ast::SymbolTable & symtab;
-	const ast::TypeEnvironment & env;
-	CostCalculation costCalc;
-public:
-	static size_t traceId;
-	Cost cost;
-	Cost result() { return cost; }
-
-	ConversionCost( const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
-			const ast::TypeEnvironment & env, CostCalculation costCalc ) :
-		dst( dst ), srcIsLvalue( srcIsLvalue ), symtab( symtab ), env( env ),
-		costCalc( costCalc ), cost( Cost::infinity )
-	{}
-
-	void previsit( const ast::Node * ) { visit_children = false; }
-
-	void postvisit( const ast::VoidType * voidType );
-	void postvisit( const ast::BasicType * basicType );
-	void postvisit( const ast::PointerType * pointerType );
-	void postvisit( const ast::ArrayType * arrayType );
-	void postvisit( const ast::ReferenceType * refType );
-	void postvisit( const ast::FunctionType * functionType );
-	void postvisit( const ast::EnumInstType * enumInstType );
-	void postvisit( const ast::TraitInstType * traitInstType );
-	void postvisit( const ast::TypeInstType * typeInstType );
-	void postvisit( const ast::TupleType * tupleType );
-	void postvisit( const ast::VarArgsType * varArgsType );
-	void postvisit( const ast::ZeroType * zeroType );
-	void postvisit( const ast::OneType * oneType );
-	void postvisit( const ast::EnumAttrType * posType );
-private:
-	// refactor for code resue
-	void conversionCostFromBasicToBasic( const ast::BasicType * src, const ast::BasicType* dest );
-};
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/ConversionCost.hpp
===================================================================
--- src/ResolvExpr/ConversionCost.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/ConversionCost.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,86 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ConversionCost.hpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 09:37:28 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jul 29 16:12:00 2020
+// Update Count     : 7
+//
+
+#pragma once
+
+#include <functional>         // for function
+
+#include "Cost.hpp"           // for Cost
+
+#include "AST/Fwd.hpp"
+#include "AST/Pass.hpp"       // for WithShortCircuiting
+
+namespace ResolvExpr {
+
+// Some function pointer types, differ in return type.
+using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *, bool,
+	const ast::SymbolTable &, const ast::TypeEnvironment &)>;
+using PtrsCalculation = std::function<int(const ast::Type *, const ast::Type *,
+	const ast::SymbolTable &, const ast::TypeEnvironment &)>;
+
+Cost conversionCost(
+	const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
+	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
+
+Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dest,
+	bool srcIsLvalue, const ast::SymbolTable & indexer, const ast::TypeEnvironment & env,
+	PtrsCalculation func );
+
+class ConversionCost : public ast::WithShortCircuiting {
+protected:
+	const ast::Type * dst;
+	bool srcIsLvalue;
+	const ast::SymbolTable & symtab;
+	const ast::TypeEnvironment & env;
+	CostCalculation costCalc;
+public:
+	static size_t traceId;
+	Cost cost;
+	Cost result() { return cost; }
+
+	ConversionCost( const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
+			const ast::TypeEnvironment & env, CostCalculation costCalc ) :
+		dst( dst ), srcIsLvalue( srcIsLvalue ), symtab( symtab ), env( env ),
+		costCalc( costCalc ), cost( Cost::infinity )
+	{}
+
+	void previsit( const ast::Node * ) { visit_children = false; }
+
+	void postvisit( const ast::VoidType * voidType );
+	void postvisit( const ast::BasicType * basicType );
+	void postvisit( const ast::PointerType * pointerType );
+	void postvisit( const ast::ArrayType * arrayType );
+	void postvisit( const ast::ReferenceType * refType );
+	void postvisit( const ast::FunctionType * functionType );
+	void postvisit( const ast::EnumInstType * enumInstType );
+	void postvisit( const ast::TraitInstType * traitInstType );
+	void postvisit( const ast::TypeInstType * typeInstType );
+	void postvisit( const ast::TupleType * tupleType );
+	void postvisit( const ast::VarArgsType * varArgsType );
+	void postvisit( const ast::ZeroType * zeroType );
+	void postvisit( const ast::OneType * oneType );
+	void postvisit( const ast::EnumAttrType * posType );
+private:
+	// refactor for code resue
+	void conversionCostFromBasicToBasic( const ast::BasicType * src, const ast::BasicType* dest );
+};
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/Cost.h
===================================================================
--- src/ResolvExpr/Cost.h	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,181 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Cost.h --
-//
-// Author           : Peter Buhr and Aaron Moss
-// Created On       : Sun May 17 09:39:50 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Fri May  3 17:15:41 2024
-// Update Count     : 64
-//
-
-#pragma once
-
-#include <iostream>
-#include <cassert>
-#include <climits>
-#include <cstdint>
-
-namespace ResolvExpr {
-
-// To maximize performance and space, the 7 resolution costs are packed into a single 64-bit word. However, the
-// specialization cost is a negative value so a correction is needed is a few places.
-
-class Cost {
-	union {
-		struct {
-		#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-			// Little-endian => first value is low priority and last is high priority.
-			unsigned char padding;					///< unused
-			unsigned char referenceCost;			///< reference conversions
-			unsigned char specCost;					///< Polymorphic type specializations (type assertions), negative cost
-			unsigned char varCost;					///< Count of polymorphic type variables
-			unsigned char signCost;					///< Count of safe sign conversions
-			unsigned char safeCost;					///< Safe (widening) conversions
-			unsigned char polyCost;					///< Count of parameters and return values bound to some poly type
-			unsigned char unsafeCost;				///< Unsafe (narrowing) conversions
-		#else
-			#error Cost BIG_ENDIAN unsupported
-		#endif
-		} v;
-		uint64_t all;
-	};
-	static const unsigned char correctb = 0xff;		// byte correction for negative spec cost
-	static const uint64_t correctw = 0x00'00'00'00'00'ff'00'00; //' word correction for negative spec cost
-  public:
-	// Compiler adjusts constants for correct endian.
-	enum : uint64_t {
-		zero      = 0x00'00'00'00'00'ff'00'00,
-		infinity  = 0xff'ff'ff'ff'ff'00'ff'ff,
-		unsafe    = 0x01'00'00'00'00'ff'00'00,
-		poly      = 0x00'01'00'00'00'ff'00'00,
-		safe      = 0x00'00'01'00'00'ff'00'00,
-		sign      = 0x00'00'00'01'00'ff'00'00,
-		var       = 0x00'00'00'00'01'ff'00'00,
-		spec      = 0x00'00'00'00'00'fe'00'00,
-		reference = 0x00'00'00'00'00'ff'01'00,
-	}; //'
-
-	Cost( uint64_t all ) { Cost::all = all; }
-	Cost( int unsafeCost, int polyCost, int safeCost, int signCost, int varCost, int specCost, int referenceCost ) {
-		// Assume little-endian => first value is low priority and last is high priority.
-		v = {
-		#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-			(unsigned char)0,						// padding
-			(unsigned char)referenceCost,			// low priority
-			(unsigned char)(specCost + correctb),	// correct for signedness
-			(unsigned char)varCost,
-			(unsigned char)signCost,
-			(unsigned char)safeCost,
-			(unsigned char)polyCost,
-			(unsigned char)unsafeCost, 				// high priority
-		#else
-			#error Cost BIG_ENDIAN unsupported
-		#endif
-		};
-	}
-
-	int get_unsafeCost() const { return v.unsafeCost; }
-	int get_polyCost() const { return v.polyCost; }
-	int get_safeCost() const { return v.safeCost; }
-	int get_signCost() const { return v.signCost; }
-	int get_varCost() const { return v.varCost; }
-	int get_specCost() const { return -(correctb - v.specCost); }
-	int get_referenceCost() const { return v.referenceCost; }
-
-	friend bool operator==( const Cost, const Cost );
-	friend bool operator!=( const Cost lhs, const Cost rhs );
-	// returns negative for *this < rhs, 0 for *this == rhs, positive for *this > rhs
-	int compare( const Cost rhs ) const {
-		if ( all == infinity ) return 1;
-		if ( rhs.all == infinity ) return -1;
-		return all > rhs.all ? 1 : all == rhs.all ? 0 : -1;
-	}
-	friend bool operator<( const Cost lhs, const Cost rhs );
-
-	friend Cost operator+( const Cost lhs, const Cost rhs );
-
-	Cost operator+=( const Cost rhs ) {
-		if ( all == infinity ) return *this;
-		if ( rhs.all == infinity ) {
-			all = infinity;
-			return *this;
-		}
-		all += rhs.all - correctw;					// correct for negative spec cost
-		return *this;
-	}
-
-	Cost incUnsafe( int inc = 1 ) {
-		if ( all != infinity ) { assert( v.unsafeCost + inc <= UCHAR_MAX ); v.unsafeCost += inc; }
-		return *this;
-	}
-
-	Cost incPoly( int inc = 1 ) {
-		if ( all != infinity ) { assert( v.polyCost + inc <= UCHAR_MAX ); v.polyCost += inc; }
-		return *this;
-	}
-
-	Cost incSafe( int inc = 1 ) {
-		if ( all != infinity ) { assert( v.safeCost + inc <= UCHAR_MAX ); v.safeCost += inc; }
-		return *this;
-	}
-
-	Cost incSign( int inc = 1 ) {
-		if ( all != infinity ) { assert( v.signCost + inc <= UCHAR_MAX ); v.signCost += inc; }
-		return *this;
-	}
-
-	Cost incVar( int inc = 1 ) {
-		if ( all != infinity ) { assert( v.varCost + inc <= UCHAR_MAX ); v.varCost += inc; }
-		return *this;
-	}
-
-	Cost decSpec( int dec = 1 ) {
-		if ( all != infinity ) { assert( v.specCost - dec >= 0 ); v.specCost -= dec; }
-		return *this;
-	}
-
-	Cost incReference( int inc = 1 ) {
-		if ( all != infinity ) { assert( v.referenceCost + inc <= UCHAR_MAX ); v.referenceCost += inc; }
-		return *this;
-	}
-
-	friend std::ostream & operator<<( std::ostream & os, const Cost cost );
-};
-
-inline bool operator==( const Cost lhs, const Cost rhs ) {
-	return lhs.all == rhs.all;
-}
-
-inline bool operator!=( const Cost lhs, const Cost rhs ) {
-	return !( lhs.all == rhs.all );
-}
-
-inline bool operator<( const Cost lhs, const Cost rhs ) {
-	if ( lhs.all == Cost::infinity ) return false;
-	if ( rhs.all == Cost::infinity ) return true;
-	return lhs.all < rhs.all;
-}
-
-inline Cost operator+( const Cost lhs, const Cost rhs ) {
-	if ( lhs.all == Cost::infinity || rhs.all == Cost::infinity ) return Cost{ Cost::infinity };
-	return Cost{ lhs.all + rhs.all - Cost::correctw }; // correct for negative spec cost
-}
-
-inline std::ostream & operator<<( std::ostream & os, const Cost cost ) {
-	return os << "( " << cost.get_unsafeCost() << ", " << cost.get_polyCost() << ", " << cost.get_safeCost()
-			  << ", " << cost.get_signCost() << ", " << cost.get_varCost() << ", " << cost.get_specCost()
-			  << ", " << cost.get_referenceCost() << " )";
-}
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/Cost.hpp
===================================================================
--- src/ResolvExpr/Cost.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/Cost.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,181 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Cost.h --
+//
+// Author           : Peter Buhr and Aaron Moss
+// Created On       : Sun May 17 09:39:50 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Fri May  3 17:15:41 2024
+// Update Count     : 64
+//
+
+#pragma once
+
+#include <iostream>
+#include <cassert>
+#include <climits>
+#include <cstdint>
+
+namespace ResolvExpr {
+
+// To maximize performance and space, the 7 resolution costs are packed into a single 64-bit word. However, the
+// specialization cost is a negative value so a correction is needed is a few places.
+
+class Cost {
+	union {
+		struct {
+		#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+			// Little-endian => first value is low priority and last is high priority.
+			unsigned char padding;					///< unused
+			unsigned char referenceCost;			///< reference conversions
+			unsigned char specCost;					///< Polymorphic type specializations (type assertions), negative cost
+			unsigned char varCost;					///< Count of polymorphic type variables
+			unsigned char signCost;					///< Count of safe sign conversions
+			unsigned char safeCost;					///< Safe (widening) conversions
+			unsigned char polyCost;					///< Count of parameters and return values bound to some poly type
+			unsigned char unsafeCost;				///< Unsafe (narrowing) conversions
+		#else
+			#error Cost BIG_ENDIAN unsupported
+		#endif
+		} v;
+		uint64_t all;
+	};
+	static const unsigned char correctb = 0xff;		// byte correction for negative spec cost
+	static const uint64_t correctw = 0x00'00'00'00'00'ff'00'00; //' word correction for negative spec cost
+  public:
+	// Compiler adjusts constants for correct endian.
+	enum : uint64_t {
+		zero      = 0x00'00'00'00'00'ff'00'00,
+		infinity  = 0xff'ff'ff'ff'ff'00'ff'ff,
+		unsafe    = 0x01'00'00'00'00'ff'00'00,
+		poly      = 0x00'01'00'00'00'ff'00'00,
+		safe      = 0x00'00'01'00'00'ff'00'00,
+		sign      = 0x00'00'00'01'00'ff'00'00,
+		var       = 0x00'00'00'00'01'ff'00'00,
+		spec      = 0x00'00'00'00'00'fe'00'00,
+		reference = 0x00'00'00'00'00'ff'01'00,
+	}; //'
+
+	Cost( uint64_t all ) { Cost::all = all; }
+	Cost( int unsafeCost, int polyCost, int safeCost, int signCost, int varCost, int specCost, int referenceCost ) {
+		// Assume little-endian => first value is low priority and last is high priority.
+		v = {
+		#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+			(unsigned char)0,						// padding
+			(unsigned char)referenceCost,			// low priority
+			(unsigned char)(specCost + correctb),	// correct for signedness
+			(unsigned char)varCost,
+			(unsigned char)signCost,
+			(unsigned char)safeCost,
+			(unsigned char)polyCost,
+			(unsigned char)unsafeCost, 				// high priority
+		#else
+			#error Cost BIG_ENDIAN unsupported
+		#endif
+		};
+	}
+
+	int get_unsafeCost() const { return v.unsafeCost; }
+	int get_polyCost() const { return v.polyCost; }
+	int get_safeCost() const { return v.safeCost; }
+	int get_signCost() const { return v.signCost; }
+	int get_varCost() const { return v.varCost; }
+	int get_specCost() const { return -(correctb - v.specCost); }
+	int get_referenceCost() const { return v.referenceCost; }
+
+	friend bool operator==( const Cost, const Cost );
+	friend bool operator!=( const Cost lhs, const Cost rhs );
+	// returns negative for *this < rhs, 0 for *this == rhs, positive for *this > rhs
+	int compare( const Cost rhs ) const {
+		if ( all == infinity ) return 1;
+		if ( rhs.all == infinity ) return -1;
+		return all > rhs.all ? 1 : all == rhs.all ? 0 : -1;
+	}
+	friend bool operator<( const Cost lhs, const Cost rhs );
+
+	friend Cost operator+( const Cost lhs, const Cost rhs );
+
+	Cost operator+=( const Cost rhs ) {
+		if ( all == infinity ) return *this;
+		if ( rhs.all == infinity ) {
+			all = infinity;
+			return *this;
+		}
+		all += rhs.all - correctw;					// correct for negative spec cost
+		return *this;
+	}
+
+	Cost incUnsafe( int inc = 1 ) {
+		if ( all != infinity ) { assert( v.unsafeCost + inc <= UCHAR_MAX ); v.unsafeCost += inc; }
+		return *this;
+	}
+
+	Cost incPoly( int inc = 1 ) {
+		if ( all != infinity ) { assert( v.polyCost + inc <= UCHAR_MAX ); v.polyCost += inc; }
+		return *this;
+	}
+
+	Cost incSafe( int inc = 1 ) {
+		if ( all != infinity ) { assert( v.safeCost + inc <= UCHAR_MAX ); v.safeCost += inc; }
+		return *this;
+	}
+
+	Cost incSign( int inc = 1 ) {
+		if ( all != infinity ) { assert( v.signCost + inc <= UCHAR_MAX ); v.signCost += inc; }
+		return *this;
+	}
+
+	Cost incVar( int inc = 1 ) {
+		if ( all != infinity ) { assert( v.varCost + inc <= UCHAR_MAX ); v.varCost += inc; }
+		return *this;
+	}
+
+	Cost decSpec( int dec = 1 ) {
+		if ( all != infinity ) { assert( v.specCost - dec >= 0 ); v.specCost -= dec; }
+		return *this;
+	}
+
+	Cost incReference( int inc = 1 ) {
+		if ( all != infinity ) { assert( v.referenceCost + inc <= UCHAR_MAX ); v.referenceCost += inc; }
+		return *this;
+	}
+
+	friend std::ostream & operator<<( std::ostream & os, const Cost cost );
+};
+
+inline bool operator==( const Cost lhs, const Cost rhs ) {
+	return lhs.all == rhs.all;
+}
+
+inline bool operator!=( const Cost lhs, const Cost rhs ) {
+	return !( lhs.all == rhs.all );
+}
+
+inline bool operator<( const Cost lhs, const Cost rhs ) {
+	if ( lhs.all == Cost::infinity ) return false;
+	if ( rhs.all == Cost::infinity ) return true;
+	return lhs.all < rhs.all;
+}
+
+inline Cost operator+( const Cost lhs, const Cost rhs ) {
+	if ( lhs.all == Cost::infinity || rhs.all == Cost::infinity ) return Cost{ Cost::infinity };
+	return Cost{ lhs.all + rhs.all - Cost::correctw }; // correct for negative spec cost
+}
+
+inline std::ostream & operator<<( std::ostream & os, const Cost cost ) {
+	return os << "( " << cost.get_unsafeCost() << ", " << cost.get_polyCost() << ", " << cost.get_safeCost()
+			  << ", " << cost.get_signCost() << ", " << cost.get_varCost() << ", " << cost.get_specCost()
+			  << ", " << cost.get_referenceCost() << " )";
+}
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/CurrentObject.cc
===================================================================
--- src/ResolvExpr/CurrentObject.cc	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,610 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// CurrentObject.h --
-//
-// Author           : Rob Schluntz
-// Created On       : Tue Jun 13 15:28:32 2017
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Dec  9 17:49:51 2023
-// Update Count     : 20
-//
-
-#include <stddef.h>                    // for size_t
-#include <cassert>                     // for assertf, assert, safe_dynamic_...
-#include <deque>
-#include <iostream>                    // for ostream, operator<<, basic_ost...
-#include <stack>                       // for stack
-#include <string>                      // for string, operator<<, allocator
-
-#include "AST/Copy.hpp"                // for shallowCopy
-#include "AST/Expr.hpp"                // for InitAlternative
-#include "AST/GenericSubstitution.hpp" // for genericSubstitution
-#include "AST/Init.hpp"                // for Designation
-#include "AST/Node.hpp"                // for readonly
-#include "AST/Print.hpp"               // for readonly
-#include "AST/Type.hpp"
-#include "Common/Eval.h"               // for eval
-#include "Common/Indenter.h"           // for Indenter, operator<<
-#include "Common/SemanticError.h"      // for SemanticError
-#include "Common/utility.h"            // for toString
-#include "CurrentObject.h"
-
-#if 0
-#define PRINT(x) x
-#else
-#define PRINT(x)
-#endif
-
-namespace ast {
-
-/// Iterates members of a type by initializer.
-class MemberIterator {
-public:
-	virtual ~MemberIterator() {}
-
-	/// Internal set position based on iterator ranges.
-	virtual void setPosition(
-		std::deque< ptr< Expr > >::const_iterator it,
-		std::deque< ptr< Expr > >::const_iterator end ) = 0;
-
-	/// Walks the current object using the given designators as a guide.
-	void setPosition( const std::deque< ptr< Expr > > & designators ) {
-		setPosition( designators.begin(), designators.end() );
-	}
-
-	/// Retrieve the list of possible (Type,Designation) pairs for the
-	/// current position in the current object.
-	virtual std::deque< InitAlternative > operator* () const = 0;
-
-	/// True if the iterator is not currently at the end.
-	virtual operator bool() const = 0;
-
-	/// Moves the iterator by one member in the current object.
-	virtual MemberIterator & bigStep() = 0;
-
-	/// Moves the iterator by one member in the current subobject.
-	virtual MemberIterator & smallStep() = 0;
-
-	/// The type of the current object.
-	virtual const Type * getType() = 0;
-
-	/// The type of the current subobject.
-	virtual const Type * getNext() = 0;
-
-	/// Helper for operator*; aggregates must add designator to each init
-	/// alternative, but adding designators in operator* creates duplicates.
-	virtual std::deque< InitAlternative > first() const = 0;
-};
-
-namespace {
-
-/// create a new MemberIterator that traverses a type correctly
-MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type );
-
-/// Iterates "other" types (e.g. basic, pointer) which do not change at list initializer entry
-class SimpleIterator final : public MemberIterator {
-	CodeLocation location;
-	const Type * type = nullptr;
-public:
-	SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {}
-
-	void setPosition(
-		std::deque< ptr< Expr > >::const_iterator begin,
-		std::deque< ptr< Expr > >::const_iterator end
-	) override {
-		if ( begin != end ) {
-			SemanticError( location, "Un-designated initializer given non-empty designator" );
-		}
-	}
-
-	std::deque< InitAlternative > operator* () const override { return first(); }
-
-	operator bool() const override { return type; }
-
-	SimpleIterator & bigStep() override { return smallStep(); }
-	SimpleIterator & smallStep() override {
-		type = nullptr;  // empty on increment because no members
-		return *this;
-	}
-
-	const Type * getType() override { return type; }
-
-	const Type * getNext() override { return type; }
-
-	std::deque< InitAlternative > first() const override {
-		if ( type ) return { InitAlternative{ type, new Designation{ location } } };
-		return {};
-	}
-};
-
-/// Iterates over an indexed type:
-class IndexIterator : public MemberIterator {
-protected:
-	CodeLocation location;
-	size_t index = 0;
-	size_t size = 0;
-	std::unique_ptr<MemberIterator> memberIter;
-public:
-	IndexIterator( const CodeLocation & loc, size_t size ) :
-		location( loc ), size( size )
-	{}
-
-	void setPosition( const Expr * expr ) {
-		// need to permit integer-constant-expressions, including: integer constants,
-		// enumeration constants, character constants, sizeof expressions, alignof expressions,
-		// cast expressions
-
-		auto arg = eval( expr );
-		assertf( arg.hasKnownValue, "Non-evaluable expression made it to IndexIterator" );
-		index = arg.knownValue;
-
-		// if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
-		// 	try {
-		// 		index = constExpr->intValue();
-		// 	} catch ( SemanticErrorException & ) {
-		// 		SemanticError( expr, "Constant expression of non-integral type in array designator: " );
-		// 	}
-		// } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
-		// 	setPosition( castExpr->arg );
-		// } else if ( dynamic_cast< const SizeofExpr * >( expr ) || dynamic_cast< const AlignofExpr * >( expr ) ) {
-		// 	index = 0;
-		// } else {
-		// 	assertf( false,	"2 bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
-		// }
-	}
-
-	void setPosition(
-		std::deque<ast::ptr<ast::Expr>>::const_iterator begin,
-		std::deque<ast::ptr<ast::Expr>>::const_iterator end
-	) override {
-		if ( begin == end ) return;
-
-		setPosition( *begin );
-		memberIter->setPosition( ++begin, end );
-	}
-
-	std::deque< InitAlternative > operator* () const override { return first(); }
-
-	operator bool() const override { return index < size; }
-};
-
-/// Iterates over the members of array types:
-class ArrayIterator final : public IndexIterator {
-	const ArrayType * array = nullptr;
-	const Type * base = nullptr;
-
-	size_t getSize( const Expr * expr ) {
-		auto res = eval( expr );
-		if ( !res.hasKnownValue ) {
-			SemanticError( location, "Array designator must be a constant expression %s", toString( expr ).c_str() );
-		}
-		return res.knownValue;
-	}
-
-public:
-	ArrayIterator( const CodeLocation & loc, const ArrayType * at ) :
-			IndexIterator( loc, getSize( at->dimension) ),
-			array( at ), base( at->base ) {
-		PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
-		memberIter.reset( createMemberIterator( loc, base ) );
-		if ( at->isVarLen ) {
-			SemanticError( location, at, "VLA initialization does not support @=: " );
-		}
-	}
-
-	ArrayIterator & bigStep() override {
-		PRINT( std::cerr << "bigStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
-		++index;
-		memberIter.reset( index < size ? createMemberIterator( location, base ) : nullptr );
-		return *this;
-	}
-
-	ArrayIterator & smallStep() override {
-		PRINT( std::cerr << "smallStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
-		if ( memberIter ) {
-			PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
-			memberIter->smallStep();
-			if ( *memberIter ) {
-				PRINT( std::cerr << "has valid member iter" << std::endl; )
-				return *this;
-			}
-		}
-		return bigStep();
-	}
-
-	const Type * getType() override { return array; }
-
-	const Type * getNext() override { return base; }
-
-	std::deque< InitAlternative > first() const override {
-		PRINT( std::cerr << "first in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
-		if ( memberIter && *memberIter ) {
-			std::deque< InitAlternative > ret = memberIter->first();
-			for ( InitAlternative & alt : ret ) {
-				alt.designation.get_and_mutate()->designators.emplace_front( ConstantExpr::from_ulong( location, index ) );
-			}
-			return ret;
-		}
-		return {};
-	}
-};
-
-class AggregateIterator : public MemberIterator {
-protected:
-	using MemberList = std::vector< ptr< Decl > >;
-
-	CodeLocation location;
-	std::string kind;  // for debug
-	std::string name;
-	const Type * inst;
-	const MemberList & members;
-	MemberList::const_iterator curMember;
-	bool atbegin = true;  // false at first {small,big}Step
-	const Type * curType = nullptr;
-	std::unique_ptr< MemberIterator > memberIter = nullptr;
-	TypeSubstitution sub;
-
-	bool init() {
-		PRINT( std::cerr << "--init()--" << members.size() << std::endl; )
-		if ( curMember != members.end() ) {
-			if ( auto field = curMember->as< ObjectDecl >() ) {
-				PRINT( std::cerr << "incremented to field: " << field << std::endl; )
-				curType = field->get_type();
-				memberIter.reset( createMemberIterator( location, curType ) );
-				return true;
-			}
-		}
-		return false;
-	}
-
-	AggregateIterator(
-		const CodeLocation & loc, const std::string k, const std::string & n, const Type * i,
-		const MemberList & ms )
-	: location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ),
-	  sub( genericSubstitution( i ) ) {
-		PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )
-		init();
-	}
-
-public:
-	void setPosition(
-		std::deque< ptr< Expr > >::const_iterator begin,
-		std::deque< ptr< Expr > >::const_iterator end
-	) final {
-		if ( begin == end ) return;
-
-		if ( auto varExpr = begin->as< VariableExpr >() ) {
-			for ( curMember = members.begin(); curMember != members.end(); ++curMember ) {
-				if ( *curMember != varExpr->var ) continue;
-
-				++begin;
-
-				memberIter.reset( createMemberIterator( location, varExpr->result ) );
-				curType = varExpr->result;
-				atbegin = curMember == members.begin() && begin == end;
-				memberIter->setPosition( begin, end );
-				return;
-			}
-			assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
-		} else {
-			assertf( false, "1 bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() );
-		}
-	}
-
-	std::deque< InitAlternative > operator* () const final {
-		if ( memberIter && *memberIter ) {
-			std::deque< InitAlternative > ret = memberIter->first();
-			PRINT( std::cerr << "sub: " << sub << std::endl; )
-			for ( InitAlternative & alt : ret ) {
-				PRINT( std::cerr << "iterating and adding designators" << std::endl; )
-				alt.designation.get_and_mutate()->designators.emplace_front(
-					new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
-				// need to substitute for generic types so that casts are to concrete types
-				alt.type = shallowCopy(alt.type.get());
-				PRINT( std::cerr << "  type is: " << alt.type; )
-				sub.apply( alt.type ); // also apply to designation??
-				PRINT( std::cerr << " ==> " << alt.type << std::endl; )
-			}
-			return ret;
-		}
-		return {};
-	}
-
-	AggregateIterator & smallStep() final {
-		PRINT( std::cerr << "smallStep in " << kind << std::endl; )
-		atbegin = false;
-		if ( memberIter ) {
-			PRINT( std::cerr << "has member iter, incrementing..." << std::endl; )
-			memberIter->smallStep();
-			if ( *memberIter ) {
-				PRINT( std::cerr << "success!" << std::endl; )
-				return *this;
-			}
-		}
-		return bigStep();
-	}
-
-	AggregateIterator & bigStep() override = 0;
-
-	const Type * getType() final { return inst; }
-
-	const Type * getNext() final {
-		bool hasMember = memberIter && *memberIter;
-		return hasMember ? memberIter->getType() : nullptr;
-	}
-
-	std::deque< InitAlternative > first() const final {
-		std::deque< InitAlternative > ret;
-		PRINT( std::cerr << "first " << kind << std::endl; )
-		if ( memberIter && *memberIter ) {
-			PRINT( std::cerr << "adding children" << std::endl; )
-			ret = memberIter->first();
-			for ( InitAlternative & alt : ret ) {
-				PRINT( std::cerr << "iterating and adding designators" << std::endl; )
-				alt.designation.get_and_mutate()->designators.emplace_front(
-					new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
-			}
-		}
-		if ( atbegin ) {
-			// only add self if at the very beginning of the structure
-			PRINT( std::cerr << "adding self" << std::endl; )
-			ret.emplace_front( inst, new Designation{ location } );
-		}
-		return ret;
-	}
-};
-
-class StructIterator final : public AggregateIterator {
-public:
-	StructIterator( const CodeLocation & loc, const StructInstType * inst )
-	: AggregateIterator( loc, "StructIterator", inst->name, inst, inst->base->members ) {}
-
-	operator bool() const override {
-		return curMember != members.end() || (memberIter && *memberIter);
-	}
-
-	StructIterator & bigStep() override {
-		PRINT( std::cerr << "bigStep in " << kind << std::endl; )
-		atbegin = false;
-		memberIter = nullptr;
-		curType = nullptr;
-		while ( curMember != members.end() ) {
-			++curMember;
-			if ( init() ) return *this;
-		}
-		return *this;
-	}
-};
-
-class UnionIterator final : public AggregateIterator {
-public:
-	UnionIterator( const CodeLocation & loc, const UnionInstType * inst )
-	: AggregateIterator( loc, "UnionIterator", inst->name, inst, inst->base->members ) {}
-
-	operator bool() const override { return memberIter && *memberIter; }
-
-	UnionIterator & bigStep() override {
-		// unions only initialize one member
-		PRINT( std::cerr << "bigStep in " << kind << std::endl; )
-		atbegin = false;
-		memberIter = nullptr;
-		curType = nullptr;
-		curMember = members.end();
-		return *this;
-	}
-};
-
-/// Iterates across the positions in a tuple:
-class TupleIterator final : public IndexIterator {
-	ast::TupleType const * const tuple;
-
-	const ast::Type * typeAtIndex() const {
-		assert( index < size );
-		return tuple->types[ index ].get();
-	}
-
-public:
-	TupleIterator( const CodeLocation & loc, const TupleType * type )
-	: IndexIterator( loc, type->size() ), tuple( type ) {
-		PRINT( std::cerr << "Creating tuple iterator: " << type << std::endl; )
-		memberIter.reset( createMemberIterator( loc, typeAtIndex() ) );
-	}
-
-	TupleIterator & bigStep() override {
-		++index;
-		memberIter.reset( index < size ?
-			createMemberIterator( location, typeAtIndex() ) : nullptr );
-		return *this;
-	}
-
-	TupleIterator & smallStep() override {
-		if ( memberIter ) {
-			PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
-			memberIter->smallStep();
-			if ( !memberIter ) {
-				PRINT( std::cerr << "has valid member iter" << std::endl; )
-				return *this;
-			}
-		}
-		return bigStep();
-	}
-
-	const ast::Type * getType() override {
-		return tuple;
-	}
-
-	const ast::Type * getNext() override {
-		bool hasMember = memberIter && *memberIter;
-		return hasMember ? memberIter->getType() : nullptr;
-	}
-
-	std::deque< InitAlternative > first() const override {
-		PRINT( std::cerr << "first in TupleIterator (" << index << "/" << size << ")" << std::endl; )
-		if ( memberIter && *memberIter ) {
-			std::deque< InitAlternative > ret = memberIter->first();
-			for ( InitAlternative & alt : ret ) {
-				alt.designation.get_and_mutate()->designators.emplace_front(
-					ConstantExpr::from_ulong( location, index ) );
-			}
-			return ret;
-		}
-		return {};
-	}
-};
-
-MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ) {
-	if ( auto aggr = dynamic_cast< const BaseInstType * >( type ) ) {
-		if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) {
-			assert( sit->base );
-			return new StructIterator{ loc, sit };
-		} else if ( auto uit = dynamic_cast< const UnionInstType * >( aggr ) ) {
-			assert( uit->base );
-			return new UnionIterator{ loc, uit };
-		} else {
-			assertf(
-				dynamic_cast< const EnumInstType * >( type )
-					|| dynamic_cast< const TypeInstType * >( type ),
-				"Encountered unhandled BaseInstType in createMemberIterator: %s",
-					toString( type ).c_str() );
-			return new SimpleIterator{ loc, type };
-		}
-	} else if ( auto at = dynamic_cast< const ArrayType * >( type ) ) {
-		return new ArrayIterator{ loc, at };
-	} else if ( auto tt = dynamic_cast< const TupleType * >( type ) ) {
-		return new TupleIterator{ loc, tt };
-	} else {
-		return new SimpleIterator{ loc, type };
-	}
-}
-
-} // namespace
-
-CurrentObject::CurrentObject( const CodeLocation & loc, const Type * type ) : objStack() {
-	objStack.emplace_back( new SimpleIterator{ loc, type } );
-}
-
-const Designation * CurrentObject::findNext( const Designation * designation ) {
-	using DesignatorChain = std::deque< ptr< Expr > >;
-	PRINT( std::cerr << "___findNext" << std::endl; )
-
-	// find all the d's
-	std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts;
-	std::deque< const Type * > curTypes{ objStack.back()->getType() }, newTypes;
-	for ( const Expr * expr : designation->designators ) {
-		PRINT( std::cerr << "____untyped: " << expr << std::endl; )
-		auto dit = desigAlts.begin();
-		auto nexpr = dynamic_cast< const NameExpr * >( expr );
-
-		for ( const Type * t : curTypes ) {
-			assert( dit != desigAlts.end() );
-			DesignatorChain & d = *dit;
-			// Name Designation:
-			if ( nexpr ) {
-				PRINT( std::cerr << "____actual: " << t << std::endl; )
-				if ( auto refType = dynamic_cast< const BaseInstType * >( t ) ) {
-					// concatenate identical field names
-					for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
-						if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) {
-							PRINT( std::cerr << "____alt: " << field->type << std::endl; )
-							DesignatorChain d2 = d;
-							d2.emplace_back( new VariableExpr{ expr->location, field } );
-							newDesigAlts.emplace_back( std::move( d2 ) );
-							newTypes.emplace_back( field->type );
-						}
-					}
-				}
-
-				++dit;
-			// Index Designation:
-			} else {
-				if ( auto at = dynamic_cast< const ArrayType * >( t ) ) {
-					PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; )
-					d.emplace_back( expr );
-					newDesigAlts.emplace_back( d );
-					newTypes.emplace_back( at->base );
-				}
-			}
-		}
-
-		// reset queue
-		desigAlts = std::move( newDesigAlts );
-		newDesigAlts.clear();
-		curTypes = std::move( newTypes );
-		newTypes.clear();
-		assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() );
-	}
-
-	if ( desigAlts.size() > 1 ) {
-		SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") );
-	} else if ( desigAlts.empty() ) {
-		SemanticError( designation, "No reasonable alternatives for designation: " );
-	}
-
-	DesignatorChain & d = desigAlts.back();
-	PRINT( for ( Expression * expr : d ) {
-		std::cerr << "____desig: " << expr << std::endl;
-	} ) // for
-	assertf( ! curTypes.empty(), "empty designator chosen");
-
-	// set new designators
-	assertf( ! objStack.empty(), "empty object stack when setting designation" );
-	Designation * actualDesignation =
-		new Designation{ designation->location, DesignatorChain{d} };
-	objStack.back()->setPosition( d ); // destroys d
-	return actualDesignation;
-}
-
-void CurrentObject::setNext( const Designation * designation ) {
-	PRINT( std::cerr << "____setNext" << designation << std::endl; )
-	assertf( ! objStack.empty(), "obj stack empty in setNext" );
-	objStack.back()->setPosition( designation->designators );
-}
-
-void CurrentObject::increment() {
-	PRINT( std::cerr << "____increment" << std::endl; )
-	if ( objStack.empty() ) return;
-	PRINT( std::cerr << *objStack.back() << std::endl; )
-	objStack.back()->smallStep();
-}
-
-void CurrentObject::enterListInit( const CodeLocation & loc ) {
-	PRINT( std::cerr << "____entering list init" << std::endl; )
-	assertf( ! objStack.empty(), "empty obj stack entering list init" );
-	const ast::Type * type = objStack.back()->getNext();
-	assert( type );
-	objStack.emplace_back( createMemberIterator( loc, type ) );
-}
-
-void CurrentObject::exitListInit() {
-	PRINT( std::cerr << "____exiting list init" << std::endl; )
-	assertf( ! objStack.empty(), "objstack empty" );
-	objStack.pop_back();
-	if ( ! objStack.empty() ) {
-		PRINT( std::cerr << *objStack.back() << std::endl; )
-		objStack.back()->bigStep();
-	}
-}
-
-std::deque< InitAlternative > CurrentObject::getOptions() {
-	PRINT( std::cerr << "____getting current options" << std::endl; )
-	assertf( ! objStack.empty(), "objstack empty in getOptions" );
-	return **objStack.back();
-}
-
-const Type * CurrentObject::getCurrentType() {
-	PRINT( std::cerr << "____getting current type" << std::endl; )
-	assertf( ! objStack.empty(), "objstack empty in getCurrentType" );
-	return objStack.back()->getNext();
-}
-
-} // namespace ast
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/CurrentObject.cpp
===================================================================
--- src/ResolvExpr/CurrentObject.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/CurrentObject.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,611 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// CurrentObject.cpp --
+//
+// Author           : Rob Schluntz
+// Created On       : Tue Jun 13 15:28:32 2017
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sat Dec  9 17:49:51 2023
+// Update Count     : 20
+//
+
+#include "CurrentObject.hpp"
+
+#include <stddef.h>                    // for size_t
+#include <cassert>                     // for assertf, assert, safe_dynamic_...
+#include <deque>
+#include <iostream>                    // for ostream, operator<<, basic_ost...
+#include <stack>                       // for stack
+#include <string>                      // for string, operator<<, allocator
+
+#include "AST/Copy.hpp"                // for shallowCopy
+#include "AST/Expr.hpp"                // for InitAlternative
+#include "AST/GenericSubstitution.hpp" // for genericSubstitution
+#include "AST/Init.hpp"                // for Designation
+#include "AST/Node.hpp"                // for readonly
+#include "AST/Print.hpp"               // for readonly
+#include "AST/Type.hpp"
+#include "Common/Eval.hpp"             // for eval
+#include "Common/Indenter.hpp"         // for Indenter, operator<<
+#include "Common/SemanticError.hpp"    // for SemanticError
+#include "Common/Utility.hpp"          // for toString
+
+#if 0
+#define PRINT(x) x
+#else
+#define PRINT(x)
+#endif
+
+namespace ast {
+
+/// Iterates members of a type by initializer.
+class MemberIterator {
+public:
+	virtual ~MemberIterator() {}
+
+	/// Internal set position based on iterator ranges.
+	virtual void setPosition(
+		std::deque< ptr< Expr > >::const_iterator it,
+		std::deque< ptr< Expr > >::const_iterator end ) = 0;
+
+	/// Walks the current object using the given designators as a guide.
+	void setPosition( const std::deque< ptr< Expr > > & designators ) {
+		setPosition( designators.begin(), designators.end() );
+	}
+
+	/// Retrieve the list of possible (Type,Designation) pairs for the
+	/// current position in the current object.
+	virtual std::deque< InitAlternative > operator* () const = 0;
+
+	/// True if the iterator is not currently at the end.
+	virtual operator bool() const = 0;
+
+	/// Moves the iterator by one member in the current object.
+	virtual MemberIterator & bigStep() = 0;
+
+	/// Moves the iterator by one member in the current subobject.
+	virtual MemberIterator & smallStep() = 0;
+
+	/// The type of the current object.
+	virtual const Type * getType() = 0;
+
+	/// The type of the current subobject.
+	virtual const Type * getNext() = 0;
+
+	/// Helper for operator*; aggregates must add designator to each init
+	/// alternative, but adding designators in operator* creates duplicates.
+	virtual std::deque< InitAlternative > first() const = 0;
+};
+
+namespace {
+
+/// create a new MemberIterator that traverses a type correctly
+MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type );
+
+/// Iterates "other" types (e.g. basic, pointer) which do not change at list initializer entry
+class SimpleIterator final : public MemberIterator {
+	CodeLocation location;
+	const Type * type = nullptr;
+public:
+	SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {}
+
+	void setPosition(
+		std::deque< ptr< Expr > >::const_iterator begin,
+		std::deque< ptr< Expr > >::const_iterator end
+	) override {
+		if ( begin != end ) {
+			SemanticError( location, "Un-designated initializer given non-empty designator" );
+		}
+	}
+
+	std::deque< InitAlternative > operator* () const override { return first(); }
+
+	operator bool() const override { return type; }
+
+	SimpleIterator & bigStep() override { return smallStep(); }
+	SimpleIterator & smallStep() override {
+		type = nullptr;  // empty on increment because no members
+		return *this;
+	}
+
+	const Type * getType() override { return type; }
+
+	const Type * getNext() override { return type; }
+
+	std::deque< InitAlternative > first() const override {
+		if ( type ) return { InitAlternative{ type, new Designation{ location } } };
+		return {};
+	}
+};
+
+/// Iterates over an indexed type:
+class IndexIterator : public MemberIterator {
+protected:
+	CodeLocation location;
+	size_t index = 0;
+	size_t size = 0;
+	std::unique_ptr<MemberIterator> memberIter;
+public:
+	IndexIterator( const CodeLocation & loc, size_t size ) :
+		location( loc ), size( size )
+	{}
+
+	void setPosition( const Expr * expr ) {
+		// need to permit integer-constant-expressions, including: integer constants,
+		// enumeration constants, character constants, sizeof expressions, alignof expressions,
+		// cast expressions
+
+		auto arg = eval( expr );
+		assertf( arg.hasKnownValue, "Non-evaluable expression made it to IndexIterator" );
+		index = arg.knownValue;
+
+		// if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
+		// 	try {
+		// 		index = constExpr->intValue();
+		// 	} catch ( SemanticErrorException & ) {
+		// 		SemanticError( expr, "Constant expression of non-integral type in array designator: " );
+		// 	}
+		// } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
+		// 	setPosition( castExpr->arg );
+		// } else if ( dynamic_cast< const SizeofExpr * >( expr ) || dynamic_cast< const AlignofExpr * >( expr ) ) {
+		// 	index = 0;
+		// } else {
+		// 	assertf( false,	"2 bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
+		// }
+	}
+
+	void setPosition(
+		std::deque<ast::ptr<ast::Expr>>::const_iterator begin,
+		std::deque<ast::ptr<ast::Expr>>::const_iterator end
+	) override {
+		if ( begin == end ) return;
+
+		setPosition( *begin );
+		memberIter->setPosition( ++begin, end );
+	}
+
+	std::deque< InitAlternative > operator* () const override { return first(); }
+
+	operator bool() const override { return index < size; }
+};
+
+/// Iterates over the members of array types:
+class ArrayIterator final : public IndexIterator {
+	const ArrayType * array = nullptr;
+	const Type * base = nullptr;
+
+	size_t getSize( const Expr * expr ) {
+		auto res = eval( expr );
+		if ( !res.hasKnownValue ) {
+			SemanticError( location, "Array designator must be a constant expression %s", toString( expr ).c_str() );
+		}
+		return res.knownValue;
+	}
+
+public:
+	ArrayIterator( const CodeLocation & loc, const ArrayType * at ) :
+			IndexIterator( loc, getSize( at->dimension) ),
+			array( at ), base( at->base ) {
+		PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
+		memberIter.reset( createMemberIterator( loc, base ) );
+		if ( at->isVarLen ) {
+			SemanticError( location, at, "VLA initialization does not support @=: " );
+		}
+	}
+
+	ArrayIterator & bigStep() override {
+		PRINT( std::cerr << "bigStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
+		++index;
+		memberIter.reset( index < size ? createMemberIterator( location, base ) : nullptr );
+		return *this;
+	}
+
+	ArrayIterator & smallStep() override {
+		PRINT( std::cerr << "smallStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
+		if ( memberIter ) {
+			PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
+			memberIter->smallStep();
+			if ( *memberIter ) {
+				PRINT( std::cerr << "has valid member iter" << std::endl; )
+				return *this;
+			}
+		}
+		return bigStep();
+	}
+
+	const Type * getType() override { return array; }
+
+	const Type * getNext() override { return base; }
+
+	std::deque< InitAlternative > first() const override {
+		PRINT( std::cerr << "first in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
+		if ( memberIter && *memberIter ) {
+			std::deque< InitAlternative > ret = memberIter->first();
+			for ( InitAlternative & alt : ret ) {
+				alt.designation.get_and_mutate()->designators.emplace_front( ConstantExpr::from_ulong( location, index ) );
+			}
+			return ret;
+		}
+		return {};
+	}
+};
+
+class AggregateIterator : public MemberIterator {
+protected:
+	using MemberList = std::vector< ptr< Decl > >;
+
+	CodeLocation location;
+	std::string kind;  // for debug
+	std::string name;
+	const Type * inst;
+	const MemberList & members;
+	MemberList::const_iterator curMember;
+	bool atbegin = true;  // false at first {small,big}Step
+	const Type * curType = nullptr;
+	std::unique_ptr< MemberIterator > memberIter = nullptr;
+	TypeSubstitution sub;
+
+	bool init() {
+		PRINT( std::cerr << "--init()--" << members.size() << std::endl; )
+		if ( curMember != members.end() ) {
+			if ( auto field = curMember->as< ObjectDecl >() ) {
+				PRINT( std::cerr << "incremented to field: " << field << std::endl; )
+				curType = field->get_type();
+				memberIter.reset( createMemberIterator( location, curType ) );
+				return true;
+			}
+		}
+		return false;
+	}
+
+	AggregateIterator(
+		const CodeLocation & loc, const std::string k, const std::string & n, const Type * i,
+		const MemberList & ms )
+	: location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ),
+	  sub( genericSubstitution( i ) ) {
+		PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )
+		init();
+	}
+
+public:
+	void setPosition(
+		std::deque< ptr< Expr > >::const_iterator begin,
+		std::deque< ptr< Expr > >::const_iterator end
+	) final {
+		if ( begin == end ) return;
+
+		if ( auto varExpr = begin->as< VariableExpr >() ) {
+			for ( curMember = members.begin(); curMember != members.end(); ++curMember ) {
+				if ( *curMember != varExpr->var ) continue;
+
+				++begin;
+
+				memberIter.reset( createMemberIterator( location, varExpr->result ) );
+				curType = varExpr->result;
+				atbegin = curMember == members.begin() && begin == end;
+				memberIter->setPosition( begin, end );
+				return;
+			}
+			assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
+		} else {
+			assertf( false, "1 bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() );
+		}
+	}
+
+	std::deque< InitAlternative > operator* () const final {
+		if ( memberIter && *memberIter ) {
+			std::deque< InitAlternative > ret = memberIter->first();
+			PRINT( std::cerr << "sub: " << sub << std::endl; )
+			for ( InitAlternative & alt : ret ) {
+				PRINT( std::cerr << "iterating and adding designators" << std::endl; )
+				alt.designation.get_and_mutate()->designators.emplace_front(
+					new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
+				// need to substitute for generic types so that casts are to concrete types
+				alt.type = shallowCopy(alt.type.get());
+				PRINT( std::cerr << "  type is: " << alt.type; )
+				sub.apply( alt.type ); // also apply to designation??
+				PRINT( std::cerr << " ==> " << alt.type << std::endl; )
+			}
+			return ret;
+		}
+		return {};
+	}
+
+	AggregateIterator & smallStep() final {
+		PRINT( std::cerr << "smallStep in " << kind << std::endl; )
+		atbegin = false;
+		if ( memberIter ) {
+			PRINT( std::cerr << "has member iter, incrementing..." << std::endl; )
+			memberIter->smallStep();
+			if ( *memberIter ) {
+				PRINT( std::cerr << "success!" << std::endl; )
+				return *this;
+			}
+		}
+		return bigStep();
+	}
+
+	AggregateIterator & bigStep() override = 0;
+
+	const Type * getType() final { return inst; }
+
+	const Type * getNext() final {
+		bool hasMember = memberIter && *memberIter;
+		return hasMember ? memberIter->getType() : nullptr;
+	}
+
+	std::deque< InitAlternative > first() const final {
+		std::deque< InitAlternative > ret;
+		PRINT( std::cerr << "first " << kind << std::endl; )
+		if ( memberIter && *memberIter ) {
+			PRINT( std::cerr << "adding children" << std::endl; )
+			ret = memberIter->first();
+			for ( InitAlternative & alt : ret ) {
+				PRINT( std::cerr << "iterating and adding designators" << std::endl; )
+				alt.designation.get_and_mutate()->designators.emplace_front(
+					new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
+			}
+		}
+		if ( atbegin ) {
+			// only add self if at the very beginning of the structure
+			PRINT( std::cerr << "adding self" << std::endl; )
+			ret.emplace_front( inst, new Designation{ location } );
+		}
+		return ret;
+	}
+};
+
+class StructIterator final : public AggregateIterator {
+public:
+	StructIterator( const CodeLocation & loc, const StructInstType * inst )
+	: AggregateIterator( loc, "StructIterator", inst->name, inst, inst->base->members ) {}
+
+	operator bool() const override {
+		return curMember != members.end() || (memberIter && *memberIter);
+	}
+
+	StructIterator & bigStep() override {
+		PRINT( std::cerr << "bigStep in " << kind << std::endl; )
+		atbegin = false;
+		memberIter = nullptr;
+		curType = nullptr;
+		while ( curMember != members.end() ) {
+			++curMember;
+			if ( init() ) return *this;
+		}
+		return *this;
+	}
+};
+
+class UnionIterator final : public AggregateIterator {
+public:
+	UnionIterator( const CodeLocation & loc, const UnionInstType * inst )
+	: AggregateIterator( loc, "UnionIterator", inst->name, inst, inst->base->members ) {}
+
+	operator bool() const override { return memberIter && *memberIter; }
+
+	UnionIterator & bigStep() override {
+		// unions only initialize one member
+		PRINT( std::cerr << "bigStep in " << kind << std::endl; )
+		atbegin = false;
+		memberIter = nullptr;
+		curType = nullptr;
+		curMember = members.end();
+		return *this;
+	}
+};
+
+/// Iterates across the positions in a tuple:
+class TupleIterator final : public IndexIterator {
+	ast::TupleType const * const tuple;
+
+	const ast::Type * typeAtIndex() const {
+		assert( index < size );
+		return tuple->types[ index ].get();
+	}
+
+public:
+	TupleIterator( const CodeLocation & loc, const TupleType * type )
+	: IndexIterator( loc, type->size() ), tuple( type ) {
+		PRINT( std::cerr << "Creating tuple iterator: " << type << std::endl; )
+		memberIter.reset( createMemberIterator( loc, typeAtIndex() ) );
+	}
+
+	TupleIterator & bigStep() override {
+		++index;
+		memberIter.reset( index < size ?
+			createMemberIterator( location, typeAtIndex() ) : nullptr );
+		return *this;
+	}
+
+	TupleIterator & smallStep() override {
+		if ( memberIter ) {
+			PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
+			memberIter->smallStep();
+			if ( !memberIter ) {
+				PRINT( std::cerr << "has valid member iter" << std::endl; )
+				return *this;
+			}
+		}
+		return bigStep();
+	}
+
+	const ast::Type * getType() override {
+		return tuple;
+	}
+
+	const ast::Type * getNext() override {
+		bool hasMember = memberIter && *memberIter;
+		return hasMember ? memberIter->getType() : nullptr;
+	}
+
+	std::deque< InitAlternative > first() const override {
+		PRINT( std::cerr << "first in TupleIterator (" << index << "/" << size << ")" << std::endl; )
+		if ( memberIter && *memberIter ) {
+			std::deque< InitAlternative > ret = memberIter->first();
+			for ( InitAlternative & alt : ret ) {
+				alt.designation.get_and_mutate()->designators.emplace_front(
+					ConstantExpr::from_ulong( location, index ) );
+			}
+			return ret;
+		}
+		return {};
+	}
+};
+
+MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ) {
+	if ( auto aggr = dynamic_cast< const BaseInstType * >( type ) ) {
+		if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) {
+			assert( sit->base );
+			return new StructIterator{ loc, sit };
+		} else if ( auto uit = dynamic_cast< const UnionInstType * >( aggr ) ) {
+			assert( uit->base );
+			return new UnionIterator{ loc, uit };
+		} else {
+			assertf(
+				dynamic_cast< const EnumInstType * >( type )
+					|| dynamic_cast< const TypeInstType * >( type ),
+				"Encountered unhandled BaseInstType in createMemberIterator: %s",
+					toString( type ).c_str() );
+			return new SimpleIterator{ loc, type };
+		}
+	} else if ( auto at = dynamic_cast< const ArrayType * >( type ) ) {
+		return new ArrayIterator{ loc, at };
+	} else if ( auto tt = dynamic_cast< const TupleType * >( type ) ) {
+		return new TupleIterator{ loc, tt };
+	} else {
+		return new SimpleIterator{ loc, type };
+	}
+}
+
+} // namespace
+
+CurrentObject::CurrentObject( const CodeLocation & loc, const Type * type ) : objStack() {
+	objStack.emplace_back( new SimpleIterator{ loc, type } );
+}
+
+const Designation * CurrentObject::findNext( const Designation * designation ) {
+	using DesignatorChain = std::deque< ptr< Expr > >;
+	PRINT( std::cerr << "___findNext" << std::endl; )
+
+	// find all the d's
+	std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts;
+	std::deque< const Type * > curTypes{ objStack.back()->getType() }, newTypes;
+	for ( const Expr * expr : designation->designators ) {
+		PRINT( std::cerr << "____untyped: " << expr << std::endl; )
+		auto dit = desigAlts.begin();
+		auto nexpr = dynamic_cast< const NameExpr * >( expr );
+
+		for ( const Type * t : curTypes ) {
+			assert( dit != desigAlts.end() );
+			DesignatorChain & d = *dit;
+			// Name Designation:
+			if ( nexpr ) {
+				PRINT( std::cerr << "____actual: " << t << std::endl; )
+				if ( auto refType = dynamic_cast< const BaseInstType * >( t ) ) {
+					// concatenate identical field names
+					for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
+						if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) {
+							PRINT( std::cerr << "____alt: " << field->type << std::endl; )
+							DesignatorChain d2 = d;
+							d2.emplace_back( new VariableExpr{ expr->location, field } );
+							newDesigAlts.emplace_back( std::move( d2 ) );
+							newTypes.emplace_back( field->type );
+						}
+					}
+				}
+
+				++dit;
+			// Index Designation:
+			} else {
+				if ( auto at = dynamic_cast< const ArrayType * >( t ) ) {
+					PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; )
+					d.emplace_back( expr );
+					newDesigAlts.emplace_back( d );
+					newTypes.emplace_back( at->base );
+				}
+			}
+		}
+
+		// reset queue
+		desigAlts = std::move( newDesigAlts );
+		newDesigAlts.clear();
+		curTypes = std::move( newTypes );
+		newTypes.clear();
+		assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() );
+	}
+
+	if ( desigAlts.size() > 1 ) {
+		SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") );
+	} else if ( desigAlts.empty() ) {
+		SemanticError( designation, "No reasonable alternatives for designation: " );
+	}
+
+	DesignatorChain & d = desigAlts.back();
+	PRINT( for ( Expression * expr : d ) {
+		std::cerr << "____desig: " << expr << std::endl;
+	} ) // for
+	assertf( ! curTypes.empty(), "empty designator chosen");
+
+	// set new designators
+	assertf( ! objStack.empty(), "empty object stack when setting designation" );
+	Designation * actualDesignation =
+		new Designation{ designation->location, DesignatorChain{d} };
+	objStack.back()->setPosition( d ); // destroys d
+	return actualDesignation;
+}
+
+void CurrentObject::setNext( const Designation * designation ) {
+	PRINT( std::cerr << "____setNext" << designation << std::endl; )
+	assertf( ! objStack.empty(), "obj stack empty in setNext" );
+	objStack.back()->setPosition( designation->designators );
+}
+
+void CurrentObject::increment() {
+	PRINT( std::cerr << "____increment" << std::endl; )
+	if ( objStack.empty() ) return;
+	PRINT( std::cerr << *objStack.back() << std::endl; )
+	objStack.back()->smallStep();
+}
+
+void CurrentObject::enterListInit( const CodeLocation & loc ) {
+	PRINT( std::cerr << "____entering list init" << std::endl; )
+	assertf( ! objStack.empty(), "empty obj stack entering list init" );
+	const ast::Type * type = objStack.back()->getNext();
+	assert( type );
+	objStack.emplace_back( createMemberIterator( loc, type ) );
+}
+
+void CurrentObject::exitListInit() {
+	PRINT( std::cerr << "____exiting list init" << std::endl; )
+	assertf( ! objStack.empty(), "objstack empty" );
+	objStack.pop_back();
+	if ( ! objStack.empty() ) {
+		PRINT( std::cerr << *objStack.back() << std::endl; )
+		objStack.back()->bigStep();
+	}
+}
+
+std::deque< InitAlternative > CurrentObject::getOptions() {
+	PRINT( std::cerr << "____getting current options" << std::endl; )
+	assertf( ! objStack.empty(), "objstack empty in getOptions" );
+	return **objStack.back();
+}
+
+const Type * CurrentObject::getCurrentType() {
+	PRINT( std::cerr << "____getting current type" << std::endl; )
+	assertf( ! objStack.empty(), "objstack empty in getCurrentType" );
+	return objStack.back()->getNext();
+}
+
+} // namespace ast
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/CurrentObject.h
===================================================================
--- src/ResolvExpr/CurrentObject.h	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,67 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// CurrentObject.h --
-//
-// Author           : Rob Schluntz
-// Created On       : Thu Jun  8 11:07:25 2017
-// Last Modified By : Andrew Beach
-// Last Modified On : Thu Apr  6 16:14:00 2023
-// Update Count     : 4
-//
-
-#pragma once
-
-#include <deque>
-#include <memory> // for unique_ptr
-#include <vector>
-
-#include "AST/Node.hpp"  // for ptr
-#include "Common/CodeLocation.h"
-
-namespace ast {
-
-// AST class types:
-class Designation;
-class Type;
-struct InitAlternative;
-
-/// Iterates members of a type by initializer
-class MemberIterator;
-
-/// Builds initializer lists in resolution
-class CurrentObject final {
-	std::vector<std::shared_ptr<MemberIterator>> objStack;
-
-public:
-	CurrentObject() = default;
-	CurrentObject( const CodeLocation & loc, const Type * type );
-
-	/// Resolves unresolved designation.
-	const Designation * findNext( const Designation * designation );
-	/// Sets current position using the resolved designation.
-	void setNext( const Designation * designation );
-	/// Steps to next sub-object of current object.
-	void increment();
-	/// Sets new current object for the duration of this brace-enclosed intializer-list.
-	void enterListInit( const CodeLocation & loc );
-	/// Restores previous current object.
-	void exitListInit();
-	/// Produces a list of alternatives (Type *, Designation *)
-	/// for the current sub-object's initializer.
-	std::deque< InitAlternative > getOptions();
-	/// Produces the type of the current object but no subobjects.
-	const Type * getCurrentType();
-};
-
-} // namespace ast
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
-
Index: src/ResolvExpr/CurrentObject.hpp
===================================================================
--- src/ResolvExpr/CurrentObject.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/CurrentObject.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,67 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// CurrentObject.hpp --
+//
+// Author           : Rob Schluntz
+// Created On       : Thu Jun  8 11:07:25 2017
+// Last Modified By : Andrew Beach
+// Last Modified On : Thu Apr  6 16:14:00 2023
+// Update Count     : 4
+//
+
+#pragma once
+
+#include <deque>
+#include <memory> // for unique_ptr
+#include <vector>
+
+#include "AST/Node.hpp"  // for ptr
+#include "Common/CodeLocation.hpp"
+
+namespace ast {
+
+// AST class types:
+class Designation;
+class Type;
+struct InitAlternative;
+
+/// Iterates members of a type by initializer
+class MemberIterator;
+
+/// Builds initializer lists in resolution
+class CurrentObject final {
+	std::vector<std::shared_ptr<MemberIterator>> objStack;
+
+public:
+	CurrentObject() = default;
+	CurrentObject( const CodeLocation & loc, const Type * type );
+
+	/// Resolves unresolved designation.
+	const Designation * findNext( const Designation * designation );
+	/// Sets current position using the resolved designation.
+	void setNext( const Designation * designation );
+	/// Steps to next sub-object of current object.
+	void increment();
+	/// Sets new current object for the duration of this brace-enclosed intializer-list.
+	void enterListInit( const CodeLocation & loc );
+	/// Restores previous current object.
+	void exitListInit();
+	/// Produces a list of alternatives (Type *, Designation *)
+	/// for the current sub-object's initializer.
+	std::deque< InitAlternative > getOptions();
+	/// Produces the type of the current object but no subobjects.
+	const Type * getCurrentType();
+};
+
+} // namespace ast
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
+
Index: src/ResolvExpr/ExplodedArg.cpp
===================================================================
--- src/ResolvExpr/ExplodedArg.cpp	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ src/ResolvExpr/ExplodedArg.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -16,5 +16,5 @@
 #include "ExplodedArg.hpp"
 
-#include "Tuples/Explode.h"   // for Tuples::explode
+#include "Tuples/Explode.hpp"   // for Tuples::explode
 
 namespace ResolvExpr {
Index: src/ResolvExpr/ExplodedArg.hpp
===================================================================
--- src/ResolvExpr/ExplodedArg.hpp	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ src/ResolvExpr/ExplodedArg.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -19,5 +19,5 @@
 
 #include "Candidate.hpp"            // for Candidate, CandidateList
-#include "Cost.h"                   // for Cost
+#include "Cost.hpp"                 // for Cost
 #include "AST/Expr.hpp"
 #include "AST/Node.hpp"             // for ptr
Index: src/ResolvExpr/FindOpenVars.cc
===================================================================
--- src/ResolvExpr/FindOpenVars.cc	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,95 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// FindOpenVars.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 09:42:48 2015
-// Last Modified By : Andrew
-// Last Modified On : Fri Jul 12 14:18:00 2019
-// Update Count     : 4
-//
-
-#include "FindOpenVars.h"
-
-#include "AST/Pass.hpp"
-#include "AST/Type.hpp"
-#include "AST/TypeEnvironment.hpp"
-
-#include <iostream>
-
-namespace ResolvExpr {
-
-namespace {
-
-struct FindOpenVars final : public ast::WithGuards {
-	ast::OpenVarSet & open;
-	ast::OpenVarSet & closed;
-	ast::AssertionSet & need;
-	ast::AssertionSet & have;
-	ast::TypeEnvironment & env;
-	bool nextIsOpen;
-
-	FindOpenVars(
-		ast::OpenVarSet & o, ast::OpenVarSet & c, ast::AssertionSet & n,
-		ast::AssertionSet & h, ast::TypeEnvironment & env, FirstMode firstIsOpen )
-	: open( o ), closed( c ), need( n ), have( h ), env (env), nextIsOpen( firstIsOpen ) {}
-
-	void previsit( const ast::FunctionType * type ) {
-		// mark open/closed variables
-		if ( nextIsOpen ) {
-			// trying to remove this from resolver.
-			// occasionally used in other parts so not deleting right now.
-
-			// insert open variables unbound to environment.
-			env.add(type->forall);
-
-			for ( auto & decl : type->forall ) {
-				open[ *decl ] = ast::TypeData{ decl->base };
-			}
-			for ( auto & assert : type->assertions ) {
-				need[ assert ].isUsed = false;
-			}
-		} else {
-			for ( auto & decl : type->forall ) {
-				closed[ *decl ] = ast::TypeData{ decl->base };
-			}
-			for ( auto & assert : type->assertions ) {
-				have[ assert ].isUsed = false;
-			}
-		}
-
-		// flip open variables for contained function types
-	//	nextIsOpen = ! nextIsOpen;
-	//	GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } );
-		GuardValue( nextIsOpen ) = !nextIsOpen;
-	}
-};
-
-} // namespace
-
-void findOpenVars(
-		const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed,
-		ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen ) {
-	ast::Pass< FindOpenVars > finder{ open, closed, need, have, env, firstIsOpen };
-	type->accept( finder );
-
-	if (!closed.empty()) {
-		std::cerr << "closed: ";
-		for (auto& i : closed) {
-			std::cerr << i.first.base->location << ":" << i.first.base->name << ' ';
-		}
-		std::cerr << std::endl;
-	}
-}
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/FindOpenVars.cpp
===================================================================
--- src/ResolvExpr/FindOpenVars.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/FindOpenVars.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,95 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// FindOpenVars.cpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 09:42:48 2015
+// Last Modified By : Andrew
+// Last Modified On : Fri Jul 12 14:18:00 2019
+// Update Count     : 4
+//
+
+#include "FindOpenVars.hpp"
+
+#include "AST/Pass.hpp"
+#include "AST/Type.hpp"
+#include "AST/TypeEnvironment.hpp"
+
+#include <iostream>
+
+namespace ResolvExpr {
+
+namespace {
+
+struct FindOpenVars final : public ast::WithGuards {
+	ast::OpenVarSet & open;
+	ast::OpenVarSet & closed;
+	ast::AssertionSet & need;
+	ast::AssertionSet & have;
+	ast::TypeEnvironment & env;
+	bool nextIsOpen;
+
+	FindOpenVars(
+		ast::OpenVarSet & o, ast::OpenVarSet & c, ast::AssertionSet & n,
+		ast::AssertionSet & h, ast::TypeEnvironment & env, FirstMode firstIsOpen )
+	: open( o ), closed( c ), need( n ), have( h ), env (env), nextIsOpen( firstIsOpen ) {}
+
+	void previsit( const ast::FunctionType * type ) {
+		// mark open/closed variables
+		if ( nextIsOpen ) {
+			// trying to remove this from resolver.
+			// occasionally used in other parts so not deleting right now.
+
+			// insert open variables unbound to environment.
+			env.add(type->forall);
+
+			for ( auto & decl : type->forall ) {
+				open[ *decl ] = ast::TypeData{ decl->base };
+			}
+			for ( auto & assert : type->assertions ) {
+				need[ assert ].isUsed = false;
+			}
+		} else {
+			for ( auto & decl : type->forall ) {
+				closed[ *decl ] = ast::TypeData{ decl->base };
+			}
+			for ( auto & assert : type->assertions ) {
+				have[ assert ].isUsed = false;
+			}
+		}
+
+		// flip open variables for contained function types
+	//	nextIsOpen = ! nextIsOpen;
+	//	GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } );
+		GuardValue( nextIsOpen ) = !nextIsOpen;
+	}
+};
+
+} // namespace
+
+void findOpenVars(
+		const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed,
+		ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen ) {
+	ast::Pass< FindOpenVars > finder{ open, closed, need, have, env, firstIsOpen };
+	type->accept( finder );
+
+	if (!closed.empty()) {
+		std::cerr << "closed: ";
+		for (auto& i : closed) {
+			std::cerr << i.first.base->location << ":" << i.first.base->name << ' ';
+		}
+		std::cerr << std::endl;
+	}
+}
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/FindOpenVars.h
===================================================================
--- src/ResolvExpr/FindOpenVars.h	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,39 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// FindOpenVars.h -- 
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 09:46:04 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:35:18 2017
-// Update Count     : 3
-//
-
-#pragma once
-
-#include "AST/TypeEnvironment.hpp"  // for AssertionSet, OpenVarSet
-
-namespace ast {
-	class Type;
-}
-
-namespace ResolvExpr {
-
-enum FirstMode { FirstClosed, FirstOpen };
-
-// Updates open and closed variables and their associated assertions
-void findOpenVars(
-	const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed,
-	ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen );
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/FindOpenVars.hpp
===================================================================
--- src/ResolvExpr/FindOpenVars.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/FindOpenVars.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,39 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// FindOpenVars.h -- 
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 09:46:04 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sat Jul 22 09:35:18 2017
+// Update Count     : 3
+//
+
+#pragma once
+
+#include "AST/TypeEnvironment.hpp"  // for AssertionSet, OpenVarSet
+
+namespace ast {
+	class Type;
+}
+
+namespace ResolvExpr {
+
+enum FirstMode { FirstClosed, FirstOpen };
+
+// Updates open and closed variables and their associated assertions
+void findOpenVars(
+	const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed,
+	ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env, FirstMode firstIsOpen );
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/PolyCost.cc
===================================================================
--- src/ResolvExpr/PolyCost.cc	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,63 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// PolyCost.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 09:50:12 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Jun 19 10:45:00 2019
-// Update Count     : 4
-//
-
-#include "AST/SymbolTable.hpp"
-#include "AST/Pass.hpp"
-#include "AST/Type.hpp"
-#include "AST/TypeEnvironment.hpp"
-
-namespace ResolvExpr {
-
-namespace {
-
-class PolyCost {
-	const ast::SymbolTable &symtab;
-public:
-	int result;
-	const ast::TypeEnvironment &env_;
-
-	PolyCost( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env )
-	: symtab( symtab ), result( 0 ), env_( env ) {}
-
-	void previsit( const ast::TypeInstType * type ) {
-		if ( const ast::EqvClass * eqv = env_.lookup( *type ) ; eqv && eqv->bound ) {
-			if ( const ast::TypeInstType * otherType = eqv->bound.as< ast::TypeInstType >() ) {
-				if ( symtab.lookupType( otherType->name ) ) {
-					// Bound to opaque type.
-					result = 1;
-				}
-			} else {
-				// Bound to concrete type.
-				result = 1;
-			}
-		}
-	}
-};
-
-} // namespace
-
-int polyCost(
-	const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
-) {
-	return ast::Pass<PolyCost>::read( type, symtab, env );
-}
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/PolyCost.cpp
===================================================================
--- src/ResolvExpr/PolyCost.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/PolyCost.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,63 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// PolyCost.cc --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 09:50:12 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jun 19 10:45:00 2019
+// Update Count     : 4
+//
+
+#include "AST/SymbolTable.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Type.hpp"
+#include "AST/TypeEnvironment.hpp"
+
+namespace ResolvExpr {
+
+namespace {
+
+class PolyCost {
+	const ast::SymbolTable &symtab;
+public:
+	int result;
+	const ast::TypeEnvironment &env_;
+
+	PolyCost( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env )
+	: symtab( symtab ), result( 0 ), env_( env ) {}
+
+	void previsit( const ast::TypeInstType * type ) {
+		if ( const ast::EqvClass * eqv = env_.lookup( *type ) ; eqv && eqv->bound ) {
+			if ( const ast::TypeInstType * otherType = eqv->bound.as< ast::TypeInstType >() ) {
+				if ( symtab.lookupType( otherType->name ) ) {
+					// Bound to opaque type.
+					result = 1;
+				}
+			} else {
+				// Bound to concrete type.
+				result = 1;
+			}
+		}
+	}
+};
+
+} // namespace
+
+int polyCost(
+	const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
+) {
+	return ast::Pass<PolyCost>::read( type, symtab, env );
+}
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/PtrsAssignable.cc
===================================================================
--- src/ResolvExpr/PtrsAssignable.cc	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,113 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// PtrsAssignable.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 11:44:11 2015
-// Last Modified By : Andrew
-// Last Modified On : Mon Jun 24 15:29:00 2019
-// Update Count     : 9
-//
-
-#include "PtrsAssignable.hpp"
-
-#include "AST/Pass.hpp"
-#include "AST/Type.hpp"
-#include "AST/TypeEnvironment.hpp"
-
-namespace ResolvExpr {
-
-namespace {
-
-struct PtrsAssignable : public ast::WithShortCircuiting {
-	const ast::Type * dst;
-	const ast::TypeEnvironment & typeEnv;
-	int result;
-
-	PtrsAssignable( const ast::Type * dst, const ast::TypeEnvironment & env ) :
-		dst( dst ), typeEnv( env ), result( 0 ) {}
-
-	void previsit( ast::Type * ) { visit_children = false; }
-
-	void postvisit( const ast::EnumInstType * ) {
-		if ( dynamic_cast< const ast::BasicType * >( dst ) ) {
-			// int * = E *, etc. is safe. This isn't technically correct, as each
-			// enum has one basic type that it is compatible with, an that type can
-			// differ from enum to enum. Without replicating GCC's internal logic,
-			// there is no way to know which type this particular enum is compatible
-			// with, so punt on this for now.
-			result = 1;
-		}
-	}
-	void postvisit( const ast::TypeInstType * inst ) {
-		if ( const ast::EqvClass * eqv = typeEnv.lookup( *inst ) ) {
-			if ( eqv->bound ) {
-				// T * = S * for any S depends on the type bound to T
-				result = ptrsAssignable( eqv->bound, dst, typeEnv );
-			}
-		}
-	}
-};
-
-} // namespace
-
-int ptrsAssignable( const ast::Type * src, const ast::Type * dst,
-		const ast::TypeEnvironment & env ) {
-	if ( const ast::TypeInstType * dstAsInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
-		if ( const ast::EqvClass * eqv = env.lookup( *dstAsInst ) ) {
-			return ptrsAssignable( src, eqv->bound, env );
-		}
-	}
-	if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
-		return -1;
-	} else {
-		ast::Pass<PtrsAssignable> visitor( dst, env );
-		src->accept( visitor );
-		return visitor.core.result;
-	}
-
-// see ticket #136 (this should be able to replace the visitor).
-#if 0
-	if ( const ast::TypeInstType * dstAsTypeInst =
-			dynamic_cast< const ast::TypeInstType* >( dst ) ) {
-		if ( const ast::EqvClass * eqv = env.lookup( dstAsTypeInst->get_name() ) ) {
-			return ptrsAssignable( src, eqv->type, env );
-		} // if
-	} // if
-	if ( dynamic_cast< VoidType* >( dst ) ) {
-		// void * = T * for any T is unsafe
-		// xxx - this should be safe, but that currently breaks the build
-		return -1;
-	} else if ( dynamic_cast< EnumInstType * >( src ) ) {
-		if ( dynamic_cast< BasicType * >( dst ) ) {
-			// int * = E *, etc. is safe. This isn't technically correct, as each
-			// enum has one basic type that it is compatible with, an that type can
-			// differ from enum to enum. Without replicating GCC's internal logic,
-			// there is no way to know which type this particular enum is compatible
-			// with, so punt on this for now.
-			return 1;
-		}
-	} else if ( const ast::TypeInstType * typeInstType =
-			dynamic_cast< const ast::TypeInstType * >( src ) ) {
-		if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) {
-			if ( eqv->bound ) {
-				// T * = S * for any S depends on the type bound to T
-				return ptrsAssignable( eqv->bound, dst, env );
-			}
-		}
-	}
-	return 0;
-#endif
-}
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/PtrsAssignable.cpp
===================================================================
--- src/ResolvExpr/PtrsAssignable.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/PtrsAssignable.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,113 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// PtrsAssignable.cc --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 11:44:11 2015
+// Last Modified By : Andrew
+// Last Modified On : Mon Jun 24 15:29:00 2019
+// Update Count     : 9
+//
+
+#include "PtrsAssignable.hpp"
+
+#include "AST/Pass.hpp"
+#include "AST/Type.hpp"
+#include "AST/TypeEnvironment.hpp"
+
+namespace ResolvExpr {
+
+namespace {
+
+struct PtrsAssignable : public ast::WithShortCircuiting {
+	const ast::Type * dst;
+	const ast::TypeEnvironment & typeEnv;
+	int result;
+
+	PtrsAssignable( const ast::Type * dst, const ast::TypeEnvironment & env ) :
+		dst( dst ), typeEnv( env ), result( 0 ) {}
+
+	void previsit( ast::Type * ) { visit_children = false; }
+
+	void postvisit( const ast::EnumInstType * ) {
+		if ( dynamic_cast< const ast::BasicType * >( dst ) ) {
+			// int * = E *, etc. is safe. This isn't technically correct, as each
+			// enum has one basic type that it is compatible with, an that type can
+			// differ from enum to enum. Without replicating GCC's internal logic,
+			// there is no way to know which type this particular enum is compatible
+			// with, so punt on this for now.
+			result = 1;
+		}
+	}
+	void postvisit( const ast::TypeInstType * inst ) {
+		if ( const ast::EqvClass * eqv = typeEnv.lookup( *inst ) ) {
+			if ( eqv->bound ) {
+				// T * = S * for any S depends on the type bound to T
+				result = ptrsAssignable( eqv->bound, dst, typeEnv );
+			}
+		}
+	}
+};
+
+} // namespace
+
+int ptrsAssignable( const ast::Type * src, const ast::Type * dst,
+		const ast::TypeEnvironment & env ) {
+	if ( const ast::TypeInstType * dstAsInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
+		if ( const ast::EqvClass * eqv = env.lookup( *dstAsInst ) ) {
+			return ptrsAssignable( src, eqv->bound, env );
+		}
+	}
+	if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
+		return -1;
+	} else {
+		ast::Pass<PtrsAssignable> visitor( dst, env );
+		src->accept( visitor );
+		return visitor.core.result;
+	}
+
+// see ticket #136 (this should be able to replace the visitor).
+#if 0
+	if ( const ast::TypeInstType * dstAsTypeInst =
+			dynamic_cast< const ast::TypeInstType* >( dst ) ) {
+		if ( const ast::EqvClass * eqv = env.lookup( dstAsTypeInst->get_name() ) ) {
+			return ptrsAssignable( src, eqv->type, env );
+		} // if
+	} // if
+	if ( dynamic_cast< VoidType* >( dst ) ) {
+		// void * = T * for any T is unsafe
+		// xxx - this should be safe, but that currently breaks the build
+		return -1;
+	} else if ( dynamic_cast< EnumInstType * >( src ) ) {
+		if ( dynamic_cast< BasicType * >( dst ) ) {
+			// int * = E *, etc. is safe. This isn't technically correct, as each
+			// enum has one basic type that it is compatible with, an that type can
+			// differ from enum to enum. Without replicating GCC's internal logic,
+			// there is no way to know which type this particular enum is compatible
+			// with, so punt on this for now.
+			return 1;
+		}
+	} else if ( const ast::TypeInstType * typeInstType =
+			dynamic_cast< const ast::TypeInstType * >( src ) ) {
+		if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) {
+			if ( eqv->bound ) {
+				// T * = S * for any S depends on the type bound to T
+				return ptrsAssignable( eqv->bound, dst, env );
+			}
+		}
+	}
+	return 0;
+#endif
+}
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/PtrsCastable.cc
===================================================================
--- src/ResolvExpr/PtrsCastable.cc	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,161 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// PtrsCastable.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 11:48:00 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Dec 11 21:48:33 2019
-// Update Count     : 9
-//
-
-#include "PtrsCastable.hpp"
-
-#include "AST/Decl.hpp"
-#include "AST/Pass.hpp"
-#include "AST/Type.hpp"
-#include "AST/TypeEnvironment.hpp"
-#include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable
-
-namespace ResolvExpr {
-
-namespace {
-	// can this type be cast to an object (1 for yes, -1 for no)
-	int objectCast(
-		const ast::Type * src, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab
-	) {
-		if ( dynamic_cast< const ast::FunctionType * >( src ) ) {
-			return -1;
-		} else if ( auto inst = dynamic_cast< const ast::TypeInstType * >( src ) ) {
-			if ( const ast::NamedTypeDecl * named = symtab.lookupType( inst->name ) ) {
-				if ( auto tyDecl = dynamic_cast< const ast::TypeDecl * >( named ) ) {
-					if ( tyDecl->kind == ast::TypeDecl::Ftype ) {
-						return -1;
-					}
-				}
-			} else if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) {
-				if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
-					return -1;
-				}
-			}
-		}
-
-		return 1;
-	}
-
-	// can this type be cast to a function (inverse of objectCast)
-	int functionCast(
-		const ast::Type * src, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab
-	) {
-		return -1 * objectCast( src, env, symtab );
-	}
-
-	class PtrsCastable : public ast::WithShortCircuiting {
-		const ast::Type * dst;
-		const ast::TypeEnvironment & env;
-		const ast::SymbolTable & symtab;
-	public:
-		int result;
-
-		PtrsCastable(
-			const ast::Type * d, const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
-		: dst( d ), env( e ), symtab( syms ), result( 0 ) {}
-
-		void previsit( const ast::Type * ) { visit_children = false; }
-
-		void postvisit( const ast::VoidType * ) {
-			result = objectCast( dst, env, symtab );
-		}
-
-		void postvisit( const ast::BasicType * ) {
-			result = objectCast( dst, env, symtab );
-		}
-
-		void postvisit( const ast::PointerType * ) {
-			result = objectCast( dst, env, symtab );
-		}
-
-		void postvisit( const ast::ArrayType * ) {
-			result = objectCast( dst, env, symtab );
-		}
-
-		void postvisit( const ast::FunctionType * ) {
-			result = functionCast( dst, env, symtab );
-		}
-
-		void postvisit( const ast::StructInstType * ) {
-			result = objectCast( dst, env, symtab );
-		}
-
-		void postvisit( const ast::UnionInstType * ) {
-			result = objectCast( dst, env, symtab );
-		}
-
-		void postvisit( const ast::EnumInstType * ) {
-			if ( dynamic_cast< const ast::EnumInstType * >( dst ) ) {
-				result = 1;
-			} else if ( auto bt = dynamic_cast< const ast::BasicType * >( dst ) ) {
-				if ( bt->kind == ast::BasicKind::SignedInt ) {
-					result = 0;
-				} else {
-					result = 1;
-				}
-			} else {
-				result = objectCast( dst, env, symtab );
-			}
-		}
-
-		void postvisit( const ast::TraitInstType * ) {}
-
-		void postvisit( const ast::TypeInstType * inst ) {
-			// check trait and destination type are both object or both function
-			result = objectCast( inst, env, symtab ) == objectCast( dst, env, symtab ) ? 1 : -1;
-		}
-
-		void postvisit( const ast::TupleType * ) {
-			result = objectCast( dst, env, symtab );
-		}
-
-		void postvisit( const ast::VarArgsType * ) {
-			result = objectCast( dst, env, symtab );
-		}
-
-		void postvisit( const ast::ZeroType * ) {
-			result = objectCast( dst, env, symtab );
-		}
-
-		void postvisit( const ast::OneType * ) {
-			result = objectCast( dst, env, symtab );
-		}
-
-	};
-} // anonymous namespace
-
-int ptrsCastable(
-	const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
-	const ast::TypeEnvironment & env
-) {
-	if ( auto inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
-		if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) {
-			return ptrsAssignable( src, eqvClass->bound, env );
-		}
-	}
-
-	if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
-		return objectCast( src, env, symtab );
-	} else {
-		return ast::Pass<PtrsCastable>::read( src, dst, env, symtab );
-	}
-}
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/PtrsCastable.cpp
===================================================================
--- src/ResolvExpr/PtrsCastable.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/PtrsCastable.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,161 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// PtrsCastable.cc --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 11:48:00 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Wed Dec 11 21:48:33 2019
+// Update Count     : 9
+//
+
+#include "PtrsCastable.hpp"
+
+#include "AST/Decl.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Type.hpp"
+#include "AST/TypeEnvironment.hpp"
+#include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable
+
+namespace ResolvExpr {
+
+namespace {
+	// can this type be cast to an object (1 for yes, -1 for no)
+	int objectCast(
+		const ast::Type * src, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab
+	) {
+		if ( dynamic_cast< const ast::FunctionType * >( src ) ) {
+			return -1;
+		} else if ( auto inst = dynamic_cast< const ast::TypeInstType * >( src ) ) {
+			if ( const ast::NamedTypeDecl * named = symtab.lookupType( inst->name ) ) {
+				if ( auto tyDecl = dynamic_cast< const ast::TypeDecl * >( named ) ) {
+					if ( tyDecl->kind == ast::TypeDecl::Ftype ) {
+						return -1;
+					}
+				}
+			} else if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) {
+				if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
+					return -1;
+				}
+			}
+		}
+
+		return 1;
+	}
+
+	// can this type be cast to a function (inverse of objectCast)
+	int functionCast(
+		const ast::Type * src, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab
+	) {
+		return -1 * objectCast( src, env, symtab );
+	}
+
+	class PtrsCastable : public ast::WithShortCircuiting {
+		const ast::Type * dst;
+		const ast::TypeEnvironment & env;
+		const ast::SymbolTable & symtab;
+	public:
+		int result;
+
+		PtrsCastable(
+			const ast::Type * d, const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
+		: dst( d ), env( e ), symtab( syms ), result( 0 ) {}
+
+		void previsit( const ast::Type * ) { visit_children = false; }
+
+		void postvisit( const ast::VoidType * ) {
+			result = objectCast( dst, env, symtab );
+		}
+
+		void postvisit( const ast::BasicType * ) {
+			result = objectCast( dst, env, symtab );
+		}
+
+		void postvisit( const ast::PointerType * ) {
+			result = objectCast( dst, env, symtab );
+		}
+
+		void postvisit( const ast::ArrayType * ) {
+			result = objectCast( dst, env, symtab );
+		}
+
+		void postvisit( const ast::FunctionType * ) {
+			result = functionCast( dst, env, symtab );
+		}
+
+		void postvisit( const ast::StructInstType * ) {
+			result = objectCast( dst, env, symtab );
+		}
+
+		void postvisit( const ast::UnionInstType * ) {
+			result = objectCast( dst, env, symtab );
+		}
+
+		void postvisit( const ast::EnumInstType * ) {
+			if ( dynamic_cast< const ast::EnumInstType * >( dst ) ) {
+				result = 1;
+			} else if ( auto bt = dynamic_cast< const ast::BasicType * >( dst ) ) {
+				if ( bt->kind == ast::BasicKind::SignedInt ) {
+					result = 0;
+				} else {
+					result = 1;
+				}
+			} else {
+				result = objectCast( dst, env, symtab );
+			}
+		}
+
+		void postvisit( const ast::TraitInstType * ) {}
+
+		void postvisit( const ast::TypeInstType * inst ) {
+			// check trait and destination type are both object or both function
+			result = objectCast( inst, env, symtab ) == objectCast( dst, env, symtab ) ? 1 : -1;
+		}
+
+		void postvisit( const ast::TupleType * ) {
+			result = objectCast( dst, env, symtab );
+		}
+
+		void postvisit( const ast::VarArgsType * ) {
+			result = objectCast( dst, env, symtab );
+		}
+
+		void postvisit( const ast::ZeroType * ) {
+			result = objectCast( dst, env, symtab );
+		}
+
+		void postvisit( const ast::OneType * ) {
+			result = objectCast( dst, env, symtab );
+		}
+
+	};
+} // anonymous namespace
+
+int ptrsCastable(
+	const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
+	const ast::TypeEnvironment & env
+) {
+	if ( auto inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
+		if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) {
+			return ptrsAssignable( src, eqvClass->bound, env );
+		}
+	}
+
+	if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
+		return objectCast( src, env, symtab );
+	} else {
+		return ast::Pass<PtrsCastable>::read( src, dst, env, symtab );
+	}
+}
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/RenameVars.cc
===================================================================
--- src/ResolvExpr/RenameVars.cc	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,153 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// RenameVars.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 12:05:18 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Thr Jun 20 17:39:00 2019
-// Update Count     : 8
-//
-
-#include <ext/alloc_traits.h>      // for __alloc_traits<>::value_type
-#include <memory>                  // for allocator_traits<>::value_type
-#include <sstream>                 // for operator<<, basic_ostream, ostring...
-#include <utility>                 // for pair
-
-#include "AST/Pass.hpp"
-#include "AST/Type.hpp"
-#include "Common/ScopedMap.h"
-#include "Common/SemanticError.h"  // for SemanticError
-#include "RenameVars.h"
-
-#include "AST/Copy.hpp"
-
-namespace ResolvExpr {
-
-namespace {
-
-class RenamingData {
-	int level = 0;
-	int resetCount = 0;
-
-	int next_expr_id = 1;
-	int next_usage_id = 1;
-	ScopedMap< std::string, std::string > nameMap;
-	ScopedMap< std::string, ast::TypeEnvKey > idMap;
-public:
-	void reset() {
-		level = 0;
-		++resetCount;
-	}
-
-	void nextUsage() {
-		++next_usage_id;
-	}
-
-	const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
-		auto it = idMap.find( type->name );
-		if ( it == idMap.end() ) return type;
-
-		// Unconditionally mutate because map will *always* have different name.
-		ast::TypeInstType * mut = ast::shallowCopy( type );
-		// Reconcile base node since some copies might have been made.
-		mut->base = it->second.base;
-		mut->formal_usage = it->second.formal_usage;
-		mut->expr_id = it->second.expr_id;
-		return mut;
-	}
-
-	const ast::FunctionType * openLevel( const ast::FunctionType * type, RenameMode mode ) {
-		if ( type->forall.empty() ) return type;
-		idMap.beginScope();
-
-		// Load new names from this forall clause and perform renaming.
-		auto mutType = ast::shallowCopy( type );
-		// assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
-		for ( auto & td : mutType->forall ) {
-			auto mut = ast::shallowCopy( td.get() );
-			// assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
-
-			if ( mode == GEN_EXPR_ID ) {
-				mut->expr_id = next_expr_id;
-				mut->formal_usage = -1;
-				++next_expr_id;
-			} else if ( mode == GEN_USAGE ) {
-				assertf( mut->expr_id, "unfilled expression id in generating candidate type" );
-				mut->formal_usage = next_usage_id;
-			} else {
-				assert(false);
-			}
-			idMap[ td->name ] = ast::TypeEnvKey( *mut );
-
-			td = mut;
-		}
-
-		return mutType;
-	}
-
-	void closeLevel( const ast::FunctionType * type ) {
-		if ( type->forall.empty() ) return;
-		idMap.endScope();
-	}
-};
-
-// Global State:
-RenamingData renaming;
-
-struct RenameVars final : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
-	RenameMode mode;
-
-	const ast::FunctionType * previsit( const ast::FunctionType * type ) {
-		return renaming.openLevel( type, mode );
-	}
-
-	/*
-	const ast::StructInstType * previsit( const ast::StructInstType * type ) {
-		return renaming.openLevel( type );
-	}
-	const ast::UnionInstType * previsit( const ast::UnionInstType * type ) {
-		return renaming.openLevel( type );
-	}
-	const ast::TraitInstType * previsit( const ast::TraitInstType * type ) {
-		return renaming.openLevel( type );
-	}
-	*/
-
-	const ast::TypeInstType * previsit( const ast::TypeInstType * type ) {
-		// Do not rename an actual type.
-		if ( mode == GEN_USAGE && !type->formal_usage ) return type;
-		return renaming.rename( type );
-	}
-	void postvisit( const ast::FunctionType * type ) {
-		renaming.closeLevel( type );
-	}
-};
-
-} // namespace
-
-const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) {
-	ast::Pass<RenameVars> renamer;
-	renamer.core.mode = mode;
-	if (mode == GEN_USAGE && reset) {
-		renaming.nextUsage();
-	}
-	return t->accept( renamer );
-}
-
-void resetTyVarRenaming() {
-	renaming.reset();
-	renaming.nextUsage();
-}
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/RenameVars.cpp
===================================================================
--- src/ResolvExpr/RenameVars.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/RenameVars.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,153 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// RenameVars.cpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 12:05:18 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Thr Jun 20 17:39:00 2019
+// Update Count     : 8
+//
+
+#include <ext/alloc_traits.h>         // for __alloc_traits<>::value_type
+#include <memory>                     // for allocator_traits<>::value_type
+#include <sstream>                    // for operator<<, basic_ostream, ostr...
+#include <utility>                    // for pair
+
+#include "AST/Pass.hpp"
+#include "AST/Type.hpp"
+#include "Common/ScopedMap.hpp"
+#include "Common/SemanticError.hpp"   // for SemanticError
+#include "RenameVars.hpp"
+
+#include "AST/Copy.hpp"
+
+namespace ResolvExpr {
+
+namespace {
+
+class RenamingData {
+	int level = 0;
+	int resetCount = 0;
+
+	int next_expr_id = 1;
+	int next_usage_id = 1;
+	ScopedMap< std::string, std::string > nameMap;
+	ScopedMap< std::string, ast::TypeEnvKey > idMap;
+public:
+	void reset() {
+		level = 0;
+		++resetCount;
+	}
+
+	void nextUsage() {
+		++next_usage_id;
+	}
+
+	const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
+		auto it = idMap.find( type->name );
+		if ( it == idMap.end() ) return type;
+
+		// Unconditionally mutate because map will *always* have different name.
+		ast::TypeInstType * mut = ast::shallowCopy( type );
+		// Reconcile base node since some copies might have been made.
+		mut->base = it->second.base;
+		mut->formal_usage = it->second.formal_usage;
+		mut->expr_id = it->second.expr_id;
+		return mut;
+	}
+
+	const ast::FunctionType * openLevel( const ast::FunctionType * type, RenameMode mode ) {
+		if ( type->forall.empty() ) return type;
+		idMap.beginScope();
+
+		// Load new names from this forall clause and perform renaming.
+		auto mutType = ast::shallowCopy( type );
+		// assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
+		for ( auto & td : mutType->forall ) {
+			auto mut = ast::shallowCopy( td.get() );
+			// assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
+
+			if ( mode == GEN_EXPR_ID ) {
+				mut->expr_id = next_expr_id;
+				mut->formal_usage = -1;
+				++next_expr_id;
+			} else if ( mode == GEN_USAGE ) {
+				assertf( mut->expr_id, "unfilled expression id in generating candidate type" );
+				mut->formal_usage = next_usage_id;
+			} else {
+				assert(false);
+			}
+			idMap[ td->name ] = ast::TypeEnvKey( *mut );
+
+			td = mut;
+		}
+
+		return mutType;
+	}
+
+	void closeLevel( const ast::FunctionType * type ) {
+		if ( type->forall.empty() ) return;
+		idMap.endScope();
+	}
+};
+
+// Global State:
+RenamingData renaming;
+
+struct RenameVars final : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
+	RenameMode mode;
+
+	const ast::FunctionType * previsit( const ast::FunctionType * type ) {
+		return renaming.openLevel( type, mode );
+	}
+
+	/*
+	const ast::StructInstType * previsit( const ast::StructInstType * type ) {
+		return renaming.openLevel( type );
+	}
+	const ast::UnionInstType * previsit( const ast::UnionInstType * type ) {
+		return renaming.openLevel( type );
+	}
+	const ast::TraitInstType * previsit( const ast::TraitInstType * type ) {
+		return renaming.openLevel( type );
+	}
+	*/
+
+	const ast::TypeInstType * previsit( const ast::TypeInstType * type ) {
+		// Do not rename an actual type.
+		if ( mode == GEN_USAGE && !type->formal_usage ) return type;
+		return renaming.rename( type );
+	}
+	void postvisit( const ast::FunctionType * type ) {
+		renaming.closeLevel( type );
+	}
+};
+
+} // namespace
+
+const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) {
+	ast::Pass<RenameVars> renamer;
+	renamer.core.mode = mode;
+	if (mode == GEN_USAGE && reset) {
+		renaming.nextUsage();
+	}
+	return t->accept( renamer );
+}
+
+void resetTyVarRenaming() {
+	renaming.reset();
+	renaming.nextUsage();
+}
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/RenameVars.h
===================================================================
--- src/ResolvExpr/RenameVars.h	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,39 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// RenameVars.h --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 12:10:28 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:33:54 2017
-// Update Count     : 4
-//
-
-#pragma once
-
-namespace ast {
-	class Type;
-}
-
-namespace ResolvExpr {
-
-enum RenameMode {
-	GEN_USAGE, // for type in VariableExpr
-	GEN_EXPR_ID // for type in decl
-};
-const ast::Type * renameTyVars( const ast::Type *, RenameMode mode = GEN_USAGE, bool reset = true );
-
-/// Resets internal state of renamer to avoid overflow.
-void resetTyVarRenaming();
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/RenameVars.hpp
===================================================================
--- src/ResolvExpr/RenameVars.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/RenameVars.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,39 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// RenameVars.hpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 12:10:28 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sat Jul 22 09:33:54 2017
+// Update Count     : 4
+//
+
+#pragma once
+
+namespace ast {
+	class Type;
+}
+
+namespace ResolvExpr {
+
+enum RenameMode {
+	GEN_USAGE, // for type in VariableExpr
+	GEN_EXPR_ID // for type in decl
+};
+const ast::Type * renameTyVars( const ast::Type *, RenameMode mode = GEN_USAGE, bool reset = true );
+
+/// Resets internal state of renamer to avoid overflow.
+void resetTyVarRenaming();
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/ResolveTypeof.cc
===================================================================
--- src/ResolvExpr/ResolveTypeof.cc	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,188 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// ResolveTypeof.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 12:12:20 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Mar 16 16:09:00 2022
-// Update Count     : 4
-//
-
-#include "ResolveTypeof.h"
-
-#include <cassert>  // for assert
-
-#include "AST/CVQualifiers.hpp"
-#include "AST/Node.hpp"
-#include "AST/Pass.hpp"
-#include "AST/TranslationUnit.hpp"
-#include "AST/Type.hpp"
-#include "AST/TypeEnvironment.hpp"
-#include "Common/utility.h"       // for copy
-#include "InitTweak/InitTweak.h"  // for isConstExpr
-#include "RenameVars.h"
-#include "Resolver.h"  // for resolveInVoidContext
-#include "SymTab/Mangler.h"
-
-namespace ResolvExpr {
-
-namespace {
-
-struct ResolveTypeof : public ast::WithShortCircuiting {
-	const ResolveContext & context;
-
-	ResolveTypeof( const ResolveContext & context ) : context( context ) {}
-
-	void previsit( const ast::TypeofType * ) { visit_children = false; }
-
-	const ast::Type * postvisit( const ast::TypeofType * typeofType ) {
-		// pass on null expression
-		if ( ! typeofType->expr ) return typeofType;
-
-		ast::ptr< ast::Type > newType;
-		if ( auto tyExpr = typeofType->expr.as< ast::TypeExpr >() ) {
-			// typeof wrapping type
-			newType = tyExpr->type;
-		} else {
-			// typeof wrapping expression
-			ast::TypeEnvironment dummy;
-			ast::ptr< ast::Expr > newExpr =
-				resolveInVoidContext( typeofType->expr, context, dummy );
-			assert( newExpr->result && ! newExpr->result->isVoid() );
-			newType = newExpr->result;
-		}
-
-		// clear qualifiers for base, combine with typeoftype quals regardless
-		if ( typeofType->kind == ast::TypeofType::Basetypeof ) {
-			// replace basetypeof(<enum>) by int
-			if ( newType.as< ast::EnumInstType >() ) {
-				newType = new ast::BasicType(
-					ast::BasicKind::SignedInt, newType->qualifiers, copy(newType->attributes) );
-			}
-			reset_qualifiers(
-				newType,
-				( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers );
-		} else {
-			add_qualifiers( newType, typeofType->qualifiers );
-		}
-
-		return newType.release();
-	}
-};
-
-} // anonymous namespace
-
-const ast::Type * resolveTypeof( const ast::Type * type , const ResolveContext & context ) {
-	ast::Pass< ResolveTypeof > mutator( context );
-	return type->accept( mutator );
-}
-
-struct FixArrayDimension {
-	const ResolveContext & context;
-	FixArrayDimension(const ResolveContext & context) : context( context ) {}
-
-	const ast::ArrayType * previsit (const ast::ArrayType * arrayType) {
-		if (!arrayType->dimension) return arrayType;
-		auto mutType = mutate(arrayType);
-		auto globalSizeType = context.global.sizeType;
-		ast::ptr<ast::Type> sizetype = globalSizeType ? globalSizeType : new ast::BasicType( ast::BasicKind::LongUnsignedInt );
-		mutType->dimension = findSingleExpression(arrayType->dimension, sizetype, context );
-
-		if (InitTweak::isConstExpr(mutType->dimension)) {
-			mutType->isVarLen = ast::LengthFlag::FixedLen;
-		}
-		else {
-			mutType->isVarLen = ast::LengthFlag::VariableLen;
-		}
-		return mutType;
-	}
-};
-
-const ast::Type * fixArrayType( const ast::Type * type, const ResolveContext & context ) {
-	ast::Pass<FixArrayDimension> visitor(context);
-	return type->accept(visitor);
-}
-
-const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & context ) {
-	if ( decl->isTypeFixed ) {
-		return decl;
-	}
-
-	auto mutDecl = mutate(decl);
-	fixObjectInit(decl, context);
-	{
-		auto resolvedType = resolveTypeof(decl->type, context);
-		resolvedType = fixArrayType(resolvedType, context);
-		mutDecl->type = resolvedType;
-	}
-
-	// Do not mangle unnamed variables.
-	if ( !mutDecl->name.empty() ) {
-		mutDecl->mangleName = Mangle::mangle(mutDecl);
-	}
-
-	mutDecl->type = renameTyVars(mutDecl->type, RenameMode::GEN_EXPR_ID);
-	mutDecl->isTypeFixed = true;
-	return mutDecl;
-}
-
-const ast::ObjectDecl *fixObjectInit(
-		const ast::ObjectDecl *decl, const ResolveContext &context) {
-	if ( decl->isTypeFixed ) {
-		return decl;
-	}
-
-	if ( auto listInit = decl->init.as<ast::ListInit>() ) {
-		for ( size_t k = 0; k < listInit->designations.size(); k++ ) {
-			const ast::Designation *des = listInit->designations[k].get();
-			// Desination here
-			ast::Designation * newDesignation = new ast::Designation(des->location);
-			std::deque<ast::ptr<ast::Expr>> newDesignators;
-
-			for ( ast::ptr<ast::Expr> designator : des->designators ) {
-				// Stupid flag variable for development, to be removed
-				if ( const ast::NameExpr * designatorName = designator.as<ast::NameExpr>() ) {
-					auto candidates = context.symtab.lookupId(designatorName->name);
-					// Does not work for the overloading case currently
-					// assert( candidates.size() == 1 );
-					if ( candidates.size() != 1 ) return decl;
-					auto candidate = candidates.at(0);
-					if ( const ast::EnumInstType * enumInst = dynamic_cast<const ast::EnumInstType *>(candidate.id->get_type())) {
-						// determine that is an enumInst, swap it with its const value
-						assert( candidates.size() == 1 );
-						const ast::EnumDecl * baseEnum = enumInst->base;
-						// Need to iterate over all enum value to find the initializer to swap
-						for ( size_t m = 0; m < baseEnum->members.size(); ++m ) {
-							const ast::ObjectDecl * mem = baseEnum->members.at(m).as<const ast::ObjectDecl>();
-							if ( baseEnum->members.at(m)->name == designatorName->name ) {
-								assert( mem );
-								newDesignators.push_back( ast::ConstantExpr::from_int(designator->location, m) );
-								break;
-							}
-						}
-					} else {
-						newDesignators.push_back( des->designators.at(0) );
-					}
-				} else {
-					newDesignators.push_back( des->designators.at(0) );
-				}
-			}
-			newDesignation->designators = newDesignators;
-			listInit = ast::mutate_field_index(listInit, &ast::ListInit::designations, k, newDesignation);
-		}
-	}
-	return decl;
-}
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/ResolveTypeof.cpp
===================================================================
--- src/ResolvExpr/ResolveTypeof.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/ResolveTypeof.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,188 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ResolveTypeof.cpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 12:12:20 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Mar 16 16:09:00 2022
+// Update Count     : 4
+//
+
+#include "ResolveTypeof.hpp"
+
+#include <cassert>                  // for assert
+
+#include "AST/CVQualifiers.hpp"
+#include "AST/Node.hpp"
+#include "AST/Pass.hpp"
+#include "AST/TranslationUnit.hpp"
+#include "AST/Type.hpp"
+#include "AST/TypeEnvironment.hpp"
+#include "Common/Utility.hpp"       // for copy
+#include "InitTweak/InitTweak.hpp"  // for isConstExpr
+#include "RenameVars.hpp"
+#include "Resolver.hpp"             // for resolveInVoidContext
+#include "SymTab/Mangler.hpp"
+
+namespace ResolvExpr {
+
+namespace {
+
+struct ResolveTypeof : public ast::WithShortCircuiting {
+	const ResolveContext & context;
+
+	ResolveTypeof( const ResolveContext & context ) : context( context ) {}
+
+	void previsit( const ast::TypeofType * ) { visit_children = false; }
+
+	const ast::Type * postvisit( const ast::TypeofType * typeofType ) {
+		// pass on null expression
+		if ( ! typeofType->expr ) return typeofType;
+
+		ast::ptr< ast::Type > newType;
+		if ( auto tyExpr = typeofType->expr.as< ast::TypeExpr >() ) {
+			// typeof wrapping type
+			newType = tyExpr->type;
+		} else {
+			// typeof wrapping expression
+			ast::TypeEnvironment dummy;
+			ast::ptr< ast::Expr > newExpr =
+				resolveInVoidContext( typeofType->expr, context, dummy );
+			assert( newExpr->result && ! newExpr->result->isVoid() );
+			newType = newExpr->result;
+		}
+
+		// clear qualifiers for base, combine with typeoftype quals regardless
+		if ( typeofType->kind == ast::TypeofType::Basetypeof ) {
+			// replace basetypeof(<enum>) by int
+			if ( newType.as< ast::EnumInstType >() ) {
+				newType = new ast::BasicType(
+					ast::BasicKind::SignedInt, newType->qualifiers, copy(newType->attributes) );
+			}
+			reset_qualifiers(
+				newType,
+				( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers );
+		} else {
+			add_qualifiers( newType, typeofType->qualifiers );
+		}
+
+		return newType.release();
+	}
+};
+
+} // anonymous namespace
+
+const ast::Type * resolveTypeof( const ast::Type * type , const ResolveContext & context ) {
+	ast::Pass< ResolveTypeof > mutator( context );
+	return type->accept( mutator );
+}
+
+struct FixArrayDimension {
+	const ResolveContext & context;
+	FixArrayDimension(const ResolveContext & context) : context( context ) {}
+
+	const ast::ArrayType * previsit (const ast::ArrayType * arrayType) {
+		if (!arrayType->dimension) return arrayType;
+		auto mutType = mutate(arrayType);
+		auto globalSizeType = context.global.sizeType;
+		ast::ptr<ast::Type> sizetype = globalSizeType ? globalSizeType : new ast::BasicType( ast::BasicKind::LongUnsignedInt );
+		mutType->dimension = findSingleExpression(arrayType->dimension, sizetype, context );
+
+		if (InitTweak::isConstExpr(mutType->dimension)) {
+			mutType->isVarLen = ast::LengthFlag::FixedLen;
+		}
+		else {
+			mutType->isVarLen = ast::LengthFlag::VariableLen;
+		}
+		return mutType;
+	}
+};
+
+const ast::Type * fixArrayType( const ast::Type * type, const ResolveContext & context ) {
+	ast::Pass<FixArrayDimension> visitor(context);
+	return type->accept(visitor);
+}
+
+const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & context ) {
+	if ( decl->isTypeFixed ) {
+		return decl;
+	}
+
+	auto mutDecl = mutate(decl);
+	fixObjectInit(decl, context);
+	{
+		auto resolvedType = resolveTypeof(decl->type, context);
+		resolvedType = fixArrayType(resolvedType, context);
+		mutDecl->type = resolvedType;
+	}
+
+	// Do not mangle unnamed variables.
+	if ( !mutDecl->name.empty() ) {
+		mutDecl->mangleName = Mangle::mangle(mutDecl);
+	}
+
+	mutDecl->type = renameTyVars(mutDecl->type, RenameMode::GEN_EXPR_ID);
+	mutDecl->isTypeFixed = true;
+	return mutDecl;
+}
+
+const ast::ObjectDecl *fixObjectInit(
+		const ast::ObjectDecl *decl, const ResolveContext &context) {
+	if ( decl->isTypeFixed ) {
+		return decl;
+	}
+
+	if ( auto listInit = decl->init.as<ast::ListInit>() ) {
+		for ( size_t k = 0; k < listInit->designations.size(); k++ ) {
+			const ast::Designation *des = listInit->designations[k].get();
+			// Desination here
+			ast::Designation * newDesignation = new ast::Designation(des->location);
+			std::deque<ast::ptr<ast::Expr>> newDesignators;
+
+			for ( ast::ptr<ast::Expr> designator : des->designators ) {
+				// Stupid flag variable for development, to be removed
+				if ( const ast::NameExpr * designatorName = designator.as<ast::NameExpr>() ) {
+					auto candidates = context.symtab.lookupId(designatorName->name);
+					// Does not work for the overloading case currently
+					// assert( candidates.size() == 1 );
+					if ( candidates.size() != 1 ) return decl;
+					auto candidate = candidates.at(0);
+					if ( const ast::EnumInstType * enumInst = dynamic_cast<const ast::EnumInstType *>(candidate.id->get_type())) {
+						// determine that is an enumInst, swap it with its const value
+						assert( candidates.size() == 1 );
+						const ast::EnumDecl * baseEnum = enumInst->base;
+						// Need to iterate over all enum value to find the initializer to swap
+						for ( size_t m = 0; m < baseEnum->members.size(); ++m ) {
+							const ast::ObjectDecl * mem = baseEnum->members.at(m).as<const ast::ObjectDecl>();
+							if ( baseEnum->members.at(m)->name == designatorName->name ) {
+								assert( mem );
+								newDesignators.push_back( ast::ConstantExpr::from_int(designator->location, m) );
+								break;
+							}
+						}
+					} else {
+						newDesignators.push_back( des->designators.at(0) );
+					}
+				} else {
+					newDesignators.push_back( des->designators.at(0) );
+				}
+			}
+			newDesignation->designators = newDesignators;
+			listInit = ast::mutate_field_index(listInit, &ast::ListInit::designations, k, newDesignation);
+		}
+	}
+	return decl;
+}
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/ResolveTypeof.h
===================================================================
--- src/ResolvExpr/ResolveTypeof.h	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,38 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// ResolveTypeof.h --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 12:14:53 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Mar 16 11:33:00 2022
-// Update Count     : 4
-//
-
-#pragma once
-
-namespace ast {
-	class Type;
-	class ObjectDecl;
-}
-
-namespace ResolvExpr {
-
-struct ResolveContext;
-
-const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & );
-const ast::Type * fixArrayType( const ast::Type *, const ResolveContext & );
-const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & );
-const ast::ObjectDecl * fixObjectInit( const ast::ObjectDecl * decl , const ResolveContext & );
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/ResolveTypeof.hpp
===================================================================
--- src/ResolvExpr/ResolveTypeof.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/ResolveTypeof.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,38 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ResolveTypeof.hpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 12:14:53 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Mar 16 11:33:00 2022
+// Update Count     : 4
+//
+
+#pragma once
+
+namespace ast {
+	class Type;
+	class ObjectDecl;
+}
+
+namespace ResolvExpr {
+
+struct ResolveContext;
+
+const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & );
+const ast::Type * fixArrayType( const ast::Type *, const ResolveContext & );
+const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & );
+const ast::ObjectDecl * fixObjectInit( const ast::ObjectDecl * decl , const ResolveContext & );
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,1269 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Resolver.cc --
-//
-// Author           : Aaron B. Moss
-// Created On       : Sun May 17 12:17:01 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Dec 14 18:44:43 2023
-// Update Count     : 251
-//
-
-#include <cassert>                       // for strict_dynamic_cast, assert
-#include <memory>                        // for allocator, allocator_traits<...
-#include <tuple>                         // for get
-#include <vector>                        // for vector
-
-#include "Candidate.hpp"
-#include "CandidateFinder.hpp"
-#include "CurrentObject.h"               // for CurrentObject
-#include "RenameVars.h"                  // for RenameVars, global_renamer
-#include "Resolver.h"
-#include "ResolveTypeof.h"
-#include "ResolveMode.hpp"               // for ResolveMode
-#include "typeops.h"                     // for extractResultType
-#include "Unify.h"                       // for unify
-#include "CompilationState.hpp"
-#include "AST/Decl.hpp"
-#include "AST/Init.hpp"
-#include "AST/Pass.hpp"
-#include "AST/Print.hpp"
-#include "AST/SymbolTable.hpp"
-#include "AST/Type.hpp"
-#include "Common/Eval.h"                 // for eval
-#include "Common/Iterate.hpp"            // for group_iterate
-#include "Common/SemanticError.h"        // for SemanticError
-#include "Common/Stats/ResolveTime.h"    // for ResolveTime::start(), ResolveTime::stop()
-#include "Common/ToString.hpp"           // for toCString
-#include "Common/UniqueName.h"           // for UniqueName
-#include "InitTweak/GenInit.h"
-#include "InitTweak/InitTweak.h"         // for isIntrinsicSingleArgCallStmt
-#include "SymTab/Mangler.h"              // for Mangler
-#include "Tuples/Tuples.h"
-#include "Validate/FindSpecialDecls.h"   // for SizeType
-
-using namespace std;
-
-namespace ResolvExpr {
-
-namespace {
-	/// Finds deleted expressions in an expression tree
-	struct DeleteFinder final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder> {
-		const ast::DeletedExpr * result = nullptr;
-
-		void previsit( const ast::DeletedExpr * expr ) {
-			if ( result ) { visit_children = false; }
-			else { result = expr; }
-		}
-
-		void previsit( const ast::Expr * expr ) {
-			if ( result ) { visit_children = false; }
-			if (expr->inferred.hasParams()) {
-				for (auto & imp : expr->inferred.inferParams() ) {
-					imp.second.expr->accept(*visitor);
-				}
-			}
-		}
-	};
-
-	struct ResolveDesignators final : public ast::WithShortCircuiting {
-		ResolveContext& context;
-		bool result = false;
-
-		ResolveDesignators( ResolveContext& _context ): context(_context) {};
-
-		void previsit( const ast::Node * ) {
-			// short circuit if we already know there are designations
-			if ( result ) visit_children = false;
-		}
-
-		void previsit( const ast::Designation * des ) {
-			if ( result ) visit_children = false;
-			else if ( ! des->designators.empty() ) {
-				if ( (des->designators.size() == 1) ) {
-					const ast::Expr * designator = des->designators.at(0);
-					if ( const ast::NameExpr * designatorName = dynamic_cast<const ast::NameExpr *>(designator) ) {
-						auto candidates = context.symtab.lookupId(designatorName->name);
-						for ( auto candidate : candidates ) {
-							if ( dynamic_cast<const ast::EnumInstType *>(candidate.id->get_type()) ) {
-								result = true;
-								break;
-							}
-						}
-					}
-				}
-				visit_children = false;
-			}
-		}
-	};
-} // anonymous namespace
-
-/// Check if this expression is or includes a deleted expression
-const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
-	return ast::Pass<DeleteFinder>::read( expr );
-}
-
-namespace {
-	/// always-accept candidate filter
-	bool anyCandidate( const Candidate & ) { return true; }
-
-	/// Calls the CandidateFinder and finds the single best candidate
-	CandidateRef findUnfinishedKindExpression(
-		const ast::Expr * untyped, const ResolveContext & context, const std::string & kind,
-		std::function<bool(const Candidate &)> pred = anyCandidate, ResolveMode mode = {}
-	) {
-		if ( ! untyped ) return nullptr;
-
-		// xxx - this isn't thread-safe, but should work until we parallelize the resolver
-		static unsigned recursion_level = 0;
-
-		++recursion_level;
-		ast::TypeEnvironment env;
-		CandidateFinder finder( context, env );
-		finder.allowVoid = true;
-		finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
-		--recursion_level;
-
-		// produce a filtered list of candidates
-		CandidateList candidates;
-		for ( auto & cand : finder.candidates ) {
-			if ( pred( *cand ) ) { candidates.emplace_back( cand ); }
-		}
-
-		// produce invalid error if no candidates
-		if ( candidates.empty() ) {
-			SemanticError( untyped,
-				toString( "No reasonable alternatives for ", kind, (kind != "" ? " " : ""),
-				"expression: ") );
-		}
-
-		// search for cheapest candidate
-		CandidateList winners;
-		bool seen_undeleted = false;
-		for ( CandidateRef & cand : candidates ) {
-			int c = winners.empty() ? -1 : cand->cost.compare( winners.front()->cost );
-
-			if ( c > 0 ) continue;  // skip more expensive than winner
-
-			if ( c < 0 ) {
-				// reset on new cheapest
-				seen_undeleted = ! findDeletedExpr( cand->expr );
-				winners.clear();
-			} else /* if ( c == 0 ) */ {
-				if ( findDeletedExpr( cand->expr ) ) {
-					// skip deleted expression if already seen one equivalent-cost not
-					if ( seen_undeleted ) continue;
-				} else if ( ! seen_undeleted ) {
-					// replace list of equivalent-cost deleted expressions with one non-deleted
-					winners.clear();
-					seen_undeleted = true;
-				}
-			}
-
-			winners.emplace_back( std::move( cand ) );
-		}
-
-		// promote candidate.cvtCost to .cost
-		// promoteCvtCost( winners );
-
-		// produce ambiguous errors, if applicable
-		if ( winners.size() != 1 ) {
-			std::ostringstream stream;
-			stream << "Cannot choose between " << winners.size() << " alternatives for "
-				<< kind << (kind != "" ? " " : "") << "expression\n";
-			ast::print( stream, untyped );
-			stream << " Alternatives are:\n";
-			print( stream, winners, 1 );
-			SemanticError( untyped->location, stream.str() );
-		}
-
-		// single selected choice
-		CandidateRef & choice = winners.front();
-
-		// fail on only expression deleted
-		if ( ! seen_undeleted ) {
-			SemanticError( untyped->location, choice->expr.get(), "Unique best alternative "
-			"includes deleted identifier in " );
-		}
-
-		return std::move( choice );
-	}
-
-	/// Strips extraneous casts out of an expression
-	struct StripCasts final {
-		const ast::Expr * postvisit( const ast::CastExpr * castExpr ) {
-			if (
-				castExpr->isGenerated == ast::GeneratedCast
-				&& typesCompatible( castExpr->arg->result, castExpr->result )
-			) {
-				// generated cast is the same type as its argument, remove it after keeping env
-				return ast::mutate_field(
-					castExpr->arg.get(), &ast::Expr::env, castExpr->env );
-			}
-			return castExpr;
-		}
-
-		static void strip( ast::ptr< ast::Expr > & expr ) {
-			ast::Pass< StripCasts > stripper;
-			expr = expr->accept( stripper );
-		}
-	};
-
-	/// Swaps argument into expression pointer, saving original environment
-	void swap_and_save_env( ast::ptr< ast::Expr > & expr, const ast::Expr * newExpr ) {
-		ast::ptr< ast::TypeSubstitution > env = expr->env;
-		expr.set_and_mutate( newExpr )->env = env;
-	}
-
-	/// Removes cast to type of argument (unlike StripCasts, also handles non-generated casts)
-	void removeExtraneousCast( ast::ptr<ast::Expr> & expr ) {
-		if ( const ast::CastExpr * castExpr = expr.as< ast::CastExpr >() ) {
-			if ( typesCompatible( castExpr->arg->result, castExpr->result ) ) {
-				// cast is to the same type as its argument, remove it
-				swap_and_save_env( expr, castExpr->arg );
-			}
-		}
-	}
-
-} // anonymous namespace
-
-/// Establish post-resolver invariants for expressions
-void finishExpr(
-	ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env,
-	const ast::TypeSubstitution * oldenv = nullptr
-) {
-	// set up new type substitution for expression
-	ast::ptr< ast::TypeSubstitution > newenv =
-		 oldenv ? oldenv : new ast::TypeSubstitution{};
-	env.writeToSubstitution( *newenv.get_and_mutate() );
-	expr.get_and_mutate()->env = std::move( newenv );
-	// remove unncecessary casts
-	StripCasts::strip( expr );
-}
-
-ast::ptr< ast::Expr > resolveInVoidContext(
-	const ast::Expr * expr, const ResolveContext & context,
-	ast::TypeEnvironment & env
-) {
-	assertf( expr, "expected a non-null expression" );
-
-	// set up and resolve expression cast to void
-	ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr };
-	CandidateRef choice = findUnfinishedKindExpression(
-		untyped, context, "", anyCandidate, ResolveMode::withAdjustment() );
-
-	// a cast expression has either 0 or 1 interpretations (by language rules);
-	// if 0, an exception has already been thrown, and this code will not run
-	const ast::CastExpr * castExpr = choice->expr.strict_as< ast::CastExpr >();
-	env = std::move( choice->env );
-
-	return castExpr->arg;
-}
-
-/// Resolve `untyped` to the expression whose candidate is the best match for a `void`
-/// context.
-ast::ptr< ast::Expr > findVoidExpression(
-	const ast::Expr * untyped, const ResolveContext & context
-) {
-	ast::TypeEnvironment env;
-	ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, context, env );
-	finishExpr( newExpr, env, untyped->env );
-	return newExpr;
-}
-
-namespace {
-	/// resolve `untyped` to the expression whose candidate satisfies `pred` with the
-	/// lowest cost, returning the resolved version
-	ast::ptr< ast::Expr > findKindExpression(
-		const ast::Expr * untyped, const ResolveContext & context,
-		std::function<bool(const Candidate &)> pred = anyCandidate,
-		const std::string & kind = "", ResolveMode mode = {}
-	) {
-		if ( ! untyped ) return {};
-		CandidateRef choice =
-			findUnfinishedKindExpression( untyped, context, kind, pred, mode );
-		ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env );
-		return std::move( choice->expr );
-	}
-
-	/// Resolve `untyped` to the single expression whose candidate is the best match
-	ast::ptr< ast::Expr > findSingleExpression(
-		const ast::Expr * untyped, const ResolveContext & context
-	) {
-		Stats::ResolveTime::start( untyped );
-		auto res = findKindExpression( untyped, context );
-		Stats::ResolveTime::stop();
-		return res;
-	}
-} // anonymous namespace
-
-ast::ptr< ast::Expr > findSingleExpression(
-	const ast::Expr * untyped, const ast::Type * type,
-	const ResolveContext & context
-) {
-	assert( untyped && type );
-	ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
-	ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, context );
-	removeExtraneousCast( newExpr );
-	return newExpr;
-}
-
-namespace {
-	bool structOrUnion( const Candidate & i ) {
-		const ast::Type * t = i.expr->result->stripReferences();
-		return dynamic_cast< const ast::StructInstType * >( t ) || dynamic_cast< const ast::UnionInstType * >( t );
-	}
-	/// Predicate for "Candidate has integral type"
-	bool hasIntegralType( const Candidate & i ) {
-		const ast::Type * type = i.expr->result;
-
-		if ( auto bt = dynamic_cast< const ast::BasicType * >( type ) ) {
-			return bt->isInteger();
-		} else if (
-			dynamic_cast< const ast::EnumInstType * >( type )
-			|| dynamic_cast< const ast::ZeroType * >( type )
-			|| dynamic_cast< const ast::OneType * >( type )
-		) {
-			return true;
-		} else return false;
-	}
-
-	/// Resolve `untyped` as an integral expression, returning the resolved version
-	ast::ptr< ast::Expr > findIntegralExpression(
-		const ast::Expr * untyped, const ResolveContext & context
-	) {
-		return findKindExpression( untyped, context, hasIntegralType, "condition" );
-	}
-
-	ast::ptr< ast::Expr > findCondExpression(
-		const ast::Expr * untyped, const ResolveContext & context
-	) {
-		if ( nullptr == untyped ) return untyped;
-		ast::ptr<ast::Expr> condExpr = createCondExpr( untyped );
-		return findIntegralExpression( condExpr, context );
-	}
-
-	/// check if a type is a character type
-	bool isCharType( const ast::Type * t ) {
-		if ( auto bt = dynamic_cast< const ast::BasicType * >( t ) ) {
-			return bt->kind == ast::BasicKind::Char
-				|| bt->kind == ast::BasicKind::SignedChar
-				|| bt->kind == ast::BasicKind::UnsignedChar;
-		}
-		return false;
-	}
-
-	/// Advance a type itertor to the next mutex parameter
-	template<typename Iter>
-	inline bool nextMutex( Iter & it, const Iter & end ) {
-		while ( it != end && ! (*it)->is_mutex() ) { ++it; }
-		return it != end;
-	}
-} // anonymous namespace
-
-class Resolver final
-: public ast::WithSymbolTable, public ast::WithGuards,
-  public ast::WithVisitorRef<Resolver>, public ast::WithShortCircuiting,
-  public ast::WithStmtsToAdd<> {
-
-	ast::ptr< ast::Type > functionReturn = nullptr;
-	ast::CurrentObject currentObject;
-	// for work previously in GenInit
-	static InitTweak::ManagedTypes managedTypes;
-	ResolveContext context;
-
-	bool inEnumDecl = false;
-
-public:
-	static size_t traceId;
-	Resolver( const ast::TranslationGlobal & global ) :
-		ast::WithSymbolTable(ast::SymbolTable::ErrorDetection::ValidateOnAdd),
-		context{ symtab, global } {}
-	Resolver( const ResolveContext & context ) :
-		ast::WithSymbolTable{ context.symtab },
-		context{ symtab, context.global } {}
-
-	const ast::FunctionDecl * previsit( const ast::FunctionDecl * );
-	const ast::FunctionDecl * postvisit( const ast::FunctionDecl * );
-	const ast::ObjectDecl * previsit( const ast::ObjectDecl * );
-	void previsit( const ast::AggregateDecl * );
-	void previsit( const ast::StructDecl * );
-	void previsit( const ast::EnumDecl * );
-	const ast::StaticAssertDecl * previsit( const ast::StaticAssertDecl * );
-
-	const ast::ArrayType * previsit( const ast::ArrayType * );
-	const ast::PointerType * previsit( const ast::PointerType * );
-
-	const ast::ExprStmt *        previsit( const ast::ExprStmt * );
-	const ast::AsmExpr *         previsit( const ast::AsmExpr * );
-	const ast::AsmStmt *         previsit( const ast::AsmStmt * );
-	const ast::IfStmt *          previsit( const ast::IfStmt * );
-	const ast::WhileDoStmt *     previsit( const ast::WhileDoStmt * );
-	const ast::ForStmt *         previsit( const ast::ForStmt * );
-	const ast::SwitchStmt *      previsit( const ast::SwitchStmt * );
-	const ast::CaseClause *      previsit( const ast::CaseClause * );
-	const ast::BranchStmt *      previsit( const ast::BranchStmt * );
-	const ast::ReturnStmt *      previsit( const ast::ReturnStmt * );
-	const ast::ThrowStmt *       previsit( const ast::ThrowStmt * );
-	const ast::CatchClause *     previsit( const ast::CatchClause * );
-	const ast::CatchClause *     postvisit( const ast::CatchClause * );
-	const ast::WaitForStmt *     previsit( const ast::WaitForStmt * );
-	const ast::WithStmt *        previsit( const ast::WithStmt * );
-
-	const ast::SingleInit *      previsit( const ast::SingleInit * );
-	const ast::ListInit *        previsit( const ast::ListInit * );
-	const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
-
-	void resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd);
-	bool shouldGenCtorInit( const ast::ObjectDecl * ) const;
-
-	void beginScope() { managedTypes.beginScope(); }
-	void endScope() { managedTypes.endScope(); }
-	bool on_error(ast::ptr<ast::Decl> & decl);
-};
-// size_t Resolver::traceId = Stats::Heap::new_stacktrace_id("Resolver");
-
-InitTweak::ManagedTypes Resolver::managedTypes;
-
-void resolve( ast::TranslationUnit& translationUnit ) {
-	ast::Pass< Resolver >::run( translationUnit, translationUnit.global );
-}
-
-ast::ptr< ast::Init > resolveCtorInit(
-	const ast::ConstructorInit * ctorInit, const ResolveContext & context
-) {
-	assert( ctorInit );
-	ast::Pass< Resolver > resolver( context );
-	return ctorInit->accept( resolver );
-}
-
-const ast::Expr * resolveStmtExpr(
-	const ast::StmtExpr * stmtExpr, const ResolveContext & context
-) {
-	assert( stmtExpr );
-	ast::Pass< Resolver > resolver( context );
-	auto ret = mutate(stmtExpr->accept(resolver));
-	strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult();
-	return ret;
-}
-
-namespace {
-	const ast::Attribute * handleAttribute(const CodeLocation & loc, const ast::Attribute * attr, const ResolveContext & context) {
-		std::string name = attr->normalizedName();
-		if (name == "constructor" || name == "destructor") {
-			if (attr->params.size() == 1) {
-				auto arg = attr->params.front();
-				auto resolved = ResolvExpr::findSingleExpression( arg, new ast::BasicType( ast::BasicKind::LongLongSignedInt ), context );
-				auto result = eval(arg);
-
-				auto mutAttr = mutate(attr);
-				mutAttr->params.front() = resolved;
-				if (! result.hasKnownValue) {
-					SemanticWarning(loc, Warning::GccAttributes,
-						toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) );
-				}
-				else {
-					auto priority = result.knownValue;
-					if (priority < 101) {
-						SemanticWarning(loc, Warning::GccAttributes,
-							toCString( name, " priorities from 0 to 100 are reserved for the implementation" ) );
-					} else if (priority < 201 && ! buildingLibrary()) {
-						SemanticWarning(loc, Warning::GccAttributes,
-							toCString( name, " priorities from 101 to 200 are reserved for the implementation" ) );
-					}
-				}
-				return mutAttr;
-			} else if (attr->params.size() > 1) {
-				SemanticWarning(loc, Warning::GccAttributes, toCString( "too many arguments to ", name, " attribute" ) );
-			} else {
-				SemanticWarning(loc, Warning::GccAttributes, toCString( "too few arguments to ", name, " attribute" ) );
-			}
-		}
-		return attr;
-	}
-}
-
-const ast::FunctionDecl * Resolver::previsit( const ast::FunctionDecl * functionDecl ) {
-	GuardValue( functionReturn );
-
-	assert (functionDecl->unique());
-	if (!functionDecl->has_body() && !functionDecl->withExprs.empty()) {
-		SemanticError(functionDecl->location, functionDecl, "Function without body has with declarations");
-	}
-
-	if (!functionDecl->isTypeFixed) {
-		auto mutDecl = mutate(functionDecl);
-		auto mutType = mutDecl->type.get_and_mutate();
-
-		for (auto & attr: mutDecl->attributes) {
-			attr = handleAttribute(mutDecl->location, attr, context );
-		}
-
-		// handle assertions
-
-		symtab.enterScope();
-		mutType->forall.clear();
-		mutType->assertions.clear();
-		for (auto & typeParam : mutDecl->type_params) {
-			symtab.addType(typeParam);
-			mutType->forall.emplace_back(new ast::TypeInstType(typeParam));
-		}
-		for (auto & asst : mutDecl->assertions) {
-			asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), context);
-			symtab.addId(asst);
-			mutType->assertions.emplace_back(new ast::VariableExpr(functionDecl->location, asst));
-		}
-
-		// temporarily adds params to symbol table.
-		// actual scoping rules for params and withexprs differ - see Pass::visit(FunctionDecl)
-
-		std::vector<ast::ptr<ast::Type>> paramTypes;
-		std::vector<ast::ptr<ast::Type>> returnTypes;
-
-		for (auto & param : mutDecl->params) {
-			param = fixObjectType(param.strict_as<ast::ObjectDecl>(), context);
-			symtab.addId(param);
-			paramTypes.emplace_back(param->get_type());
-		}
-		for (auto & ret : mutDecl->returns) {
-			ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), context);
-			returnTypes.emplace_back(ret->get_type());
-		}
-		// since function type in decl is just a view of param types, need to update that as well
-		mutType->params = std::move(paramTypes);
-		mutType->returns = std::move(returnTypes);
-
-		auto renamedType = strict_dynamic_cast<const ast::FunctionType *>(renameTyVars(mutType, RenameMode::GEN_EXPR_ID));
-
-		std::list<ast::ptr<ast::Stmt>> newStmts;
-		resolveWithExprs (mutDecl->withExprs, newStmts);
-
-		if (mutDecl->stmts) {
-			auto mutStmt = mutDecl->stmts.get_and_mutate();
-			mutStmt->kids.splice(mutStmt->kids.begin(), std::move(newStmts));
-			mutDecl->stmts = mutStmt;
-		}
-
-		symtab.leaveScope();
-
-		mutDecl->type = renamedType;
-		mutDecl->mangleName = Mangle::mangle(mutDecl);
-		mutDecl->isTypeFixed = true;
-		functionDecl = mutDecl;
-	}
-	managedTypes.handleDWT(functionDecl);
-
-	functionReturn = extractResultType( functionDecl->type );
-	return functionDecl;
-}
-
-const ast::FunctionDecl * Resolver::postvisit( const ast::FunctionDecl * functionDecl ) {
-	// default value expressions have an environment which shouldn't be there and trips up
-	// later passes.
-	assert( functionDecl->unique() );
-	ast::FunctionType * mutType = mutate( functionDecl->type.get() );
-
-	for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) {
-		if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) {
-			if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) {
-				if ( init->value->env == nullptr ) continue;
-				// clone initializer minus the initializer environment
-				auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() );
-				auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() );
-				auto mutValue = mutate( mutInit->value.get() );
-
-				mutValue->env = nullptr;
-				mutInit->value = mutValue;
-				mutParam->init = mutInit;
-				mutType->params[i] = mutParam;
-
-				assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env);
-			}
-		}
-	}
-	mutate_field(functionDecl, &ast::FunctionDecl::type, mutType);
-	return functionDecl;
-}
-
-bool Resolver::shouldGenCtorInit( ast::ObjectDecl const * decl ) const {
-	// If we shouldn't try to construct it, then don't.
-	if ( !InitTweak::tryConstruct( decl ) ) return false;
-	// Otherwise, if it is a managed type, we may construct it.
-	if ( managedTypes.isManaged( decl ) ) return true;
-	// Skip construction if it is trivial at compile-time.
-	if ( InitTweak::isConstExpr( decl->init ) ) return false;
-	// Skip construction for local declarations.
-	return ( !isInFunction() || decl->storage.is_static );
-}
-
-const ast::ObjectDecl * Resolver::previsit( const ast::ObjectDecl * objectDecl ) {
-	// To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
-	// class-variable `initContext` is changed multiple times because the LHS is analyzed
-	// twice. The second analysis changes `initContext` because a function type can contain
-	// object declarations in the return and parameter types. Therefore each value of
-	// `initContext` is retained so the type on the first analysis is preserved and used for
-	// selecting the RHS.
-	GuardValue( currentObject );
-
-	if ( inEnumDecl && dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() ) ) {
-		// enumerator initializers should not use the enum type to initialize, since the
-		// enum type is still incomplete at this point. Use `int` instead.
-
-		if ( auto enumBase = dynamic_cast< const ast::EnumInstType * >
-			( objectDecl->get_type() )->base->base ) {
-			objectDecl = fixObjectType( objectDecl, context );
-			currentObject = ast::CurrentObject{
-				objectDecl->location,
-				enumBase
-			};
-		} else {
-			objectDecl = fixObjectType( objectDecl, context );
-			currentObject = ast::CurrentObject{
-				objectDecl->location, new ast::BasicType{ ast::BasicKind::SignedInt } };
-		}
-	} else {
-		if ( !objectDecl->isTypeFixed ) {
-			auto newDecl = fixObjectType(objectDecl, context);
-			auto mutDecl = mutate(newDecl);
-
-			// generate CtorInit wrapper when necessary.
-			// in certain cases, fixObjectType is called before reaching
-			// this object in visitor pass, thus disabling CtorInit codegen.
-			// this happens on aggregate members and function parameters.
-			if ( shouldGenCtorInit( mutDecl ) ) {
-				// constructed objects cannot be designated
-				if ( InitTweak::isDesignated( mutDecl->init ) ) {
-					ast::Pass<ResolveDesignators> res( context );
-					maybe_accept( mutDecl->init.get(), res );
-					if ( !res.core.result ) {
-						SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object.\n"
-									   "If this is really what you want, initialize with @=." );
-					}
-				}
-				// constructed objects should not have initializers nested too deeply
-				if ( ! InitTweak::checkInitDepth( mutDecl ) ) SemanticError( mutDecl, "Managed object's initializer is too deep " );
-
-				mutDecl->init = InitTweak::genCtorInit( mutDecl->location, mutDecl );
-			}
-
-			objectDecl = mutDecl;
-		}
-		currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
-	}
-
-	return objectDecl;
-}
-
-void Resolver::previsit( const ast::AggregateDecl * _aggDecl ) {
-	auto aggDecl = mutate(_aggDecl);
-	assertf(aggDecl == _aggDecl, "type declarations must be unique");
-
-	for (auto & member: aggDecl->members) {
-		// nested type decls are hoisted already. no need to do anything
-		if (auto obj = member.as<ast::ObjectDecl>()) {
-			member = fixObjectType(obj, context);
-		}
-	}
-}
-
-void Resolver::previsit( const ast::StructDecl * structDecl ) {
-	previsit(static_cast<const ast::AggregateDecl *>(structDecl));
-	managedTypes.handleStruct(structDecl);
-}
-
-void Resolver::previsit( const ast::EnumDecl * ) {
-	// in case we decide to allow nested enums
-	GuardValue( inEnumDecl );
-	inEnumDecl = true;
-	// don't need to fix types for enum fields
-}
-
-const ast::StaticAssertDecl * Resolver::previsit(
-	const ast::StaticAssertDecl * assertDecl
-) {
-	return ast::mutate_field(
-		assertDecl, &ast::StaticAssertDecl::cond,
-		findIntegralExpression( assertDecl->cond, context ) );
-}
-
-template< typename PtrType >
-const PtrType * handlePtrType( const PtrType * type, const ResolveContext & context ) {
-	if ( type->dimension ) {
-		const ast::Type * sizeType = context.global.sizeType.get();
-		ast::ptr< ast::Expr > dimension = findSingleExpression( type->dimension, sizeType, context );
-		assertf(dimension->env->empty(), "array dimension expr has nonempty env");
-		dimension.get_and_mutate()->env = nullptr;
-		ast::mutate_field( type, &PtrType::dimension, dimension );
-	}
-	return type;
-}
-
-const ast::ArrayType * Resolver::previsit( const ast::ArrayType * at ) {
-	return handlePtrType( at, context );
-}
-
-const ast::PointerType * Resolver::previsit( const ast::PointerType * pt ) {
-	return handlePtrType( pt, context );
-}
-
-const ast::ExprStmt * Resolver::previsit( const ast::ExprStmt * exprStmt ) {
-	visit_children = false;
-	assertf( exprStmt->expr, "ExprStmt has null expression in resolver" );
-
-	return ast::mutate_field(
-		exprStmt, &ast::ExprStmt::expr, findVoidExpression( exprStmt->expr, context ) );
-}
-
-const ast::AsmExpr * Resolver::previsit( const ast::AsmExpr * asmExpr ) {
-	visit_children = false;
-
-	asmExpr = ast::mutate_field(
-		asmExpr, &ast::AsmExpr::operand, findVoidExpression( asmExpr->operand, context ) );
-
-	return asmExpr;
-}
-
-const ast::AsmStmt * Resolver::previsit( const ast::AsmStmt * asmStmt ) {
-	visitor->maybe_accept( asmStmt, &ast::AsmStmt::input );
-	visitor->maybe_accept( asmStmt, &ast::AsmStmt::output );
-	visit_children = false;
-	return asmStmt;
-}
-
-const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) {
-	return ast::mutate_field(
-		ifStmt, &ast::IfStmt::cond, findCondExpression( ifStmt->cond, context ) );
-}
-
-const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) {
-	return ast::mutate_field(
-		whileDoStmt, &ast::WhileDoStmt::cond, findCondExpression( whileDoStmt->cond, context ) );
-}
-
-const ast::ForStmt * Resolver::previsit( const ast::ForStmt * forStmt ) {
-	if ( forStmt->cond ) {
-		forStmt = ast::mutate_field(
-			forStmt, &ast::ForStmt::cond, findCondExpression( forStmt->cond, context ) );
-	}
-
-	if ( forStmt->inc ) {
-		forStmt = ast::mutate_field(
-			forStmt, &ast::ForStmt::inc, findVoidExpression( forStmt->inc, context ) );
-	}
-
-	return forStmt;
-}
-
-const ast::SwitchStmt * Resolver::previsit( const ast::SwitchStmt * switchStmt ) {
-	GuardValue( currentObject );
-	switchStmt = ast::mutate_field(
-		switchStmt, &ast::SwitchStmt::cond,
-		findIntegralExpression( switchStmt->cond, context ) );
-	currentObject = ast::CurrentObject{ switchStmt->location, switchStmt->cond->result };
-	return switchStmt;
-}
-
-const ast::CaseClause * Resolver::previsit( const ast::CaseClause * caseStmt ) {
-	if ( caseStmt->cond ) {
-		std::deque< ast::InitAlternative > initAlts = currentObject.getOptions();
-		assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral "
-			"expression." );
-
-		ast::ptr< ast::Expr > untyped =
-			new ast::CastExpr{ caseStmt->location, caseStmt->cond, initAlts.front().type };
-		ast::ptr< ast::Expr > newExpr = findSingleExpression( untyped, context );
-
-		// case condition cannot have a cast in C, so it must be removed here, regardless of
-		// whether it would perform a conversion.
-		if ( const ast::CastExpr * castExpr = newExpr.as< ast::CastExpr >() ) {
-			swap_and_save_env( newExpr, castExpr->arg );
-		}
-
-		caseStmt = ast::mutate_field( caseStmt, &ast::CaseClause::cond, newExpr );
-	}
-	return caseStmt;
-}
-
-const ast::BranchStmt * Resolver::previsit( const ast::BranchStmt * branchStmt ) {
-	visit_children = false;
-	// must resolve the argument of a computed goto
-	if ( branchStmt->kind == ast::BranchStmt::Goto && branchStmt->computedTarget ) {
-		// computed goto argument is void*
-		ast::ptr< ast::Type > target = new ast::PointerType{ new ast::VoidType{} };
-		branchStmt = ast::mutate_field(
-			branchStmt, &ast::BranchStmt::computedTarget,
-			findSingleExpression( branchStmt->computedTarget, target, context ) );
-	}
-	return branchStmt;
-}
-
-const ast::ReturnStmt * Resolver::previsit( const ast::ReturnStmt * returnStmt ) {
-	visit_children = false;
-	if ( returnStmt->expr ) {
-		returnStmt = ast::mutate_field(
-			returnStmt, &ast::ReturnStmt::expr,
-			findSingleExpression( returnStmt->expr, functionReturn, context ) );
-	}
-	return returnStmt;
-}
-
-const ast::ThrowStmt * Resolver::previsit( const ast::ThrowStmt * throwStmt ) {
-	visit_children = false;
-	if ( throwStmt->expr ) {
-		const ast::StructDecl * exceptionDecl =
-			symtab.lookupStruct( "__cfaehm_base_exception_t" );
-		assert( exceptionDecl );
-		ast::ptr< ast::Type > exceptType =
-			new ast::PointerType{ new ast::StructInstType{ exceptionDecl } };
-		throwStmt = ast::mutate_field(
-			throwStmt, &ast::ThrowStmt::expr,
-			findSingleExpression( throwStmt->expr, exceptType, context ) );
-	}
-	return throwStmt;
-}
-
-const ast::CatchClause * Resolver::previsit( const ast::CatchClause * catchClause ) {
-	// Until we are very sure this invarent (ifs that move between passes have then)
-	// holds, check it. This allows a check for when to decode the mangling.
-	if ( auto ifStmt = catchClause->body.as<ast::IfStmt>() ) {
-		assert( ifStmt->then );
-	}
-	// Encode the catchStmt so the condition can see the declaration.
-	if ( catchClause->cond ) {
-		ast::CatchClause * clause = mutate( catchClause );
-		clause->body = new ast::IfStmt( clause->location, clause->cond, nullptr, clause->body );
-		clause->cond = nullptr;
-		return clause;
-	}
-	return catchClause;
-}
-
-const ast::CatchClause * Resolver::postvisit( const ast::CatchClause * catchClause ) {
-	// Decode the catchStmt so everything is stored properly.
-	const ast::IfStmt * ifStmt = catchClause->body.as<ast::IfStmt>();
-	if ( nullptr != ifStmt && nullptr == ifStmt->then ) {
-		assert( ifStmt->cond );
-		assert( ifStmt->else_ );
-		ast::CatchClause * clause = ast::mutate( catchClause );
-		clause->cond = ifStmt->cond;
-		clause->body = ifStmt->else_;
-		// ifStmt should be implicately deleted here.
-		return clause;
-	}
-	return catchClause;
-}
-
-const ast::WaitForStmt * Resolver::previsit( const ast::WaitForStmt * stmt ) {
-	visit_children = false;
-
-	// Resolve all clauses first
-	for ( unsigned i = 0; i < stmt->clauses.size(); ++i ) {
-		const ast::WaitForClause & clause = *stmt->clauses[i];
-
-		ast::TypeEnvironment env;
-		CandidateFinder funcFinder( context, env );
-
-		// Find all candidates for a function in canonical form
-		funcFinder.find( clause.target, ResolveMode::withAdjustment() );
-
-		if ( funcFinder.candidates.empty() ) {
-			stringstream ss;
-			ss << "Use of undeclared indentifier '";
-			ss << clause.target.strict_as< ast::NameExpr >()->name;
-			ss << "' in call to waitfor";
-			SemanticError( stmt->location, ss.str() );
-		}
-
-		if ( clause.target_args.empty() ) {
-			SemanticError( stmt->location,
-				"Waitfor clause must have at least one mutex parameter");
-		}
-
-		// Find all alternatives for all arguments in canonical form
-		std::vector< CandidateFinder > argFinders =
-			funcFinder.findSubExprs( clause.target_args );
-
-		// List all combinations of arguments
-		std::vector< CandidateList > possibilities;
-		combos( argFinders.begin(), argFinders.end(), back_inserter( possibilities ) );
-
-		// For every possible function:
-		// * try matching the arguments to the parameters, not the other way around because
-		//   more arguments than parameters
-		CandidateList funcCandidates;
-		std::vector< CandidateList > argsCandidates;
-		SemanticErrorException errors;
-		for ( CandidateRef & func : funcFinder.candidates ) {
-			try {
-				auto pointerType = dynamic_cast< const ast::PointerType * >(
-					func->expr->result->stripReferences() );
-				if ( ! pointerType ) {
-					SemanticError( stmt->location, func->expr->result.get(),
-						"candidate not viable: not a pointer type\n" );
-				}
-
-				auto funcType = pointerType->base.as< ast::FunctionType >();
-				if ( ! funcType ) {
-					SemanticError( stmt->location, func->expr->result.get(),
-						"candidate not viable: not a function type\n" );
-				}
-
-				{
-					auto param    = funcType->params.begin();
-					auto paramEnd = funcType->params.end();
-
-					if( ! nextMutex( param, paramEnd ) ) {
-						SemanticError( stmt->location, funcType,
-							"candidate function not viable: no mutex parameters\n");
-					}
-				}
-
-				CandidateRef func2{ new Candidate{ *func } };
-				// strip reference from function
-				func2->expr = referenceToRvalueConversion( func->expr, func2->cost );
-
-				// Each argument must be matched with a parameter of the current candidate
-				for ( auto & argsList : possibilities ) {
-					try {
-						// Declare data structures needed for resolution
-						ast::OpenVarSet open;
-						ast::AssertionSet need, have;
-						ast::TypeEnvironment resultEnv{ func->env };
-						// Add all type variables as open so that those not used in the
-						// parameter list are still considered open
-						resultEnv.add( funcType->forall );
-
-						// load type variables from arguments into one shared space
-						for ( auto & arg : argsList ) {
-							resultEnv.simpleCombine( arg->env );
-						}
-
-						// Make sure we don't widen any existing bindings
-						resultEnv.forbidWidening();
-
-						// Find any unbound type variables
-						resultEnv.extractOpenVars( open );
-
-						auto param = funcType->params.begin();
-						auto paramEnd = funcType->params.end();
-
-						unsigned n_mutex_param = 0;
-
-						// For every argument of its set, check if it matches one of the
-						// parameters. The order is important
-						for ( auto & arg : argsList ) {
-							// Ignore non-mutex arguments
-							if ( ! nextMutex( param, paramEnd ) ) {
-								// We ran out of parameters but still have arguments.
-								// This function doesn't match
-								SemanticError( stmt->location, funcType,
-									toString("candidate function not viable: too many mutex "
-									"arguments, expected ", n_mutex_param, "\n" ) );
-							}
-
-							++n_mutex_param;
-
-							// Check if the argument matches the parameter type in the current scope.
-							// ast::ptr< ast::Type > paramType = (*param)->get_type();
-
-							if (
-								! unify(
-									arg->expr->result, *param, resultEnv, need, have, open )
-							) {
-								// Type doesn't match
-								stringstream ss;
-								ss << "candidate function not viable: no known conversion "
-									"from '";
-								ast::print( ss, *param );
-								ss << "' to '";
-								ast::print( ss, arg->expr->result );
-								ss << "' with env '";
-								ast::print( ss, resultEnv );
-								ss << "'\n";
-								SemanticError( stmt->location, funcType, ss.str() );
-							}
-
-							++param;
-						}
-
-						// All arguments match!
-
-						// Check if parameters are missing
-						if ( nextMutex( param, paramEnd ) ) {
-							do {
-								++n_mutex_param;
-								++param;
-							} while ( nextMutex( param, paramEnd ) );
-
-							// We ran out of arguments but still have parameters left; this
-							// function doesn't match
-							SemanticError( stmt->location, funcType,
-								toString( "candidate function not viable: too few mutex "
-								"arguments, expected ", n_mutex_param, "\n" ) );
-						}
-
-						// All parameters match!
-
-						// Finish the expressions to tie in proper environments
-						finishExpr( func2->expr, resultEnv );
-						for ( CandidateRef & arg : argsList ) {
-							finishExpr( arg->expr, resultEnv );
-						}
-
-						// This is a match, store it and save it for later
-						funcCandidates.emplace_back( std::move( func2 ) );
-						argsCandidates.emplace_back( std::move( argsList ) );
-
-					} catch ( SemanticErrorException & e ) {
-						errors.append( e );
-					}
-				}
-			} catch ( SemanticErrorException & e ) {
-				errors.append( e );
-			}
-		}
-
-		// Make sure correct number of arguments
-		if( funcCandidates.empty() ) {
-			SemanticErrorException top( stmt->location,
-				"No alternatives for function in call to waitfor" );
-			top.append( errors );
-			throw top;
-		}
-
-		if( argsCandidates.empty() ) {
-			SemanticErrorException top( stmt->location,
-				"No alternatives for arguments in call to waitfor" );
-			top.append( errors );
-			throw top;
-		}
-
-		if( funcCandidates.size() > 1 ) {
-			SemanticErrorException top( stmt->location,
-				"Ambiguous function in call to waitfor" );
-			top.append( errors );
-			throw top;
-		}
-		if( argsCandidates.size() > 1 ) {
-			SemanticErrorException top( stmt->location,
-				"Ambiguous arguments in call to waitfor" );
-			top.append( errors );
-			throw top;
-		}
-		// TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
-
-		// build new clause
-		auto clause2 = new ast::WaitForClause( clause.location );
-
-		clause2->target = funcCandidates.front()->expr;
-
-		clause2->target_args.reserve( clause.target_args.size() );
-		const ast::StructDecl * decl_monitor = symtab.lookupStruct( "monitor$" );
-		for ( auto arg : argsCandidates.front() ) {
-			const auto & loc = stmt->location;
-
-			ast::Expr * init = new ast::CastExpr( loc,
-				new ast::UntypedExpr( loc,
-					new ast::NameExpr( loc, "get_monitor" ),
-					{ arg->expr }
-				),
-				new ast::PointerType(
-					new ast::StructInstType(
-						decl_monitor
-					)
-				)
-			);
-
-			clause2->target_args.emplace_back( findSingleExpression( init, context ) );
-		}
-
-		// Resolve the conditions as if it were an IfStmt, statements normally
-		clause2->when_cond = findCondExpression( clause.when_cond, context );
-		clause2->stmt = clause.stmt->accept( *visitor );
-
-		// set results into stmt
-		auto n = mutate( stmt );
-		n->clauses[i] = clause2;
-		stmt = n;
-	}
-
-	if ( stmt->timeout_stmt ) {
-		// resolve the timeout as a size_t, the conditions like IfStmt, and stmts normally
-		ast::ptr< ast::Type > target =
-			new ast::BasicType{ ast::BasicKind::LongLongUnsignedInt };
-		auto timeout_time = findSingleExpression( stmt->timeout_time, target, context );
-		auto timeout_cond = findCondExpression( stmt->timeout_cond, context );
-		auto timeout_stmt = stmt->timeout_stmt->accept( *visitor );
-
-		// set results into stmt
-		auto n = mutate( stmt );
-		n->timeout_time = std::move( timeout_time );
-		n->timeout_cond = std::move( timeout_cond );
-		n->timeout_stmt = std::move( timeout_stmt );
-		stmt = n;
-	}
-
-	if ( stmt->else_stmt ) {
-		// resolve the condition like IfStmt, stmts normally
-		auto else_cond = findCondExpression( stmt->else_cond, context );
-		auto else_stmt = stmt->else_stmt->accept( *visitor );
-
-		// set results into stmt
-		auto n = mutate( stmt );
-		n->else_cond = std::move( else_cond );
-		n->else_stmt = std::move( else_stmt );
-		stmt = n;
-	}
-
-	return stmt;
-}
-
-const ast::WithStmt * Resolver::previsit( const ast::WithStmt * withStmt ) {
-	auto mutStmt = mutate(withStmt);
-	resolveWithExprs(mutStmt->exprs, stmtsToAddBefore);
-	return mutStmt;
-}
-
-void Resolver::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) {
-	for (auto & expr : exprs) {
-		// only struct- and union-typed expressions are viable candidates
-		expr = findKindExpression( expr, context, structOrUnion, "with expression" );
-
-		// if with expression might be impure, create a temporary so that it is evaluated once
-		if ( Tuples::maybeImpure( expr ) ) {
-			static UniqueName tmpNamer( "_with_tmp_" );
-			const CodeLocation loc = expr->location;
-			auto tmp = new ast::ObjectDecl(loc, tmpNamer.newName(), expr->result, new ast::SingleInit(loc, expr ) );
-			expr = new ast::VariableExpr( loc, tmp );
-			stmtsToAdd.push_back( new ast::DeclStmt(loc, tmp ) );
-			if ( InitTweak::isConstructable( tmp->type ) ) {
-				// generate ctor/dtor and resolve them
-				tmp->init = InitTweak::genCtorInit( loc, tmp );
-			}
-			// since tmp is freshly created, this should modify tmp in-place
-			tmp->accept( *visitor );
-		} else if (expr->env && expr->env->empty()) {
-			expr = ast::mutate_field(expr.get(), &ast::Expr::env, nullptr);
-		}
-	}
-}
-
-const ast::SingleInit * Resolver::previsit( const ast::SingleInit * singleInit ) {
-	visit_children = false;
-	// resolve initialization using the possibilities as determined by the `currentObject`
-	// cursor.
-	ast::ptr< ast::Expr > untyped = new ast::UntypedInitExpr{
-		singleInit->location, singleInit->value, currentObject.getOptions() };
-	ast::ptr<ast::Expr> newExpr = findSingleExpression( untyped, context );
-	const ast::InitExpr * initExpr = newExpr.strict_as< ast::InitExpr >();
-
-	// move cursor to the object that is actually initialized
-	currentObject.setNext( initExpr->designation );
-
-	// discard InitExpr wrapper and retain relevant pieces.
-	// `initExpr` may have inferred params in the case where the expression specialized a
-	// function pointer, and newExpr may already have inferParams of its own, so a simple
-	// swap is not sufficient
-	ast::Expr::InferUnion inferred = initExpr->inferred;
-	swap_and_save_env( newExpr, initExpr->expr );
-	newExpr.get_and_mutate()->inferred.splice( std::move(inferred) );
-
-	// get the actual object's type (may not exactly match what comes back from the resolver
-	// due to conversions)
-	const ast::Type * initContext = currentObject.getCurrentType();
-
-	removeExtraneousCast( newExpr );
-
-	// check if actual object's type is char[]
-	if ( auto at = dynamic_cast< const ast::ArrayType * >( initContext ) ) {
-		if ( isCharType( at->base ) ) {
-			// check if the resolved type is char*
-			if ( auto pt = newExpr->result.as< ast::PointerType >() ) {
-				if ( isCharType( pt->base ) ) {
-					// strip cast if we're initializing a char[] with a char*
-					// e.g. char x[] = "hello"
-					if ( auto ce = newExpr.as< ast::CastExpr >() ) {
-						swap_and_save_env( newExpr, ce->arg );
-					}
-				}
-			}
-		}
-	}
-
-	// move cursor to next object in preparation for next initializer
-	currentObject.increment();
-
-	// set initializer expression to resolved expression
-	return ast::mutate_field( singleInit, &ast::SingleInit::value, std::move(newExpr) );
-}
-
-const ast::ListInit * Resolver::previsit( const ast::ListInit * listInit ) {
-	// move cursor into brace-enclosed initializer-list
-	currentObject.enterListInit( listInit->location );
-
-	assert( listInit->designations.size() == listInit->initializers.size() );
-	for ( unsigned i = 0; i < listInit->designations.size(); ++i ) {
-		// iterate designations and initializers in pairs, moving the cursor to the current
-		// designated object and resolving the initializer against that object
-		listInit = ast::mutate_field_index(
-			listInit, &ast::ListInit::designations, i,
-			currentObject.findNext( listInit->designations[i] ) );
-		listInit = ast::mutate_field_index(
-			listInit, &ast::ListInit::initializers, i,
-			listInit->initializers[i]->accept( *visitor ) );
-	}
-
-	// move cursor out of brace-enclosed initializer-list
-	currentObject.exitListInit();
-
-	visit_children = false;
-	return listInit;
-}
-
-const ast::ConstructorInit * Resolver::previsit( const ast::ConstructorInit * ctorInit ) {
-	visitor->maybe_accept( ctorInit, &ast::ConstructorInit::ctor );
-	visitor->maybe_accept( ctorInit, &ast::ConstructorInit::dtor );
-
-	// found a constructor - can get rid of C-style initializer
-	// xxx - Rob suggests this field is dead code
-	ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::init, nullptr );
-
-	// intrinsic single-parameter constructors and destructors do nothing. Since this was
-	// implicitly generated, there's no way for it to have side effects, so get rid of it to
-	// clean up generated code
-	if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
-		ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::ctor, nullptr );
-	}
-	if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {
-		ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::dtor, nullptr );
-	}
-
-	return ctorInit;
-}
-
-// suppress error on autogen functions and mark invalid autogen as deleted.
-bool Resolver::on_error(ast::ptr<ast::Decl> & decl) {
-	if (auto functionDecl = decl.as<ast::FunctionDecl>()) {
-		// xxx - can intrinsic gen ever fail?
-		if (functionDecl->linkage == ast::Linkage::AutoGen) {
-			auto mutDecl = mutate(functionDecl);
-			mutDecl->isDeleted = true;
-			mutDecl->stmts = nullptr;
-			decl = mutDecl;
-			return false;
-		}
-	}
-	return true;
-}
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/Resolver.cpp
===================================================================
--- src/ResolvExpr/Resolver.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/Resolver.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,1269 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Resolver.cpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Sun May 17 12:17:01 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Thu Dec 14 18:44:43 2023
+// Update Count     : 251
+//
+
+#include <cassert>                       // for strict_dynamic_cast, assert
+#include <memory>                        // for allocator, allocator_traits<...
+#include <tuple>                         // for get
+#include <vector>                        // for vector
+
+#include "Candidate.hpp"
+#include "CandidateFinder.hpp"
+#include "CurrentObject.hpp"             // for CurrentObject
+#include "RenameVars.hpp"                // for RenameVars, global_renamer
+#include "Resolver.hpp"
+#include "ResolveTypeof.hpp"
+#include "ResolveMode.hpp"               // for ResolveMode
+#include "Typeops.hpp"                   // for extractResultType
+#include "Unify.hpp"                     // for unify
+#include "CompilationState.hpp"
+#include "AST/Decl.hpp"
+#include "AST/Init.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Print.hpp"
+#include "AST/SymbolTable.hpp"
+#include "AST/Type.hpp"
+#include "Common/Eval.hpp"               // for eval
+#include "Common/Iterate.hpp"            // for group_iterate
+#include "Common/SemanticError.hpp"      // for SemanticError
+#include "Common/Stats/ResolveTime.hpp"  // for ResolveTime::start(), ResolveTime::stop()
+#include "Common/ToString.hpp"           // for toCString
+#include "Common/UniqueName.hpp"         // for UniqueName
+#include "InitTweak/GenInit.hpp"
+#include "InitTweak/InitTweak.hpp"       // for isIntrinsicSingleArgCallStmt
+#include "SymTab/Mangler.hpp"            // for Mangler
+#include "Tuples/Tuples.hpp"
+#include "Validate/FindSpecialDecls.hpp" // for SizeType
+
+using namespace std;
+
+namespace ResolvExpr {
+
+namespace {
+	/// Finds deleted expressions in an expression tree
+	struct DeleteFinder final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder> {
+		const ast::DeletedExpr * result = nullptr;
+
+		void previsit( const ast::DeletedExpr * expr ) {
+			if ( result ) { visit_children = false; }
+			else { result = expr; }
+		}
+
+		void previsit( const ast::Expr * expr ) {
+			if ( result ) { visit_children = false; }
+			if (expr->inferred.hasParams()) {
+				for (auto & imp : expr->inferred.inferParams() ) {
+					imp.second.expr->accept(*visitor);
+				}
+			}
+		}
+	};
+
+	struct ResolveDesignators final : public ast::WithShortCircuiting {
+		ResolveContext& context;
+		bool result = false;
+
+		ResolveDesignators( ResolveContext& _context ): context(_context) {};
+
+		void previsit( const ast::Node * ) {
+			// short circuit if we already know there are designations
+			if ( result ) visit_children = false;
+		}
+
+		void previsit( const ast::Designation * des ) {
+			if ( result ) visit_children = false;
+			else if ( ! des->designators.empty() ) {
+				if ( (des->designators.size() == 1) ) {
+					const ast::Expr * designator = des->designators.at(0);
+					if ( const ast::NameExpr * designatorName = dynamic_cast<const ast::NameExpr *>(designator) ) {
+						auto candidates = context.symtab.lookupId(designatorName->name);
+						for ( auto candidate : candidates ) {
+							if ( dynamic_cast<const ast::EnumInstType *>(candidate.id->get_type()) ) {
+								result = true;
+								break;
+							}
+						}
+					}
+				}
+				visit_children = false;
+			}
+		}
+	};
+} // anonymous namespace
+
+/// Check if this expression is or includes a deleted expression
+const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
+	return ast::Pass<DeleteFinder>::read( expr );
+}
+
+namespace {
+	/// always-accept candidate filter
+	bool anyCandidate( const Candidate & ) { return true; }
+
+	/// Calls the CandidateFinder and finds the single best candidate
+	CandidateRef findUnfinishedKindExpression(
+		const ast::Expr * untyped, const ResolveContext & context, const std::string & kind,
+		std::function<bool(const Candidate &)> pred = anyCandidate, ResolveMode mode = {}
+	) {
+		if ( ! untyped ) return nullptr;
+
+		// xxx - this isn't thread-safe, but should work until we parallelize the resolver
+		static unsigned recursion_level = 0;
+
+		++recursion_level;
+		ast::TypeEnvironment env;
+		CandidateFinder finder( context, env );
+		finder.allowVoid = true;
+		finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
+		--recursion_level;
+
+		// produce a filtered list of candidates
+		CandidateList candidates;
+		for ( auto & cand : finder.candidates ) {
+			if ( pred( *cand ) ) { candidates.emplace_back( cand ); }
+		}
+
+		// produce invalid error if no candidates
+		if ( candidates.empty() ) {
+			SemanticError( untyped,
+				toString( "No reasonable alternatives for ", kind, (kind != "" ? " " : ""),
+				"expression: ") );
+		}
+
+		// search for cheapest candidate
+		CandidateList winners;
+		bool seen_undeleted = false;
+		for ( CandidateRef & cand : candidates ) {
+			int c = winners.empty() ? -1 : cand->cost.compare( winners.front()->cost );
+
+			if ( c > 0 ) continue;  // skip more expensive than winner
+
+			if ( c < 0 ) {
+				// reset on new cheapest
+				seen_undeleted = ! findDeletedExpr( cand->expr );
+				winners.clear();
+			} else /* if ( c == 0 ) */ {
+				if ( findDeletedExpr( cand->expr ) ) {
+					// skip deleted expression if already seen one equivalent-cost not
+					if ( seen_undeleted ) continue;
+				} else if ( ! seen_undeleted ) {
+					// replace list of equivalent-cost deleted expressions with one non-deleted
+					winners.clear();
+					seen_undeleted = true;
+				}
+			}
+
+			winners.emplace_back( std::move( cand ) );
+		}
+
+		// promote candidate.cvtCost to .cost
+		// promoteCvtCost( winners );
+
+		// produce ambiguous errors, if applicable
+		if ( winners.size() != 1 ) {
+			std::ostringstream stream;
+			stream << "Cannot choose between " << winners.size() << " alternatives for "
+				<< kind << (kind != "" ? " " : "") << "expression\n";
+			ast::print( stream, untyped );
+			stream << " Alternatives are:\n";
+			print( stream, winners, 1 );
+			SemanticError( untyped->location, stream.str() );
+		}
+
+		// single selected choice
+		CandidateRef & choice = winners.front();
+
+		// fail on only expression deleted
+		if ( ! seen_undeleted ) {
+			SemanticError( untyped->location, choice->expr.get(), "Unique best alternative "
+			"includes deleted identifier in " );
+		}
+
+		return std::move( choice );
+	}
+
+	/// Strips extraneous casts out of an expression
+	struct StripCasts final {
+		const ast::Expr * postvisit( const ast::CastExpr * castExpr ) {
+			if (
+				castExpr->isGenerated == ast::GeneratedCast
+				&& typesCompatible( castExpr->arg->result, castExpr->result )
+			) {
+				// generated cast is the same type as its argument, remove it after keeping env
+				return ast::mutate_field(
+					castExpr->arg.get(), &ast::Expr::env, castExpr->env );
+			}
+			return castExpr;
+		}
+
+		static void strip( ast::ptr< ast::Expr > & expr ) {
+			ast::Pass< StripCasts > stripper;
+			expr = expr->accept( stripper );
+		}
+	};
+
+	/// Swaps argument into expression pointer, saving original environment
+	void swap_and_save_env( ast::ptr< ast::Expr > & expr, const ast::Expr * newExpr ) {
+		ast::ptr< ast::TypeSubstitution > env = expr->env;
+		expr.set_and_mutate( newExpr )->env = env;
+	}
+
+	/// Removes cast to type of argument (unlike StripCasts, also handles non-generated casts)
+	void removeExtraneousCast( ast::ptr<ast::Expr> & expr ) {
+		if ( const ast::CastExpr * castExpr = expr.as< ast::CastExpr >() ) {
+			if ( typesCompatible( castExpr->arg->result, castExpr->result ) ) {
+				// cast is to the same type as its argument, remove it
+				swap_and_save_env( expr, castExpr->arg );
+			}
+		}
+	}
+
+} // anonymous namespace
+
+/// Establish post-resolver invariants for expressions
+void finishExpr(
+	ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env,
+	const ast::TypeSubstitution * oldenv = nullptr
+) {
+	// set up new type substitution for expression
+	ast::ptr< ast::TypeSubstitution > newenv =
+		 oldenv ? oldenv : new ast::TypeSubstitution{};
+	env.writeToSubstitution( *newenv.get_and_mutate() );
+	expr.get_and_mutate()->env = std::move( newenv );
+	// remove unncecessary casts
+	StripCasts::strip( expr );
+}
+
+ast::ptr< ast::Expr > resolveInVoidContext(
+	const ast::Expr * expr, const ResolveContext & context,
+	ast::TypeEnvironment & env
+) {
+	assertf( expr, "expected a non-null expression" );
+
+	// set up and resolve expression cast to void
+	ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr };
+	CandidateRef choice = findUnfinishedKindExpression(
+		untyped, context, "", anyCandidate, ResolveMode::withAdjustment() );
+
+	// a cast expression has either 0 or 1 interpretations (by language rules);
+	// if 0, an exception has already been thrown, and this code will not run
+	const ast::CastExpr * castExpr = choice->expr.strict_as< ast::CastExpr >();
+	env = std::move( choice->env );
+
+	return castExpr->arg;
+}
+
+/// Resolve `untyped` to the expression whose candidate is the best match for a `void`
+/// context.
+ast::ptr< ast::Expr > findVoidExpression(
+	const ast::Expr * untyped, const ResolveContext & context
+) {
+	ast::TypeEnvironment env;
+	ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, context, env );
+	finishExpr( newExpr, env, untyped->env );
+	return newExpr;
+}
+
+namespace {
+	/// resolve `untyped` to the expression whose candidate satisfies `pred` with the
+	/// lowest cost, returning the resolved version
+	ast::ptr< ast::Expr > findKindExpression(
+		const ast::Expr * untyped, const ResolveContext & context,
+		std::function<bool(const Candidate &)> pred = anyCandidate,
+		const std::string & kind = "", ResolveMode mode = {}
+	) {
+		if ( ! untyped ) return {};
+		CandidateRef choice =
+			findUnfinishedKindExpression( untyped, context, kind, pred, mode );
+		ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env );
+		return std::move( choice->expr );
+	}
+
+	/// Resolve `untyped` to the single expression whose candidate is the best match
+	ast::ptr< ast::Expr > findSingleExpression(
+		const ast::Expr * untyped, const ResolveContext & context
+	) {
+		Stats::ResolveTime::start( untyped );
+		auto res = findKindExpression( untyped, context );
+		Stats::ResolveTime::stop();
+		return res;
+	}
+} // anonymous namespace
+
+ast::ptr< ast::Expr > findSingleExpression(
+	const ast::Expr * untyped, const ast::Type * type,
+	const ResolveContext & context
+) {
+	assert( untyped && type );
+	ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
+	ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, context );
+	removeExtraneousCast( newExpr );
+	return newExpr;
+}
+
+namespace {
+	bool structOrUnion( const Candidate & i ) {
+		const ast::Type * t = i.expr->result->stripReferences();
+		return dynamic_cast< const ast::StructInstType * >( t ) || dynamic_cast< const ast::UnionInstType * >( t );
+	}
+	/// Predicate for "Candidate has integral type"
+	bool hasIntegralType( const Candidate & i ) {
+		const ast::Type * type = i.expr->result;
+
+		if ( auto bt = dynamic_cast< const ast::BasicType * >( type ) ) {
+			return bt->isInteger();
+		} else if (
+			dynamic_cast< const ast::EnumInstType * >( type )
+			|| dynamic_cast< const ast::ZeroType * >( type )
+			|| dynamic_cast< const ast::OneType * >( type )
+		) {
+			return true;
+		} else return false;
+	}
+
+	/// Resolve `untyped` as an integral expression, returning the resolved version
+	ast::ptr< ast::Expr > findIntegralExpression(
+		const ast::Expr * untyped, const ResolveContext & context
+	) {
+		return findKindExpression( untyped, context, hasIntegralType, "condition" );
+	}
+
+	ast::ptr< ast::Expr > findCondExpression(
+		const ast::Expr * untyped, const ResolveContext & context
+	) {
+		if ( nullptr == untyped ) return untyped;
+		ast::ptr<ast::Expr> condExpr = createCondExpr( untyped );
+		return findIntegralExpression( condExpr, context );
+	}
+
+	/// check if a type is a character type
+	bool isCharType( const ast::Type * t ) {
+		if ( auto bt = dynamic_cast< const ast::BasicType * >( t ) ) {
+			return bt->kind == ast::BasicKind::Char
+				|| bt->kind == ast::BasicKind::SignedChar
+				|| bt->kind == ast::BasicKind::UnsignedChar;
+		}
+		return false;
+	}
+
+	/// Advance a type itertor to the next mutex parameter
+	template<typename Iter>
+	inline bool nextMutex( Iter & it, const Iter & end ) {
+		while ( it != end && ! (*it)->is_mutex() ) { ++it; }
+		return it != end;
+	}
+} // anonymous namespace
+
+class Resolver final
+: public ast::WithSymbolTable, public ast::WithGuards,
+  public ast::WithVisitorRef<Resolver>, public ast::WithShortCircuiting,
+  public ast::WithStmtsToAdd<> {
+
+	ast::ptr< ast::Type > functionReturn = nullptr;
+	ast::CurrentObject currentObject;
+	// for work previously in GenInit
+	static InitTweak::ManagedTypes managedTypes;
+	ResolveContext context;
+
+	bool inEnumDecl = false;
+
+public:
+	static size_t traceId;
+	Resolver( const ast::TranslationGlobal & global ) :
+		ast::WithSymbolTable(ast::SymbolTable::ErrorDetection::ValidateOnAdd),
+		context{ symtab, global } {}
+	Resolver( const ResolveContext & context ) :
+		ast::WithSymbolTable{ context.symtab },
+		context{ symtab, context.global } {}
+
+	const ast::FunctionDecl * previsit( const ast::FunctionDecl * );
+	const ast::FunctionDecl * postvisit( const ast::FunctionDecl * );
+	const ast::ObjectDecl * previsit( const ast::ObjectDecl * );
+	void previsit( const ast::AggregateDecl * );
+	void previsit( const ast::StructDecl * );
+	void previsit( const ast::EnumDecl * );
+	const ast::StaticAssertDecl * previsit( const ast::StaticAssertDecl * );
+
+	const ast::ArrayType * previsit( const ast::ArrayType * );
+	const ast::PointerType * previsit( const ast::PointerType * );
+
+	const ast::ExprStmt *        previsit( const ast::ExprStmt * );
+	const ast::AsmExpr *         previsit( const ast::AsmExpr * );
+	const ast::AsmStmt *         previsit( const ast::AsmStmt * );
+	const ast::IfStmt *          previsit( const ast::IfStmt * );
+	const ast::WhileDoStmt *     previsit( const ast::WhileDoStmt * );
+	const ast::ForStmt *         previsit( const ast::ForStmt * );
+	const ast::SwitchStmt *      previsit( const ast::SwitchStmt * );
+	const ast::CaseClause *      previsit( const ast::CaseClause * );
+	const ast::BranchStmt *      previsit( const ast::BranchStmt * );
+	const ast::ReturnStmt *      previsit( const ast::ReturnStmt * );
+	const ast::ThrowStmt *       previsit( const ast::ThrowStmt * );
+	const ast::CatchClause *     previsit( const ast::CatchClause * );
+	const ast::CatchClause *     postvisit( const ast::CatchClause * );
+	const ast::WaitForStmt *     previsit( const ast::WaitForStmt * );
+	const ast::WithStmt *        previsit( const ast::WithStmt * );
+
+	const ast::SingleInit *      previsit( const ast::SingleInit * );
+	const ast::ListInit *        previsit( const ast::ListInit * );
+	const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
+
+	void resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd);
+	bool shouldGenCtorInit( const ast::ObjectDecl * ) const;
+
+	void beginScope() { managedTypes.beginScope(); }
+	void endScope() { managedTypes.endScope(); }
+	bool on_error(ast::ptr<ast::Decl> & decl);
+};
+// size_t Resolver::traceId = Stats::Heap::new_stacktrace_id("Resolver");
+
+InitTweak::ManagedTypes Resolver::managedTypes;
+
+void resolve( ast::TranslationUnit& translationUnit ) {
+	ast::Pass< Resolver >::run( translationUnit, translationUnit.global );
+}
+
+ast::ptr< ast::Init > resolveCtorInit(
+	const ast::ConstructorInit * ctorInit, const ResolveContext & context
+) {
+	assert( ctorInit );
+	ast::Pass< Resolver > resolver( context );
+	return ctorInit->accept( resolver );
+}
+
+const ast::Expr * resolveStmtExpr(
+	const ast::StmtExpr * stmtExpr, const ResolveContext & context
+) {
+	assert( stmtExpr );
+	ast::Pass< Resolver > resolver( context );
+	auto ret = mutate(stmtExpr->accept(resolver));
+	strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult();
+	return ret;
+}
+
+namespace {
+	const ast::Attribute * handleAttribute(const CodeLocation & loc, const ast::Attribute * attr, const ResolveContext & context) {
+		std::string name = attr->normalizedName();
+		if (name == "constructor" || name == "destructor") {
+			if (attr->params.size() == 1) {
+				auto arg = attr->params.front();
+				auto resolved = ResolvExpr::findSingleExpression( arg, new ast::BasicType( ast::BasicKind::LongLongSignedInt ), context );
+				auto result = eval(arg);
+
+				auto mutAttr = mutate(attr);
+				mutAttr->params.front() = resolved;
+				if (! result.hasKnownValue) {
+					SemanticWarning(loc, Warning::GccAttributes,
+						toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) );
+				}
+				else {
+					auto priority = result.knownValue;
+					if (priority < 101) {
+						SemanticWarning(loc, Warning::GccAttributes,
+							toCString( name, " priorities from 0 to 100 are reserved for the implementation" ) );
+					} else if (priority < 201 && ! buildingLibrary()) {
+						SemanticWarning(loc, Warning::GccAttributes,
+							toCString( name, " priorities from 101 to 200 are reserved for the implementation" ) );
+					}
+				}
+				return mutAttr;
+			} else if (attr->params.size() > 1) {
+				SemanticWarning(loc, Warning::GccAttributes, toCString( "too many arguments to ", name, " attribute" ) );
+			} else {
+				SemanticWarning(loc, Warning::GccAttributes, toCString( "too few arguments to ", name, " attribute" ) );
+			}
+		}
+		return attr;
+	}
+}
+
+const ast::FunctionDecl * Resolver::previsit( const ast::FunctionDecl * functionDecl ) {
+	GuardValue( functionReturn );
+
+	assert (functionDecl->unique());
+	if (!functionDecl->has_body() && !functionDecl->withExprs.empty()) {
+		SemanticError(functionDecl->location, functionDecl, "Function without body has with declarations");
+	}
+
+	if (!functionDecl->isTypeFixed) {
+		auto mutDecl = mutate(functionDecl);
+		auto mutType = mutDecl->type.get_and_mutate();
+
+		for (auto & attr: mutDecl->attributes) {
+			attr = handleAttribute(mutDecl->location, attr, context );
+		}
+
+		// handle assertions
+
+		symtab.enterScope();
+		mutType->forall.clear();
+		mutType->assertions.clear();
+		for (auto & typeParam : mutDecl->type_params) {
+			symtab.addType(typeParam);
+			mutType->forall.emplace_back(new ast::TypeInstType(typeParam));
+		}
+		for (auto & asst : mutDecl->assertions) {
+			asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), context);
+			symtab.addId(asst);
+			mutType->assertions.emplace_back(new ast::VariableExpr(functionDecl->location, asst));
+		}
+
+		// temporarily adds params to symbol table.
+		// actual scoping rules for params and withexprs differ - see Pass::visit(FunctionDecl)
+
+		std::vector<ast::ptr<ast::Type>> paramTypes;
+		std::vector<ast::ptr<ast::Type>> returnTypes;
+
+		for (auto & param : mutDecl->params) {
+			param = fixObjectType(param.strict_as<ast::ObjectDecl>(), context);
+			symtab.addId(param);
+			paramTypes.emplace_back(param->get_type());
+		}
+		for (auto & ret : mutDecl->returns) {
+			ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), context);
+			returnTypes.emplace_back(ret->get_type());
+		}
+		// since function type in decl is just a view of param types, need to update that as well
+		mutType->params = std::move(paramTypes);
+		mutType->returns = std::move(returnTypes);
+
+		auto renamedType = strict_dynamic_cast<const ast::FunctionType *>(renameTyVars(mutType, RenameMode::GEN_EXPR_ID));
+
+		std::list<ast::ptr<ast::Stmt>> newStmts;
+		resolveWithExprs (mutDecl->withExprs, newStmts);
+
+		if (mutDecl->stmts) {
+			auto mutStmt = mutDecl->stmts.get_and_mutate();
+			mutStmt->kids.splice(mutStmt->kids.begin(), std::move(newStmts));
+			mutDecl->stmts = mutStmt;
+		}
+
+		symtab.leaveScope();
+
+		mutDecl->type = renamedType;
+		mutDecl->mangleName = Mangle::mangle(mutDecl);
+		mutDecl->isTypeFixed = true;
+		functionDecl = mutDecl;
+	}
+	managedTypes.handleDWT(functionDecl);
+
+	functionReturn = extractResultType( functionDecl->type );
+	return functionDecl;
+}
+
+const ast::FunctionDecl * Resolver::postvisit( const ast::FunctionDecl * functionDecl ) {
+	// default value expressions have an environment which shouldn't be there and trips up
+	// later passes.
+	assert( functionDecl->unique() );
+	ast::FunctionType * mutType = mutate( functionDecl->type.get() );
+
+	for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) {
+		if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) {
+			if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) {
+				if ( init->value->env == nullptr ) continue;
+				// clone initializer minus the initializer environment
+				auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() );
+				auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() );
+				auto mutValue = mutate( mutInit->value.get() );
+
+				mutValue->env = nullptr;
+				mutInit->value = mutValue;
+				mutParam->init = mutInit;
+				mutType->params[i] = mutParam;
+
+				assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env);
+			}
+		}
+	}
+	mutate_field(functionDecl, &ast::FunctionDecl::type, mutType);
+	return functionDecl;
+}
+
+bool Resolver::shouldGenCtorInit( ast::ObjectDecl const * decl ) const {
+	// If we shouldn't try to construct it, then don't.
+	if ( !InitTweak::tryConstruct( decl ) ) return false;
+	// Otherwise, if it is a managed type, we may construct it.
+	if ( managedTypes.isManaged( decl ) ) return true;
+	// Skip construction if it is trivial at compile-time.
+	if ( InitTweak::isConstExpr( decl->init ) ) return false;
+	// Skip construction for local declarations.
+	return ( !isInFunction() || decl->storage.is_static );
+}
+
+const ast::ObjectDecl * Resolver::previsit( const ast::ObjectDecl * objectDecl ) {
+	// To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
+	// class-variable `initContext` is changed multiple times because the LHS is analyzed
+	// twice. The second analysis changes `initContext` because a function type can contain
+	// object declarations in the return and parameter types. Therefore each value of
+	// `initContext` is retained so the type on the first analysis is preserved and used for
+	// selecting the RHS.
+	GuardValue( currentObject );
+
+	if ( inEnumDecl && dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() ) ) {
+		// enumerator initializers should not use the enum type to initialize, since the
+		// enum type is still incomplete at this point. Use `int` instead.
+
+		if ( auto enumBase = dynamic_cast< const ast::EnumInstType * >
+			( objectDecl->get_type() )->base->base ) {
+			objectDecl = fixObjectType( objectDecl, context );
+			currentObject = ast::CurrentObject{
+				objectDecl->location,
+				enumBase
+			};
+		} else {
+			objectDecl = fixObjectType( objectDecl, context );
+			currentObject = ast::CurrentObject{
+				objectDecl->location, new ast::BasicType{ ast::BasicKind::SignedInt } };
+		}
+	} else {
+		if ( !objectDecl->isTypeFixed ) {
+			auto newDecl = fixObjectType(objectDecl, context);
+			auto mutDecl = mutate(newDecl);
+
+			// generate CtorInit wrapper when necessary.
+			// in certain cases, fixObjectType is called before reaching
+			// this object in visitor pass, thus disabling CtorInit codegen.
+			// this happens on aggregate members and function parameters.
+			if ( shouldGenCtorInit( mutDecl ) ) {
+				// constructed objects cannot be designated
+				if ( InitTweak::isDesignated( mutDecl->init ) ) {
+					ast::Pass<ResolveDesignators> res( context );
+					maybe_accept( mutDecl->init.get(), res );
+					if ( !res.core.result ) {
+						SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object.\n"
+									   "If this is really what you want, initialize with @=." );
+					}
+				}
+				// constructed objects should not have initializers nested too deeply
+				if ( ! InitTweak::checkInitDepth( mutDecl ) ) SemanticError( mutDecl, "Managed object's initializer is too deep " );
+
+				mutDecl->init = InitTweak::genCtorInit( mutDecl->location, mutDecl );
+			}
+
+			objectDecl = mutDecl;
+		}
+		currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
+	}
+
+	return objectDecl;
+}
+
+void Resolver::previsit( const ast::AggregateDecl * _aggDecl ) {
+	auto aggDecl = mutate(_aggDecl);
+	assertf(aggDecl == _aggDecl, "type declarations must be unique");
+
+	for (auto & member: aggDecl->members) {
+		// nested type decls are hoisted already. no need to do anything
+		if (auto obj = member.as<ast::ObjectDecl>()) {
+			member = fixObjectType(obj, context);
+		}
+	}
+}
+
+void Resolver::previsit( const ast::StructDecl * structDecl ) {
+	previsit(static_cast<const ast::AggregateDecl *>(structDecl));
+	managedTypes.handleStruct(structDecl);
+}
+
+void Resolver::previsit( const ast::EnumDecl * ) {
+	// in case we decide to allow nested enums
+	GuardValue( inEnumDecl );
+	inEnumDecl = true;
+	// don't need to fix types for enum fields
+}
+
+const ast::StaticAssertDecl * Resolver::previsit(
+	const ast::StaticAssertDecl * assertDecl
+) {
+	return ast::mutate_field(
+		assertDecl, &ast::StaticAssertDecl::cond,
+		findIntegralExpression( assertDecl->cond, context ) );
+}
+
+template< typename PtrType >
+const PtrType * handlePtrType( const PtrType * type, const ResolveContext & context ) {
+	if ( type->dimension ) {
+		const ast::Type * sizeType = context.global.sizeType.get();
+		ast::ptr< ast::Expr > dimension = findSingleExpression( type->dimension, sizeType, context );
+		assertf(dimension->env->empty(), "array dimension expr has nonempty env");
+		dimension.get_and_mutate()->env = nullptr;
+		ast::mutate_field( type, &PtrType::dimension, dimension );
+	}
+	return type;
+}
+
+const ast::ArrayType * Resolver::previsit( const ast::ArrayType * at ) {
+	return handlePtrType( at, context );
+}
+
+const ast::PointerType * Resolver::previsit( const ast::PointerType * pt ) {
+	return handlePtrType( pt, context );
+}
+
+const ast::ExprStmt * Resolver::previsit( const ast::ExprStmt * exprStmt ) {
+	visit_children = false;
+	assertf( exprStmt->expr, "ExprStmt has null expression in resolver" );
+
+	return ast::mutate_field(
+		exprStmt, &ast::ExprStmt::expr, findVoidExpression( exprStmt->expr, context ) );
+}
+
+const ast::AsmExpr * Resolver::previsit( const ast::AsmExpr * asmExpr ) {
+	visit_children = false;
+
+	asmExpr = ast::mutate_field(
+		asmExpr, &ast::AsmExpr::operand, findVoidExpression( asmExpr->operand, context ) );
+
+	return asmExpr;
+}
+
+const ast::AsmStmt * Resolver::previsit( const ast::AsmStmt * asmStmt ) {
+	visitor->maybe_accept( asmStmt, &ast::AsmStmt::input );
+	visitor->maybe_accept( asmStmt, &ast::AsmStmt::output );
+	visit_children = false;
+	return asmStmt;
+}
+
+const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) {
+	return ast::mutate_field(
+		ifStmt, &ast::IfStmt::cond, findCondExpression( ifStmt->cond, context ) );
+}
+
+const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) {
+	return ast::mutate_field(
+		whileDoStmt, &ast::WhileDoStmt::cond, findCondExpression( whileDoStmt->cond, context ) );
+}
+
+const ast::ForStmt * Resolver::previsit( const ast::ForStmt * forStmt ) {
+	if ( forStmt->cond ) {
+		forStmt = ast::mutate_field(
+			forStmt, &ast::ForStmt::cond, findCondExpression( forStmt->cond, context ) );
+	}
+
+	if ( forStmt->inc ) {
+		forStmt = ast::mutate_field(
+			forStmt, &ast::ForStmt::inc, findVoidExpression( forStmt->inc, context ) );
+	}
+
+	return forStmt;
+}
+
+const ast::SwitchStmt * Resolver::previsit( const ast::SwitchStmt * switchStmt ) {
+	GuardValue( currentObject );
+	switchStmt = ast::mutate_field(
+		switchStmt, &ast::SwitchStmt::cond,
+		findIntegralExpression( switchStmt->cond, context ) );
+	currentObject = ast::CurrentObject{ switchStmt->location, switchStmt->cond->result };
+	return switchStmt;
+}
+
+const ast::CaseClause * Resolver::previsit( const ast::CaseClause * caseStmt ) {
+	if ( caseStmt->cond ) {
+		std::deque< ast::InitAlternative > initAlts = currentObject.getOptions();
+		assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral "
+			"expression." );
+
+		ast::ptr< ast::Expr > untyped =
+			new ast::CastExpr{ caseStmt->location, caseStmt->cond, initAlts.front().type };
+		ast::ptr< ast::Expr > newExpr = findSingleExpression( untyped, context );
+
+		// case condition cannot have a cast in C, so it must be removed here, regardless of
+		// whether it would perform a conversion.
+		if ( const ast::CastExpr * castExpr = newExpr.as< ast::CastExpr >() ) {
+			swap_and_save_env( newExpr, castExpr->arg );
+		}
+
+		caseStmt = ast::mutate_field( caseStmt, &ast::CaseClause::cond, newExpr );
+	}
+	return caseStmt;
+}
+
+const ast::BranchStmt * Resolver::previsit( const ast::BranchStmt * branchStmt ) {
+	visit_children = false;
+	// must resolve the argument of a computed goto
+	if ( branchStmt->kind == ast::BranchStmt::Goto && branchStmt->computedTarget ) {
+		// computed goto argument is void*
+		ast::ptr< ast::Type > target = new ast::PointerType{ new ast::VoidType{} };
+		branchStmt = ast::mutate_field(
+			branchStmt, &ast::BranchStmt::computedTarget,
+			findSingleExpression( branchStmt->computedTarget, target, context ) );
+	}
+	return branchStmt;
+}
+
+const ast::ReturnStmt * Resolver::previsit( const ast::ReturnStmt * returnStmt ) {
+	visit_children = false;
+	if ( returnStmt->expr ) {
+		returnStmt = ast::mutate_field(
+			returnStmt, &ast::ReturnStmt::expr,
+			findSingleExpression( returnStmt->expr, functionReturn, context ) );
+	}
+	return returnStmt;
+}
+
+const ast::ThrowStmt * Resolver::previsit( const ast::ThrowStmt * throwStmt ) {
+	visit_children = false;
+	if ( throwStmt->expr ) {
+		const ast::StructDecl * exceptionDecl =
+			symtab.lookupStruct( "__cfaehm_base_exception_t" );
+		assert( exceptionDecl );
+		ast::ptr< ast::Type > exceptType =
+			new ast::PointerType{ new ast::StructInstType{ exceptionDecl } };
+		throwStmt = ast::mutate_field(
+			throwStmt, &ast::ThrowStmt::expr,
+			findSingleExpression( throwStmt->expr, exceptType, context ) );
+	}
+	return throwStmt;
+}
+
+const ast::CatchClause * Resolver::previsit( const ast::CatchClause * catchClause ) {
+	// Until we are very sure this invarent (ifs that move between passes have then)
+	// holds, check it. This allows a check for when to decode the mangling.
+	if ( auto ifStmt = catchClause->body.as<ast::IfStmt>() ) {
+		assert( ifStmt->then );
+	}
+	// Encode the catchStmt so the condition can see the declaration.
+	if ( catchClause->cond ) {
+		ast::CatchClause * clause = mutate( catchClause );
+		clause->body = new ast::IfStmt( clause->location, clause->cond, nullptr, clause->body );
+		clause->cond = nullptr;
+		return clause;
+	}
+	return catchClause;
+}
+
+const ast::CatchClause * Resolver::postvisit( const ast::CatchClause * catchClause ) {
+	// Decode the catchStmt so everything is stored properly.
+	const ast::IfStmt * ifStmt = catchClause->body.as<ast::IfStmt>();
+	if ( nullptr != ifStmt && nullptr == ifStmt->then ) {
+		assert( ifStmt->cond );
+		assert( ifStmt->else_ );
+		ast::CatchClause * clause = ast::mutate( catchClause );
+		clause->cond = ifStmt->cond;
+		clause->body = ifStmt->else_;
+		// ifStmt should be implicately deleted here.
+		return clause;
+	}
+	return catchClause;
+}
+
+const ast::WaitForStmt * Resolver::previsit( const ast::WaitForStmt * stmt ) {
+	visit_children = false;
+
+	// Resolve all clauses first
+	for ( unsigned i = 0; i < stmt->clauses.size(); ++i ) {
+		const ast::WaitForClause & clause = *stmt->clauses[i];
+
+		ast::TypeEnvironment env;
+		CandidateFinder funcFinder( context, env );
+
+		// Find all candidates for a function in canonical form
+		funcFinder.find( clause.target, ResolveMode::withAdjustment() );
+
+		if ( funcFinder.candidates.empty() ) {
+			stringstream ss;
+			ss << "Use of undeclared indentifier '";
+			ss << clause.target.strict_as< ast::NameExpr >()->name;
+			ss << "' in call to waitfor";
+			SemanticError( stmt->location, ss.str() );
+		}
+
+		if ( clause.target_args.empty() ) {
+			SemanticError( stmt->location,
+				"Waitfor clause must have at least one mutex parameter");
+		}
+
+		// Find all alternatives for all arguments in canonical form
+		std::vector< CandidateFinder > argFinders =
+			funcFinder.findSubExprs( clause.target_args );
+
+		// List all combinations of arguments
+		std::vector< CandidateList > possibilities;
+		combos( argFinders.begin(), argFinders.end(), back_inserter( possibilities ) );
+
+		// For every possible function:
+		// * try matching the arguments to the parameters, not the other way around because
+		//   more arguments than parameters
+		CandidateList funcCandidates;
+		std::vector< CandidateList > argsCandidates;
+		SemanticErrorException errors;
+		for ( CandidateRef & func : funcFinder.candidates ) {
+			try {
+				auto pointerType = dynamic_cast< const ast::PointerType * >(
+					func->expr->result->stripReferences() );
+				if ( ! pointerType ) {
+					SemanticError( stmt->location, func->expr->result.get(),
+						"candidate not viable: not a pointer type\n" );
+				}
+
+				auto funcType = pointerType->base.as< ast::FunctionType >();
+				if ( ! funcType ) {
+					SemanticError( stmt->location, func->expr->result.get(),
+						"candidate not viable: not a function type\n" );
+				}
+
+				{
+					auto param    = funcType->params.begin();
+					auto paramEnd = funcType->params.end();
+
+					if( ! nextMutex( param, paramEnd ) ) {
+						SemanticError( stmt->location, funcType,
+							"candidate function not viable: no mutex parameters\n");
+					}
+				}
+
+				CandidateRef func2{ new Candidate{ *func } };
+				// strip reference from function
+				func2->expr = referenceToRvalueConversion( func->expr, func2->cost );
+
+				// Each argument must be matched with a parameter of the current candidate
+				for ( auto & argsList : possibilities ) {
+					try {
+						// Declare data structures needed for resolution
+						ast::OpenVarSet open;
+						ast::AssertionSet need, have;
+						ast::TypeEnvironment resultEnv{ func->env };
+						// Add all type variables as open so that those not used in the
+						// parameter list are still considered open
+						resultEnv.add( funcType->forall );
+
+						// load type variables from arguments into one shared space
+						for ( auto & arg : argsList ) {
+							resultEnv.simpleCombine( arg->env );
+						}
+
+						// Make sure we don't widen any existing bindings
+						resultEnv.forbidWidening();
+
+						// Find any unbound type variables
+						resultEnv.extractOpenVars( open );
+
+						auto param = funcType->params.begin();
+						auto paramEnd = funcType->params.end();
+
+						unsigned n_mutex_param = 0;
+
+						// For every argument of its set, check if it matches one of the
+						// parameters. The order is important
+						for ( auto & arg : argsList ) {
+							// Ignore non-mutex arguments
+							if ( ! nextMutex( param, paramEnd ) ) {
+								// We ran out of parameters but still have arguments.
+								// This function doesn't match
+								SemanticError( stmt->location, funcType,
+									toString("candidate function not viable: too many mutex "
+									"arguments, expected ", n_mutex_param, "\n" ) );
+							}
+
+							++n_mutex_param;
+
+							// Check if the argument matches the parameter type in the current scope.
+							// ast::ptr< ast::Type > paramType = (*param)->get_type();
+
+							if (
+								! unify(
+									arg->expr->result, *param, resultEnv, need, have, open )
+							) {
+								// Type doesn't match
+								stringstream ss;
+								ss << "candidate function not viable: no known conversion "
+									"from '";
+								ast::print( ss, *param );
+								ss << "' to '";
+								ast::print( ss, arg->expr->result );
+								ss << "' with env '";
+								ast::print( ss, resultEnv );
+								ss << "'\n";
+								SemanticError( stmt->location, funcType, ss.str() );
+							}
+
+							++param;
+						}
+
+						// All arguments match!
+
+						// Check if parameters are missing
+						if ( nextMutex( param, paramEnd ) ) {
+							do {
+								++n_mutex_param;
+								++param;
+							} while ( nextMutex( param, paramEnd ) );
+
+							// We ran out of arguments but still have parameters left; this
+							// function doesn't match
+							SemanticError( stmt->location, funcType,
+								toString( "candidate function not viable: too few mutex "
+								"arguments, expected ", n_mutex_param, "\n" ) );
+						}
+
+						// All parameters match!
+
+						// Finish the expressions to tie in proper environments
+						finishExpr( func2->expr, resultEnv );
+						for ( CandidateRef & arg : argsList ) {
+							finishExpr( arg->expr, resultEnv );
+						}
+
+						// This is a match, store it and save it for later
+						funcCandidates.emplace_back( std::move( func2 ) );
+						argsCandidates.emplace_back( std::move( argsList ) );
+
+					} catch ( SemanticErrorException & e ) {
+						errors.append( e );
+					}
+				}
+			} catch ( SemanticErrorException & e ) {
+				errors.append( e );
+			}
+		}
+
+		// Make sure correct number of arguments
+		if( funcCandidates.empty() ) {
+			SemanticErrorException top( stmt->location,
+				"No alternatives for function in call to waitfor" );
+			top.append( errors );
+			throw top;
+		}
+
+		if( argsCandidates.empty() ) {
+			SemanticErrorException top( stmt->location,
+				"No alternatives for arguments in call to waitfor" );
+			top.append( errors );
+			throw top;
+		}
+
+		if( funcCandidates.size() > 1 ) {
+			SemanticErrorException top( stmt->location,
+				"Ambiguous function in call to waitfor" );
+			top.append( errors );
+			throw top;
+		}
+		if( argsCandidates.size() > 1 ) {
+			SemanticErrorException top( stmt->location,
+				"Ambiguous arguments in call to waitfor" );
+			top.append( errors );
+			throw top;
+		}
+		// TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
+
+		// build new clause
+		auto clause2 = new ast::WaitForClause( clause.location );
+
+		clause2->target = funcCandidates.front()->expr;
+
+		clause2->target_args.reserve( clause.target_args.size() );
+		const ast::StructDecl * decl_monitor = symtab.lookupStruct( "monitor$" );
+		for ( auto arg : argsCandidates.front() ) {
+			const auto & loc = stmt->location;
+
+			ast::Expr * init = new ast::CastExpr( loc,
+				new ast::UntypedExpr( loc,
+					new ast::NameExpr( loc, "get_monitor" ),
+					{ arg->expr }
+				),
+				new ast::PointerType(
+					new ast::StructInstType(
+						decl_monitor
+					)
+				)
+			);
+
+			clause2->target_args.emplace_back( findSingleExpression( init, context ) );
+		}
+
+		// Resolve the conditions as if it were an IfStmt, statements normally
+		clause2->when_cond = findCondExpression( clause.when_cond, context );
+		clause2->stmt = clause.stmt->accept( *visitor );
+
+		// set results into stmt
+		auto n = mutate( stmt );
+		n->clauses[i] = clause2;
+		stmt = n;
+	}
+
+	if ( stmt->timeout_stmt ) {
+		// resolve the timeout as a size_t, the conditions like IfStmt, and stmts normally
+		ast::ptr< ast::Type > target =
+			new ast::BasicType{ ast::BasicKind::LongLongUnsignedInt };
+		auto timeout_time = findSingleExpression( stmt->timeout_time, target, context );
+		auto timeout_cond = findCondExpression( stmt->timeout_cond, context );
+		auto timeout_stmt = stmt->timeout_stmt->accept( *visitor );
+
+		// set results into stmt
+		auto n = mutate( stmt );
+		n->timeout_time = std::move( timeout_time );
+		n->timeout_cond = std::move( timeout_cond );
+		n->timeout_stmt = std::move( timeout_stmt );
+		stmt = n;
+	}
+
+	if ( stmt->else_stmt ) {
+		// resolve the condition like IfStmt, stmts normally
+		auto else_cond = findCondExpression( stmt->else_cond, context );
+		auto else_stmt = stmt->else_stmt->accept( *visitor );
+
+		// set results into stmt
+		auto n = mutate( stmt );
+		n->else_cond = std::move( else_cond );
+		n->else_stmt = std::move( else_stmt );
+		stmt = n;
+	}
+
+	return stmt;
+}
+
+const ast::WithStmt * Resolver::previsit( const ast::WithStmt * withStmt ) {
+	auto mutStmt = mutate(withStmt);
+	resolveWithExprs(mutStmt->exprs, stmtsToAddBefore);
+	return mutStmt;
+}
+
+void Resolver::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) {
+	for (auto & expr : exprs) {
+		// only struct- and union-typed expressions are viable candidates
+		expr = findKindExpression( expr, context, structOrUnion, "with expression" );
+
+		// if with expression might be impure, create a temporary so that it is evaluated once
+		if ( Tuples::maybeImpure( expr ) ) {
+			static UniqueName tmpNamer( "_with_tmp_" );
+			const CodeLocation loc = expr->location;
+			auto tmp = new ast::ObjectDecl(loc, tmpNamer.newName(), expr->result, new ast::SingleInit(loc, expr ) );
+			expr = new ast::VariableExpr( loc, tmp );
+			stmtsToAdd.push_back( new ast::DeclStmt(loc, tmp ) );
+			if ( InitTweak::isConstructable( tmp->type ) ) {
+				// generate ctor/dtor and resolve them
+				tmp->init = InitTweak::genCtorInit( loc, tmp );
+			}
+			// since tmp is freshly created, this should modify tmp in-place
+			tmp->accept( *visitor );
+		} else if (expr->env && expr->env->empty()) {
+			expr = ast::mutate_field(expr.get(), &ast::Expr::env, nullptr);
+		}
+	}
+}
+
+const ast::SingleInit * Resolver::previsit( const ast::SingleInit * singleInit ) {
+	visit_children = false;
+	// resolve initialization using the possibilities as determined by the `currentObject`
+	// cursor.
+	ast::ptr< ast::Expr > untyped = new ast::UntypedInitExpr{
+		singleInit->location, singleInit->value, currentObject.getOptions() };
+	ast::ptr<ast::Expr> newExpr = findSingleExpression( untyped, context );
+	const ast::InitExpr * initExpr = newExpr.strict_as< ast::InitExpr >();
+
+	// move cursor to the object that is actually initialized
+	currentObject.setNext( initExpr->designation );
+
+	// discard InitExpr wrapper and retain relevant pieces.
+	// `initExpr` may have inferred params in the case where the expression specialized a
+	// function pointer, and newExpr may already have inferParams of its own, so a simple
+	// swap is not sufficient
+	ast::Expr::InferUnion inferred = initExpr->inferred;
+	swap_and_save_env( newExpr, initExpr->expr );
+	newExpr.get_and_mutate()->inferred.splice( std::move(inferred) );
+
+	// get the actual object's type (may not exactly match what comes back from the resolver
+	// due to conversions)
+	const ast::Type * initContext = currentObject.getCurrentType();
+
+	removeExtraneousCast( newExpr );
+
+	// check if actual object's type is char[]
+	if ( auto at = dynamic_cast< const ast::ArrayType * >( initContext ) ) {
+		if ( isCharType( at->base ) ) {
+			// check if the resolved type is char*
+			if ( auto pt = newExpr->result.as< ast::PointerType >() ) {
+				if ( isCharType( pt->base ) ) {
+					// strip cast if we're initializing a char[] with a char*
+					// e.g. char x[] = "hello"
+					if ( auto ce = newExpr.as< ast::CastExpr >() ) {
+						swap_and_save_env( newExpr, ce->arg );
+					}
+				}
+			}
+		}
+	}
+
+	// move cursor to next object in preparation for next initializer
+	currentObject.increment();
+
+	// set initializer expression to resolved expression
+	return ast::mutate_field( singleInit, &ast::SingleInit::value, std::move(newExpr) );
+}
+
+const ast::ListInit * Resolver::previsit( const ast::ListInit * listInit ) {
+	// move cursor into brace-enclosed initializer-list
+	currentObject.enterListInit( listInit->location );
+
+	assert( listInit->designations.size() == listInit->initializers.size() );
+	for ( unsigned i = 0; i < listInit->designations.size(); ++i ) {
+		// iterate designations and initializers in pairs, moving the cursor to the current
+		// designated object and resolving the initializer against that object
+		listInit = ast::mutate_field_index(
+			listInit, &ast::ListInit::designations, i,
+			currentObject.findNext( listInit->designations[i] ) );
+		listInit = ast::mutate_field_index(
+			listInit, &ast::ListInit::initializers, i,
+			listInit->initializers[i]->accept( *visitor ) );
+	}
+
+	// move cursor out of brace-enclosed initializer-list
+	currentObject.exitListInit();
+
+	visit_children = false;
+	return listInit;
+}
+
+const ast::ConstructorInit * Resolver::previsit( const ast::ConstructorInit * ctorInit ) {
+	visitor->maybe_accept( ctorInit, &ast::ConstructorInit::ctor );
+	visitor->maybe_accept( ctorInit, &ast::ConstructorInit::dtor );
+
+	// found a constructor - can get rid of C-style initializer
+	// xxx - Rob suggests this field is dead code
+	ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::init, nullptr );
+
+	// intrinsic single-parameter constructors and destructors do nothing. Since this was
+	// implicitly generated, there's no way for it to have side effects, so get rid of it to
+	// clean up generated code
+	if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
+		ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::ctor, nullptr );
+	}
+	if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {
+		ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::dtor, nullptr );
+	}
+
+	return ctorInit;
+}
+
+// suppress error on autogen functions and mark invalid autogen as deleted.
+bool Resolver::on_error(ast::ptr<ast::Decl> & decl) {
+	if (auto functionDecl = decl.as<ast::FunctionDecl>()) {
+		// xxx - can intrinsic gen ever fail?
+		if (functionDecl->linkage == ast::Linkage::AutoGen) {
+			auto mutDecl = mutate(functionDecl);
+			mutDecl->isDeleted = true;
+			mutDecl->stmts = nullptr;
+			decl = mutDecl;
+			return false;
+		}
+	}
+	return true;
+}
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/Resolver.h
===================================================================
--- src/ResolvExpr/Resolver.h	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,69 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Resolver.h --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 12:18:34 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Mar 16 11:32:00 2022
-// Update Count     : 5
-//
-
-#pragma once
-
-#include "AST/Node.hpp"  // for ptr
-
-namespace ast {
-	class ConstructorInit;
-	class Decl;
-	class DeletedExpr;
-	class Expr;
-	class Init;
-	class StmtExpr;
-	class SymbolTable;
-	class TranslationGlobal;
-	class TranslationUnit;
-	class Type;
-	class TypeEnvironment;
-} // namespace ast
-
-namespace ResolvExpr {
-
-/// Helper Type: Passes around information between various sub-calls.
-struct ResolveContext {
-	const ast::SymbolTable & symtab;
-	const ast::TranslationGlobal & global;
-};
-
-/// Checks types and binds syntactic constructs to typed representations
-void resolve( ast::TranslationUnit& translationUnit );
-/// Searches expr and returns the first DeletedExpr found, otherwise nullptr
-const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr );
-/// Find the expression candidate that is the unique
-/// best match for `untyped` in a `void` context.
-ast::ptr< ast::Expr > resolveInVoidContext(
-	const ast::Expr * expr, const ResolveContext &, ast::TypeEnvironment & env );
-/// Resolve `untyped` to the single expression whose
-/// candidate is the best match for the given type.
-ast::ptr< ast::Expr > findSingleExpression(
-	const ast::Expr * untyped, const ast::Type * type, const ResolveContext & );
-ast::ptr< ast::Expr > findVoidExpression(
-	const ast::Expr * untyped, const ResolveContext & );
-/// Resolves a constructor init expression
-ast::ptr< ast::Init > resolveCtorInit(
-	const ast::ConstructorInit * ctorInit, const ResolveContext & context );
-/// Resolves a statement expression
-const ast::Expr * resolveStmtExpr(
-	const ast::StmtExpr * stmtExpr, const ResolveContext & context );
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/Resolver.hpp
===================================================================
--- src/ResolvExpr/Resolver.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/Resolver.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,69 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Resolver.hpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 12:18:34 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Mar 16 11:32:00 2022
+// Update Count     : 5
+//
+
+#pragma once
+
+#include "AST/Node.hpp"  // for ptr
+
+namespace ast {
+	class ConstructorInit;
+	class Decl;
+	class DeletedExpr;
+	class Expr;
+	class Init;
+	class StmtExpr;
+	class SymbolTable;
+	class TranslationGlobal;
+	class TranslationUnit;
+	class Type;
+	class TypeEnvironment;
+} // namespace ast
+
+namespace ResolvExpr {
+
+/// Helper Type: Passes around information between various sub-calls.
+struct ResolveContext {
+	const ast::SymbolTable & symtab;
+	const ast::TranslationGlobal & global;
+};
+
+/// Checks types and binds syntactic constructs to typed representations
+void resolve( ast::TranslationUnit& translationUnit );
+/// Searches expr and returns the first DeletedExpr found, otherwise nullptr
+const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr );
+/// Find the expression candidate that is the unique
+/// best match for `untyped` in a `void` context.
+ast::ptr< ast::Expr > resolveInVoidContext(
+	const ast::Expr * expr, const ResolveContext &, ast::TypeEnvironment & env );
+/// Resolve `untyped` to the single expression whose
+/// candidate is the best match for the given type.
+ast::ptr< ast::Expr > findSingleExpression(
+	const ast::Expr * untyped, const ast::Type * type, const ResolveContext & );
+ast::ptr< ast::Expr > findVoidExpression(
+	const ast::Expr * untyped, const ResolveContext & );
+/// Resolves a constructor init expression
+ast::ptr< ast::Init > resolveCtorInit(
+	const ast::ConstructorInit * ctorInit, const ResolveContext & context );
+/// Resolves a statement expression
+const ast::Expr * resolveStmtExpr(
+	const ast::StmtExpr * stmtExpr, const ResolveContext & context );
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/SatisfyAssertions.cpp
===================================================================
--- src/ResolvExpr/SatisfyAssertions.cpp	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ src/ResolvExpr/SatisfyAssertions.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -28,9 +28,9 @@
 #include "CandidateFinder.hpp"
 #include "CommonType.hpp"
-#include "Cost.h"
-#include "RenameVars.h"
+#include "Cost.hpp"
+#include "RenameVars.hpp"
 #include "SpecCost.hpp"
-#include "typeops.h"
-#include "Unify.h"
+#include "Typeops.hpp"
+#include "Unify.hpp"
 #include "AST/Decl.hpp"
 #include "AST/Expr.hpp"
@@ -40,9 +40,9 @@
 #include "AST/SymbolTable.hpp"
 #include "AST/TypeEnvironment.hpp"
-#include "FindOpenVars.h"
-#include "Common/FilterCombos.h"
-#include "Common/Indenter.h"
-#include "GenPoly/GenPoly.h"
-#include "SymTab/Mangler.h"
+#include "FindOpenVars.hpp"
+#include "Common/FilterCombos.hpp"
+#include "Common/Indenter.hpp"
+#include "GenPoly/GenPoly.hpp"
+#include "SymTab/Mangler.hpp"
 
 namespace ResolvExpr {
Index: src/ResolvExpr/SpecCost.cc
===================================================================
--- src/ResolvExpr/SpecCost.cc	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,127 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// SpecCost.cc --
-//
-// Author           : Aaron B. Moss
-// Created On       : Tue Oct 02 15:50:00 2018
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Jul  3 11:07:00 2019
-// Update Count     : 3
-//
-
-#include <cassert>
-#include <limits>
-#include <type_traits>
-
-#include "AST/Pass.hpp"
-#include "AST/Type.hpp"
-
-namespace ResolvExpr {
-
-namespace {
-
-const ast::Type * expr_result( const ast::ptr< ast::Expr > & expr ) {
-	return expr->result.get();
-}
-
-const ast::Type * type_deref( const ast::ptr< ast::Type > & type ) {
-	return type.get();
-}
-
-/// The specialization counter inner class.
-class SpecCounter : public ast::WithShortCircuiting, public ast::WithVisitorRef<SpecCounter> {
-	int count = -1;  ///< specialization count (-1 for none)
-
-	// Converts the max value to -1 (none), otherwise increments the value.
-	static int toNoneOrInc( int value ) {
-		assert( 0 <= value );
-		return value < std::numeric_limits<int>::max() ? value + 1 : -1;
-	}
-
-	template<typename T> using MapperT =
-		typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type;
-
-	// Update the minimum to the new lowest non-none value.
-	template<typename T>
-	void updateMinimumPresent( int & minimum, const T & list, MapperT<T> mapper ) {
-		for ( const auto & node : list ) {
-			count = -1;
-
-			if ( ast::Type const * type = mapper( node ) ) {
-				ast::Type const * newType = type->accept( *visitor );
-				assert( newType == nullptr || newType == type );
-			}
-
-			if ( count != -1 && count < minimum ) minimum = count;
-		}
-	}
-
-	// Returns minimum non-negative count + 1 over type parameters (-1 if none such).
-	template<typename T>
-	int minimumPresent( const T & list, MapperT<T> mapper ) {
-		int minCount = std::numeric_limits<int>::max();
-		updateMinimumPresent( minCount, list, mapper );
-		return toNoneOrInc( minCount );
-	}
-
-public:
-	int result() const { return 0 <= count ? count : 0; }
-
-	// Mark specialization of base type.
-	void postvisit( const ast::PointerType * ) { if ( 0 <= count ) ++count; }
-	void postvisit( const ast::ArrayType * ) { if ( 0 <= count ) ++count; }
-	void postvisit( const ast::ReferenceType * ) { if ( 0 <= count ) ++count; }
-
-	void postvisit( const ast::StructInstType * ) { if ( 0 <= count ) ++count; }
-	void postvisit( const ast::UnionInstType * ) { if ( 0 <= count ) ++count; }
-
-	// Use the minimal specialization value over returns and params.
-	void previsit( const ast::FunctionType * fty ) {
-		int minCount = std::numeric_limits<int>::max();
-		updateMinimumPresent( minCount, fty->params, type_deref );
-		updateMinimumPresent( minCount, fty->returns, type_deref );
-		// Add another level to minCount if set.
-		count = toNoneOrInc( minCount );
-		// We have already visited children.
-		visit_children = false;
-	}
-
-	// Look for polymorphic parameters.
-	void previsit( const ast::StructInstType * sty ) {
-		count = minimumPresent( sty->params, expr_result );
-	}
-
-	// Look for polymorphic parameters.
-	void previsit( const ast::UnionInstType * uty ) {
-		count = minimumPresent( uty->params, expr_result );
-	}
-
-	// Note polymorphic type (which may be specialized).
-	// xxx - maybe account for open/closed type variables
-	void postvisit( const ast::TypeInstType * ) { count = 0; }
-
-	// Use the minimal specialization over elements.
-	// xxx - maybe don't increment, tuple flattening doesn't necessarily specialize
-	void previsit( const ast::TupleType * tty ) {
-		count = minimumPresent( tty->types, type_deref );
-		visit_children = false;
-	}
-};
-
-} // namespace
-
-int specCost( const ast::Type * type ) {
-	return ( nullptr == type ) ? 0 : ast::Pass<SpecCounter>::read( type );
-}
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/SpecCost.cpp
===================================================================
--- src/ResolvExpr/SpecCost.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/SpecCost.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,127 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// SpecCost.cc --
+//
+// Author           : Aaron B. Moss
+// Created On       : Tue Oct 02 15:50:00 2018
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jul  3 11:07:00 2019
+// Update Count     : 3
+//
+
+#include <cassert>
+#include <limits>
+#include <type_traits>
+
+#include "AST/Pass.hpp"
+#include "AST/Type.hpp"
+
+namespace ResolvExpr {
+
+namespace {
+
+const ast::Type * expr_result( const ast::ptr< ast::Expr > & expr ) {
+	return expr->result.get();
+}
+
+const ast::Type * type_deref( const ast::ptr< ast::Type > & type ) {
+	return type.get();
+}
+
+/// The specialization counter inner class.
+class SpecCounter : public ast::WithShortCircuiting, public ast::WithVisitorRef<SpecCounter> {
+	int count = -1;  ///< specialization count (-1 for none)
+
+	// Converts the max value to -1 (none), otherwise increments the value.
+	static int toNoneOrInc( int value ) {
+		assert( 0 <= value );
+		return value < std::numeric_limits<int>::max() ? value + 1 : -1;
+	}
+
+	template<typename T> using MapperT =
+		typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type;
+
+	// Update the minimum to the new lowest non-none value.
+	template<typename T>
+	void updateMinimumPresent( int & minimum, const T & list, MapperT<T> mapper ) {
+		for ( const auto & node : list ) {
+			count = -1;
+
+			if ( ast::Type const * type = mapper( node ) ) {
+				ast::Type const * newType = type->accept( *visitor );
+				assert( newType == nullptr || newType == type );
+			}
+
+			if ( count != -1 && count < minimum ) minimum = count;
+		}
+	}
+
+	// Returns minimum non-negative count + 1 over type parameters (-1 if none such).
+	template<typename T>
+	int minimumPresent( const T & list, MapperT<T> mapper ) {
+		int minCount = std::numeric_limits<int>::max();
+		updateMinimumPresent( minCount, list, mapper );
+		return toNoneOrInc( minCount );
+	}
+
+public:
+	int result() const { return 0 <= count ? count : 0; }
+
+	// Mark specialization of base type.
+	void postvisit( const ast::PointerType * ) { if ( 0 <= count ) ++count; }
+	void postvisit( const ast::ArrayType * ) { if ( 0 <= count ) ++count; }
+	void postvisit( const ast::ReferenceType * ) { if ( 0 <= count ) ++count; }
+
+	void postvisit( const ast::StructInstType * ) { if ( 0 <= count ) ++count; }
+	void postvisit( const ast::UnionInstType * ) { if ( 0 <= count ) ++count; }
+
+	// Use the minimal specialization value over returns and params.
+	void previsit( const ast::FunctionType * fty ) {
+		int minCount = std::numeric_limits<int>::max();
+		updateMinimumPresent( minCount, fty->params, type_deref );
+		updateMinimumPresent( minCount, fty->returns, type_deref );
+		// Add another level to minCount if set.
+		count = toNoneOrInc( minCount );
+		// We have already visited children.
+		visit_children = false;
+	}
+
+	// Look for polymorphic parameters.
+	void previsit( const ast::StructInstType * sty ) {
+		count = minimumPresent( sty->params, expr_result );
+	}
+
+	// Look for polymorphic parameters.
+	void previsit( const ast::UnionInstType * uty ) {
+		count = minimumPresent( uty->params, expr_result );
+	}
+
+	// Note polymorphic type (which may be specialized).
+	// xxx - maybe account for open/closed type variables
+	void postvisit( const ast::TypeInstType * ) { count = 0; }
+
+	// Use the minimal specialization over elements.
+	// xxx - maybe don't increment, tuple flattening doesn't necessarily specialize
+	void previsit( const ast::TupleType * tty ) {
+		count = minimumPresent( tty->types, type_deref );
+		visit_children = false;
+	}
+};
+
+} // namespace
+
+int specCost( const ast::Type * type ) {
+	return ( nullptr == type ) ? 0 : ast::Pass<SpecCounter>::read( type );
+}
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/Typeops.hpp
===================================================================
--- src/ResolvExpr/Typeops.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/Typeops.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,105 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Typeops.hpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 07:28:22 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jan 18 11:54:00 2023
+// Update Count     : 7
+//
+
+#pragma once
+
+#include <vector>
+
+#include "AST/Type.hpp"
+
+namespace ResolvExpr {
+
+class TypeEnvironment;
+
+// combos: takes a list of sets and returns a set of lists representing every possible way of forming a list by
+// picking one element out of each set
+template< typename InputIterator, typename OutputIterator >
+void combos( InputIterator begin, InputIterator end, OutputIterator out ) {
+	typedef typename InputIterator::value_type SetType;
+	typedef typename std::vector< typename SetType::value_type > ListType;
+
+	if ( begin == end )	{
+		*out++ = ListType();
+		return;
+	} // if
+
+	InputIterator current = begin;
+	begin++;
+
+	std::vector< ListType > recursiveResult;
+	combos( begin, end, back_inserter( recursiveResult ) );
+
+	for ( const auto& i : recursiveResult ) for ( const auto& j : *current ) {
+		ListType result;
+		std::back_insert_iterator< ListType > inserter = back_inserter( result );
+		*inserter++ = j;
+		std::copy( i.begin(), i.end(), inserter );
+		*out++ = result;
+	}
+}
+
+/// Flatten tuple type into existing list of types.
+inline void flatten(
+	const ast::Type * type, std::vector< ast::ptr< ast::Type > > & out
+) {
+	if ( auto tupleType = dynamic_cast< const ast::TupleType * >( type ) ) {
+		for ( const ast::Type * t : tupleType->types ) {
+			flatten( t, out );
+		}
+	} else {
+		out.emplace_back( type );
+	}
+}
+
+/// Flatten tuple type into list of types.
+inline std::vector< ast::ptr< ast::Type > > flatten( const ast::Type * type ) {
+	std::vector< ast::ptr< ast::Type > > out;
+	out.reserve( type->size() );
+	flatten( type, out );
+	return out;
+}
+
+template< typename Iter >
+const ast::Type * tupleFromTypes( Iter crnt, Iter end ) {
+	std::vector< ast::ptr< ast::Type > > types;
+	while ( crnt != end ) {
+		// it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure
+		// that this results in a flat tuple
+		flatten( *crnt, types );
+
+		++crnt;
+	}
+
+	return new ast::TupleType( std::move(types) );
+}
+
+inline const ast::Type * tupleFromTypes(
+	const std::vector< ast::ptr< ast::Type > > & tys
+) {
+	return tupleFromTypes( tys.begin(), tys.end() );
+}
+
+} // namespace ResolvExpr
+
+namespace ast {
+	// in TypeEnvironment.cpp
+	bool isFtype( const ast::Type * type );
+} // namespace ast
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,760 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Unify.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 12:27:10 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Dec 13 23:43:05 2019
-// Update Count     : 46
-//
-
-#include "Unify.h"
-
-#include <cassert>                  // for assertf, assert
-#include <iterator>                 // for back_insert_iterator, back_inserter
-#include <map>                      // for _Rb_tree_const_iterator, _Rb_tree_i...
-#include <memory>                   // for unique_ptr
-#include <set>                      // for set
-#include <string>                   // for string, operator==, operator!=, bas...
-#include <utility>                  // for pair, move
-#include <vector>
-
-#include "AST/Copy.hpp"
-#include "AST/Decl.hpp"
-#include "AST/Node.hpp"
-#include "AST/Pass.hpp"
-#include "AST/Print.hpp"
-#include "AST/Type.hpp"
-#include "AST/TypeEnvironment.hpp"
-#include "Common/Eval.h"            // for eval
-#include "CommonType.hpp"           // for commonType
-#include "FindOpenVars.h"           // for findOpenVars
-#include "SpecCost.hpp"             // for SpecCost
-#include "Tuples/Tuples.h"          // for isTtype
-#include "typeops.h"                // for flatten, occurs
-
-namespace ast {
-	class SymbolTable;
-}
-
-// #define DEBUG
-
-namespace ResolvExpr {
-
-bool typesCompatible(
-		const ast::Type * first, const ast::Type * second,
-		const ast::TypeEnvironment & env ) {
-	ast::TypeEnvironment newEnv;
-	ast::OpenVarSet open, closed;
-	ast::AssertionSet need, have;
-
-	ast::ptr<ast::Type> newFirst( first ), newSecond( second );
-	env.apply( newFirst );
-	env.apply( newSecond );
-
-	// findOpenVars( newFirst, open, closed, need, have, FirstClosed );
-	findOpenVars( newSecond, open, closed, need, have, newEnv, FirstOpen );
-
-	return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() );
-}
-
-bool typesCompatibleIgnoreQualifiers(
-		const ast::Type * first, const ast::Type * second,
-		const ast::TypeEnvironment & env ) {
-	ast::TypeEnvironment newEnv;
-	ast::OpenVarSet open;
-	ast::AssertionSet need, have;
-
-	ast::Type * newFirst  = shallowCopy( first  );
-	ast::Type * newSecond = shallowCopy( second );
-
-	newFirst ->qualifiers = {};
-	newSecond->qualifiers = {};
-	ast::ptr< ast::Type > t1_(newFirst );
-	ast::ptr< ast::Type > t2_(newSecond);
-
-	ast::ptr< ast::Type > subFirst = env.apply(newFirst).node;
-	ast::ptr< ast::Type > subSecond = env.apply(newSecond).node;
-
-	return unifyExact(
-		subFirst,
-		subSecond,
-		newEnv, need, have, open, noWiden() );
-}
-
-namespace {
-	/// Replaces ttype variables with their bound types.
-	/// If this isn't done when satifying ttype assertions, then argument lists can have
-	/// different size and structure when they should be compatible.
-	struct TtypeExpander : public ast::WithShortCircuiting, public ast::PureVisitor {
-		ast::TypeEnvironment & tenv;
-
-		TtypeExpander( ast::TypeEnvironment & env ) : tenv( env ) {}
-
-		const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
-			if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {
-				// expand ttype parameter into its actual type
-				if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
-					return clz->bound;
-				}
-			}
-			return typeInst;
-		}
-	};
-}
-
-std::vector< ast::ptr< ast::Type > > flattenList(
-	const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env
-) {
-	std::vector< ast::ptr< ast::Type > > dst;
-	dst.reserve( src.size() );
-	for ( const auto & d : src ) {
-		ast::Pass<TtypeExpander> expander( env );
-		// TtypeExpander pass is impure (may mutate nodes in place)
-		// need to make nodes shared to prevent accidental mutation
-		ast::ptr<ast::Type> dc = d->accept(expander);
-		auto types = flatten( dc );
-		for ( ast::ptr< ast::Type > & t : types ) {
-			// outermost const, volatile, _Atomic qualifiers in parameters should not play
-			// a role in the unification of function types, since they do not determine
-			// whether a function is callable.
-			// NOTE: **must** consider at least mutex qualifier, since functions can be
-			// overloaded on outermost mutex and a mutex function has different
-			// requirements than a non-mutex function
-			remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
-			dst.emplace_back( t );
-		}
-	}
-	return dst;
-}
-
-// Unification of Expressions
-//
-// Boolean outcome (obvious):  Are they basically spelled the same?
-// Side effect of binding variables (subtle):  if `sizeof(int)` ===_expr `sizeof(T)` then `int` ===_ty `T`
-//
-// Context:  if `float[VAREXPR1]` ===_ty `float[VAREXPR2]` then `VAREXPR1` ===_expr `VAREXPR2`
-// where the VAREXPR are meant as notational metavariables representing the fact that unification always
-// sees distinct ast::VariableExpr objects at these positions
-
-static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
-	ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
-	WidenMode widen );
-
-class UnifyExpr final : public ast::WithShortCircuiting {
-	const ast::Expr * e2;
-	ast::TypeEnvironment & tenv;
-	ast::AssertionSet & need;
-	ast::AssertionSet & have;
-	const ast::OpenVarSet & open;
-	WidenMode widen;
-public:
-	bool result;
-
-private:
-
-	void tryMatchOnStaticValue( const ast::Expr * e1 ) {
-		Evaluation r1 = eval(e1);
-		Evaluation r2 = eval(e2);
-
-		if ( !r1.hasKnownValue ) return;
-		if ( !r2.hasKnownValue ) return;
-
-		if ( r1.knownValue != r2.knownValue ) return;
-
-		visit_children = false;
-		result = true;
-	}
-
-public:
-
-	void previsit( const ast::Node * ) { assert(false); }
-
-	void previsit( const ast::Expr * e1 ) {
-		tryMatchOnStaticValue( e1 );
-		visit_children = false;
-	}
-
-	void previsit( const ast::CastExpr * e1 ) {
-		tryMatchOnStaticValue( e1 );
-
-		if ( result ) {
-			assert( visit_children == false );
-		} else {
-			assert( visit_children == true );
-			visit_children = false;
-
-			auto e2c = dynamic_cast< const ast::CastExpr * >( e2 );
-			if ( !e2c ) return;
-
-			// inspect casts' target types
-			if ( !unifyExact(
-				e1->result, e2c->result, tenv, need, have, open, widen ) ) return;
-
-			// inspect casts' inner expressions
-			result = unify( e1->arg, e2c->arg, tenv, need, have, open, widen );
-		}
-	}
-
-	void previsit( const ast::VariableExpr * e1 ) {
-		tryMatchOnStaticValue( e1 );
-
-		if ( result ) {
-			assert( visit_children == false );
-		} else {
-			assert( visit_children == true );
-			visit_children = false;
-
-			auto e2v = dynamic_cast< const ast::VariableExpr * >( e2 );
-			if ( !e2v ) return;
-
-			assert(e1->var);
-			assert(e2v->var);
-
-			// conservative: variable exprs match if their declarations are represented by the same C++ AST object
-			result = (e1->var == e2v->var);
-		}
-	}
-
-	void previsit( const ast::SizeofExpr * e1 ) {
-		tryMatchOnStaticValue( e1 );
-
-		if ( result ) {
-			assert( visit_children == false );
-		} else {
-			assert( visit_children == true );
-			visit_children = false;
-
-			auto e2so = dynamic_cast< const ast::SizeofExpr * >( e2 );
-			if ( !e2so ) return;
-
-			assert((e1->type != nullptr) ^ (e1->expr != nullptr));
-			assert((e2so->type != nullptr) ^ (e2so->expr != nullptr));
-			if ( !(e1->type && e2so->type) ) return;
-
-			// expression unification calls type unification (mutual recursion)
-			result = unifyExact( e1->type, e2so->type, tenv, need, have, open, widen );
-		}
-	}
-
-	UnifyExpr( const ast::Expr * e2, ast::TypeEnvironment & env, ast::AssertionSet & need,
-		ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
-	: e2( e2 ), tenv(env), need(need), have(have), open(open), widen(widen), result(false) {}
-};
-
-static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
-	ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
-	WidenMode widen ) {
-	assert( e1 && e2 );
-	return ast::Pass<UnifyExpr>::read( e1, e2, env, need, have, open, widen );
-}
-
-class Unify final : public ast::WithShortCircuiting {
-	const ast::Type * type2;
-	ast::TypeEnvironment & tenv;
-	ast::AssertionSet & need;
-	ast::AssertionSet & have;
-	const ast::OpenVarSet & open;
-	WidenMode widen;
-public:
-	static size_t traceId;
-	bool result;
-
-	Unify(
-		const ast::Type * type2, ast::TypeEnvironment & env, ast::AssertionSet & need,
-		ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
-	: type2(type2), tenv(env), need(need), have(have), open(open), widen(widen),
-	result(false) {}
-
-	void previsit( const ast::Node * ) { visit_children = false; }
-
-	void postvisit( const ast::VoidType * vt) {
-		result = dynamic_cast< const ast::VoidType * >( type2 )
-			|| tryToUnifyWithEnumValue(vt, type2, tenv, need, have, open, noWiden());
-		;
-	}
-
-	void postvisit( const ast::BasicType * basic ) {
-		if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
-			result = basic->kind == basic2->kind;
-		}
-		result = result || tryToUnifyWithEnumValue(basic, type2, tenv, need, have, open, noWiden());
-	}
-
-	void postvisit( const ast::PointerType * pointer ) {
-		if ( auto pointer2 = dynamic_cast< const ast::PointerType * >( type2 ) ) {
-			result = unifyExact(
-				pointer->base, pointer2->base, tenv, need, have, open,
-				noWiden());
-		}
-		result = result || tryToUnifyWithEnumValue(pointer, type2, tenv, need, have, open, noWiden());
-	}
-
-	void postvisit( const ast::ArrayType * array ) {
-		auto array2 = dynamic_cast< const ast::ArrayType * >( type2 );
-		if ( !array2 ) return;
-
-		if ( array->isVarLen != array2->isVarLen ) return;
-		if ( (array->dimension != nullptr) != (array2->dimension != nullptr) ) return;
-
-		if ( array->dimension ) {
-			assert( array2->dimension );
-			// type unification calls expression unification (mutual recursion)
-			if ( !unify(array->dimension, array2->dimension,
-				tenv, need, have, open, widen) ) return;
-		}
-
-		result = unifyExact(
-			array->base, array2->base, tenv, need, have, open, noWiden())
-			|| tryToUnifyWithEnumValue(array, type2, tenv, need, have, open, noWiden());
-	}
-
-	void postvisit( const ast::ReferenceType * ref ) {
-		if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) {
-			result = unifyExact(
-				ref->base, ref2->base, tenv, need, have, open, noWiden());
-		}
-	}
-
-private:
-
-	template< typename Iter >
-	static bool unifyTypeList(
-		Iter crnt1, Iter end1, Iter crnt2, Iter end2, ast::TypeEnvironment & env,
-		ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
-	) {
-		while ( crnt1 != end1 && crnt2 != end2 ) {
-			const ast::Type * t1 = *crnt1;
-			const ast::Type * t2 = *crnt2;
-			bool isTuple1 = Tuples::isTtype( t1 );
-			bool isTuple2 = Tuples::isTtype( t2 );
-
-			// assumes here that ttype *must* be last parameter
-			if ( isTuple1 && !isTuple2 ) {
-				// combine remainder of list2, then unify
-				return unifyExact(
-					t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
-					noWiden() );
-			} else if ( !isTuple1 && isTuple2 ) {
-				// combine remainder of list1, then unify
-				return unifyExact(
-					tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
-					noWiden() );
-			}
-
-			if ( !unifyExact(
-				t1, t2, env, need, have, open, noWiden() )
-			) return false;
-
-			++crnt1; ++crnt2;
-		}
-
-		// May get to the end of one argument list before the other. This is only okay if the
-		// other is a ttype
-		if ( crnt1 != end1 ) {
-			// try unifying empty tuple with ttype
-			const ast::Type * t1 = *crnt1;
-			if ( !Tuples::isTtype( t1 ) ) return false;
-			return unifyExact(
-				t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
-				noWiden() );
-		} else if ( crnt2 != end2 ) {
-			// try unifying empty tuple with ttype
-			const ast::Type * t2 = *crnt2;
-			if ( !Tuples::isTtype( t2 ) ) return false;
-			return unifyExact(
-				tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
-				noWiden() );
-		}
-
-		return true;
-	}
-
-	static bool unifyTypeList(
-		const std::vector< ast::ptr< ast::Type > > & list1,
-		const std::vector< ast::ptr< ast::Type > > & list2,
-		ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
-		const ast::OpenVarSet & open
-	) {
-		return unifyTypeList(
-			list1.begin(), list1.end(), list2.begin(), list2.end(), env, need, have, open);
-	}
-
-	static void markAssertionSet( ast::AssertionSet & assns, const ast::VariableExpr * assn ) {
-		auto i = assns.find( assn );
-		if ( i != assns.end() ) {
-			i->second.isUsed = true;
-		}
-	}
-
-	/// mark all assertions in `type` used in both `assn1` and `assn2`
-	static void markAssertions(
-		ast::AssertionSet & assn1, ast::AssertionSet & assn2,
-		const ast::FunctionType * type
-	) {
-		for ( auto & assert : type->assertions ) {
-			markAssertionSet( assn1, assert );
-			markAssertionSet( assn2, assert );
-		}
-	}
-
-	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 ) {
-		auto func2 = dynamic_cast< const ast::FunctionType * >( type2 );
-		if ( !func2 ) return;
-
-		if ( func->isVarArgs != func2->isVarArgs ) return;
-
-		// Flatten the parameter lists for both functions so that tuple structure does not
-		// affect unification. Does not actually mutate function parameters.
-		auto params = flattenList( func->params, tenv );
-		auto params2 = flattenList( func2->params, tenv );
-
-		// sizes don't have to match if ttypes are involved; need to be more precise w.r.t.
-		// where the ttype is to prevent errors
-		if (
-			( params.size() != params2.size() || func->returns.size() != func2->returns.size() )
-			&& !func->isTtype()
-			&& !func2->isTtype()
-		) return;
-
-		if ( !unifyTypeList( params, params2, tenv, need, have, open ) ) return;
-		if ( !unifyTypeList(
-			func->returns, func2->returns, tenv, need, have, open ) ) return;
-
-		markAssertions( have, need, func );
-		markAssertions( have, need, func2 );
-
-		result = true;
-	}
-
-private:
-	// Returns: other, cast as XInstType
-	// Assigns this->result: whether types are compatible (up to generic parameters)
-	template< typename XInstType >
-	const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) {
-		// check that the other type is compatible and named the same
-		auto otherInst = dynamic_cast< const XInstType * >( other );
-		if ( otherInst && inst->name == otherInst->name ) {
-			this->result = otherInst;
-		}
-		return otherInst;
-	}
-
-	/// Creates a tuple type based on a list of TypeExpr
-	template< typename Iter >
-	static const ast::Type * tupleFromExprs(
-		const ast::TypeExpr * param, Iter & crnt, Iter end, ast::CV::Qualifiers qs
-	) {
-		std::vector< ast::ptr< ast::Type > > types;
-		do {
-			types.emplace_back( param->type );
-
-			++crnt;
-			if ( crnt == end ) break;
-			param = strict_dynamic_cast< const ast::TypeExpr * >( crnt->get() );
-		} while(true);
-
-		return new ast::TupleType( std::move(types), qs );
-	}
-
-	template< typename XInstType >
-	void handleGenericRefType( const XInstType * inst, const ast::Type * other ) {
-		// check that other type is compatible and named the same
-		const XInstType * otherInst = handleRefType( inst, other );
-		if ( !this->result ) return;
-
-		// check that parameters of types unify, if any
-		const std::vector< ast::ptr< ast::Expr > > & params = inst->params;
-		const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params;
-
-		auto it = params.begin();
-		auto jt = params2.begin();
-		for ( ; it != params.end() && jt != params2.end(); ++it, ++jt ) {
-			auto param = strict_dynamic_cast< const ast::TypeExpr * >( it->get() );
-			auto param2 = strict_dynamic_cast< const ast::TypeExpr * >( jt->get() );
-
-			ast::ptr< ast::Type > pty = param->type;
-			ast::ptr< ast::Type > pty2 = param2->type;
-
-			bool isTuple = Tuples::isTtype( pty );
-			bool isTuple2 = Tuples::isTtype( pty2 );
-
-			if ( isTuple && isTuple2 ) {
-				++it; ++jt;  // skip ttype parameters before break
-			} else if ( isTuple ) {
-				// bundle remaining params into tuple
-				pty2 = tupleFromExprs( param2, jt, params2.end(), pty->qualifiers );
-				++it;  // skip ttype parameter for break
-			} else if ( isTuple2 ) {
-				// bundle remaining params into tuple
-				pty = tupleFromExprs( param, it, params.end(), pty2->qualifiers );
-				++jt;  // skip ttype parameter for break
-			}
-
-			if ( !unifyExact(
-					pty, pty2, tenv, need, have, open, noWiden() ) ) {
-				result = false;
-				return;
-			}
-
-			// ttype parameter should be last
-			if ( isTuple || isTuple2 ) break;
-		}
-		result = it == params.end() && jt == params2.end();
-	}
-
-public:
-	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 );
-		result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
-	}
-
-	void postvisit( const ast::EnumAttrType * enumAttr ) {
-		// Lazy approach for now
-		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());
-	}
-
-	void postvisit( const ast::TypeInstType * typeInst ) {
-		// assert( open.find( *typeInst ) == open.end() );
-		auto otherInst = dynamic_cast< const ast::TypeInstType * >( type2 );
-		if ( otherInst && typeInst->name == otherInst->name ) {
-			this->result = otherInst;
-		}
-		result = result || tryToUnifyWithEnumValue(typeInst, type2, tenv, need, have, open, noWiden());
-	}
-
-private:
-	/// Creates a tuple type based on a list of Type
-	static bool unifyList(
-		const std::vector< ast::ptr< ast::Type > > & list1,
-		const std::vector< ast::ptr< ast::Type > > & list2, ast::TypeEnvironment & env,
-		ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
-	) {
-		auto crnt1 = list1.begin();
-		auto crnt2 = list2.begin();
-		while ( crnt1 != list1.end() && crnt2 != list2.end() ) {
-			const ast::Type * t1 = *crnt1;
-			const ast::Type * t2 = *crnt2;
-			bool isTuple1 = Tuples::isTtype( t1 );
-			bool isTuple2 = Tuples::isTtype( t2 );
-
-			// assumes ttype must be last parameter
-			if ( isTuple1 && !isTuple2 ) {
-				// combine entirety of list2, then unify
-				return unifyExact(
-					t1, tupleFromTypes( list2 ), env, need, have, open,
-					noWiden() );
-			} else if ( !isTuple1 && isTuple2 ) {
-				// combine entirety of list1, then unify
-				return unifyExact(
-					tupleFromTypes( list1 ), t2, env, need, have, open,
-					noWiden() );
-			}
-
-			if ( !unifyExact(
-				t1, t2, env, need, have, open, noWiden() )
-			) return false;
-
-			++crnt1; ++crnt2;
-		}
-
-		if ( crnt1 != list1.end() ) {
-			// try unifying empty tuple type with ttype
-			const ast::Type * t1 = *crnt1;
-			if ( !Tuples::isTtype( t1 ) ) return false;
-			// xxx - this doesn't generate an empty tuple, contrary to comment; both ported
-			// from Rob's code
-			return unifyExact(
-					t1, tupleFromTypes( list2 ), env, need, have, open,
-					noWiden() );
-		} else if ( crnt2 != list2.end() ) {
-			// try unifying empty tuple with ttype
-			const ast::Type * t2 = *crnt2;
-			if ( !Tuples::isTtype( t2 ) ) return false;
-			// xxx - this doesn't generate an empty tuple, contrary to comment; both ported
-			// from Rob's code
-			return unifyExact(
-					tupleFromTypes( list1 ), t2, env, need, have, open,
-					noWiden() );
-		}
-
-		return true;
-	}
-
-public:
-	void postvisit( const ast::TupleType * tuple ) {
-		auto tuple2 = dynamic_cast< const ast::TupleType * >( type2 );
-		if ( ! tuple2 ) return;
-
-		ast::Pass<TtypeExpander> expander{ tenv };
-
-		const ast::Type * flat = tuple->accept( expander );
-		const ast::Type * flat2 = tuple2->accept( expander );
-
-		auto types = flatten( flat );
-		auto types2 = flatten( flat2 );
-
-		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());
-	}
-};
-
-// size_t Unify::traceId = Stats::Heap::new_stacktrace_id("Unify");
-
-bool unify(
-		const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
-		ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
-		ast::OpenVarSet & open
-) {
-	ast::ptr<ast::Type> common;
-	return unify( type1, type2, env, need, have, open, common );
-}
-
-bool unify(
-		const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
-		ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
-		ast::OpenVarSet & open, ast::ptr<ast::Type> & common
-) {
-	ast::OpenVarSet closed;
-	// findOpenVars( type1, open, closed, need, have, FirstClosed );
-	findOpenVars( type2, open, closed, need, have, env, FirstOpen );
-	return unifyInexact(
-		type1, type2, env, need, have, open, WidenMode{ true, true }, common );
-}
-
-bool unifyExact(
-		const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
-		ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
-		WidenMode widen
-) {
-	if ( type1->qualifiers != type2->qualifiers ) return false;
-
-	auto var1 = dynamic_cast< const ast::TypeInstType * >( type1 );
-	auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
-	bool isopen1 = var1 && env.lookup(*var1);
-	bool isopen2 = var2 && env.lookup(*var2);
-
-	if ( isopen1 && isopen2 ) {
-		if ( var1->base->kind != var2->base->kind ) return false;
-		return env.bindVarToVar(
-			var1, var2, ast::TypeData{ var1->base->kind, var1->base->sized||var2->base->sized }, need, have,
-			open, widen );
-	} else if ( isopen1 ) {
-		return env.bindVar( var1, type2, ast::TypeData{var1->base}, need, have, open, widen );
-	} else if ( isopen2 ) {
-		return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen );
-	} else {
-		return ast::Pass<Unify>::read(
-			type1, type2, env, need, have, open, widen );
-	}
-}
-
-bool unifyInexact(
-		const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
-		ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
-		const ast::OpenVarSet & open, WidenMode widen,
-		ast::ptr<ast::Type> & common
-) {
-	ast::CV::Qualifiers q1 = type1->qualifiers, q2 = type2->qualifiers;
-
-	// force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and
-	// type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1
-	ast::Type * t1 = shallowCopy(type1.get());
-	ast::Type * t2 = shallowCopy(type2.get());
-	t1->qualifiers = {};
-	t2->qualifiers = {};
-	ast::ptr< ast::Type > t1_(t1);
-	ast::ptr< ast::Type > t2_(t2);
-
-	if ( unifyExact( t1, t2, env, need, have, open, widen ) ) {
-		// if exact unification on unqualified types, try to merge qualifiers
-		if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) {
-			t1->qualifiers = q1 | q2;
-			common = t1;
-			return true;
-		} else {
-			return false;
-		}
-	} else if (( common = commonType( t1, t2, env, need, have, open, widen ))) {
-		// no exact unification, but common type
-		auto c = shallowCopy(common.get());
-		c->qualifiers = q1 | q2;
-		common = c;
-		return true;
-	} else {
-		return false;
-	}
-}
-
-ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) {
-	if ( func->returns.empty() ) return new ast::VoidType();
-	if ( func->returns.size() == 1 ) return func->returns[0];
-
-	std::vector<ast::ptr<ast::Type>> tys;
-	for ( const auto & decl : func->returns ) {
-		tys.emplace_back( decl );
-	}
-	return new ast::TupleType( std::move(tys) );
-}
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/Unify.cpp
===================================================================
--- src/ResolvExpr/Unify.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/Unify.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,760 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Unify.cpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 12:27:10 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Fri Dec 13 23:43:05 2019
+// Update Count     : 46
+//
+
+#include "Unify.hpp"
+
+#include <cassert>                  // for assertf, assert
+#include <iterator>                 // for back_insert_iterator, back_inserter
+#include <map>                      // for _Rb_tree_const_iterator, _Rb_tree_i...
+#include <memory>                   // for unique_ptr
+#include <set>                      // for set
+#include <string>                   // for string, operator==, operator!=, bas...
+#include <utility>                  // for pair, move
+#include <vector>
+
+#include "AST/Copy.hpp"
+#include "AST/Decl.hpp"
+#include "AST/Node.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Print.hpp"
+#include "AST/Type.hpp"
+#include "AST/TypeEnvironment.hpp"
+#include "Common/Eval.hpp"          // for eval
+#include "CommonType.hpp"           // for commonType
+#include "FindOpenVars.hpp"         // for findOpenVars
+#include "SpecCost.hpp"             // for SpecCost
+#include "Tuples/Tuples.hpp"        // for isTtype
+#include "Typeops.hpp"              // for flatten, occurs
+
+namespace ast {
+	class SymbolTable;
+}
+
+// #define DEBUG
+
+namespace ResolvExpr {
+
+bool typesCompatible(
+		const ast::Type * first, const ast::Type * second,
+		const ast::TypeEnvironment & env ) {
+	ast::TypeEnvironment newEnv;
+	ast::OpenVarSet open, closed;
+	ast::AssertionSet need, have;
+
+	ast::ptr<ast::Type> newFirst( first ), newSecond( second );
+	env.apply( newFirst );
+	env.apply( newSecond );
+
+	// findOpenVars( newFirst, open, closed, need, have, FirstClosed );
+	findOpenVars( newSecond, open, closed, need, have, newEnv, FirstOpen );
+
+	return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() );
+}
+
+bool typesCompatibleIgnoreQualifiers(
+		const ast::Type * first, const ast::Type * second,
+		const ast::TypeEnvironment & env ) {
+	ast::TypeEnvironment newEnv;
+	ast::OpenVarSet open;
+	ast::AssertionSet need, have;
+
+	ast::Type * newFirst  = shallowCopy( first  );
+	ast::Type * newSecond = shallowCopy( second );
+
+	newFirst ->qualifiers = {};
+	newSecond->qualifiers = {};
+	ast::ptr< ast::Type > t1_(newFirst );
+	ast::ptr< ast::Type > t2_(newSecond);
+
+	ast::ptr< ast::Type > subFirst = env.apply(newFirst).node;
+	ast::ptr< ast::Type > subSecond = env.apply(newSecond).node;
+
+	return unifyExact(
+		subFirst,
+		subSecond,
+		newEnv, need, have, open, noWiden() );
+}
+
+namespace {
+	/// Replaces ttype variables with their bound types.
+	/// If this isn't done when satifying ttype assertions, then argument lists can have
+	/// different size and structure when they should be compatible.
+	struct TtypeExpander : public ast::WithShortCircuiting, public ast::PureVisitor {
+		ast::TypeEnvironment & tenv;
+
+		TtypeExpander( ast::TypeEnvironment & env ) : tenv( env ) {}
+
+		const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
+			if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {
+				// expand ttype parameter into its actual type
+				if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
+					return clz->bound;
+				}
+			}
+			return typeInst;
+		}
+	};
+}
+
+std::vector< ast::ptr< ast::Type > > flattenList(
+	const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env
+) {
+	std::vector< ast::ptr< ast::Type > > dst;
+	dst.reserve( src.size() );
+	for ( const auto & d : src ) {
+		ast::Pass<TtypeExpander> expander( env );
+		// TtypeExpander pass is impure (may mutate nodes in place)
+		// need to make nodes shared to prevent accidental mutation
+		ast::ptr<ast::Type> dc = d->accept(expander);
+		auto types = flatten( dc );
+		for ( ast::ptr< ast::Type > & t : types ) {
+			// outermost const, volatile, _Atomic qualifiers in parameters should not play
+			// a role in the unification of function types, since they do not determine
+			// whether a function is callable.
+			// NOTE: **must** consider at least mutex qualifier, since functions can be
+			// overloaded on outermost mutex and a mutex function has different
+			// requirements than a non-mutex function
+			remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
+			dst.emplace_back( t );
+		}
+	}
+	return dst;
+}
+
+// Unification of Expressions
+//
+// Boolean outcome (obvious):  Are they basically spelled the same?
+// Side effect of binding variables (subtle):  if `sizeof(int)` ===_expr `sizeof(T)` then `int` ===_ty `T`
+//
+// Context:  if `float[VAREXPR1]` ===_ty `float[VAREXPR2]` then `VAREXPR1` ===_expr `VAREXPR2`
+// where the VAREXPR are meant as notational metavariables representing the fact that unification always
+// sees distinct ast::VariableExpr objects at these positions
+
+static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
+	ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
+	WidenMode widen );
+
+class UnifyExpr final : public ast::WithShortCircuiting {
+	const ast::Expr * e2;
+	ast::TypeEnvironment & tenv;
+	ast::AssertionSet & need;
+	ast::AssertionSet & have;
+	const ast::OpenVarSet & open;
+	WidenMode widen;
+public:
+	bool result;
+
+private:
+
+	void tryMatchOnStaticValue( const ast::Expr * e1 ) {
+		Evaluation r1 = eval(e1);
+		Evaluation r2 = eval(e2);
+
+		if ( !r1.hasKnownValue ) return;
+		if ( !r2.hasKnownValue ) return;
+
+		if ( r1.knownValue != r2.knownValue ) return;
+
+		visit_children = false;
+		result = true;
+	}
+
+public:
+
+	void previsit( const ast::Node * ) { assert(false); }
+
+	void previsit( const ast::Expr * e1 ) {
+		tryMatchOnStaticValue( e1 );
+		visit_children = false;
+	}
+
+	void previsit( const ast::CastExpr * e1 ) {
+		tryMatchOnStaticValue( e1 );
+
+		if ( result ) {
+			assert( visit_children == false );
+		} else {
+			assert( visit_children == true );
+			visit_children = false;
+
+			auto e2c = dynamic_cast< const ast::CastExpr * >( e2 );
+			if ( !e2c ) return;
+
+			// inspect casts' target types
+			if ( !unifyExact(
+				e1->result, e2c->result, tenv, need, have, open, widen ) ) return;
+
+			// inspect casts' inner expressions
+			result = unify( e1->arg, e2c->arg, tenv, need, have, open, widen );
+		}
+	}
+
+	void previsit( const ast::VariableExpr * e1 ) {
+		tryMatchOnStaticValue( e1 );
+
+		if ( result ) {
+			assert( visit_children == false );
+		} else {
+			assert( visit_children == true );
+			visit_children = false;
+
+			auto e2v = dynamic_cast< const ast::VariableExpr * >( e2 );
+			if ( !e2v ) return;
+
+			assert(e1->var);
+			assert(e2v->var);
+
+			// conservative: variable exprs match if their declarations are represented by the same C++ AST object
+			result = (e1->var == e2v->var);
+		}
+	}
+
+	void previsit( const ast::SizeofExpr * e1 ) {
+		tryMatchOnStaticValue( e1 );
+
+		if ( result ) {
+			assert( visit_children == false );
+		} else {
+			assert( visit_children == true );
+			visit_children = false;
+
+			auto e2so = dynamic_cast< const ast::SizeofExpr * >( e2 );
+			if ( !e2so ) return;
+
+			assert((e1->type != nullptr) ^ (e1->expr != nullptr));
+			assert((e2so->type != nullptr) ^ (e2so->expr != nullptr));
+			if ( !(e1->type && e2so->type) ) return;
+
+			// expression unification calls type unification (mutual recursion)
+			result = unifyExact( e1->type, e2so->type, tenv, need, have, open, widen );
+		}
+	}
+
+	UnifyExpr( const ast::Expr * e2, ast::TypeEnvironment & env, ast::AssertionSet & need,
+		ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
+	: e2( e2 ), tenv(env), need(need), have(have), open(open), widen(widen), result(false) {}
+};
+
+static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
+	ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
+	WidenMode widen ) {
+	assert( e1 && e2 );
+	return ast::Pass<UnifyExpr>::read( e1, e2, env, need, have, open, widen );
+}
+
+class Unify final : public ast::WithShortCircuiting {
+	const ast::Type * type2;
+	ast::TypeEnvironment & tenv;
+	ast::AssertionSet & need;
+	ast::AssertionSet & have;
+	const ast::OpenVarSet & open;
+	WidenMode widen;
+public:
+	static size_t traceId;
+	bool result;
+
+	Unify(
+		const ast::Type * type2, ast::TypeEnvironment & env, ast::AssertionSet & need,
+		ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
+	: type2(type2), tenv(env), need(need), have(have), open(open), widen(widen),
+	result(false) {}
+
+	void previsit( const ast::Node * ) { visit_children = false; }
+
+	void postvisit( const ast::VoidType * vt) {
+		result = dynamic_cast< const ast::VoidType * >( type2 )
+			|| tryToUnifyWithEnumValue(vt, type2, tenv, need, have, open, noWiden());
+		;
+	}
+
+	void postvisit( const ast::BasicType * basic ) {
+		if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
+			result = basic->kind == basic2->kind;
+		}
+		result = result || tryToUnifyWithEnumValue(basic, type2, tenv, need, have, open, noWiden());
+	}
+
+	void postvisit( const ast::PointerType * pointer ) {
+		if ( auto pointer2 = dynamic_cast< const ast::PointerType * >( type2 ) ) {
+			result = unifyExact(
+				pointer->base, pointer2->base, tenv, need, have, open,
+				noWiden());
+		}
+		result = result || tryToUnifyWithEnumValue(pointer, type2, tenv, need, have, open, noWiden());
+	}
+
+	void postvisit( const ast::ArrayType * array ) {
+		auto array2 = dynamic_cast< const ast::ArrayType * >( type2 );
+		if ( !array2 ) return;
+
+		if ( array->isVarLen != array2->isVarLen ) return;
+		if ( (array->dimension != nullptr) != (array2->dimension != nullptr) ) return;
+
+		if ( array->dimension ) {
+			assert( array2->dimension );
+			// type unification calls expression unification (mutual recursion)
+			if ( !unify(array->dimension, array2->dimension,
+				tenv, need, have, open, widen) ) return;
+		}
+
+		result = unifyExact(
+			array->base, array2->base, tenv, need, have, open, noWiden())
+			|| tryToUnifyWithEnumValue(array, type2, tenv, need, have, open, noWiden());
+	}
+
+	void postvisit( const ast::ReferenceType * ref ) {
+		if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) {
+			result = unifyExact(
+				ref->base, ref2->base, tenv, need, have, open, noWiden());
+		}
+	}
+
+private:
+
+	template< typename Iter >
+	static bool unifyTypeList(
+		Iter crnt1, Iter end1, Iter crnt2, Iter end2, ast::TypeEnvironment & env,
+		ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
+	) {
+		while ( crnt1 != end1 && crnt2 != end2 ) {
+			const ast::Type * t1 = *crnt1;
+			const ast::Type * t2 = *crnt2;
+			bool isTuple1 = Tuples::isTtype( t1 );
+			bool isTuple2 = Tuples::isTtype( t2 );
+
+			// assumes here that ttype *must* be last parameter
+			if ( isTuple1 && !isTuple2 ) {
+				// combine remainder of list2, then unify
+				return unifyExact(
+					t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
+					noWiden() );
+			} else if ( !isTuple1 && isTuple2 ) {
+				// combine remainder of list1, then unify
+				return unifyExact(
+					tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
+					noWiden() );
+			}
+
+			if ( !unifyExact(
+				t1, t2, env, need, have, open, noWiden() )
+			) return false;
+
+			++crnt1; ++crnt2;
+		}
+
+		// May get to the end of one argument list before the other. This is only okay if the
+		// other is a ttype
+		if ( crnt1 != end1 ) {
+			// try unifying empty tuple with ttype
+			const ast::Type * t1 = *crnt1;
+			if ( !Tuples::isTtype( t1 ) ) return false;
+			return unifyExact(
+				t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
+				noWiden() );
+		} else if ( crnt2 != end2 ) {
+			// try unifying empty tuple with ttype
+			const ast::Type * t2 = *crnt2;
+			if ( !Tuples::isTtype( t2 ) ) return false;
+			return unifyExact(
+				tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
+				noWiden() );
+		}
+
+		return true;
+	}
+
+	static bool unifyTypeList(
+		const std::vector< ast::ptr< ast::Type > > & list1,
+		const std::vector< ast::ptr< ast::Type > > & list2,
+		ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
+		const ast::OpenVarSet & open
+	) {
+		return unifyTypeList(
+			list1.begin(), list1.end(), list2.begin(), list2.end(), env, need, have, open);
+	}
+
+	static void markAssertionSet( ast::AssertionSet & assns, const ast::VariableExpr * assn ) {
+		auto i = assns.find( assn );
+		if ( i != assns.end() ) {
+			i->second.isUsed = true;
+		}
+	}
+
+	/// mark all assertions in `type` used in both `assn1` and `assn2`
+	static void markAssertions(
+		ast::AssertionSet & assn1, ast::AssertionSet & assn2,
+		const ast::FunctionType * type
+	) {
+		for ( auto & assert : type->assertions ) {
+			markAssertionSet( assn1, assert );
+			markAssertionSet( assn2, assert );
+		}
+	}
+
+	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 ) {
+		auto func2 = dynamic_cast< const ast::FunctionType * >( type2 );
+		if ( !func2 ) return;
+
+		if ( func->isVarArgs != func2->isVarArgs ) return;
+
+		// Flatten the parameter lists for both functions so that tuple structure does not
+		// affect unification. Does not actually mutate function parameters.
+		auto params = flattenList( func->params, tenv );
+		auto params2 = flattenList( func2->params, tenv );
+
+		// sizes don't have to match if ttypes are involved; need to be more precise w.r.t.
+		// where the ttype is to prevent errors
+		if (
+			( params.size() != params2.size() || func->returns.size() != func2->returns.size() )
+			&& !func->isTtype()
+			&& !func2->isTtype()
+		) return;
+
+		if ( !unifyTypeList( params, params2, tenv, need, have, open ) ) return;
+		if ( !unifyTypeList(
+			func->returns, func2->returns, tenv, need, have, open ) ) return;
+
+		markAssertions( have, need, func );
+		markAssertions( have, need, func2 );
+
+		result = true;
+	}
+
+private:
+	// Returns: other, cast as XInstType
+	// Assigns this->result: whether types are compatible (up to generic parameters)
+	template< typename XInstType >
+	const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) {
+		// check that the other type is compatible and named the same
+		auto otherInst = dynamic_cast< const XInstType * >( other );
+		if ( otherInst && inst->name == otherInst->name ) {
+			this->result = otherInst;
+		}
+		return otherInst;
+	}
+
+	/// Creates a tuple type based on a list of TypeExpr
+	template< typename Iter >
+	static const ast::Type * tupleFromExprs(
+		const ast::TypeExpr * param, Iter & crnt, Iter end, ast::CV::Qualifiers qs
+	) {
+		std::vector< ast::ptr< ast::Type > > types;
+		do {
+			types.emplace_back( param->type );
+
+			++crnt;
+			if ( crnt == end ) break;
+			param = strict_dynamic_cast< const ast::TypeExpr * >( crnt->get() );
+		} while(true);
+
+		return new ast::TupleType( std::move(types), qs );
+	}
+
+	template< typename XInstType >
+	void handleGenericRefType( const XInstType * inst, const ast::Type * other ) {
+		// check that other type is compatible and named the same
+		const XInstType * otherInst = handleRefType( inst, other );
+		if ( !this->result ) return;
+
+		// check that parameters of types unify, if any
+		const std::vector< ast::ptr< ast::Expr > > & params = inst->params;
+		const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params;
+
+		auto it = params.begin();
+		auto jt = params2.begin();
+		for ( ; it != params.end() && jt != params2.end(); ++it, ++jt ) {
+			auto param = strict_dynamic_cast< const ast::TypeExpr * >( it->get() );
+			auto param2 = strict_dynamic_cast< const ast::TypeExpr * >( jt->get() );
+
+			ast::ptr< ast::Type > pty = param->type;
+			ast::ptr< ast::Type > pty2 = param2->type;
+
+			bool isTuple = Tuples::isTtype( pty );
+			bool isTuple2 = Tuples::isTtype( pty2 );
+
+			if ( isTuple && isTuple2 ) {
+				++it; ++jt;  // skip ttype parameters before break
+			} else if ( isTuple ) {
+				// bundle remaining params into tuple
+				pty2 = tupleFromExprs( param2, jt, params2.end(), pty->qualifiers );
+				++it;  // skip ttype parameter for break
+			} else if ( isTuple2 ) {
+				// bundle remaining params into tuple
+				pty = tupleFromExprs( param, it, params.end(), pty2->qualifiers );
+				++jt;  // skip ttype parameter for break
+			}
+
+			if ( !unifyExact(
+					pty, pty2, tenv, need, have, open, noWiden() ) ) {
+				result = false;
+				return;
+			}
+
+			// ttype parameter should be last
+			if ( isTuple || isTuple2 ) break;
+		}
+		result = it == params.end() && jt == params2.end();
+	}
+
+public:
+	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 );
+		result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
+	}
+
+	void postvisit( const ast::EnumAttrType * enumAttr ) {
+		// Lazy approach for now
+		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());
+	}
+
+	void postvisit( const ast::TypeInstType * typeInst ) {
+		// assert( open.find( *typeInst ) == open.end() );
+		auto otherInst = dynamic_cast< const ast::TypeInstType * >( type2 );
+		if ( otherInst && typeInst->name == otherInst->name ) {
+			this->result = otherInst;
+		}
+		result = result || tryToUnifyWithEnumValue(typeInst, type2, tenv, need, have, open, noWiden());
+	}
+
+private:
+	/// Creates a tuple type based on a list of Type
+	static bool unifyList(
+		const std::vector< ast::ptr< ast::Type > > & list1,
+		const std::vector< ast::ptr< ast::Type > > & list2, ast::TypeEnvironment & env,
+		ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
+	) {
+		auto crnt1 = list1.begin();
+		auto crnt2 = list2.begin();
+		while ( crnt1 != list1.end() && crnt2 != list2.end() ) {
+			const ast::Type * t1 = *crnt1;
+			const ast::Type * t2 = *crnt2;
+			bool isTuple1 = Tuples::isTtype( t1 );
+			bool isTuple2 = Tuples::isTtype( t2 );
+
+			// assumes ttype must be last parameter
+			if ( isTuple1 && !isTuple2 ) {
+				// combine entirety of list2, then unify
+				return unifyExact(
+					t1, tupleFromTypes( list2 ), env, need, have, open,
+					noWiden() );
+			} else if ( !isTuple1 && isTuple2 ) {
+				// combine entirety of list1, then unify
+				return unifyExact(
+					tupleFromTypes( list1 ), t2, env, need, have, open,
+					noWiden() );
+			}
+
+			if ( !unifyExact(
+				t1, t2, env, need, have, open, noWiden() )
+			) return false;
+
+			++crnt1; ++crnt2;
+		}
+
+		if ( crnt1 != list1.end() ) {
+			// try unifying empty tuple type with ttype
+			const ast::Type * t1 = *crnt1;
+			if ( !Tuples::isTtype( t1 ) ) return false;
+			// xxx - this doesn't generate an empty tuple, contrary to comment; both ported
+			// from Rob's code
+			return unifyExact(
+					t1, tupleFromTypes( list2 ), env, need, have, open,
+					noWiden() );
+		} else if ( crnt2 != list2.end() ) {
+			// try unifying empty tuple with ttype
+			const ast::Type * t2 = *crnt2;
+			if ( !Tuples::isTtype( t2 ) ) return false;
+			// xxx - this doesn't generate an empty tuple, contrary to comment; both ported
+			// from Rob's code
+			return unifyExact(
+					tupleFromTypes( list1 ), t2, env, need, have, open,
+					noWiden() );
+		}
+
+		return true;
+	}
+
+public:
+	void postvisit( const ast::TupleType * tuple ) {
+		auto tuple2 = dynamic_cast< const ast::TupleType * >( type2 );
+		if ( ! tuple2 ) return;
+
+		ast::Pass<TtypeExpander> expander{ tenv };
+
+		const ast::Type * flat = tuple->accept( expander );
+		const ast::Type * flat2 = tuple2->accept( expander );
+
+		auto types = flatten( flat );
+		auto types2 = flatten( flat2 );
+
+		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());
+	}
+};
+
+// size_t Unify::traceId = Stats::Heap::new_stacktrace_id("Unify");
+
+bool unify(
+		const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
+		ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
+		ast::OpenVarSet & open
+) {
+	ast::ptr<ast::Type> common;
+	return unify( type1, type2, env, need, have, open, common );
+}
+
+bool unify(
+		const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
+		ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
+		ast::OpenVarSet & open, ast::ptr<ast::Type> & common
+) {
+	ast::OpenVarSet closed;
+	// findOpenVars( type1, open, closed, need, have, FirstClosed );
+	findOpenVars( type2, open, closed, need, have, env, FirstOpen );
+	return unifyInexact(
+		type1, type2, env, need, have, open, WidenMode{ true, true }, common );
+}
+
+bool unifyExact(
+		const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
+		ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
+		WidenMode widen
+) {
+	if ( type1->qualifiers != type2->qualifiers ) return false;
+
+	auto var1 = dynamic_cast< const ast::TypeInstType * >( type1 );
+	auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
+	bool isopen1 = var1 && env.lookup(*var1);
+	bool isopen2 = var2 && env.lookup(*var2);
+
+	if ( isopen1 && isopen2 ) {
+		if ( var1->base->kind != var2->base->kind ) return false;
+		return env.bindVarToVar(
+			var1, var2, ast::TypeData{ var1->base->kind, var1->base->sized||var2->base->sized }, need, have,
+			open, widen );
+	} else if ( isopen1 ) {
+		return env.bindVar( var1, type2, ast::TypeData{var1->base}, need, have, open, widen );
+	} else if ( isopen2 ) {
+		return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen );
+	} else {
+		return ast::Pass<Unify>::read(
+			type1, type2, env, need, have, open, widen );
+	}
+}
+
+bool unifyInexact(
+		const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
+		ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
+		const ast::OpenVarSet & open, WidenMode widen,
+		ast::ptr<ast::Type> & common
+) {
+	ast::CV::Qualifiers q1 = type1->qualifiers, q2 = type2->qualifiers;
+
+	// force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and
+	// type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1
+	ast::Type * t1 = shallowCopy(type1.get());
+	ast::Type * t2 = shallowCopy(type2.get());
+	t1->qualifiers = {};
+	t2->qualifiers = {};
+	ast::ptr< ast::Type > t1_(t1);
+	ast::ptr< ast::Type > t2_(t2);
+
+	if ( unifyExact( t1, t2, env, need, have, open, widen ) ) {
+		// if exact unification on unqualified types, try to merge qualifiers
+		if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) {
+			t1->qualifiers = q1 | q2;
+			common = t1;
+			return true;
+		} else {
+			return false;
+		}
+	} else if (( common = commonType( t1, t2, env, need, have, open, widen ))) {
+		// no exact unification, but common type
+		auto c = shallowCopy(common.get());
+		c->qualifiers = q1 | q2;
+		common = c;
+		return true;
+	} else {
+		return false;
+	}
+}
+
+ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) {
+	if ( func->returns.empty() ) return new ast::VoidType();
+	if ( func->returns.size() == 1 ) return func->returns[0];
+
+	std::vector<ast::ptr<ast::Type>> tys;
+	for ( const auto & decl : func->returns ) {
+		tys.emplace_back( decl );
+	}
+	return new ast::TupleType( std::move(tys) );
+}
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/Unify.h
===================================================================
--- src/ResolvExpr/Unify.h	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,71 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Unify.h --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 13:09:04 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Tue Jan 17 11:12:00 2023
-// Update Count     : 5
-//
-
-#pragma once
-
-#include "AST/Node.hpp"             // for ptr
-#include "AST/TypeEnvironment.hpp"  // for TypeEnvironment, AssertionSet, OpenVarSet
-#include "WidenMode.h"              // for WidenMode
-
-namespace ast {
-	class SymbolTable;
-	class Type;
-}
-
-namespace ResolvExpr {
-
-bool unify(
-	const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
-	ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
-	ast::OpenVarSet & open );
-
-bool unify(
-	const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
-	ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
-	ast::OpenVarSet & open, ast::ptr<ast::Type> & common );
-
-bool unifyExact(
-	const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
-	ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
-	WidenMode widen );
-
-bool unifyInexact(
-	const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
-	ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
-	const ast::OpenVarSet & open, WidenMode widen,
-	ast::ptr<ast::Type> & common );
-
-bool typesCompatible(
-	const ast::Type *, const ast::Type *,
-	const ast::TypeEnvironment & env = {} );
-
-bool typesCompatibleIgnoreQualifiers(
-	const ast::Type *, const ast::Type *,
-	const ast::TypeEnvironment & env = {} );
-
-/// Creates or extracts the type represented by returns in a `FunctionType`.
-ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func );
-
-std::vector<ast::ptr<ast::Type>> flattenList(
-	const std::vector<ast::ptr<ast::Type>> & src, ast::TypeEnvironment & env
-);
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/Unify.hpp
===================================================================
--- src/ResolvExpr/Unify.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/Unify.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,71 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Unify.hpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 13:09:04 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Jan 17 11:12:00 2023
+// Update Count     : 5
+//
+
+#pragma once
+
+#include "AST/Node.hpp"             // for ptr
+#include "AST/TypeEnvironment.hpp"  // for TypeEnvironment, AssertionSet, OpenVarSet
+#include "WidenMode.hpp"            // for WidenMode
+
+namespace ast {
+	class SymbolTable;
+	class Type;
+}
+
+namespace ResolvExpr {
+
+bool unify(
+	const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
+	ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
+	ast::OpenVarSet & open );
+
+bool unify(
+	const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
+	ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
+	ast::OpenVarSet & open, ast::ptr<ast::Type> & common );
+
+bool unifyExact(
+	const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
+	ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
+	WidenMode widen );
+
+bool unifyInexact(
+	const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
+	ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
+	const ast::OpenVarSet & open, WidenMode widen,
+	ast::ptr<ast::Type> & common );
+
+bool typesCompatible(
+	const ast::Type *, const ast::Type *,
+	const ast::TypeEnvironment & env = {} );
+
+bool typesCompatibleIgnoreQualifiers(
+	const ast::Type *, const ast::Type *,
+	const ast::TypeEnvironment & env = {} );
+
+/// Creates or extracts the type represented by returns in a `FunctionType`.
+ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func );
+
+std::vector<ast::ptr<ast::Type>> flattenList(
+	const std::vector<ast::ptr<ast::Type>> & src, ast::TypeEnvironment & env
+);
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/WidenMode.h
===================================================================
--- src/ResolvExpr/WidenMode.h	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,52 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// WidenMode.h --
-//
-// Author           : Aaron B. Moss
-// Created On       : Mon Jun 18 11:58:00 2018
-// Last Modified By : Aaron B. Moss
-// Last Modified On : Mon Jun 18 11:58:00 2018
-// Update Count     : 1
-//
-
-#pragma once
-
-namespace ResolvExpr {
-
-struct WidenMode {
-	WidenMode( bool first, bool second ): first( first ), second( second ) {}
-
-	WidenMode &operator|=( const WidenMode &other ) {
-		first |= other.first; second |= other.second; return *this;
-	}
-
-	WidenMode &operator&=( const WidenMode &other ) {
-		first &= other.first; second &= other.second; return *this;
-	}
-
-	WidenMode operator|( const WidenMode &other ) {
-		WidenMode newWM( *this ); newWM |= other; return newWM;
-	}
-
-	WidenMode operator&( const WidenMode &other ) {
-		WidenMode newWM( *this ); newWM &= other; return newWM;
-	}
-
-	operator bool() { return first && second; }
-
-	bool first : 1, second : 1;
-};
-
-static inline WidenMode noWiden() { return { false, false }; }
-
-} // namespace ResolvExpr
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/ResolvExpr/WidenMode.hpp
===================================================================
--- src/ResolvExpr/WidenMode.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/ResolvExpr/WidenMode.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,52 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// WidenMode.h --
+//
+// Author           : Aaron B. Moss
+// Created On       : Mon Jun 18 11:58:00 2018
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Mon Jun 18 11:58:00 2018
+// Update Count     : 1
+//
+
+#pragma once
+
+namespace ResolvExpr {
+
+struct WidenMode {
+	WidenMode( bool first, bool second ): first( first ), second( second ) {}
+
+	WidenMode &operator|=( const WidenMode &other ) {
+		first |= other.first; second |= other.second; return *this;
+	}
+
+	WidenMode &operator&=( const WidenMode &other ) {
+		first &= other.first; second &= other.second; return *this;
+	}
+
+	WidenMode operator|( const WidenMode &other ) {
+		WidenMode newWM( *this ); newWM |= other; return newWM;
+	}
+
+	WidenMode operator&( const WidenMode &other ) {
+		WidenMode newWM( *this ); newWM &= other; return newWM;
+	}
+
+	operator bool() { return first && second; }
+
+	bool first : 1, second : 1;
+};
+
+static inline WidenMode noWiden() { return { false, false }; }
+
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/module.mk
===================================================================
--- src/ResolvExpr/module.mk	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ src/ResolvExpr/module.mk	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -16,5 +16,5 @@
 
 SRC_RESOLVEXPR = \
-      ResolvExpr/AdjustExprType.cc \
+      ResolvExpr/AdjustExprType.cpp \
       ResolvExpr/AdjustExprType.hpp \
       ResolvExpr/Candidate.cpp \
@@ -22,38 +22,38 @@
       ResolvExpr/CandidateFinder.hpp \
       ResolvExpr/Candidate.hpp \
-      ResolvExpr/CastCost.cc \
+      ResolvExpr/CastCost.cpp \
       ResolvExpr/CastCost.hpp \
-      ResolvExpr/CommonType.cc \
+      ResolvExpr/CommonType.cpp \
       ResolvExpr/CommonType.hpp \
-      ResolvExpr/ConversionCost.cc \
-      ResolvExpr/ConversionCost.h \
-      ResolvExpr/Cost.h \
-      ResolvExpr/CurrentObject.cc \
-      ResolvExpr/CurrentObject.h \
+      ResolvExpr/ConversionCost.cpp \
+      ResolvExpr/ConversionCost.hpp \
+      ResolvExpr/Cost.hpp \
+      ResolvExpr/CurrentObject.cpp \
+      ResolvExpr/CurrentObject.hpp \
       ResolvExpr/ExplodedArg.cpp \
       ResolvExpr/ExplodedArg.hpp \
-      ResolvExpr/FindOpenVars.cc \
-      ResolvExpr/FindOpenVars.h \
-      ResolvExpr/PolyCost.cc \
+      ResolvExpr/FindOpenVars.cpp \
+      ResolvExpr/FindOpenVars.hpp \
+      ResolvExpr/PolyCost.cpp \
       ResolvExpr/PolyCost.hpp \
-      ResolvExpr/PtrsAssignable.cc \
+      ResolvExpr/PtrsAssignable.cpp \
       ResolvExpr/PtrsAssignable.hpp \
-      ResolvExpr/PtrsCastable.cc \
+      ResolvExpr/PtrsCastable.cpp \
       ResolvExpr/PtrsCastable.hpp \
-      ResolvExpr/RenameVars.cc \
-      ResolvExpr/RenameVars.h \
-      ResolvExpr/Resolver.cc \
-      ResolvExpr/Resolver.h \
-      ResolvExpr/ResolveTypeof.cc \
-      ResolvExpr/ResolveTypeof.h \
+      ResolvExpr/RenameVars.cpp \
+      ResolvExpr/RenameVars.hpp \
+      ResolvExpr/Resolver.cpp \
+      ResolvExpr/Resolver.hpp \
+      ResolvExpr/ResolveTypeof.cpp \
+      ResolvExpr/ResolveTypeof.hpp \
       ResolvExpr/ResolveMode.hpp \
       ResolvExpr/SatisfyAssertions.cpp \
       ResolvExpr/SatisfyAssertions.hpp \
-      ResolvExpr/SpecCost.cc \
+      ResolvExpr/SpecCost.cpp \
       ResolvExpr/SpecCost.hpp \
-      ResolvExpr/typeops.h \
-      ResolvExpr/Unify.cc \
-      ResolvExpr/Unify.h \
-      ResolvExpr/WidenMode.h
+      ResolvExpr/typeops.hpp \
+      ResolvExpr/Unify.cpp \
+      ResolvExpr/Unify.hpp \
+      ResolvExpr/WidenMode.hpp
 
 SRC += $(SRC_RESOLVEXPR) \
Index: src/ResolvExpr/typeops.h
===================================================================
--- src/ResolvExpr/typeops.h	(revision 0b6c1c9d7993039f8227b9cd78963415137bb5ef)
+++ 	(revision )
@@ -1,105 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// typeops.h --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 07:28:22 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Jan 18 11:54:00 2023
-// Update Count     : 7
-//
-
-#pragma once
-
-#include <vector>
-
-#include "AST/Type.hpp"
-
-namespace ResolvExpr {
-
-class TypeEnvironment;
-
-// combos: takes a list of sets and returns a set of lists representing every possible way of forming a list by
-// picking one element out of each set
-template< typename InputIterator, typename OutputIterator >
-void combos( InputIterator begin, InputIterator end, OutputIterator out ) {
-	typedef typename InputIterator::value_type SetType;
-	typedef typename std::vector< typename SetType::value_type > ListType;
-
-	if ( begin == end )	{
-		*out++ = ListType();
-		return;
-	} // if
-
-	InputIterator current = begin;
-	begin++;
-
-	std::vector< ListType > recursiveResult;
-	combos( begin, end, back_inserter( recursiveResult ) );
-
-	for ( const auto& i : recursiveResult ) for ( const auto& j : *current ) {
-		ListType result;
-		std::back_insert_iterator< ListType > inserter = back_inserter( result );
-		*inserter++ = j;
-		std::copy( i.begin(), i.end(), inserter );
-		*out++ = result;
-	}
-}
-
-/// Flatten tuple type into existing list of types.
-inline void flatten(
-	const ast::Type * type, std::vector< ast::ptr< ast::Type > > & out
-) {
-	if ( auto tupleType = dynamic_cast< const ast::TupleType * >( type ) ) {
-		for ( const ast::Type * t : tupleType->types ) {
-			flatten( t, out );
-		}
-	} else {
-		out.emplace_back( type );
-	}
-}
-
-/// Flatten tuple type into list of types.
-inline std::vector< ast::ptr< ast::Type > > flatten( const ast::Type * type ) {
-	std::vector< ast::ptr< ast::Type > > out;
-	out.reserve( type->size() );
-	flatten( type, out );
-	return out;
-}
-
-template< typename Iter >
-const ast::Type * tupleFromTypes( Iter crnt, Iter end ) {
-	std::vector< ast::ptr< ast::Type > > types;
-	while ( crnt != end ) {
-		// it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure
-		// that this results in a flat tuple
-		flatten( *crnt, types );
-
-		++crnt;
-	}
-
-	return new ast::TupleType( std::move(types) );
-}
-
-inline const ast::Type * tupleFromTypes(
-	const std::vector< ast::ptr< ast::Type > > & tys
-) {
-	return tupleFromTypes( tys.begin(), tys.end() );
-}
-
-} // namespace ResolvExpr
-
-namespace ast {
-	// in TypeEnvironment.cpp
-	bool isFtype( const ast::Type * type );
-} // namespace ast
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
