Skip to content

Commit ee71704

Browse files
authored
Merge pull request #32902 from xymus/ioi-in-spi-5.3
[5.3][ModuleInterface] Print some implementation-only imports in the private interface
2 parents cceb9a3 + b1e4a89 commit ee71704

6 files changed

+111
-2
lines changed

include/swift/Frontend/ModuleInterfaceSupport.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ struct ModuleInterfaceOptions {
4343

4444
// Print SPI decls and attributes.
4545
bool PrintSPIs = false;
46+
47+
/// Print imports with both @_implementationOnly and @_spi, only applies
48+
/// when PrintSPIs is true.
49+
bool ExperimentalSPIImports = false;
4650
};
4751

4852
extern version::Version InterfaceFormatVersion;

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,10 @@ def module_interface_preserve_types_as_written :
627627
HelpText<"When emitting a module interface, preserve types as they were "
628628
"written in the source">;
629629

630+
def experimental_spi_imports :
631+
Flag<["-"], "experimental-spi-imports">,
632+
HelpText<"Enable experimental support for SPI imports">;
633+
630634
def experimental_print_full_convention :
631635
Flag<["-"], "experimental-print-full-convention">,
632636
HelpText<"When emitting a module interface, emit additional @convention "

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ static void ParseModuleInterfaceArgs(ModuleInterfaceOptions &Opts,
303303
Args.hasArg(OPT_module_interface_preserve_types_as_written);
304304
Opts.PrintFullConvention |=
305305
Args.hasArg(OPT_experimental_print_full_convention);
306+
Opts.ExperimentalSPIImports |=
307+
Args.hasArg(OPT_experimental_spi_imports);
306308
}
307309

308310
/// Save a copy of any flags marked as ModuleInterfaceOption, if running

lib/Frontend/ModuleInterfaceSupport.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,21 @@ static void printImports(raw_ostream &out,
104104
allImportFilter |= ModuleDecl::ImportFilterKind::Private;
105105
allImportFilter |= ModuleDecl::ImportFilterKind::SPIAccessControl;
106106

107+
// With -experimental-spi-imports:
108+
// When printing the private swiftinterface file, print implementation-only
109+
// imports only if they are also SPI. First, list all implementation-only
110+
// imports and filter them later.
111+
llvm::SmallSet<ModuleDecl::ImportedModule, 4,
112+
ModuleDecl::OrderImportedModules> ioiImportSet;
113+
if (Opts.PrintSPIs && Opts.ExperimentalSPIImports) {
114+
allImportFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly;
115+
116+
SmallVector<ModuleDecl::ImportedModule, 4> ioiImport;
117+
M->getImportedModules(ioiImport,
118+
ModuleDecl::ImportFilterKind::ImplementationOnly);
119+
ioiImportSet.insert(ioiImport.begin(), ioiImport.end());
120+
}
121+
107122
SmallVector<ModuleDecl::ImportedModule, 8> allImports;
108123
M->getImportedModules(allImports, allImportFilter);
109124
ModuleDecl::removeDuplicateImports(allImports);
@@ -124,13 +139,21 @@ static void printImports(raw_ostream &out,
124139
continue;
125140
}
126141

142+
llvm::SmallVector<Identifier, 4> spis;
143+
M->lookupImportedSPIGroups(importedModule, spis);
144+
145+
// Only print implementation-only imports which have an SPI import.
146+
if (ioiImportSet.count(import)) {
147+
if (spis.empty())
148+
continue;
149+
out << "@_implementationOnly ";
150+
}
151+
127152
if (publicImportSet.count(import))
128153
out << "@_exported ";
129154

130155
// SPI attribute on imports
131156
if (Opts.PrintSPIs) {
132-
SmallVector<Identifier, 4> spis;
133-
M->lookupImportedSPIGroups(importedModule, spis);
134157
for (auto spiName : spis)
135158
out << "@_spi(" << spiName << ") ";
136159
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/// Test the textual interfaces generated with -experimental-spi-imports.
2+
3+
// RUN: %empty-directory(%t)
4+
5+
/// Generate 3 empty modules.
6+
// RUN: touch %t/empty.swift
7+
// RUN: %target-swift-frontend -emit-module %t/empty.swift -module-name ExperimentalImported -emit-module-path %t/ExperimentalImported.swiftmodule -swift-version 5 -enable-library-evolution
8+
// RUN: %target-swift-frontend -emit-module %t/empty.swift -module-name IOIImported -emit-module-path %t/IOIImported.swiftmodule -swift-version 5 -enable-library-evolution
9+
// RUN: %target-swift-frontend -emit-module %t/empty.swift -module-name SPIImported -emit-module-path %t/SPIImported.swiftmodule -swift-version 5 -enable-library-evolution
10+
11+
/// Test the generated swiftinterface.
12+
// RUN: %target-swift-frontend -typecheck %s -emit-module-interface-path %t/main.swiftinterface -emit-private-module-interface-path %t/main.private.swiftinterface -enable-library-evolution -swift-version 5 -I %t -experimental-spi-imports
13+
// RUN: %FileCheck -check-prefix=CHECK-PUBLIC %s < %t/main.swiftinterface
14+
// RUN: %FileCheck -check-prefix=CHECK-PRIVATE %s < %t/main.private.swiftinterface
15+
16+
@_spi(dummy) @_implementationOnly import ExperimentalImported
17+
// CHECK-PUBLIC-NOT: import ExperimentalImported
18+
// CHECK-PRIVATE: @_implementationOnly @_spi{{.*}} import ExperimentalImported
19+
20+
@_implementationOnly import IOIImported
21+
// CHECK-PUBLIC-NOT: IOIImported
22+
// CHECK-PRIVATE-NOT: IOIImported
23+
24+
@_spi(dummy) import SPIImported
25+
// CHECK-PUBLIC: {{^}}import SPIImported
26+
// CHECK-PRIVATE: @_spi{{.*}} import SPIImported
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/// Test the use of implementation-only types with -experimental-spi-imports.
2+
3+
/// Build LibCore an internal module and LibPublic a public module using LibCore.
4+
// RUN: %empty-directory(%t)
5+
// RUN: %target-swift-frontend -emit-module -DLIB_CORE %s -module-name LibCore -emit-module-path %t/LibCore.swiftmodule -enable-library-evolution -swift-version 5
6+
// RUN: %target-swift-frontend -emit-module -DLIB_PUBLIC %s -module-name LibPublic -emit-module-path %t/LibPublic.swiftmodule -I %t -emit-module-interface-path %t/LibPublic.swiftinterface -emit-private-module-interface-path %t/LibPublic.private.swiftinterface -enable-library-evolution -swift-version 5 -experimental-spi-imports
7+
8+
/// Test with the swiftmodule file, the compiler raises an error only when
9+
/// LibCore isn't loaded by the client.
10+
// RUN: %target-typecheck-verify-swift -DCLIENT -I %t
11+
// RUN: %target-swift-frontend -typecheck %s -DCLIENT -DCLIENT_LOAD_CORE -I %t
12+
13+
/// Test with the private swiftinterface file, the compiler raises an error
14+
/// only when LibCore isn't loaded by the client.
15+
// RUN: rm %t/LibPublic.swiftmodule
16+
// RUN: %target-typecheck-verify-swift -DCLIENT -I %t
17+
// RUN: %target-swift-frontend -typecheck %s -DCLIENT -DCLIENT_LOAD_CORE -I %t
18+
19+
/// Test with the public swiftinterface file, the SPI is unknown.
20+
// RUN: rm %t/LibPublic.private.swiftinterface
21+
// RUN: %target-typecheck-verify-swift -DCLIENT -I %t
22+
// RUN: %target-typecheck-verify-swift -DCLIENT -DCLIENT_LOAD_CORE -I %t
23+
24+
#if LIB_CORE
25+
26+
public struct CoreStruct {
27+
public init() {}
28+
public func coreMethod() {}
29+
}
30+
31+
32+
#elseif LIB_PUBLIC
33+
34+
@_spi(dummy) @_implementationOnly import LibCore
35+
36+
@_spi(A) public func SPIFunc() -> CoreStruct { return CoreStruct() }
37+
38+
39+
#elseif CLIENT
40+
41+
@_spi(A) import LibPublic
42+
43+
#if CLIENT_LOAD_CORE
44+
import LibCore
45+
#endif
46+
47+
let x = SPIFunc() // expected-error {{cannot find 'SPIFunc' in scope}}
48+
x.coreMethod()
49+
50+
#endif

0 commit comments

Comments
 (0)