Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/ConversionCost.cc

    r7e003011 rcb43451  
    2121
    2222namespace ResolvExpr {
    23         const Cost Cost::zero = Cost( 0, 0, 0 );
    24         const Cost Cost::infinity = Cost( -1, -1, -1 );
     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
    2530
    2631        Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
     
    4146                                assert( type );
    4247                                if ( type->get_base() ) {
    43                                         return conversionCost( src, type->get_base(), indexer, env ) + Cost( 0, 0, 1 );
     48                                        return conversionCost( src, type->get_base(), indexer, env ) + Cost::safe;
    4449                                } // if
    4550                        } // if
     
    5459                if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {
    5560///     std::cout << "compatible!" << std::endl;
    56                         return Cost( 0, 0, 0 );
     61                        return Cost::zero;
    5762                } else if ( dynamic_cast< VoidType* >( dest ) ) {
    58                         return Cost( 0, 0, 1 );
     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 );
    5967                } else {
    6068                        ConversionCost converter( dest, indexer, env );
     
    6371                                return Cost::infinity;
    6472                        } else {
    65                                 return converter.get_cost() + Cost( 0, 0, 0 );
    66                         } // if
    67                 } // if
     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 );
    68144        }
    69145
     
    157233                        int tableResult = costMatrix[ basicType->get_kind() ][ destAsBasic->get_kind() ];
    158234                        if ( tableResult == -1 ) {
    159                                 cost = Cost( 1, 0, 0 );
    160                         } else {
    161                                 cost = Cost( 0, 0, tableResult );
     235                                cost = Cost::unsafe;
     236                        } else {
     237                                cost = Cost::zero;
     238                                cost.incSafe( tableResult );
    162239                        } // if
    163240                } else if ( dynamic_cast< EnumInstType *>( dest ) ) {
    164241                        // xxx - not positive this is correct, but appears to allow casting int => enum
    165                         cost = Cost( 1, 0, 0 );
     242                        cost = Cost::unsafe;
    166243                } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) {
    167                         cost = Cost( 1, 0, 0 );
     244                        cost = Cost::unsafe;
    168245                } // if
    169246        }
     
    171248        void ConversionCost::visit(PointerType *pointerType) {
    172249                if ( PointerType *destAsPtr = dynamic_cast< PointerType* >( dest ) ) {
    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 {
     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?
    176263                                int assignResult = ptrsAssignable( pointerType->get_base(), destAsPtr->get_base(), env );
    177                                 if ( assignResult < 0 ) {
    178                                         cost = Cost( 0, 0, 1 );
     264                                // std::cerr << " :: " << assignResult << std::endl;
     265                                if ( assignResult < 0 && pointerType->get_base()->get_qualifiers() <= destAsPtr->get_qualifiers() ) {
     266                                        cost = Cost::safe;
    179267                                } else if ( assignResult > 0 ) {
    180                                         cost = Cost( 1, 0, 0 );
     268                                        cost = Cost::unsafe;
    181269                                } // if
     270                                // assignResult == 0 means Cost::Infinity
    182271                        } // if
    183272                } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) {
    184                         cost = Cost( 1, 0, 0 );
     273                        cost = Cost::unsafe;
    185274                } // if
    186275        }
    187276
    188277        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
    189296        void ConversionCost::visit(__attribute((unused)) FunctionType *functionType) {}
    190297
     
    208315                static Type::Qualifiers q;
    209316                static BasicType integer( q, BasicType::SignedInt );
    210                 integer.accept( *this );
    211                 if ( cost < Cost( 1, 0, 0 ) ) {
     317                integer.accept( *this );  // safe if dest >= int
     318                if ( cost < Cost::unsafe ) {
    212319                        cost.incSafe();
    213320                } // if
     
    231338                        assert( type );
    232339                        if ( type->get_base() ) {
    233                                 cost = conversionCost( type->get_base(), dest, indexer, env ) + Cost( 0, 0, 1 );
     340                                cost = conversionCost( type->get_base(), dest, indexer, env ) + Cost::safe;
    234341                        } // if
    235342                } // if
     
    237344
    238345        void ConversionCost::visit( __attribute((unused)) TupleType *tupleType) {
    239                 Cost c;
     346                Cost c = Cost::zero;
    240347                if ( TupleType *destAsTuple = dynamic_cast< TupleType* >( dest ) ) {
    241348                        std::list< Type* >::const_iterator srcIt = tupleType->get_types().begin();
     
    269376                        int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
    270377                        if ( tableResult == -1 ) {
    271                                 cost = Cost( 1, 0, 0 );
    272                         } else {
    273                                 cost = Cost( 0, 0, tableResult + 1 );
     378                                cost = Cost::unsafe;
     379                        } else {
     380                                cost = Cost::zero;
     381                                cost.incSafe( tableResult + 1 );
    274382                        }
    275383                } else if ( dynamic_cast< PointerType* >( dest ) ) {
    276                         cost = Cost( 0, 0, 1 );
     384                        cost = Cost::safe;
    277385                }
    278386        }
     
    285393                        int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
    286394                        if ( tableResult == -1 ) {
    287                                 cost = Cost( 1, 0, 0 );
    288                         } else {
    289                                 cost = Cost( 0, 0, tableResult + 1 );
     395                                cost = Cost::unsafe;
     396                        } else {
     397                                cost = Cost::zero;
     398                                cost.incSafe( tableResult + 1 );
    290399                        }
    291400                }
Note: See TracChangeset for help on using the changeset viewer.