[Mirror] Handle fields of thin metatypes.

Fields containing metatypes with no possible subtypes are thin i.e. they have no storage. There is only one possible value they can have: the corresponding type. Mirror attempted to copy the nonexistent field value from the nonexistent storage, producing garbage. Instead, special-case thin metatypes and copy the instance type out of the metatype metadata rather than trying to copy it from the field.

rdar://108280543
This commit is contained in:
Mike Ash
2024-09-06 10:34:24 -04:00
parent 350c1ce771
commit 7d3451316a
2 changed files with 66 additions and 0 deletions

View File

@@ -171,6 +171,29 @@ static AnyReturn copyFieldContents(OpaqueValue *fieldData,
auto ownership = fieldType.getReferenceOwnership();
auto *destContainer = type->allocateBoxForExistentialIn(&outValue.Buffer);
// If the field's type is a thin metatype, then there's no actual data at
// fieldData, and we need to obtain the metatype value from the field type.
if (auto *metatype = dyn_cast<MetatypeMetadata>(type)) {
switch (metatype->InstanceType->getKind()) {
case MetadataKind::Struct:
case MetadataKind::Enum:
case MetadataKind::Optional:
case MetadataKind::Tuple:
case MetadataKind::Function:
case MetadataKind::Existential: {
// These kinds don't have subtypes and thus have thin representations.
auto asOpaque = const_cast<OpaqueValue *>(
reinterpret_cast<const OpaqueValue *>(&metatype->InstanceType));
type->vw_initializeWithCopy(destContainer, asOpaque);
return AnyReturn(outValue);
}
default:
// Other kinds have subtypes and will not have a thin representation.
break;
}
}
if (ownership.isStrong()) {
type->vw_initializeWithCopy(destContainer, fieldData);
}

View File

@@ -27,6 +27,7 @@
// REQUIRES: reflection
// rdar://96439408
// UNSUPPORTED: back_deployment_runtime
// UNSUPPORTED: use_os_stdlib
import StdlibUnittest
@@ -1669,6 +1670,48 @@ mirrors.test("MetatypeMirror") {
}
}
class MetatypeExampleClass {}
class MetatypeExampleSubclass: MetatypeExampleClass {}
final class MetatypeExampleFinalClass {}
enum MetatypeExampleEnum {}
struct MetatypeContainer {
var before = 42
var before2 = 43
var structType = String.self
var enumType = MetatypeExampleEnum.self
var tupleType = (Int, String, AnyObject).self
var functionType = (() -> Void).self
var classType = MetatypeExampleClass.self
var subclassType: MetatypeExampleClass.Type = MetatypeExampleSubclass.self
var finalClassType = MetatypeExampleFinalClass.self
var existentialType: (any Any).Type = Any.self
var existentialType2: Any.Type = Any.self
var after = 45
}
mirrors.test("MetatypeFields") {
var output = ""
let container = MetatypeContainer()
dump(container, to: &output)
expectEqual("""
▿ Mirror.MetatypeContainer
- before: 42
- before2: 43
- structType: Swift.String #0
- enumType: Mirror.MetatypeExampleEnum #1
- tupleType: (Swift.Int, Swift.String, Swift.AnyObject) #2
- functionType: () -> () #3
- classType: Mirror.MetatypeExampleClass #4
- subclassType: Mirror.MetatypeExampleSubclass #5
- finalClassType: Mirror.MetatypeExampleFinalClass #6
- existentialType: Any #7
- existentialType2: Any #7
- after: 45
""",
output)
}
//===--- Tuples -----------------------------------------------------------===//
//===----------------------------------------------------------------------===//