Skip to content

Commit e087704

Browse files
authored
Merge pull request #40382 from slavapestov/disable-rawrepresentable-enum-equal-synthesis
Sema: Narrow down the derivation of == for RawRepresentable enums to non-resilient modules
2 parents d27e6e1 + 2256c80 commit e087704

File tree

2 files changed

+60
-40
lines changed

2 files changed

+60
-40
lines changed

lib/Sema/TypeCheckProtocol.cpp

+24-13
Original file line numberDiff line numberDiff line change
@@ -4104,6 +4104,11 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
41044104
}
41054105
}
41064106

4107+
static bool isSwiftRawRepresentableEnum(Type adoptee) {
4108+
auto *enumDecl = dyn_cast<EnumDecl>(adoptee->getAnyNominal());
4109+
return (enumDecl && enumDecl->hasRawType() && !enumDecl->isObjC());
4110+
}
4111+
41074112
// If the given witness matches a generic RawRepresentable function conforming
41084113
// with a given protocol e.g. `func == <T : RawRepresentable>(lhs: T, rhs: T) ->
41094114
// Bool where T.RawValue : Equatable`
@@ -4182,13 +4187,8 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
41824187
!requirement->getAttrs().isUnavailable(getASTContext());
41834188

41844189
auto &ctx = getASTContext();
4185-
bool isEquatableConformance = Conformance->getProtocol() ==
4186-
ctx.getProtocol(KnownProtocolKind::Equatable);
4187-
4188-
auto decl = Conformance->getDeclContext()->getSelfNominalTypeDecl();
4189-
auto *enumDecl = dyn_cast_or_null<EnumDecl>(decl);
4190-
bool isSwiftRawRepresentableEnum =
4191-
enumDecl && enumDecl->hasRawType() && !enumDecl->isObjC();
4190+
bool isEquatableConformance = (Conformance->getProtocol() ==
4191+
ctx.getProtocol(KnownProtocolKind::Equatable));
41924192

41934193
if (findBestWitness(requirement,
41944194
considerRenames ? &ignoringNames : nullptr,
@@ -4198,12 +4198,23 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
41984198
const auto &best = matches[bestIdx];
41994199
auto witness = best.Witness;
42004200

4201-
if (canDerive && isSwiftRawRepresentableEnum && isEquatableConformance) {
4202-
// For swift enum types that can derive equatable conformance,
4203-
// if the best witness is default generic conditional conforming
4204-
// `func == <T : RawRepresentable>(lhs: T, rhs: T) -> Bool where
4205-
// T.RawValue : Equatable` let's return as missing and derive
4206-
// the conformance since it is possible.
4201+
if (canDerive &&
4202+
isEquatableConformance &&
4203+
isSwiftRawRepresentableEnum(Adoptee) &&
4204+
!Conformance->getDeclContext()->getParentModule()->isResilient()) {
4205+
// For swift enum types that can derive an Equatable conformance,
4206+
// if the best witness is the default implementation
4207+
//
4208+
// func == <T : RawRepresentable>(lhs: T, rhs: T) -> Bool
4209+
// where T.RawValue : Equatable
4210+
//
4211+
// let's return as missing and derive the conformance, since it will be
4212+
// more efficient than comparing rawValues.
4213+
//
4214+
// However, we only do this if the module is non-resilient. If it is
4215+
// resilient, this change can break ABI by publishing a synthesized ==
4216+
// declaration that may not exist in versions of the framework built
4217+
// with an older compiler.
42074218
if (isRawRepresentableGenericFunction(ctx, witness, Conformance)) {
42084219
return ResolveWitnessResult::Missing;
42094220
}
+36-27
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,79 @@
1-
// RUN: %target-swift-emit-silgen -module-name main %s -verify | %FileCheck %s
1+
// RUN: %target-swift-emit-silgen -module-name main %s -verify | %FileCheck %s --check-prefix=FRAGILE
2+
// RUN: %target-swift-emit-silgen -module-name main %s -verify -enable-library-evolution | %FileCheck %s --check-prefix=RESILIENT
3+
24
// SR-9425
3-
enum MyState : String {
5+
public enum MyState : String {
46
case closed = "closed"
57
case opened = "opened"
68
}
79

8-
@inline(never)
9-
func check_state(_ state : MyState) -> Int {
10-
// CHECK: function_ref @$s4main7MyStateO21__derived_enum_equalsySbAC_ACtFZ
10+
// CHECK-LABEL: sil [ossa] @$s4main11check_stateySiAA7MyStateOF : $@convention(thin) (MyState) -> Int {
11+
public func check_state(_ state : MyState) -> Int {
12+
// FRAGILE: function_ref @$s4main7MyStateO21__derived_enum_equalsySbAC_ACtFZ
13+
// RESILIENT: function_ref @$ss2eeoiySbx_xtSYRzSQ8RawValueRpzlF
1114
return state == .opened ? 1 : 0
1215
}
1316

1417
// generic-enum.swift
15-
enum GenericMyState<T> : String {
18+
public enum GenericMyState<T> : String {
1619
case closed
1720
case opened
1821
}
1922

20-
@inline(never)
21-
func check_generic_state(_ state : GenericMyState<Int>) -> Int {
22-
// CHECK: function_ref @$s4main14GenericMyStateO21__derived_enum_equalsySbACyxG_AEtFZ
23+
// CHECK-LABEL: sil [ossa] @$s4main19check_generic_stateySiAA14GenericMyStateOySiGF : $@convention(thin) (GenericMyState<Int>) -> Int {
24+
public func check_generic_state(_ state : GenericMyState<Int>) -> Int {
25+
// FRAGILE: function_ref @$s4main14GenericMyStateO21__derived_enum_equalsySbACyxG_AEtFZ
26+
// RESILIENT: function_ref @$ss2eeoiySbx_xtSYRzSQ8RawValueRpzlF
2327
return state == .opened ? 1 : 0
2428
}
2529

2630
// regular-enum.swift
27-
enum Regular {
31+
public enum Regular {
2832
case closed
2933
case opened
3034
}
3135

32-
@inline(never)
33-
func check_regular(_ state : Regular) -> Int {
34-
// CHECK: function_ref @$s4main7RegularO21__derived_enum_equalsySbAC_ACtFZ
36+
// CHECK-LABEL: sil [ossa] @$s4main13check_regularySiAA7RegularOF : $@convention(thin) (Regular) -> Int {
37+
public func check_regular(_ state : Regular) -> Int {
38+
// FRAGILE: function_ref @$s4main7RegularO21__derived_enum_equalsySbAC_ACtFZ
39+
// RESILIENT: function_ref @$ss2eeoiySbx_xtSYRzSQ8RawValueRpzlF
3540
return state == .closed ? 1 : 0
3641
}
3742

3843
// string-enum.swift
39-
enum Alphabet : String {
44+
public enum Alphabet : String {
4045
case A = "A", B = "B", C = "C", D = "D", E = "E", F = "F", G = "G", H = "H", I = "I", J = "J"
4146
}
4247

43-
@inline(never)
44-
func check_alphabet(_ state : Alphabet) -> Int {
45-
// CHECK: function_ref @$s4main8AlphabetO21__derived_enum_equalsySbAC_ACtFZ
48+
// CHECK-LABEL: sil [ossa] @$s4main14check_alphabetySiAA8AlphabetOF : $@convention(thin) (Alphabet) -> Int {
49+
public func check_alphabet(_ state : Alphabet) -> Int {
50+
// FRAGILE: function_ref @$s4main8AlphabetO21__derived_enum_equalsySbAC_ACtFZ
51+
// RESILIENT: function_ref @$ss2eeoiySbx_xtSYRzSQ8RawValueRpzlF
4652
return state == .E ? 1 : 0
4753
}
4854

49-
@inline(never)
50-
func compareIt(_ state : Alphabet, _ rhs: Alphabet) -> Bool {
51-
// CHECK: function_ref @$s4main8AlphabetO21__derived_enum_equalsySbAC_ACtFZ
55+
// CHECK-LABEL: sil [ossa] @$s4main9compareItySbAA8AlphabetO_ADtF : $@convention(thin) (Alphabet, Alphabet) -> Bool {
56+
public func compareIt(_ state : Alphabet, _ rhs: Alphabet) -> Bool {
57+
// FRAGILE: function_ref @$s4main8AlphabetO21__derived_enum_equalsySbAC_ACtFZ
58+
// RESILIENT: function_ref @$ss2eeoiySbx_xtSYRzSQ8RawValueRpzlF
5259
return state == rhs
5360
}
5461

5562
// int-enum.swift
56-
enum AlphabetInt : Int {
63+
public enum AlphabetInt : Int {
5764
case A = 10, B = 100, C = 12, D = 456, E = 1, F = 3, G = 77, H = 2, I = 27, J = 42
5865
}
5966

60-
@inline(never)
61-
func check_alphabet_int(_ state : AlphabetInt) -> Int {
62-
// CHECK: function_ref @$s4main11AlphabetIntO21__derived_enum_equalsySbAC_ACtFZ
67+
// CHECK-LABEL: sil [ossa] @$s4main18check_alphabet_intySiAA11AlphabetIntOF : $@convention(thin) (AlphabetInt) -> Int {
68+
public func check_alphabet_int(_ state : AlphabetInt) -> Int {
69+
// FRAGILE: function_ref @$s4main11AlphabetIntO21__derived_enum_equalsySbAC_ACtFZ
70+
// RESILIENT: function_ref @$ss2eeoiySbx_xtSYRzSQ8RawValueRpzlF
6371
return state == .E ? 1 : 0
6472
}
6573

66-
@inline(never)
67-
func compareIt(_ state : AlphabetInt, _ rhs: AlphabetInt) -> Bool {
68-
// CHECK: function_ref @$s4main11AlphabetIntO21__derived_enum_equalsySbAC_ACtFZ
74+
// CHECK-LABEL: sil [ossa] @$s4main9compareItySbAA11AlphabetIntO_ADtF : $@convention(thin) (AlphabetInt, AlphabetInt) -> Bool {
75+
public func compareIt(_ state : AlphabetInt, _ rhs: AlphabetInt) -> Bool {
76+
// FRAGILE: function_ref @$s4main11AlphabetIntO21__derived_enum_equalsySbAC_ACtFZ
77+
// RESILIENT: function_ref @$ss2eeoiySbx_xtSYRzSQ8RawValueRpzlF
6978
return state == rhs
7079
}

0 commit comments

Comments
 (0)