Index: src/ResolvExpr/AdjustExprType.cc
===================================================================
--- src/ResolvExpr/AdjustExprType.cc	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/AdjustExprType.cc	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -23,51 +23,53 @@
 
 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 ) {}
+class AdjustExprType final : public ast::WithShortCircuiting {
+	const ast::SymbolTable & symtab;
+public:
+	const ast::TypeEnvironment & tenv;
 
-		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; }
+	AdjustExprType( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
+	: symtab( syms ), tenv( e ) {}
 
-		const ast::Type * postvisit( const ast::ArrayType * at ) {
-			return new ast::PointerType{ at->base, at->qualifiers };
-		}
+	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::FunctionType * ft ) {
-			return new ast::PointerType{ ft };
-		}
+	const ast::Type * postvisit( const ast::ArrayType * at ) {
+		return new ast::PointerType( at->base, at->qualifiers );
+	}
 
-		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 };
-					}
+	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;
 		}
-	};
+		return inst;
+	}
+};
+
 } // anonymous namespace
 
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -751,5 +751,5 @@
 			const ast::Type * returnType = funcType->returns.front();
 			if ( selfFinder.strictMode ) {
-				if ( ! unifyExact(
+				if ( !unifyExact(
 					returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, noWiden() ) // xxx - is no widening correct?
 				) {
@@ -757,7 +757,6 @@
 					return;
 				}
-			}
-			else {
-				if ( ! unify(
+			} else {
+				if ( !unify(
 					returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen )
 				) {
@@ -1109,6 +1108,5 @@
 						intrinsicResult.emplace_back(std::move(withFunc));
 					}
-				}
-				else {
+				} else {
 					candidates.emplace_back( std::move( withFunc ) );
 				}
@@ -1156,5 +1154,5 @@
 
 		for ( CandidateRef & r : finder.candidates ) {
-			if ( ! isLvalue( r->expr ) ) continue;
+			if ( !isLvalue( r->expr ) ) continue;
 			addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );
 		}
Index: src/ResolvExpr/CommonType.cc
===================================================================
--- src/ResolvExpr/CommonType.cc	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/CommonType.cc	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -343,477 +343,466 @@
 	);
 
-	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::BasicType::Kind 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 };
+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::BasicType::Kind 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 ) {
+				result = enumDecl->base.get();
+			} else {
+				ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ];
+				if (
+					( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
+						|| widen.first )
+					&& ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
+						|| widen.second )
+				) {
+					result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
 				}
+			}
+		}
+	}
+
+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 );
+	}
+
+	// For a typed enum, we want to unify type1 with the base type of the enum
+	bool tryResolveWithTypedEnum( const ast::Type * type1 ) {
+		if (auto enumInst = dynamic_cast<const ast::EnumInstType *> (type2) ) {
+			ast::OpenVarSet newOpen{ open };
+			if (enumInst->base->base
+				&& unifyExact(type1, enumInst->base->base, tenv, need, have, newOpen, widen)) {
+					result = type1;
+				return true;
+			}
+		}
+		return false;
+	}
+
+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 (
-				dynamic_cast< const ast::ZeroType * >( type2 )
-				|| dynamic_cast< const ast::OneType * >( type2 )
+				widen.second
+				&& pointer->base.as< ast::VoidType >()
+				&& ! ast::isFtype( pointer2->base )
 			) {
-				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 ) {
-					result = enumDecl->base.get();
-				} else {
-					ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ];
+				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 (
-						( ( 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 };
+						( 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 );
+		} else {
+			tryResolveWithTypedEnum( pointer );
+		}
+	}
+
+	void postvisit( const ast::ArrayType * arr ) {
+		// xxx - does it make sense?
+		tryResolveWithTypedEnum( arr );
+	}
+
+	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;
 					}
 				}
 			}
-		}
-
-	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 );
-		}
-
-		// For a typed enum, we want to unify type1 with the base type of the enum
-		bool tryResolveWithTypedEnum( const ast::Type * type1 ) {
-			if (auto enumInst = dynamic_cast<const ast::EnumInstType *> (type2) ) {
-				ast::OpenVarSet newOpen{ open };
-				if (enumInst->base->base 
-				&& unifyExact(type1, enumInst->base->base, tenv, need, have, newOpen, widen)) {
-					result = type1;
-					return true;
-				}
-			}
-			return false;
-		}
-
-	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 );
+		} 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 * func) {
+		tryResolveWithTypedEnum( func );
+	}
+
+	void postvisit( const ast::StructInstType * inst ) {
+		tryResolveWithTypedEnum( inst );
+	}
+
+	void postvisit( const ast::UnionInstType * inst ) {
+		tryResolveWithTypedEnum( inst );
+	}
+
+	void postvisit( const ast::EnumInstType * enumInst ) {
+		if (!dynamic_cast<const ast::EnumInstType *>(type2))
+			result = commonType( type2, enumInst, tenv, need, have, open, widen);
+		}
+
+	void postvisit( const ast::TraitInstType * ) {}
+
+	void postvisit( const ast::TypeInstType * ) {}
+
+	void postvisit( const ast::TupleType * tuple ) {
+		tryResolveWithTypedEnum( tuple );
+	}
+
+	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::BasicType::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 ( tryResolveWithTypedEnum( zero ) )
+					add_qualifiers( result, zero->qualifiers );
 			} else {
-				tryResolveWithTypedEnum( pointer );
-			}
-		}
-
-		void postvisit( const ast::ArrayType * arr ) {
-			// xxx - does it make sense? 
-			tryResolveWithTypedEnum( arr );
-		}
-
-		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 * func) {
-			tryResolveWithTypedEnum( func ); 
-		}
-
-		void postvisit( const ast::StructInstType * inst ) {
-			tryResolveWithTypedEnum( inst );
-		}
-
-		void postvisit( const ast::UnionInstType * inst ) {
-			tryResolveWithTypedEnum( inst );
-		}
-
-		void postvisit( const ast::EnumInstType * enumInst ) {
-			if (!dynamic_cast<const ast::EnumInstType *>(type2))
-				result = commonType( type2, enumInst, tenv, need, have, open, widen);
-		}
-
-		void postvisit( const ast::TraitInstType * ) {}
-
-		void postvisit( const ast::TypeInstType * ) {}
-
-		void postvisit( const ast::TupleType * tuple ) {
-			tryResolveWithTypedEnum( tuple );
-		}
-
-		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::BasicType::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 ( tryResolveWithTypedEnum( zero ) ) 
-						add_qualifiers( result, zero->qualifiers );
-				} else {
-					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 ) ) {
+			}
+		}
+	}
+
+	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::BasicType::SignedInt, one->qualifiers | type2->qualifiers };
+		} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
+			const ast::EnumDecl * enumBase = enumInst->base;
+			if ( enumBase->base ) {
+				if ( tryResolveWithTypedEnum( one ))
+					add_qualifiers( result, one->qualifiers );
+			} else {
 				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::BasicType::SignedInt, one->qualifiers | type2->qualifiers };
-			} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
-				const ast::EnumDecl * enumBase = enumInst->base;
-				if ( enumBase->base ) {
-					if ( tryResolveWithTypedEnum( one ))
-						add_qualifiers( result, one->qualifiers );
-				} else {
-					if ( widen.second || one->qualifiers <= type2->qualifiers ) {
-						result = type2;
-						add_qualifiers( result, one->qualifiers );
-					}
-				}
-			}
-		}
-
-	};
-
-	// size_t CommonType::traceId = Stats::Heap::new_stacktrace_id("CommonType");
-	namespace {
-		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;
+			}
+		}
+	}
+};
+
+// size_t CommonType::traceId = Stats::Heap::new_stacktrace_id("CommonType");
+
+namespace {
+	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 << "unify success: " << widenFirst << " " << widenSecond << std::endl;
+					std::cerr << "widen okay" << 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;
-				}
-			}
-
+				add_qualifiers( common, q1 | q2 );
+				return common;
+			}
+		}
+
+		PRINT(
+			std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;
+		)
+		return { nullptr };
+	}
+}
+
+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 << "exact unify failed: " << t1 << " " << t2 << std::endl;
+				std::cerr << "formal is reference; result should be reference" << std::endl;
 			)
-			return { nullptr };
-		}
-	}
-
-	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
-		ast::Pass<CommonType> visitor{ type2, widen, env, open, need, have };
-		type1->accept( visitor );
-		// ast::ptr< ast::Type > result = visitor.core.result;
-
-		return visitor.core.result;
-	}
+			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
+	ast::Pass<CommonType> visitor{ type2, widen, env, open, need, have };
+	type1->accept( visitor );
+	// ast::ptr< ast::Type > result = visitor.core.result;
+
+	return visitor.core.result;
+}
 
 } // namespace ResolvExpr
Index: src/ResolvExpr/Cost.h
===================================================================
--- src/ResolvExpr/Cost.h	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/Cost.h	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -21,153 +21,155 @@
 
 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;
+// 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
 		};
-		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; }
 
-		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 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 );
 
-		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
+	Cost operator+=( const Cost rhs ) {
+		if ( all == infinity ) return *this;
+		if ( rhs.all == infinity ) {
+			all = infinity;
 			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;
+		all += rhs.all - correctw;					// correct for negative spec cost
+		return *this;
 	}
 
-	inline bool operator!=( const Cost lhs, const Cost rhs ) {
-		return !( lhs.all == rhs.all );
+	Cost incUnsafe( int inc = 1 ) {
+		if ( all != infinity ) { assert( v.unsafeCost + inc <= UCHAR_MAX ); v.unsafeCost += inc; }
+		return *this;
 	}
 
-	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;
+	Cost incPoly( int inc = 1 ) {
+		if ( all != infinity ) { assert( v.polyCost + inc <= UCHAR_MAX ); v.polyCost += inc; }
+		return *this;
 	}
 
-	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
+	Cost incSafe( int inc = 1 ) {
+		if ( all != infinity ) { assert( v.safeCost + inc <= UCHAR_MAX ); v.safeCost += inc; }
+		return *this;
 	}
 
-	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() << " )";
+	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
 
Index: src/ResolvExpr/CurrentObject.cc
===================================================================
--- src/ResolvExpr/CurrentObject.cc	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/CurrentObject.cc	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -41,567 +41,573 @@
 
 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;
-	};
-
-	/// 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, toString( "Array designator must be a constant expression: ", expr ) );
-			}
-			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 } );
+
+/// 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, toString( "Array designator must be a constant expression: ", expr ) );
+		}
+		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;
 		}
-	};
-
-	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 };
+		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 };
 		}
-	}
-
-	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();
-
-			for ( const Type * t : curTypes ) {
-				assert( dit != desigAlts.end() );
-				DesignatorChain & d = *dit;
-				if ( auto nexpr = dynamic_cast< const NameExpr *>( expr ) ) {
-					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 );
-							}
-						}
-					} else if ( auto at = dynamic_cast< const ArrayType * >( t ) ) {
-						auto nexpr = dynamic_cast< const NameExpr *>( expr );
-						for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
-							if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) {
-								DesignatorChain d2 = d;
-								d2.emplace_back( new VariableExpr{ expr->location, field } );
-								newDesigAlts.emplace_back( std::move( d2 ) );
-								newTypes.emplace_back( at->base );
-							}
+	} 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();
+
+		for ( const Type * t : curTypes ) {
+			assert( dit != desigAlts.end() );
+			DesignatorChain & d = *dit;
+			if ( auto nexpr = dynamic_cast< const NameExpr *>( expr ) ) {
+				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;
-				} 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 );
+				} else if ( auto at = dynamic_cast< const ArrayType * >( t ) ) {
+					auto nexpr = dynamic_cast< const NameExpr *>( expr );
+					for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
+						if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) {
+							DesignatorChain d2 = d;
+							d2.emplace_back( new VariableExpr{ expr->location, field } );
+							newDesigAlts.emplace_back( std::move( d2 ) );
+							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;
+
+				++dit;
+			} 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()->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();
-	}
-}
+		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: //
Index: src/ResolvExpr/CurrentObject.h
===================================================================
--- src/ResolvExpr/CurrentObject.h	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/CurrentObject.h	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -17,7 +17,5 @@
 
 #include <deque>
-#include <list>   // for list
 #include <memory> // for unique_ptr
-#include <stack>  // for stack
 #include <vector>
 
@@ -25,70 +23,39 @@
 #include "Common/CodeLocation.h"
 
+namespace ast {
+
+// AST class types:
 class Designation;
 class Type;
 struct InitAlternative;
 
-namespace ResolvExpr {
-	class MemberIterator;
+/// Iterates members of a type by initializer
+class MemberIterator;
 
-	// TODO: memory management of MemberIterators
-	class CurrentObject {
-	public:
-		CurrentObject();
-		CurrentObject( Type * type );
+/// Builds initializer lists in resolution
+class CurrentObject final {
+	std::vector<std::shared_ptr<MemberIterator>> objStack;
 
-		/// resolves unresolved designation
-		Designation * findNext( Designation * designation );
-		/// sets current position using resolved designation
-		void setNext( Designation * designation );
-		/// steps to next sub-object of current-object
-		void increment();
-		/// sets new current-object for the duration of this brace-enclosed initializer-list
-		void enterListInit();
-		/// restores previous current-object
-		void exitListInit();
-		/// produces a list of alternatives (Type *, Designation *) for the current sub-object's initializer
-		std::list< InitAlternative > getOptions();
-		/// produces the type of the current object but no subobjects
-		Type * getCurrentType();
+public:
+	CurrentObject() = default;
+	CurrentObject( const CodeLocation & loc, const Type * type );
 
-	private:
-		std::stack< MemberIterator * > objStack;
-	};
-} // namespace ResolvExpr
+	/// 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 {
-	// AST class types
-	class Designation;
-	struct InitAlternative;
-	class Type;
-
-	/// 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 ast::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
 
Index: src/ResolvExpr/FindOpenVars.cc
===================================================================
--- src/ResolvExpr/FindOpenVars.cc	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/FindOpenVars.cc	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -24,64 +24,67 @@
 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;
+namespace {
 
-			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 ) {}
+struct FindOpenVars final : public ast::WithGuards {
+	ast::OpenVarSet & open;
+	ast::OpenVarSet & closed;
+	ast::AssertionSet & need;
+	ast::AssertionSet & have;
+	ast::TypeEnvironment & env;
+	bool nextIsOpen;
 
-			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.
+	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 ) {}
 
-					// insert open variables unbound to environment.
-					env.add(type->forall);
+	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.
 
-					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;
-					}
-				}
+			// insert open variables unbound to environment.
+			env.add(type->forall);
 
-				// flip open variables for contained function types
-				nextIsOpen = ! nextIsOpen;
-				GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } );
+			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;
 	}
+};
 
-	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 );
+} // namespace
 
-		if (!closed.empty()) {
-			std::cerr << "closed: ";
-			for (auto& i : closed) {
-				std::cerr << i.first.base->location << ":" << i.first.base->name << ' ';
-			}
-			std::cerr << std::endl;
+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
 
Index: src/ResolvExpr/FindOpenVars.h
===================================================================
--- src/ResolvExpr/FindOpenVars.h	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/FindOpenVars.h	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -23,10 +23,12 @@
 
 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 );
+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
 
Index: src/ResolvExpr/PolyCost.cc
===================================================================
--- src/ResolvExpr/PolyCost.cc	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/PolyCost.cc	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -20,4 +20,6 @@
 
 namespace ResolvExpr {
+
+namespace {
 
 class PolyCost {
@@ -45,4 +47,6 @@
 };
 
+} // namespace
+
 int polyCost(
 	const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
Index: src/ResolvExpr/PtrsAssignable.cc
===================================================================
--- src/ResolvExpr/PtrsAssignable.cc	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/PtrsAssignable.cc	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -21,4 +21,6 @@
 
 namespace ResolvExpr {
+
+namespace {
 
 struct PtrsAssignable : public ast::WithShortCircuiting {
@@ -51,4 +53,6 @@
 	}
 };
+
+} // namespace
 
 int ptrsAssignable( const ast::Type * src, const ast::Type * dst,
Index: src/ResolvExpr/RenameVars.h
===================================================================
--- src/ResolvExpr/RenameVars.h	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/RenameVars.h	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -21,12 +21,14 @@
 
 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();
+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
 
Index: src/ResolvExpr/ResolvMode.h
===================================================================
--- src/ResolvExpr/ResolvMode.h	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/ResolvMode.h	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -17,30 +17,32 @@
 
 namespace ResolvExpr {
-	/// Flag set for resolution
-	struct ResolvMode {
-		const bool adjust;			 ///< Adjust array and function types to pointer types? [false]
-		const bool prune;            ///< Prune alternatives to min-cost per return type? [true]
-		const bool failFast;         ///< Fail on no resulting alternatives? [true]
 
-		constexpr ResolvMode(bool a, bool p, bool ff) 
-		: adjust(a), prune(p), failFast(ff) {}
+/// Flag set for resolution
+struct ResolvMode {
+	const bool adjust;			 ///< Adjust array and function types to pointer types? [false]
+	const bool prune;            ///< Prune alternatives to min-cost per return type? [true]
+	const bool failFast;         ///< Fail on no resulting alternatives? [true]
 
-		/// Default settings
-		constexpr ResolvMode() : adjust(false), prune(true), failFast(true) {}
-		
-		/// With adjust flag set; turns array and function types into equivalent pointers
-		static constexpr ResolvMode withAdjustment() { return { true, true, true }; }
+	constexpr ResolvMode(bool a, bool p, bool ff)
+	: adjust(a), prune(p), failFast(ff) {}
 
-		/// With adjust flag set but prune unset; pruning ensures there is at least one alternative 
-		/// per result type
-		static constexpr ResolvMode withoutPrune() { return { true, false, true }; }
+	/// Default settings
+	constexpr ResolvMode() : adjust(false), prune(true), failFast(true) {}
 
-		/// With adjust and prune flags set but failFast unset; failFast ensures there is at least 
-		/// one resulting alternative
-		static constexpr ResolvMode withoutFailFast() { return { true, true, false }; }
+	/// With adjust flag set; turns array and function types into equivalent pointers
+	static constexpr ResolvMode withAdjustment() { return { true, true, true }; }
 
-		/// The same mode, but with satisfyAssns turned on; for top-level calls
-		ResolvMode atTopLevel() const { return { adjust, true, failFast }; }
-	};
+	/// With adjust flag set but prune unset; pruning ensures there is at least one alternative
+	/// per result type
+	static constexpr ResolvMode withoutPrune() { return { true, false, true }; }
+
+	/// With adjust and prune flags set but failFast unset; failFast ensures there is at least
+	/// one resulting alternative
+	static constexpr ResolvMode withoutFailFast() { return { true, true, false }; }
+
+	/// The same mode, but with satisfyAssns turned on; for top-level calls
+	ResolvMode atTopLevel() const { return { adjust, true, failFast }; }
+};
+
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/ResolveTypeof.cc
===================================================================
--- src/ResolvExpr/ResolveTypeof.cc	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/ResolveTypeof.cc	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -33,4 +33,5 @@
 
 namespace {
+
 struct ResolveTypeof : public ast::WithShortCircuiting {
     const ResolveContext & context;
@@ -75,4 +76,5 @@
     }
 };
+
 } // anonymous namespace
 
Index: src/ResolvExpr/ResolveTypeof.h
===================================================================
--- src/ResolvExpr/ResolveTypeof.h	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/ResolveTypeof.h	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -22,10 +22,12 @@
 
 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 & );
+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
 
Index: src/ResolvExpr/Resolver.h
===================================================================
--- src/ResolvExpr/Resolver.h	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/Resolver.h	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -34,30 +34,31 @@
 namespace ResolvExpr {
 
-	/// Helper Type: Passes around information between various sub-calls.
-	struct ResolveContext {
-		const ast::SymbolTable & symtab;
-		const ast::TranslationGlobal & global;
-	};
+/// 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 );
+/// 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
 
Index: src/ResolvExpr/SatisfyAssertions.cpp
===================================================================
--- src/ResolvExpr/SatisfyAssertions.cpp	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/SatisfyAssertions.cpp	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -473,6 +473,5 @@
 						errors.emplace_back( ss.str() );
 						goto nextSat;
-					}
-					else if ( result == AssertionResult::Skip ) {
+					} else if ( result == AssertionResult::Skip ) {
 						next.emplace_back(assn);
 						// goto nextSat;
Index: src/ResolvExpr/SpecCost.cc
===================================================================
--- src/ResolvExpr/SpecCost.cc	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/SpecCost.cc	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -33,83 +33,83 @@
 }
 
-	/// The specialization counter inner class.
-	class SpecCounter : public ast::WithShortCircuiting, public ast::WithVisitorRef<SpecCounter> {
-		int count = -1;  ///< specialization count (-1 for none)
+/// 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;
+	// 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;
 		}
+	}
 
-		template<typename T> using MapperT =
-			typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type;
+	// 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 );
+	}
 
-		// 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;
+public:
+	int result() const { return 0 <= count ? count : 0; }
 
-				if ( ast::Type const * type = mapper( node ) ) {
-					ast::Type const * newType = type->accept( *visitor );
-					assert( newType == nullptr || newType == type );
-				}
+	// 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; }
 
-				if ( count != -1 && count < minimum ) minimum = count;
-			}
-		}
+	void postvisit( const ast::StructInstType * ) { if ( 0 <= count ) ++count; }
+	void postvisit( const ast::UnionInstType * ) { if ( 0 <= count ) ++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 );
-		}
+	// 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;
+	}
 
-	public:
-		int result() const { return 0 <= count ? count : 0; }
+	// Look for polymorphic parameters.
+	void previsit( const ast::StructInstType * sty ) {
+		count = minimumPresent( sty->params, expr_result );
+	}
 
-		// Mark specialization of base type.
-		void postvisit( const ast::PointerType * ) { if ( count >= 0 ) ++count; }
-		void postvisit( const ast::ArrayType * ) { if ( count >= 0 ) ++count; }
-		void postvisit( const ast::ReferenceType * ) { if ( count >= 0 ) ++count; }
+	// Look for polymorphic parameters.
+	void previsit( const ast::UnionInstType * uty ) {
+		count = minimumPresent( uty->params, expr_result );
+	}
 
-		void postvisit( const ast::StructInstType * ) { if ( count >= 0 ) ++count; }
-		void postvisit( const ast::UnionInstType * ) { if ( count >= 0 ) ++count; }
+	// 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 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;
-		}
-	};
+	// 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
Index: src/ResolvExpr/SpecCost.hpp
===================================================================
--- src/ResolvExpr/SpecCost.hpp	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/SpecCost.hpp	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -16,5 +16,4 @@
 #pragma once
 
-class Type;
 namespace ast {
     class Type;
@@ -23,5 +22,4 @@
 namespace ResolvExpr {
 
-int specCost( Type * type );
 int specCost( const ast::Type * type );
 
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/Unify.cc	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -537,7 +537,7 @@
 			// assert( open.find( *typeInst ) == open.end() );
 			auto otherInst = dynamic_cast< const ast::TypeInstType * >( type2 );
-			if (otherInst && typeInst->name == otherInst->name) 
+			if ( otherInst && typeInst->name == otherInst->name ) {
 				this->result = otherInst;
-			// return otherInst;
+			}
 		}
 
@@ -628,8 +628,4 @@
 			result = dynamic_cast< const ast::OneType * >( type2 );
 		}
-
-	  private:
-		template< typename RefType > void handleRefType( RefType *inst, Type *other );
-		template< typename RefType > void handleGenericRefType( RefType *inst, Type *other );
 	};
 
Index: src/ResolvExpr/Unify.h
===================================================================
--- src/ResolvExpr/Unify.h	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/Unify.h	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -15,6 +15,4 @@
 
 #pragma once
-
-#include <list>                   // for list
 
 #include "AST/Node.hpp"             // for ptr
@@ -47,9 +45,9 @@
 	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, 
+	const ast::OpenVarSet & open, WidenMode widen,
 	ast::ptr<ast::Type> & common );
 
 bool typesCompatible(
-	const ast::Type *, const ast::Type *, 
+	const ast::Type *, const ast::Type *,
 	const ast::TypeEnvironment & env = {} );
 
Index: src/ResolvExpr/WidenMode.h
===================================================================
--- src/ResolvExpr/WidenMode.h	(revision 41606df1c8a25852791147aa8665029c6146c8fc)
+++ src/ResolvExpr/WidenMode.h	(revision 2908f08a0e243fe6bf1b61d204824745ab192f95)
@@ -17,29 +17,31 @@
 
 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;
-		}
+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 ) {
+		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; }
+	WidenMode operator&( const WidenMode &other ) {
+		WidenMode newWM( *this ); newWM &= other; return newWM;
+	}
 
-		bool first : 1, second : 1;
-	};
+	operator bool() { return first && second; }
 
-	static inline WidenMode noWiden() { return { false, false }; }
+	bool first : 1, second : 1;
+};
+
+static inline WidenMode noWiden() { return { false, false }; }
+
 } // namespace ResolvExpr
 
