mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Casting] Make more casts look inside __SwiftValue
The following sequence of casts would previously succeed
```
struct S {}
let s = S() as AnyObject
s as? NSObject
```
The final cast here should fail, since `S` clearly is not a
subclass of NSObject. But it would previously succeed because
the `as AnyObject` would package the struct into an ObjC-compatible
`__SwiftValue` class. This latter is an NSObject subclass.
This bug was fixed in the main `swift_dynamicCast` runtime function
some time ago, but not in the `swift_dynamicCastObjCClass` which
is chosen by IRGen to optimize casts to ObjC class types.
This PR changes the latter to test for `__SwiftValue` and fall
back to the former in that case in order to get the correct
handling. Falling back to `swift_dynamicCast` also ensures that
the contents of the `__SwiftValue` are correctly unwrapped/bridged/etc
as necessary to fully support Swift casting semantics.
Resolves: rdar://111422725
TODO: I've left an XFAILed test here about the behavior of `type(of:)`
with `__SwiftValue` boxes.
This commit is contained in:
@@ -1093,6 +1093,22 @@ swift_dynamicCastObjCClassImpl(const void *object,
|
||||
if (object == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if ([id_const_cast(object) isKindOfClass:[__SwiftValue class]]) {
|
||||
// Source is a `__SwiftValue` container
|
||||
// Unwrap, then use the most general casting machine to do the heavy lifting
|
||||
auto typeValue = getValueFromSwiftValue(reinterpret_cast<__SwiftValue *>(object));
|
||||
const void *result = nullptr;
|
||||
if (swift_dynamicCast(reinterpret_cast<OpaqueValue *>(&result),
|
||||
const_cast<OpaqueValue *>(typeValue.second),
|
||||
typeValue.first,
|
||||
targetType,
|
||||
DynamicCastFlags::TakeOnSuccess)) {
|
||||
return result;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if ([id_const_cast(object) isKindOfClass:class_const_cast(targetType)]) {
|
||||
return object;
|
||||
}
|
||||
|
||||
@@ -1064,4 +1064,19 @@ CastsTests.test("Don't put AnyHashable inside AnyObject") {
|
||||
expectTrue(a === d)
|
||||
}
|
||||
|
||||
CastsTests.test("__SwiftValue should not be obvious to `is`") {
|
||||
struct S {}
|
||||
let s = S() as AnyObject
|
||||
expectFalse(s is NSObject)
|
||||
}
|
||||
|
||||
CastsTests.test("type(of:) should look through __SwiftValue")
|
||||
.xfail(.always("Known to be broken"))
|
||||
.code {
|
||||
struct S {}
|
||||
let s = S() as AnyObject
|
||||
let t = "\(type(of: s))"
|
||||
expectEqual(t, "S") // Fails: currently says `__SwiftValue`
|
||||
}
|
||||
|
||||
runAllTests()
|
||||
|
||||
Reference in New Issue
Block a user