Skip to content

Commit 94cd52c

Browse files
committed
Sema: Intro import cache services for Swift only reexported imports
1 parent bd4e5e7 commit 94cd52c

File tree

2 files changed

+99
-10
lines changed

2 files changed

+99
-10
lines changed

include/swift/AST/ImportCache.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,12 @@ class ImportSet final :
5656
unsigned HasHeaderImportModule : 1;
5757
unsigned NumTopLevelImports : 31;
5858
unsigned NumTransitiveImports;
59+
unsigned NumTransitiveSwiftOnlyImports;
5960

6061
ImportSet(bool hasHeaderImportModule,
6162
ArrayRef<ImportedModule> topLevelImports,
62-
ArrayRef<ImportedModule> transitiveImports);
63+
ArrayRef<ImportedModule> transitiveImports,
64+
ArrayRef<ImportedModule> transitiveSwiftOnlyImports);
6365

6466
ImportSet(const ImportSet &) = delete;
6567
void operator=(const ImportSet &) = delete;
@@ -73,7 +75,8 @@ class ImportSet final :
7375
ArrayRef<ImportedModule> topLevelImports);
7476

7577
size_t numTrailingObjects(OverloadToken<ImportedModule>) const {
76-
return NumTopLevelImports + NumTransitiveImports;
78+
return NumTopLevelImports + NumTransitiveImports +
79+
NumTransitiveSwiftOnlyImports;
7780
}
7881

7982
/// This is a bit of a hack to make module name lookup work properly.
@@ -94,6 +97,12 @@ class ImportSet final :
9497
NumTransitiveImports};
9598
}
9699

100+
ArrayRef<ImportedModule> getTransitiveSwiftOnlyImports() const {
101+
return {getTrailingObjects<ImportedModule>() +
102+
NumTopLevelImports + NumTransitiveImports,
103+
NumTransitiveSwiftOnlyImports};
104+
}
105+
97106
ArrayRef<ImportedModule> getAllImports() const {
98107
return {getTrailingObjects<ImportedModule>(),
99108
NumTopLevelImports + NumTransitiveImports};
@@ -115,6 +124,9 @@ class alignas(ImportedModule) ImportCache {
115124
const ModuleDecl *,
116125
const DeclContext *>,
117126
ArrayRef<ImportPath::Access>> ShadowCache;
127+
llvm::DenseMap<std::tuple<const ModuleDecl *,
128+
const DeclContext *>,
129+
bool> SwiftOnlyCache;
118130

119131
ImportPath::Access EmptyAccessPath;
120132

@@ -142,6 +154,12 @@ class alignas(ImportedModule) ImportCache {
142154
return !getAllVisibleAccessPaths(mod, dc).empty();
143155
}
144156

157+
/// Is `mod` imported from `dc` via a purely Swift access path?
158+
/// Always returns false if `dc` is a non-Swift module and only takes
159+
/// into account re-exports declared from Swift modules for transitive imports.
160+
bool isImportedByViaSwiftOnly(const ModuleDecl *mod,
161+
const DeclContext *dc);
162+
145163
/// Returns all access paths in 'mod' that are visible from 'dc' if we
146164
/// subtract imports of 'other'.
147165
ArrayRef<ImportPath::Access>

lib/AST/ImportCache.cpp

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,21 @@ using namespace namelookup;
2727

2828
ImportSet::ImportSet(bool hasHeaderImportModule,
2929
ArrayRef<ImportedModule> topLevelImports,
30-
ArrayRef<ImportedModule> transitiveImports)
30+
ArrayRef<ImportedModule> transitiveImports,
31+
ArrayRef<ImportedModule> transitiveSwiftOnlyImports)
3132
: HasHeaderImportModule(hasHeaderImportModule),
3233
NumTopLevelImports(topLevelImports.size()),
33-
NumTransitiveImports(transitiveImports.size()) {
34+
NumTransitiveImports(transitiveImports.size()),
35+
NumTransitiveSwiftOnlyImports(transitiveSwiftOnlyImports.size()) {
3436
auto buffer = getTrailingObjects<ImportedModule>();
3537
std::uninitialized_copy(topLevelImports.begin(), topLevelImports.end(),
3638
buffer);
3739
std::uninitialized_copy(transitiveImports.begin(), transitiveImports.end(),
3840
buffer + topLevelImports.size());
41+
std::uninitialized_copy(transitiveSwiftOnlyImports.begin(),
42+
transitiveSwiftOnlyImports.end(),
43+
buffer + topLevelImports.size() +
44+
transitiveImports.size());
3945

4046
#ifndef NDEBUG
4147
llvm::SmallDenseSet<ImportedModule, 8> unique;
@@ -47,6 +53,15 @@ ImportSet::ImportSet(bool hasHeaderImportModule,
4753
auto result = unique.insert(import).second;
4854
assert(result && "Duplicate imports in import set");
4955
}
56+
57+
unique.clear();
58+
for (auto import : topLevelImports) {
59+
unique.insert(import);
60+
}
61+
for (auto import : transitiveSwiftOnlyImports) {
62+
auto result = unique.insert(import).second;
63+
assert(result && "Duplicate imports in import set");
64+
}
5065
#endif
5166
}
5267

@@ -82,10 +97,14 @@ void ImportSet::dump() const {
8297
}
8398

8499
static void collectExports(ImportedModule next,
85-
SmallVectorImpl<ImportedModule> &stack) {
100+
SmallVectorImpl<ImportedModule> &stack,
101+
bool onlySwiftExports) {
86102
SmallVector<ImportedModule, 4> exports;
87103
next.importedModule->getImportedModulesForLookup(exports);
88104
for (auto exported : exports) {
105+
if (onlySwiftExports && exported.importedModule->isNonSwiftModule())
106+
continue;
107+
89108
if (next.accessPath.empty())
90109
stack.push_back(exported);
91110
else if (exported.accessPath.empty()) {
@@ -135,7 +154,7 @@ ImportCache::getImportSet(ASTContext &ctx,
135154

136155
SmallVector<ImportedModule, 4> stack;
137156
for (auto next : topLevelImports) {
138-
collectExports(next, stack);
157+
collectExports(next, stack, /*onlySwiftExports*/false);
139158
}
140159

141160
while (!stack.empty()) {
@@ -148,7 +167,26 @@ ImportCache::getImportSet(ASTContext &ctx,
148167
if (next.importedModule == headerImportModule)
149168
hasHeaderImportModule = true;
150169

151-
collectExports(next, stack);
170+
collectExports(next, stack, /*onlySwiftExports*/false);
171+
}
172+
173+
// Now collect transitive imports through Swift reexported imports only.
174+
SmallVector<ImportedModule, 4> transitiveSwiftOnlyImports;
175+
visited.clear();
176+
stack.clear();
177+
for (auto next : topLevelImports) {
178+
if (!visited.insert(next).second)
179+
continue;
180+
collectExports(next, stack, /*onlySwiftExports*/true);
181+
}
182+
183+
while (!stack.empty()) {
184+
auto next = stack.pop_back_val();
185+
if (!visited.insert(next).second)
186+
continue;
187+
188+
transitiveSwiftOnlyImports.push_back(next);
189+
collectExports(next, stack, /*onlySwiftExports*/true);
152190
}
153191

154192
// Find the insert position again, in case the above traversal invalidated
@@ -157,12 +195,15 @@ ImportCache::getImportSet(ASTContext &ctx,
157195
if (ImportSet *result = ImportSets.FindNodeOrInsertPos(ID, InsertPos))
158196
return *result;
159197

160-
size_t bytes = ImportSet::totalSizeToAlloc<ImportedModule>(topLevelImports.size() + transitiveImports.size());
198+
size_t bytes = ImportSet::totalSizeToAlloc<ImportedModule>(
199+
topLevelImports.size() + transitiveImports.size() +
200+
transitiveSwiftOnlyImports.size());
161201
void *mem = ctx.Allocate(bytes, alignof(ImportSet), AllocationArena::Permanent);
162202

163203
auto *result = new (mem) ImportSet(hasHeaderImportModule,
164204
topLevelImports,
165-
transitiveImports);
205+
transitiveImports,
206+
transitiveSwiftOnlyImports);
166207
ImportSets.InsertNode(result, InsertPos);
167208

168209
return *result;
@@ -249,6 +290,36 @@ ImportCache::getAllVisibleAccessPaths(const ModuleDecl *mod,
249290
return result;
250291
}
251292

293+
bool ImportCache::isImportedByViaSwiftOnly(const ModuleDecl *mod,
294+
const DeclContext *dc) {
295+
dc = dc->getModuleScopeContext();
296+
if (dc->getParentModule()->isNonSwiftModule())
297+
return false;
298+
299+
auto &ctx = mod->getASTContext();
300+
auto key = std::make_pair(mod, dc);
301+
auto found = SwiftOnlyCache.find(key);
302+
if (found != SwiftOnlyCache.end()) {
303+
if (ctx.Stats)
304+
++ctx.Stats->getFrontendCounters().ModuleVisibilityCacheHit;
305+
return found->second;
306+
}
307+
308+
if (ctx.Stats)
309+
++ctx.Stats->getFrontendCounters().ModuleVisibilityCacheMiss;
310+
311+
bool result = false;
312+
for (auto next : getImportSet(dc).getTransitiveSwiftOnlyImports()) {
313+
if (next.importedModule == mod) {
314+
result = true;
315+
break;
316+
}
317+
}
318+
319+
SwiftOnlyCache[key] = result;
320+
return result;
321+
}
322+
252323
ArrayRef<ImportPath::Access>
253324
ImportCache::getAllAccessPathsNotShadowedBy(const ModuleDecl *mod,
254325
const ModuleDecl *other,
@@ -307,7 +378,7 @@ ImportCache::getAllAccessPathsNotShadowedBy(const ModuleDecl *mod,
307378
accessPaths.push_back(next.accessPath);
308379
}
309380

310-
collectExports(next, stack);
381+
collectExports(next, stack, /*onlySwiftExports*/false);
311382
}
312383

313384
auto result = allocateArray(ctx, accessPaths);

0 commit comments

Comments
 (0)