mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
We need to arrange enum type metadata in a way where a client can fish out generic parameters without knowing if we have a payload size or not. The payload size is only used inside the module that defined the enum, and may change if new cases are added. So put the generic parameters first before the payload size, and don't crash when an EnumMetadataScanner is used with a resilient enum.
429 lines
9.1 KiB
Swift
429 lines
9.1 KiB
Swift
// RUN: rm -rf %t && mkdir -p %t
|
|
|
|
// RUN: %target-build-swift -emit-library -Xfrontend -enable-resilience -c %S/../Inputs/resilient_struct.swift -o %t/resilient_struct.o
|
|
// RUN: %target-build-swift -emit-module -Xfrontend -enable-resilience -c %S/../Inputs/resilient_struct.swift -o %t/resilient_struct.o
|
|
|
|
// RUN: %target-build-swift -emit-library -Xfrontend -enable-resilience -c %S/../Inputs/resilient_enum.swift -I %t/ -o %t/resilient_enum.o
|
|
// RUN: %target-build-swift -emit-module -Xfrontend -enable-resilience -c %S/../Inputs/resilient_enum.swift -I %t/ -o %t/resilient_enum.o
|
|
|
|
// RUN: %target-build-swift %s -Xlinker %t/resilient_struct.o -Xlinker %t/resilient_enum.o -I %t -L %t -o %t/main
|
|
// RUN: %target-run %t/main
|
|
|
|
// REQUIRES: executable_test
|
|
|
|
import StdlibUnittest
|
|
|
|
|
|
import resilient_enum
|
|
import resilient_struct
|
|
|
|
var ResilientEnumTestSuite = TestSuite("ResilientEnum")
|
|
|
|
ResilientEnumTestSuite.test("ResilientEmptyEnum") {
|
|
let e = ResilientEmptyEnum.X
|
|
let n: Int
|
|
switch e {
|
|
case .X: n = 0
|
|
default: n = -1
|
|
}
|
|
expectEqual(n, 0)
|
|
}
|
|
|
|
ResilientEnumTestSuite.test("ResilientSingletonEnum") {
|
|
let o: AnyObject = ArtClass()
|
|
let e = ResilientSingletonEnum.X(o)
|
|
let n: Int
|
|
switch e {
|
|
case .X(let oo):
|
|
n = 0
|
|
expectTrue(o === oo)
|
|
default:
|
|
n = -1
|
|
}
|
|
expectEqual(n, 0)
|
|
}
|
|
|
|
ResilientEnumTestSuite.test("ResilientSingletonGenericEnum") {
|
|
let o = ArtClass()
|
|
let e = ResilientSingletonGenericEnum.X(o)
|
|
let n: Int
|
|
switch e {
|
|
case .X(let oo):
|
|
n = 0
|
|
expectEqual(o === oo, true)
|
|
default:
|
|
n = -1
|
|
}
|
|
expectEqual(n, 0)
|
|
}
|
|
|
|
ResilientEnumTestSuite.test("ResilientNoPayloadEnum") {
|
|
let a: [ResilientNoPayloadEnum] = [.A, .B, .C]
|
|
let b: [Int] = a.map {
|
|
switch $0 {
|
|
case .A:
|
|
return 0
|
|
case .B:
|
|
return 1
|
|
case .C:
|
|
return 2
|
|
default:
|
|
return -1
|
|
}
|
|
}
|
|
|
|
expectEqual(b, [0, 1, 2])
|
|
}
|
|
|
|
ResilientEnumTestSuite.test("ResilientSinglePayloadEnum") {
|
|
let o = ArtClass()
|
|
let a: [ResilientSinglePayloadEnum] = [.A, .B, .C, .X(o)]
|
|
let b: [Int] = a.map {
|
|
switch $0 {
|
|
case .A:
|
|
return 0
|
|
case .B:
|
|
return 1
|
|
case .C:
|
|
return 2
|
|
case .X(let oo):
|
|
expectTrue(o === oo)
|
|
return 3
|
|
default:
|
|
return -1
|
|
}
|
|
}
|
|
|
|
expectEqual(b, [0, 1, 2, 3])
|
|
}
|
|
|
|
ResilientEnumTestSuite.test("ResilientSinglePayloadGenericEnum") {
|
|
let o = ArtClass()
|
|
let a: [ResilientSinglePayloadGenericEnum<ArtClass>] = [.A, .B, .C, .X(o)]
|
|
let b: [Int] = a.map {
|
|
switch $0 {
|
|
case .A:
|
|
return 0
|
|
case .B:
|
|
return 1
|
|
case .C:
|
|
return 2
|
|
case .X(let oo):
|
|
expectTrue(o === oo)
|
|
return 3
|
|
default:
|
|
return -1
|
|
}
|
|
}
|
|
|
|
expectEqual(b, [0, 1, 2, 3])
|
|
}
|
|
|
|
ResilientEnumTestSuite.test("ResilientMultiPayloadEnum") {
|
|
let a: [ResilientMultiPayloadEnum] =
|
|
[.A, .B, .C, .X(1), .Y(2)]
|
|
let b: [Int] = a.map {
|
|
switch $0 {
|
|
case .A:
|
|
return 0
|
|
case .B:
|
|
return 1
|
|
case .C:
|
|
return 2
|
|
case .X(let x):
|
|
expectEqual(x, 1)
|
|
return 3
|
|
case .Y(let y):
|
|
expectEqual(y, 2)
|
|
return 4
|
|
default:
|
|
return -1
|
|
}
|
|
}
|
|
|
|
expectEqual(b, [0, 1, 2, 3, 4])
|
|
}
|
|
|
|
ResilientEnumTestSuite.test("ResilientMultiPayloadEnumRoundTrip") {
|
|
let a = [0, 1, 2, 3, 4]
|
|
let b = a.map { makeResilientMultiPayloadEnum(1122, i: $0) }
|
|
let c: [Int] = b.map {
|
|
switch $0 {
|
|
case .A:
|
|
return 0
|
|
case .B:
|
|
return 1
|
|
case .C:
|
|
return 2
|
|
case .X(let x):
|
|
expectEqual(x, 1122)
|
|
return 3
|
|
case .Y(let y):
|
|
expectEqual(y, 1122)
|
|
return 4
|
|
default:
|
|
return -1
|
|
}
|
|
}
|
|
|
|
expectEqual(c, a)
|
|
}
|
|
|
|
ResilientEnumTestSuite.test("ResilientMultiPayloadEnumSpareBits") {
|
|
let o1 = ArtClass()
|
|
let o2 = ArtClass()
|
|
let a: [ResilientMultiPayloadEnumSpareBits] =
|
|
[.A, .B, .C, .X(o1), .Y(o2)]
|
|
let b: [Int] = a.map {
|
|
switch $0 {
|
|
case .A:
|
|
return 0
|
|
case .B:
|
|
return 1
|
|
case .C:
|
|
return 2
|
|
case .X(let oo1):
|
|
expectTrue(oo1 === o1)
|
|
return 3
|
|
case .Y(let oo2):
|
|
expectTrue(oo2 === o2)
|
|
return 4
|
|
default:
|
|
return -1
|
|
}
|
|
}
|
|
|
|
expectEqual(b, [0, 1, 2, 3, 4])
|
|
}
|
|
|
|
ResilientEnumTestSuite.test("ResilientMultiPayloadEnumSpareBitsRoundTrip") {
|
|
let o = ArtClass()
|
|
let a = [0, 1, 2, 3, 4]
|
|
let b = a.map { makeResilientMultiPayloadEnumSpareBits(o, i: $0) }
|
|
let c: [Int] = b.map {
|
|
switch $0 {
|
|
case .A:
|
|
return 0
|
|
case .B:
|
|
return 1
|
|
case .C:
|
|
return 2
|
|
case .X(let oo):
|
|
expectTrue(oo === o)
|
|
return 3
|
|
case .Y(let oo):
|
|
expectTrue(oo === o)
|
|
return 4
|
|
default:
|
|
return -1
|
|
}
|
|
}
|
|
|
|
expectEqual(c, a)
|
|
}
|
|
|
|
ResilientEnumTestSuite.test("ResilientMultiPayloadEnumSpareBitsAndExtraBits") {
|
|
let o = ArtClass()
|
|
let s: SevenSpareBits = (false, 1, 2, 3, 4, 5, 6, 7)
|
|
let a: [ResilientMultiPayloadEnumSpareBitsAndExtraBits]
|
|
= [.P1(s), .P2(o), .P3(o), .P4(o), .P5(o), .P6(o), .P7(o), .P8(o)]
|
|
let b: [Int] = a.map {
|
|
switch $0 {
|
|
case .P1(let ss):
|
|
// FIXME: derive Equatable conformances for arbitrary tuples :-)
|
|
expectEqual(ss.0, s.0)
|
|
expectEqual(ss.1, s.1)
|
|
expectEqual(ss.2, s.2)
|
|
expectEqual(ss.3, s.3)
|
|
expectEqual(ss.4, s.4)
|
|
expectEqual(ss.5, s.5)
|
|
expectEqual(ss.6, s.6)
|
|
expectEqual(ss.7, s.7)
|
|
return 0
|
|
case .P2(let oo):
|
|
expectTrue(oo === o)
|
|
return 1
|
|
case .P3(let oo):
|
|
expectTrue(oo === o)
|
|
return 2
|
|
case .P4(let oo):
|
|
expectTrue(oo === o)
|
|
return 3
|
|
case .P5(let oo):
|
|
expectTrue(oo === o)
|
|
return 4
|
|
case .P6(let oo):
|
|
expectTrue(oo === o)
|
|
return 5
|
|
case .P7(let oo):
|
|
expectTrue(oo === o)
|
|
return 6
|
|
case .P8(let oo):
|
|
expectTrue(oo === o)
|
|
return 7
|
|
default:
|
|
return -1
|
|
}
|
|
}
|
|
|
|
expectEqual(b, [0, 1, 2, 3, 4, 5, 6, 7])
|
|
}
|
|
|
|
ResilientEnumTestSuite.test("ResilientMultiPayloadGenericEnum") {
|
|
let o1 = ArtClass()
|
|
let o2 = ArtClass()
|
|
let a: [ResilientMultiPayloadGenericEnum<ArtClass>] =
|
|
[.A, .B, .C, .X(o1), .Y(o2)]
|
|
let b: [Int] = a.map {
|
|
switch $0 {
|
|
case .A:
|
|
return 0
|
|
case .B:
|
|
return 1
|
|
case .C:
|
|
return 2
|
|
case .X(let oo1):
|
|
expectTrue(oo1 === o1)
|
|
return 3
|
|
case .Y(let oo2):
|
|
expectTrue(oo2 === o2)
|
|
return 4
|
|
default:
|
|
return -1
|
|
}
|
|
}
|
|
|
|
expectEqual(b, [0, 1, 2, 3, 4])
|
|
}
|
|
|
|
public func getMetadata() -> Any.Type {
|
|
return Shape.self
|
|
}
|
|
|
|
ResilientEnumTestSuite.test("DynamicLayoutMetatype") {
|
|
do {
|
|
var output = ""
|
|
let expected = "- resilient_enum.Shape #0\n"
|
|
dump(getMetadata(), to: &output)
|
|
expectEqual(output, expected)
|
|
}
|
|
do {
|
|
expectEqual(true, getMetadata() == getMetadata())
|
|
}
|
|
}
|
|
|
|
ResilientEnumTestSuite.test("DynamicLayoutSinglePayload") {
|
|
let s = Size(w: 10, h: 20)
|
|
let a: [SimpleShape] = [.KleinBottle, .Triangle(s)]
|
|
|
|
let b: [Int] = a.map {
|
|
switch $0 {
|
|
case .KleinBottle:
|
|
return 0
|
|
case .Triangle(let s):
|
|
expectEqual(s.w, 10)
|
|
expectEqual(s.h, 20)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
expectEqual(b, [0, 1])
|
|
}
|
|
|
|
ResilientEnumTestSuite.test("DynamicLayoutMultiPayload") {
|
|
let s = Size(w: 10, h: 20)
|
|
let a: [Shape] = [.Point, .Rect(s), .RoundedRect(s, s)]
|
|
|
|
let b: [Int] = a.map {
|
|
switch $0 {
|
|
case .Point:
|
|
return 0
|
|
case .Rect(let s):
|
|
expectEqual(s.w, 10)
|
|
expectEqual(s.h, 20)
|
|
return 1
|
|
case .RoundedRect(let s, let ss):
|
|
expectEqual(s.w, 10)
|
|
expectEqual(s.h, 20)
|
|
expectEqual(ss.w, 10)
|
|
expectEqual(ss.h, 20)
|
|
return 2
|
|
}
|
|
}
|
|
|
|
expectEqual(b, [0, 1, 2])
|
|
}
|
|
|
|
ResilientEnumTestSuite.test("DynamicLayoutMultiPayload2") {
|
|
let c = Color(r: 1, g: 2, b: 3)
|
|
let a: [CustomColor] = [.Black, .White, .Custom(c), .Bespoke(c, c)]
|
|
|
|
let b: [Int] = a.map {
|
|
switch $0 {
|
|
case .Black:
|
|
return 0
|
|
case .White:
|
|
return 1
|
|
case .Custom(let c):
|
|
expectEqual(c.r, 1)
|
|
expectEqual(c.g, 2)
|
|
expectEqual(c.b, 3)
|
|
return 2
|
|
case .Bespoke(let c, let cc):
|
|
expectEqual(c.r, 1)
|
|
expectEqual(c.g, 2)
|
|
expectEqual(c.b, 3)
|
|
expectEqual(cc.r, 1)
|
|
expectEqual(cc.g, 2)
|
|
expectEqual(cc.b, 3)
|
|
return 3
|
|
}
|
|
}
|
|
|
|
expectEqual(b, [0, 1, 2, 3])
|
|
}
|
|
|
|
// Make sure case numbers round-trip if payload has zero size
|
|
|
|
ResilientEnumTestSuite.test("ResilientEnumWithEmptyCase") {
|
|
let a: [ResilientEnumWithEmptyCase] = getResilientEnumWithEmptyCase()
|
|
|
|
let b: [Int] = a.map {
|
|
switch $0 {
|
|
case .A:
|
|
return 0
|
|
case .B:
|
|
return 1
|
|
case .Empty:
|
|
return 2
|
|
default:
|
|
return -1
|
|
}
|
|
}
|
|
|
|
expectEqual(b, [0, 1, 2])
|
|
}
|
|
|
|
// Methods inside extensions of resilient enums fish out type parameters
|
|
// from metadata -- make sure we can do that
|
|
extension ResilientMultiPayloadGenericEnum {
|
|
public func getTypeParameter() -> T.Type {
|
|
return T.self
|
|
}
|
|
}
|
|
|
|
extension ResilientMultiPayloadGenericEnumFixedSize {
|
|
public func getTypeParameter() -> T.Type {
|
|
return T.self
|
|
}
|
|
}
|
|
|
|
class Base {}
|
|
|
|
ResilientEnumTestSuite.test("ResilientEnumExtension") {
|
|
expectEqual(Base.self, ResilientMultiPayloadGenericEnum<Base>.A.getTypeParameter())
|
|
expectEqual(Base.self, ResilientMultiPayloadGenericEnumFixedSize<Base>.A.getTypeParameter())
|
|
}
|
|
|
|
runAllTests()
|