Index: src/Makefile.am
===================================================================
--- src/Makefile.am	(revision 04bdc267074e647270359bb1cb01aea37691be2f)
+++ src/Makefile.am	(revision 1dd1bd2218b33ed1d1d472ad9341291c381d9f22)
@@ -128,4 +128,5 @@
   ResolvExpr/Resolver.cc \
   ResolvExpr/ResolveTypeof.cc \
+  ResolvExpr/SpecCost.cc \
   ResolvExpr/TypeEnvironment.cc \
   ResolvExpr/Unify.cc \
Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(revision 04bdc267074e647270359bb1cb01aea37691be2f)
+++ src/Makefile.in	(revision 1dd1bd2218b33ed1d1d472ad9341291c381d9f22)
@@ -205,4 +205,5 @@
 	ResolvExpr/RenameVars.$(OBJEXT) ResolvExpr/Resolver.$(OBJEXT) \
 	ResolvExpr/ResolveTypeof.$(OBJEXT) \
+	ResolvExpr/SpecCost.$(OBJEXT) \
 	ResolvExpr/TypeEnvironment.$(OBJEXT) \
 	ResolvExpr/Unify.$(OBJEXT) SymTab/Autogen.$(OBJEXT) \
@@ -259,5 +260,6 @@
 	ResolvExpr/TypeEnvironment.$(OBJEXT) \
 	ResolvExpr/CurrentObject.$(OBJEXT) \
-	ResolvExpr/ExplodedActual.$(OBJEXT) SymTab/Indexer.$(OBJEXT) \
+	ResolvExpr/ExplodedActual.$(OBJEXT) \
+	ResolvExpr/SpecCost.$(OBJEXT) SymTab/Indexer.$(OBJEXT) \
 	SymTab/Mangler.$(OBJEXT) SymTab/ManglerCommon.$(OBJEXT) \
 	SymTab/Validate.$(OBJEXT) SymTab/FixFunction.$(OBJEXT) \
@@ -547,7 +549,8 @@
 	ResolvExpr/Occurs.cc ResolvExpr/TypeEnvironment.cc \
 	ResolvExpr/CurrentObject.cc ResolvExpr/ExplodedActual.cc \
-	SymTab/Indexer.cc SymTab/Mangler.cc SymTab/ManglerCommon.cc \
-	SymTab/Validate.cc SymTab/FixFunction.cc SymTab/Autogen.cc \
-	SynTree/Type.cc SynTree/VoidType.cc SynTree/BasicType.cc \
+	ResolvExpr/SpecCost.cc SymTab/Indexer.cc SymTab/Mangler.cc \
+	SymTab/ManglerCommon.cc SymTab/Validate.cc \
+	SymTab/FixFunction.cc SymTab/Autogen.cc SynTree/Type.cc \
+	SynTree/VoidType.cc SynTree/BasicType.cc \
 	SynTree/PointerType.cc SynTree/ArrayType.cc \
 	SynTree/ReferenceType.cc SynTree/FunctionType.cc \
@@ -656,4 +659,5 @@
   ResolvExpr/Resolver.cc \
   ResolvExpr/ResolveTypeof.cc \
+  ResolvExpr/SpecCost.cc \
   ResolvExpr/TypeEnvironment.cc \
   ResolvExpr/Unify.cc \
@@ -908,4 +912,6 @@
 ResolvExpr/ResolveTypeof.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
 	ResolvExpr/$(DEPDIR)/$(am__dirstamp)
+ResolvExpr/SpecCost.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
+	ResolvExpr/$(DEPDIR)/$(am__dirstamp)
 ResolvExpr/TypeEnvironment.$(OBJEXT): ResolvExpr/$(am__dirstamp) \
 	ResolvExpr/$(DEPDIR)/$(am__dirstamp)
@@ -1160,4 +1166,5 @@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/ResolveTypeof.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/Resolver.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/SpecCost.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/TypeEnvironment.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@ResolvExpr/$(DEPDIR)/Unify.Po@am__quote@
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 04bdc267074e647270359bb1cb01aea37691be2f)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision 1dd1bd2218b33ed1d1d472ad9341291c381d9f22)
@@ -410,26 +410,26 @@
 	Cost computeApplicationConversionCost( Alternative &alt, const SymTab::Indexer &indexer ) {
 		ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( alt.expr );
-		PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
-		FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() );
+		PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->function->result );
+		FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->base );
 
 		Cost convCost = Cost::zero;
-		std::list< DeclarationWithType* >& formals = function->get_parameters();
+		std::list< DeclarationWithType* >& formals = function->parameters;
 		std::list< DeclarationWithType* >::iterator formal = formals.begin();
-		std::list< Expression* >& actuals = appExpr->get_args();
-
-		for ( std::list< Expression* >::iterator actualExpr = actuals.begin(); actualExpr != actuals.end(); ++actualExpr ) {
-			Type * actualType = (*actualExpr)->get_result();
+		std::list< Expression* >& actuals = appExpr->args;
+
+		for ( Expression*& actualExpr : actuals ) {
+			Type * actualType = actualExpr->result;
 			PRINT(
 				std::cerr << "actual expression:" << std::endl;
-				(*actualExpr)->print( std::cerr, 8 );
+				actualExpr->print( std::cerr, 8 );
 				std::cerr << "--- results are" << std::endl;
 				actualType->print( std::cerr, 8 );
 			)
 			if ( formal == formals.end() ) {
-				if ( function->get_isVarArgs() ) {
+				if ( function->isVarArgs ) {
 					convCost.incUnsafe();
 					PRINT( std::cerr << "end of formals with varargs function: inc unsafe: " << convCost << std::endl; ; )
 					// convert reference-typed expressions to value-typed expressions
-					referenceToRvalueConversion( *actualExpr, convCost );
+					referenceToRvalueConversion( actualExpr, convCost );
 					continue;
 				} else {
@@ -437,13 +437,15 @@
 				}
 			}
-			if ( DefaultArgExpr * def = dynamic_cast< DefaultArgExpr * >( *actualExpr ) ) {
+			if ( DefaultArgExpr * def = dynamic_cast< DefaultArgExpr * >( actualExpr ) ) {
 				// default arguments should be free - don't include conversion cost.
 				// Unwrap them here because they are not relevant to the rest of the system.
-				*actualExpr = def->expr;
+				actualExpr = def->expr;
 				++formal;
 				continue;
 			}
+			// mark conversion cost to formal and also specialization cost of formal type
 			Type * formalType = (*formal)->get_type();
-			convCost += computeExpressionConversionCost( *actualExpr, formalType, indexer, alt.env );
+			convCost += computeExpressionConversionCost( actualExpr, formalType, indexer, alt.env );
+			convCost.decSpec( specCost( formalType ) );
 			++formal; // can't be in for-loop update because of the continue
 		}
@@ -452,4 +454,16 @@
 		}
 
+		// mark specialization cost of return types
+		for ( DeclarationWithType* returnVal : function->returnVals ) {
+			convCost.decSpec( specCost( returnVal->get_type() ) );
+		}
+
+		// mark type variable and specialization cost of forall clause
+		convCost.incVar( function->forall.size() );
+		for ( TypeDecl* td : function->forall ) {
+			convCost.decSpec( td->assertions.size() );
+		}
+
+		// xxx -- replace with new costs in resolver
 		for ( InferredParams::const_iterator assert = appExpr->get_inferParams().begin(); assert != appExpr->get_inferParams().end(); ++assert ) {
 			convCost += computeConversionCost( assert->second.actualType, assert->second.formalType, indexer, alt.env );
Index: src/ResolvExpr/ConversionCost.cc
===================================================================
--- src/ResolvExpr/ConversionCost.cc	(revision 04bdc267074e647270359bb1cb01aea37691be2f)
+++ src/ResolvExpr/ConversionCost.cc	(revision 1dd1bd2218b33ed1d1d472ad9341291c381d9f22)
@@ -28,10 +28,12 @@
 
 namespace ResolvExpr {
-	const Cost Cost::zero =      Cost(  0,  0,  0,  0 );
-	const Cost Cost::infinity =  Cost( -1, -1, -1, -1 );
-	const Cost Cost::unsafe =    Cost(  1,  0,  0,  0 );
-	const Cost Cost::poly =      Cost(  0,  1,  0,  0 );
-	const Cost Cost::safe =      Cost(  0,  0,  1,  0 );
-	const Cost Cost::reference = Cost(  0,  0,  0,  1 );
+	const Cost Cost::zero =      Cost{  0,  0,  0,  0,  0,  0 };
+	const Cost Cost::infinity =  Cost{ -1, -1, -1,  1, -1, -1 };
+	const Cost Cost::unsafe =    Cost{  1,  0,  0,  0,  0,  0 };
+	const Cost Cost::poly =      Cost{  0,  1,  0,  0,  0,  0 };
+	const Cost Cost::var =       Cost{  0,  0,  1,  0,  0,  0 };
+	const Cost Cost::spec =      Cost{  0,  0,  0, -1,  0,  0 };
+	const Cost Cost::safe =      Cost{  0,  0,  0,  0,  1,  0 };
+	const Cost Cost::reference = Cost{  0,  0,  0,  0,  0,  1 };
 
 #if 0
Index: src/ResolvExpr/Cost.h
===================================================================
--- src/ResolvExpr/Cost.h	(revision 04bdc267074e647270359bb1cb01aea37691be2f)
+++ src/ResolvExpr/Cost.h	(revision 1dd1bd2218b33ed1d1d472ad9341291c381d9f22)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 09:39:50 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:35:55 2017
-// Update Count     : 5
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Tue Oct 02 14:40:00 2018
+// Update Count     : 6
 //
 
@@ -21,9 +21,12 @@
 	class Cost {
 	  private:
-		Cost( int unsafeCost, int polyCost, int safeCost, int referenceCost );
+		Cost( int unsafeCost, int polyCost, int varCost, int specCost, int safeCost, 
+		      int referenceCost );
 
 	  public:
 		Cost & incUnsafe( int inc = 1 );
 		Cost & incPoly( int inc = 1 );
+		Cost & incVar( int inc = 1 );
+		Cost & decSpec( int inc = 1 );
 		Cost & incSafe( int inc = 1 );
 		Cost & incReference( int inc = 1 );
@@ -31,4 +34,6 @@
 		int get_unsafeCost() const { return unsafeCost; }
 		int get_polyCost() const { return polyCost; }
+		int get_varCost() const { return varCost; }
+		int get_specCost() const { return specCost; }
 		int get_safeCost() const { return safeCost; }
 		int get_referenceCost() const { return referenceCost; }
@@ -47,4 +52,6 @@
 		static const Cost unsafe;
 		static const Cost poly;
+		static const Cost var;
+		static const Cost spec;
 		static const Cost safe;
 		static const Cost reference;
@@ -52,11 +59,16 @@
 		int compare( const Cost &other ) const;
 
-		int unsafeCost;
-		int polyCost;
-		int safeCost;
-		int referenceCost;
+		int unsafeCost;     ///< Unsafe (narrowing) conversions
+		int polyCost;       ///< Count of parameters and return values bound to some poly type
+		int varCost;        ///< Count of polymorphic type variables
+		int specCost;       ///< Polymorphic type specializations (type assertions), negative cost
+		int safeCost;       ///< Safe (widening) conversions
+		int referenceCost;  ///< reference conversions
 	};
 
-	inline Cost::Cost( int unsafeCost, int polyCost, int safeCost, int referenceCost ) : unsafeCost( unsafeCost ), polyCost( polyCost ), safeCost( safeCost ), referenceCost( referenceCost ) {}
+	inline Cost::Cost( int unsafeCost, int polyCost, int varCost, int specCost, int safeCost, 
+			int referenceCost ) 
+		: unsafeCost( unsafeCost ), polyCost( polyCost ), varCost( varCost ), specCost( specCost ), 
+		  safeCost( safeCost ), referenceCost( referenceCost ) {}
 
 	inline Cost & Cost::incUnsafe( int inc ) {
@@ -69,4 +81,16 @@
 		if ( *this == infinity ) return *this;
 		polyCost += inc;
+		return *this;
+	}
+
+	inline Cost & Cost::incVar( int inc ) {
+		if ( *this == infinity ) return *this;
+		varCost += inc;
+		return *this;
+	}
+
+	inline Cost& Cost::decSpec( int dec ) {
+		if ( *this == infinity ) return *this;
+		specCost -= dec;
 		return *this;
 	}
@@ -86,10 +110,16 @@
 	inline Cost Cost::operator+( const Cost &other ) const {
 		if ( *this == infinity || other == infinity ) return infinity;
-		return Cost( unsafeCost + other.unsafeCost, polyCost + other.polyCost, safeCost + other.safeCost, referenceCost + other.referenceCost );
+		return Cost{ 
+			unsafeCost + other.unsafeCost, polyCost + other.polyCost, 
+			varCost + other.varCost, specCost + other.specCost, 
+			safeCost + other.safeCost, referenceCost + other.referenceCost };
 	}
 
 	inline Cost Cost::operator-( const Cost &other ) const {
 		if ( *this == infinity || other == infinity ) return infinity;
-		return Cost( unsafeCost - other.unsafeCost, polyCost - other.polyCost, safeCost - other.safeCost, referenceCost - other.referenceCost );
+		return Cost{ 
+			unsafeCost - other.unsafeCost, polyCost - other.polyCost, 
+			varCost - other.varCost, specCost - other.specCost, 
+			safeCost - other.safeCost, referenceCost - other.referenceCost };
 	}
 
@@ -102,4 +132,6 @@
 		unsafeCost += other.unsafeCost;
 		polyCost += other.polyCost;
+		varCost += other.varCost;
+		specCost += other.specCost;
 		safeCost += other.safeCost;
 		referenceCost += other.referenceCost;
@@ -119,4 +151,12 @@
 		} else if ( polyCost < other.polyCost ) {
 			return true;
+		} else if ( varCost > other.varCost ) {
+			return false;
+		} else if ( varCost < other.varCost ) {
+			return true;
+		} else if ( specCost > other.specCost ) {
+			return false;
+		} else if ( specCost > other.specCost ) {
+			return true;
 		} else if ( safeCost > other.safeCost ) {
 			return false;
@@ -135,4 +175,6 @@
 		return unsafeCost == other.unsafeCost
 			&& polyCost == other.polyCost
+			&& varCost == other.varCost
+			&& specCost == other.specCost
 			&& safeCost == other.safeCost
 			&& referenceCost == other.referenceCost;
@@ -144,6 +186,7 @@
 
 	inline std::ostream &operator<<( std::ostream &os, const Cost &cost ) {
-		os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", " << cost.safeCost << ", " << cost.referenceCost << " )";
-		return os;
+		return os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", " 
+		          << cost.varCost << ", " << cost.specCost << ", "
+		          << cost.safeCost << ", " << cost.referenceCost << " )";
 	}
 } // namespace ResolvExpr
Index: src/ResolvExpr/SpecCost.cc
===================================================================
--- src/ResolvExpr/SpecCost.cc	(revision 1dd1bd2218b33ed1d1d472ad9341291c381d9f22)
+++ src/ResolvExpr/SpecCost.cc	(revision 1dd1bd2218b33ed1d1d472ad9341291c381d9f22)
@@ -0,0 +1,119 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// SpecCost.cc --
+//
+// Author           : Aaron B. Moss
+// Created On       : Tue Oct 02 15:50:00 2018
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Tue Oct 02 15:50:00 2018
+// Update Count     : 1
+//
+
+#include <limits>
+#include <list>
+
+#include "Common/PassVisitor.h"
+#include "SynTree/Declaration.h"
+#include "SynTree/Expression.h"
+#include "SynTree/Type.h"
+
+namespace ResolvExpr {
+
+	/// Counts specializations in a type
+	class CountSpecs : public WithShortCircuiting, public WithVisitorRef<CountSpecs> {
+		int count = -1;  ///< specialization count (-1 for none)
+
+	public:
+		int get_count() const { return count >= 0 ? count : 0; }
+
+		// mark specialization of base type
+		void postvisit(PointerType*) { if ( count >= 0 ) ++count; }
+
+		// mark specialization of base type
+		void postvisit(ArrayType*) { if ( count >= 0 ) ++count; }
+
+		// mark specialization of base type
+		void postvisit(ReferenceType*) { if ( count >= 0 ) ++count; }
+
+	private:
+		// takes minimum non-negative count over parameter/return list
+		void takeminover( int& mincount, std::list<DeclarationWithType*>& dwts ) {
+			for ( DeclarationWithType* dwt : dwts ) {
+				count = -1;
+				maybeAccept( dwt->get_type(), *visitor );
+				if ( count != -1 && count < mincount ) mincount = count;
+			}
+		}
+
+	public:
+		// take minimal specialization value over ->returnVals and ->parameters
+		void previsit(FunctionType* fty) {
+			int mincount = std::numeric_limits<int>::max();
+			takeminover( mincount, fty->parameters );
+			takeminover( mincount, fty->returnVals );
+			// add another level to mincount if set
+			count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
+			// already visited children
+			visit_children = false;
+		}
+	
+	private:
+		// returns minimum non-negative count + 1 over type parameters (-1 if none such)
+		int minover( std::list<Expression*>& parms ) {
+			int mincount = std::numeric_limits<int>::max();
+			for ( Expression* parm : parms ) {
+				count = -1;
+				maybeAccept( parm->result, *visitor );
+				if ( count != -1 && count < mincount ) mincount = count;
+			}
+			return mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
+		}
+
+	public:
+		// look for polymorphic parameters
+		void previsit(StructInstType* sty) {
+			count = minover( sty->parameters );
+			visit_children = false;
+		}
+		
+		// look for polymorphic parameters
+		void previsit(UnionInstType* uty) {
+			count = minover( uty->parameters );
+			visit_children = false;
+		}
+
+		// note polymorphic type (which may be specialized)
+		// xxx - maybe account for open/closed type variables
+		void postvisit(TypeInstType*) { count = 0; }
+
+		// take minimal specialization over elements
+		// xxx - maybe don't increment, tuple flattening doesn't necessarily specialize
+		void previsit(TupleType* tty) {
+			int mincount = std::numeric_limits<int>::max();
+			for ( Type* ty : tty->types ) {
+				count = -1;
+				maybeAccept( ty, *visitor );
+				if ( count != -1 && count < mincount ) mincount = count;
+			}
+			count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
+			visit_children = false;
+		}
+	};
+
+	/// Returns the (negated) specialization cost for a given type
+	int specCost( Type* ty ) {
+		PassVisitor<CountSpecs> counter;
+		maybeAccept( ty, *counter.pass.visitor );
+		return counter.pass.get_count();
+	}
+} // namespace ResolvExpr
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ResolvExpr/module.mk
===================================================================
--- src/ResolvExpr/module.mk	(revision 04bdc267074e647270359bb1cb01aea37691be2f)
+++ src/ResolvExpr/module.mk	(revision 1dd1bd2218b33ed1d1d472ad9341291c381d9f22)
@@ -33,3 +33,4 @@
        ResolvExpr/TypeEnvironment.cc \
        ResolvExpr/CurrentObject.cc \
-       ResolvExpr/ExplodedActual.cc
+       ResolvExpr/ExplodedActual.cc \
+       ResolvExpr/SpecCost.cc
Index: src/ResolvExpr/typeops.h
===================================================================
--- src/ResolvExpr/typeops.h	(revision 04bdc267074e647270359bb1cb01aea37691be2f)
+++ src/ResolvExpr/typeops.h	(revision 1dd1bd2218b33ed1d1d472ad9341291c381d9f22)
@@ -102,4 +102,7 @@
 	int polyCost( Type *type, const TypeEnvironment &env, const SymTab::Indexer &indexer );
 
+	// in SpecCost.cc
+	int specCost( Type *type );
+
 	// in Occurs.cc
 	bool occurs( Type *type, std::string varName, const TypeEnvironment &env );
