mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Recent changes added support for resiliently-sized enums, and enums resilient to changes in implementation strategy. This patch adds resilient case numbering, fixing the problem where adding new payload cases would break existing code by changing the numbering of no-payload cases. The problem is that internally, enum cases are numbered with payload cases coming first, followed by no-payload cases. While each list is itself in declaration order, with new additions coming at the end, we need to partition it to give us a fast runtime test for "is this a payload or no-payload case index." The resilient numbering strategy used here is that the getEnumTag and destructiveInjectEnumTag value witness functions now take a tag index in the range [-ElementsWithPayload..ElementsWithNoPayload-1]. Payload elements are numbered in *reverse* declaration order, so adding new payload cases yields decreasing tag indices, and adding new no-payload cases yields increasing tag indices, allowing use sites to be resilient. This adds the adjustment between 'fragile' and 'resilient' tag indices in a somewhat unsatisfying manner, because the calculation could be pushed down further into EnumImplStrategy, simplifying both the IRGen code and the generated IR. I'll clean this up later. In the meantime, clean up some other stuff in GenEnum.cpp, mostly abstracting code that walks cases.
198 lines
4.1 KiB
Swift
198 lines
4.1 KiB
Swift
import resilient_struct
|
|
|
|
// Fixed-layout enum with resilient members
|
|
@_fixed_layout public enum SimpleShape {
|
|
case KleinBottle
|
|
case Triangle(Size)
|
|
}
|
|
|
|
// Fixed-layout enum with resilient members
|
|
@_fixed_layout public enum Shape {
|
|
case Point
|
|
case Rect(Size)
|
|
case RoundedRect(Size, Size)
|
|
}
|
|
|
|
// Fixed-layout enum with indirect resilient members
|
|
@_fixed_layout public enum FunnyShape {
|
|
indirect case Parallelogram(Size)
|
|
indirect case Trapezoid(Size)
|
|
}
|
|
|
|
// The enum payload has fixed layout inside this module, but
|
|
// resilient layout outside. Make sure we emit the payload
|
|
// size in the metadata.
|
|
|
|
public struct Color {
|
|
public let r: Int, g: Int, b: Int
|
|
|
|
public init(r: Int, g: Int, b: Int) {
|
|
self.r = r
|
|
self.g = g
|
|
self.b = b
|
|
}
|
|
}
|
|
|
|
@_fixed_layout public enum CustomColor {
|
|
case Black
|
|
case White
|
|
case Custom(Color)
|
|
case Bespoke(Color, Color)
|
|
}
|
|
|
|
// Resilient enum
|
|
public enum Medium {
|
|
// Indirect case
|
|
indirect case Pamphlet(Medium) // -1
|
|
|
|
// Case with resilient payload
|
|
case Postcard(Size) // -2
|
|
|
|
// Empty cases
|
|
case Paper // 0
|
|
case Canvas // 1
|
|
}
|
|
|
|
// Indirect resilient enum
|
|
public indirect enum IndirectApproach {
|
|
case Angle(Double) // -1
|
|
}
|
|
|
|
// Resilient enum with resilient empty payload case
|
|
public struct EmptyStruct {
|
|
public init() {}
|
|
}
|
|
|
|
public enum ResilientEnumWithEmptyCase {
|
|
case A // 0
|
|
case B // 1
|
|
case Empty(EmptyStruct) // -1
|
|
}
|
|
|
|
public func getResilientEnumWithEmptyCase() -> [ResilientEnumWithEmptyCase] {
|
|
return [.A, .B, .Empty(EmptyStruct())]
|
|
}
|
|
|
|
// Specific enum implementations for executable tests
|
|
public enum ResilientEmptyEnum {
|
|
case X
|
|
}
|
|
|
|
public enum ResilientSingletonEnum {
|
|
case X(AnyObject)
|
|
}
|
|
|
|
public enum ResilientSingletonGenericEnum<T> {
|
|
case X(T)
|
|
}
|
|
|
|
public enum ResilientNoPayloadEnum {
|
|
case A
|
|
case B
|
|
case C
|
|
}
|
|
|
|
public enum ResilientSinglePayloadEnum {
|
|
case X(AnyObject) // -1
|
|
case A // 0
|
|
case B // 1
|
|
case C // 2
|
|
}
|
|
|
|
public enum ResilientSinglePayloadGenericEnum<T> {
|
|
case X(T) // -1
|
|
case A // 0
|
|
case B // 1
|
|
case C // 2
|
|
}
|
|
|
|
public class ArtClass {
|
|
public init() {}
|
|
}
|
|
|
|
public enum ResilientMultiPayloadEnum {
|
|
case A
|
|
case B
|
|
case C
|
|
case X(Int)
|
|
case Y(Int)
|
|
}
|
|
|
|
public func makeResilientMultiPayloadEnum(n: Int, i: Int)
|
|
-> ResilientMultiPayloadEnum {
|
|
switch i {
|
|
case 0:
|
|
return .A
|
|
case 1:
|
|
return .B
|
|
case 2:
|
|
return .C
|
|
case 3:
|
|
return .X(n)
|
|
case 4:
|
|
return .Y(n)
|
|
default:
|
|
while true {}
|
|
}
|
|
}
|
|
|
|
public enum ResilientMultiPayloadEnumSpareBits {
|
|
case A // 0
|
|
case B // 1
|
|
case C // 2
|
|
case X(ArtClass) // -1
|
|
case Y(ArtClass) // -2
|
|
}
|
|
|
|
public func makeResilientMultiPayloadEnumSpareBits(o: ArtClass, i: Int)
|
|
-> ResilientMultiPayloadEnumSpareBits {
|
|
switch i {
|
|
case 0:
|
|
return .A
|
|
case 1:
|
|
return .B
|
|
case 2:
|
|
return .C
|
|
case 3:
|
|
return .X(o)
|
|
case 4:
|
|
return .Y(o)
|
|
default:
|
|
while true {}
|
|
}
|
|
}
|
|
|
|
public typealias SevenSpareBits = (Bool, Int8, Int8, Int8, Int8, Int8, Int8, Int8)
|
|
|
|
public enum ResilientMultiPayloadEnumSpareBitsAndExtraBits {
|
|
// On 64-bit little endian, 7 spare bits at the LSB end
|
|
case P1(SevenSpareBits)
|
|
// On 64-bit, 8 spare bits at the MSB end and 3 at the LSB end
|
|
case P2(ArtClass)
|
|
case P3(ArtClass)
|
|
case P4(ArtClass)
|
|
case P5(ArtClass)
|
|
case P6(ArtClass)
|
|
case P7(ArtClass)
|
|
case P8(ArtClass)
|
|
}
|
|
|
|
public enum ResilientMultiPayloadGenericEnum<T> {
|
|
case A // 0
|
|
case B // 1
|
|
case C // 2
|
|
case X(T) // -1
|
|
case Y(T) // -2
|
|
}
|
|
|
|
public enum ResilientIndirectEnum {
|
|
// 0
|
|
case Base
|
|
|
|
// -1
|
|
indirect case A(ResilientIndirectEnum)
|
|
|
|
// -2
|
|
indirect case B(ResilientIndirectEnum, ResilientIndirectEnum)
|
|
}
|