Skip to content

Commit e83fb64

Browse files
committed
[Runtime] Extract an embedded NSError when dynamic casting to an Error existential.
SILGen already attempts to extract an embedded NSError when type-erasing to an Error existential; make the runtime do the same thing dynamically. Huge thanks to Joe Groff who noticed that I missed this path.
1 parent 6c14ca3 commit e83fb64

File tree

2 files changed

+38
-11
lines changed

2 files changed

+38
-11
lines changed

stdlib/public/runtime/Casting.cpp

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,16 @@ swift_dynamicCastMetatypeToObjectUnconditional(const Metadata *metatype) {
872872
}
873873
}
874874
}
875+
876+
// @_silgen_name("swift_stdlib_getErrorEmbeddedNSErrorIndirect")
877+
// public func _stdlib_getErrorEmbeddedNSErrorIndirect<T : Error>(
878+
/// _ x: UnsafePointer<T>) -> AnyObject?
879+
SWIFT_CC(swift)
880+
extern "C" id swift_stdlib_getErrorEmbeddedNSErrorIndirect(
881+
const OpaqueValue *error,
882+
const Metadata *T,
883+
const WitnessTable *Error);
884+
875885
#endif
876886

877887
/// Perform a dynamic cast to an existential type.
@@ -1040,7 +1050,20 @@ static bool _dynamicCastToExistential(OpaqueValue *dest,
10401050
targetType->Protocols,
10411051
&errorWitness))
10421052
return _fail(src, srcType, targetType, flags, srcDynamicType);
1043-
1053+
1054+
#if SWIFT_OBJC_INTEROP
1055+
// Check whether there is an embedded NSError. If so, use that for our Error
1056+
// representation.
1057+
if (auto embedded =
1058+
swift_stdlib_getErrorEmbeddedNSErrorIndirect(srcDynamicValue,
1059+
srcDynamicType,
1060+
errorWitness)) {
1061+
*destBoxAddr = reinterpret_cast<SwiftError*>(embedded);
1062+
maybeDeallocateSourceAfterSuccess();
1063+
return true;
1064+
}
1065+
#endif
1066+
10441067
BoxPair destBox = swift_allocError(srcDynamicType, errorWitness,
10451068
srcDynamicValue,
10461069
/*isTake*/ canTake && (flags & DynamicCastFlags::TakeOnSuccess));
@@ -2006,20 +2029,11 @@ static bool _dynamicCastToFunction(OpaqueValue *dest,
20062029
}
20072030

20082031
#if SWIFT_OBJC_INTEROP
2009-
// @_silgen_name("swift_stdlib_getErrorEmbeddedNSErrorIndirect")
2010-
// public func _stdlib_getErrorEmbeddedNSErrorIndirect<T : Error>(
2011-
/// _ x: UnsafePointer<T>) -> AnyObject?
2012-
SWIFT_CC(swift)
2013-
extern "C" id swift_stdlib_getErrorEmbeddedNSErrorIndirect(
2014-
const OpaqueValue *error,
2015-
const Metadata *T,
2016-
const WitnessTable *Error);
2017-
20182032
static id dynamicCastValueToNSError(OpaqueValue *src,
20192033
const Metadata *srcType,
20202034
const WitnessTable *srcErrorWitness,
20212035
DynamicCastFlags flags) {
2022-
// Check whether there is an embedded error.
2036+
// Check whether there is an embedded NSError.
20232037
if (auto embedded =
20242038
swift_stdlib_getErrorEmbeddedNSErrorIndirect(src, srcType,
20252039
srcErrorWitness)) {

test/1_stdlib/ErrorBridged.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,11 +633,24 @@ extension Error {
633633
}
634634
}
635635

636+
func unconditionalCast<T>(_ x: Any, to: T.Type) -> T {
637+
return x as! T
638+
}
639+
640+
func conditionalCast<T>(_ x: Any, to: T.Type) -> T? {
641+
return x as? T
642+
}
643+
636644
// SR-1562
637645
ErrorBridgingTests.test("Error archetype identity") {
638646
let myError = NSError(domain: "myErrorDomain", code: 0,
639647
userInfo: [ AnyHashable("one") : 1 ])
640648
expectTrue(myError === myError.asNSError())
649+
650+
expectTrue(unconditionalCast(myError, to: Error.self) as NSError
651+
=== myError)
652+
expectTrue(conditionalCast(myError, to: Error.self)! as NSError
653+
=== myError)
641654
}
642655

643656
runAllTests()

0 commit comments

Comments
 (0)