Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/ConversionCost.cc

    r74b007ba r7e003011  
    2121
    2222namespace ResolvExpr {
    23         const Cost Cost::zero = Cost( 0, 0, 0, 0 );
    24         const Cost Cost::infinity = Cost( -1, -1, -1, -1 );
    25         const Cost Cost::unsafe = Cost( 1, 0, 0, 0 );
    26         const Cost Cost::poly = Cost( 0, 1, 0, 0 );
    27         const Cost Cost::safe = Cost( 0, 0, 1, 0 );
    28         const Cost Cost::reference = Cost( 0, 0, 0, 1 );
    29 
     23        const Cost Cost::zero = Cost( 0, 0, 0 );
     24        const Cost Cost::infinity = Cost( -1, -1, -1 );
    3025
    3126        Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
     
    4641                                assert( type );
    4742                                if ( type->get_base() ) {
    48                                         return conversionCost( src, type->get_base(), indexer, env ) + Cost::safe;
     43                                        return conversionCost( src, type->get_base(), indexer, env ) + Cost( 0, 0, 1 );
    4944                                } // if
    5045                        } // if
     
    5954                if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {
    6055///     std::cout << "compatible!" << std::endl;
    61                         return Cost::zero;
     56                        return Cost( 0, 0, 0 );
    6257                } else if ( dynamic_cast< VoidType* >( dest ) ) {
    63                         return Cost::safe;
    64                 } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * > ( dest ) ) {
    65                         // std::cerr << "conversionCost: dest is reference" << std::endl;
    66                         return convertToReferenceCost( src, refType, indexer, env );
     58                        return Cost( 0, 0, 1 );
    6759                } else {
    6860                        ConversionCost converter( dest, indexer, env );
     
    7163                                return Cost::infinity;
    7264                        } else {
    73                                 return converter.get_cost() + Cost::zero;
    74                         } // if
    75                 } // if
    76         }
    77 
    78         Cost convertToReferenceCost( Type * src, Type * dest, int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
    79                 // std::cerr << "convert to reference cost..." << std::endl;
    80                 if ( diff > 0 ) {
    81                         // TODO: document this
    82                         Cost cost = convertToReferenceCost( safe_dynamic_cast< ReferenceType * >( src )->get_base(), dest, diff-1, indexer, env );
    83                         cost.incReference();
    84                         return cost;
    85                 } else if ( diff < -1 ) {
    86                         // TODO: document this
    87                         Cost cost = convertToReferenceCost( src, safe_dynamic_cast< ReferenceType * >( dest )->get_base(), diff+1, indexer, env );
    88                         cost.incReference();
    89                         return cost;
    90                 } else if ( diff == 0 ) {
    91                         ReferenceType * srcAsRef = dynamic_cast< ReferenceType * >( src );
    92                         ReferenceType * destAsRef = dynamic_cast< ReferenceType * >( dest );
    93                         if ( srcAsRef && destAsRef ) { // pointer-like conversions between references
    94                                 // std::cerr << "converting between references" << std::endl;
    95                                 if ( srcAsRef->get_base()->get_qualifiers() <= destAsRef->get_base()->get_qualifiers() && typesCompatibleIgnoreQualifiers( srcAsRef->get_base(), destAsRef->get_base(), indexer, env ) ) {
    96                                         return Cost::safe;
    97                                 } else {  // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
    98                                         int assignResult = ptrsAssignable( srcAsRef->get_base(), destAsRef->get_base(), env );
    99                                         if ( assignResult < 0 ) {
    100                                                 return Cost::safe;
    101                                         } else if ( assignResult > 0 ) {
    102                                                 return Cost::unsafe;
    103                                         } // if
    104                                 } // if
    105                         } else {
    106                                 // std::cerr << "reference to rvalue conversion" << std::endl;
    107                                 ConversionCost converter( dest, indexer, env );
    108                                 src->accept( converter );
    109                                 return converter.get_cost();
    110                         } // if
    111                 } else {
    112                         ReferenceType * destAsRef = dynamic_cast< ReferenceType * >( dest );
    113                         assert( diff == -1 && destAsRef );
    114                         if ( typesCompatibleIgnoreQualifiers( src, destAsRef->get_base(), indexer, env ) ) {
    115                                 // std::cerr << "converting compatible base type" << std::endl;
    116                                 if ( src->get_lvalue() ) {
    117                                         // std::cerr << "lvalue to reference conversion" << std::endl;
    118                                         // lvalue-to-reference conversion:  cv lvalue T => cv T &
    119                                         if ( src->get_qualifiers() == destAsRef->get_base()->get_qualifiers() ) {
    120                                                 return Cost::reference; // cost needs to be non-zero to add cast
    121                                         } if ( src->get_qualifiers() < destAsRef->get_base()->get_qualifiers() ) {
    122                                                 return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same
    123                                         } else {
    124                                                 return Cost::unsafe;
    125                                         } // if
    126                                 } else if ( destAsRef->get_base()->get_const() ) {
    127                                         // std::cerr << "rvalue to const ref conversion" << std::endl;
    128                                         // rvalue-to-const-reference conversion: T => const T &
    129                                         return Cost::safe;
    130                                 } else {
    131                                         // std::cerr << "rvalue to non-const reference conversion" << std::endl;
    132                                         // rvalue-to-reference conversion: T => T &
    133                                         return Cost::unsafe;
    134                                 } // if
    135                         } // if
    136                         // std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl;
    137                 }
    138                 return Cost::infinity;
    139         }
    140 
    141         Cost convertToReferenceCost( Type * src, ReferenceType * dest, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
    142                 int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth();
    143                 return convertToReferenceCost( src, dest, sdepth-ddepth, indexer, env );
     65                                return converter.get_cost() + Cost( 0, 0, 0 );
     66                        } // if
     67                } // if
    14468        }
    14569
     
    233157                        int tableResult = costMatrix[ basicType->get_kind() ][ destAsBasic->get_kind() ];
    234158                        if ( tableResult == -1 ) {
    235                                 cost = Cost::unsafe;
    236                         } else {
    237                                 cost = Cost::zero;
    238                                 cost.incSafe( tableResult );
     159                                cost = Cost( 1, 0, 0 );
     160                        } else {
     161                                cost = Cost( 0, 0, tableResult );
    239162                        } // if
    240163                } else if ( dynamic_cast< EnumInstType *>( dest ) ) {
    241164                        // xxx - not positive this is correct, but appears to allow casting int => enum
    242                         cost = Cost::unsafe;
     165                        cost = Cost( 1, 0, 0 );
    243166                } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) {
    244                         cost = Cost::unsafe;
     167                        cost = Cost( 1, 0, 0 );
    245168                } // if
    246169        }
     
    248171        void ConversionCost::visit(PointerType *pointerType) {
    249172                if ( PointerType *destAsPtr = dynamic_cast< PointerType* >( dest ) ) {
    250                         // std::cerr << pointerType << " ===> " << destAsPtr;
    251                         Type::Qualifiers tq1 = pointerType->get_base()->get_qualifiers();
    252                         Type::Qualifiers tq2 = destAsPtr->get_base()->get_qualifiers();
    253                         if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->get_base(), destAsPtr->get_base(), indexer, env ) ) {
    254                                 if ( tq1 == tq2 ) {
    255                                         // types are the same
    256                                         cost = Cost::zero;
    257                                 } else {
    258                                         // types are the same, except otherPointer has more qualifiers
    259                                         // std::cerr << " :: compatible and good qualifiers" << std::endl;
    260                                         cost = Cost::safe;
    261                                 }
    262                         } else {  // xxx - this discards qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
     173                        if ( pointerType->get_base()->get_qualifiers() <= destAsPtr->get_base()->get_qualifiers() && typesCompatibleIgnoreQualifiers( pointerType->get_base(), destAsPtr->get_base(), indexer, env ) ) {
     174                                cost = Cost( 0, 0, 1 );
     175                        } else {
    263176                                int assignResult = ptrsAssignable( pointerType->get_base(), destAsPtr->get_base(), env );
    264                                 // std::cerr << " :: " << assignResult << std::endl;
    265                                 if ( assignResult < 0 && pointerType->get_base()->get_qualifiers() <= destAsPtr->get_qualifiers() ) {
    266                                         cost = Cost::safe;
     177                                if ( assignResult < 0 ) {
     178                                        cost = Cost( 0, 0, 1 );
    267179                                } else if ( assignResult > 0 ) {
    268                                         cost = Cost::unsafe;
     180                                        cost = Cost( 1, 0, 0 );
    269181                                } // if
    270                                 // assignResult == 0 means Cost::Infinity
    271182                        } // if
    272183                } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) {
    273                         cost = Cost::unsafe;
     184                        cost = Cost( 1, 0, 0 );
    274185                } // if
    275186        }
    276187
    277188        void ConversionCost::visit(__attribute((unused)) ArrayType *arrayType) {}
    278 
    279         void ConversionCost::visit(ReferenceType *refType) {
    280                 // Note: dest can never be a reference, since it would have been caught in an earlier check
    281                 assert( ! dynamic_cast< ReferenceType * >( dest ) );
    282                 // convert reference to rvalue: cv T1 & => T2
    283                 // recursively compute conversion cost from T1 to T2.
    284                 // cv can be safely dropped because of 'implicit dereference' behavior.
    285                 refType->get_base()->accept( *this );
    286                 if ( refType->get_base()->get_qualifiers() == dest->get_qualifiers() ) {
    287                         cost.incReference();  // prefer exact qualifiers
    288                 } else if ( refType->get_base()->get_qualifiers() < dest->get_qualifiers() ) {
    289                         cost.incSafe(); // then gaining qualifiers
    290                 } else {
    291                         cost.incUnsafe(); // lose qualifiers as last resort
    292                 }
    293                 // std::cerr << refType << " ==> " << dest << " " << cost << std::endl;
    294         }
    295 
    296189        void ConversionCost::visit(__attribute((unused)) FunctionType *functionType) {}
    297190
     
    315208                static Type::Qualifiers q;
    316209                static BasicType integer( q, BasicType::SignedInt );
    317                 integer.accept( *this );  // safe if dest >= int
    318                 if ( cost < Cost::unsafe ) {
     210                integer.accept( *this );
     211                if ( cost < Cost( 1, 0, 0 ) ) {
    319212                        cost.incSafe();
    320213                } // if
     
    338231                        assert( type );
    339232                        if ( type->get_base() ) {
    340                                 cost = conversionCost( type->get_base(), dest, indexer, env ) + Cost::safe;
     233                                cost = conversionCost( type->get_base(), dest, indexer, env ) + Cost( 0, 0, 1 );
    341234                        } // if
    342235                } // if
     
    344237
    345238        void ConversionCost::visit( __attribute((unused)) TupleType *tupleType) {
    346                 Cost c = Cost::zero;
     239                Cost c;
    347240                if ( TupleType *destAsTuple = dynamic_cast< TupleType* >( dest ) ) {
    348241                        std::list< Type* >::const_iterator srcIt = tupleType->get_types().begin();
     
    376269                        int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
    377270                        if ( tableResult == -1 ) {
    378                                 cost = Cost::unsafe;
    379                         } else {
    380                                 cost = Cost::zero;
    381                                 cost.incSafe( tableResult + 1 );
     271                                cost = Cost( 1, 0, 0 );
     272                        } else {
     273                                cost = Cost( 0, 0, tableResult + 1 );
    382274                        }
    383275                } else if ( dynamic_cast< PointerType* >( dest ) ) {
    384                         cost = Cost::safe;
     276                        cost = Cost( 0, 0, 1 );
    385277                }
    386278        }
     
    393285                        int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
    394286                        if ( tableResult == -1 ) {
    395                                 cost = Cost::unsafe;
    396                         } else {
    397                                 cost = Cost::zero;
    398                                 cost.incSafe( tableResult + 1 );
     287                                cost = Cost( 1, 0, 0 );
     288                        } else {
     289                                cost = Cost( 0, 0, tableResult + 1 );
    399290                        }
    400291                }
Note: See TracChangeset for help on using the changeset viewer.