Skip to content

Commit

Permalink
[Mirror] Handle fields of thin metatypes.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mikeash committed Sep 6, 2024
1 parent 350c1ce commit 65a512b
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 0 deletions.
23 changes: 23 additions & 0 deletions stdlib/public/runtime/ReflectionMirror.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
43 changes: 43 additions & 0 deletions test/stdlib/Mirror.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
// REQUIRES: reflection

// rdar://96439408
// UNSUPPORTED: back_deployment_runtime
// UNSUPPORTED: use_os_stdlib

import StdlibUnittest
Expand Down Expand Up @@ -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 -----------------------------------------------------------===//
//===----------------------------------------------------------------------===//

Expand Down

0 comments on commit 65a512b

Please sign in to comment.