stdlib/runtime: teach DynamicCastToExistential1 to handle source values that

are existentials

rdar://16925792


Swift SVN r18107
This commit is contained in:
Dmitri Hrybenko
2014-05-15 16:32:13 +00:00
parent bf8fbfc32e
commit 2a956966ac
3 changed files with 201 additions and 11 deletions

View File

@@ -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);

View File

@@ -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")
}

View File

@@ -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()