Skip to content

Tbkka radar59302422 swift 5.2 #29883

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 21 additions & 13 deletions stdlib/public/runtime/Casting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,10 @@ swift_dynamicCastMetatypeImpl(const Metadata *sourceType,
const Metadata *targetType) {
auto origSourceType = sourceType;

// Identical types always succeed
if (sourceType == targetType)
return origSourceType;

switch (targetType->getKind()) {
case MetadataKind::ObjCClassWrapper:
// Get the actual class object.
Expand Down Expand Up @@ -1111,17 +1115,13 @@ swift_dynamicCastMetatypeImpl(const Metadata *sourceType,

case MetadataKind::Existential: {
auto targetTypeAsExistential = static_cast<const ExistentialTypeMetadata *>(targetType);
if (!_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr))
return nullptr;
return origSourceType;
if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr))
return origSourceType;
return nullptr;
}

default:
// The cast succeeds only if the metadata pointers are statically
// equivalent.
if (sourceType != targetType)
return nullptr;
return origSourceType;
return nullptr;
}

swift_runtime_unreachable("Unhandled MetadataKind in switch.");
Expand All @@ -1133,6 +1133,10 @@ swift_dynamicCastMetatypeUnconditionalImpl(const Metadata *sourceType,
const char *file, unsigned line, unsigned column) {
auto origSourceType = sourceType;

// Identical types always succeed
if (sourceType == targetType)
return origSourceType;

switch (targetType->getKind()) {
case MetadataKind::ObjCClassWrapper:
// Get the actual class object.
Expand Down Expand Up @@ -1199,12 +1203,16 @@ swift_dynamicCastMetatypeUnconditionalImpl(const Metadata *sourceType,
swift_dynamicCastFailure(sourceType, targetType);
}
break;

case MetadataKind::Existential: {
auto targetTypeAsExistential = static_cast<const ExistentialTypeMetadata *>(targetType);
if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr))
return origSourceType;
swift_dynamicCastFailure(sourceType, targetType);
}

default:
// The cast succeeds only if the metadata pointers are statically
// equivalent.
if (sourceType != targetType)
swift_dynamicCastFailure(sourceType, targetType);
return origSourceType;
swift_dynamicCastFailure(sourceType, targetType);
}
}

Expand Down
133 changes: 118 additions & 15 deletions test/Interpreter/generic_casts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,21 @@ enum PE: P {}
class PC: P {}
class PCSub: PC {}

func nongenericAnyIsP(type: Any.Type) -> Bool {
// `is` checks
func nongenericAnyIsPConforming(type: Any.Type) -> Bool {
// `is P.Type` tests whether the argument conforms to `P`
// Note: this can only be true for a concrete type, never a protocol
return type is P.Type
}
func nongenericAnyIsPAndAnyObject(type: Any.Type) -> Bool {
func nongenericAnyIsPSubtype(type: Any.Type) -> Bool {
// `is P.Protocol` tests whether the argument is a subtype of `P`
// In particular, it is true for `P.self`
return type is P.Protocol
}
func nongenericAnyIsPAndAnyObjectConforming(type: Any.Type) -> Bool {
return type is (P & AnyObject).Type
}
func nongenericAnyIsPAndPCSub(type: Any.Type) -> Bool {
func nongenericAnyIsPAndPCSubConforming(type: Any.Type) -> Bool {
return type is (P & PCSub).Type
}
func genericAnyIs<T>(type: Any.Type, to: T.Type, expected: Bool) -> Bool {
Expand All @@ -157,38 +165,133 @@ func genericAnyIs<T>(type: Any.Type, to: T.Type, expected: Bool) -> Bool {
return expected
}
}
// `as?` checks
func nongenericAnyAsConditionalPConforming(type: Any.Type) -> Bool {
return (type as? P.Type) != nil
}
func nongenericAnyAsConditionalPSubtype(type: Any.Type) -> Bool {
return (type as? P.Protocol) != nil
}
func nongenericAnyAsConditionalPAndAnyObjectConforming(type: Any.Type) -> Bool {
return (type as? (P & AnyObject).Type) != nil
}
func nongenericAnyAsConditionalPAndPCSubConforming(type: Any.Type) -> Bool {
return (type as? (P & PCSub).Type) != nil
}
func genericAnyAsConditional<T>(type: Any.Type, to: T.Type, expected: Bool) -> Bool {
// If we're testing against a runtime that doesn't have the fix this tests,
// just pretend we got it right.
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
return (type as? T.Type) != nil
} else {
return expected
}
}
// `as!` checks
func blackhole<T>(_ : T) { }

func nongenericAnyAsUnconditionalPConforming(type: Any.Type) -> Bool {
blackhole(type as! P.Type)
return true
}
func nongenericAnyAsUnconditionalPSubtype(type: Any.Type) -> Bool {
blackhole(type as! P.Protocol)
return true
}
func nongenericAnyAsUnconditionalPAndAnyObjectConforming(type: Any.Type) -> Bool {
blackhole(type as! (P & AnyObject).Type)
return true
}
func nongenericAnyAsUnconditionalPAndPCSubConforming(type: Any.Type) -> Bool {
blackhole(type as! (P & PCSub).Type)
return true
}
func genericAnyAsUnconditional<T>(type: Any.Type, to: T.Type, expected: Bool) -> Bool {
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
blackhole(type as! T.Type)
}
return true
}

// CHECK-LABEL: casting types to protocols with generics:
print("casting types to protocols with generics:")
print(nongenericAnyIsP(type: PS.self)) // CHECK: true
print(nongenericAnyIsPConforming(type: P.self)) // CHECK: false
print(nongenericAnyIsPSubtype(type: P.self)) // CHECK: true
print(genericAnyIs(type: P.self, to: P.self, expected: true)) // CHECK: true
print(nongenericAnyIsPConforming(type: PS.self)) // CHECK: true
print(genericAnyIs(type: PS.self, to: P.self, expected: true)) // CHECK-ONONE: true
print(nongenericAnyIsP(type: PE.self)) // CHECK: true
print(nongenericAnyIsPConforming(type: PE.self)) // CHECK: true
print(genericAnyIs(type: PE.self, to: P.self, expected: true)) // CHECK-ONONE: true
print(nongenericAnyIsP(type: PC.self)) // CHECK: true
print(nongenericAnyIsPConforming(type: PC.self)) // CHECK: true
print(genericAnyIs(type: PC.self, to: P.self, expected: true)) // CHECK-ONONE: true
print(nongenericAnyIsP(type: PCSub.self)) // CHECK: true
print(nongenericAnyIsPConforming(type: PCSub.self)) // CHECK: true
print(genericAnyIs(type: PCSub.self, to: P.self, expected: true)) // CHECK-ONONE: true

// CHECK-LABEL: conditionally casting types to protocols with generics:
print("conditionally casting types to protocols with generics:")
print(nongenericAnyAsConditionalPConforming(type: P.self)) // CHECK: false
print(nongenericAnyAsConditionalPSubtype(type: P.self)) // CHECK: true
print(genericAnyAsConditional(type: P.self, to: P.self, expected: true)) // CHECK: true
print(nongenericAnyAsConditionalPConforming(type: PS.self)) // CHECK: true
print(genericAnyAsConditional(type: PS.self, to: P.self, expected: true)) // CHECK-ONONE: true
print(nongenericAnyAsConditionalPConforming(type: PE.self)) // CHECK: true
print(genericAnyAsConditional(type: PE.self, to: P.self, expected: true)) // CHECK-ONONE: true
print(nongenericAnyAsConditionalPConforming(type: PC.self)) // CHECK: true
print(genericAnyAsConditional(type: PC.self, to: P.self, expected: true)) // CHECK-ONONE: true
print(nongenericAnyAsConditionalPConforming(type: PCSub.self)) // CHECK: true
print(genericAnyAsConditional(type: PCSub.self, to: P.self, expected: true)) // CHECK-ONONE: true

// CHECK-LABEL: unconditionally casting types to protocols with generics:
print("unconditionally casting types to protocols with generics:")
//print(nongenericAnyAsUnconditionalPConforming(type: P.self)) // expected to trap
print(nongenericAnyAsUnconditionalPSubtype(type: P.self)) // CHECK: true
print(genericAnyAsUnconditional(type: P.self, to: P.self, expected: true)) // CHECK: true
print(nongenericAnyAsUnconditionalPConforming(type: PS.self)) // CHECK: true
print(genericAnyAsUnconditional(type: PS.self, to: P.self, expected: true)) // CHECK: true
print(nongenericAnyAsUnconditionalPConforming(type: PE.self)) // CHECK: true
print(genericAnyAsUnconditional(type: PE.self, to: P.self, expected: true)) // CHECK: true
print(nongenericAnyAsUnconditionalPConforming(type: PC.self)) // CHECK: true
print(genericAnyAsUnconditional(type: PC.self, to: P.self, expected: true)) // CHECK: true
print(nongenericAnyAsUnconditionalPConforming(type: PCSub.self)) // CHECK: true
print(genericAnyAsUnconditional(type: PCSub.self, to: P.self, expected: true)) // CHECK: true

// CHECK-LABEL: casting types to protocol & AnyObject existentials:
print("casting types to protocol & AnyObject existentials:")
print(nongenericAnyIsPAndAnyObject(type: PS.self)) // CHECK: false
print(nongenericAnyIsPAndAnyObjectConforming(type: PS.self)) // CHECK: false
print(genericAnyIs(type: PS.self, to: (P & AnyObject).self, expected: false)) // CHECK: false
print(nongenericAnyIsPAndAnyObject(type: PE.self)) // CHECK: false
print(nongenericAnyIsPAndAnyObjectConforming(type: PE.self)) // CHECK: false
print(genericAnyIs(type: PE.self, to: (P & AnyObject).self, expected: false)) // CHECK: false
print(nongenericAnyIsPAndAnyObject(type: PC.self)) // CHECK: true
print(nongenericAnyIsPAndAnyObjectConforming(type: PC.self)) // CHECK: true
print(genericAnyIs(type: PC.self, to: (P & AnyObject).self, expected: true)) // CHECK-ONONE: true
print(nongenericAnyIsPAndAnyObject(type: PCSub.self)) // CHECK: true
print(nongenericAnyIsPAndAnyObjectConforming(type: PCSub.self)) // CHECK: true
print(genericAnyIs(type: PCSub.self, to: (P & AnyObject).self, expected: true)) // CHECK-ONONE: true
print(nongenericAnyAsConditionalPAndAnyObjectConforming(type: PS.self)) // CHECK: false
print(genericAnyAsConditional(type: PS.self, to: (P & AnyObject).self, expected: false)) // CHECK: false
print(nongenericAnyAsConditionalPAndAnyObjectConforming(type: PE.self)) // CHECK: false
print(genericAnyAsConditional(type: PE.self, to: (P & AnyObject).self, expected: false)) // CHECK: false
print(nongenericAnyAsConditionalPAndAnyObjectConforming(type: PC.self)) // CHECK: true
print(genericAnyAsConditional(type: PC.self, to: (P & AnyObject).self, expected: true)) // CHECK-ONONE: true
print(nongenericAnyAsConditionalPAndAnyObjectConforming(type: PCSub.self)) // CHECK: true
print(genericAnyAsConditional(type: PCSub.self, to: (P & AnyObject).self, expected: true)) // CHECK-ONONE: true

// CHECK-LABEL: casting types to protocol & class existentials:
print("casting types to protocol & class existentials:")
print(nongenericAnyIsPAndPCSub(type: PS.self)) // CHECK: false
print(nongenericAnyIsPAndPCSubConforming(type: PS.self)) // CHECK: false
print(genericAnyIs(type: PS.self, to: (P & PCSub).self, expected: false)) // CHECK: false
print(nongenericAnyIsPAndPCSub(type: PE.self)) // CHECK: false
print(nongenericAnyIsPAndPCSubConforming(type: PE.self)) // CHECK: false
print(genericAnyIs(type: PE.self, to: (P & PCSub).self, expected: false)) // CHECK: false
//print(nongenericAnyIsPAndPCSub(type: PC.self)) // CHECK-SR-11565: false -- FIXME: reenable this when SR-11565 is fixed
//print(nongenericAnyIsPAndPCSubConforming(type: PC.self)) // CHECK-SR-11565: false -- FIXME: reenable this when SR-11565 is fixed
print(genericAnyIs(type: PC.self, to: (P & PCSub).self, expected: false)) // CHECK: false
print(nongenericAnyIsPAndPCSub(type: PCSub.self)) // CHECK: true
print(nongenericAnyIsPAndPCSubConforming(type: PCSub.self)) // CHECK: true
print(genericAnyIs(type: PCSub.self, to: (P & PCSub).self, expected: true)) // CHECK-ONONE: true
print(nongenericAnyAsConditionalPAndPCSubConforming(type: PS.self)) // CHECK: false
print(genericAnyAsConditional(type: PS.self, to: (P & PCSub).self, expected: false)) // CHECK: false
print(nongenericAnyAsConditionalPAndPCSubConforming(type: PE.self)) // CHECK: false
print(genericAnyAsConditional(type: PE.self, to: (P & PCSub).self, expected: false)) // CHECK: false
//print(nongenericAnyAsConditionalPAndPCSubConforming(type: PC.self)) // CHECK-SR-11565: false -- FIXME: reenable this when SR-11565 is fixed
print(genericAnyAsConditional(type: PC.self, to: (P & PCSub).self, expected: false)) // CHECK: false
print(nongenericAnyAsConditionalPAndPCSubConforming(type: PCSub.self)) // CHECK: true
print(genericAnyAsConditional(type: PCSub.self, to: (P & PCSub).self, expected: true)) // CHECK-ONONE: true


// CHECK-LABEL: type comparisons:
Expand Down