diff --git a/CHANGELOG.md b/CHANGELOG.md index 09ba71572e370..7cc63bc9baf08 100644 --- a/CHANGELOG.md +++ b/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][]: diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 8e582043fad25..37b642d20d7fd 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -1294,6 +1294,10 @@ class ASTContext final { return const_cast(this)->getStdlibModule(false); } + /// Names of underscored modules whose contents, if imported, should be + /// treated as separately-imported overlays of the standard library module. + ArrayRef StdlibOverlayNames; + /// Insert an externally-sourced module into the set of known loaded modules /// in this context. void addLoadedModule(ModuleDecl *M); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c7b0d15309108..cf51584e5b76e 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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; diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index d6142e787fc44..5b5cfbe3e9524 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -447,6 +447,16 @@ DeclContext *DeclContext::getModuleScopeContext() const { void DeclContext::getSeparatelyImportedOverlays( ModuleDecl *declaring, SmallVectorImpl &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); } diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index ed35eca070ffe..93fcbab1ffbd9 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -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 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; } diff --git a/lib/AST/ModuleNameLookup.cpp b/lib/AST/ModuleNameLookup.cpp index cd5915b468fd0..53d02d5dafb17 100644 --- a/lib/AST/ModuleNameLookup.cpp +++ b/lib/AST/ModuleNameLookup.cpp @@ -163,11 +163,18 @@ void ModuleNameLookup::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(); diff --git a/lib/IDE/CompletionLookup.cpp b/lib/IDE/CompletionLookup.cpp index 10330fb55c46a..4e2ff8c41bfe9 100644 --- a/lib/IDE/CompletionLookup.cpp +++ b/lib/IDE/CompletionLookup.cpp @@ -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 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()); diff --git a/test/Concurrency/concurrency_module_shadowing.swift b/test/Concurrency/concurrency_module_shadowing.swift index 69958b2667f9b..32362ad67f967 100644 --- a/test/Concurrency/concurrency_module_shadowing.swift +++ b/test/Concurrency/concurrency_module_shadowing.swift @@ -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) {} diff --git a/test/Concurrency/global_actor_function_types.swift b/test/Concurrency/global_actor_function_types.swift index 452755af4a1c1..a41a5b97c8672 100644 --- a/test/Concurrency/global_actor_function_types.swift +++ b/test/Concurrency/global_actor_function_types.swift @@ -408,7 +408,7 @@ struct GlobalType {} @_Concurrency.MainActor extension GlobalType { - @_Concurrency.MainActor static func ==( + @Swift.MainActor static func ==( lhs: GlobalType, rhs: GlobalType ) -> Bool { true } diff --git a/validation-test/stdlib/Assert.swift b/validation-test/stdlib/Assert.swift index 7df90cb4ba57b..acfadb0e6da7a 100644 --- a/validation-test/stdlib/Assert.swift +++ b/validation-test/stdlib/Assert.swift @@ -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