Skip to content

Commit 00f49a9

Browse files
committed
Provide a Bincompat override for the newly tightened casting semantics
1 parent 1846545 commit 00f49a9

File tree

4 files changed

+35
-7
lines changed

4 files changed

+35
-7
lines changed

include/swift/Runtime/Bincompat.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ bool useLegacyOptionalNilInjectionInCasting();
3838
/// Obj-C interop
3939
bool useLegacyObjCBoxingInCasting();
4040

41+
/// Whether to use legacy semantics when unboxing __SwiftValue
42+
bool useLegacySwiftValueUnboxingInCasting();
43+
4144
} // namespace bincompat
4245

4346
} // namespace runtime

stdlib/public/runtime/Bincompat.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,26 @@ bool useLegacyObjCBoxingInCasting() {
195195
#endif
196196
}
197197

198+
// Should casting be strict about protocol conformance when
199+
// unboxing values that were boxed for Obj-C use?
200+
201+
// Similar to `useLegacyObjCBoxingInCasting()`, but
202+
// this applies to the case where you have already boxed
203+
// some Swift non-reference-type into a `__SwiftValue`
204+
// and are now casting to a protocol.
205+
206+
// For example, this cast
207+
// `x as! AnyObject as? NSCopying`
208+
// always succeeded with the legacy semantics.
209+
210+
bool useLegacySwiftValueUnboxingInCasting() {
211+
#if BINARY_COMPATIBILITY_APPLE
212+
return true; // For now, continue using the legacy behavior on Apple OSes
213+
#else
214+
return false; // Always use the new behavior on non-Apple OSes
215+
#endif
216+
}
217+
198218
} // namespace bincompat
199219

200220
} // namespace runtime

stdlib/public/runtime/DynamicCast.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,10 +1494,12 @@ tryCastToClassExistential(
14941494
#if SWIFT_OBJC_INTEROP
14951495
id srcObject;
14961496
memcpy(&srcObject, srcValue, sizeof(id));
1497-
if (getAsSwiftValue(srcObject) != nullptr) {
1498-
// Do not directly cast a `__SwiftValue` box
1499-
// Return failure so our caller will unwrap and try again
1500-
return DynamicCastResult::Failure;
1497+
if (!runtime::bincompat::useLegacySwiftValueUnboxingInCasting()) {
1498+
if (getAsSwiftValue(srcObject) != nullptr) {
1499+
// Do not directly cast a `__SwiftValue` box
1500+
// Return failure so our caller will unwrap and try again
1501+
return DynamicCastResult::Failure;
1502+
}
15011503
}
15021504
#endif
15031505
SWIFT_FALLTHROUGH;

stdlib/public/runtime/SwiftObject.mm

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#endif
2626
#include "llvm/ADT/StringRef.h"
2727
#include "swift/Basic/Lazy.h"
28+
#include "swift/Runtime/Bincompat.h"
2829
#include "swift/Runtime/Casting.h"
2930
#include "swift/Runtime/CustomRRABI.h"
3031
#include "swift/Runtime/Debug.h"
@@ -1270,9 +1271,11 @@ id swift_dynamicCastObjCProtocolUnconditional(id object,
12701271
id swift_dynamicCastObjCProtocolConditional(id object,
12711272
size_t numProtocols,
12721273
Protocol * const *protocols) {
1273-
if (getAsSwiftValue(object) != nil) {
1274-
// SwiftValue wrapper never holds a class object
1275-
return nil;
1274+
if (!runtime::bincompat::useLegacySwiftValueUnboxingInCasting()) {
1275+
if (getAsSwiftValue(object) != nil) {
1276+
// SwiftValue wrapper never holds a class object
1277+
return nil;
1278+
}
12761279
}
12771280
for (size_t i = 0; i < numProtocols; ++i) {
12781281
if (![object conformsToProtocol:protocols[i]]) {

0 commit comments

Comments
 (0)