- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/ConversionCost.cc
r5ccb10d rea6332d 15 15 16 16 #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 21 28 22 29 namespace 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 ); 35 32 36 33 Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) { … … 38 35 EqvClass eqvClass; 39 36 NamedTypeDecl *namedType; 40 PRINT( std::cerr << "type inst " << destAsTypeInst->get_name(); ) 37 /// std::cout << "type inst " << destAsTypeInst->get_name(); 41 38 if ( env.lookup( destAsTypeInst->get_name(), eqvClass ) ) { 42 39 if ( eqvClass.type ) { … … 46 43 } 47 44 } else if ( ( namedType = indexer.lookupType( destAsTypeInst->get_name() ) ) ) { 48 PRINT( std::cerr << " found" << std::endl; ) 45 /// std::cout << " found" << std::endl; 49 46 TypeDecl *type = dynamic_cast< TypeDecl* >( namedType ); 50 47 // all typedefs should be gone by this point 51 48 assert( type ); 52 49 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 ); 54 51 } // if 55 52 } // 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 ); 66 61 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 ); 69 64 } 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 ); 74 66 } else { 75 67 ConversionCost converter( dest, indexer, env ); … … 78 70 return Cost::infinity; 79 71 } 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 155 75 } 156 76 … … 244 164 int tableResult = costMatrix[ basicType->get_kind() ][ destAsBasic->get_kind() ]; 245 165 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 ); 250 169 } // if 251 170 } else if ( dynamic_cast< EnumInstType *>( dest ) ) { 252 171 // xxx - not positive this is correct, but appears to allow casting int => enum 253 cost = Cost ::unsafe;172 cost = Cost( 1, 0, 0 ); 254 173 } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) { 255 cost = Cost ::unsafe;174 cost = Cost( 1, 0, 0 ); 256 175 } // if 257 176 } … … 259 178 void ConversionCost::visit(PointerType *pointerType) { 260 179 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 { 274 183 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 ); 278 186 } else if ( assignResult > 0 ) { 279 cost = Cost ::unsafe;187 cost = Cost( 1, 0, 0 ); 280 188 } // if 281 // assignResult == 0 means Cost::Infinity282 189 } // if 283 190 } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) { 284 cost = Cost ::unsafe;191 cost = Cost( 1, 0, 0 ); 285 192 } // if 286 193 } 287 194 288 195 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 check292 assert( ! dynamic_cast< ReferenceType * >( dest ) );293 // convert reference to rvalue: cv T1 & => T2294 // 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 qualifiers299 } else if ( refType->get_base()->get_qualifiers() < dest->get_qualifiers() ) {300 cost.incSafe(); // then gaining qualifiers301 } else {302 cost.incUnsafe(); // lose qualifiers as last resort303 }304 PRINT( std::cerr << refType << " ==> " << dest << " " << cost << std::endl; )305 }306 307 196 void ConversionCost::visit(__attribute((unused)) FunctionType *functionType) {} 308 197 … … 326 215 static Type::Qualifiers q; 327 216 static BasicType integer( q, BasicType::SignedInt ); 328 integer.accept( *this ); // safe if dest >= int329 if ( cost < Cost ::unsafe) {217 integer.accept( *this ); 218 if ( cost < Cost( 1, 0, 0 ) ) { 330 219 cost.incSafe(); 331 220 } // if … … 349 238 assert( type ); 350 239 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 ); 352 241 } // if 353 242 } // if … … 355 244 356 245 void ConversionCost::visit( __attribute((unused)) TupleType *tupleType) { 357 Cost c = Cost::zero;246 Cost c; 358 247 if ( TupleType *destAsTuple = dynamic_cast< TupleType* >( dest ) ) { 359 248 std::list< Type* >::const_iterator srcIt = tupleType->get_types().begin(); … … 387 276 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ]; 388 277 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 ); 393 281 } 394 282 } else if ( dynamic_cast< PointerType* >( dest ) ) { 395 cost = Cost ::safe;283 cost = Cost( 0, 0, 1 ); 396 284 } 397 285 } … … 404 292 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ]; 405 293 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 ); 410 297 } 411 298 }
Note:
See TracChangeset
for help on using the changeset viewer.