Skip to content

Commit f5c8644

Browse files
authored
Merge pull request #74532 from xymus/access-level-imports-conformances-6.0
[6.0] Sema: Report public conformances to non-publicly imported protocols
2 parents ecda180 + c2247da commit f5c8644

14 files changed

+186
-36
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3633,7 +3633,8 @@ ERROR(decl_from_hidden_module,none,
36333633
"cannot use %kind0 %select{here|as property wrapper here|"
36343634
"as result builder here|"
36353635
"in an extension with public or '@usableFromInline' members|"
3636-
"in an extension with conditional conformances}1; "
3636+
"in an extension with conditional conformances|"
3637+
"in a public or '@usableFromInline' conformance}1; "
36373638
"%select{%2 has been imported as implementation-only|"
36383639
"it is an SPI imported from %2|"
36393640
"it is SPI|"
@@ -3647,7 +3648,8 @@ ERROR(typealias_desugars_to_type_from_hidden_module,none,
36473648
"as property wrapper here|"
36483649
"as result builder here|"
36493650
"in an extension with public or '@usableFromInline' members|"
3650-
"in an extension with conditional conformances}3 "
3651+
"in an extension with conditional conformance|"
3652+
"in a public or '@usableFromInline' conformance}3 "
36513653
"because %select{%4 has been imported as implementation-only|"
36523654
"it is an SPI imported from %4|"
36533655
"<<ERROR>>|"
@@ -3660,7 +3662,8 @@ ERROR(conformance_from_implementation_only_module,none,
36603662
"cannot use conformance of %0 to %1 %select{here|as property wrapper here|"
36613663
"as result builder here|"
36623664
"in an extension with public or '@usableFromInline' members|"
3663-
"in an extension with conditional conformances}2; "
3665+
"in an extension with conditional conformances|"
3666+
"<<ERROR>>}2; "
36643667
"%select{%3 has been imported as implementation-only|"
36653668
"the conformance is declared as SPI in %3|"
36663669
"the conformance is declared as SPI|"

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,22 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D,
248248
}
249249

250250
// Access levels from imports are reported with the others access levels.
251-
// Except for extensions, we report them here.
252-
if (originKind == DisallowedOriginKind::NonPublicImport &&
253-
reason != ExportabilityReason::ExtensionWithPublicMembers &&
254-
reason != ExportabilityReason::ExtensionWithConditionalConformances)
255-
return false;
251+
// Except for extensions and protocol conformances, we report them here.
252+
if (originKind == DisallowedOriginKind::NonPublicImport) {
253+
bool reportHere = [&] {
254+
switch (*reason) {
255+
case ExportabilityReason::ExtensionWithPublicMembers:
256+
case ExportabilityReason::ExtensionWithConditionalConformances:
257+
return true;
258+
case ExportabilityReason::Inheritance:
259+
return isa<ProtocolDecl>(D);
260+
default:
261+
return false;
262+
}
263+
}();
264+
if (!reportHere)
265+
return false;
266+
}
256267

257268
if (ctx.LangOpts.EnableModuleApiImportRemarks &&
258269
import.has_value() && where.isExported() &&

lib/Sema/TypeCheckAccess.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2260,7 +2260,7 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
22602260

22612261
for (TypeLoc inherited : nominal->getInherited().getEntries()) {
22622262
checkType(inherited.getType(), inherited.getTypeRepr(), nominal,
2263-
ExportabilityReason::General, flags);
2263+
ExportabilityReason::Inheritance, flags);
22642264
}
22652265
}
22662266

@@ -2362,7 +2362,7 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
23622362
// must be exported.
23632363
for (TypeLoc inherited : ED->getInherited().getEntries()) {
23642364
checkType(inherited.getType(), inherited.getTypeRepr(), ED,
2365-
ExportabilityReason::General,
2365+
ExportabilityReason::Inheritance,
23662366
DeclAvailabilityFlag::AllowPotentiallyUnavailableProtocol);
23672367
}
23682368

lib/Sema/TypeCheckAvailability.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ enum class ExportabilityReason : unsigned {
7272
PropertyWrapper,
7373
ResultBuilder,
7474
ExtensionWithPublicMembers,
75-
ExtensionWithConditionalConformances
75+
ExtensionWithConditionalConformances,
76+
Inheritance
7677
};
7778

7879
/// A description of the restrictions on what declarations can be referenced

test/SPI/implementation_only_spi_import_exposability.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ public protocol IOIProtocol {}
3232
@_spi(B) public func leakSPIStruct(_ a: SPIStruct) -> SPIStruct { fatalError() } // expected-warning 2 {{cannot use struct 'SPIStruct' here; 'Lib' has been imported as implementation-only}}
3333
@_spi(B) public func leakIOIStruct(_ a: IOIStruct) -> IOIStruct { fatalError() } // expected-warning 2 {{cannot use struct 'IOIStruct' here; 'Lib' has been imported as implementation-only}}
3434

35-
public struct PublicStruct : IOIProtocol, SPIProtocol { // expected-error {{cannot use protocol 'IOIProtocol' here; 'Lib' has been imported as implementation-only}}
36-
// expected-error @-1 {{cannot use protocol 'SPIProtocol' here; 'Lib' has been imported as implementation-only}}
35+
public struct PublicStruct : IOIProtocol, SPIProtocol { // expected-error {{cannot use protocol 'IOIProtocol' in a public or '@usableFromInline' conformance; 'Lib' has been imported as implementation-only}}
36+
// expected-error @-1 {{cannot use protocol 'SPIProtocol' in a public or '@usableFromInline' conformance; 'Lib' has been imported as implementation-only}}
3737
public var spiStruct = SPIStruct() // expected-error {{cannot use struct 'SPIStruct' here; 'Lib' has been imported as implementation-only}}
3838
public var ioiStruct = IOIStruct() // expected-error {{cannot use struct 'IOIStruct' here; 'Lib' has been imported as implementation-only}}
3939

@@ -49,8 +49,8 @@ public struct PublicStruct : IOIProtocol, SPIProtocol { // expected-error {{cann
4949
}
5050

5151
@_spi(B)
52-
public struct LocalSPIStruct : IOIProtocol, SPIProtocol { // expected-warning {{cannot use protocol 'IOIProtocol' here; 'Lib' has been imported as implementation-only}}
53-
// expected-warning @-1 {{cannot use protocol 'SPIProtocol' here; 'Lib' has been imported as implementation-only}}
52+
public struct LocalSPIStruct : IOIProtocol, SPIProtocol { // expected-warning {{cannot use protocol 'IOIProtocol' in a public or '@usableFromInline' conformance; 'Lib' has been imported as implementation-only}}
53+
// expected-warning @-1 {{cannot use protocol 'SPIProtocol' in a public or '@usableFromInline' conformance; 'Lib' has been imported as implementation-only}}
5454
}
5555

5656
#endif

test/SPI/local_spi_decls.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ private protocol PrivateProtocol {} // expected-note {{type declared here}}
7070

7171
@_spi(S) public class BadSubclass : InternalClass {} // expected-error{{class cannot be declared public because its superclass is internal}}
7272
@_spi(S) public class OkSPISubclass : SPIClass {} // OK
73-
public class BadPublicClass : SPIClass {} // expected-error {{cannot use class 'SPIClass' here; it is SPI}}
73+
public class BadPublicClass : SPIClass {} // expected-error {{cannot use class 'SPIClass' in a public or '@usableFromInline' conformance; it is SPI}}
7474
@_spi(S) public class BadSPIClass : PrivateClass {} // expected-error {{class cannot be declared public because its superclass is private}}
7575

7676
@_spi(s) public func genFunc<T: PrivateProtocol>(_ t: T) {} // expected-error {{global function cannot be declared public because its generic parameter uses a private type}}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend -emit-module -o %t/NormalLibrary.swiftmodule \
4+
// RUN: %S/Inputs/implementation-only-import-in-decls-public-helper.swift \
5+
// RUN: -enable-library-evolution -swift-version 5
6+
7+
// RUN: %target-swift-frontend -emit-module -o %t/BADLibrary.swiftmodule \
8+
// RUN: %S/Inputs/implementation-only-import-in-decls-helper.swift -I %t \
9+
// RUN: -enable-library-evolution -swift-version 5
10+
11+
// RUN: %target-typecheck-verify-swift -I %t \
12+
// RUN: -swift-version 5 -package-name pkg -enable-library-evolution
13+
// RUN: %target-typecheck-verify-swift -I %t \
14+
// RUN: -swift-version 5 -package-name pkg
15+
16+
internal import BADLibrary // expected-note 9 {{protocol 'BadProto' imported as 'internal' from 'BADLibrary' here}}
17+
// expected-note @-1 2 {{struct 'IntLike' imported as 'internal' from 'BADLibrary' here}}
18+
// expected-note @-2 2 {{class 'BadClass' imported as 'internal' from 'BADLibrary' here}}
19+
20+
public protocol LocalProto {}
21+
22+
public struct TestConformance: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}}
23+
public struct TestConformanceComposition: LocalProto & BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}}
24+
25+
@usableFromInline struct TestConformanceUFI: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}}
26+
27+
public class TestConformanceClass: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}}
28+
public enum TestConformanceEnum: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}}
29+
30+
public struct TestExtensionStruct {}
31+
extension TestExtensionStruct: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}}
32+
33+
package struct TestConformancePackage: BadProto {} // FIXME-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}}
34+
package struct TestConformanceCompositionPackage: LocalProto & BadProto {} // FIXME-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}}
35+
36+
@usableFromInline struct TestConformanceUFIPackage: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}}
37+
38+
package class TestConformanceClassPackage: BadProto {} // FIXME-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}}
39+
package enum TestConformanceEnumPackage: BADLibrary.BadProto {} // FIXME-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}}
40+
41+
package struct TestExtensionStructPackage {}
42+
extension TestExtensionStructPackage: BadProto {} // FIXME-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}}
43+
44+
/// Other inheritance types are covered by the classic access-level check.
45+
46+
public class TestSubclass: BadClass { // expected-error {{class cannot be declared public because its superclass is internal}}
47+
// expected-note @-1 {{class 'BadClass' is imported by this file as 'internal' from 'BADLibrary'}}
48+
}
49+
50+
public enum TestRawType: IntLike { // expected-error {{enum cannot be declared public because its raw type uses an internal type}}
51+
// expected-note @-1 {{struct 'IntLike' is imported by this file as 'internal' from 'BADLibrary'}}
52+
case x = 1
53+
}
54+
55+
public protocol TestRefinedProto: BadProto { // expected-error {{public protocol cannot refine an internal protocol}}
56+
// expected-note @-1 {{protocol 'BadProto' is imported by this file as 'internal' from 'BADLibrary'}}
57+
}
58+
59+
package class TestSubclassPackage: BadClass { // expected-error {{class cannot be declared package because its superclass is internal}}
60+
// expected-note @-1 {{class 'BadClass' is imported by this file as 'internal' from 'BADLibrary'}}
61+
}
62+
63+
package enum TestRawTypePackage: IntLike { // expected-error {{enum cannot be declared package because its raw type uses an internal type}}
64+
// expected-note @-1 {{struct 'IntLike' is imported by this file as 'internal' from 'BADLibrary'}}
65+
case x = 1
66+
}
67+
68+
package protocol TestRefinedProtoPackage: BadProto { // expected-error {{package protocol cannot refine an internal protocol}}
69+
// expected-note @-1 {{protocol 'BadProto' is imported by this file as 'internal' from 'BADLibrary'}}
70+
}

test/Sema/access-level-import-typealias.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,10 @@ public typealias ClazzAlias = Clazz
2424
public import Aliases
2525
internal import Original // expected-note 2 {{class 'Clazz' imported as 'internal' from 'Original' here}}
2626

27-
// expected-error@+1 {{'ClazzAlias' aliases 'Original.Clazz' and cannot be used here because 'Original' was not imported publicly}}
27+
// expected-error@+1 {{'ClazzAlias' aliases 'Original.Clazz' and cannot be used in a public or '@usableFromInline' conformance because 'Original' was not imported publicly}}
2828
public class InheritsFromClazzAlias: ClazzAlias {}
2929

3030
@inlinable public func inlinableFunc() {
3131
// expected-error@+1 {{'ClazzAlias' aliases 'Original.Clazz' and cannot be used in an '@inlinable' function because 'Original' was not imported publicly}}
3232
_ = ClazzAlias.self
3333
}
34-

test/Sema/implementation-only-import-in-decls.swift

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,14 @@ import NormalLibrary
1111
@_implementationOnly import BADLibrary
1212
// expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}}
1313

14-
public struct TestConformance: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}}
14+
public struct TestConformance: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' has been imported as implementation-only}}
1515

16-
@usableFromInline struct TestConformanceUFI: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}}
16+
@usableFromInline struct TestConformanceUFI: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' has been imported as implementation-only}}
1717

1818
struct TestConformanceOkay: BadProto {} // ok
1919

20-
public class TestConformanceClass: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}}
21-
public enum TestConformanceEnum: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}}
22-
20+
public class TestConformanceClass: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' has been imported as implementation-only}}
21+
public enum TestConformanceEnum: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' has been imported as implementation-only}}
2322

2423
public struct TestGenericParams<T: BadProto> {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}}
2524

@@ -75,11 +74,11 @@ public protocol TestAssocTypeWhereClause {
7574
associatedtype Assoc: Collection where Assoc.Element: BadProto // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}}
7675
}
7776

78-
public enum TestRawType: IntLike { // expected-error {{cannot use struct 'IntLike' here; 'BADLibrary' has been imported as implementation-only}}
77+
public enum TestRawType: IntLike { // expected-error {{cannot use struct 'IntLike' in a public or '@usableFromInline' conformance; 'BADLibrary' has been imported as implementation-only}}
7978
case x = 1
8079
}
8180

82-
public class TestSubclass: BadClass { // expected-error {{cannot use class 'BadClass' here; 'BADLibrary' has been imported as implementation-only}}
81+
public class TestSubclass: BadClass { // expected-error {{cannot use class 'BadClass' in a public or '@usableFromInline' conformance; 'BADLibrary' has been imported as implementation-only}}
8382
}
8483

8584
public typealias TestUnderlying = BadStruct // expected-error {{cannot use struct 'BadStruct' here; 'BADLibrary' has been imported as implementation-only}}
@@ -121,7 +120,7 @@ extension Array where Element == BadStruct {
121120
subscript(okay _: Int) -> Int { 0 } // okay
122121
}
123122

124-
extension Int: @retroactive BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}}
123+
extension Int: @retroactive BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' has been imported as implementation-only}}
125124
struct TestExtensionConformanceOkay {}
126125
extension TestExtensionConformanceOkay: BadProto {} // okay
127126

test/Sema/missing-import-typealias-swift6.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ public typealias ClazzAlias = Clazz
2828

2929
public import Aliases
3030

31-
// expected-error@+1 {{'ClazzAlias' aliases 'Original.Clazz' and cannot be used here because 'Original' was not imported by this file}}
31+
// expected-error@+1 {{'ClazzAlias' aliases 'Original.Clazz' and cannot be used in a public or '@usableFromInline' conformance because 'Original' was not imported by this file}}
3232
public class InheritsFromClazzAlias: ClazzAlias {}
3333

test/Sema/missing-import-typealias.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ import Aliases
6666

6767
// CHECK-NON-RESILIENT-NOT: was not imported by this file
6868

69-
// expected-warning@+2 {{'ClazzAlias' aliases 'Original.Clazz' and cannot be used here because 'Original' was not imported by this file; this is an error in the Swift 6 language mode}}
69+
// expected-warning@+2 {{'ClazzAlias' aliases 'Original.Clazz' and cannot be used in a public or '@usableFromInline' conformance because 'Original' was not imported by this file; this is an error in the Swift 6 language mode}}
7070
// expected-note@+1 {{The missing import of module 'Original' will be added implicitly}}
7171
public class InheritsFromClazzAlias: ClazzAlias {}
7272

0 commit comments

Comments
 (0)