Skip to content

Commit 1fdcdce

Browse files
authored
Merge pull request swiftlang#33575 from xymus/dont-print-ioi-extensions
[ModuleInterface] Don't print extensions to implementation-only imported types
2 parents 7fcc7ba + bfe74f5 commit 1fdcdce

File tree

7 files changed

+110
-1
lines changed

7 files changed

+110
-1
lines changed

include/swift/AST/Module.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,12 @@ class ModuleDecl : public DeclContext, public TypeDecl {
685685
void
686686
getImportedModulesForLookup(SmallVectorImpl<ImportedModule> &imports) const;
687687

688+
/// Has \p module been imported via an '@_implementationOnly' import
689+
/// instead of another kind of import?
690+
///
691+
/// This assumes that \p module was imported.
692+
bool isImportedImplementationOnly(const ModuleDecl *module) const;
693+
688694
/// Uniques the items in \p imports, ignoring the source locations of the
689695
/// access paths.
690696
///

lib/AST/ASTPrinter.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,24 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr,
169169
if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
170170
if (!shouldPrint(ED->getExtendedNominal(), options))
171171
return false;
172+
173+
// Skip extensions to implementation-only imported types that have
174+
// no public members.
175+
auto localModule = ED->getParentModule();
176+
auto nominalModule = ED->getExtendedNominal()->getParentModule();
177+
if (localModule != nominalModule &&
178+
localModule->isImportedImplementationOnly(nominalModule)) {
179+
180+
bool shouldPrintMembers = llvm::any_of(
181+
ED->getMembers(),
182+
[&](const Decl *member) -> bool {
183+
return shouldPrint(member, options);
184+
});
185+
186+
if (!shouldPrintMembers)
187+
return false;
188+
}
189+
172190
for (const Requirement &req : ED->getGenericRequirements()) {
173191
if (!isPublicOrUsableFromInline(req.getFirstType()))
174192
return false;

lib/AST/Module.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1994,6 +1994,27 @@ bool SourceFile::isImportedImplementationOnly(const ModuleDecl *module) const {
19941994
return !imports.isImportedBy(module, getParentModule());
19951995
}
19961996

1997+
bool ModuleDecl::isImportedImplementationOnly(const ModuleDecl *module) const {
1998+
auto &imports = getASTContext().getImportCache();
1999+
2000+
// Look through non-implementation-only imports to see if module is imported
2001+
// in some other way. Otherwise we assume it's implementation-only imported.
2002+
ModuleDecl::ImportFilter filter = {
2003+
ModuleDecl::ImportFilterKind::Public,
2004+
ModuleDecl::ImportFilterKind::Private,
2005+
ModuleDecl::ImportFilterKind::SPIAccessControl,
2006+
ModuleDecl::ImportFilterKind::ShadowedBySeparateOverlay};
2007+
SmallVector<ModuleDecl::ImportedModule, 4> results;
2008+
getImportedModules(results, filter);
2009+
2010+
for (auto &desc : results) {
2011+
if (imports.isImportedBy(module, desc.importedModule))
2012+
return false;
2013+
}
2014+
2015+
return true;
2016+
}
2017+
19972018
void SourceFile::lookupImportedSPIGroups(
19982019
const ModuleDecl *importedModule,
19992020
llvm::SmallSetVector<Identifier, 4> &spiGroups) const {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Test that we don't print extensions to implementation-only imported types.
2+
3+
// RUN: %empty-directory(%t)
4+
5+
// RUN: %target-swift-frontend -emit-module %s -DIOI_LIB -module-name IOILib -emit-module-path %t/IOILib.swiftmodule
6+
// RUN: %target-swift-frontend -emit-module %s -DEXPORTED_LIB -module-name IndirectLib -emit-module-path %t/IndirectLib.swiftmodule -I %t
7+
// RUN: %target-swift-frontend -emit-module %s -DLIB -module-name Lib -emit-module-path %t/Lib.swiftmodule -I %t
8+
9+
// RUN: %target-swift-frontend-typecheck -emit-module-interface-path %t/out.swiftinterface %s -I %t -swift-version 5 -enable-library-evolution
10+
// RUN: %FileCheck %s < %t/out.swiftinterface
11+
12+
#if IOI_LIB
13+
14+
public struct IOIImportedType {
15+
public func foo() {}
16+
}
17+
18+
#elseif EXPORTED_LIB
19+
20+
public struct ExportedType {
21+
public func foo() {}
22+
}
23+
24+
#elseif LIB
25+
26+
@_exported import IndirectLib
27+
28+
public struct NormalImportedType {
29+
public func foo() {}
30+
}
31+
32+
#else // Client
33+
34+
import Lib
35+
@_implementationOnly import IOILib
36+
37+
public protocol PublicProto {
38+
func foo()
39+
}
40+
extension IOIImportedType : PublicProto {}
41+
// CHECK-NOT: IOIImportedType
42+
43+
extension NormalImportedType : PublicProto {}
44+
// CHECK: extension NormalImportedType
45+
46+
extension ExportedType : PublicProto {}
47+
// CHECK: extension ExportedType
48+
49+
#endif

test/SPI/Inputs/ioi_helper.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
public struct IOIPublicStruct {}

test/SPI/experimental_spi_imports_swiftinterface.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
/// Generate 3 empty modules.
66
// 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
7+
// RUN: %target-swift-frontend -emit-module %S/Inputs/ioi_helper.swift -module-name ExperimentalImported -emit-module-path %t/ExperimentalImported.swiftmodule -swift-version 5 -enable-library-evolution
88
// RUN: %target-swift-frontend -emit-module %t/empty.swift -module-name IOIImported -emit-module-path %t/IOIImported.swiftmodule -swift-version 5 -enable-library-evolution
99
// RUN: %target-swift-frontend -emit-module %t/empty.swift -module-name SPIImported -emit-module-path %t/SPIImported.swiftmodule -swift-version 5 -enable-library-evolution
1010

@@ -24,3 +24,10 @@
2424
@_spi(dummy) import SPIImported
2525
// CHECK-PUBLIC: {{^}}import SPIImported
2626
// CHECK-PRIVATE: @_spi{{.*}} import SPIImported
27+
28+
@_spi(X)
29+
extension IOIPublicStruct {
30+
public func foo() {}
31+
}
32+
// CHECK-PUBLIC-NOT: IOIPublicStruct
33+
// CHECK-PRIVATE: @_spi{{.*}} extension IOIPublicStruct

test/SPI/private_swiftinterface.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
// RUN: %empty-directory(%t)
55
// RUN: %target-swift-frontend -emit-module %S/Inputs/spi_helper.swift -module-name SPIHelper -emit-module-path %t/SPIHelper.swiftmodule -swift-version 5 -enable-library-evolution -emit-module-interface-path %t/SPIHelper.swiftinterface -emit-private-module-interface-path %t/SPIHelper.private.swiftinterface
6+
// RUN: %target-swift-frontend -emit-module %S/Inputs/ioi_helper.swift -module-name IOIHelper -emit-module-path %t/IOIHelper.swiftmodule -swift-version 5 -enable-library-evolution -emit-module-interface-path %t/IOIHelper.swiftinterface -emit-private-module-interface-path %t/IOIHelper.private.swiftinterface
67

78
/// Make sure that the public swiftinterface of spi_helper doesn't leak SPI.
89
// RUN: %FileCheck -check-prefix=CHECK-HELPER %s < %t/SPIHelper.swiftinterface
@@ -25,6 +26,7 @@
2526
// CHECK-PUBLIC: import SPIHelper
2627
// CHECK-PRIVATE: @_spi(OtherSPI) @_spi(HelperSPI) import SPIHelper
2728

29+
@_implementationOnly import IOIHelper
2830
public func foo() {}
2931
// CHECK-PUBLIC: foo()
3032
// CHECK-PRIVATE: foo()
@@ -155,6 +157,11 @@ extension PublicType: SPIProto2 where T: SPIProto2 {}
155157
// CHECK-PRIVATE: extension PublicType : {{.*}}.SPIProto2 where T : {{.*}}.SPIProto2
156158
// CHECK-PUBLIC-NOT: _ConstraintThatIsNotPartOfTheAPIOfThisLibrary
157159

160+
public protocol LocalPublicProto {}
161+
extension IOIPublicStruct : LocalPublicProto {}
162+
// CHECK-PRIVATE-NOT: IOIPublicStruct
163+
// CHECK-PUBLIC-NOT: IOIPublicStruct
164+
158165
// The dummy conformance should be only in the private swiftinterface for
159166
// SPI extensions.
160167
@_spi(LocalSPI)

0 commit comments

Comments
 (0)