Index: src/ResolvExpr/ConversionCost.cc
===================================================================
--- src/ResolvExpr/ConversionCost.cc	(revision 9d5089e3f418f8ae4795697294bf00b26fc226a7)
+++ src/ResolvExpr/ConversionCost.cc	(revision da7454c9ddb30bc7658a647a83559efd03c17858)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 07:06:19 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon May  6 14:18:22 2019
-// Update Count     : 25
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Jun 24 13:33:00 2019
+// Update Count     : 26
 //
 
@@ -489,13 +489,303 @@
 	}
 
-	Cost conversionCost( 
-		const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab, 
-		const ast::TypeEnvironment & env
-	) {
-		#warning unimplemented
-		(void)src; (void)dst; (void)symtab; (void)env;
-		assert(false);
+static int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
+		const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
+	return ptrsAssignable( t1, t2, env );
+}
+
+// TODO: This is used for overload resolution. It might be able to be dropped once the old system
+// is removed.
+static Cost localConversionCost(
+	const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
+	const ast::TypeEnvironment & env
+) { return conversionCost( src, dst, symtab, env ); }
+
+Cost conversionCost(
+	const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
+	const ast::TypeEnvironment & env
+) {
+	if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
+		if ( const ast::EqvClass * eqv = env.lookup( inst->name ) ) {
+			if ( eqv->bound ) {
+				return conversionCost(src, eqv->bound, symtab, env );
+			} else {
+				return Cost::infinity;
+			}
+		} else if ( const ast::NamedTypeDecl * named = symtab.lookupType( inst->name ) ) {
+			const ast::TypeDecl * type = dynamic_cast< const ast::TypeDecl * >( named );
+			assertf( type, "Unexpected typedef." );
+			if ( type->base ) {
+				return conversionCost( src, type->base, symtab, env ) + Cost::safe;
+			}
+		}
+	}
+	if ( typesCompatibleIgnoreQualifiers( src, dst, symtab, env ) ) {
 		return Cost::zero;
-	}
+	} else if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
+		return Cost::safe;
+	} else if ( const ast::ReferenceType * refType =
+			 dynamic_cast< const ast::ReferenceType * >( dst ) ) {
+		return convertToReferenceCost( src, refType, symtab, env, localPtrsAssignable );
+	} else {
+		ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost );
+		src->accept( converter );
+		return converter.pass.cost;
+	}
+}
+
+Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, int diff,
+		const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
+		NumCostCalculation func ) {
+	if ( 0 < diff ) {
+		Cost cost = convertToReferenceCost(
+			strict_dynamic_cast< const ast::ReferenceType * >( src )->base,
+			dst, (diff - 1), symtab, env, func );
+		cost.incReference();
+		return cost;
+	} else if ( diff < -1 ) {
+		Cost cost = convertToReferenceCost(
+			src, strict_dynamic_cast< const ast::ReferenceType * >( dst )->base,
+			(diff + 1), symtab, env, func );
+		cost.incReference();
+		return cost;
+	} else if ( 0 == diff ) {
+		const ast::ReferenceType * srcAsRef = dynamic_cast< const ast::ReferenceType * >( src );
+		const ast::ReferenceType * dstAsRef = dynamic_cast< const ast::ReferenceType * >( dst );
+		if ( srcAsRef && dstAsRef ) {
+			ast::CV::Qualifiers tq1 = srcAsRef->base->qualifiers;
+			ast::CV::Qualifiers tq2 = dstAsRef->base->qualifiers;
+			if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers(
+					srcAsRef->base, dstAsRef->base, symtab, env ) ) {
+				if ( tq1 == tq2 ) {
+					return Cost::zero;
+				} else {
+					return Cost::safe;
+				}
+			} else {
+				int assignResult = func( srcAsRef->base, dstAsRef->base, symtab, env );
+				if ( 0 < assignResult ) {
+					return Cost::safe;
+				} else if ( assignResult < 0 ) {
+					return Cost::unsafe;
+				}
+			}
+		} else {
+			ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost );
+			src->accept( converter );
+			return converter.pass.cost;
+		}
+	} else {
+		assert( -1 == diff );
+		const ast::ReferenceType * dstAsRef = dynamic_cast< const ast::ReferenceType * >( dst );
+		assert( dstAsRef );
+		if ( typesCompatibleIgnoreQualifiers( src, dstAsRef->base, symtab, env ) ) {
+			if ( src->is_lvalue() ) {
+				if ( src->qualifiers == dstAsRef->base->qualifiers ) {
+					return Cost::reference;
+				} else if ( src->qualifiers < dstAsRef->base->qualifiers ) {
+					return Cost::safe;
+				} else {
+					return Cost::unsafe;
+				}
+			} else if ( dstAsRef->base->is_const() ) {
+				return Cost::safe;
+			} else {
+				return Cost::unsafe;
+			}
+		}
+	}
+	return Cost::infinity;
+}
+
+Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dst,
+	    const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
+		NumCostCalculation func ) {
+	int sdepth = src->referenceDepth(), ddepth = dst->referenceDepth();
+	return convertToReferenceCost( src, dst, sdepth - ddepth, symtab, env, func );
+}
+
+void ConversionCost_new::postvisit( const ast::VoidType * voidType ) {
+	(void)voidType;
+	cost = Cost::infinity;
+}
+
+void ConversionCost_new::postvisit( const ast::BasicType * basicType ) {
+	if ( const ast::BasicType * dstAsBasic = dynamic_cast< const ast::BasicType * >( dst ) ) {
+		int tableResult = costMatrix[ basicType->kind ][ dstAsBasic->kind ];
+		if ( tableResult == -1 ) {
+			cost = Cost::unsafe;
+		} else {
+			cost = Cost::zero;
+			cost.incSafe( tableResult );
+			cost.incSign( signMatrix[ basicType->kind ][ dstAsBasic->kind ] );
+		}
+	} else if ( dynamic_cast< const ast::EnumInstType * >( dst ) ) {
+		// xxx - not positive this is correct, but appears to allow casting int => enum
+		cost = Cost::unsafe;
+	}
+}
+
+void ConversionCost_new::postvisit( const ast::PointerType * pointerType ) {
+	if ( const ast::PointerType * dstAsPtr = dynamic_cast< const ast::PointerType * >( dst ) ) {
+		ast::CV::Qualifiers tq1 = pointerType->base->qualifiers;
+		ast::CV::Qualifiers tq2 = dstAsPtr->base->qualifiers;
+		if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers(
+				pointerType->base, dstAsPtr->base, symtab, env ) ) {
+			if ( tq1 == tq2 ) {
+				cost = Cost::zero;
+			} else {
+				cost = Cost::safe;
+			}
+		} else {
+			int assignResult = ptrsAssignable( pointerType->base, dstAsPtr->base, env );
+			if ( 0 < assignResult && tq1 <= tq2 ) {
+				if ( tq1 == tq2 ) {
+					cost = Cost::safe;
+				} else {
+					cost = Cost::safe + Cost::safe;
+				}
+			} else if ( assignResult < 0 ) {
+				cost = Cost::unsafe;
+			} // else Cost::infinity
+		}
+	}
+}
+
+void ConversionCost_new::postvisit( const ast::ArrayType * arrayType ) {
+	(void)arrayType;
+}
+
+void ConversionCost_new::postvisit( const ast::ReferenceType * refType ) {
+	assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) );
+
+	cost = costCalc( refType->base, dst, symtab, env );
+	if ( refType->base->qualifiers == dst->qualifiers ) {
+		cost.incReference();
+	} else if ( refType->base->qualifiers < dst->qualifiers ) {
+		cost.incSafe();
+	} else {
+		cost.incUnsafe();
+	}
+}
+
+void ConversionCost_new::postvisit( const ast::FunctionType * functionType ) {
+	(void)functionType;
+}
+
+void ConversionCost_new::postvisit( const ast::StructInstType * structInstType ) {
+	if ( const ast::StructInstType * dstAsInst =
+			dynamic_cast< const ast::StructInstType * >( dst ) ) {
+		if ( structInstType->name == dstAsInst->name ) {
+			cost = Cost::zero;
+		}
+	}
+}
+
+void ConversionCost_new::postvisit( const ast::UnionInstType * unionInstType ) {
+	if ( const ast::UnionInstType * dstAsInst =
+			dynamic_cast< const ast::UnionInstType * >( dst ) ) {
+		if ( unionInstType->name == dstAsInst->name ) {
+			cost = Cost::zero;
+		}
+	}
+}
+
+void ConversionCost_new::postvisit( const ast::EnumInstType * enumInstType ) {
+	(void)enumInstType;
+	static const ast::BasicType integer( ast::BasicType::SignedInt );
+	cost = costCalc( &integer, dst, symtab, env );
+	if ( cost < Cost::unsafe ) {
+		cost.incSafe();
+	}
+}
+
+void ConversionCost_new::postvisit( const ast::TraitInstType * traitInstType ) {
+	(void)traitInstType;
+}
+
+void ConversionCost_new::postvisit( const ast::TypeInstType * typeInstType ) {
+	if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) {
+		cost = costCalc( eqv->bound, dst, symtab, env );
+	} else if ( const ast::TypeInstType * dstAsInst =
+			dynamic_cast< const ast::TypeInstType * >( dst ) ) {
+		if ( typeInstType->name == dstAsInst->name ) {
+			cost = Cost::zero;
+		}
+	} else if ( const ast::NamedTypeDecl * namedType = symtab.lookupType( typeInstType->name ) ) {
+		const ast::TypeDecl * type = dynamic_cast< const ast::TypeDecl * >( namedType );
+		assertf( type, "Unexpected typedef.");
+		if ( type->base ) {
+			cost = costCalc( type->base, dst, symtab, env ) + Cost::safe;
+		}
+	}
+}
+
+void ConversionCost_new::postvisit( const ast::TupleType * tupleType ) {
+	Cost c = Cost::zero;
+	if ( const ast::TupleType * dstAsTuple = dynamic_cast< const ast::TupleType * >( dst ) ) {
+		auto srcIt = tupleType->types.begin();
+		auto dstIt = dstAsTuple->types.begin();
+		auto srcEnd = tupleType->types.end();
+		auto dstEnd = dstAsTuple->types.end();
+		while ( srcIt != srcEnd && dstIt != dstEnd ) {
+			Cost newCost = costCalc( *srcIt++, *dstIt++, symtab, env );
+			if ( newCost == Cost::infinity ) {
+				return;
+			}
+			c += newCost;
+		}
+		if ( dstIt != dstEnd ) {
+			cost = Cost::infinity;
+		} else {
+			cost = c;
+		}
+	}
+}
+
+void ConversionCost_new::postvisit( const ast::VarArgsType * varArgsType ) {
+	(void)varArgsType;
+	if ( dynamic_cast< const ast::VarArgsType * >( dst ) ) {
+		cost = Cost::zero;
+	}
+}
+
+void ConversionCost_new::postvisit( const ast::ZeroType * zeroType ) {
+	(void)zeroType;
+	if ( dynamic_cast< const ast::ZeroType * >( dst ) ) {
+		cost = Cost::zero;
+	} else if ( const ast::BasicType * dstAsBasic =
+			dynamic_cast< const ast::BasicType * >( dst ) ) {
+		int tableResult = costMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ];
+		if ( -1 == tableResult ) {
+			cost = Cost::unsafe;
+		} else {
+			cost = Cost::zero;
+			cost.incSafe( tableResult + 1 );
+			cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
+		}
+	}
+}
+
+void ConversionCost_new::postvisit( const ast::OneType * oneType ) {
+	(void)oneType;
+	if ( dynamic_cast< const ast::OneType * >( dst ) ) {
+		cost = Cost::zero;
+	} else if ( const ast::BasicType * dstAsBasic =
+			dynamic_cast< const ast::BasicType * >( dst ) ) {
+		int tableResult = costMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ];
+		if ( -1 == tableResult ) {
+			cost = Cost::unsafe;
+		} else {
+			cost = Cost::zero;
+			cost.incSafe( tableResult + 1 );
+			cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
+		}
+	} else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
+		cost = Cost::zero;
+		cost.incSafe( maxIntCost + 2 );
+	}
+}
+
+
 } // namespace ResolvExpr
 
