Skip to content

Commit 2b5ada1

Browse files
authored
Correctly calculate extra inhabitants for no-payload enums (#28830)
In particular, this fixes the size calculation for nested enums, specifically enums within Optionals. Without this, the reflection library computes `v` below as requiring two bytes instead of one. ``` enum E { case a case b } let v = Optional<E> ``` This also adds a number of test cases for enums alone and wrapped in optionals, including: * Zero-case enums are allocated zero size and have zero extra inhabitants * Zero-case enums in optionals also get zero size * One-case no-payload enums are allocated zero size and have zero extra inhabitants * One-case no-payload enums in optionals get one byte allocated and have zero extra inhabitants * 254-case enums have only two extra inhabitants, so putting them in thrice-nested optionals requires an extra byte * Various cases where each nested optional gets an extra byte Resolves rdar://31154770
1 parent 9b59996 commit 2b5ada1

9 files changed

+1211
-6
lines changed

stdlib/public/Reflection/TypeLowering.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,10 +1007,22 @@ class EnumTypeInfoBuilder {
10071007
// NoPayloadEnumImplStrategy
10081008
if (PayloadCases.empty()) {
10091009
Kind = RecordKind::NoPayloadEnum;
1010-
Size += getEnumTagCounts(/*size=*/0,
1011-
NoPayloadCases,
1012-
/*payloadCases=*/0).numTagBytes;
1013-
1010+
switch (NoPayloadCases) {
1011+
case 0:
1012+
case 1: // Zero or one tag has size = 0, extra_inhab = 0
1013+
NumExtraInhabitants = 0;
1014+
break;
1015+
default: { // 2 or more tags
1016+
auto tagCounts = getEnumTagCounts(/*size=*/0,
1017+
NoPayloadCases,
1018+
/*payloadCases=*/0);
1019+
Size += tagCounts.numTagBytes;
1020+
NumExtraInhabitants =
1021+
(1 << (tagCounts.numTagBytes * 8)) - tagCounts.numTags;
1022+
NumExtraInhabitants = std::min(NumExtraInhabitants,
1023+
unsigned(ValueWitnessFlags::MaxNumExtraInhabitants));
1024+
}
1025+
}
10141026
// SinglePayloadEnumImplStrategy
10151027
} else if (PayloadCases.size() == 1) {
10161028
auto *CaseTR = getCaseTypeRef(PayloadCases[0]);

test/Reflection/typeref_lowering.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,9 +1039,9 @@
10391039
// CHECK-64-NEXT: (field name=empty offset=0
10401040
// CHECK-64-NEXT: (no_payload_enum size=0 alignment=1 stride=1 num_extra_inhabitants=0 bitwise_takable=1))
10411041
// CHECK-64-NEXT: (field name=noPayload offset=0
1042-
// CHECK-64-NEXT: (no_payload_enum size=1 alignment=1 stride=1 num_extra_inhabitants=0 bitwise_takable=1))
1042+
// CHECK-64-NEXT: (no_payload_enum size=1 alignment=1 stride=1 num_extra_inhabitants=252 bitwise_takable=1))
10431043
// CHECK-64-NEXT: (field name=sillyNoPayload offset=1
1044-
// CHECK-64-NEXT: (no_payload_enum size=1 alignment=1 stride=1 num_extra_inhabitants=0 bitwise_takable=1))
1044+
// CHECK-64-NEXT: (no_payload_enum size=1 alignment=1 stride=1 num_extra_inhabitants=252 bitwise_takable=1))
10451045
// CHECK-64-NEXT: (field name=singleton offset=8
10461046
// CHECK-64-NEXT: (reference kind=strong refcounting=native))
10471047
// CHECK-64-NEXT: (field name=singlePayload offset=16

0 commit comments

Comments
 (0)