From 4d3a8c28004ce88f49a4bb512bb4d9ec0dd697be Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Wed, 6 May 2020 17:18:29 -0700 Subject: [PATCH 1/5] SR-12486: `T.self is Any.Protocol` is broken This turned out to be fallout from https://github.com/apple/swift/pull/27572 which was in turn motivated by our confusing metatype syntax when generic variables are bound to protocols. In particular, the earlier PR was an attempt to make the expression `x is T.Type` (where `T` is a generic type variable bound to a protocol `P`) behave the same as `x is P.Type` (where `P` is a protocol). Unfortunately, the generic `T.Type` actually binds to `P.Protocol` in this case (not `P.Type`), so the original motivation was flawed, and as it happens, `x is T.Type` already behaved the same as `x is P.Protocol` in this situation. This PR reverts that earlier change and beefs up some of the tests around these behaviors. Resolves SR-12486 Resolves rdar://62201613 Reverts PR#27572 --- stdlib/public/runtime/Casting.cpp | 7 - test/Interpreter/generic_casts.swift | 232 +++++++++++++++------------ test/stdlib/Casts.swift | 57 +++++++ 3 files changed, 182 insertions(+), 114 deletions(-) diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp index 64d1b1f2edc66..3e309d071be44 100644 --- a/stdlib/public/runtime/Casting.cpp +++ b/stdlib/public/runtime/Casting.cpp @@ -1185,13 +1185,6 @@ swift_dynamicCastMetatypeImpl(const Metadata *sourceType, } break; - case MetadataKind::Existential: { - auto targetTypeAsExistential = static_cast(targetType); - if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr)) - return origSourceType; - return nullptr; - } - default: return nullptr; } diff --git a/test/Interpreter/generic_casts.swift b/test/Interpreter/generic_casts.swift index 99941a08524d6..5f6644d9182f4 100644 --- a/test/Interpreter/generic_casts.swift +++ b/test/Interpreter/generic_casts.swift @@ -1,9 +1,10 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -Onone %s -o %t/a.out -// RUN: %target-run %t/a.out | %FileCheck --check-prefix CHECK --check-prefix CHECK-ONONE %s // RUN: %target-build-swift -O %s -o %t/a.out.optimized // RUN: %target-codesign %t/a.out.optimized -// RUN: %target-run %t/a.out.optimized | %FileCheck %s +// +// RUN: %target-run %t/a.out | %FileCheck --check-prefix CHECK %s +// RUN: %target-run %t/a.out.optimized | %FileCheck --check-prefix CHECK %s // REQUIRES: executable_test // FIXME: rdar://problem/19648117 Needs splitting objc parts out @@ -140,42 +141,44 @@ class PC: P {} class PCSub: PC {} // `is` checks -func nongenericAnyIsPConforming(type: Any.Type) -> Bool { +func nongenericAnyIsPType(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 nongenericAnyIsPSubtype(type: Any.Type) -> Bool { +func nongenericAnyIsPProtocol(type: Any.Type) -> Bool { + // `P.Protocol` is the metatype for `P` (the type of `P.self`) // `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 { +func nongenericAnyIsPAndAnyObjectType(type: Any.Type) -> Bool { return type is (P & AnyObject).Type } -func nongenericAnyIsPAndPCSubConforming(type: Any.Type) -> Bool { +func nongenericAnyIsPAndPCSubType(type: Any.Type) -> Bool { return type is (P & PCSub).Type } func genericAnyIs(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 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *) { + // Remember: If `T` is bound to `P`, then `T.Type` is `P.Protocol` return type is T.Type } else { return expected } } // `as?` checks -func nongenericAnyAsConditionalPConforming(type: Any.Type) -> Bool { +func nongenericAnyAsConditionalPType(type: Any.Type) -> Bool { return (type as? P.Type) != nil } -func nongenericAnyAsConditionalPSubtype(type: Any.Type) -> Bool { +func nongenericAnyAsConditionalPProtocol(type: Any.Type) -> Bool { return (type as? P.Protocol) != nil } -func nongenericAnyAsConditionalPAndAnyObjectConforming(type: Any.Type) -> Bool { +func nongenericAnyAsConditionalPAndAnyObjectType(type: Any.Type) -> Bool { return (type as? (P & AnyObject).Type) != nil } -func nongenericAnyAsConditionalPAndPCSubConforming(type: Any.Type) -> Bool { +func nongenericAnyAsConditionalPAndPCSubType(type: Any.Type) -> Bool { return (type as? (P & PCSub).Type) != nil } func genericAnyAsConditional(type: Any.Type, to: T.Type, expected: Bool) -> Bool { @@ -190,19 +193,19 @@ func genericAnyAsConditional(type: Any.Type, to: T.Type, expected: Bool) -> B // `as!` checks func blackhole(_ : T) { } -func nongenericAnyAsUnconditionalPConforming(type: Any.Type) -> Bool { +func nongenericAnyAsUnconditionalPType(type: Any.Type) -> Bool { blackhole(type as! P.Type) return true } -func nongenericAnyAsUnconditionalPSubtype(type: Any.Type) -> Bool { +func nongenericAnyAsUnconditionalPProtocol(type: Any.Type) -> Bool { blackhole(type as! P.Protocol) return true } -func nongenericAnyAsUnconditionalPAndAnyObjectConforming(type: Any.Type) -> Bool { +func nongenericAnyAsUnconditionalPAndAnyObjectType(type: Any.Type) -> Bool { blackhole(type as! (P & AnyObject).Type) return true } -func nongenericAnyAsUnconditionalPAndPCSubConforming(type: Any.Type) -> Bool { +func nongenericAnyAsUnconditionalPAndPCSubType(type: Any.Type) -> Bool { blackhole(type as! (P & PCSub).Type) return true } @@ -215,135 +218,150 @@ func genericAnyAsUnconditional(type: Any.Type, to: T.Type, expected: Bool) -> // CHECK-LABEL: casting types to protocols with generics: print("casting types to protocols with generics:") -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(nongenericAnyIsPConforming(type: PE.self)) // CHECK: true -print(genericAnyIs(type: PE.self, to: P.self, expected: true)) // CHECK-ONONE: true -print(nongenericAnyIsPConforming(type: PC.self)) // CHECK: true -print(genericAnyIs(type: PC.self, to: P.self, expected: true)) // CHECK-ONONE: true -print(nongenericAnyIsPConforming(type: PCSub.self)) // CHECK: true -print(genericAnyIs(type: PCSub.self, to: P.self, expected: true)) // CHECK-ONONE: true +print(#line, nongenericAnyIsPType(type: P.self)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPProtocol(type: P.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyIs(type: P.self, to: P.self, expected: true)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyIsPType(type: PS.self)) // CHECK: [[@LINE]] true +print(#line, PS() is P) // CHECK: [[@LINE]] true +// One candidate for a Swift type theory holds that +// `A is a subtype of B iff A.self is metatype` +// In that theory, `PS() is P` above would imply that +// `PS.self is P.Protocol` below must also be true. +// But that theory is not the one that Swift currently +// implements. +print(#line, nongenericAnyIsPProtocol(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PS.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPType(type: PE.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyIsPProtocol(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PE.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPType(type: PC.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyIsPProtocol(type: PC.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PC.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPType(type: PCSub.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyIsPProtocol(type: PCSub.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PCSub.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false // 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 +print(#line, "conditionally casting types to protocols with generics:") +print(#line, nongenericAnyAsConditionalPType(type: P.self)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPProtocol(type: P.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsConditional(type: P.self, to: P.self, expected: true)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsConditionalPType(type: PS.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsConditionalPProtocol(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PS.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPType(type: PE.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsConditionalPProtocol(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PE.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPType(type: PC.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsConditionalPProtocol(type: PC.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PC.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPType(type: PCSub.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsConditionalPProtocol(type: PCSub.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PCSub.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false // 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 +print(#line, "unconditionally casting types to protocols with generics:") +//print(#line, nongenericAnyAsUnconditionalPType(type: P.self)) // expected to trap +print(#line, nongenericAnyAsUnconditionalPProtocol(type: P.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsUnconditional(type: P.self, to: P.self, expected: true)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsUnconditionalPType(type: PS.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsUnconditional(type: PS.self, to: P.self, expected: true)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsUnconditionalPType(type: PE.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsUnconditional(type: PE.self, to: P.self, expected: true)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsUnconditionalPType(type: PC.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsUnconditional(type: PC.self, to: P.self, expected: true)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsUnconditionalPType(type: PCSub.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsUnconditional(type: PCSub.self, to: P.self, expected: true)) // CHECK: [[@LINE]] true // CHECK-LABEL: casting types to protocol & AnyObject existentials: -print("casting types to protocol & AnyObject existentials:") -print(nongenericAnyIsPAndAnyObjectConforming(type: PS.self)) // CHECK: false -print(genericAnyIs(type: PS.self, to: (P & AnyObject).self, expected: false)) // CHECK: false -print(nongenericAnyIsPAndAnyObjectConforming(type: PE.self)) // CHECK: false -print(genericAnyIs(type: PE.self, to: (P & AnyObject).self, expected: false)) // CHECK: false -print(nongenericAnyIsPAndAnyObjectConforming(type: PC.self)) // CHECK: true -print(genericAnyIs(type: PC.self, to: (P & AnyObject).self, expected: true)) // CHECK-ONONE: 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 +print(#line, "casting types to protocol & AnyObject existentials:") +print(#line, nongenericAnyIsPAndAnyObjectType(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PS.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPAndAnyObjectType(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PE.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPAndAnyObjectType(type: PC.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyIs(type: PC.self, to: (P & AnyObject).self, expected: true)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPAndAnyObjectType(type: PCSub.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyIs(type: PCSub.self, to: (P & AnyObject).self, expected: true)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPAndAnyObjectType(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PS.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPAndAnyObjectType(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PE.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPAndAnyObjectType(type: PC.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsConditional(type: PC.self, to: (P & AnyObject).self, expected: true)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPAndAnyObjectType(type: PCSub.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsConditional(type: PCSub.self, to: (P & AnyObject).self, expected: true)) // CHECK: [[@LINE]] false // CHECK-LABEL: casting types to protocol & class existentials: -print("casting types to protocol & class existentials:") -print(nongenericAnyIsPAndPCSubConforming(type: PS.self)) // CHECK: false -print(genericAnyIs(type: PS.self, to: (P & PCSub).self, expected: false)) // CHECK: false -print(nongenericAnyIsPAndPCSubConforming(type: PE.self)) // CHECK: false -print(genericAnyIs(type: PE.self, to: (P & PCSub).self, expected: false)) // CHECK: false -//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(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 +print(#line, "casting types to protocol & class existentials:") +print(#line, nongenericAnyIsPAndPCSubType(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PS.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPAndPCSubType(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PE.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false +//print(#line, nongenericAnyIsPAndPCSubType(type: PC.self)) // CHECK-SR-11565: [[@LINE]] false -- FIXME: reenable this when SR-11565 is fixed +print(#line, genericAnyIs(type: PC.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPAndPCSubType(type: PCSub.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyIs(type: PCSub.self, to: (P & PCSub).self, expected: true)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPAndPCSubType(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PS.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPAndPCSubType(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PE.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false +// print(#line, nongenericAnyAsConditionalPAndPCSubType(type: PC.self)) // CHECK-SR-11565: [[@LINE]] false -- FIXME: reenable this when SR-11565 is fixed +print(#line, genericAnyAsConditional(type: PC.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPAndPCSubType(type: PCSub.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsConditional(type: PCSub.self, to: (P & PCSub).self, expected: true)) // CHECK: [[@LINE]] false // CHECK-LABEL: type comparisons: -print("type comparisons:\n") -print(allMetasToAllMetas(Int.self, Int.self)) // CHECK: true -print(allMetasToAllMetas(Int.self, Float.self)) // CHECK: false -print(allMetasToAllMetas(C.self, C.self)) // CHECK: true -print(allMetasToAllMetas(D.self, C.self)) // CHECK: true -print(allMetasToAllMetas(C.self, D.self)) // CHECK: false -print(C.self is D.Type) // CHECK: false -print((D.self as C.Type) is D.Type) // CHECK: true +print(#line, "type comparisons:\n") +print(#line, allMetasToAllMetas(Int.self, Int.self)) // CHECK: [[@LINE]] true +print(#line, allMetasToAllMetas(Int.self, Float.self)) // CHECK: [[@LINE]] false +print(#line, allMetasToAllMetas(C.self, C.self)) // CHECK: [[@LINE]] true +print(#line, allMetasToAllMetas(D.self, C.self)) // CHECK: [[@LINE]] true +print(#line, allMetasToAllMetas(C.self, D.self)) // CHECK: [[@LINE]] false +print(#line, C.self is D.Type) // CHECK: [[@LINE]] false +print(#line, (D.self as C.Type) is D.Type) // CHECK: [[@LINE]] true let t: Any.Type = type(of: 1 as Any) -print(t is Int.Type) // CHECK: true -print(t is Float.Type) // CHECK: false -print(t is C.Type) // CHECK: false +print(#line, t is Int.Type) // CHECK: [[@LINE]] true +print(#line, t is Float.Type) // CHECK: [[@LINE]] false +print(#line, t is C.Type) // CHECK: [[@LINE]] false let u: Any.Type = type(of: (D() as Any)) -print(u is C.Type) // CHECK: true -print(u is D.Type) // CHECK: true -print(u is E.Type) // CHECK: false -print(u is Int.Type) // CHECK: false +print(#line, u is C.Type) // CHECK: [[@LINE]] true +print(#line, u is D.Type) // CHECK: [[@LINE]] true +print(#line, u is E.Type) // CHECK: [[@LINE]] false +print(#line, u is Int.Type) // CHECK: [[@LINE]] false // FIXME: Can't spell AnyObject.Protocol // CHECK-LABEL: AnyObject casts: -print("AnyObject casts:") -print(allToAll(C(), AnyObject.self)) // CHECK: true +print(#line, "AnyObject casts:") +print(#line, allToAll(C(), AnyObject.self)) // CHECK: [[@LINE]] true // On Darwin, the object will be the ObjC-runtime-class object; // out of Darwin, this should not succeed. -print(allToAll(type(of: C()), AnyObject.self)) +print(#line, allToAll(type(of: C()), AnyObject.self)) // CHECK-objc: true // CHECK-native: false // Bridging // NSNumber on Darwin, __SwiftValue on Linux. -print(allToAll(0, AnyObject.self)) // CHECK: true +print(#line, allToAll(0, AnyObject.self)) // CHECK: [[@LINE]] true // This will get bridged using __SwiftValue. struct NotBridged { var x: Int } -print(allToAll(NotBridged(x: 0), AnyObject.self)) // CHECK: true +print(#line, allToAll(NotBridged(x: 0), AnyObject.self)) // CHECK: [[@LINE]] true #if canImport(Foundation) // This requires Foundation (for NSCopying): -print(allToAll(NotBridged(x: 0), NSCopying.self)) // CHECK-objc: true +print(#line, allToAll(NotBridged(x: 0), NSCopying.self)) // CHECK-objc: [[@LINE]] true #endif // On Darwin, these casts fail (intentionally) even though __SwiftValue does // technically conform to these protocols through NSObject. // Off Darwin, it should not conform at all. -print(allToAll(NotBridged(x: 0), CustomStringConvertible.self)) // CHECK: false -print(allToAll(NotBridged(x: 0), (AnyObject & CustomStringConvertible).self)) // CHECK: false +print(#line, allToAll(NotBridged(x: 0), CustomStringConvertible.self)) // CHECK: [[@LINE]] false +print(#line, allToAll(NotBridged(x: 0), (AnyObject & CustomStringConvertible).self)) // CHECK: [[@LINE]] false #if canImport(Foundation) // This requires Foundation (for NSArray): @@ -362,5 +380,5 @@ func swiftOptimizesThisFunctionIncorrectly() -> Bool { } let result = swiftOptimizesThisFunctionIncorrectly() -print("Bridge cast result: \(result)") // CHECK-NEXT-objc: Bridge cast result: true +print(#line, "Bridge cast result: \(result)") // CHECK-NEXT-objc: Bridge cast result: true #endif diff --git a/test/stdlib/Casts.swift b/test/stdlib/Casts.swift index abab9b680b4ac..13e1754c06b08 100644 --- a/test/stdlib/Casts.swift +++ b/test/stdlib/Casts.swift @@ -21,6 +21,8 @@ import StdlibUnittest import Foundation #endif +private func blackhole(_ t: T) {} + let CastsTests = TestSuite("Casts") // Test for SR-426: missing release for some types after failed conversion @@ -161,4 +163,59 @@ CastsTests.test("Dynamic casts of CF types to protocol existentials") } #endif +CastsTests.test("Any.Protocol") { + class C {} + struct S {} + func isAnyProtocol(_ type: T.Type) -> Bool { + blackhole(T.self as! Any.Protocol) + return T.self is Any.Protocol + } + func isAnyType(_ type: T.Type) -> Bool { + return T.self is Any.Type + } + func isType(_ type: T.Type, to: U.Type) -> Bool { + return T.self is U.Type + } + + expectTrue(Int.self is Any.Type) + expectNotNil(Int.self as? Any.Type) + expectTrue(isAnyType(Int.self)) + expectFalse(Int.self is Any.Protocol) + expectNil(Int.self as? Any.Protocol) + expectFalse(isAnyProtocol(Int.self)) + expectFalse(isType(Int.self, to: Any.self)) + + expectTrue(C.self is Any.Type) + expectNotNil(C.self as? Any.Type) + expectTrue(isAnyType(C.self)) + expectFalse(C.self is Any.Protocol) + expectNil(C.self as? Any.Protocol) + expectFalse(isAnyProtocol(C.self)) + expectFalse(isType(C.self, to: Any.self)) + + expectTrue(S.self is Any.Type) + expectNotNil(S.self as? Any.Type) + expectTrue(isAnyType(S.self)) + expectFalse(S.self is Any.Protocol) + expectNil(S.self as? Any.Protocol) + expectFalse(isAnyProtocol(S.self)) + expectFalse(isType(S.self, to: Any.self)) + + expectTrue(Any.self is Any.Type) + expectNotNil(Any.self as? Any.Type) + expectTrue(isAnyType(Any.self)) + expectTrue(Any.self is Any.Protocol) + expectNotNil(Any.self as? Any.Protocol) + expectTrue(isAnyProtocol(Any.self)) + expectTrue(isType(Any.self, to: Any.self)) + + expectTrue(Any?.self is Any.Type) + expectNotNil(Any?.self as? Any.Type) + expectTrue(isAnyType(Any?.self)) + expectFalse(Any?.self is Any.Protocol) + expectNil(Any?.self as? Any.Protocol) + expectFalse(isAnyProtocol(Any?.self)) + expectFalse(isType(Any?.self, to: Any.self)) +} + runAllTests() From 45a973b6d27906f27ebf1ad429d40e654e95c26e Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Mon, 11 May 2020 13:25:33 -0700 Subject: [PATCH 2/5] Update ObjC protocol metatype test --- test/Interpreter/generic_casts_objc.swift | 35 ++++++++++++++++------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/test/Interpreter/generic_casts_objc.swift b/test/Interpreter/generic_casts_objc.swift index f7e9ccd80c01e..b3dc4f01de5b8 100644 --- a/test/Interpreter/generic_casts_objc.swift +++ b/test/Interpreter/generic_casts_objc.swift @@ -16,9 +16,12 @@ enum PE: P {} class PC: P, PObjC {} class PCSub: PC {} -func nongenericAnyIsPObjC(type: Any.Type) -> Bool { +func nongenericAnyIsPObjCType(type: Any.Type) -> Bool { return type is PObjC.Type } +func nongenericAnyIsPObjCProtocol(type: Any.Type) -> Bool { + return type is PObjC.Protocol +} func genericAnyIs(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. @@ -29,13 +32,23 @@ func genericAnyIs(type: Any.Type, to: T.Type, expected: Bool) -> Bool { } } -// CHECK-LABEL: casting types to ObjC protocols with generics: -print("casting types to ObjC protocols with generics:") -print(nongenericAnyIsPObjC(type: PS.self)) // CHECK: false -print(genericAnyIs(type: PS.self, to: PObjC.self, expected: false)) // CHECK: false -print(nongenericAnyIsPObjC(type: PE.self)) // CHECK: false -print(genericAnyIs(type: PE.self, to: PObjC.self, expected: false)) // CHECK: false -print(nongenericAnyIsPObjC(type: PC.self)) // CHECK: true -print(genericAnyIs(type: PC.self, to: PObjC.self, expected: true)) // CHECK-ONONE: true -print(nongenericAnyIsPObjC(type: PCSub.self)) // CHECK: true -print(genericAnyIs(type: PCSub.self, to: PObjC.self, expected: true)) // CHECK-ONONE: true +// CHECK-LABEL: casting types to ObjC protocol existential metatype: +print("casting types to ObjC protocol existential metatype:") +print(#line, nongenericAnyIsPObjCType(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPObjCType(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPObjCType(type: PC.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyIsPObjCType(type: PCSub.self)) // CHECK: [[@LINE]] true + +// CHECK-LABEL: casting types to ObjC protocol metatype: +print("casting types to ObjC protocol metatype:") +print(#line, nongenericAnyIsPObjCProtocol(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPObjCProtocol(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPObjCProtocol(type: PC.self)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPObjCProtocol(type: PCSub.self)) // CHECK: [[@LINE]] false + +// CHECK-LABEL: casting types to ObjC protocol metatype via generic: +print("casting types to ObjC protocol metatype via generic:") +print(#line, genericAnyIs(type: PS.self, to: PObjC.self, expected: false)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PE.self, to: PObjC.self, expected: false)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PC.self, to: PObjC.self, expected: true)) // CHECK-ONONE: [[@LINE]] false +print(#line, genericAnyIs(type: PCSub.self, to: PObjC.self, expected: true)) // CHECK-ONONE: [[@LINE]] false From c4028723cb7dc07e1f312e4dd2e3abdf44b37d81 Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Tue, 12 May 2020 16:29:56 -0700 Subject: [PATCH 3/5] Don't exercise as! here if it's sure to fail --- test/stdlib/Casts.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/stdlib/Casts.swift b/test/stdlib/Casts.swift index 13e1754c06b08..b7adf2bb4d6b3 100644 --- a/test/stdlib/Casts.swift +++ b/test/stdlib/Casts.swift @@ -167,8 +167,12 @@ CastsTests.test("Any.Protocol") { class C {} struct S {} func isAnyProtocol(_ type: T.Type) -> Bool { - blackhole(T.self as! Any.Protocol) - return T.self is Any.Protocol + let result = T.self is Any.Protocol + if result { + // `as!` should succeed if `is` does + blackhole(T.self as! Any.Protocol) + } + return result } func isAnyType(_ type: T.Type) -> Bool { return T.self is Any.Type From 821ae7dc9a06ba3abd36fba3447325c72c284fe7 Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Wed, 1 Jul 2020 11:15:18 -0700 Subject: [PATCH 4/5] Make the default value and the expected value match --- test/Interpreter/generic_casts.swift | 37 +++++++++++++++++----------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/test/Interpreter/generic_casts.swift b/test/Interpreter/generic_casts.swift index 1ff0a48574be1..73f1837d20ab9 100644 --- a/test/Interpreter/generic_casts.swift +++ b/test/Interpreter/generic_casts.swift @@ -155,6 +155,9 @@ func nongenericAnyIsPProtocol(type: Any.Type) -> Bool { func nongenericAnyIsPAndAnyObjectType(type: Any.Type) -> Bool { return type is (P & AnyObject).Type } +func nongenericAnyIsPAndAnyObjectProtocol(type: Any.Type) -> Bool { + return type is (P & AnyObject).Protocol +} func nongenericAnyIsPAndPCSubType(type: Any.Type) -> Bool { return type is (P & PCSub).Type } @@ -178,6 +181,9 @@ func nongenericAnyAsConditionalPProtocol(type: Any.Type) -> Bool { func nongenericAnyAsConditionalPAndAnyObjectType(type: Any.Type) -> Bool { return (type as? (P & AnyObject).Type) != nil } +func nongenericAnyAsConditionalPAndAnyObjectProtocol(type: Any.Type) -> Bool { + return (type as? (P & AnyObject).Protocol) != nil +} func nongenericAnyAsConditionalPAndPCSubType(type: Any.Type) -> Bool { return (type as? (P & PCSub).Type) != nil } @@ -230,16 +236,16 @@ print(#line, PS() is P) // CHECK: [[@LINE]] true // But that theory is not the one that Swift currently // implements. print(#line, nongenericAnyIsPProtocol(type: PS.self)) // CHECK: [[@LINE]] false -print(#line, genericAnyIs(type: PS.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PS.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyIsPType(type: PE.self)) // CHECK: [[@LINE]] true print(#line, nongenericAnyIsPProtocol(type: PE.self)) // CHECK: [[@LINE]] false -print(#line, genericAnyIs(type: PE.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PE.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyIsPType(type: PC.self)) // CHECK: [[@LINE]] true print(#line, nongenericAnyIsPProtocol(type: PC.self)) // CHECK: [[@LINE]] false -print(#line, genericAnyIs(type: PC.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PC.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyIsPType(type: PCSub.self)) // CHECK: [[@LINE]] true print(#line, nongenericAnyIsPProtocol(type: PCSub.self)) // CHECK: [[@LINE]] false -print(#line, genericAnyIs(type: PCSub.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PCSub.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false // CHECK-LABEL: conditionally casting types to protocols with generics: print(#line, "conditionally casting types to protocols with generics:") @@ -248,16 +254,16 @@ print(#line, nongenericAnyAsConditionalPProtocol(type: P.self)) // CHECK: [[@LIN print(#line, genericAnyAsConditional(type: P.self, to: P.self, expected: true)) // CHECK: [[@LINE]] true print(#line, nongenericAnyAsConditionalPType(type: PS.self)) // CHECK: [[@LINE]] true print(#line, nongenericAnyAsConditionalPProtocol(type: PS.self)) // CHECK: [[@LINE]] false -print(#line, genericAnyAsConditional(type: PS.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PS.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyAsConditionalPType(type: PE.self)) // CHECK: [[@LINE]] true print(#line, nongenericAnyAsConditionalPProtocol(type: PE.self)) // CHECK: [[@LINE]] false -print(#line, genericAnyAsConditional(type: PE.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PE.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyAsConditionalPType(type: PC.self)) // CHECK: [[@LINE]] true print(#line, nongenericAnyAsConditionalPProtocol(type: PC.self)) // CHECK: [[@LINE]] false -print(#line, genericAnyAsConditional(type: PC.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PC.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyAsConditionalPType(type: PCSub.self)) // CHECK: [[@LINE]] true print(#line, nongenericAnyAsConditionalPProtocol(type: PCSub.self)) // CHECK: [[@LINE]] false -print(#line, genericAnyAsConditional(type: PCSub.self, to: P.self, expected: true)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PCSub.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false // CHECK-LABEL: unconditionally casting types to protocols with generics: print(#line, "unconditionally casting types to protocols with generics:") @@ -280,17 +286,20 @@ print(#line, genericAnyIs(type: PS.self, to: (P & AnyObject).self, expected: fal print(#line, nongenericAnyIsPAndAnyObjectType(type: PE.self)) // CHECK: [[@LINE]] false print(#line, genericAnyIs(type: PE.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyIsPAndAnyObjectType(type: PC.self)) // CHECK: [[@LINE]] true -print(#line, genericAnyIs(type: PC.self, to: (P & AnyObject).self, expected: true)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPAndAnyObjectProtocol(type: PC.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PC.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyIsPAndAnyObjectType(type: PCSub.self)) // CHECK: [[@LINE]] true -print(#line, genericAnyIs(type: PCSub.self, to: (P & AnyObject).self, expected: true)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPAndAnyObjectProtocol(type: PCSub.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PCSub.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyAsConditionalPAndAnyObjectType(type: PS.self)) // CHECK: [[@LINE]] false print(#line, genericAnyAsConditional(type: PS.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyAsConditionalPAndAnyObjectType(type: PE.self)) // CHECK: [[@LINE]] false print(#line, genericAnyAsConditional(type: PE.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyAsConditionalPAndAnyObjectType(type: PC.self)) // CHECK: [[@LINE]] true -print(#line, genericAnyAsConditional(type: PC.self, to: (P & AnyObject).self, expected: true)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPAndAnyObjectProtocol(type: PC.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PC.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyAsConditionalPAndAnyObjectType(type: PCSub.self)) // CHECK: [[@LINE]] true -print(#line, genericAnyAsConditional(type: PCSub.self, to: (P & AnyObject).self, expected: true)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PCSub.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false // CHECK-LABEL: casting types to protocol & class existentials: print(#line, "casting types to protocol & class existentials:") @@ -301,7 +310,7 @@ print(#line, genericAnyIs(type: PE.self, to: (P & PCSub).self, expected: false)) //print(#line, nongenericAnyIsPAndPCSubType(type: PC.self)) // CHECK-SR-11565: [[@LINE]] false -- FIXME: reenable this when SR-11565 is fixed print(#line, genericAnyIs(type: PC.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyIsPAndPCSubType(type: PCSub.self)) // CHECK: [[@LINE]] true -print(#line, genericAnyIs(type: PCSub.self, to: (P & PCSub).self, expected: true)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PCSub.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyAsConditionalPAndPCSubType(type: PS.self)) // CHECK: [[@LINE]] false print(#line, genericAnyAsConditional(type: PS.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyAsConditionalPAndPCSubType(type: PE.self)) // CHECK: [[@LINE]] false @@ -309,7 +318,7 @@ print(#line, genericAnyAsConditional(type: PE.self, to: (P & PCSub).self, expect // print(#line, nongenericAnyAsConditionalPAndPCSubType(type: PC.self)) // CHECK-SR-11565: [[@LINE]] false -- FIXME: reenable this when SR-11565 is fixed print(#line, genericAnyAsConditional(type: PC.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false print(#line, nongenericAnyAsConditionalPAndPCSubType(type: PCSub.self)) // CHECK: [[@LINE]] true -print(#line, genericAnyAsConditional(type: PCSub.self, to: (P & PCSub).self, expected: true)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PCSub.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false // CHECK-LABEL: type comparisons: From 66989ffdf358e6544a6b2d61aa83688d990a8ee6 Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Wed, 1 Jul 2020 12:45:31 -0700 Subject: [PATCH 5/5] Make default values match expected values --- test/Interpreter/generic_casts_objc.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Interpreter/generic_casts_objc.swift b/test/Interpreter/generic_casts_objc.swift index b3dc4f01de5b8..e9561d2e2e047 100644 --- a/test/Interpreter/generic_casts_objc.swift +++ b/test/Interpreter/generic_casts_objc.swift @@ -50,5 +50,5 @@ print(#line, nongenericAnyIsPObjCProtocol(type: PCSub.self)) // CHECK: [[@LINE]] print("casting types to ObjC protocol metatype via generic:") print(#line, genericAnyIs(type: PS.self, to: PObjC.self, expected: false)) // CHECK: [[@LINE]] false print(#line, genericAnyIs(type: PE.self, to: PObjC.self, expected: false)) // CHECK: [[@LINE]] false -print(#line, genericAnyIs(type: PC.self, to: PObjC.self, expected: true)) // CHECK-ONONE: [[@LINE]] false -print(#line, genericAnyIs(type: PCSub.self, to: PObjC.self, expected: true)) // CHECK-ONONE: [[@LINE]] false +print(#line, genericAnyIs(type: PC.self, to: PObjC.self, expected: false)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PCSub.self, to: PObjC.self, expected: false)) // CHECK: [[@LINE]] false