Changeset c6b4432 for src/ResolvExpr/ConversionCost.cc
- Timestamp:
- Nov 8, 2023, 2:01:11 PM (8 months ago)
- Branches:
- master
- Children:
- 3e4bf0d, f5ec35a
- Parents:
- 790d835
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/ConversionCost.cc
r790d835 rc6b4432 21 21 22 22 #include "ResolvExpr/Cost.h" // for Cost 23 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment24 23 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 25 24 #include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable 26 #include "SymTab/Indexer.h" // for Indexer27 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl28 #include "SynTree/Type.h" // for Type, BasicType, TypeInstType29 30 25 31 26 namespace ResolvExpr { 32 #if 033 const Cost Cost::zero = Cost{ 0, 0, 0, 0, 0, 0, 0 };34 const Cost Cost::infinity = Cost{ -1, -1, -1, -1, -1, 1, -1 };35 const Cost Cost::unsafe = Cost{ 1, 0, 0, 0, 0, 0, 0 };36 const Cost Cost::poly = Cost{ 0, 1, 0, 0, 0, 0, 0 };37 const Cost Cost::safe = Cost{ 0, 0, 1, 0, 0, 0, 0 };38 const Cost Cost::sign = Cost{ 0, 0, 0, 1, 0, 0, 0 };39 const Cost Cost::var = Cost{ 0, 0, 0, 0, 1, 0, 0 };40 const Cost Cost::spec = Cost{ 0, 0, 0, 0, 0, -1, 0 };41 const Cost Cost::reference = Cost{ 0, 0, 0, 0, 0, 0, 1 };42 #endif43 27 44 28 #if 0 … … 47 31 #define PRINT(x) 48 32 #endif 49 50 Cost conversionCost( const Type * src, const Type * dest, bool srcIsLvalue,51 const SymTab::Indexer &indexer, const TypeEnvironment &env ) {52 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) {53 PRINT( std::cerr << "type inst " << destAsTypeInst->name; )54 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) {55 if ( eqvClass->type ) {56 return conversionCost( src, eqvClass->type, srcIsLvalue, indexer, env );57 } else {58 return Cost::infinity;59 }60 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) {61 PRINT( std::cerr << " found" << std::endl; )62 const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );63 // all typedefs should be gone by this point64 assert( type );65 if ( type->base ) {66 return conversionCost( src, type->base, srcIsLvalue, indexer, env )67 + Cost::safe;68 } // if69 } // if70 PRINT( std::cerr << " not found" << std::endl; )71 } // if72 PRINT(73 std::cerr << "src is ";74 src->print( std::cerr );75 std::cerr << std::endl << "dest is ";76 dest->print( std::cerr );77 std::cerr << std::endl << "env is" << std::endl;78 env.print( std::cerr, 8 );79 )80 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {81 PRINT( std::cerr << "compatible!" << std::endl; )82 return Cost::zero;83 } else if ( dynamic_cast< const VoidType * >( dest ) ) {84 return Cost::safe;85 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) {86 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )87 return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * const t1, const Type * t2, const SymTab::Indexer &, const TypeEnvironment & env ){88 return ptrsAssignable( t1, t2, env );89 });90 } else {91 PassVisitor<ConversionCost> converter(92 dest, srcIsLvalue, indexer, env,93 (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))94 conversionCost );95 src->accept( converter );96 if ( converter.pass.get_cost() == Cost::infinity ) {97 return Cost::infinity;98 } else {99 return converter.pass.get_cost() + Cost::zero;100 } // if101 } // if102 }103 104 static Cost convertToReferenceCost( const Type * src, const Type * dest, bool srcIsLvalue,105 int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {106 PRINT( std::cerr << "convert to reference cost... diff " << diff << " " << src << " / " << dest << std::endl; )107 if ( diff > 0 ) {108 // TODO: document this109 Cost cost = convertToReferenceCost(110 strict_dynamic_cast< const ReferenceType * >( src )->base, dest, srcIsLvalue,111 diff-1, indexer, env, func );112 cost.incReference();113 return cost;114 } else if ( diff < -1 ) {115 // TODO: document this116 Cost cost = convertToReferenceCost(117 src, strict_dynamic_cast< const ReferenceType * >( dest )->base, srcIsLvalue,118 diff+1, indexer, env, func );119 cost.incReference();120 return cost;121 } else if ( diff == 0 ) {122 const ReferenceType * srcAsRef = dynamic_cast< const ReferenceType * >( src );123 const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );124 if ( srcAsRef && destAsRef ) { // pointer-like conversions between references125 PRINT( std::cerr << "converting between references" << std::endl; )126 Type::Qualifiers tq1 = srcAsRef->base->tq;127 Type::Qualifiers tq2 = destAsRef->base->tq;128 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( srcAsRef->base, destAsRef->base, indexer, env ) ) {129 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )130 if ( tq1 == tq2 ) {131 // types are the same132 return Cost::zero;133 } else {134 // types are the same, except otherPointer has more qualifiers135 return Cost::safe;136 }137 } else { // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?138 int assignResult = func( srcAsRef->base, destAsRef->base, indexer, env );139 PRINT( std::cerr << "comparing references: " << assignResult << " " << srcAsRef << " " << destAsRef << std::endl; )140 if ( assignResult > 0 ) {141 return Cost::safe;142 } else if ( assignResult < 0 ) {143 return Cost::unsafe;144 } // if145 } // if146 } else {147 PRINT( std::cerr << "reference to rvalue conversion" << std::endl; )148 PassVisitor<ConversionCost> converter(149 dest, srcIsLvalue, indexer, env,150 (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))151 conversionCost );152 src->accept( converter );153 return converter.pass.get_cost();154 } // if155 } else {156 const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );157 assert( diff == -1 && destAsRef );158 PRINT( std::cerr << "dest is: " << dest << " / src is: " << src << std::endl; )159 if ( typesCompatibleIgnoreQualifiers( src, destAsRef->base, indexer, env ) ) {160 PRINT( std::cerr << "converting compatible base type" << std::endl; )161 if ( srcIsLvalue ) {162 PRINT(163 std::cerr << "lvalue to reference conversion" << std::endl;164 std::cerr << src << " => " << destAsRef << std::endl;165 )166 // lvalue-to-reference conversion: cv lvalue T => cv T &167 if ( src->tq == destAsRef->base->tq ) {168 return Cost::reference; // cost needs to be non-zero to add cast169 } if ( src->tq < destAsRef->base->tq ) {170 return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same171 } else {172 return Cost::unsafe;173 } // if174 } else if ( destAsRef->base->get_const() ) {175 PRINT( std::cerr << "rvalue to const ref conversion" << std::endl; )176 // rvalue-to-const-reference conversion: T => const T &177 return Cost::safe;178 } else {179 PRINT( std::cerr << "rvalue to non-const reference conversion" << std::endl; )180 // rvalue-to-reference conversion: T => T &181 return Cost::unsafe;182 } // if183 } // if184 PRINT( std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl; )185 }186 return Cost::infinity;187 }188 189 Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue,190 const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {191 int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth();192 Cost cost = convertToReferenceCost( src, dest, srcIsLvalue, sdepth-ddepth, indexer, env, func );193 PRINT( std::cerr << "convertToReferenceCost result: " << cost << std::endl; )194 return cost;195 }196 197 ConversionCost::ConversionCost( const Type * dest, bool srcIsLvalue, const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )198 : dest( dest ), srcIsLvalue( srcIsLvalue ), indexer( indexer ), cost( Cost::infinity ), env( env ), costFunc( costFunc ) {199 }200 33 201 34 // GENERATED START, DO NOT EDIT … … 319 152 ); 320 153 321 void ConversionCost::postvisit( const VoidType * ) {322 cost = Cost::infinity;323 }324 325 // refactor for code resue326 void ConversionCost::conversionCostFromBasicToBasic(const BasicType * src, const BasicType * dest) {327 int tableResult = costMatrix[ src->kind ][ dest->kind ];328 if ( tableResult == -1 ) {329 cost = Cost::unsafe;330 } else {331 cost = Cost::zero;332 cost.incSafe( tableResult );333 cost.incSign( signMatrix[ src->kind ][ dest->kind ] );334 } // if335 } // ConversionCost::conversionCostFromBasicToBasic336 337 void ConversionCost::postvisit(const BasicType * basicType) {338 if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {339 conversionCostFromBasicToBasic(basicType, destAsBasic);340 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * >( dest ) ) {341 const EnumDecl * base_enum = enumInst->baseEnum;342 if ( const Type * base = base_enum->base ) {343 if ( const BasicType * enumBaseAstBasic = dynamic_cast< const BasicType *> (base) ) {344 conversionCostFromBasicToBasic(basicType, enumBaseAstBasic);345 } else {346 cost = Cost::infinity;347 } // if348 } else {349 cost = Cost::unsafe;350 } // if351 } // if352 // no cases for zero_t/one_t because it should not be possible to convert int, etc. to zero_t/one_t.353 }354 355 void ConversionCost::postvisit( const PointerType * pointerType ) {356 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) {357 PRINT( std::cerr << pointerType << " ===> " << destAsPtr << std::endl; )358 Type::Qualifiers tq1 = pointerType->base->tq;359 Type::Qualifiers tq2 = destAsPtr->base->tq;360 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {361 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )362 if ( tq1 == tq2 ) {363 // types are the same364 cost = Cost::zero;365 } else {366 // types are the same, except otherPointer has more qualifiers367 cost = Cost::safe;368 } // if369 } else {370 int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env );371 PRINT( std::cerr << " :: " << assignResult << std::endl; )372 if ( assignResult > 0 && tq1 <= tq2 ) {373 // 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?374 if ( tq1 == tq2 ) {375 cost = Cost::safe;376 } else if ( tq1 < tq2 ) {377 cost = Cost::safe+Cost::safe;378 }379 } else if ( assignResult < 0 ) {380 cost = Cost::unsafe;381 } // if382 // assignResult == 0 means Cost::Infinity383 } // if384 // case case for zero_t because it should not be possible to convert pointers to zero_t.385 } // if386 }387 388 void ConversionCost::postvisit( const ArrayType * ) {}389 390 void ConversionCost::postvisit( const ReferenceType * refType ) {391 // Note: dest can never be a reference, since it would have been caught in an earlier check392 assert( ! dynamic_cast< const ReferenceType * >( dest ) );393 // convert reference to rvalue: cv T1 & => T2394 // recursively compute conversion cost from T1 to T2.395 // cv can be safely dropped because of 'implicit dereference' behavior.396 cost = costFunc( refType->base, dest, srcIsLvalue, indexer, env );397 if ( refType->base->tq == dest->tq ) {398 cost.incReference(); // prefer exact qualifiers399 } else if ( refType->base->tq < dest->tq ) {400 cost.incSafe(); // then gaining qualifiers401 } else {402 cost.incUnsafe(); // lose qualifiers as last resort403 }404 PRINT( std::cerr << refType << " ==> " << dest << " " << cost << std::endl; )405 }406 407 void ConversionCost::postvisit( const FunctionType * ) {}408 409 void ConversionCost::postvisit( const EnumInstType * enumInst) {410 const EnumDecl * enumDecl = enumInst -> baseEnum;411 if ( const Type * enumType = enumDecl -> base ) { // if it is a typed enum412 cost = costFunc( enumType, dest, srcIsLvalue, indexer, env );413 } else {414 static Type::Qualifiers q;415 static BasicType integer( q, BasicType::SignedInt );416 cost = costFunc( &integer, dest, srcIsLvalue, indexer, env ); // safe if dest >= int417 } // if418 if ( cost < Cost::unsafe ) {419 cost.incSafe();420 } // if421 }422 423 void ConversionCost::postvisit( const TraitInstType * ) {}424 425 void ConversionCost::postvisit( const TypeInstType * inst ) {426 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) {427 cost = costFunc( eqvClass->type, dest, srcIsLvalue, indexer, env );428 } else if ( const TypeInstType * destAsInst = dynamic_cast< const TypeInstType * >( dest ) ) {429 if ( inst->name == destAsInst->name ) {430 cost = Cost::zero;431 }432 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( inst->name ) ) {433 const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );434 // all typedefs should be gone by this point435 assert( type );436 if ( type->base ) {437 cost = costFunc( type->base, dest, srcIsLvalue, indexer, env ) + Cost::safe;438 } // if439 } // if440 }441 442 void ConversionCost::postvisit( const TupleType * tupleType ) {443 Cost c = Cost::zero;444 if ( const TupleType * destAsTuple = dynamic_cast< const TupleType * >( dest ) ) {445 std::list< Type * >::const_iterator srcIt = tupleType->types.begin();446 std::list< Type * >::const_iterator destIt = destAsTuple->types.begin();447 while ( srcIt != tupleType->types.end() && destIt != destAsTuple->types.end() ) {448 Cost newCost = costFunc( * srcIt++, * destIt++, srcIsLvalue, indexer, env );449 if ( newCost == Cost::infinity ) {450 return;451 } // if452 c += newCost;453 } // while454 if ( destIt != destAsTuple->types.end() ) {455 cost = Cost::infinity;456 } else {457 cost = c;458 } // if459 } // if460 }461 462 void ConversionCost::postvisit( const VarArgsType * ) {463 if ( dynamic_cast< const VarArgsType * >( dest ) ) {464 cost = Cost::zero;465 }466 }467 468 void ConversionCost::postvisit( const ZeroType * ) {469 if ( dynamic_cast< const ZeroType * >( dest ) ) {470 cost = Cost::zero;471 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {472 // copied from visit(BasicType *) for signed int, but +1 for safe conversions473 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];474 if ( tableResult == -1 ) {475 cost = Cost::unsafe;476 } else {477 cost = Cost::zero;478 cost.incSafe( tableResult + 1 );479 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );480 } // if481 } else if ( dynamic_cast< const PointerType * >( dest ) ) {482 cost = Cost::zero;483 cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation484 } // if485 }486 487 void ConversionCost::postvisit( const OneType * ) {488 if ( dynamic_cast< const OneType * >( dest ) ) {489 cost = Cost::zero;490 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {491 // copied from visit(BasicType *) for signed int, but +1 for safe conversions492 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];493 if ( tableResult == -1 ) {494 cost = Cost::unsafe;495 } else {496 cost = Cost::zero;497 cost.incSafe( tableResult + 1 );498 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );499 } // if500 } // if501 }502 503 154 namespace { 504 155 # warning For overload resolution between the two versions.
Note: See TracChangeset
for help on using the changeset viewer.