SR-14635: __SwiftValue should be transparent to casting

This PR changes the casting machinery to avoid casting `__SwiftValue` boxes
directly.  This forces the caster to instead unwrap `__SwiftValue` boxes and
retry with the inner content.  This results in boxed values being cast like the
inner content.

This fixes the behavior in situations like the following:
```
   let t = ...
   let s = t as Any as! AnyObject
   // `s` is now a `__SwiftValue` box
   // Next line should be true iff t conforms to NSCopying
   // Prior to this change, it always succeeds
   s is NSCopying
```

After this change, the above cast succeeds only if `t` actually
conforms to `NSCopying`.

This is a follow-on to PR#37683.
Related to: SR-14635
This commit is contained in:
Tim Kientzle
2021-06-14 15:25:22 -07:00
parent bbda52f7e5
commit b91f29dfcb
3 changed files with 66 additions and 6 deletions

View File

@@ -425,6 +425,29 @@ tryCastUnwrappingObjCSwiftValueSource(
destFailureType, srcFailureType,
/*takeOnSuccess=*/ false, mayDeferChecks);
}
#else
static DynamicCastResult
tryCastUnwrappingSwiftValueSource(
OpaqueValue *destLocation, const Metadata *destType,
OpaqueValue *srcValue, const Metadata *srcType,
const Metadata *&destFailureType, const Metadata *&srcFailureType,
bool takeOnSuccess, bool mayDeferChecks)
{
const Metadata *srcInnerType;
const OpaqueValue *srcInnerValue;
if (swift_unboxFromSwiftValueWithType(srcValue, &srcInnerValue, &srcInnerType)) {
return DynamicCastResult::SuccessViaCopy;
}
// Note: We never `take` the contents from a SwiftValue box as
// it might have other references. Instead, let our caller
// destroy the reference if necessary.
return tryCast(
destLocation, destType,
const_cast<OpaqueValue *>(srcInnerValue), srcInnerType,
destFailureType, srcFailureType,
/*takeOnSuccess=*/ false, mayDeferChecks);
}
#endif
/******************************************************************************/
@@ -1474,6 +1497,16 @@ tryCastToClassExistential(
}
case MetadataKind::ObjCClassWrapper:
#if SWIFT_OBJC_INTEROP
id srcObject;
memcpy(&srcObject, srcValue, sizeof(id));
if (getAsSwiftValue(srcObject) != nullptr) {
// Do not directly cast a `__SwiftValue` box
// Return failure so our caller will unwrap and try again
return DynamicCastResult::Failure;
}
#endif
SWIFT_FALLTHROUGH;
case MetadataKind::Class:
case MetadataKind::ForeignClass: {
auto srcObject = getNonNullSrcObject(srcValue, srcType, destType);
@@ -2285,8 +2318,11 @@ tryCast(
case MetadataKind::Class: {
#if !SWIFT_OBJC_INTEROP
// Try unwrapping native __SwiftValue implementation
if (swift_unboxFromSwiftValueWithType(srcValue, destLocation, destType)) {
return DynamicCastResult::SuccessViaCopy;
auto subcastResult = tryCastUnwrappingSwiftValueSource(
destLocation, destType, srcValue, srcType,
destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks);
if (isSuccess(subcastResult)) {
return subcastResult;
}
#endif
break;