mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
stdlib/runtime: teach DynamicCastToExistential1 to handle source values that
are existentials rdar://16925792 Swift SVN r18107
This commit is contained in:
@@ -2512,7 +2512,8 @@ recur:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const void *
|
static const void *
|
||||||
findWitnessTableForDynamicCastToExistential1(const Metadata *sourceType,
|
findWitnessTableForDynamicCastToExistential1(OpaqueValue *sourceValue,
|
||||||
|
const Metadata *sourceType,
|
||||||
const Metadata *destType) {
|
const Metadata *destType) {
|
||||||
if (destType->getKind() != MetadataKind::Existential)
|
if (destType->getKind() != MetadataKind::Existential)
|
||||||
swift::crash("Swift protocol conformance check failed: "
|
swift::crash("Swift protocol conformance check failed: "
|
||||||
@@ -2527,6 +2528,15 @@ findWitnessTableForDynamicCastToExistential1(const Metadata *sourceType,
|
|||||||
|
|
||||||
auto destProtocolDescriptor = destExistentialMetadata->Protocols[0];
|
auto destProtocolDescriptor = destExistentialMetadata->Protocols[0];
|
||||||
|
|
||||||
|
if (sourceType->getKind() == MetadataKind::Existential) {
|
||||||
|
const auto sourceExistentialMetadata =
|
||||||
|
static_cast<const ExistentialTypeMetadata *>(sourceType);
|
||||||
|
// Existentials don't carry complete type information about the value, but
|
||||||
|
// it is necessary to find the witness tables. Find the dynamic type and
|
||||||
|
// use it instead.
|
||||||
|
sourceType = sourceExistentialMetadata->getDynamicType(sourceValue);
|
||||||
|
}
|
||||||
|
|
||||||
return swift_conformsToProtocol(sourceType, destProtocolDescriptor, nullptr);
|
return swift_conformsToProtocol(sourceType, destProtocolDescriptor, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2537,7 +2547,8 @@ extern "C" bool
|
|||||||
swift_stdlib_conformsToProtocol(
|
swift_stdlib_conformsToProtocol(
|
||||||
OpaqueValue *sourceValue, const Metadata *_destType,
|
OpaqueValue *sourceValue, const Metadata *_destType,
|
||||||
const Metadata *sourceType, const Metadata *destType) {
|
const Metadata *sourceType, const Metadata *destType) {
|
||||||
auto vw = findWitnessTableForDynamicCastToExistential1(sourceType, destType);
|
auto vw = findWitnessTableForDynamicCastToExistential1(sourceValue,
|
||||||
|
sourceType, destType);
|
||||||
sourceType->vw_destroy(sourceValue);
|
sourceType->vw_destroy(sourceValue);
|
||||||
return vw != nullptr;
|
return vw != nullptr;
|
||||||
}
|
}
|
||||||
@@ -2550,7 +2561,8 @@ extern "C" FixedOpaqueExistentialContainer<1>
|
|||||||
swift_stdlib_dynamicCastToExistential1Unconditional(
|
swift_stdlib_dynamicCastToExistential1Unconditional(
|
||||||
OpaqueValue *sourceValue, const Metadata *_destType,
|
OpaqueValue *sourceValue, const Metadata *_destType,
|
||||||
const Metadata *sourceType, const Metadata *destType) {
|
const Metadata *sourceType, const Metadata *destType) {
|
||||||
auto vw = findWitnessTableForDynamicCastToExistential1(sourceType, destType);
|
auto vw = findWitnessTableForDynamicCastToExistential1(sourceValue,
|
||||||
|
sourceType, destType);
|
||||||
if (!vw)
|
if (!vw)
|
||||||
swift::crash("Swift dynamic cast failed: "
|
swift::crash("Swift dynamic cast failed: "
|
||||||
"type does not conform to the protocol");
|
"type does not conform to the protocol");
|
||||||
@@ -2586,7 +2598,8 @@ _TFSs26_injectNothingIntoOptionalU__FT_GSqQ__(const Metadata *T);
|
|||||||
extern "C" OpaqueExistentialContainer swift_stdlib_dynamicCastToExistential1(
|
extern "C" OpaqueExistentialContainer swift_stdlib_dynamicCastToExistential1(
|
||||||
OpaqueValue *sourceValue, const Metadata *_destType,
|
OpaqueValue *sourceValue, const Metadata *_destType,
|
||||||
const Metadata *sourceType, const Metadata *destType) {
|
const Metadata *sourceType, const Metadata *destType) {
|
||||||
auto vw = findWitnessTableForDynamicCastToExistential1(sourceType, destType);
|
auto vw = findWitnessTableForDynamicCastToExistential1(sourceValue,
|
||||||
|
sourceType, destType);
|
||||||
if (!vw) {
|
if (!vw) {
|
||||||
sourceType->vw_destroy(sourceValue);
|
sourceType->vw_destroy(sourceValue);
|
||||||
return _TFSs26_injectNothingIntoOptionalU__FT_GSqQ__(destType);
|
return _TFSs26_injectNothingIntoOptionalU__FT_GSqQ__(destType);
|
||||||
|
|||||||
@@ -251,7 +251,9 @@ func test_CTypesPrinting() {
|
|||||||
test_CTypesPrinting()
|
test_CTypesPrinting()
|
||||||
// CHECK: test_CTypesPrinting done
|
// CHECK: test_CTypesPrinting done
|
||||||
|
|
||||||
struct StructPrintable : Printable {
|
protocol ProtocolUnrelatedToPrinting {}
|
||||||
|
|
||||||
|
struct StructPrintable : Printable, ProtocolUnrelatedToPrinting {
|
||||||
let x: Int
|
let x: Int
|
||||||
|
|
||||||
init(_ x: Int) {
|
init(_ x: Int) {
|
||||||
@@ -275,6 +277,22 @@ struct StructDebugPrintable : DebugPrintable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct StructVeryPrintable : Printable, DebugPrintable, ProtocolUnrelatedToPrinting {
|
||||||
|
let x: Int
|
||||||
|
|
||||||
|
init(_ x: Int) {
|
||||||
|
self.x = x
|
||||||
|
}
|
||||||
|
|
||||||
|
var description: String {
|
||||||
|
return "<description: \(x)>"
|
||||||
|
}
|
||||||
|
|
||||||
|
var debugDescription: String {
|
||||||
|
return "<debugDescription: \(x)>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct WithoutDescription {
|
struct WithoutDescription {
|
||||||
let x: Int
|
let x: Int
|
||||||
|
|
||||||
@@ -283,6 +301,116 @@ struct WithoutDescription {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ClassPrintable : Printable, ProtocolUnrelatedToPrinting {
|
||||||
|
let x: Int
|
||||||
|
|
||||||
|
init(_ x: Int) {
|
||||||
|
self.x = x
|
||||||
|
}
|
||||||
|
|
||||||
|
var description: String {
|
||||||
|
return "►\(x)◀︎"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClassVeryPrintable : Printable, DebugPrintable, ProtocolUnrelatedToPrinting {
|
||||||
|
let x: Int
|
||||||
|
|
||||||
|
init(_ x: Int) {
|
||||||
|
self.x = x
|
||||||
|
}
|
||||||
|
|
||||||
|
var description: String {
|
||||||
|
return "<description: \(x)>"
|
||||||
|
}
|
||||||
|
|
||||||
|
var debugDescription: String {
|
||||||
|
return "<debugDescription: \(x)>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_ObjectPrinting() {
|
||||||
|
if true {
|
||||||
|
let s = StructPrintable(1)
|
||||||
|
printedIs(s, "►1◀︎")
|
||||||
|
}
|
||||||
|
if true {
|
||||||
|
let s: ProtocolUnrelatedToPrinting = StructPrintable(1)
|
||||||
|
printedIs(s, "►1◀︎")
|
||||||
|
}
|
||||||
|
if true {
|
||||||
|
let s: Printable = StructPrintable(1)
|
||||||
|
printedIs(s, "►1◀︎")
|
||||||
|
}
|
||||||
|
if true {
|
||||||
|
let s: Any = StructPrintable(1)
|
||||||
|
printedIs(s, "►1◀︎")
|
||||||
|
}
|
||||||
|
|
||||||
|
if true {
|
||||||
|
let s = StructVeryPrintable(1)
|
||||||
|
printedIs(s, "<description: 1>")
|
||||||
|
}
|
||||||
|
if true {
|
||||||
|
let s: ProtocolUnrelatedToPrinting = StructVeryPrintable(1)
|
||||||
|
printedIs(s, "<description: 1>")
|
||||||
|
}
|
||||||
|
if true {
|
||||||
|
let s: Printable = StructVeryPrintable(1)
|
||||||
|
printedIs(s, "<description: 1>")
|
||||||
|
}
|
||||||
|
if true {
|
||||||
|
let s: DebugPrintable = StructVeryPrintable(1)
|
||||||
|
printedIs(s, "<description: 1>")
|
||||||
|
}
|
||||||
|
if true {
|
||||||
|
let s: Any = StructVeryPrintable(1)
|
||||||
|
printedIs(s, "<description: 1>")
|
||||||
|
}
|
||||||
|
|
||||||
|
if true {
|
||||||
|
let c = ClassPrintable(1)
|
||||||
|
printedIs(c, "►1◀︎")
|
||||||
|
}
|
||||||
|
if true {
|
||||||
|
let c: ProtocolUnrelatedToPrinting = ClassPrintable(1)
|
||||||
|
printedIs(c, "►1◀︎")
|
||||||
|
}
|
||||||
|
if true {
|
||||||
|
let c: Printable = ClassPrintable(1)
|
||||||
|
printedIs(c, "►1◀︎")
|
||||||
|
}
|
||||||
|
if true {
|
||||||
|
let c: Any = ClassPrintable(1)
|
||||||
|
printedIs(c, "►1◀︎")
|
||||||
|
}
|
||||||
|
|
||||||
|
if true {
|
||||||
|
let c = ClassVeryPrintable(1)
|
||||||
|
printedIs(c, "<description: 1>")
|
||||||
|
}
|
||||||
|
if true {
|
||||||
|
let c: ProtocolUnrelatedToPrinting = ClassVeryPrintable(1)
|
||||||
|
printedIs(c, "<description: 1>")
|
||||||
|
}
|
||||||
|
if true {
|
||||||
|
let c: Printable = ClassVeryPrintable(1)
|
||||||
|
printedIs(c, "<description: 1>")
|
||||||
|
}
|
||||||
|
if true {
|
||||||
|
let c: DebugPrintable = ClassVeryPrintable(1)
|
||||||
|
printedIs(c, "<description: 1>")
|
||||||
|
}
|
||||||
|
if true {
|
||||||
|
let c: Any = ClassVeryPrintable(1)
|
||||||
|
printedIs(c, "<description: 1>")
|
||||||
|
}
|
||||||
|
|
||||||
|
println("test_ObjectPrinting done")
|
||||||
|
}
|
||||||
|
test_ObjectPrinting()
|
||||||
|
// CHECK: test_ObjectPrinting done
|
||||||
|
|
||||||
func test_ArrayPrinting() {
|
func test_ArrayPrinting() {
|
||||||
var arrayOfInts: Int[] = []
|
var arrayOfInts: Int[] = []
|
||||||
printedIs(arrayOfInts, "[]")
|
printedIs(arrayOfInts, "[]")
|
||||||
@@ -299,6 +427,14 @@ func test_ArrayPrinting() {
|
|||||||
|
|
||||||
printedIs([ StructDebugPrintable(1) ], "[►1◀︎]")
|
printedIs([ StructDebugPrintable(1) ], "[►1◀︎]")
|
||||||
|
|
||||||
|
printedIs([ ClassPrintable(1), ClassPrintable(2),
|
||||||
|
ClassPrintable(3) ],
|
||||||
|
"[►1◀︎, ►2◀︎, ►3◀︎]")
|
||||||
|
|
||||||
|
printedIs([ ClassPrintable(1), ClassPrintable(2),
|
||||||
|
ClassPrintable(3) ] as Array<AnyObject>,
|
||||||
|
"[►1◀︎, ►2◀︎, ►3◀︎]")
|
||||||
|
|
||||||
println("test_ArrayPrinting done")
|
println("test_ArrayPrinting done")
|
||||||
}
|
}
|
||||||
test_ArrayPrinting()
|
test_ArrayPrinting()
|
||||||
@@ -320,13 +456,13 @@ func test_TuplePrinting() {
|
|||||||
var arrayOfTuples1 =
|
var arrayOfTuples1 =
|
||||||
[ (1, "two", StructPrintable(3), StructDebugPrintable(4),
|
[ (1, "two", StructPrintable(3), StructDebugPrintable(4),
|
||||||
WithoutDescription(5)) ]
|
WithoutDescription(5)) ]
|
||||||
printedIs(arrayOfTuples1, "[(1, two, V1a15StructPrintable (has 1 child), V1a20StructDebugPrintable (has 1 child), V1a18WithoutDescription (has 1 child))]")
|
printedIs(arrayOfTuples1, "[(1, two, ►3◀︎, ►4◀︎, V1a18WithoutDescription (has 1 child))]")
|
||||||
|
|
||||||
var arrayOfTuples2 =
|
var arrayOfTuples2 =
|
||||||
[ (1, "two", WithoutDescription(3)),
|
[ (1, "two", WithoutDescription(3)),
|
||||||
(11, "twenty-two", WithoutDescription(33)),
|
(11, "twenty-two", WithoutDescription(33)),
|
||||||
(111, "two hundred twenty-two", WithoutDescription(333)) ]
|
(111, "two hundred twenty-two", WithoutDescription(333)) ]
|
||||||
printedIs(arrayOfTuples1, "[(1, two, V1a15StructPrintable (has 1 child), V1a20StructDebugPrintable (has 1 child), V1a18WithoutDescription (has 1 child))]")
|
printedIs(arrayOfTuples2, "[(1, two, V1a18WithoutDescription (has 1 child)), (11, twenty-two, V1a18WithoutDescription (has 1 child)), (111, two hundred twenty-two, V1a18WithoutDescription (has 1 child))]")
|
||||||
|
|
||||||
println("test_TuplePrinting done")
|
println("test_TuplePrinting done")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -350,27 +350,28 @@ test_isBridgedVerbatimToObjectiveC()
|
|||||||
|
|
||||||
//===---------------------------------------------------------------------===//
|
//===---------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
protocol P2 {}
|
||||||
func test_dynamicCastToExistential1() {
|
func test_dynamicCastToExistential1() {
|
||||||
// The protocol should be defined in the standard library, otherwise the cast
|
// The protocol should be defined in the standard library, otherwise the cast
|
||||||
// does not work.
|
// does not work.
|
||||||
|
|
||||||
typealias P1 = LogicValue
|
typealias P1 = LogicValue
|
||||||
|
|
||||||
struct StructConformsToP1 : LogicValue {
|
struct StructConformsToP1 : LogicValue, P2 {
|
||||||
func getLogicValue() -> Bool {
|
func getLogicValue() -> Bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StructDoesNotConformToP1 {}
|
struct StructDoesNotConformToP1 : P2 {}
|
||||||
|
|
||||||
class ClassConformsToP1 : LogicValue {
|
class ClassConformsToP1 : LogicValue, P2 {
|
||||||
func getLogicValue() -> Bool {
|
func getLogicValue() -> Bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ClassDoesNotConformToP1 {}
|
class ClassDoesNotConformToP1 : P2 {}
|
||||||
|
|
||||||
var someP1Value = StructConformsToP1()
|
var someP1Value = StructConformsToP1()
|
||||||
var someNotP1Value = StructDoesNotConformToP1()
|
var someNotP1Value = StructDoesNotConformToP1()
|
||||||
@@ -382,14 +383,54 @@ func test_dynamicCastToExistential1() {
|
|||||||
assert(_stdlib_conformsToProtocol(someP1Ref, P1.self))
|
assert(_stdlib_conformsToProtocol(someP1Ref, P1.self))
|
||||||
assert(!_stdlib_conformsToProtocol(someNotP1Ref, P1.self))
|
assert(!_stdlib_conformsToProtocol(someNotP1Ref, P1.self))
|
||||||
|
|
||||||
|
assert(_stdlib_conformsToProtocol(someP1Value as P1, P1.self))
|
||||||
|
assert(_stdlib_conformsToProtocol(someP1Ref as P1, P1.self))
|
||||||
|
|
||||||
|
assert(_stdlib_conformsToProtocol(someP1Value as P2, P1.self))
|
||||||
|
assert(!_stdlib_conformsToProtocol(someNotP1Value as P2, P1.self))
|
||||||
|
assert(_stdlib_conformsToProtocol(someP1Ref as P2, P1.self))
|
||||||
|
assert(!_stdlib_conformsToProtocol(someNotP1Ref as P2, P1.self))
|
||||||
|
|
||||||
|
assert(_stdlib_conformsToProtocol(someP1Value as Any, P1.self))
|
||||||
|
assert(!_stdlib_conformsToProtocol(someNotP1Value as Any, P1.self))
|
||||||
|
assert(_stdlib_conformsToProtocol(someP1Ref as Any, P1.self))
|
||||||
|
assert(!_stdlib_conformsToProtocol(someNotP1Ref as Any, P1.self))
|
||||||
|
|
||||||
|
assert(_stdlib_conformsToProtocol(someP1Ref as AnyObject, P1.self))
|
||||||
|
assert(!_stdlib_conformsToProtocol(someNotP1Ref as AnyObject, P1.self))
|
||||||
|
|
||||||
assert(_stdlib_dynamicCastToExistential1Unconditional(someP1Value, P1.self).getLogicValue())
|
assert(_stdlib_dynamicCastToExistential1Unconditional(someP1Value, P1.self).getLogicValue())
|
||||||
assert(_stdlib_dynamicCastToExistential1Unconditional(someP1Ref, P1.self).getLogicValue())
|
assert(_stdlib_dynamicCastToExistential1Unconditional(someP1Ref, P1.self).getLogicValue())
|
||||||
|
|
||||||
|
assert(_stdlib_dynamicCastToExistential1Unconditional(someP1Value as P2, P1.self).getLogicValue())
|
||||||
|
assert(_stdlib_dynamicCastToExistential1Unconditional(someP1Ref as P2, P1.self).getLogicValue())
|
||||||
|
|
||||||
|
assert(_stdlib_dynamicCastToExistential1Unconditional(someP1Value as Any, P1.self).getLogicValue())
|
||||||
|
assert(_stdlib_dynamicCastToExistential1Unconditional(someP1Ref as Any, P1.self).getLogicValue())
|
||||||
|
|
||||||
|
assert(_stdlib_dynamicCastToExistential1Unconditional(someP1Ref as AnyObject, P1.self).getLogicValue())
|
||||||
|
|
||||||
assert(_stdlib_dynamicCastToExistential1(someP1Value, P1.self)!.getLogicValue())
|
assert(_stdlib_dynamicCastToExistential1(someP1Value, P1.self)!.getLogicValue())
|
||||||
assert(!_stdlib_dynamicCastToExistential1(someNotP1Value, P1.self))
|
assert(!_stdlib_dynamicCastToExistential1(someNotP1Value, P1.self))
|
||||||
assert(_stdlib_dynamicCastToExistential1(someP1Ref, P1.self)!.getLogicValue())
|
assert(_stdlib_dynamicCastToExistential1(someP1Ref, P1.self)!.getLogicValue())
|
||||||
assert(!_stdlib_dynamicCastToExistential1(someNotP1Ref, P1.self))
|
assert(!_stdlib_dynamicCastToExistential1(someNotP1Ref, P1.self))
|
||||||
|
|
||||||
|
assert(_stdlib_dynamicCastToExistential1(someP1Value as P1, P1.self)!.getLogicValue())
|
||||||
|
assert(_stdlib_dynamicCastToExistential1(someP1Ref as P1, P1.self)!.getLogicValue())
|
||||||
|
|
||||||
|
assert(_stdlib_dynamicCastToExistential1(someP1Value as P2, P1.self)!.getLogicValue())
|
||||||
|
assert(!_stdlib_dynamicCastToExistential1(someNotP1Value as P2, P1.self))
|
||||||
|
assert(_stdlib_dynamicCastToExistential1(someP1Ref as P2, P1.self)!.getLogicValue())
|
||||||
|
assert(!_stdlib_dynamicCastToExistential1(someNotP1Ref as P2, P1.self))
|
||||||
|
|
||||||
|
assert(_stdlib_dynamicCastToExistential1(someP1Value as Any, P1.self)!.getLogicValue())
|
||||||
|
assert(!_stdlib_dynamicCastToExistential1(someNotP1Value as Any, P1.self))
|
||||||
|
assert(_stdlib_dynamicCastToExistential1(someP1Ref as Any, P1.self)!.getLogicValue())
|
||||||
|
assert(!_stdlib_dynamicCastToExistential1(someNotP1Ref as Any, P1.self))
|
||||||
|
|
||||||
|
assert(_stdlib_dynamicCastToExistential1(someP1Ref as AnyObject, P1.self)!.getLogicValue())
|
||||||
|
assert(!_stdlib_dynamicCastToExistential1(someNotP1Ref as AnyObject, P1.self))
|
||||||
|
|
||||||
println("test_dynamicCastToExistential1 done")
|
println("test_dynamicCastToExistential1 done")
|
||||||
}
|
}
|
||||||
test_dynamicCastToExistential1()
|
test_dynamicCastToExistential1()
|
||||||
|
|||||||
Reference in New Issue
Block a user