Ignore:
Timestamp:
Nov 8, 2023, 2:01:11 PM (8 months ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
master
Children:
3e4bf0d, f5ec35a
Parents:
790d835
Message:

Remove BaseSyntaxNode? and clean-up.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/ConversionCost.cc

    r790d835 rc6b4432  
    2121
    2222#include "ResolvExpr/Cost.h"             // for Cost
    23 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    2423#include "ResolvExpr/Unify.h"            // for typesCompatibleIgnoreQualifiers
    2524#include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable
    26 #include "SymTab/Indexer.h"              // for Indexer
    27 #include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl
    28 #include "SynTree/Type.h"                // for Type, BasicType, TypeInstType
    29 
    3025
    3126namespace ResolvExpr {
    32 #if 0
    33         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 #endif
    4327
    4428#if 0
     
    4731#define PRINT(x)
    4832#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 point
    64                                 assert( type );
    65                                 if ( type->base ) {
    66                                         return conversionCost( src, type->base, srcIsLvalue, indexer, env )
    67                                                 + Cost::safe;
    68                                 } // if
    69                         } // if
    70                         PRINT( std::cerr << " not found" << std::endl; )
    71                 } // if
    72                 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                         } // if
    101                 } // if
    102         }
    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 this
    109                         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 this
    116                         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 references
    125                                 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 same
    132                                                 return Cost::zero;
    133                                         } else {
    134                                                 // types are the same, except otherPointer has more qualifiers
    135                                                 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                                         } // if
    145                                 } // if
    146                         } 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                         } // if
    155                 } 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 cast
    169                                         } if ( src->tq < destAsRef->base->tq ) {
    170                                                 return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same
    171                                         } else {
    172                                                 return Cost::unsafe;
    173                                         } // if
    174                                 } 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                                 } // if
    183                         } // if
    184                         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         }
    20033
    20134        // GENERATED START, DO NOT EDIT
     
    319152        );
    320153
    321         void ConversionCost::postvisit( const VoidType * ) {
    322                 cost = Cost::infinity;
    323         }
    324 
    325         // refactor for code resue
    326         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                 } // if
    335         } // ConversionCost::conversionCostFromBasicToBasic
    336 
    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                                 } // if
    348                         } else {
    349                                 cost = Cost::unsafe;
    350                         } // if
    351                 } // if
    352                 // 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 same
    364                                         cost = Cost::zero;
    365                                 } else {
    366                                         // types are the same, except otherPointer has more qualifiers
    367                                         cost = Cost::safe;
    368                                 } // if
    369                         } 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                                 } // if
    382                                 // assignResult == 0 means Cost::Infinity
    383                         } // if
    384                         // case case for zero_t because it should not be possible to convert pointers to zero_t.
    385                 } // if
    386         }
    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 check
    392                 assert( ! dynamic_cast< const ReferenceType * >( dest ) );
    393                 // convert reference to rvalue: cv T1 & => T2
    394                 // 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 qualifiers
    399                 } else if ( refType->base->tq < dest->tq ) {
    400                         cost.incSafe(); // then gaining qualifiers
    401                 } else {
    402                         cost.incUnsafe(); // lose qualifiers as last resort
    403                 }
    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 enum
    412                         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 >= int
    417                 } // if
    418                 if ( cost < Cost::unsafe ) {
    419                                 cost.incSafe();
    420                 } // if
    421         }
    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 point
    435                         assert( type );
    436                         if ( type->base ) {
    437                                 cost = costFunc( type->base, dest, srcIsLvalue, indexer, env ) + Cost::safe;
    438                         } // if
    439                 } // if
    440         }
    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                                 } // if
    452                                 c += newCost;
    453                         } // while
    454                         if ( destIt != destAsTuple->types.end() ) {
    455                                 cost = Cost::infinity;
    456                         } else {
    457                                 cost = c;
    458                         } // if
    459                 } // if
    460         }
    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 conversions
    473                         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                         } // if
    481                 } else if ( dynamic_cast< const PointerType * >( dest ) ) {
    482                         cost = Cost::zero;
    483                         cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation
    484                 } // if
    485         }
    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 conversions
    492                         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                         } // if
    500                 } // if
    501         }
    502 
    503154namespace {
    504155        # warning For overload resolution between the two versions.
Note: See TracChangeset for help on using the changeset viewer.