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,
|
const ModuleDecl *importedModule,
|
||||||
llvm::SmallSetVector<Identifier, 4> &spiGroups) const {};
|
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
|
/// Find all availability domains defined in this module with the given
|
||||||
/// identifier.
|
/// identifier.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -965,6 +965,10 @@ public:
|
|||||||
const ModuleDecl *importedModule,
|
const ModuleDecl *importedModule,
|
||||||
llvm::SmallSetVector<Identifier, 4> &spiGroups) const;
|
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
|
/// Finds the custom availability domain defined by this module with the
|
||||||
/// given identifier and if one exists adds it to results.
|
/// given identifier and if one exists adds it to results.
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -471,6 +471,11 @@ public:
|
|||||||
const ModuleDecl *importedModule,
|
const ModuleDecl *importedModule,
|
||||||
llvm::SmallSetVector<Identifier, 4> &spiGroups) const override;
|
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?
|
// Is \p targetDecl accessible as an explicitly imported SPI from this file?
|
||||||
bool isImportedAsSPI(const ValueDecl *targetDecl) const;
|
bool isImportedAsSPI(const ValueDecl *targetDecl) const;
|
||||||
|
|
||||||
|
|||||||
@@ -466,6 +466,9 @@ public:
|
|||||||
const ModuleDecl *importedModule,
|
const ModuleDecl *importedModule,
|
||||||
llvm::SmallSetVector<Identifier, 4> &spiGroups) const override;
|
llvm::SmallSetVector<Identifier, 4> &spiGroups) const override;
|
||||||
|
|
||||||
|
virtual bool isModuleImportedPreconcurrency(
|
||||||
|
const ModuleDecl *importedModule) const override;
|
||||||
|
|
||||||
std::optional<CommentInfo> getCommentForDecl(const Decl *D) const override;
|
std::optional<CommentInfo> getCommentForDecl(const Decl *D) const override;
|
||||||
|
|
||||||
bool hasLoadedSwiftDoc() const override;
|
bool hasLoadedSwiftDoc() const override;
|
||||||
|
|||||||
@@ -1044,6 +1044,20 @@ void ModuleDecl::lookupImportedSPIGroups(
|
|||||||
FORWARD(lookupImportedSPIGroups, (importedModule, spiGroups));
|
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(
|
void ModuleDecl::lookupAvailabilityDomains(
|
||||||
Identifier identifier,
|
Identifier identifier,
|
||||||
llvm::SmallVectorImpl<AvailabilityDomain> &results) const {
|
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) {
|
bool shouldImplicitImportAsSPI(ArrayRef<Identifier> spiGroups) {
|
||||||
for (auto group : spiGroups) {
|
for (auto group : spiGroups) {
|
||||||
if (group.empty())
|
if (group.empty())
|
||||||
|
|||||||
@@ -271,6 +271,9 @@ static void printImports(raw_ostream &out,
|
|||||||
ModuleDecl::ImportFilterKind::Default,
|
ModuleDecl::ImportFilterKind::Default,
|
||||||
ModuleDecl::ImportFilterKind::ShadowedByCrossImportOverlay};
|
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>;
|
using ImportSet = llvm::SmallSet<ImportedModule, 8, ImportedModule::Order>;
|
||||||
auto getImports = [M](ModuleDecl::ImportFilter filter) -> ImportSet {
|
auto getImports = [M](ModuleDecl::ImportFilter filter) -> ImportSet {
|
||||||
SmallVector<ImportedModule, 8> matchingImports;
|
SmallVector<ImportedModule, 8> matchingImports;
|
||||||
@@ -355,6 +358,9 @@ static void printImports(raw_ostream &out,
|
|||||||
out << "@_spi(" << spiName << ") ";
|
out << "@_spi(" << spiName << ") ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (M->isModuleImportedPreconcurrency(importedModule))
|
||||||
|
out << "@preconcurrency ";
|
||||||
|
|
||||||
if (Opts.printPackageInterface() &&
|
if (Opts.printPackageInterface() &&
|
||||||
!publicImportSet.count(import) &&
|
!publicImportSet.count(import) &&
|
||||||
packageOnlyImportSet.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>
|
std::optional<CommentInfo>
|
||||||
SerializedASTFile::getCommentForDecl(const Decl *D) const {
|
SerializedASTFile::getCommentForDecl(const Decl *D) const {
|
||||||
return File.getCommentForDecl(D);
|
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