mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()),
|
||||||
|
|||||||
Reference in New Issue
Block a user