- File:
-
- 1 edited
-
src/ResolvExpr/ConversionCost.cc (modified) (11 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/ConversionCost.cc
r74b007ba r7e003011 21 21 22 22 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 23 const Cost Cost::zero = Cost( 0, 0, 0 ); 24 const Cost Cost::infinity = Cost( -1, -1, -1 ); 30 25 31 26 Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) { … … 46 41 assert( type ); 47 42 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 ); 49 44 } // if 50 45 } // if … … 59 54 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) { 60 55 /// std::cout << "compatible!" << std::endl; 61 return Cost ::zero;56 return Cost( 0, 0, 0 ); 62 57 } 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 ); 67 59 } else { 68 60 ConversionCost converter( dest, indexer, env ); … … 71 63 return Cost::infinity; 72 64 } 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 144 68 } 145 69 … … 233 157 int tableResult = costMatrix[ basicType->get_kind() ][ destAsBasic->get_kind() ]; 234 158 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 ); 239 162 } // if 240 163 } else if ( dynamic_cast< EnumInstType *>( dest ) ) { 241 164 // xxx - not positive this is correct, but appears to allow casting int => enum 242 cost = Cost ::unsafe;165 cost = Cost( 1, 0, 0 ); 243 166 } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) { 244 cost = Cost ::unsafe;167 cost = Cost( 1, 0, 0 ); 245 168 } // if 246 169 } … … 248 171 void ConversionCost::visit(PointerType *pointerType) { 249 172 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 { 263 176 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 ); 267 179 } else if ( assignResult > 0 ) { 268 cost = Cost ::unsafe;180 cost = Cost( 1, 0, 0 ); 269 181 } // if 270 // assignResult == 0 means Cost::Infinity271 182 } // if 272 183 } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) { 273 cost = Cost ::unsafe;184 cost = Cost( 1, 0, 0 ); 274 185 } // if 275 186 } 276 187 277 188 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 check281 assert( ! dynamic_cast< ReferenceType * >( dest ) );282 // convert reference to rvalue: cv T1 & => T2283 // 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 qualifiers288 } else if ( refType->get_base()->get_qualifiers() < dest->get_qualifiers() ) {289 cost.incSafe(); // then gaining qualifiers290 } else {291 cost.incUnsafe(); // lose qualifiers as last resort292 }293 // std::cerr << refType << " ==> " << dest << " " << cost << std::endl;294 }295 296 189 void ConversionCost::visit(__attribute((unused)) FunctionType *functionType) {} 297 190 … … 315 208 static Type::Qualifiers q; 316 209 static BasicType integer( q, BasicType::SignedInt ); 317 integer.accept( *this ); // safe if dest >= int318 if ( cost < Cost ::unsafe) {210 integer.accept( *this ); 211 if ( cost < Cost( 1, 0, 0 ) ) { 319 212 cost.incSafe(); 320 213 } // if … … 338 231 assert( type ); 339 232 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 ); 341 234 } // if 342 235 } // if … … 344 237 345 238 void ConversionCost::visit( __attribute((unused)) TupleType *tupleType) { 346 Cost c = Cost::zero;239 Cost c; 347 240 if ( TupleType *destAsTuple = dynamic_cast< TupleType* >( dest ) ) { 348 241 std::list< Type* >::const_iterator srcIt = tupleType->get_types().begin(); … … 376 269 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ]; 377 270 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 ); 382 274 } 383 275 } else if ( dynamic_cast< PointerType* >( dest ) ) { 384 cost = Cost ::safe;276 cost = Cost( 0, 0, 1 ); 385 277 } 386 278 } … … 393 285 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ]; 394 286 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 ); 399 290 } 400 291 }
Note:
See TracChangeset
for help on using the changeset viewer.