Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/ConversionCost.cc

    r5ccb10d rea6332d  
    1515
    1616#include "ConversionCost.h"
    17 #include "typeops.h"
    18 #include "SynTree/Type.h"
    19 #include "SynTree/Visitor.h"
    20 #include "SymTab/Indexer.h"
     17
     18#include <cassert>                       // for assert
     19#include <list>                          // for list, list<>::const_iterator
     20#include <string>                        // for operator==, string
     21
     22#include "ResolvExpr/Cost.h"             // for Cost
     23#include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
     24#include "SymTab/Indexer.h"              // for Indexer
     25#include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl
     26#include "SynTree/Type.h"                // for Type, BasicType, TypeInstType
     27#include "typeops.h"                     // for typesCompatibleIgnoreQualifiers
    2128
    2229namespace 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 
    30 #if 0
    31 #define PRINT(x) x
    32 #else
    33 #define PRINT(x)
    34 #endif
     30        const Cost Cost::zero = Cost( 0, 0, 0 );
     31        const Cost Cost::infinity = Cost( -1, -1, -1 );
    3532
    3633        Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
     
    3835                        EqvClass eqvClass;
    3936                        NamedTypeDecl *namedType;
    40                         PRINT( std::cerr << "type inst " << destAsTypeInst->get_name(); )
     37///     std::cout << "type inst " << destAsTypeInst->get_name();
    4138                        if ( env.lookup( destAsTypeInst->get_name(), eqvClass ) ) {
    4239                                if ( eqvClass.type ) {
     
    4643                                }
    4744                        } else if ( ( namedType = indexer.lookupType( destAsTypeInst->get_name() ) ) ) {
    48                                 PRINT( std::cerr << " found" << std::endl; )
     45///       std::cout << " found" << std::endl;
    4946                                TypeDecl *type = dynamic_cast< TypeDecl* >( namedType );
    5047                                // all typedefs should be gone by this point
    5148                                assert( type );
    5249                                if ( type->get_base() ) {
    53                                         return conversionCost( src, type->get_base(), indexer, env ) + Cost::safe;
     50                                        return conversionCost( src, type->get_base(), indexer, env ) + Cost( 0, 0, 1 );
    5451                                } // if
    5552                        } // if
    56                         PRINT( std::cerr << " not found" << std::endl; )
    57                 } // if
    58                 PRINT(
    59                         std::cerr << "src is ";
    60                         src->print( std::cerr );
    61                         std::cerr << std::endl << "dest is ";
    62                         dest->print( std::cerr );
    63                         std::cerr << std::endl << "env is" << std::endl;
    64                         env.print( std::cerr, 8 );
    65                 )
     53///     std::cout << " not found" << std::endl;
     54                } // if
     55///   std::cout << "src is ";
     56///   src->print( std::cout );
     57///   std::cout << std::endl << "dest is ";
     58///   dest->print( std::cout );
     59///   std::cout << std::endl << "env is" << std::endl;
     60///   env.print( std::cout, 8 );
    6661                if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {
    67                         PRINT( std::cerr << "compatible!" << std::endl; )
    68                         return Cost::zero;
     62///     std::cout << "compatible!" << std::endl;
     63                        return Cost( 0, 0, 0 );
    6964                } else if ( dynamic_cast< VoidType* >( dest ) ) {
    70                         return Cost::safe;
    71                 } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * > ( dest ) ) {
    72                         PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
    73                         return convertToReferenceCost( src, refType, indexer, env );
     65                        return Cost( 0, 0, 1 );
    7466                } else {
    7567                        ConversionCost converter( dest, indexer, env );
     
    7870                                return Cost::infinity;
    7971                        } else {
    80                                 return converter.get_cost() + Cost::zero;
    81                         } // if
    82                 } // if
    83         }
    84 
    85         Cost convertToReferenceCost( Type * src, Type * dest, int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
    86                 PRINT( std::cerr << "convert to reference cost..." << std::endl; )
    87                 if ( diff > 0 ) {
    88                         // TODO: document this
    89                         Cost cost = convertToReferenceCost( safe_dynamic_cast< ReferenceType * >( src )->get_base(), dest, diff-1, indexer, env );
    90                         cost.incReference();
    91                         return cost;
    92                 } else if ( diff < -1 ) {
    93                         // TODO: document this
    94                         Cost cost = convertToReferenceCost( src, safe_dynamic_cast< ReferenceType * >( dest )->get_base(), diff+1, indexer, env );
    95                         cost.incReference();
    96                         return cost;
    97                 } else if ( diff == 0 ) {
    98                         ReferenceType * srcAsRef = dynamic_cast< ReferenceType * >( src );
    99                         ReferenceType * destAsRef = dynamic_cast< ReferenceType * >( dest );
    100                         if ( srcAsRef && destAsRef ) { // pointer-like conversions between references
    101                                 PRINT( std::cerr << "converting between references" << std::endl; )
    102                                 if ( srcAsRef->get_base()->get_qualifiers() <= destAsRef->get_base()->get_qualifiers() && typesCompatibleIgnoreQualifiers( srcAsRef->get_base(), destAsRef->get_base(), indexer, env ) ) {
    103                                         return Cost::safe;
    104                                 } else {  // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
    105                                         int assignResult = ptrsAssignable( srcAsRef->get_base(), destAsRef->get_base(), env );
    106                                         PRINT( std::cerr << "comparing references: " << assignResult << " " << srcAsRef << " " << destAsRef << std::endl; )
    107                                         if ( assignResult < 0 ) {
    108                                                 return Cost::safe;
    109                                         } else if ( assignResult > 0 ) {
    110                                                 return Cost::unsafe;
    111                                         } // if
    112                                 } // if
    113                         } else {
    114                                 PRINT( std::cerr << "reference to rvalue conversion" << std::endl; )
    115                                 ConversionCost converter( dest, indexer, env );
    116                                 src->accept( converter );
    117                                 return converter.get_cost();
    118                         } // if
    119                 } else {
    120                         ReferenceType * destAsRef = dynamic_cast< ReferenceType * >( dest );
    121                         assert( diff == -1 && destAsRef );
    122                         if ( typesCompatibleIgnoreQualifiers( src, destAsRef->get_base(), indexer, env ) ) {
    123                                 PRINT( std::cerr << "converting compatible base type" << std::endl; )
    124                                 if ( src->get_lvalue() ) {
    125                                         PRINT(
    126                                                 std::cerr << "lvalue to reference conversion" << std::endl;
    127                                                 std::cerr << src << " => " << destAsRef << std::endl;
    128                                         )
    129                                         // lvalue-to-reference conversion:  cv lvalue T => cv T &
    130                                         if ( src->get_qualifiers() == destAsRef->get_base()->get_qualifiers() ) {
    131                                                 return Cost::reference; // cost needs to be non-zero to add cast
    132                                         } if ( src->get_qualifiers() < destAsRef->get_base()->get_qualifiers() ) {
    133                                                 return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same
    134                                         } else {
    135                                                 return Cost::unsafe;
    136                                         } // if
    137                                 } else if ( destAsRef->get_base()->get_const() ) {
    138                                         PRINT( std::cerr << "rvalue to const ref conversion" << std::endl; )
    139                                         // rvalue-to-const-reference conversion: T => const T &
    140                                         return Cost::safe;
    141                                 } else {
    142                                         PRINT( std::cerr << "rvalue to non-const reference conversion" << std::endl; )
    143                                         // rvalue-to-reference conversion: T => T &
    144                                         return Cost::unsafe;
    145                                 } // if
    146                         } // if
    147                         PRINT( std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl; )
    148                 }
    149                 return Cost::infinity;
    150         }
    151 
    152         Cost convertToReferenceCost( Type * src, ReferenceType * dest, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
    153                 int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth();
    154                 return convertToReferenceCost( src, dest, sdepth-ddepth, indexer, env );
     72                                return converter.get_cost() + Cost( 0, 0, 0 );
     73                        } // if
     74                } // if
    15575        }
    15676
     
    244164                        int tableResult = costMatrix[ basicType->get_kind() ][ destAsBasic->get_kind() ];
    245165                        if ( tableResult == -1 ) {
    246                                 cost = Cost::unsafe;
    247                         } else {
    248                                 cost = Cost::zero;
    249                                 cost.incSafe( tableResult );
     166                                cost = Cost( 1, 0, 0 );
     167                        } else {
     168                                cost = Cost( 0, 0, tableResult );
    250169                        } // if
    251170                } else if ( dynamic_cast< EnumInstType *>( dest ) ) {
    252171                        // xxx - not positive this is correct, but appears to allow casting int => enum
    253                         cost = Cost::unsafe;
     172                        cost = Cost( 1, 0, 0 );
    254173                } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) {
    255                         cost = Cost::unsafe;
     174                        cost = Cost( 1, 0, 0 );
    256175                } // if
    257176        }
     
    259178        void ConversionCost::visit(PointerType *pointerType) {
    260179                if ( PointerType *destAsPtr = dynamic_cast< PointerType* >( dest ) ) {
    261                         PRINT( std::cerr << pointerType << " ===> " << destAsPtr; )
    262                         Type::Qualifiers tq1 = pointerType->get_base()->get_qualifiers();
    263                         Type::Qualifiers tq2 = destAsPtr->get_base()->get_qualifiers();
    264                         if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->get_base(), destAsPtr->get_base(), indexer, env ) ) {
    265                                 if ( tq1 == tq2 ) {
    266                                         // types are the same
    267                                         cost = Cost::zero;
    268                                 } else {
    269                                         // types are the same, except otherPointer has more qualifiers
    270                                         PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
    271                                         cost = Cost::safe;
    272                                 }
    273                         } else {  // xxx - this discards qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
     180                        if ( pointerType->get_base()->get_qualifiers() <= destAsPtr->get_base()->get_qualifiers() && typesCompatibleIgnoreQualifiers( pointerType->get_base(), destAsPtr->get_base(), indexer, env ) ) {
     181                                cost = Cost( 0, 0, 1 );
     182                        } else {
    274183                                int assignResult = ptrsAssignable( pointerType->get_base(), destAsPtr->get_base(), env );
    275                                 PRINT( std::cerr << " :: " << assignResult << std::endl; )
    276                                 if ( assignResult < 0 && pointerType->get_base()->get_qualifiers() <= destAsPtr->get_qualifiers() ) {
    277                                         cost = Cost::safe;
     184                                if ( assignResult < 0 ) {
     185                                        cost = Cost( 0, 0, 1 );
    278186                                } else if ( assignResult > 0 ) {
    279                                         cost = Cost::unsafe;
     187                                        cost = Cost( 1, 0, 0 );
    280188                                } // if
    281                                 // assignResult == 0 means Cost::Infinity
    282189                        } // if
    283190                } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) {
    284                         cost = Cost::unsafe;
     191                        cost = Cost( 1, 0, 0 );
    285192                } // if
    286193        }
    287194
    288195        void ConversionCost::visit(__attribute((unused)) ArrayType *arrayType) {}
    289 
    290         void ConversionCost::visit(ReferenceType *refType) {
    291                 // Note: dest can never be a reference, since it would have been caught in an earlier check
    292                 assert( ! dynamic_cast< ReferenceType * >( dest ) );
    293                 // convert reference to rvalue: cv T1 & => T2
    294                 // recursively compute conversion cost from T1 to T2.
    295                 // cv can be safely dropped because of 'implicit dereference' behavior.
    296                 refType->get_base()->accept( *this );
    297                 if ( refType->get_base()->get_qualifiers() == dest->get_qualifiers() ) {
    298                         cost.incReference();  // prefer exact qualifiers
    299                 } else if ( refType->get_base()->get_qualifiers() < dest->get_qualifiers() ) {
    300                         cost.incSafe(); // then gaining qualifiers
    301                 } else {
    302                         cost.incUnsafe(); // lose qualifiers as last resort
    303                 }
    304                 PRINT( std::cerr << refType << " ==> " << dest << " " << cost << std::endl; )
    305         }
    306 
    307196        void ConversionCost::visit(__attribute((unused)) FunctionType *functionType) {}
    308197
     
    326215                static Type::Qualifiers q;
    327216                static BasicType integer( q, BasicType::SignedInt );
    328                 integer.accept( *this );  // safe if dest >= int
    329                 if ( cost < Cost::unsafe ) {
     217                integer.accept( *this );
     218                if ( cost < Cost( 1, 0, 0 ) ) {
    330219                        cost.incSafe();
    331220                } // if
     
    349238                        assert( type );
    350239                        if ( type->get_base() ) {
    351                                 cost = conversionCost( type->get_base(), dest, indexer, env ) + Cost::safe;
     240                                cost = conversionCost( type->get_base(), dest, indexer, env ) + Cost( 0, 0, 1 );
    352241                        } // if
    353242                } // if
     
    355244
    356245        void ConversionCost::visit( __attribute((unused)) TupleType *tupleType) {
    357                 Cost c = Cost::zero;
     246                Cost c;
    358247                if ( TupleType *destAsTuple = dynamic_cast< TupleType* >( dest ) ) {
    359248                        std::list< Type* >::const_iterator srcIt = tupleType->get_types().begin();
     
    387276                        int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
    388277                        if ( tableResult == -1 ) {
    389                                 cost = Cost::unsafe;
    390                         } else {
    391                                 cost = Cost::zero;
    392                                 cost.incSafe( tableResult + 1 );
     278                                cost = Cost( 1, 0, 0 );
     279                        } else {
     280                                cost = Cost( 0, 0, tableResult + 1 );
    393281                        }
    394282                } else if ( dynamic_cast< PointerType* >( dest ) ) {
    395                         cost = Cost::safe;
     283                        cost = Cost( 0, 0, 1 );
    396284                }
    397285        }
     
    404292                        int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
    405293                        if ( tableResult == -1 ) {
    406                                 cost = Cost::unsafe;
    407                         } else {
    408                                 cost = Cost::zero;
    409                                 cost.incSafe( tableResult + 1 );
     294                                cost = Cost( 1, 0, 0 );
     295                        } else {
     296                                cost = Cost( 0, 0, tableResult + 1 );
    410297                        }
    411298                }
Note: See TracChangeset for help on using the changeset viewer.