mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Treat "lookup into immediately imported modules" as a special case
Features like `@testable import` change the results produced by name lookup in the source file with the testable import. What they /shouldn't/ do is change the results of lookup into the same module from elsewhere in the import graph...and neither should cached results from lookup elsewhere in the import graph affect the lookups from the source file. Encode this difference in the cache used during module-level name lookup to fix testable imports like this. (The test case here looks a little contrived because of '@_exported', but that's how imports are treated in Clang modules and with bridging headers, so it is in fact a realistic scenario.) rdar://problem/48890959
This commit is contained in:
@@ -19,9 +19,10 @@ using namespace swift;
|
||||
using namespace namelookup;
|
||||
|
||||
namespace {
|
||||
using ModuleLookupCache = llvm::SmallDenseMap<ModuleDecl::ImportedModule,
|
||||
TinyPtrVector<ValueDecl *>,
|
||||
32>;
|
||||
using ModuleLookupCacheKey = std::pair<ModuleDecl::ImportedModule,
|
||||
const DeclContext * /*lookupScope*/>;
|
||||
using ModuleLookupCache = llvm::SmallDenseMap<ModuleLookupCacheKey,
|
||||
TinyPtrVector<ValueDecl *>, 32>;
|
||||
|
||||
class SortCanType {
|
||||
public:
|
||||
@@ -155,12 +156,15 @@ static void lookupInModule(ModuleDecl *module, ModuleDecl::AccessPathTy accessPa
|
||||
return !import.second;
|
||||
}));
|
||||
|
||||
ModuleLookupCache::iterator iter;
|
||||
bool isNew;
|
||||
std::tie(iter, isNew) = cache.insert({{accessPath, module}, {}});
|
||||
if (!isNew) {
|
||||
decls.append(iter->second.begin(), iter->second.end());
|
||||
return;
|
||||
ModuleDecl::ImportedModule import{accessPath, module};
|
||||
ModuleLookupCacheKey cacheKey{import, moduleScopeContext};
|
||||
|
||||
{
|
||||
auto iter = cache.find(cacheKey);
|
||||
if (iter != cache.end()) {
|
||||
decls.append(iter->second.begin(), iter->second.end());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
size_t initialCount = decls.size();
|
||||
@@ -174,7 +178,10 @@ static void lookupInModule(ModuleDecl *module, ModuleDecl::AccessPathTy accessPa
|
||||
});
|
||||
localDecls.erase(newEndIter, localDecls.end());
|
||||
|
||||
// This only applies to immediate imports of the top-level module.
|
||||
// Special treatment based on the use site only applies to immediate
|
||||
// imports of the top-level module.
|
||||
// FIXME: It ought to apply to anything re-exported by those immediate
|
||||
// imports as well.
|
||||
if (moduleScopeContext && moduleScopeContext->getParentModule() != module)
|
||||
moduleScopeContext = nullptr;
|
||||
}
|
||||
@@ -189,8 +196,8 @@ static void lookupInModule(ModuleDecl *module, ModuleDecl::AccessPathTy accessPa
|
||||
SmallVector<ModuleDecl::ImportedModule, 8> reexports;
|
||||
module->getImportedModulesForLookup(reexports);
|
||||
assert(std::none_of(reexports.begin(), reexports.end(),
|
||||
[](ModuleDecl::ImportedModule import) -> bool {
|
||||
return !import.second;
|
||||
[module](ModuleDecl::ImportedModule import) -> bool {
|
||||
return !import.second || import.second == module;
|
||||
}));
|
||||
reexports.append(extraImports.begin(), extraImports.end());
|
||||
|
||||
@@ -241,7 +248,7 @@ static void lookupInModule(ModuleDecl *module, ModuleDecl::AccessPathTy accessPa
|
||||
}),
|
||||
decls.end());
|
||||
|
||||
auto &cachedValues = cache[{accessPath, module}];
|
||||
auto &cachedValues = cache[cacheKey];
|
||||
cachedValues.insert(cachedValues.end(),
|
||||
decls.begin() + initialCount,
|
||||
decls.end());
|
||||
|
||||
Reference in New Issue
Block a user