Skip to content

Commit fe3ae26

Browse files
committed
Merge remote-tracking branch 'origin/master' into master-rebranch
2 parents 275ef4f + 9bc2819 commit fe3ae26

File tree

9 files changed

+119
-2
lines changed

9 files changed

+119
-2
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
@@ -170,6 +170,24 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr,
170170
if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
171171
if (!shouldPrint(ED->getExtendedNominal(), options))
172172
return false;
173+
174+
// Skip extensions to implementation-only imported types that have
175+
// no public members.
176+
auto localModule = ED->getParentModule();
177+
auto nominalModule = ED->getExtendedNominal()->getParentModule();
178+
if (localModule != nominalModule &&
179+
localModule->isImportedImplementationOnly(nominalModule)) {
180+
181+
bool shouldPrintMembers = llvm::any_of(
182+
ED->getMembers(),
183+
[&](const Decl *member) -> bool {
184+
return shouldPrint(member, options);
185+
});
186+
187+
if (!shouldPrintMembers)
188+
return false;
189+
}
190+
173191
for (const Requirement &req : ED->getGenericRequirements()) {
174192
if (!isPublicOrUsableFromInline(req.getFirstType()))
175193
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 {

lib/Sema/CSGen.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2775,10 +2775,17 @@ namespace {
27752775
return { true, expr };
27762776
}
27772777
} collectVarRefs(CS);
2778+
27782779
closure->walk(collectVarRefs);
27792780

2780-
if (collectVarRefs.hasErrorExprs)
2781+
// If walker discovered error expressions, let's fail constraint
2782+
// genreation only if closure is going to participate
2783+
// in the type-check. This allows us to delay validation of
2784+
// multi-statement closures until body is opened.
2785+
if (shouldTypeCheckInEnclosingExpression(closure) &&
2786+
collectVarRefs.hasErrorExprs) {
27812787
return Type();
2788+
}
27822789

27832790
auto inferredType = inferClosureType(closure);
27842791
if (!inferredType || inferredType->hasError())
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)

test/expr/closure/closures.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ func anonymousClosureArgsInClosureWithArgs() {
141141
var a5 = { (_: [Int], w: [Int]) in
142142
f($0.count) // expected-error {{anonymous closure arguments cannot be used inside a closure that has explicit arguments}}
143143
f($1.count) // expected-error {{anonymous closure arguments cannot be used inside a closure that has explicit arguments; did you mean 'w'?}} {{7-9=w}}
144+
// expected-error@-1 {{cannot convert value of type 'Int' to expected argument type 'String'}}
144145
}
145146
}
146147

0 commit comments

Comments
 (0)