- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/ResolveAssertions.cc
rb408364 r462a7c7 186 186 using InferCache = std::unordered_map< UniqueId, InferredParams >; 187 187 188 /// Lexicographically-ordered vector of costs189 using CostVec = std::vector< Cost >;190 191 int compare( const CostVec & a, const CostVec & b ) {192 unsigned i = 0;193 do {194 // lex-compare where shorter one is less195 if ( i == a.size() ) {196 return i == b.size() ? 0 : -1;197 }198 if ( i == b.size() /* && i < a.size() */ ) return 1;199 200 int c = a[i].compare( b[i] );201 if ( c != 0 ) return c;202 } while ( ++i );203 assert(!"unreachable");204 }205 206 bool operator< ( const CostVec & a, const CostVec & b ) { return compare( a, b ) < 0; }207 208 188 /// Flag for state iteration 209 189 enum IterateFlag { IterateState }; … … 216 196 DeferList deferred; ///< Deferred matches 217 197 InferCache inferred; ///< Cache of already-inferred parameters 218 CostVec costs; ///< Costs of recursive assertion satisfaction for disambiguation219 198 SymTab::Indexer& indexer; ///< Name lookup (depends on previous assertions) 220 199 221 200 /// Initial resolution state for an alternative 222 201 ResnState( Alternative& a, SymTab::Indexer& indexer ) 223 : alt(a), need(), newNeed(), deferred(), inferred(), costs{ Cost::zero },indexer(indexer) {202 : alt(a), need(), newNeed(), deferred(), inferred(), indexer(indexer) { 224 203 need.swap( a.need ); 225 204 } … … 228 207 ResnState( ResnState&& o, IterateFlag ) 229 208 : alt(std::move(o.alt)), need(o.newNeed.begin(), o.newNeed.end()), newNeed(), deferred(), 230 inferred(std::move(o.inferred)), costs(o.costs), indexer(o.indexer) { 231 costs.emplace_back( Cost::zero ); 232 } 209 inferred(std::move(o.inferred)), indexer(o.indexer) {} 233 210 }; 234 211 … … 359 336 }; 360 337 361 /// Map of alternative return types to recursive assertion satisfaction costs 362 using PruneMap = std::unordered_map<std::string, CostVec>; 363 364 /// Gets the pruning key for an alternative 365 std::string pruneKey( const Alternative & alt ) { 366 Type* resType = alt.expr->result->clone(); 367 alt.env.apply( resType ); 368 std::string resKey = SymTab::Mangler::mangleType( resType ); 369 delete resType; 370 return std::move( resKey ); 371 } 372 373 /// Replace resnSlots with inferParams and add alternative to output list, if meets pruning 374 /// threshold. 375 void finalizeAssertions( ResnState& resn, PruneMap & pruneThresholds, AltList& out ) { 376 // prune if cheaper alternative for same key has already been generated 377 std::string resKey = pruneKey( resn.alt ); 378 auto it = pruneThresholds.find( resKey ); 379 if ( it != pruneThresholds.end() ) { 380 if ( it->second < resn.costs ) return; 381 } else { 382 pruneThresholds.emplace_hint( it, resKey, resn.costs ); 383 } 384 385 // replace resolution slots with inferred params, add to output 386 PassVisitor<InferMatcher> matcher{ resn.inferred }; 387 resn.alt.expr = resn.alt.expr->acceptMutator( matcher ); 388 out.emplace_back( resn.alt ); 338 void finalizeAssertions( Alternative& alt, InferCache& inferred, AltList& out ) { 339 PassVisitor<InferMatcher> matcher{ inferred }; 340 alt.expr = alt.expr->acceptMutator( matcher ); 341 out.emplace_back( alt ); 389 342 } 390 343 … … 406 359 ResnList resns{ ResnState{ alt, root_indexer } }; 407 360 ResnList new_resns{}; 408 409 // Pruning thresholds by result type of the output alternatives.410 // Alternatives *should* be generated in sorted order, so no need to retroactively prune411 PruneMap thresholds;412 361 413 362 // resolve assertions in breadth-first-order up to a limited number of levels deep … … 415 364 // scan over all mutually-compatible resolutions 416 365 for ( auto& resn : resns ) { 417 // stop this branch if already found a better option418 auto it = thresholds.find( pruneKey( resn.alt ) );419 if ( it != thresholds.end() && it->second < resn.costs ) goto nextResn;420 421 366 // make initial pass at matching assertions 422 367 for ( auto& assn : resn.need ) { … … 438 383 // either add successful match or push back next state 439 384 if ( resn.newNeed.empty() ) { 440 finalizeAssertions( resn , thresholds, out );385 finalizeAssertions( resn.alt, resn.inferred, out ); 441 386 } else { 442 387 new_resns.emplace_back( std::move(resn), IterateState ); … … 475 420 goto nextResn; 476 421 } 477 // sort by cost for overall pruning422 // sort by cost 478 423 CandidateCost coster{ resn.indexer }; 479 424 std::sort( compatible.begin(), compatible.end(), coster ); 480 425 426 // keep map of detected options 427 std::unordered_map<std::string, Cost> found; 481 428 for ( auto& compat : compatible ) { 429 // filter by environment-adjusted result type, keep only cheapest option 430 Type* resType = alt.expr->result->clone(); 431 compat.env.apply( resType ); 432 // skip if cheaper alternative already processed with same result type 433 Cost resCost = coster.get( compat ); 434 auto it = found.emplace( SymTab::Mangler::mangleType( resType ), resCost ); 435 delete resType; 436 if ( it.second == false && it.first->second < resCost ) continue; 437 438 // proceed with resolution step 482 439 ResnState new_resn = resn; 483 440 … … 495 452 new_resn.alt.openVars = std::move(compat.openVars); 496 453 497 // mark cost of this path498 new_resn.costs.back() += compat.cost;499 500 454 // either add sucessful match or push back next state 501 455 if ( new_resn.newNeed.empty() ) { 502 finalizeAssertions( new_resn , thresholds, out );456 finalizeAssertions( new_resn.alt, new_resn.inferred, out ); 503 457 } else { 504 458 new_resns.emplace_back( std::move(new_resn), IterateState );
Note: See TracChangeset
for help on using the changeset viewer.