mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
SR-5289: Teach Mirror how to handle unowned/unmanaged references (#28368)
* SR-5289: Support reflecting weak, unowned, and unmanaged refs This refactors how we handle reference ownership when reflecting fields of struct and class objects. There are now explicit paths for each type of reference and some simple exhaustiveness checks to fail the build if a new reference type is added in the future without updating this logic.
This commit is contained in:
@@ -160,6 +160,7 @@ using TargetRelativeIndirectablePointer
|
||||
|
||||
struct HeapObject;
|
||||
class WeakReference;
|
||||
struct UnownedReference;
|
||||
|
||||
template <typename Runtime> struct TargetMetadata;
|
||||
using Metadata = TargetMetadata<InProcess>;
|
||||
@@ -645,6 +646,9 @@ public:
|
||||
// NOTE: This *is* a box for copy-on-write existentials.
|
||||
OpaqueValue *allocateBoxForExistentialIn(ValueBuffer *Buffer) const;
|
||||
|
||||
// Deallocate an out-of-line buffer box if one is present.
|
||||
void deallocateBoxForExistentialIn(ValueBuffer *Buffer) const;
|
||||
|
||||
/// Get the nominal type descriptor if this metadata describes a nominal type,
|
||||
/// or return null if it does not.
|
||||
ConstTargetMetadataPointer<Runtime, TargetTypeContextDescriptor>
|
||||
|
||||
@@ -913,55 +913,6 @@ public:
|
||||
};
|
||||
using TupleTypeFlags = TargetTupleTypeFlags<size_t>;
|
||||
|
||||
/// Field types and flags as represented in a nominal type's field/case type
|
||||
/// vector.
|
||||
class FieldType {
|
||||
typedef uintptr_t int_type;
|
||||
// Type metadata is always at least pointer-aligned, so we get at least two
|
||||
// low bits to stash flags. We could use three low bits on 64-bit, and maybe
|
||||
// some high bits as well.
|
||||
enum : int_type {
|
||||
Indirect = 1,
|
||||
Weak = 2,
|
||||
|
||||
TypeMask = ((uintptr_t)-1) & ~(alignof(void*) - 1),
|
||||
};
|
||||
int_type Data;
|
||||
|
||||
constexpr FieldType(int_type Data) : Data(Data) {}
|
||||
public:
|
||||
constexpr FieldType() : Data(0) {}
|
||||
FieldType withType(const Metadata *T) const {
|
||||
return FieldType((Data & ~TypeMask) | (uintptr_t)T);
|
||||
}
|
||||
|
||||
constexpr FieldType withIndirect(bool indirect) const {
|
||||
return FieldType((Data & ~Indirect)
|
||||
| (indirect ? Indirect : 0));
|
||||
}
|
||||
|
||||
constexpr FieldType withWeak(bool weak) const {
|
||||
return FieldType((Data & ~Weak)
|
||||
| (weak ? Weak : 0));
|
||||
}
|
||||
|
||||
bool isIndirect() const {
|
||||
return bool(Data & Indirect);
|
||||
}
|
||||
|
||||
bool isWeak() const {
|
||||
return bool(Data & Weak);
|
||||
}
|
||||
|
||||
const Metadata *getType() const {
|
||||
return (const Metadata *)(Data & TypeMask);
|
||||
}
|
||||
|
||||
int_type getIntValue() const {
|
||||
return Data;
|
||||
}
|
||||
};
|
||||
|
||||
/// Flags for exclusivity-checking operations.
|
||||
enum class ExclusivityFlags : uintptr_t {
|
||||
Read = 0x0,
|
||||
|
||||
@@ -95,6 +95,8 @@ struct ClassExistentialContainerImpl {
|
||||
using ClassExistentialContainer = ClassExistentialContainerImpl<void *>;
|
||||
using WeakClassExistentialContainer =
|
||||
ClassExistentialContainerImpl<WeakReference>;
|
||||
using UnownedClassExistentialContainer =
|
||||
ClassExistentialContainerImpl<UnownedReference>;
|
||||
|
||||
} // end swift namespace
|
||||
|
||||
|
||||
@@ -3862,6 +3862,13 @@ template <> OpaqueValue *Metadata::allocateBoxForExistentialIn(ValueBuffer *buff
|
||||
return refAndValueAddr.buffer;
|
||||
}
|
||||
|
||||
template <> void Metadata::deallocateBoxForExistentialIn(ValueBuffer *buffer) const {
|
||||
auto *vwt = getValueWitnesses();
|
||||
if (vwt->isValueInline())
|
||||
return;
|
||||
swift_deallocBox(reinterpret_cast<HeapObject *>(buffer->PrivateData[0]));
|
||||
}
|
||||
|
||||
template <> OpaqueValue *Metadata::allocateBufferIn(ValueBuffer *buffer) const {
|
||||
auto *vwt = getValueWitnesses();
|
||||
if (vwt->isValueInline())
|
||||
|
||||
@@ -50,8 +50,10 @@ public:
|
||||
|
||||
#define REF_STORAGE(Name, ...) \
|
||||
void set##Name() { Data |= Name; } \
|
||||
bool is##Name() const { return Data & Name; }
|
||||
bool is##Name() const { return Data == Name; }
|
||||
#include "swift/AST/ReferenceStorage.def"
|
||||
|
||||
bool isStrong() const { return Data == 0; }
|
||||
};
|
||||
|
||||
/// Type information consists of metadata and its ownership info,
|
||||
@@ -76,9 +78,11 @@ public:
|
||||
const Metadata *getMetadata() const { return Response.Value; }
|
||||
MetadataResponse getResponse() const { return Response; }
|
||||
|
||||
bool isWeak() const { return ReferenceOwnership.isWeak(); }
|
||||
bool isUnowned() const { return ReferenceOwnership.isUnowned(); }
|
||||
bool isUnmanaged() const { return ReferenceOwnership.isUnmanaged(); }
|
||||
#define REF_STORAGE(Name, ...) \
|
||||
bool is##Name() const { return ReferenceOwnership.is##Name(); }
|
||||
#include "swift/AST/ReferenceStorage.def"
|
||||
|
||||
bool isStrong() const { return ReferenceOwnership.isStrong(); }
|
||||
|
||||
TypeReferenceOwnership getReferenceOwnership() const {
|
||||
return ReferenceOwnership;
|
||||
|
||||
@@ -89,6 +89,29 @@ using namespace swift;
|
||||
|
||||
namespace {
|
||||
|
||||
class FieldType {
|
||||
const Metadata *type;
|
||||
bool indirect;
|
||||
TypeReferenceOwnership referenceOwnership;
|
||||
public:
|
||||
|
||||
constexpr FieldType() : type(nullptr), indirect(false), referenceOwnership() { }
|
||||
constexpr FieldType(const Metadata *T) : type(T), indirect(false), referenceOwnership() { }
|
||||
|
||||
static constexpr FieldType untypedEnumCase(bool indirect) {
|
||||
FieldType type{};
|
||||
type.indirect = indirect;
|
||||
return type;
|
||||
}
|
||||
const Metadata *getType() const { return type; }
|
||||
const TypeReferenceOwnership getReferenceOwnership() const { return referenceOwnership; }
|
||||
bool isIndirect() const { return indirect; }
|
||||
void setIndirect(bool value) { indirect = value; }
|
||||
void setReferenceOwnership(TypeReferenceOwnership newOwnership) {
|
||||
referenceOwnership = newOwnership;
|
||||
}
|
||||
};
|
||||
|
||||
/// The layout of Any.
|
||||
using Any = OpaqueExistentialContainer;
|
||||
|
||||
@@ -123,58 +146,63 @@ unwrapExistential(const Metadata *T, OpaqueValue *Value) {
|
||||
return std::make_tuple(T, Value);
|
||||
}
|
||||
|
||||
static bool loadSpecialReferenceStorage(OpaqueValue *fieldData,
|
||||
const FieldType fieldType,
|
||||
Any *outValue) {
|
||||
// isWeak() implies a reference type via Sema.
|
||||
if (!fieldType.isWeak())
|
||||
return false;
|
||||
|
||||
auto type = fieldType.getType();
|
||||
static void copyWeakFieldContents(OpaqueValue *destContainer, const Metadata *type, OpaqueValue *fieldData) {
|
||||
assert(type->getKind() == MetadataKind::Optional);
|
||||
auto *srcContainer = reinterpret_cast<WeakClassExistentialContainer*>(fieldData);
|
||||
auto *destClassContainer = reinterpret_cast<ClassExistentialContainer*>(destContainer);
|
||||
destClassContainer->Value = swift_unknownObjectWeakLoadStrong(&srcContainer->Value);
|
||||
auto witnessTablesSize = type->vw_size() - sizeof(WeakClassExistentialContainer);
|
||||
memcpy(destClassContainer->getWitnessTables(), srcContainer->getWitnessTables(), witnessTablesSize);
|
||||
}
|
||||
|
||||
auto *weakField = reinterpret_cast<WeakReference *>(fieldData);
|
||||
auto *strongValue = swift_unknownObjectWeakLoadStrong(weakField);
|
||||
static void copyUnownedFieldContents(OpaqueValue *destContainer, const Metadata *type, OpaqueValue *fieldData) {
|
||||
auto *srcContainer = reinterpret_cast<UnownedClassExistentialContainer*>(fieldData);
|
||||
auto *destClassContainer = reinterpret_cast<ClassExistentialContainer*>(destContainer);
|
||||
destClassContainer->Value = swift_unknownObjectUnownedLoadStrong(&srcContainer->Value);
|
||||
auto witnessTablesSize = type->vw_size() - sizeof(UnownedClassExistentialContainer);
|
||||
memcpy(destClassContainer->getWitnessTables(), srcContainer->getWitnessTables(), witnessTablesSize);
|
||||
}
|
||||
|
||||
// Now that we have a strong reference, we need to create a temporary buffer
|
||||
// from which to copy the whole value, which might be a native class-bound
|
||||
// existential, which means we also need to copy n witness tables, for
|
||||
// however many protocols are in the protocol composition. For example, if we
|
||||
// are copying a:
|
||||
// weak var myWeakProperty : (Protocol1 & Protocol2)?
|
||||
// then we need to copy three values:
|
||||
// - the instance
|
||||
// - the witness table for Protocol1
|
||||
// - the witness table for Protocol2
|
||||
static void copyUnmanagedFieldContents(OpaqueValue *destContainer, const Metadata *type, OpaqueValue *fieldData) {
|
||||
// Also known as "unowned(unsafe)".
|
||||
// This is simpler than the unowned/weak cases because unmanaged
|
||||
// references are fundamentally the same as strong ones, so we
|
||||
// can use the regular strong reference support that already
|
||||
// knows how to handle existentials and Obj-C references.
|
||||
type->vw_initializeWithCopy(destContainer, fieldData);
|
||||
}
|
||||
|
||||
auto *weakContainer =
|
||||
reinterpret_cast<WeakClassExistentialContainer *>(fieldData);
|
||||
static AnyReturn copyFieldContents(OpaqueValue *fieldData,
|
||||
const FieldType fieldType) {
|
||||
Any outValue;
|
||||
auto *type = fieldType.getType();
|
||||
outValue.Type = type;
|
||||
auto ownership = fieldType.getReferenceOwnership();
|
||||
auto *destContainer = type->allocateBoxForExistentialIn(&outValue.Buffer);
|
||||
|
||||
// Create a temporary existential where we can put the strong reference.
|
||||
// The allocateBuffer value witness requires a ValueBuffer to own the
|
||||
// allocated storage.
|
||||
ValueBuffer temporaryBuffer;
|
||||
if (ownership.isStrong()) {
|
||||
type->vw_initializeWithCopy(destContainer, fieldData);
|
||||
}
|
||||
|
||||
auto *temporaryValue = reinterpret_cast<ClassExistentialContainer *>(
|
||||
type->allocateBufferIn(&temporaryBuffer));
|
||||
// Generate a conditional clause for every known ownership type.
|
||||
// If this causes errors, it's because someone added a new ownership type
|
||||
// to ReferenceStorage.def and missed some related updates.
|
||||
#define REF_STORAGE(Name, ...) \
|
||||
else if (ownership.is##Name()) { \
|
||||
copy##Name##FieldContents(destContainer, type, fieldData); \
|
||||
}
|
||||
#include "swift/AST/ReferenceStorage.def"
|
||||
|
||||
// Now copy the entire value out of the parent, which will include the
|
||||
// witness tables.
|
||||
temporaryValue->Value = strongValue;
|
||||
auto valueWitnessesSize = type->getValueWitnesses()->getSize() -
|
||||
sizeof(WeakClassExistentialContainer);
|
||||
memcpy(temporaryValue->getWitnessTables(), weakContainer->getWitnessTables(),
|
||||
valueWitnessesSize);
|
||||
else {
|
||||
// The field was declared with a reference type we don't understand.
|
||||
warning(0, "Value with unrecognized reference type is reflected as ()");
|
||||
// Clean up the buffer allocated above
|
||||
type->deallocateBoxForExistentialIn(&outValue.Buffer);
|
||||
// Return an existential containing Void
|
||||
outValue.Type = &METADATA_SYM(EMPTY_TUPLE_MANGLING);
|
||||
}
|
||||
|
||||
outValue->Type = type;
|
||||
auto *opaqueValueAddr = type->allocateBoxForExistentialIn(&outValue->Buffer);
|
||||
type->vw_initializeWithCopy(opaqueValueAddr,
|
||||
reinterpret_cast<OpaqueValue *>(temporaryValue));
|
||||
|
||||
type->deallocateBufferIn(&temporaryBuffer);
|
||||
swift_unknownObjectRelease(strongValue);
|
||||
|
||||
return true;
|
||||
return AnyReturn(outValue);
|
||||
}
|
||||
|
||||
|
||||
@@ -310,11 +338,7 @@ getFieldAt(const Metadata *base, unsigned index) {
|
||||
"type '%*s' that claims to be reflectable. Its fields will show up as "
|
||||
"'unknown' in Mirrors\n",
|
||||
(int)typeName.length, typeName.data);
|
||||
return {"unknown",
|
||||
FieldType()
|
||||
.withType(&METADATA_SYM(EMPTY_TUPLE_MANGLING))
|
||||
.withIndirect(false)
|
||||
.withWeak(false)};
|
||||
return {"unknown", FieldType(&METADATA_SYM(EMPTY_TUPLE_MANGLING))};
|
||||
};
|
||||
|
||||
auto *baseDesc = base->getTypeContextDescriptor();
|
||||
@@ -325,14 +349,13 @@ getFieldAt(const Metadata *base, unsigned index) {
|
||||
if (!fields)
|
||||
return failedToFindMetadata();
|
||||
|
||||
const FieldDescriptor &descriptor = *fields;
|
||||
auto &field = descriptor.getFields()[index];
|
||||
auto &field = fields->getFields()[index];
|
||||
// Bounds are always valid as the offset is constant.
|
||||
auto name = field.getFieldName();
|
||||
|
||||
// Enum cases don't always have types.
|
||||
if (!field.hasMangledTypeName())
|
||||
return {name, FieldType().withIndirect(field.isIndirectCase())};
|
||||
return {name, FieldType::untypedEnumCase(field.isIndirectCase())};
|
||||
|
||||
auto typeName = field.getMangledTypeName();
|
||||
|
||||
@@ -360,10 +383,10 @@ getFieldAt(const Metadata *base, unsigned index) {
|
||||
(int)typeName.size(), typeName.data());
|
||||
}
|
||||
|
||||
return {name, FieldType()
|
||||
.withType(typeInfo.getMetadata())
|
||||
.withIndirect(field.isIndirectCase())
|
||||
.withWeak(typeInfo.isWeak())};
|
||||
auto fieldType = FieldType(typeInfo.getMetadata());
|
||||
fieldType.setIndirect(field.isIndirectCase());
|
||||
fieldType.setReferenceOwnership(typeInfo.getReferenceOwnership());
|
||||
return {name, fieldType};
|
||||
}
|
||||
|
||||
// Implementation for structs.
|
||||
@@ -397,7 +420,6 @@ struct StructImpl : ReflectionMirrorImpl {
|
||||
// Load the offset from its respective vector.
|
||||
auto fieldOffset = Struct->getFieldOffsets()[i];
|
||||
|
||||
Any result;
|
||||
StringRef name;
|
||||
FieldType fieldInfo;
|
||||
std::tie(name, fieldInfo) = getFieldAt(type, i);
|
||||
@@ -409,15 +431,7 @@ struct StructImpl : ReflectionMirrorImpl {
|
||||
auto *bytes = reinterpret_cast<char*>(value);
|
||||
auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
|
||||
|
||||
bool didLoad = loadSpecialReferenceStorage(fieldData, fieldInfo, &result);
|
||||
if (!didLoad) {
|
||||
result.Type = fieldInfo.getType();
|
||||
auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
|
||||
result.Type->vw_initializeWithCopy(opaqueValueAddr,
|
||||
const_cast<OpaqueValue *>(fieldData));
|
||||
}
|
||||
|
||||
return AnyReturn(result);
|
||||
return copyFieldContents(fieldData, fieldInfo);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -559,7 +573,6 @@ struct ClassImpl : ReflectionMirrorImpl {
|
||||
#endif
|
||||
}
|
||||
|
||||
Any result;
|
||||
StringRef name;
|
||||
FieldType fieldInfo;
|
||||
std::tie(name, fieldInfo) = getFieldAt(type, i);
|
||||
@@ -571,15 +584,7 @@ struct ClassImpl : ReflectionMirrorImpl {
|
||||
*outName = name.data();
|
||||
*outFreeFunc = nullptr;
|
||||
|
||||
bool didLoad = loadSpecialReferenceStorage(fieldData, fieldInfo, &result);
|
||||
if (!didLoad) {
|
||||
result.Type = fieldInfo.getType();
|
||||
auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
|
||||
result.Type->vw_initializeWithCopy(opaqueValueAddr,
|
||||
const_cast<OpaqueValue *>(fieldData));
|
||||
}
|
||||
|
||||
return AnyReturn(result);
|
||||
return copyFieldContents(fieldData, fieldInfo);
|
||||
}
|
||||
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
|
||||
@@ -509,6 +509,226 @@ mirrors.test("struct/WrapNSArray") {
|
||||
|
||||
#endif // _runtime(_ObjC)
|
||||
|
||||
//===--- Weak and Unowned References --------------------------------------===//
|
||||
|
||||
// Check that Mirror correctly reflects weak/unowned refs to both
|
||||
// Swift and ObjC objects from Swift structs and classes.
|
||||
|
||||
protocol WeakUnownedTestsP1: class {
|
||||
func f1() -> Int
|
||||
}
|
||||
|
||||
protocol WeakUnownedTestsP2 {
|
||||
func f2() -> String
|
||||
}
|
||||
|
||||
class WeakUnownedSwiftClass: WeakUnownedTestsP1, WeakUnownedTestsP2 {
|
||||
let tracker = LifetimeTracked(0)
|
||||
func f1() -> Int { return 2 }
|
||||
func f2() -> String { return "b" }
|
||||
}
|
||||
|
||||
#if _runtime(_ObjC)
|
||||
@objc class WeakUnownedObjCClass: NSObject, WeakUnownedTestsP1, WeakUnownedTestsP2 {
|
||||
let tracker = LifetimeTracked(0)
|
||||
func f1() -> Int { return 2 }
|
||||
func f2() -> String { return "b" }
|
||||
}
|
||||
#endif
|
||||
|
||||
// The four tests below populate objects with different types
|
||||
// but identical overall structure.
|
||||
// This function is used by all four to verify that the resulting
|
||||
// Mirror objects have the expected entries.
|
||||
func verifyWeakUnownedReflection
|
||||
<ExpectedClass: WeakUnownedTestsP1 & WeakUnownedTestsP2>
|
||||
(_ m: Mirror, expectedClass: ExpectedClass.Type )
|
||||
{
|
||||
let i = m.children.makeIterator()
|
||||
|
||||
func verifyClassField(child: (label: String?, value: Any), name: String) {
|
||||
expectEqual(child.label, name)
|
||||
let v = child.value as? ExpectedClass
|
||||
expectNotNil(v)
|
||||
expectEqual(v!.f1(), 2)
|
||||
}
|
||||
|
||||
func verifyExistentialField(child: (label: String?, value: Any), name: String) {
|
||||
expectEqual(child.label, name)
|
||||
expectNotNil(child.value)
|
||||
|
||||
// FIXME: These casts are currently broken (Dec 2019)
|
||||
// Once they are fixed, enable additional checks:
|
||||
//let vp1 = child.value as? WeakUnownedTestsP1
|
||||
//expectNotNil(vp1)
|
||||
//expectEqual(vp1!.f1(), 2)
|
||||
//let vp2 = child.value as? WeakUnownedTestsP2
|
||||
//expectNotNil(vp2)
|
||||
//expectEqual(vp2!.f2(), "b")
|
||||
|
||||
let v = child.value as? ExpectedClass
|
||||
expectNotNil(v)
|
||||
expectEqual(v!.f1(), 2)
|
||||
let m = Mirror(reflecting: v!)
|
||||
expectEqual(m.displayStyle, .`class`)
|
||||
// TODO: Find a way to verify that the existential wrapper carries
|
||||
// the expected protocol witnesses. The current Swift runtime does
|
||||
// a very good job of hiding this from users.
|
||||
}
|
||||
|
||||
verifyClassField(child: i.next()!, name: "strong_class")
|
||||
verifyExistentialField(child: i.next()!, name: "strong_existential")
|
||||
verifyClassField(child: i.next()!, name: "weak_class")
|
||||
verifyExistentialField(child: i.next()!, name: "weak_existential")
|
||||
verifyClassField(child: i.next()!, name: "unowned_safe_class")
|
||||
verifyExistentialField(child: i.next()!, name: "unowned_safe_existential")
|
||||
|
||||
verifyClassField(child: i.next()!, name: "unowned_unsafe_class")
|
||||
verifyExistentialField(child: i.next()!, name: "unowned_unsafe_existential")
|
||||
expectNil(i.next())
|
||||
|
||||
// The original bug report from SR-5289 crashed when the print() code
|
||||
// attempted to reflect the contents of an unowned field.
|
||||
// The tests above _should_ suffice to check this, but let's print everything
|
||||
// anyway just to be sure.
|
||||
for c in m.children {
|
||||
print(c.label ?? "?", c.value)
|
||||
}
|
||||
}
|
||||
|
||||
#if _runtime(_ObjC)
|
||||
// Related: SR-5289 reported a crash when using Mirror to inspect Swift
|
||||
// class objects containing unowned pointers to Obj-C class objects.
|
||||
mirrors.test("Weak and Unowned Obj-C refs in class (SR-5289)") {
|
||||
class SwiftClassWithWeakAndUnowned {
|
||||
var strong_class: WeakUnownedObjCClass
|
||||
var strong_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2
|
||||
weak var weak_class: WeakUnownedObjCClass?
|
||||
weak var weak_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2)?
|
||||
unowned(safe) let unowned_safe_class: WeakUnownedObjCClass
|
||||
unowned(safe) let unowned_safe_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2
|
||||
unowned(unsafe) let unowned_unsafe_class: WeakUnownedObjCClass
|
||||
unowned(unsafe) let unowned_unsafe_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2
|
||||
|
||||
init(_ objc: WeakUnownedObjCClass) {
|
||||
self.strong_class = objc
|
||||
self.strong_existential = objc
|
||||
self.weak_class = objc
|
||||
self.weak_existential = objc
|
||||
self.unowned_safe_class = objc
|
||||
self.unowned_safe_existential = objc
|
||||
self.unowned_unsafe_class = objc
|
||||
self.unowned_unsafe_existential = objc
|
||||
}
|
||||
}
|
||||
|
||||
let objc = WeakUnownedObjCClass()
|
||||
let classWithReferences = SwiftClassWithWeakAndUnowned(objc)
|
||||
let m = Mirror(reflecting: classWithReferences)
|
||||
expectEqual(m.displayStyle, .`class`)
|
||||
expectEqual(m.description, "Mirror for SwiftClassWithWeakAndUnowned")
|
||||
expectEqual(m.subjectType, SwiftClassWithWeakAndUnowned.self)
|
||||
verifyWeakUnownedReflection(m, expectedClass: WeakUnownedObjCClass.self)
|
||||
}
|
||||
|
||||
mirrors.test("Weak and Unowned Obj-C refs in struct") {
|
||||
struct SwiftStructWithWeakAndUnowned {
|
||||
var strong_class: WeakUnownedObjCClass
|
||||
var strong_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2
|
||||
weak var weak_class: WeakUnownedObjCClass?
|
||||
weak var weak_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2)?
|
||||
unowned(safe) let unowned_safe_class: WeakUnownedObjCClass
|
||||
unowned(safe) let unowned_safe_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2
|
||||
unowned(unsafe) let unowned_unsafe_class: WeakUnownedObjCClass
|
||||
unowned(unsafe) let unowned_unsafe_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2
|
||||
|
||||
init(_ objc: WeakUnownedObjCClass) {
|
||||
self.strong_class = objc
|
||||
self.strong_existential = objc
|
||||
self.weak_class = objc
|
||||
self.weak_existential = objc
|
||||
self.unowned_safe_class = objc
|
||||
self.unowned_safe_existential = objc
|
||||
self.unowned_unsafe_class = objc
|
||||
self.unowned_unsafe_existential = objc
|
||||
}
|
||||
}
|
||||
|
||||
let objc = WeakUnownedObjCClass()
|
||||
let structWithReferences = SwiftStructWithWeakAndUnowned(objc)
|
||||
let m = Mirror(reflecting: structWithReferences)
|
||||
expectEqual(m.displayStyle, .`struct`)
|
||||
expectEqual(m.description, "Mirror for SwiftStructWithWeakAndUnowned")
|
||||
expectEqual(m.subjectType, SwiftStructWithWeakAndUnowned.self)
|
||||
verifyWeakUnownedReflection(m, expectedClass: WeakUnownedObjCClass.self)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
mirrors.test("Weak and Unowned Swift refs in class") {
|
||||
class SwiftClassWithWeakAndUnowned {
|
||||
var strong_class: WeakUnownedSwiftClass
|
||||
var strong_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2
|
||||
weak var weak_class: WeakUnownedSwiftClass?
|
||||
weak var weak_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2)?
|
||||
unowned(safe) let unowned_safe_class: WeakUnownedSwiftClass
|
||||
unowned(safe) let unowned_safe_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2)
|
||||
unowned(unsafe) let unowned_unsafe_class: WeakUnownedSwiftClass
|
||||
unowned(unsafe) let unowned_unsafe_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2)
|
||||
|
||||
init(_ swift: WeakUnownedSwiftClass) {
|
||||
self.strong_class = swift
|
||||
self.strong_existential = swift
|
||||
self.weak_class = swift
|
||||
self.weak_existential = swift
|
||||
self.unowned_safe_class = swift
|
||||
self.unowned_safe_existential = swift
|
||||
self.unowned_unsafe_class = swift
|
||||
self.unowned_unsafe_existential = swift
|
||||
}
|
||||
}
|
||||
|
||||
let swift = WeakUnownedSwiftClass()
|
||||
let classWithReferences = SwiftClassWithWeakAndUnowned(swift)
|
||||
let m = Mirror(reflecting: classWithReferences)
|
||||
expectEqual(m.displayStyle, .`class`)
|
||||
expectEqual(m.description, "Mirror for SwiftClassWithWeakAndUnowned")
|
||||
expectEqual(m.subjectType, SwiftClassWithWeakAndUnowned.self)
|
||||
verifyWeakUnownedReflection(m, expectedClass: WeakUnownedSwiftClass.self)
|
||||
}
|
||||
|
||||
mirrors.test("Weak and Unowned Swift refs in struct") {
|
||||
struct SwiftStructWithWeakAndUnowned {
|
||||
var strong_class: WeakUnownedSwiftClass
|
||||
var strong_existential: WeakUnownedTestsP1 & WeakUnownedTestsP2
|
||||
weak var weak_class: WeakUnownedSwiftClass?
|
||||
weak var weak_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2)?
|
||||
unowned(safe) let unowned_safe_class: WeakUnownedSwiftClass
|
||||
unowned(safe) let unowned_safe_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2)
|
||||
unowned(unsafe) let unowned_unsafe_class: WeakUnownedSwiftClass
|
||||
unowned(unsafe) let unowned_unsafe_existential: (WeakUnownedTestsP1 & WeakUnownedTestsP2)
|
||||
|
||||
init(_ swift: WeakUnownedSwiftClass) {
|
||||
self.strong_class = swift
|
||||
self.strong_existential = swift
|
||||
self.weak_class = swift
|
||||
self.weak_existential = swift
|
||||
self.unowned_safe_class = swift
|
||||
self.unowned_safe_existential = swift
|
||||
self.unowned_unsafe_class = swift
|
||||
self.unowned_unsafe_existential = swift
|
||||
}
|
||||
}
|
||||
|
||||
let swift = WeakUnownedSwiftClass()
|
||||
let structWithReferences = SwiftStructWithWeakAndUnowned(swift)
|
||||
let m = Mirror(reflecting: structWithReferences)
|
||||
expectEqual(m.displayStyle, .`struct`)
|
||||
expectEqual(m.description, "Mirror for SwiftStructWithWeakAndUnowned")
|
||||
expectEqual(m.subjectType, SwiftStructWithWeakAndUnowned.self)
|
||||
verifyWeakUnownedReflection(m, expectedClass: WeakUnownedSwiftClass.self)
|
||||
}
|
||||
|
||||
//===--- Suppressed Superclass Mirrors ------------------------------------===//
|
||||
mirrors.test("Class/Root/NoSuperclassMirror") {
|
||||
class B : CustomReflectable {
|
||||
@@ -854,7 +1074,7 @@ struct GenericStructWithDefaultMirror<T, U> {
|
||||
|
||||
mirrors.test("Struct/Generic/DefaultMirror") {
|
||||
do {
|
||||
var value = GenericStructWithDefaultMirror<Int, [Any?]>(
|
||||
let value = GenericStructWithDefaultMirror<Int, [Any?]>(
|
||||
first: 123,
|
||||
second: ["abc", 456, 789.25])
|
||||
var output = ""
|
||||
@@ -1616,7 +1836,7 @@ mirrors.test("Float") {
|
||||
}
|
||||
|
||||
do {
|
||||
var input: Float = 42.125
|
||||
let input: Float = 42.125
|
||||
var output = ""
|
||||
dump(input, to: &output)
|
||||
|
||||
@@ -1649,7 +1869,7 @@ mirrors.test("Double") {
|
||||
}
|
||||
|
||||
do {
|
||||
var input: Double = 42.125
|
||||
let input: Double = 42.125
|
||||
var output = ""
|
||||
dump(input, to: &output)
|
||||
|
||||
@@ -1745,9 +1965,9 @@ mirrors.test("FieldNamesBug") {
|
||||
}
|
||||
|
||||
mirrors.test("MirrorMirror") {
|
||||
var object = 1
|
||||
var mirror = Mirror(reflecting: object)
|
||||
var mirrorMirror = Mirror(reflecting: mirror)
|
||||
let object = 1
|
||||
let mirror = Mirror(reflecting: object)
|
||||
let mirrorMirror = Mirror(reflecting: mirror)
|
||||
|
||||
expectEqual(0, mirrorMirror.children.count)
|
||||
}
|
||||
@@ -1755,7 +1975,7 @@ mirrors.test("MirrorMirror") {
|
||||
mirrors.test("OpaquePointer/null") {
|
||||
// Don't crash on null pointers. rdar://problem/19708338
|
||||
let pointer: OpaquePointer? = nil
|
||||
let mirror = Mirror(reflecting: pointer)
|
||||
let mirror = Mirror(reflecting: pointer as Any)
|
||||
expectEqual(0, mirror.children.count)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user