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