Skip to content

Commit 6d46eb1

Browse files
authored
Merge pull request #28353 from DougGregor/error-bridge-to-nsobject
2 parents 7b33254 + 7659121 commit 6d46eb1

File tree

4 files changed

+44
-3
lines changed

4 files changed

+44
-3
lines changed

stdlib/public/runtime/Casting.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "llvm/Support/Compiler.h"
3838
#if SWIFT_OBJC_INTEROP
3939
#include "swift/Runtime/ObjCBridge.h"
40+
#include "SwiftObject.h"
4041
#include "SwiftValue.h"
4142
#endif
4243

@@ -2330,9 +2331,10 @@ static bool swift_dynamicCastImpl(OpaqueValue *dest, OpaqueValue *src,
23302331
case MetadataKind::Class:
23312332
case MetadataKind::ObjCClassWrapper:
23322333
#if SWIFT_OBJC_INTEROP
2333-
// If the destination type is an NSError, and the source type is an
2334-
// Error, then the cast can succeed by NSError bridging.
2335-
if (targetType == getNSErrorMetadata()) {
2334+
// If the destination type is an NSError or NSObject, and the source type
2335+
// is an Error, then the cast can succeed by NSError bridging.
2336+
if (targetType == getNSErrorMetadata() ||
2337+
targetType == getNSObjectMetadata()) {
23362338
// Don't rebridge if the source is already some kind of NSError.
23372339
if (srcType->isAnyClass()
23382340
&& swift_dynamicCastObjCClass(*reinterpret_cast<id*>(src),

stdlib/public/runtime/SwiftObject.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030

3131
#if SWIFT_OBJC_INTEROP
32+
#if __OBJC__
3233

3334
// Source code: "SwiftObject"
3435
// Real class name: mangled "Swift._SwiftObject"
@@ -83,5 +84,13 @@ id getDescription(OpaqueValue *value, const Metadata *type);
8384
}
8485

8586
#endif
87+
#endif
88+
89+
namespace swift {
90+
91+
/// Get the NSObject metadata.
92+
const Metadata *getNSObjectMetadata();
93+
94+
}
8695

8796
#endif

stdlib/public/runtime/SwiftObject.mm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,6 +1552,11 @@ void swift_objc_swift3ImplicitObjCEntrypoint(id self, SEL selector,
15521552
free(nullTerminatedFilename);
15531553
}
15541554

1555+
const Metadata *swift::getNSObjectMetadata() {
1556+
return SWIFT_LAZY_CONSTANT(
1557+
swift_getObjCClassMetadata((const ClassMetadata *)[NSObject class]));
1558+
}
1559+
15551560
#endif
15561561

15571562
const ClassMetadata *swift::getRootSuperclass() {

test/stdlib/ErrorBridged.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,4 +767,29 @@ ErrorBridgingTests.test("@objc error domains for nested types") {
767767
String(reflecting: NonPrintAsObjCError.self))
768768
}
769769

770+
@inline(never)
771+
@_optimize(none)
772+
func anyToAny<T, U>(_ a: T, _ : U.Type) -> U {
773+
return a as! U
774+
}
775+
776+
ErrorBridgingTests.test("error-to-NSObject casts") {
777+
let error = MyCustomizedError(code: 12345)
778+
779+
// Unconditional cast
780+
let nsErrorAsObject1 = unconditionalCast(error, to: NSObject.self)
781+
let nsError1 = unconditionalCast(nsErrorAsObject1, to: NSError.self)
782+
expectEqual("custom", nsError1.domain)
783+
expectEqual(12345, nsError1.code)
784+
785+
// Conditional cast
786+
let nsErrorAsObject2 = conditionalCast(error, to: NSObject.self)!
787+
let nsError2 = unconditionalCast(nsErrorAsObject2, to: NSError.self)
788+
expectEqual("custom", nsError2.domain)
789+
expectEqual(12345, nsError2.code)
790+
791+
// "is" check
792+
expectTrue(error is NSObject)
793+
}
794+
770795
runAllTests()

0 commit comments

Comments
 (0)