Index: src/ResolvExpr/PolyCost.cc
===================================================================
--- src/ResolvExpr/PolyCost.cc	(revision c8293206313c3350568d818d48c8da940d369684)
+++ src/ResolvExpr/PolyCost.cc	(revision 3fc0f2a752123e109a9539276cbb0c20c61cd0e4)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 09:50:12 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sun May 17 09:52:02 2015
-// Update Count     : 3
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jun 19 10:45:00 2019
+// Update Count     : 4
 //
 
@@ -57,12 +57,35 @@
 	}
 
-	int polyCost( 
-		const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 
-	) {
-		#warning unimplemented
-		(void)type; (void)symtab; (void)env;
-		assert(false);
-		return 0;
+// TODO: When the old PolyCost is torn out get rid of the _new suffix.
+struct PolyCost_new {
+	int result;
+	const ast::SymbolTable &symtab;
+	const ast::TypeEnvironment &env_;
+
+	PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) :
+		result( 0 ), symtab( symtab ), env_( env ) {}
+
+	void previsit( const ast::TypeInstType * type ) {
+		if ( const ast::EqvClass * eqv = env_.lookup( type->name ) ) /* && */ if ( eqv->bound ) {
+			if ( const ast::TypeInstType * otherType = eqv->bound.as< ast::TypeInstType >() ) {
+				if ( symtab.lookupType( otherType->name ) ) {
+					// Bound to opaque type.
+					result += 1;
+				}
+			} else {
+				// Bound to concrete type.
+				result += 1;
+			}
+		}
 	}
+};
+
+int polyCost(
+	const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
+) {
+	ast::Pass<PolyCost_new> costing( symtab, env );
+	type->accept( costing );
+	return costing.pass.result;
+}
 
 } // namespace ResolvExpr
Index: src/ResolvExpr/SpecCost.cc
===================================================================
--- src/ResolvExpr/SpecCost.cc	(revision c8293206313c3350568d818d48c8da940d369684)
+++ src/ResolvExpr/SpecCost.cc	(revision 3fc0f2a752123e109a9539276cbb0c20c61cd0e4)
@@ -9,12 +9,14 @@
 // 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
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jun 19 10:43:00 2019
+// Update Count     : 2
 //
 
 #include <limits>
 #include <list>
-
+#include <type_traits>
+
+#include "AST/Pass.hpp"
 #include "AST/Type.hpp"
 #include "Common/PassVisitor.h"
@@ -62,5 +64,5 @@
 			visit_children = false;
 		}
-	
+
 	private:
 		// returns minimum non-negative count + 1 over type parameters (-1 if none such)
@@ -81,5 +83,5 @@
 			visit_children = false;
 		}
-		
+
 		// look for polymorphic parameters
 		void previsit(UnionInstType* uty) {
@@ -113,10 +115,101 @@
 	}
 
-	int specCost( const ast::Type * ty ) {
-		#warning unimplmented
-		(void)ty;
-		assert(false);
+namespace {
+	/// The specialization counter inner class.
+	class SpecCounter : public ast::WithShortCircuiting, public ast::WithVisitorRef<SpecCounter> {
+		int count = -1;  ///< specialization count (-1 for none)
+
+		// Converts the max value to -1 (none), otherwise increments the value.
+		static int toNoneOrInc( int value ) {
+			assert( 0 <= value );
+			return value < std::numeric_limits<int>::max() ? value + 1 : -1;
+		}
+
+		template<typename T> using MapperT =
+			typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type;
+
+		// Update the minimum to the new lowest non-none value.
+		template<typename T>
+		void updateMinimumPresent( int & minimum, const T & list, MapperT<T> mapper ) {
+			for ( const auto & node : list ) {
+				count = -1;
+				mapper( node )->accept( *visitor );
+				if ( count != -1 && count < minimum ) minimum = count;
+			}
+		}
+
+		// Returns minimum non-negative count + 1 over type parameters (-1 if none such).
+		template<typename T>
+		int minimumPresent( const T & list, MapperT<T> mapper ) {
+			int minCount = std::numeric_limits<int>::max();
+			updateMinimumPresent( minCount, list, mapper );
+			return toNoneOrInc( minCount );
+		}
+
+		// The three mappers:
+		static const ast::Type * decl_type( const ast::ptr< ast::DeclWithType > & decl ) {
+			return decl->get_type();
+		}
+		static const ast::Type * expr_result( const ast::ptr< ast::Expr > & expr ) {
+			return expr->result;
+		}
+		static const ast::Type * type_deref( const ast::ptr< ast::Type > & type ) {
+			return type.get();
+		}
+
+	public:
+		int get_count() const { return 0 <= count ? count : 0; }
+
+		// 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; }
+
+		// 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, decl_type );
+			updateMinimumPresent( minCount, fty->returns, decl_type );
+			// 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 );
+			visit_children = false;
+		}
+
+		// Look for polymorphic parameters.
+		void previsit( const ast::UnionInstType * uty ) {
+			count = minimumPresent( uty->params, expr_result );
+			visit_children = false;
+		}
+
+		// Note polymorphic type (which may be specialized).
+		// xxx - maybe account for open/closed type variables
+		void postvisit( const ast::TypeInstType * ) { count = 0; }
+
+		// Use the minimal specialization over elements.
+		// xxx - maybe don't increment, tuple flattening doesn't necessarily specialize
+		void previsit( const ast::TupleType * tty ) {
+			count = minimumPresent( tty->types, type_deref );
+			visit_children = false;
+		}
+	};
+
+} // namespace
+
+int specCost( const ast::Type * type ) {
+	if ( nullptr == type ) {
 		return 0;
 	}
+	ast::Pass<SpecCounter> counter;
+	type->accept( *counter.pass.visitor );
+	return counter.pass.get_count();
+}
+
 } // namespace ResolvExpr
 
