Skip to content

Commit 67e35c3

Browse files
committed
[ModuleInterface] Print @_spiOnly imports in the private swiftinterface
1 parent a530e38 commit 67e35c3

File tree

2 files changed

+121
-2
lines changed

2 files changed

+121
-2
lines changed

lib/Frontend/ModuleInterfaceSupport.cpp

+31-2
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,26 @@ static void printImports(raw_ostream &out,
217217
allImportFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly;
218218
}
219219

220+
/// Collect @_spiOnly imports that are not imported elsewhere publicly.
221+
llvm::SmallSet<ImportedModule, 4, ImportedModule::Order> spiOnlyImportSet;
222+
if (Opts.PrintSPIs) {
223+
SmallVector<ImportedModule, 4> spiOnlyImports, otherImports;
224+
M->getImportedModules(spiOnlyImports,
225+
ModuleDecl::ImportFilterKind::SPIOnly);
226+
227+
M->getImportedModules(otherImports,
228+
allImportFilter);
229+
llvm::SmallSet<ImportedModule, 8, ImportedModule::Order> otherImportsSet;
230+
otherImportsSet.insert(otherImports.begin(), otherImports.end());
231+
232+
// Rule out inconsistent imports.
233+
for (auto import: spiOnlyImports)
234+
if (otherImportsSet.count(import) == 0)
235+
spiOnlyImportSet.insert(import);
236+
237+
allImportFilter |= ModuleDecl::ImportFilterKind::SPIOnly;
238+
}
239+
220240
SmallVector<ImportedModule, 8> allImports;
221241
M->getImportedModules(allImports, allImportFilter);
222242

@@ -231,7 +251,6 @@ static void printImports(raw_ostream &out,
231251
SmallVector<ImportedModule, 8> publicImports;
232252
M->getImportedModules(publicImports, ModuleDecl::ImportFilterKind::Exported);
233253
llvm::SmallSet<ImportedModule, 8, ImportedModule::Order> publicImportSet;
234-
235254
publicImportSet.insert(publicImports.begin(), publicImports.end());
236255

237256
for (auto import : allImports) {
@@ -259,8 +278,18 @@ static void printImports(raw_ostream &out,
259278
if (publicImportSet.count(import))
260279
out << "@_exported ";
261280

262-
// SPI attribute on imports
263281
if (Opts.PrintSPIs) {
282+
// An import visible in the private swiftinterface only.
283+
//
284+
// In the long term, we want to print this attribute for consistency and
285+
// to enforce exportability analysis of generated code.
286+
// For now, not printing the attribute allows us to have backwards
287+
// compatible swiftinterfaces and we can live without
288+
// checking the generate code for a while.
289+
if (spiOnlyImportSet.count(import))
290+
out << "/*@_spiOnly*/ ";
291+
292+
// List of imported SPI groups for local use.
264293
for (auto spiName : spis)
265294
out << "@_spi(" << spiName << ") ";
266295
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/// Test the swiftinterfaces and @_spiOnly.
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: split-file %s %t
5+
6+
/// Generate dependencies
7+
// RUN: %target-swift-frontend -emit-module %S/Inputs/ioi_helper.swift \
8+
// RUN: -module-name A_SPIOnlyImported -emit-module-path %t/A_SPIOnlyImported.swiftmodule
9+
// RUN: %target-swift-frontend -emit-module %t/Empty.swift \
10+
// RUN: -module-name ConstantSPIOnly -emit-module-path %t/ConstantSPIOnly.swiftmodule
11+
// RUN: %target-swift-frontend -emit-module %t/Empty.swift \
12+
// RUN: -module-name InconsistentIOI -emit-module-path %t/InconsistentIOI.swiftmodule
13+
// RUN: %target-swift-frontend -emit-module %t/Empty.swift \
14+
// RUN: -module-name InconsistentPublic -emit-module-path %t/InconsistentPublic.swiftmodule
15+
// RUN: %target-swift-frontend -emit-module %t/Empty.swift \
16+
// RUN: -module-name IOIImported -emit-module-path %t/IOIImported.swiftmodule
17+
// RUN: %target-swift-frontend -emit-module %t/Empty.swift \
18+
// RUN: -module-name SPIImported -emit-module-path %t/SPIImported.swiftmodule
19+
20+
/// Test the generated swiftinterface.
21+
// RUN: %target-swift-frontend -typecheck %t/FileA.swift %t/FileB.swift \
22+
// RUN: -experimental-spi-only-imports \
23+
// RUN: -swift-version 5 -enable-library-evolution -module-name Main -I %t \
24+
// RUN: -emit-module-interface-path %t/Main.swiftinterface \
25+
// RUN: -emit-private-module-interface-path %t/Main.private.swiftinterface
26+
// RUN: %target-swift-typecheck-module-from-interface(%t/Main.swiftinterface) -I %t
27+
// RUN: %target-swift-typecheck-module-from-interface(%t/Main.private.swiftinterface) \
28+
// RUN: -module-name Main -I %t
29+
// RUN: %FileCheck -check-prefix=CHECK-PUBLIC %s < %t/Main.swiftinterface
30+
// RUN: %FileCheck -check-prefix=CHECK-PRIVATE %s < %t/Main.private.swiftinterface
31+
32+
/// Test the case of a library-level=SPI where even the public swiftinterface
33+
/// also has SPI details.
34+
// RUN: %target-swift-frontend -typecheck %t/FileA.swift %t/FileB.swift \
35+
// RUN: -experimental-spi-only-imports \
36+
// RUN: -swift-version 5 -enable-library-evolution -module-name SPIMain -I %t \
37+
// RUN: -emit-module-interface-path %t/SPIMain.swiftinterface \
38+
// RUN: -emit-private-module-interface-path %t/SPIMain.private.swiftinterface \
39+
// RUN: -library-level spi
40+
// RUN: %target-swift-typecheck-module-from-interface(%t/SPIMain.swiftinterface) -I %t
41+
// RUN: %target-swift-typecheck-module-from-interface(%t/SPIMain.private.swiftinterface) \
42+
// RUN: -module-name SPIMain -I %t
43+
// RUN: %FileCheck -check-prefix=CHECK-PRIVATE %s < %t/SPIMain.swiftinterface
44+
// RUN: %FileCheck -check-prefix=CHECK-PRIVATE %s < %t/SPIMain.private.swiftinterface
45+
46+
//--- Empty.swift
47+
//--- FileA.swift
48+
49+
/// We don't need or want the flag in the swiftinterface
50+
// CHECK-PUBLIC-NOT: -experimental-spi-only-imports
51+
// CHECK-PRIVATE-NOT: -experimental-spi-only-imports
52+
53+
@_spiOnly @_spi(SomeSPIGroup) import A_SPIOnlyImported
54+
// CHECK-PUBLIC-NOT: A_SPIOnlyImported
55+
// CHECK-PRIVATE: {{^}}/*@_spiOnly*/ @_spi(SomeSPIGroup) import A_SPIOnlyImported
56+
57+
/// This is also imported as SPI only via FileB.swift
58+
@_spiOnly import ConstantSPIOnly
59+
// CHECK-PUBLIC-NOT: ConstantSPIOnly
60+
// CHECK-PRIVATE: {{^}}/*@_spiOnly*/ import ConstantSPIOnly
61+
62+
/// This is also imported as SPI only via FileB.swift
63+
@_implementationOnly import InconsistentIOI
64+
// CHECK-PUBLIC-NOT: InconsistentIOI
65+
// CHECK-PRIVATE: {{^}}/*@_spiOnly*/ import InconsistentIOI
66+
67+
/// This is also imported as SPI only via FileB.swift
68+
import InconsistentPublic
69+
// CHECK-PUBLIC: {{^}}import InconsistentPublic
70+
// CHECK-PRIVATE: {{^}}import InconsistentPublic
71+
72+
@_implementationOnly import IOIImported
73+
// CHECK-PUBLIC-NOT: IOIImported
74+
// CHECK-PRIVATE-NOT: IOIImported
75+
76+
@_spi(dummy) import SPIImported
77+
// CHECK-PUBLIC: {{^}}import SPIImported
78+
// CHECK-PRIVATE: @_spi{{.*}} import SPIImported
79+
80+
@_spi(X)
81+
extension IOIPublicStruct {
82+
public func foo() {}
83+
}
84+
// CHECK-PUBLIC-NOT: A_SPIOnlyImported.IOIPublicStruct
85+
// CHECK-PRIVATE: @_spi{{.*}} extension A_SPIOnlyImported.IOIPublicStruct
86+
87+
//--- FileB.swift
88+
@_spiOnly import ConstantSPIOnly
89+
@_spiOnly import InconsistentPublic
90+
@_spiOnly import InconsistentIOI

0 commit comments

Comments
 (0)