//
// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
//
// The contents of this file are covered under the licence agreement in the
// file "LICENCE" distributed with Cforall.
//
// ConversionCost.cc --
//
// Author           : Richard C. Bilson
// Created On       : Sun May 17 07:06:19 2015
// Last Modified By : Peter A. Buhr
// Last Modified On : Mon May  6 14:18:22 2019
// Update Count     : 25
//

#include "ConversionCost.h"

#include <cassert>                       // for assert
#include <list>                          // for list, list<>::const_iterator
#include <string>                        // for operator==, string

#include "ResolvExpr/Cost.h"             // for Cost
#include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
#include "SymTab/Indexer.h"              // for Indexer
#include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl
#include "SynTree/Type.h"                // for Type, BasicType, TypeInstType
#include "typeops.h"                     // for typesCompatibleIgnoreQualifiers

namespace ResolvExpr {
#if 0
	const Cost Cost::zero =      Cost{  0,  0,  0,  0,  0,  0,  0 };
	const Cost Cost::infinity =  Cost{ -1, -1, -1, -1, -1,  1, -1 };
	const Cost Cost::unsafe =    Cost{  1,  0,  0,  0,  0,  0,  0 };
	const Cost Cost::poly =      Cost{  0,  1,  0,  0,  0,  0,  0 };
	const Cost Cost::safe =      Cost{  0,  0,  1,  0,  0,  0,  0 };
	const Cost Cost::sign =      Cost{  0,  0,  0,  1,  0,  0,  0 };
	const Cost Cost::var =       Cost{  0,  0,  0,  0,  1,  0,  0 };
	const Cost Cost::spec =      Cost{  0,  0,  0,  0,  0, -1,  0 };
	const Cost Cost::reference = Cost{  0,  0,  0,  0,  0,  0,  1 };
#endif

#if 0
#define PRINT(x) x
#else
#define PRINT(x)
#endif

	Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
		if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) {
			PRINT( std::cerr << "type inst " << destAsTypeInst->name; )
			if ( const EqvClass* eqvClass = env.lookup( destAsTypeInst->name ) ) {
				if ( eqvClass->type ) {
					return conversionCost( src, eqvClass->type, indexer, env );
				} else {
					return Cost::infinity;
				}
			} else if ( NamedTypeDecl *namedType = indexer.lookupType( destAsTypeInst->name ) ) {
				PRINT( std::cerr << " found" << std::endl; )
				TypeDecl *type = dynamic_cast< TypeDecl* >( namedType );
				// all typedefs should be gone by this point
				assert( type );
				if ( type->base ) {
					return conversionCost( src, type->base, indexer, env ) + Cost::safe;
				} // if
			} // if
			PRINT( std::cerr << " not found" << std::endl; )
		} // if
		PRINT(
			std::cerr << "src is ";
			src->print( std::cerr );
			std::cerr << std::endl << "dest is ";
			dest->print( std::cerr );
			std::cerr << std::endl << "env is" << std::endl;
			env.print( std::cerr, 8 );
		)
		if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {
			PRINT( std::cerr << "compatible!" << std::endl; )
			return Cost::zero;
		} else if ( dynamic_cast< VoidType* >( dest ) ) {
			return Cost::safe;
		} else if ( ReferenceType * refType = dynamic_cast< ReferenceType * > ( dest ) ) {
			PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
			return convertToReferenceCost( src, refType, indexer, env, [](Type * t1, Type * t2, const SymTab::Indexer &, const TypeEnvironment & env ){
				return ptrsAssignable( t1, t2, env );
			});
		} else {
			PassVisitor<ConversionCost> converter( dest, indexer, env, conversionCost );
			src->accept( converter );
			if ( converter.pass.get_cost() == Cost::infinity ) {
				return Cost::infinity;
			} else {
				return converter.pass.get_cost() + Cost::zero;
			} // if
		} // if
	}

	Cost convertToReferenceCost( Type * src, Type * dest, int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {
		PRINT( std::cerr << "convert to reference cost... diff " << diff << " " << src << " / " << dest << std::endl; )
		if ( diff > 0 ) {
			// TODO: document this
			Cost cost = convertToReferenceCost( strict_dynamic_cast< ReferenceType * >( src )->base, dest, diff-1, indexer, env, func );
			cost.incReference();
			return cost;
		} else if ( diff < -1 ) {
			// TODO: document this
			Cost cost = convertToReferenceCost( src, strict_dynamic_cast< ReferenceType * >( dest )->base, diff+1, indexer, env, func );
			cost.incReference();
			return cost;
		} else if ( diff == 0 ) {
			ReferenceType * srcAsRef = dynamic_cast< ReferenceType * >( src );
			ReferenceType * destAsRef = dynamic_cast< ReferenceType * >( dest );
			if ( srcAsRef && destAsRef ) { // pointer-like conversions between references
				PRINT( std::cerr << "converting between references" << std::endl; )
				Type::Qualifiers tq1 = srcAsRef->base->get_qualifiers();
				Type::Qualifiers tq2 = destAsRef->base->get_qualifiers();
				if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( srcAsRef->base, destAsRef->base, indexer, env ) ) {
					PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
					if ( tq1 == tq2 ) {
						// types are the same
						return Cost::zero;
					} else {
						// types are the same, except otherPointer has more qualifiers
						return Cost::safe;
					}
				} else {  // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
					int assignResult = func( srcAsRef->base, destAsRef->base, indexer, env );
					PRINT( std::cerr << "comparing references: " << assignResult << " " << srcAsRef << " " << destAsRef << std::endl; )
					if ( assignResult > 0 ) {
						return Cost::safe;
					} else if ( assignResult < 0 ) {
						return Cost::unsafe;
					} // if
				} // if
			} else {
				PRINT( std::cerr << "reference to rvalue conversion" << std::endl; )
				PassVisitor<ConversionCost> converter( dest, indexer, env, conversionCost );
				src->accept( converter );
				return converter.pass.get_cost();
			} // if
		} else {
			ReferenceType * destAsRef = dynamic_cast< ReferenceType * >( dest );
			assert( diff == -1 && destAsRef );
			PRINT( std::cerr << "dest is: " << dest << " / src is: " << src << std::endl; )
			if ( typesCompatibleIgnoreQualifiers( src, destAsRef->base, indexer, env ) ) {
				PRINT( std::cerr << "converting compatible base type" << std::endl; )
				if ( src->get_lvalue() ) {
					PRINT(
						std::cerr << "lvalue to reference conversion" << std::endl;
						std::cerr << src << " => " << destAsRef << std::endl;
					)
					// lvalue-to-reference conversion:  cv lvalue T => cv T &
					if ( src->get_qualifiers() == destAsRef->base->get_qualifiers() ) {
						return Cost::reference; // cost needs to be non-zero to add cast
					} if ( src->get_qualifiers() < destAsRef->base->get_qualifiers() ) {
						return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same
					} else {
						return Cost::unsafe;
					} // if
				} else if ( destAsRef->base->get_const() ) {
					PRINT( std::cerr << "rvalue to const ref conversion" << std::endl; )
					// rvalue-to-const-reference conversion: T => const T &
					return Cost::safe;
				} else {
					PRINT( std::cerr << "rvalue to non-const reference conversion" << std::endl; )
					// rvalue-to-reference conversion: T => T &
					return Cost::unsafe;
				} // if
			} // if
			PRINT( std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl; )
		}
		return Cost::infinity;
	}

	Cost convertToReferenceCost( Type * src, ReferenceType * dest, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {
		int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth();
		Cost cost = convertToReferenceCost( src, dest, sdepth-ddepth, indexer, env, func );
		PRINT( std::cerr << "convertToReferenceCost result: " << cost << std::endl; )
		return cost;
	}

	ConversionCost::ConversionCost( Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )
		: dest( dest ), indexer( indexer ), cost( Cost::infinity ), env( env ), costFunc( costFunc ) {
	}

	// GENERATED START, DO NOT EDIT
	// GENERATED BY BasicTypes-gen.cc
	/* EXTENDED INTEGRAL RANK HIERARCHY (root to leaves)
	                         _Bool
	char                signed char         unsigned char       
	          signed short int         unsigned short int       
	          signed int               unsigned int             
	          signed long int          unsigned long int        
	          signed long long int     unsigned long long int   
	          __int128                 unsigned __int128        
	          _Float16                 _Float16 _Complex        
	          _Float32                 _Float32 _Complex        
	          float                    float _Complex           
	          _Float32x                _Float32x _Complex       
	          _Float64                 _Float64 _Complex        
	          double                   double _Complex          
	          _Float64x                _Float64x _Complex       
	                     __float80
	          _Float128                _Float128 _Complex       
	                    __float128
	          long double              long double _Complex     
	          _Float128x               _Float128x _Complex      
	*/
	// GENERATED END

	// GENERATED START, DO NOT EDIT
	// GENERATED BY BasicTypes-gen.cc
	static const int costMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node
		/*             B    C   SC   UC   SI  SUI    I   UI   LI  LUI  LLI LLUI   IB  UIB  _FH  _FH   _F  _FC    F   FC  _FX _FXC   FD _FDC    D   DC F80X_FDXC  F80  _FB_FLDC   FB   LD  LDC _FBX_FLDXC */
		/*     B*/ {   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  15,  16,  17,  16,  18,  17, },
		/*     C*/ {  -1,   0,   1,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  16,  15,  17,  16, },
		/*    SC*/ {  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  16,  15,  17,  16, },
		/*    UC*/ {  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  16,  15,  17,  16, },
		/*    SI*/ {  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  15,  14,  16,  15, },
		/*   SUI*/ {  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  15,  14,  16,  15, },
		/*     I*/ {  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  14,  13,  15,  14, },
		/*    UI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  14,  13,  15,  14, },
		/*    LI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  13,  12,  14,  13, },
		/*   LUI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  13,  12,  14,  13, },
		/*   LLI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  12,  11,  13,  12, },
		/*  LLUI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  12,  11,  13,  12, },
		/*    IB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  11,  10,  12,  11, },
		/*   UIB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  11,  10,  12,  11, },
		/*   _FH*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,  10,   9,  11,  10, },
		/*   _FH*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   4,  -1,   5,  -1,   6,  -1,  -1,   7,  -1,  -1,   8,  -1,   9, },
		/*    _F*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   9,   8,  10,   9, },
		/*   _FC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   4,  -1,   5,  -1,  -1,   6,  -1,  -1,   7,  -1,   8, },
		/*     F*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   8,   7,   9,   8, },
		/*    FC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   4,  -1,  -1,   5,  -1,  -1,   6,  -1,   7, },
		/*   _FX*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   7,   6,   8,   7, },
		/*  _FXC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,  -1,   4,  -1,  -1,   5,  -1,   6, },
		/*    FD*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   6,   5,   7,   6, },
		/*  _FDC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,  -1,   3,  -1,  -1,   4,  -1,   5, },
		/*     D*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   5,   4,   6,   5, },
		/*    DC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,  -1,   2,  -1,  -1,   3,  -1,   4, },
		/*  F80X*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   4,   3,   5,   4, },
		/* _FDXC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   1,  -1,  -1,   2,  -1,   3, },
		/*   F80*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   1,   0,   1,   2,   2,   3,   3,   4,   4, },
		/*   _FB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3, },
		/* _FLDC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   1,  -1,   2, },
		/*    FB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   1,   0,   1,   2,   2,   3, },
		/*    LD*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2, },
		/*   LDC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1, },
		/*  _FBX*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1, },
		/*_FLDXC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0, },
	}; // costMatrix
	static const int maxIntCost = 15;
	// GENERATED END
	static_assert(
		sizeof(costMatrix)/sizeof(costMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES,
		"Missing row in the cost matrix"
	);

	// GENERATED START, DO NOT EDIT
	// GENERATED BY BasicTypes-gen.cc
	static const int signMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion
		/*             B    C   SC   UC   SI  SUI    I   UI   LI  LUI  LLI LLUI   IB  UIB  _FH  _FH   _F  _FC    F   FC  _FX _FXC   FD _FDC    D   DC F80X_FDXC  F80  _FB_FLDC   FB   LD  LDC _FBX_FLDXC */
		/*     B*/ {   0,   0,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*     C*/ {  -1,   0,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*    SC*/ {  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*    UC*/ {  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*    SI*/ {  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*   SUI*/ {  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*     I*/ {  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*    UI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*    LI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*   LUI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*   LLI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*  LLUI*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*    IB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*   UIB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*   _FH*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*   _FH*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
		/*    _F*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*   _FC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
		/*     F*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*    FC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
		/*   _FX*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*  _FXC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
		/*    FD*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*  _FDC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
		/*     D*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*    DC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
		/*  F80X*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/* _FDXC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
		/*   F80*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
		/*   _FB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0, },
		/* _FLDC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
		/*    FB*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0, },
		/*    LD*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0, },
		/*   LDC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0, },
		/*  _FBX*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0, },
		/*_FLDXC*/ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0, },
	}; // signMatrix
	// GENERATED END
	static_assert(
		sizeof(signMatrix)/sizeof(signMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES,
		"Missing row in the sign matrix"
	);

	void ConversionCost::postvisit( VoidType * ) {
		cost = Cost::infinity;
	}

	void ConversionCost::postvisit(BasicType *basicType) {
		if ( BasicType *destAsBasic = dynamic_cast< BasicType* >( dest ) ) {
			int tableResult = costMatrix[ basicType->get_kind() ][ destAsBasic->get_kind() ];
			if ( tableResult == -1 ) {
				cost = Cost::unsafe;
			} else {
				cost = Cost::zero;
				cost.incSafe( tableResult );
				cost.incSign( signMatrix[ basicType->get_kind() ][ destAsBasic->get_kind() ] );
			} // if
		} else if ( dynamic_cast< EnumInstType *>( dest ) ) {
			// xxx - not positive this is correct, but appears to allow casting int => enum
			cost = Cost::unsafe;
		} // if
		// no cases for zero_t/one_t because it should not be possible to convert int, etc. to zero_t/one_t.
	}

	void ConversionCost::postvisit( PointerType * pointerType ) {
		if ( PointerType *destAsPtr = dynamic_cast< PointerType* >( dest ) ) {
			PRINT( std::cerr << pointerType << " ===> " << destAsPtr << std::endl; )
			Type::Qualifiers tq1 = pointerType->base->get_qualifiers();
			Type::Qualifiers tq2 = destAsPtr->base->get_qualifiers();
			if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {
				PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
				if ( tq1 == tq2 ) {
					// types are the same
					cost = Cost::zero;
				} else {
					// types are the same, except otherPointer has more qualifiers
					cost = Cost::safe;
				} // if
			} else {
				int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env );
				PRINT( std::cerr << " :: " << assignResult << std::endl; )
				if ( assignResult > 0 && tq1 <= tq2 ) {
					// xxx - want the case where qualifiers are added to be more expensive than the case where qualifiers are the same. Is 1 safe vs. 2 safe correct?
					if ( tq1 == tq2 ) {
						cost = Cost::safe;
					} else if ( tq1 < tq2 ) {
						cost = Cost::safe+Cost::safe;
					}
				} else if ( assignResult < 0 ) {
					cost = Cost::unsafe;
				} // if
				// assignResult == 0 means Cost::Infinity
			} // if
			// case case for zero_t because it should not be possible to convert pointers to zero_t.
		} // if
	}

	void ConversionCost::postvisit( ArrayType * ) {}

	void ConversionCost::postvisit( ReferenceType * refType ) {
		// Note: dest can never be a reference, since it would have been caught in an earlier check
		assert( ! dynamic_cast< ReferenceType * >( dest ) );
		// convert reference to rvalue: cv T1 & => T2
		// recursively compute conversion cost from T1 to T2.
		// cv can be safely dropped because of 'implicit dereference' behavior.
		cost = costFunc( refType->base, dest, indexer, env );
		if ( refType->base->get_qualifiers() == dest->get_qualifiers() ) {
			cost.incReference();  // prefer exact qualifiers
		} else if ( refType->base->get_qualifiers() < dest->get_qualifiers() ) {
			cost.incSafe(); // then gaining qualifiers
		} else {
			cost.incUnsafe(); // lose qualifiers as last resort
		}
		PRINT( std::cerr << refType << " ==> " << dest << " " << cost << std::endl; )
	}

	void ConversionCost::postvisit( FunctionType * ) {}

	void ConversionCost::postvisit( StructInstType * inst ) {
		if ( StructInstType *destAsInst = dynamic_cast< StructInstType* >( dest ) ) {
			if ( inst->name == destAsInst->name ) {
				cost = Cost::zero;
			} // if
		} // if
	}

	void ConversionCost::postvisit( UnionInstType * inst ) {
		if ( UnionInstType *destAsInst = dynamic_cast< UnionInstType* >( dest ) ) {
			if ( inst->name == destAsInst->name ) {
				cost = Cost::zero;
			} // if
		} // if
	}

	void ConversionCost::postvisit( EnumInstType * ) {
		static Type::Qualifiers q;
		static BasicType integer( q, BasicType::SignedInt );
		cost = costFunc( &integer, dest, indexer, env );  // safe if dest >= int
		if ( cost < Cost::unsafe ) {
			cost.incSafe();
		} // if
	}

	void ConversionCost::postvisit( TraitInstType * ) {}

	void ConversionCost::postvisit( TypeInstType *inst ) {
		if ( const EqvClass *eqvClass = env.lookup( inst->name ) ) {
			cost = costFunc( eqvClass->type, dest, indexer, env );
		} else if ( TypeInstType *destAsInst = dynamic_cast< TypeInstType* >( dest ) ) {
			if ( inst->name == destAsInst->name ) {
				cost = Cost::zero;
			}
		} else if ( NamedTypeDecl *namedType = indexer.lookupType( inst->name ) ) {
			TypeDecl *type = dynamic_cast< TypeDecl* >( namedType );
			// all typedefs should be gone by this point
			assert( type );
			if ( type->base ) {
				cost = costFunc( type->base, dest, indexer, env ) + Cost::safe;
			} // if
		} // if
	}

	void ConversionCost::postvisit( TupleType * tupleType ) {
		Cost c = Cost::zero;
		if ( TupleType * destAsTuple = dynamic_cast< TupleType * >( dest ) ) {
			std::list< Type * >::const_iterator srcIt = tupleType->types.begin();
			std::list< Type * >::const_iterator destIt = destAsTuple->types.begin();
			while ( srcIt != tupleType->types.end() && destIt != destAsTuple->types.end() ) {
				Cost newCost = costFunc( *srcIt++, *destIt++, indexer, env );
				if ( newCost == Cost::infinity ) {
					return;
				} // if
				c += newCost;
			} // while
			if ( destIt != destAsTuple->types.end() ) {
				cost = Cost::infinity;
			} else {
				cost = c;
			} // if
		} // if
	}

	void ConversionCost::postvisit( VarArgsType * ) {
		if ( dynamic_cast< VarArgsType* >( dest ) ) {
			cost = Cost::zero;
		}
	}

	void ConversionCost::postvisit( ZeroType * ) {
		if ( dynamic_cast< ZeroType * >( dest ) ) {
			cost = Cost::zero;
		} else if ( BasicType *destAsBasic = dynamic_cast< BasicType* >( dest ) ) {
			// copied from visit(BasicType*) for signed int, but +1 for safe conversions
			int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
			if ( tableResult == -1 ) {
				cost = Cost::unsafe;
			} else {
				cost = Cost::zero;
				cost.incSafe( tableResult + 1 );
				cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ] );
			} // if
		} else if ( dynamic_cast< PointerType* >( dest ) ) {
			cost = Cost::zero;
			cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation
		} // if
	}

	void ConversionCost::postvisit( OneType * ) {
		if ( dynamic_cast< OneType * >( dest ) ) {
			cost = Cost::zero;
		} else if ( BasicType *destAsBasic = dynamic_cast< BasicType* >( dest ) ) {
			// copied from visit(BasicType*) for signed int, but +1 for safe conversions
			int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
			if ( tableResult == -1 ) {
				cost = Cost::unsafe;
			} else {
				cost = Cost::zero;
				cost.incSafe( tableResult + 1 );
				cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ] );
			} // if
		} // if
	}
} // namespace ResolvExpr

// Local Variables: //
// tab-width: 4 //
// mode: c++ //
// compile-command: "make install" //
// End: //
