mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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.
This commit is contained in:
13
CHANGELOG.md
13
CHANGELOG.md
@@ -3,6 +3,19 @@
|
||||
> [!NOTE]
|
||||
> This is in reverse chronological order, so newer entries are added to the top.
|
||||
|
||||
## Swift (next)
|
||||
|
||||
* Concurrency-related APIs like `Task` and string-processing-related APIs like `Regex` can now be qualified by the name
|
||||
`Swift`, just like other standard library APIs:
|
||||
|
||||
```swift
|
||||
Swift.Task { ... }
|
||||
func match(_ regex: Swift.Regex<(Substring)>) { ... }
|
||||
```
|
||||
|
||||
The old `_Concurrency` and `_StringProcessing` names are still supported for backwards compatibility, and Embedded
|
||||
Swift projects must still explicitly `import _Concurrency` to access concurrency APIs.
|
||||
|
||||
## Swift 6.2
|
||||
|
||||
* [SE-0472][]:
|
||||
|
||||
@@ -1294,6 +1294,10 @@ public:
|
||||
return const_cast<ASTContext *>(this)->getStdlibModule(false);
|
||||
}
|
||||
|
||||
/// Names of underscored modules whose contents, if imported, should be
|
||||
/// treated as separately-imported overlays of the standard library module.
|
||||
ArrayRef<Identifier> StdlibOverlayNames;
|
||||
|
||||
/// Insert an externally-sourced module into the set of known loaded modules
|
||||
/// in this context.
|
||||
void addLoadedModule(ModuleDecl *M);
|
||||
|
||||
@@ -840,6 +840,12 @@ ASTContext::ASTContext(
|
||||
#define IDENTIFIER_WITH_NAME(Name, IdStr) Id_##Name = getIdentifier(IdStr);
|
||||
#include "swift/AST/KnownIdentifiers.def"
|
||||
|
||||
Identifier stdlibOverlayNames[] = {
|
||||
Id_Concurrency,
|
||||
Id_StringProcessing
|
||||
};
|
||||
StdlibOverlayNames = AllocateCopy(stdlibOverlayNames);
|
||||
|
||||
// Record the initial set of search paths.
|
||||
for (const auto &path : SearchPathOpts.getImportSearchPaths())
|
||||
getImpl().SearchPathsSet[path.Path] |= SearchPathKind::Import;
|
||||
|
||||
@@ -447,6 +447,16 @@ DeclContext *DeclContext::getModuleScopeContext() const {
|
||||
|
||||
void DeclContext::getSeparatelyImportedOverlays(
|
||||
ModuleDecl *declaring, SmallVectorImpl<ModuleDecl *> &overlays) const {
|
||||
if (declaring->isStdlibModule()) {
|
||||
auto &ctx = getASTContext();
|
||||
for (auto overlayName: ctx.StdlibOverlayNames) {
|
||||
if (auto module = ctx.getLoadedModule(overlayName))
|
||||
overlays.push_back(module);
|
||||
}
|
||||
overlays.push_back(declaring);
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto SF = getOutermostParentSourceFile())
|
||||
SF->getSeparatelyImportedOverlays(declaring, overlays);
|
||||
}
|
||||
|
||||
@@ -2374,28 +2374,41 @@ void ModuleDecl::findDeclaredCrossImportOverlaysTransitive(
|
||||
if (auto *clangModule = getUnderlyingModuleIfOverlay())
|
||||
worklist.push_back(clangModule);
|
||||
|
||||
auto addOverlay = [&](Identifier overlay) {
|
||||
// We don't present non-underscored overlays as part of the underlying
|
||||
// module, so ignore them.
|
||||
if (!overlay.hasUnderscoredNaming())
|
||||
return;
|
||||
|
||||
ModuleDecl *overlayMod =
|
||||
getASTContext().getModuleByIdentifier(overlay);
|
||||
if (!overlayMod && overlayMod != this)
|
||||
return;
|
||||
|
||||
if (seen.insert(overlayMod).second) {
|
||||
overlayModules.push_back(overlayMod);
|
||||
worklist.push_back(overlayMod);
|
||||
if (auto *clangModule = overlayMod->getUnderlyingModuleIfOverlay())
|
||||
worklist.push_back(clangModule);
|
||||
}
|
||||
};
|
||||
|
||||
while (!worklist.empty()) {
|
||||
ModuleDecl *current = worklist.back();
|
||||
worklist.pop_back();
|
||||
|
||||
if (current->isStdlibModule()) {
|
||||
for (auto overlay : getASTContext().StdlibOverlayNames) {
|
||||
addOverlay(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &pair: current->declaredCrossImports) {
|
||||
Identifier &bystander = std::get<0>(pair);
|
||||
for (auto *file: std::get<1>(pair)) {
|
||||
auto overlays = file->getOverlayModuleNames(current, unused, bystander);
|
||||
for (Identifier overlay: overlays) {
|
||||
// We don't present non-underscored overlays as part of the underlying
|
||||
// module, so ignore them.
|
||||
if (!overlay.hasUnderscoredNaming())
|
||||
continue;
|
||||
ModuleDecl *overlayMod =
|
||||
getASTContext().getModuleByName(overlay.str());
|
||||
if (!overlayMod)
|
||||
continue;
|
||||
if (seen.insert(overlayMod).second) {
|
||||
overlayModules.push_back(overlayMod);
|
||||
worklist.push_back(overlayMod);
|
||||
if (auto *clangModule = overlayMod->getUnderlyingModuleIfOverlay())
|
||||
worklist.push_back(clangModule);
|
||||
}
|
||||
addOverlay(overlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2432,6 +2445,12 @@ ModuleDecl::getDeclaringModuleAndBystander() {
|
||||
if (!hasUnderscoredNaming())
|
||||
return *(declaringModuleAndBystander = {nullptr, Identifier()});
|
||||
|
||||
// If this is one of the stdlib overlays, indicate as much.
|
||||
auto &ctx = getASTContext();
|
||||
if (llvm::is_contained(ctx.StdlibOverlayNames, getRealName()))
|
||||
return *(declaringModuleAndBystander = { ctx.getStdlibModule(),
|
||||
Identifier() });
|
||||
|
||||
// Search the transitive set of imported @_exported modules to see if any have
|
||||
// this module as their overlay.
|
||||
SmallPtrSet<ModuleDecl *, 16> seen;
|
||||
@@ -2511,7 +2530,8 @@ bool ModuleDecl::getRequiredBystandersIfCrossImportOverlay(
|
||||
auto *clangModule = declaring->getUnderlyingModuleIfOverlay();
|
||||
auto current = std::make_pair(this, Identifier());
|
||||
while ((current = current.first->getDeclaringModuleAndBystander()).first) {
|
||||
bystanderNames.push_back(current.second);
|
||||
if (!current.second.empty())
|
||||
bystanderNames.push_back(current.second);
|
||||
if (current.first == declaring || current.first == clangModule)
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -163,11 +163,18 @@ void ModuleNameLookup<LookupStrategy>::lookupInModule(
|
||||
moduleOrFile->getParentModule(), overlays);
|
||||
if (!overlays.empty()) {
|
||||
// If so, look in each of those overlays.
|
||||
for (auto overlay : overlays)
|
||||
lookupInModule(decls, overlay, accessPath, moduleScopeContext, options);
|
||||
bool selfOverlay = false;
|
||||
for (auto overlay : overlays) {
|
||||
if (overlay == moduleOrFile->getParentModule())
|
||||
selfOverlay = true;
|
||||
else
|
||||
lookupInModule(decls, overlay, accessPath, moduleScopeContext,
|
||||
options);
|
||||
}
|
||||
// FIXME: This may not work gracefully if more than one of these lookups
|
||||
// finds something.
|
||||
return;
|
||||
if (!selfOverlay)
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t initialCount = decls.size();
|
||||
|
||||
@@ -2182,11 +2182,9 @@ bool CompletionLookup::tryModuleCompletions(Type ExprType,
|
||||
// If the module is shadowed by a separately imported overlay(s), look up
|
||||
// the symbols from the overlay(s) instead.
|
||||
SmallVector<ModuleDecl *, 1> ShadowingOrOriginal;
|
||||
if (auto *SF = CurrDeclContext->getParentSourceFile()) {
|
||||
SF->getSeparatelyImportedOverlays(M, ShadowingOrOriginal);
|
||||
if (ShadowingOrOriginal.empty())
|
||||
ShadowingOrOriginal.push_back(M);
|
||||
}
|
||||
CurrDeclContext->getSeparatelyImportedOverlays(M, ShadowingOrOriginal);
|
||||
if (ShadowingOrOriginal.empty())
|
||||
ShadowingOrOriginal.push_back(M);
|
||||
for (ModuleDecl *M : ShadowingOrOriginal) {
|
||||
RequestedResultsTy Request =
|
||||
RequestedResultsTy::fromModule(M, Filter).needLeadingDot(needDot());
|
||||
|
||||
@@ -17,3 +17,8 @@ func f(_ t : UnsafeCurrentTask) -> Bool {
|
||||
|
||||
@available(SwiftStdlib 5.1, *)
|
||||
func g(_: _Concurrency.UnsafeCurrentTask) {}
|
||||
|
||||
// Should also be allowed since _Concurrency is a separately-imported overlay of
|
||||
// the standard library.
|
||||
@available(SwiftStdlib 5.1, *)
|
||||
func h(_: Swift.UnsafeCurrentTask) {}
|
||||
|
||||
@@ -408,7 +408,7 @@ struct GlobalType {}
|
||||
|
||||
@_Concurrency.MainActor
|
||||
extension GlobalType {
|
||||
@_Concurrency.MainActor static func ==(
|
||||
@Swift.MainActor static func ==(
|
||||
lhs: GlobalType,
|
||||
rhs: GlobalType
|
||||
) -> Bool { true }
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -Xfrontend -disable-access-control -o %t/Assert_Debug -Onone
|
||||
// RUN: %target-build-swift %s -Xfrontend -disable-access-control -o %t/Assert_Release -O
|
||||
// RUN: %target-build-swift %s -Xfrontend -disable-access-control -o %t/Assert_Unchecked -Ounchecked
|
||||
//
|
||||
// With -disable-access-control on, `_StringProcessing._internalInvariant` would shadow `Swift._internalInvariant`
|
||||
// RUN: %target-build-swift %s -Xfrontend -disable-access-control -Xfrontend -disable-implicit-string-processing-module-import -o %t/Assert_Debug -Onone
|
||||
// RUN: %target-build-swift %s -Xfrontend -disable-access-control -Xfrontend -disable-implicit-string-processing-module-import -o %t/Assert_Release -O
|
||||
// RUN: %target-build-swift %s -Xfrontend -disable-access-control -Xfrontend -disable-implicit-string-processing-module-import -o %t/Assert_Unchecked -Ounchecked
|
||||
//
|
||||
// RUN: %target-codesign %t/Assert_Debug
|
||||
// RUN: %target-codesign %t/Assert_Release
|
||||
// RUN: %target-codesign %t/Assert_Unchecked
|
||||
|
||||
Reference in New Issue
Block a user