Skip to content

Commit 1a2beb7

Browse files
committed
IRGen: Fix extensions of resilient enums
We need to arrange enum type metadata in a way where a client can fish out generic parameters without knowing if we have a payload size or not. The payload size is only used inside the module that defined the enum, and may change if new cases are added. So put the generic parameters first before the payload size, and don't crash when an EnumMetadataScanner is used with a resilient enum.
1 parent 9638a1c commit 1a2beb7

File tree

5 files changed

+47
-5
lines changed

5 files changed

+47
-5
lines changed

lib/IRGen/EnumMetadataLayout.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@ template <class Impl> class EnumMetadataLayout : public MetadataLayout<Impl> {
5252
// emitParentMetadataRef.
5353

5454
// Instantiation-specific.
55-
55+
56+
// Add fields for generic cases.
57+
asImpl().addGenericFields(Target, Target->getDeclaredTypeInContext());
58+
5659
// Reserve a word to cache the payload size if the type has dynamic layout.
5760
auto &strategy = getEnumImplStrategy(IGM,
5861
Target->DeclContext::getDeclaredTypeInContext()->getCanonicalType());
5962
if (strategy.needsPayloadSizeInMetadata())
6063
asImpl().addPayloadSize();
61-
62-
// Add fields for generic cases.
63-
asImpl().addGenericFields(Target, Target->getDeclaredTypeInContext());
6464
}
6565
};
6666

lib/IRGen/GenEnum.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4656,7 +4656,7 @@ namespace {
46564656
}
46574657

46584658
bool needsPayloadSizeInMetadata() const override {
4659-
llvm_unreachable("resilient enums cannot be defined");
4659+
return false;
46604660
}
46614661

46624662
void initializeMetadata(IRGenFunction &IGF,

test/IRGen/enum_resilience.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,4 +239,17 @@ public func getResilientEnumType() -> Any.Type {
239239
// CHECK-NEXT: [[RESULT:%.*]] = phi %swift.type* [ [[METADATA]], %entry ], [ [[METADATA2]], %cacheIsNull ]
240240
// CHECK-NEXT: ret %swift.type* [[RESULT]]
241241

242+
// Methods inside extensions of resilient enums fish out type parameters
243+
// from metadata -- make sure we can do that
244+
extension ResilientMultiPayloadGenericEnum {
245+
246+
// CHECK-LABEL: define{{( protected)?}} %swift.type* @_TFE15enum_resilienceO14resilient_enum32ResilientMultiPayloadGenericEnum16getTypeParameterfT_Mx(%swift.type* %"ResilientMultiPayloadGenericEnum<T>", %swift.opaque* noalias nocapture)
247+
// CHECK: [[METADATA:%.*]] = bitcast %swift.type* %"ResilientMultiPayloadGenericEnum<T>" to %swift.type**
248+
// CHECK-NEXT: [[T_ADDR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[METADATA]], [[INT]] 3
249+
// CHECK-NEXT: [[T:%.*]] = load %swift.type*, %swift.type** [[T_ADDR]]
250+
public func getTypeParameter() -> T.Type {
251+
return T.self
252+
}
253+
}
254+
242255
// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_EnumWithResilientPayload(i8*)

test/Inputs/resilient_enum.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,14 @@ public enum ResilientMultiPayloadGenericEnum<T> {
185185
case Y(T) // -2
186186
}
187187

188+
public enum ResilientMultiPayloadGenericEnumFixedSize<T> {
189+
case A // 0
190+
case B // 1
191+
case C // 2
192+
case X(Int) // -1
193+
case Y(Int) // -2
194+
}
195+
188196
public enum ResilientIndirectEnum {
189197
// 0
190198
case Base

test/Interpreter/enum_resilience.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,4 +404,25 @@ ResilientEnumTestSuite.test("ResilientEnumWithEmptyCase") {
404404
expectEqual(b, [0, 1, 2])
405405
}
406406

407+
// Methods inside extensions of resilient enums fish out type parameters
408+
// from metadata -- make sure we can do that
409+
extension ResilientMultiPayloadGenericEnum {
410+
public func getTypeParameter() -> T.Type {
411+
return T.self
412+
}
413+
}
414+
415+
extension ResilientMultiPayloadGenericEnumFixedSize {
416+
public func getTypeParameter() -> T.Type {
417+
return T.self
418+
}
419+
}
420+
421+
class Base {}
422+
423+
ResilientEnumTestSuite.test("ResilientEnumExtension") {
424+
expectEqual(Base.self, ResilientMultiPayloadGenericEnum<Base>.A.getTypeParameter())
425+
expectEqual(Base.self, ResilientMultiPayloadGenericEnumFixedSize<Base>.A.getTypeParameter())
426+
}
427+
407428
runAllTests()

0 commit comments

Comments
 (0)