mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
ModuleInterface: Print imports with @preconcurrency in swiftinterface files.
When a module has been imported `@preconcurrency` in source, when it is printed in a `swiftinterface` file it should be printed along with the attribute to ensure that type checking of the module's public declarations behaves consistently. This fix is a little unsatisfying because it adds another a linear scan over all imports in the source for each printed import. This should be improved, but it can be done later. Resolves rdar://136857313.
This commit is contained in:
@@ -126,6 +126,13 @@ public:
|
||||
const ModuleDecl *importedModule,
|
||||
llvm::SmallSetVector<Identifier, 4> &spiGroups) const {};
|
||||
|
||||
/// Returns true if any import of \p importedModule has the `@preconcurrency`
|
||||
/// attribute.
|
||||
virtual bool
|
||||
isModuleImportedPreconcurrency(const ModuleDecl *importedModule) const {
|
||||
return false;
|
||||
};
|
||||
|
||||
/// Find all availability domains defined in this module with the given
|
||||
/// identifier.
|
||||
///
|
||||
|
||||
@@ -965,6 +965,10 @@ public:
|
||||
const ModuleDecl *importedModule,
|
||||
llvm::SmallSetVector<Identifier, 4> &spiGroups) const;
|
||||
|
||||
/// Returns true if any import of \p importedModule has the `@preconcurrency`
|
||||
/// attribute.
|
||||
bool isModuleImportedPreconcurrency(const ModuleDecl *importedModule) const;
|
||||
|
||||
/// Finds the custom availability domain defined by this module with the
|
||||
/// given identifier and if one exists adds it to results.
|
||||
void
|
||||
|
||||
@@ -471,6 +471,11 @@ public:
|
||||
const ModuleDecl *importedModule,
|
||||
llvm::SmallSetVector<Identifier, 4> &spiGroups) const override;
|
||||
|
||||
/// Returns true if any import of \p importedModule has the `@preconcurrency`
|
||||
/// attribute.
|
||||
virtual bool isModuleImportedPreconcurrency(
|
||||
const ModuleDecl *importedModule) const override;
|
||||
|
||||
// Is \p targetDecl accessible as an explicitly imported SPI from this file?
|
||||
bool isImportedAsSPI(const ValueDecl *targetDecl) const;
|
||||
|
||||
|
||||
@@ -466,6 +466,9 @@ public:
|
||||
const ModuleDecl *importedModule,
|
||||
llvm::SmallSetVector<Identifier, 4> &spiGroups) const override;
|
||||
|
||||
virtual bool isModuleImportedPreconcurrency(
|
||||
const ModuleDecl *importedModule) const override;
|
||||
|
||||
std::optional<CommentInfo> getCommentForDecl(const Decl *D) const override;
|
||||
|
||||
bool hasLoadedSwiftDoc() const override;
|
||||
|
||||
@@ -1044,6 +1044,20 @@ void ModuleDecl::lookupImportedSPIGroups(
|
||||
FORWARD(lookupImportedSPIGroups, (importedModule, spiGroups));
|
||||
}
|
||||
|
||||
bool ModuleDecl::isModuleImportedPreconcurrency(
|
||||
const ModuleDecl *importedModule) const {
|
||||
for (const FileUnit *file : getFiles()) {
|
||||
if (file->isModuleImportedPreconcurrency(importedModule))
|
||||
return true;
|
||||
|
||||
if (auto *synth = file->getSynthesizedFile()) {
|
||||
if (synth->isModuleImportedPreconcurrency(importedModule))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ModuleDecl::lookupAvailabilityDomains(
|
||||
Identifier identifier,
|
||||
llvm::SmallVectorImpl<AvailabilityDomain> &results) const {
|
||||
@@ -3050,6 +3064,20 @@ void SourceFile::lookupImportedSPIGroups(
|
||||
}
|
||||
}
|
||||
|
||||
bool SourceFile::isModuleImportedPreconcurrency(
|
||||
const ModuleDecl *importedModule) const {
|
||||
auto &imports = getASTContext().getImportCache();
|
||||
for (auto &import : *Imports) {
|
||||
if (import.options.contains(ImportFlags::Preconcurrency) &&
|
||||
(importedModule == import.module.importedModule ||
|
||||
imports.isImportedByViaSwiftOnly(importedModule,
|
||||
import.module.importedModule))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool shouldImplicitImportAsSPI(ArrayRef<Identifier> spiGroups) {
|
||||
for (auto group : spiGroups) {
|
||||
if (group.empty())
|
||||
|
||||
@@ -271,6 +271,9 @@ static void printImports(raw_ostream &out,
|
||||
ModuleDecl::ImportFilterKind::Default,
|
||||
ModuleDecl::ImportFilterKind::ShadowedByCrossImportOverlay};
|
||||
|
||||
// FIXME: Scan over all imports in the module once to build up the attribute
|
||||
// set for printed imports, instead of repeatedly doing linear scans for each
|
||||
// kind of attribute.
|
||||
using ImportSet = llvm::SmallSet<ImportedModule, 8, ImportedModule::Order>;
|
||||
auto getImports = [M](ModuleDecl::ImportFilter filter) -> ImportSet {
|
||||
SmallVector<ImportedModule, 8> matchingImports;
|
||||
@@ -355,6 +358,9 @@ static void printImports(raw_ostream &out,
|
||||
out << "@_spi(" << spiName << ") ";
|
||||
}
|
||||
|
||||
if (M->isModuleImportedPreconcurrency(importedModule))
|
||||
out << "@preconcurrency ";
|
||||
|
||||
if (Opts.printPackageInterface() &&
|
||||
!publicImportSet.count(import) &&
|
||||
packageOnlyImportSet.count(import))
|
||||
|
||||
@@ -1915,6 +1915,14 @@ void SerializedASTFile::lookupImportedSPIGroups(
|
||||
}
|
||||
}
|
||||
|
||||
bool SerializedASTFile::isModuleImportedPreconcurrency(
|
||||
const ModuleDecl *importedModule) const {
|
||||
// This method should only be queried during `-merge-modules` jobs, which are
|
||||
// deprecated, and thus no effort has been made to answer this query correctly
|
||||
// (@preconcurrency is not encoded on imports in serialized modules).
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<CommentInfo>
|
||||
SerializedASTFile::getCommentForDecl(const Decl *D) const {
|
||||
return File.getCommentForDecl(D);
|
||||
|
||||
37
test/ModuleInterface/preconcurrency_imports.swift
Normal file
37
test/ModuleInterface/preconcurrency_imports.swift
Normal file
@@ -0,0 +1,37 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: split-file %s %t
|
||||
|
||||
// RUN: %target-swift-frontend -emit-module %t/PreconcurrencyLib.swift -module-name PreconcurrencyLib -swift-version 5 -enable-library-evolution -emit-module-path %t/PreconcurrencyLib.swiftmodule -emit-module-interface-path %t/PreconcurrencyLib.swiftinterface
|
||||
// RUN: %target-swift-frontend -emit-module %t/OtherLib.swift -module-name OtherLib -swift-version 5 -enable-library-evolution -emit-module-path %t/OtherLib.swiftmodule -emit-module-interface-path %t/OtherLib.swiftinterface
|
||||
|
||||
// RUN: %target-swift-emit-module-interface(%t/ClientLib.swiftinterface) -swift-version 6 %t/ClientLib_file1.swift %t/ClientLib_file2.swift -module-name ClientLib -I %t
|
||||
// RUN: %target-swift-typecheck-module-from-interface(%t/ClientLib.swiftinterface) -module-name ClientLib -I %t
|
||||
// RUN: %FileCheck %s < %t/ClientLib.swiftinterface
|
||||
|
||||
// CHECK: {{^}}@preconcurrency import OtherLib
|
||||
// CHECK: {{^}}@preconcurrency import PreconcurrencyLib
|
||||
// CHECK: public struct Struct1 : Swift.Sendable
|
||||
// CHECK: public struct Struct2
|
||||
|
||||
//--- PreconcurrencyLib.swift
|
||||
|
||||
public class C {}
|
||||
|
||||
//--- OtherLib.swift
|
||||
// Intentionally empty
|
||||
|
||||
//--- ClientLib_file1.swift
|
||||
|
||||
@preconcurrency public import PreconcurrencyLib
|
||||
public import OtherLib
|
||||
|
||||
public struct Struct1: Sendable {
|
||||
public var c: C
|
||||
}
|
||||
|
||||
//--- ClientLib_file2.swift
|
||||
|
||||
internal import PreconcurrencyLib
|
||||
@preconcurrency internal import OtherLib
|
||||
|
||||
public struct Struct2 {}
|
||||
Reference in New Issue
Block a user