diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp index c8349b170830d..c25154c8d061a 100644 --- a/stdlib/public/runtime/Casting.cpp +++ b/stdlib/public/runtime/Casting.cpp @@ -403,7 +403,7 @@ static bool _conformsToProtocols(const OpaqueValue *value, for (auto protocol : existentialType->getProtocols()) { if (!_conformsToProtocol(value, type, protocol, conformances)) return false; - if (protocol.needsWitnessTable()) { + if (conformances != nullptr && protocol.needsWitnessTable()) { assert(*conformances != nullptr); ++conformances; } @@ -1115,6 +1115,13 @@ swift_dynamicCastMetatypeImpl(const Metadata *sourceType, } break; + case MetadataKind::Existential: { + auto targetTypeAsExistential = static_cast(targetType); + if (!_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr)) + return nullptr; + return origSourceType; + } + default: // The cast succeeds only if the metadata pointers are statically // equivalent. diff --git a/test/Interpreter/generic_casts.swift b/test/Interpreter/generic_casts.swift index bf87feb633bfb..0f9c359bdda06 100644 --- a/test/Interpreter/generic_casts.swift +++ b/test/Interpreter/generic_casts.swift @@ -1,4 +1,6 @@ -// RUN: %target-run-simple-swift | %FileCheck %s +// 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 @@ -131,6 +133,58 @@ anyClassToCOrE(C()).print() // CHECK: C! anyClassToCOrE(D()).print() // CHECK: D! anyClassToCOrE(X()).print() // CHECK: E! +protocol P {} +struct PS: P {} +enum PE: P {} +class PC: P {} +class PCSub: PC {} + +func nongenericAnyIsP(type: Any.Type) -> Bool { + return type is P.Type +} +func nongenericAnyIsPAndAnyObject(type: Any.Type) -> Bool { + return type is (P & AnyObject).Type +} +func nongenericAnyIsPAndPCSub(type: Any.Type) -> Bool { + return type is (P & PCSub).Type +} +func genericAnyIs(type: Any.Type, to: T.Type) -> Bool { + return type is T.Type +} +// CHECK-LABEL: casting types to protocols with generics: +print("casting types to protocols with generics:") +print(nongenericAnyIsP(type: PS.self)) // CHECK: true +print(genericAnyIs(type: PS.self, to: P.self)) // CHECK-ONONE: true +print(nongenericAnyIsP(type: PE.self)) // CHECK: true +print(genericAnyIs(type: PE.self, to: P.self)) // CHECK-ONONE: true +print(nongenericAnyIsP(type: PC.self)) // CHECK: true +print(genericAnyIs(type: PC.self, to: P.self)) // CHECK-ONONE: true +print(nongenericAnyIsP(type: PCSub.self)) // CHECK: true +print(genericAnyIs(type: PCSub.self, to: P.self)) // CHECK-ONONE: true + +// CHECK-LABEL: casting types to protocol & AnyObject existentials: +print("casting types to protocol & AnyObject existentials:") +print(nongenericAnyIsPAndAnyObject(type: PS.self)) // CHECK: false +print(genericAnyIs(type: PS.self, to: (P & AnyObject).self)) // CHECK: false +print(nongenericAnyIsPAndAnyObject(type: PE.self)) // CHECK: false +print(genericAnyIs(type: PE.self, to: (P & AnyObject).self)) // CHECK: false +print(nongenericAnyIsPAndAnyObject(type: PC.self)) // CHECK: true +print(genericAnyIs(type: PC.self, to: (P & AnyObject).self)) // CHECK-ONONE: true +print(nongenericAnyIsPAndAnyObject(type: PCSub.self)) // CHECK: true +print(genericAnyIs(type: PCSub.self, to: (P & AnyObject).self)) // 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(genericAnyIs(type: PS.self, to: (P & PCSub).self)) // CHECK: false +print(nongenericAnyIsPAndPCSub(type: PE.self)) // CHECK: false +print(genericAnyIs(type: PE.self, to: (P & PCSub).self)) // CHECK: false +//print(nongenericAnyIsPAndPCSub(type: PC.self)) // CHECK-SR-11565: false -- FIXME: reenable this when SR-11565 is fixed +print(genericAnyIs(type: PC.self, to: (P & PCSub).self)) // CHECK: false +print(nongenericAnyIsPAndPCSub(type: PCSub.self)) // CHECK: true +print(genericAnyIs(type: PCSub.self, to: (P & PCSub).self)) // CHECK-ONONE: true + + // CHECK-LABEL: type comparisons: print("type comparisons:\n") print(allMetasToAllMetas(Int.self, Int.self)) // CHECK: true diff --git a/test/Interpreter/generic_casts_objc.swift b/test/Interpreter/generic_casts_objc.swift new file mode 100644 index 0000000000000..a228d4f18402a --- /dev/null +++ b/test/Interpreter/generic_casts_objc.swift @@ -0,0 +1,33 @@ +// RUN: %target-run-simple-swift | %FileCheck --check-prefix CHECK --check-prefix CHECK-ONONE --dump-input fail %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 +// REQUIRES: executable_test +// REQUIRES: objc_interop + +import Foundation + +protocol P {} +@objc protocol PObjC {} +struct PS: P {} +enum PE: P {} +class PC: P, PObjC {} +class PCSub: PC {} + +func nongenericAnyIsPObjC(type: Any.Type) -> Bool { + return type is PObjC.Type +} +func genericAnyIs(type: Any.Type, to: T.Type) -> Bool { + return type is T.Type +} + +// 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)) // CHECK: false +print(nongenericAnyIsPObjC(type: PE.self)) // CHECK: false +print(genericAnyIs(type: PE.self, to: PObjC.self)) // CHECK: false +print(nongenericAnyIsPObjC(type: PC.self)) // CHECK: true +print(genericAnyIs(type: PC.self, to: PObjC.self)) // CHECK-ONONE: true +print(nongenericAnyIsPObjC(type: PCSub.self)) // CHECK: true +print(genericAnyIs(type: PCSub.self, to: PObjC.self)) // CHECK-ONONE: true