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 *
|
||||
findWitnessTableForDynamicCastToExistential1(const Metadata *sourceType,
|
||||
findWitnessTableForDynamicCastToExistential1(OpaqueValue *sourceValue,
|
||||
const Metadata *sourceType,
|
||||
const Metadata *destType) {
|
||||
if (destType->getKind() != MetadataKind::Existential)
|
||||
swift::crash("Swift protocol conformance check failed: "
|
||||
@@ -2527,6 +2528,15 @@ findWitnessTableForDynamicCastToExistential1(const Metadata *sourceType,
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -2537,7 +2547,8 @@ extern "C" bool
|
||||
swift_stdlib_conformsToProtocol(
|
||||
OpaqueValue *sourceValue, const Metadata *_destType,
|
||||
const Metadata *sourceType, const Metadata *destType) {
|
||||
auto vw = findWitnessTableForDynamicCastToExistential1(sourceType, destType);
|
||||
auto vw = findWitnessTableForDynamicCastToExistential1(sourceValue,
|
||||
sourceType, destType);
|
||||
sourceType->vw_destroy(sourceValue);
|
||||
return vw != nullptr;
|
||||
}
|
||||
@@ -2550,7 +2561,8 @@ extern "C" FixedOpaqueExistentialContainer<1>
|
||||
swift_stdlib_dynamicCastToExistential1Unconditional(
|
||||
OpaqueValue *sourceValue, const Metadata *_destType,
|
||||
const Metadata *sourceType, const Metadata *destType) {
|
||||
auto vw = findWitnessTableForDynamicCastToExistential1(sourceType, destType);
|
||||
auto vw = findWitnessTableForDynamicCastToExistential1(sourceValue,
|
||||
sourceType, destType);
|
||||
if (!vw)
|
||||
swift::crash("Swift dynamic cast failed: "
|
||||
"type does not conform to the protocol");
|
||||
@@ -2586,7 +2598,8 @@ _TFSs26_injectNothingIntoOptionalU__FT_GSqQ__(const Metadata *T);
|
||||
extern "C" OpaqueExistentialContainer swift_stdlib_dynamicCastToExistential1(
|
||||
OpaqueValue *sourceValue, const Metadata *_destType,
|
||||
const Metadata *sourceType, const Metadata *destType) {
|
||||
auto vw = findWitnessTableForDynamicCastToExistential1(sourceType, destType);
|
||||
auto vw = findWitnessTableForDynamicCastToExistential1(sourceValue,
|
||||
sourceType, destType);
|
||||
if (!vw) {
|
||||
sourceType->vw_destroy(sourceValue);
|
||||
return _TFSs26_injectNothingIntoOptionalU__FT_GSqQ__(destType);
|
||||
|
||||
@@ -251,7 +251,9 @@ func test_CTypesPrinting() {
|
||||
test_CTypesPrinting()
|
||||
// CHECK: test_CTypesPrinting done
|
||||
|
||||
struct StructPrintable : Printable {
|
||||
protocol ProtocolUnrelatedToPrinting {}
|
||||
|
||||
struct StructPrintable : Printable, ProtocolUnrelatedToPrinting {
|
||||
let 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 {
|
||||
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() {
|
||||
var arrayOfInts: Int[] = []
|
||||
printedIs(arrayOfInts, "[]")
|
||||
@@ -299,6 +427,14 @@ func test_ArrayPrinting() {
|
||||
|
||||
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")
|
||||
}
|
||||
test_ArrayPrinting()
|
||||
@@ -320,13 +456,13 @@ func test_TuplePrinting() {
|
||||
var arrayOfTuples1 =
|
||||
[ (1, "two", StructPrintable(3), StructDebugPrintable(4),
|
||||
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 =
|
||||
[ (1, "two", WithoutDescription(3)),
|
||||
(11, "twenty-two", WithoutDescription(33)),
|
||||
(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")
|
||||
}
|
||||
|
||||
@@ -350,27 +350,28 @@ test_isBridgedVerbatimToObjectiveC()
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
protocol P2 {}
|
||||
func test_dynamicCastToExistential1() {
|
||||
// The protocol should be defined in the standard library, otherwise the cast
|
||||
// does not work.
|
||||
|
||||
typealias P1 = LogicValue
|
||||
|
||||
struct StructConformsToP1 : LogicValue {
|
||||
struct StructConformsToP1 : LogicValue, P2 {
|
||||
func getLogicValue() -> Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
struct StructDoesNotConformToP1 {}
|
||||
struct StructDoesNotConformToP1 : P2 {}
|
||||
|
||||
class ClassConformsToP1 : LogicValue {
|
||||
class ClassConformsToP1 : LogicValue, P2 {
|
||||
func getLogicValue() -> Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class ClassDoesNotConformToP1 {}
|
||||
class ClassDoesNotConformToP1 : P2 {}
|
||||
|
||||
var someP1Value = StructConformsToP1()
|
||||
var someNotP1Value = StructDoesNotConformToP1()
|
||||
@@ -382,14 +383,54 @@ func test_dynamicCastToExistential1() {
|
||||
assert(_stdlib_conformsToProtocol(someP1Ref, 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(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(someNotP1Value, P1.self))
|
||||
assert(_stdlib_dynamicCastToExistential1(someP1Ref, P1.self)!.getLogicValue())
|
||||
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")
|
||||
}
|
||||
test_dynamicCastToExistential1()
|
||||
|
||||
Reference in New Issue
Block a user