Files
swift-mirror/test/Inputs/resilient_enum.swift
Slava Pestov 34a4075116 IRGen: Implement resilient enum case numbering
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.
2016-01-21 12:10:57 -08:00

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