Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions include/swift/AST/FileUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,13 @@ class FileUnit : public DeclContext, public ASTAllocated<FileUnit> {
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.
///
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,10 @@ class ModuleDecl
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
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/SourceFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,11 @@ class SourceFile final : public FileUnit {
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;

Expand Down
3 changes: 3 additions & 0 deletions include/swift/Serialization/SerializedModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,9 @@ class SerializedASTFile final : public LoadedFile {
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;
Expand Down
28 changes: 28 additions & 0 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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())
Expand Down
6 changes: 6 additions & 0 deletions lib/Frontend/ModuleInterfaceSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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))
Expand Down
8 changes: 8 additions & 0 deletions lib/Serialization/SerializedModuleLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
37 changes: 37 additions & 0 deletions test/ModuleInterface/preconcurrency_imports.swift
Original file line number Diff line number Diff line change
@@ -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 {}