Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/ResolveAssertions.cc

    rb408364 r462a7c7  
    186186        using InferCache = std::unordered_map< UniqueId, InferredParams >;
    187187
    188         /// Lexicographically-ordered vector of costs
    189         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 less
    195                         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 
    208188        /// Flag for state iteration
    209189        enum IterateFlag { IterateState };
     
    216196                DeferList deferred;        ///< Deferred matches
    217197                InferCache inferred;       ///< Cache of already-inferred parameters
    218                 CostVec costs;             ///< Costs of recursive assertion satisfaction for disambiguation
    219198                SymTab::Indexer& indexer;  ///< Name lookup (depends on previous assertions)
    220199
    221200                /// Initial resolution state for an alternative
    222201                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) {
    224203                        need.swap( a.need );
    225204                }
     
    228207                ResnState( ResnState&& o, IterateFlag )
    229208                : 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) {}
    233210        };
    234211
     
    359336        };
    360337
    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 );
    389342        }
    390343
     
    406359                ResnList resns{ ResnState{ alt, root_indexer } };
    407360                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 prune
    411                 PruneMap thresholds;
    412361
    413362                // resolve assertions in breadth-first-order up to a limited number of levels deep
     
    415364                        // scan over all mutually-compatible resolutions
    416365                        for ( auto& resn : resns ) {
    417                                 // stop this branch if already found a better option
    418                                 auto it = thresholds.find( pruneKey( resn.alt ) );
    419                                 if ( it != thresholds.end() && it->second < resn.costs ) goto nextResn;
    420 
    421366                                // make initial pass at matching assertions
    422367                                for ( auto& assn : resn.need ) {
     
    438383                                        // either add successful match or push back next state
    439384                                        if ( resn.newNeed.empty() ) {
    440                                                 finalizeAssertions( resn, thresholds, out );
     385                                                finalizeAssertions( resn.alt, resn.inferred, out );
    441386                                        } else {
    442387                                                new_resns.emplace_back( std::move(resn), IterateState );
     
    475420                                                goto nextResn;
    476421                                        }
    477                                         // sort by cost for overall pruning
     422                                        // sort by cost
    478423                                        CandidateCost coster{ resn.indexer };
    479424                                        std::sort( compatible.begin(), compatible.end(), coster );
    480425
     426                                        // keep map of detected options
     427                                        std::unordered_map<std::string, Cost> found;
    481428                                        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
    482439                                                ResnState new_resn = resn;
    483440
     
    495452                                                new_resn.alt.openVars = std::move(compat.openVars);
    496453
    497                                                 // mark cost of this path
    498                                                 new_resn.costs.back() += compat.cost;
    499 
    500454                                                // either add sucessful match or push back next state
    501455                                                if ( new_resn.newNeed.empty() ) {
    502                                                         finalizeAssertions( new_resn, thresholds, out );
     456                                                        finalizeAssertions( new_resn.alt, new_resn.inferred, out );
    503457                                                } else {
    504458                                                        new_resns.emplace_back( std::move(new_resn), IterateState );
Note: See TracChangeset for help on using the changeset viewer.