IRGen: Fix reflection metadata for zero-sized enum cases

If an enum has a payload case with zero size, we treat it as an empty case
for ABI purposes. Unfortunately, this meant that reflection metadata was
incomplete for such cases, with a Mirror reporting that the enum value
had zero children.

Tweak the field type metadata emission slightly to preserve the payload
type for such enum cases.

Fixes <https://bugs.swift.org/browse/SR-12044> / <rdar://problem/58861157>.
This commit is contained in:
Slava Pestov
2020-02-17 23:23:10 -05:00
parent d8bc35bc0a
commit 5b6a050e80
3 changed files with 34 additions and 7 deletions

View File

@@ -673,7 +673,7 @@ private:
const NominalTypeDecl *NTD; const NominalTypeDecl *NTD;
void addFieldDecl(const ValueDecl *value, Type type, void addFieldDecl(const ValueDecl *value, Type type,
GenericSignature genericSig, bool indirect=false) { bool indirect=false) {
reflection::FieldRecordFlags flags; reflection::FieldRecordFlags flags;
flags.setIsIndirectCase(indirect); flags.setIsIndirectCase(indirect);
if (auto var = dyn_cast<VarDecl>(value)) if (auto var = dyn_cast<VarDecl>(value))
@@ -684,6 +684,8 @@ private:
if (!type) { if (!type) {
B.addInt32(0); B.addInt32(0);
} else { } else {
auto genericSig = NTD->getGenericSignature();
// The standard library's Mirror demangles metadata from field // The standard library's Mirror demangles metadata from field
// descriptors, so use MangledTypeRefRole::Metadata to ensure // descriptors, so use MangledTypeRefRole::Metadata to ensure
// runtime metadata is available. // runtime metadata is available.
@@ -717,8 +719,7 @@ private:
auto properties = NTD->getStoredProperties(); auto properties = NTD->getStoredProperties();
B.addInt32(properties.size()); B.addInt32(properties.size());
for (auto property : properties) for (auto property : properties)
addFieldDecl(property, property->getInterfaceType(), addFieldDecl(property, property->getInterfaceType());
NTD->getGenericSignature());
} }
void layoutEnum() { void layoutEnum() {
@@ -743,12 +744,11 @@ private:
bool indirect = (enumCase.decl->isIndirect() || bool indirect = (enumCase.decl->isIndirect() ||
enumDecl->isIndirect()); enumDecl->isIndirect());
addFieldDecl(enumCase.decl, enumCase.decl->getArgumentInterfaceType(), addFieldDecl(enumCase.decl, enumCase.decl->getArgumentInterfaceType(),
enumDecl->getGenericSignature(),
indirect); indirect);
} }
for (auto enumCase : strategy.getElementsWithNoPayload()) { for (auto enumCase : strategy.getElementsWithNoPayload()) {
addFieldDecl(enumCase.decl, CanType(), nullptr); addFieldDecl(enumCase.decl, enumCase.decl->getArgumentInterfaceType());
} }
} }

View File

@@ -1041,7 +1041,11 @@
// CHECK-64-NEXT: (field name=noPayload offset=0 // CHECK-64-NEXT: (field name=noPayload offset=0
// CHECK-64-NEXT: (no_payload_enum size=1 alignment=1 stride=1 num_extra_inhabitants=252 bitwise_takable=1)) // CHECK-64-NEXT: (no_payload_enum size=1 alignment=1 stride=1 num_extra_inhabitants=252 bitwise_takable=1))
// CHECK-64-NEXT: (field name=sillyNoPayload offset=1 // CHECK-64-NEXT: (field name=sillyNoPayload offset=1
// CHECK-64-NEXT: (no_payload_enum size=1 alignment=1 stride=1 num_extra_inhabitants=252 bitwise_takable=1)) // CHECK-64-NEXT: (multi_payload_enum size=1 alignment=1 stride=1 num_extra_inhabitants=252 bitwise_takable=1
// CHECK-64-NEXT: (field name=A offset=0
// CHECK-64-NEXT: (no_payload_enum size=0 alignment=1 stride=1 num_extra_inhabitants=0 bitwise_takable=1))
// CHECK-64-NEXT: (field name=B offset=0
// CHECK-64-NEXT: (no_payload_enum size=0 alignment=1 stride=1 num_extra_inhabitants=0 bitwise_takable=1))))
// CHECK-64-NEXT: (field name=singleton offset=8 // CHECK-64-NEXT: (field name=singleton offset=8
// CHECK-64-NEXT: (reference kind=strong refcounting=native)) // CHECK-64-NEXT: (reference kind=strong refcounting=native))
// CHECK-64-NEXT: (field name=singlePayload offset=16 // CHECK-64-NEXT: (field name=singlePayload offset=16

View File

@@ -1145,6 +1145,28 @@ mirrors.test("Enum/SingletonNonGeneric/DefaultMirror") {
} }
} }
enum ZeroSizedEnumWithDefaultMirror {
case π
}
enum SingletonZeroSizedEnumWithDefaultMirror {
case wrap(ZeroSizedEnumWithDefaultMirror)
}
mirrors.test("Enum/SingletonZeroSizedEnumWithDefaultMirror/DefaultMirror") {
do {
let value = SingletonZeroSizedEnumWithDefaultMirror.wrap(.π)
var output = ""
dump(value, to: &output)
let expected =
"▿ Mirror.SingletonZeroSizedEnumWithDefaultMirror.wrap\n" +
" - wrap: Mirror.ZeroSizedEnumWithDefaultMirror.π\n"
expectEqual(expected, output)
}
}
enum SingletonGenericEnumWithDefaultMirror<T> { enum SingletonGenericEnumWithDefaultMirror<T> {
case OnlyOne(T) case OnlyOne(T)
} }
@@ -2222,7 +2244,8 @@ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) {
testSTSDump(STSContainer.Cases<Int>.a(.init()), testSTSDump(STSContainer.Cases<Int>.a(.init()),
STSContainer.Cases<Int>.a(.init()), STSContainer.Cases<Int>.a(.init()),
""" """
- Mirror.STSContainer<Mirror.STSOuter>.Cases<Swift.Int>.a\n Mirror.STSContainer<Mirror.STSOuter>.Cases<Swift.Int>.a
- a: Mirror.STSOuter\n
""") """)
testSTSDump(STSContainer.Cases<Int>.b(.init()), testSTSDump(STSContainer.Cases<Int>.b(.init()),