- File:
-
- 1 edited
-
src/ResolvExpr/ResolveAssertions.cc (modified) (14 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/ResolveAssertions.cc
r493a992 re1f7eef 20 20 #include <list> // for list 21 21 #include <memory> // for unique_ptr 22 #include <sstream> // for ostringstream 23 #include <string> // for string 22 #include <string> 24 23 #include <unordered_map> // for unordered_map, unordered_multimap 25 24 #include <utility> // for move … … 28 27 #include "Alternative.h" // for Alternative, AssertionItem, AssertionList 29 28 #include "Common/FilterCombos.h" // for filterCombos 30 #include "Common/Indenter.h" // for Indenter31 29 #include "Common/utility.h" // for sort_mins 32 30 #include "ResolvExpr/RenameVars.h" // for renameTyVars … … 35 33 #include "SynTree/Expression.h" // for InferredParams 36 34 #include "TypeEnvironment.h" // for TypeEnvironment, etc. 37 #include "typeops.h" // for adjustExprType , specCost35 #include "typeops.h" // for adjustExprType 38 36 #include "Unify.h" // for unify 39 37 … … 58 56 using CandidateList = std::vector<AssnCandidate>; 59 57 58 /// Unique identifier for a yet-to-be-resolved assertion 59 struct AssnId { 60 DeclarationWithType* decl; ///< Declaration of assertion 61 AssertionSetValue info; ///< Information about assertion 62 63 AssnId(DeclarationWithType* decl, const AssertionSetValue& info) : decl(decl), info(info) {} 64 }; 65 66 /// Cached assertion items 67 struct AssnCacheItem { 68 CandidateList matches; ///< Possible matches for this assertion 69 std::vector<AssnId> deferIds; ///< Deferred assertions which resolve to this item 70 71 AssnCacheItem( CandidateList&& m ) : matches(std::move(m)), deferIds() {} 72 }; 73 74 /// Cache of resolved assertions 75 using AssnCache = std::unordered_map<std::string, AssnCacheItem>; 76 60 77 /// Reference to single deferred item 61 78 struct DeferRef { 62 const DeclarationWithType* decl; 63 const AssertionSetValue& info; 79 const AssnCacheItem& item; 64 80 const AssnCandidate& match; 65 81 }; … … 68 84 /// Acts like indexed list of DeferRef 69 85 struct DeferItem { 70 const DeclarationWithType* decl; 71 const AssertionSetValue& info; 72 CandidateList matches; 73 74 DeferItem( DeclarationWithType* decl, const AssertionSetValue& info, CandidateList&& matches ) 75 : decl(decl), info(info), matches(std::move(matches)) {} 76 77 bool empty() const { return matches.empty(); } 78 79 CandidateList::size_type size() const { return matches.size(); } 80 81 DeferRef operator[] ( unsigned i ) const { return { decl, info, matches[i] }; } 86 const AssnCache* cache; ///< Cache storing assertion item 87 std::string key; ///< Key into cache 88 89 DeferItem( const AssnCache& cache, const std::string& key ) : cache(&cache), key(key) {} 90 91 bool empty() const { return cache->at(key).matches.empty(); } 92 93 CandidateList::size_type size() const { return cache->at(key).matches.size(); } 94 95 DeferRef operator[] ( unsigned i ) const { 96 const AssnCacheItem& item = cache->at(key); 97 return { item, item.matches[i] }; 98 } 99 100 // sortable by key 101 // TODO look into optimizing combination process with other sort orders (e.g. by number 102 // of matches in candidate) 103 bool operator< ( const DeferItem& o ) const { return key < o.key; } 104 bool operator== ( const DeferItem& o ) const { return key == o.key; } 82 105 }; 83 106 … … 154 177 for ( const auto& assn : x.assns ) { 155 178 k += computeConversionCost( 156 assn.match.adjType, assn.decl->get_type(), indexer, x.env ); 157 158 // mark vars+specialization cost on function-type assertions 159 PointerType* ptr = dynamic_cast< PointerType* >( assn.decl->get_type() ); 160 if ( ! ptr ) continue; 161 FunctionType* func = dynamic_cast< FunctionType* >( ptr->base ); 162 if ( ! func ) continue; 163 164 for ( DeclarationWithType* formal : func->parameters ) { 165 k.decSpec( specCost( formal->get_type() ) ); 166 } 167 k.incVar( func->forall.size() ); 168 for ( TypeDecl* td : func->forall ) { 169 k.decSpec( td->assertions.size() ); 170 } 179 assn.match.adjType, assn.item.deferIds[0].decl->get_type(), indexer, 180 x.env ); 171 181 } 172 182 it = cache.emplace_hint( it, &x, k ); … … 239 249 240 250 /// Resolve a single assertion, in context 241 bool resolveAssertion( AssertionItem& assn, ResnState& resn ) {251 bool resolveAssertion( AssertionItem& assn, ResnState& resn, AssnCache& cache ) { 242 252 // skip unused assertions 243 253 if ( ! assn.info.isUsed ) return true; 244 254 245 // lookup candidates for this assertion 246 std::list< SymTab::Indexer::IdData > candidates; 247 resn.indexer.lookupId( assn.decl->name, candidates ); 248 249 // find the candidates that unify with the desired type 250 CandidateList matches; 251 for ( const auto& cdata : candidates ) { 252 DeclarationWithType* candidate = cdata.id; 253 254 // build independent unification context for candidate 255 AssertionSet have, newNeed; 256 TypeEnvironment newEnv{ resn.alt.env }; 257 OpenVarSet newOpenVars{ resn.alt.openVars }; 258 Type* adjType = candidate->get_type()->clone(); 259 adjustExprType( adjType, newEnv, resn.indexer ); 260 renameTyVars( adjType ); 261 262 // keep unifying candidates 263 if ( unify( assn.decl->get_type(), adjType, newEnv, newNeed, have, newOpenVars, 264 resn.indexer ) ) { 265 // set up binding slot for recursive assertions 266 UniqueId crntResnSlot = 0; 267 if ( ! newNeed.empty() ) { 268 crntResnSlot = ++globalResnSlot; 269 for ( auto& a : newNeed ) { 270 a.second.resnSlot = crntResnSlot; 255 // check cache for this assertion 256 std::string assnKey = SymTab::Mangler::mangleAssnKey( assn.decl, resn.alt.env ); 257 auto it = cache.find( assnKey ); 258 259 // attempt to resolve assertion if this is the first time seen 260 if ( it == cache.end() ) { 261 // lookup candidates for this assertion 262 std::list< SymTab::Indexer::IdData > candidates; 263 resn.indexer.lookupId( assn.decl->name, candidates ); 264 265 // find the candidates that unify with the desired type 266 CandidateList matches; 267 for ( const auto& cdata : candidates ) { 268 DeclarationWithType* candidate = cdata.id; 269 270 // build independent unification context for candidate 271 AssertionSet have, newNeed; 272 TypeEnvironment newEnv{ resn.alt.env }; 273 OpenVarSet newOpenVars{ resn.alt.openVars }; 274 Type* adjType = candidate->get_type()->clone(); 275 adjustExprType( adjType, newEnv, resn.indexer ); 276 renameTyVars( adjType ); 277 278 // keep unifying candidates 279 if ( unify( assn.decl->get_type(), adjType, newEnv, newNeed, have, newOpenVars, 280 resn.indexer ) ) { 281 // set up binding slot for recursive assertions 282 UniqueId crntResnSlot = 0; 283 if ( ! newNeed.empty() ) { 284 crntResnSlot = ++globalResnSlot; 285 for ( auto& a : newNeed ) { 286 a.second.resnSlot = crntResnSlot; 287 } 271 288 } 272 } 273 274 matches.emplace_back( cdata, adjType, std::move(newEnv), std::move(have),275 std::move(newNeed), std::move(newOpenVars), crntResnSlot );276 } else {277 delete adjType;289 290 matches.emplace_back( cdata, adjType, std::move(newEnv), std::move(have), 291 std::move(newNeed), std::move(newOpenVars), crntResnSlot ); 292 } else { 293 delete adjType; 294 } 278 295 } 279 } 296 297 it = cache.emplace_hint( it, assnKey, AssnCacheItem{ std::move(matches) } ); 298 } 299 300 CandidateList& matches = it->second.matches; 280 301 281 302 // break if no suitable assertion … … 284 305 // defer if too many suitable assertions 285 306 if ( matches.size() > 1 ) { 286 resn.deferred.emplace_back( assn.decl, assn.info, std::move(matches) ); 307 it->second.deferIds.emplace_back( assn.decl, assn.info ); 308 resn.deferred.emplace_back( cache, assnKey ); 287 309 return true; 288 310 } … … 292 314 addToIndexer( match.have, resn.indexer ); 293 315 resn.newNeed.insert( match.need.begin(), match.need.end() ); 294 resn.alt.env = std::move(match.env);295 resn.alt.openVars = std::move(match.openVars);316 resn.alt.env = match.env; 317 resn.alt.openVars = match.openVars; 296 318 297 319 bindAssertion( assn.decl, assn.info, resn.alt, match, resn.inferred ); … … 342 364 static const int recursionLimit = /* 10 */ 4; 343 365 344 void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out , std::list<std::string>& errors) {366 void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out ) { 345 367 // finish early if no assertions to resolve 346 368 if ( alt.need.empty() ) { … … 354 376 ResnList resns{ ResnState{ alt, root_indexer } }; 355 377 ResnList new_resns{}; 378 AssnCache assnCache; 356 379 357 380 // resolve assertions in breadth-first-order up to a limited number of levels deep … … 362 385 for ( auto& assn : resn.need ) { 363 386 // fail early if any assertion is not resolvable 364 if ( ! resolveAssertion( assn, resn ) ) { 365 Indenter tabs{ Indenter::tabsize, 3 }; 366 std::ostringstream ss; 367 ss << tabs << "Unsatisfiable alternative:\n"; 368 resn.alt.print( ss, ++tabs ); 369 ss << --tabs << "Could not satisfy assertion:\n"; 370 assn.decl->print( ss, ++tabs ); 371 372 errors.emplace_back( ss.str() ); 373 goto nextResn; 374 } 387 if ( ! resolveAssertion( assn, resn, assnCache ) ) goto nextResn; 375 388 } 376 389 … … 383 396 } 384 397 } else { 398 // only resolve each deferred assertion once 399 std::sort( resn.deferred.begin(), resn.deferred.end() ); 400 auto last = std::unique( resn.deferred.begin(), resn.deferred.end() ); 401 resn.deferred.erase( last, resn.deferred.end() ); 385 402 // resolve deferred assertions by mutual compatibility 386 403 std::vector<CandidateEnvMerger::OutType> compatible = filterCombos( 387 404 resn.deferred, 388 405 CandidateEnvMerger{ resn.alt.env, resn.alt.openVars, resn.indexer } ); 389 // fail early if no mutually-compatible assertion satisfaction390 if ( compatible.empty() ) {391 Indenter tabs{ Indenter::tabsize, 3 };392 std::ostringstream ss;393 ss << tabs << "Unsatisfiable alternative:\n";394 resn.alt.print( ss, ++tabs );395 ss << --tabs << "No mutually-compatible satisfaction for assertions:\n";396 ++tabs;397 for ( const auto& d : resn.deferred ) {398 d.decl->print( ss, tabs );399 }400 401 errors.emplace_back( ss.str() );402 goto nextResn;403 }404 406 // sort by cost 405 407 CandidateCost coster{ resn.indexer }; … … 427 429 new_resn.newNeed.insert( match.need.begin(), match.need.end() ); 428 430 429 bindAssertion( r.decl, r.info, new_resn.alt, match, new_resn.inferred ); 431 // for each deferred assertion with the same form 432 for ( AssnId id : r.item.deferIds ) { 433 bindAssertion( 434 id.decl, id.info, new_resn.alt, match, new_resn.inferred ); 435 } 430 436 } 431 437
Note:
See TracChangeset
for help on using the changeset viewer.