Skip to content

Commit 3abbfaa

Browse files
committed
Introduce separately-imported stdlib overlays
The `_Concurrency` and `_StringProcessing` modules are implementation details of the standard library; to developers, their contents should behave as though they are declared directly within module `Swift`. This is the exact same behavior we expect of cross-import overlays, so treat these modules as though they are cross-import overlays with no bystanding module. Because these modules don’t re-export the standard library, it’s also necessary to treat `Swift` as a separately imported overlay of itself; do so and make that actually work.
1 parent 8362997 commit 3abbfaa

File tree

10 files changed

+93
-27
lines changed

10 files changed

+93
-27
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@
33
> [!NOTE]
44
> This is in reverse chronological order, so newer entries are added to the top.
55
6+
## Swift (next)
7+
8+
* Concurrency-related APIs like `Task` and string-processing-related APIs like `Regex` can now be qualified by the name
9+
`Swift`, just like other standard library APIs:
10+
11+
```swift
12+
Swift.Task { ... }
13+
func match(_ regex: Swift.Regex<(Substring)>) { ... }
14+
```
15+
16+
The old `_Concurrency` and `_StringProcessing` names are still supported for backwards compatibility, and Embedded
17+
Swift projects must still explicitly `import _Concurrency` to access concurrency APIs.
18+
619
## Swift 6.2
720

821
* [SE-0472][]:

include/swift/AST/ASTContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,10 @@ class ASTContext final {
12941294
return const_cast<ASTContext *>(this)->getStdlibModule(false);
12951295
}
12961296

1297+
/// Names of underscored modules whose contents, if imported, should be
1298+
/// treated as separately-imported overlays of the standard library module.
1299+
ArrayRef<Identifier> StdlibOverlayNames;
1300+
12971301
/// Insert an externally-sourced module into the set of known loaded modules
12981302
/// in this context.
12991303
void addLoadedModule(ModuleDecl *M);

lib/AST/ASTContext.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,12 @@ ASTContext::ASTContext(
840840
#define IDENTIFIER_WITH_NAME(Name, IdStr) Id_##Name = getIdentifier(IdStr);
841841
#include "swift/AST/KnownIdentifiers.def"
842842

843+
Identifier stdlibOverlayNames[] = {
844+
Id_Concurrency,
845+
Id_StringProcessing
846+
};
847+
StdlibOverlayNames = AllocateCopy(stdlibOverlayNames);
848+
843849
// Record the initial set of search paths.
844850
for (const auto &path : SearchPathOpts.getImportSearchPaths())
845851
getImpl().SearchPathsSet[path.Path] |= SearchPathKind::Import;

lib/AST/DeclContext.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,16 @@ DeclContext *DeclContext::getModuleScopeContext() const {
447447

448448
void DeclContext::getSeparatelyImportedOverlays(
449449
ModuleDecl *declaring, SmallVectorImpl<ModuleDecl *> &overlays) const {
450+
if (declaring->isStdlibModule()) {
451+
auto &ctx = getASTContext();
452+
for (auto overlayName: ctx.StdlibOverlayNames) {
453+
if (auto module = ctx.getLoadedModule(overlayName))
454+
overlays.push_back(module);
455+
}
456+
overlays.push_back(declaring);
457+
return;
458+
}
459+
450460
if (auto SF = getOutermostParentSourceFile())
451461
SF->getSeparatelyImportedOverlays(declaring, overlays);
452462
}

lib/AST/Module.cpp

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,28 +2374,41 @@ void ModuleDecl::findDeclaredCrossImportOverlaysTransitive(
23742374
if (auto *clangModule = getUnderlyingModuleIfOverlay())
23752375
worklist.push_back(clangModule);
23762376

2377+
auto addOverlay = [&](Identifier overlay) {
2378+
// We don't present non-underscored overlays as part of the underlying
2379+
// module, so ignore them.
2380+
if (!overlay.hasUnderscoredNaming())
2381+
return;
2382+
2383+
ModuleDecl *overlayMod =
2384+
getASTContext().getModuleByIdentifier(overlay);
2385+
if (!overlayMod && overlayMod != this)
2386+
return;
2387+
2388+
if (seen.insert(overlayMod).second) {
2389+
overlayModules.push_back(overlayMod);
2390+
worklist.push_back(overlayMod);
2391+
if (auto *clangModule = overlayMod->getUnderlyingModuleIfOverlay())
2392+
worklist.push_back(clangModule);
2393+
}
2394+
};
2395+
23772396
while (!worklist.empty()) {
23782397
ModuleDecl *current = worklist.back();
23792398
worklist.pop_back();
2399+
2400+
if (current->isStdlibModule()) {
2401+
for (auto overlay : getASTContext().StdlibOverlayNames) {
2402+
addOverlay(overlay);
2403+
}
2404+
}
2405+
23802406
for (auto &pair: current->declaredCrossImports) {
23812407
Identifier &bystander = std::get<0>(pair);
23822408
for (auto *file: std::get<1>(pair)) {
23832409
auto overlays = file->getOverlayModuleNames(current, unused, bystander);
23842410
for (Identifier overlay: overlays) {
2385-
// We don't present non-underscored overlays as part of the underlying
2386-
// module, so ignore them.
2387-
if (!overlay.hasUnderscoredNaming())
2388-
continue;
2389-
ModuleDecl *overlayMod =
2390-
getASTContext().getModuleByName(overlay.str());
2391-
if (!overlayMod)
2392-
continue;
2393-
if (seen.insert(overlayMod).second) {
2394-
overlayModules.push_back(overlayMod);
2395-
worklist.push_back(overlayMod);
2396-
if (auto *clangModule = overlayMod->getUnderlyingModuleIfOverlay())
2397-
worklist.push_back(clangModule);
2398-
}
2411+
addOverlay(overlay);
23992412
}
24002413
}
24012414
}
@@ -2432,6 +2445,12 @@ ModuleDecl::getDeclaringModuleAndBystander() {
24322445
if (!hasUnderscoredNaming())
24332446
return *(declaringModuleAndBystander = {nullptr, Identifier()});
24342447

2448+
// If this is one of the stdlib overlays, indicate as much.
2449+
auto &ctx = getASTContext();
2450+
if (llvm::is_contained(ctx.StdlibOverlayNames, getRealName()))
2451+
return *(declaringModuleAndBystander = { ctx.getStdlibModule(),
2452+
Identifier() });
2453+
24352454
// Search the transitive set of imported @_exported modules to see if any have
24362455
// this module as their overlay.
24372456
SmallPtrSet<ModuleDecl *, 16> seen;
@@ -2511,7 +2530,8 @@ bool ModuleDecl::getRequiredBystandersIfCrossImportOverlay(
25112530
auto *clangModule = declaring->getUnderlyingModuleIfOverlay();
25122531
auto current = std::make_pair(this, Identifier());
25132532
while ((current = current.first->getDeclaringModuleAndBystander()).first) {
2514-
bystanderNames.push_back(current.second);
2533+
if (!current.second.empty())
2534+
bystanderNames.push_back(current.second);
25152535
if (current.first == declaring || current.first == clangModule)
25162536
return true;
25172537
}

lib/AST/ModuleNameLookup.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,18 @@ void ModuleNameLookup<LookupStrategy>::lookupInModule(
163163
moduleOrFile->getParentModule(), overlays);
164164
if (!overlays.empty()) {
165165
// If so, look in each of those overlays.
166-
for (auto overlay : overlays)
167-
lookupInModule(decls, overlay, accessPath, moduleScopeContext, options);
166+
bool selfOverlay = false;
167+
for (auto overlay : overlays) {
168+
if (overlay == moduleOrFile->getParentModule())
169+
selfOverlay = true;
170+
else
171+
lookupInModule(decls, overlay, accessPath, moduleScopeContext,
172+
options);
173+
}
168174
// FIXME: This may not work gracefully if more than one of these lookups
169175
// finds something.
170-
return;
176+
if (!selfOverlay)
177+
return;
171178
}
172179

173180
const size_t initialCount = decls.size();

lib/IDE/CompletionLookup.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2182,11 +2182,9 @@ bool CompletionLookup::tryModuleCompletions(Type ExprType,
21822182
// If the module is shadowed by a separately imported overlay(s), look up
21832183
// the symbols from the overlay(s) instead.
21842184
SmallVector<ModuleDecl *, 1> ShadowingOrOriginal;
2185-
if (auto *SF = CurrDeclContext->getParentSourceFile()) {
2186-
SF->getSeparatelyImportedOverlays(M, ShadowingOrOriginal);
2187-
if (ShadowingOrOriginal.empty())
2188-
ShadowingOrOriginal.push_back(M);
2189-
}
2185+
CurrDeclContext->getSeparatelyImportedOverlays(M, ShadowingOrOriginal);
2186+
if (ShadowingOrOriginal.empty())
2187+
ShadowingOrOriginal.push_back(M);
21902188
for (ModuleDecl *M : ShadowingOrOriginal) {
21912189
RequestedResultsTy Request =
21922190
RequestedResultsTy::fromModule(M, Filter).needLeadingDot(needDot());

test/Concurrency/concurrency_module_shadowing.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,8 @@ func f(_ t : UnsafeCurrentTask) -> Bool {
1717

1818
@available(SwiftStdlib 5.1, *)
1919
func g(_: _Concurrency.UnsafeCurrentTask) {}
20+
21+
// Should also be allowed since _Concurrency is a separately-imported overlay of
22+
// the standard library.
23+
@available(SwiftStdlib 5.1, *)
24+
func h(_: Swift.UnsafeCurrentTask) {}

test/Concurrency/global_actor_function_types.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ struct GlobalType {}
408408

409409
@_Concurrency.MainActor
410410
extension GlobalType {
411-
@_Concurrency.MainActor static func ==(
411+
@Swift.MainActor static func ==(
412412
lhs: GlobalType,
413413
rhs: GlobalType
414414
) -> Bool { true }

validation-test/stdlib/Assert.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-build-swift %s -Xfrontend -disable-access-control -o %t/Assert_Debug -Onone
3-
// RUN: %target-build-swift %s -Xfrontend -disable-access-control -o %t/Assert_Release -O
4-
// RUN: %target-build-swift %s -Xfrontend -disable-access-control -o %t/Assert_Unchecked -Ounchecked
2+
//
3+
// With -disable-access-control on, `_StringProcessing._internalInvariant` would shadow `Swift._internalInvariant`
4+
// RUN: %target-build-swift %s -Xfrontend -disable-access-control -Xfrontend -disable-implicit-string-processing-module-import -o %t/Assert_Debug -Onone
5+
// RUN: %target-build-swift %s -Xfrontend -disable-access-control -Xfrontend -disable-implicit-string-processing-module-import -o %t/Assert_Release -O
6+
// RUN: %target-build-swift %s -Xfrontend -disable-access-control -Xfrontend -disable-implicit-string-processing-module-import -o %t/Assert_Unchecked -Ounchecked
7+
//
58
// RUN: %target-codesign %t/Assert_Debug
69
// RUN: %target-codesign %t/Assert_Release
710
// RUN: %target-codesign %t/Assert_Unchecked

0 commit comments

Comments
 (0)