blob: ac064f4bd53d6c9f3fdf7894bac6730164566e4f [file] [log] [blame]
// RUN: %target-swift-emit-silgen -parse-as-library %s | %FileCheck %s
enum Boolish {
case falsy
case truthy
}
// CHECK-LABEL: sil hidden [ossa] @$s4enum13Boolish_casesyyF
func Boolish_cases() {
// CHECK: [[BOOLISH:%[0-9]+]] = metatype $@thin Boolish.Type
// CHECK-NEXT: [[FALSY:%[0-9]+]] = enum $Boolish, #Boolish.falsy!enumelt
_ = Boolish.falsy
// CHECK-NEXT: [[BOOLISH:%[0-9]+]] = metatype $@thin Boolish.Type
// CHECK-NEXT: [[TRUTHY:%[0-9]+]] = enum $Boolish, #Boolish.truthy!enumelt
_ = Boolish.truthy
}
enum Optionable {
case nought
case mere(Int)
}
// CHECK-LABEL: sil hidden [ossa] @$s4enum16Optionable_casesyySiF
func Optionable_cases(_ x: Int) {
// CHECK: [[METATYPE:%.*]] = metatype $@thin Optionable.Type
// CHECK: [[FN:%.*]] = function_ref @$s4enum10OptionableO4mereyACSicACmFTc
// CHECK-NEXT: [[CTOR:%.*]] = apply [[FN]]([[METATYPE]])
// CHECK-NEXT: destroy_value [[CTOR]]
_ = Optionable.mere
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin Optionable.Type
// CHECK-NEXT: [[RES:%.*]] = enum $Optionable, #Optionable.mere!enumelt.1, %0 : $Int
_ = Optionable.mere(x)
}
// CHECK-LABEL: sil shared [transparent] [thunk] [ossa] @$s4enum10OptionableO4mereyACSicACmF
// CHECK: [[FN:%.*]] = function_ref @$s4enum10OptionableO4mereyACSicACmF
// CHECK-NEXT: [[METHOD:%.*]] = partial_apply [callee_guaranteed] [[FN]](%0)
// CHECK-NEXT: return [[METHOD]]
// CHECK-NEXT: }
// CHECK-LABEL: sil shared [transparent] [ossa] @$s4enum10OptionableO4mereyACSicACmF
// CHECK: [[RES:%.*]] = enum $Optionable, #Optionable.mere!enumelt.1, %0 : $Int
// CHECK-NEXT: return [[RES]] : $Optionable
// CHECK-NEXT: }
protocol P {}
struct S : P {}
enum AddressOnly {
case nought
case mere(P)
case phantom(S)
}
// CHECK-LABEL: sil hidden [ossa] @$s4enum17AddressOnly_casesyyAA1SVF
func AddressOnly_cases(_ s: S) {
// CHECK: [[METATYPE:%.*]] = metatype $@thin AddressOnly.Type
// CHECK: [[FN:%.*]] = function_ref @$s4enum11AddressOnlyO4mereyAcA1P_pcACmFTc
// CHECK-NEXT: [[CTOR:%.*]] = apply [[FN]]([[METATYPE]])
// CHECK-NEXT: destroy_value [[CTOR]]
_ = AddressOnly.mere
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin AddressOnly.Type
// CHECK-NEXT: [[NOUGHT:%.*]] = alloc_stack $AddressOnly
// CHECK-NEXT: inject_enum_addr [[NOUGHT]]
// CHECK-NEXT: destroy_addr [[NOUGHT]]
// CHECK-NEXT: dealloc_stack [[NOUGHT]]
_ = AddressOnly.nought
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin AddressOnly.Type
// CHECK-NEXT: [[P_BUF:%.*]] = alloc_stack $P
// CHECK-NEXT: [[PAYLOAD_ADDR:%.*]] = init_existential_addr [[P_BUF]]
// CHECK-NEXT: store %0 to [trivial] [[PAYLOAD_ADDR]]
// CHECK-NEXT: [[MERE:%.*]] = alloc_stack $AddressOnly
// CHECK-NEXT: [[PAYLOAD:%.*]] = init_enum_data_addr [[MERE]]
// CHECK-NEXT: copy_addr [take] [[P_BUF]] to [initialization] [[PAYLOAD]] : $*P
// CHECK-NEXT: inject_enum_addr [[MERE]]
// CHECK-NEXT: destroy_addr [[MERE]]
// CHECK-NEXT: dealloc_stack [[MERE]]
// CHECK-NEXT: dealloc_stack [[P_BUF]] : $*P
_ = AddressOnly.mere(s)
// Address-only enum vs loadable payload
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin AddressOnly.Type
// CHECK-NEXT: [[PHANTOM:%.*]] = alloc_stack $AddressOnly
// CHECK-NEXT: [[PAYLOAD:%.*]] = init_enum_data_addr [[PHANTOM]] : $*AddressOnly, #AddressOnly.phantom!enumelt.1
// CHECK-NEXT: store %0 to [trivial] [[PAYLOAD]]
// CHECK-NEXT: inject_enum_addr [[PHANTOM]] : $*AddressOnly, #AddressOnly.phantom!enumelt.1
// CHECK-NEXT: destroy_addr [[PHANTOM]]
// CHECK-NEXT: dealloc_stack [[PHANTOM]]
_ = AddressOnly.phantom(s)
// CHECK: return
}
// CHECK-LABEL: sil shared [transparent] [thunk] [ossa] @$s4enum11AddressOnlyO4mereyAcA1P_pcACmFTc
// CHECK: [[FN:%.*]] = function_ref @$s4enum11AddressOnlyO4mereyAcA1P_pcACmF
// CHECK-NEXT: [[METHOD:%.*]] = partial_apply [callee_guaranteed] [[FN]](%0)
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[CANONICAL_THUNK_FN:%.*]] = function_ref @$s4enum1P_pAA11AddressOnlyOIegir_AaB_pADIegnr_TR : $@convention(thin) (@in_guaranteed P, @guaranteed @callee_guaranteed (@in P) -> @out AddressOnly) -> @out AddressOnly
// CHECK-NEXT: [[CANONICAL_THUNK:%.*]] = partial_apply [callee_guaranteed] [[CANONICAL_THUNK_FN]]([[METHOD]])
// CHECK-NEXT: return [[CANONICAL_THUNK]] : $@callee_guaranteed (@in_guaranteed P) -> @out AddressOnly
// CHECK-NEXT: }
// CHECK-LABEL: sil shared [transparent] [ossa] @$s4enum11AddressOnlyO4mereyAcA1P_pcACmF : $@convention
// CHECK: bb0([[ARG0:%.*]] : $*AddressOnly, [[ARG1:%.*]] : $*P, [[ARG2:%.*]] : $@thin AddressOnly.Type):
// CHECK: [[RET_DATA:%.*]] = init_enum_data_addr [[ARG0]] : $*AddressOnly, #AddressOnly.mere!enumelt.1
// CHECK-NEXT: copy_addr [take] [[ARG1]] to [initialization] [[RET_DATA]] : $*P
// CHECK-NEXT: inject_enum_addr [[ARG0]] : $*AddressOnly, #AddressOnly.mere!enumelt.1
// CHECK: return
// CHECK-NEXT: } // end sil function '$s4enum11AddressOnlyO4mereyAcA1P_pcACmF'
enum PolyOptionable<T> {
case nought
case mere(T)
}
// CHECK-LABEL: sil hidden [ossa] @$s4enum20PolyOptionable_casesyyxlF
func PolyOptionable_cases<T>(_ t: T) {
// CHECK: [[METATYPE:%.*]] = metatype $@thin PolyOptionable<T>.Type
// CHECK-NEXT: [[NOUGHT:%.*]] = alloc_stack $PolyOptionable<T>
// CHECK-NEXT: inject_enum_addr [[NOUGHT]]
// CHECK-NEXT: destroy_addr [[NOUGHT]]
// CHECK-NEXT: dealloc_stack [[NOUGHT]]
_ = PolyOptionable<T>.nought
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin PolyOptionable<T>.Type
// CHECK-NEXT: [[T_BUF:%.*]] = alloc_stack $T
// CHECK-NEXT: copy_addr %0 to [initialization] [[T_BUF]]
// CHECK-NEXT: [[MERE:%.*]] = alloc_stack $PolyOptionable<T>
// CHECK-NEXT: [[PAYLOAD:%.*]] = init_enum_data_addr [[MERE]]
// CHECK-NEXT: copy_addr [take] [[T_BUF]] to [initialization] [[PAYLOAD]] : $*T
// CHECK-NEXT: inject_enum_addr [[MERE]]
// CHECK-NEXT: destroy_addr [[MERE]]
// CHECK-NEXT: dealloc_stack [[MERE]]
// CHECK-NEXT: dealloc_stack [[T_BUF]] : $*T
_ = PolyOptionable<T>.mere(t)
// CHECK-NOT: destroy_addr %0
// CHECK: return
}
// The substituted type is loadable and trivial here
// CHECK-LABEL: sil hidden [ossa] @$s4enum32PolyOptionable_specialized_casesyySiF
func PolyOptionable_specialized_cases(_ t: Int) {
// CHECK: [[METATYPE:%.*]] = metatype $@thin PolyOptionable<Int>.Type
// CHECK-NEXT: [[NOUGHT:%.*]] = enum $PolyOptionable<Int>, #PolyOptionable.nought!enumelt
_ = PolyOptionable<Int>.nought
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin PolyOptionable<Int>.Type
// CHECK-NEXT: [[NOUGHT:%.*]] = enum $PolyOptionable<Int>, #PolyOptionable.mere!enumelt.1, %0
_ = PolyOptionable<Int>.mere(t)
// CHECK: return
}
// Regression test for a bug where temporary allocations created as a result of
// tuple implosion were not deallocated in enum constructors.
struct String { var ptr: AnyObject }
enum Foo { case a(P, String) }
// Curry Thunk for Foo.a(_:)
//
// CHECK-LABEL: sil shared [transparent] [thunk] [ossa] @$s4enum3FooO1ayAcA1P_p_AA6StringVtcACmFTc
// CHECK: [[FN:%.*]] = function_ref @$s4enum3FooO1ayAcA1P_p_AA6StringVtcACmF
// CHECK-NEXT: [[METHOD:%.*]] = partial_apply [callee_guaranteed] [[FN]](%0)
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[CANONICAL_THUNK_FN:%.*]] = function_ref @$s4enum1P_pAA6StringVAA3FooOIegixr_AaB_pAdFIegngr_TR : $@convention(thin) (@in_guaranteed P, @guaranteed String, @guaranteed @callee_guaranteed (@in P, @owned String) -> @out Foo) -> @out Foo
// CHECK-NEXT: [[CANONICAL_THUNK:%.*]] = partial_apply [callee_guaranteed] [[CANONICAL_THUNK_FN]]([[METHOD]])
// CHECK-NEXT: return [[CANONICAL_THUNK]]
// CHECK-NEXT: }
// Foo.a(_:)
// CHECK-LABEL: sil shared [transparent] [ossa] @$s4enum3FooO1ayAcA1P_p_AA6StringVtcACmF
// CHECK: bb0([[ARG0:%.*]] : $*Foo, [[ARG1:%.*]] : $*P, [[ARG2:%.*]] : @owned $String, [[ARG3:%.*]] : $@thin Foo.Type):
// CHECK: [[PAYLOAD:%.*]] = init_enum_data_addr [[ARG0]] : $*Foo, #Foo.a!enumelt.1
// CHECK-NEXT: [[LEFT:%.*]] = tuple_element_addr [[PAYLOAD]] : $*(P, String), 0
// CHECK-NEXT: [[RIGHT:%.*]] = tuple_element_addr [[PAYLOAD]] : $*(P, String), 1
// CHECK-NEXT: copy_addr [take] [[ARG1]] to [initialization] [[LEFT]] : $*P
// CHECK-NEXT: store [[ARG2]] to [init] [[RIGHT]]
// CHECK-NEXT: inject_enum_addr [[ARG0]] : $*Foo, #Foo.a!enumelt.1
// CHECK: return
// CHECK-NEXT: } // end sil function '$s4enum3FooO1ayAcA1P_p_AA6StringVtcACmF'
func Foo_cases() {
_ = Foo.a
}
enum Indirect<T> {
indirect case payload((T, other: T))
case none
}
// CHECK-LABEL: sil{{.*}} @{{.*}}makeIndirectEnum{{.*}} : $@convention(thin) <T> (@in_guaranteed T) -> @owned Indirect<T>
// CHECK: [[BOX:%.*]] = alloc_box $<τ_0_0> { var (τ_0_0, other: τ_0_0) } <T>
// CHECK: enum $Indirect<T>, #Indirect.payload!enumelt.1, [[BOX]] : $<τ_0_0> { var (τ_0_0, other: τ_0_0) } <T>
func makeIndirectEnum<T>(_ payload: T) -> Indirect<T> {
return Indirect.payload((payload, other: payload))
}
// https://bugs.swift.org/browse/SR-9675
enum TrailingClosureConcrete {
case label(fn: () -> Int)
case noLabel(() -> Int)
case twoElementsLabel(x: Int, fn: () -> Int)
case twoElementsNoLabel(_ x: Int, _ fn: () -> Int)
}
func useTrailingClosureConcrete() {
_ = TrailingClosureConcrete.label { 0 }
_ = TrailingClosureConcrete.noLabel { 0 }
_ = TrailingClosureConcrete.twoElementsLabel(x: 0) { 0 }
_ = TrailingClosureConcrete.twoElementsNoLabel(0) { 0 }
}
enum TrailingClosureGeneric<T> {
case label(fn: () -> T)
case noLabel(() -> T)
case twoElementsLabel(x: T, fn: () -> T)
case twoElementsNoLabel(_ x: T, _ fn: () -> T)
}
func useTrailingClosureGeneric<T>(t: T) {
_ = TrailingClosureGeneric<T>.label { t }
_ = TrailingClosureGeneric<T>.noLabel { t }
_ = TrailingClosureGeneric<T>.twoElementsLabel(x: t) { t }
_ = TrailingClosureGeneric<T>.twoElementsNoLabel(t) { t }
}
enum SR7799 {
case one
case two
}
// CHECK-LABEL: sil hidden [ossa] @$s4enum6sr77993baryAA6SR7799OSg_tF : $@convention(thin) (Optional<SR7799>) -> () {
// CHECK: bb0(%0 : $Optional<SR7799>):
// CHECK-NEXT: debug_value %0 : $Optional<SR7799>, let, name "bar", argno 1
// CHECK-NEXT: switch_enum %0 : $Optional<SR7799>, case #Optional.some!enumelt.1: bb1, default bb4
// CHECK: bb1(%3 : $SR7799):
// CHECK-NEXT: switch_enum %3 : $SR7799, case #SR7799.one!enumelt: bb2, case #SR7799.two!enumelt: bb3
func sr7799(bar: SR7799?) {
switch bar {
case .one: print("one")
case .two?: print("two")
default: print("default")
}
}
// CHECK-LABEL: sil hidden [ossa] @$s4enum8sr7799_13baryAA6SR7799OSgSg_tF : $@convention(thin) (Optional<Optional<SR7799>>) -> () {
// CHECK: bb0(%0 : $Optional<Optional<SR7799>>):
// CHECK-NEXT: debug_value %0 : $Optional<Optional<SR7799>>, let, name "bar", argno 1
// CHECK-NEXT: switch_enum %0 : $Optional<Optional<SR7799>>, case #Optional.none!enumelt: bb1, default bb2
func sr7799_1(bar: SR7799??) {
switch bar {
case .none: print("none")
default: print("default")
}
}