Files
swift-mirror/test/SILOptimizer/cast_optimizer_conditional_conformance.sil
Slava Pestov 8bcd09aaa4 SIL: Preliminary refactoring of SILWitnessTable::AssociatedConformanceWitness
The Protocol field isn't really necessary, because the conformance
stores the protocol. But we do need the substituted subject type
of the requirement, just temporarily, until an abstract conformance
stores its own subject type too.
2025-03-18 19:38:42 -04:00

415 lines
18 KiB
Plaintext

// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all -wmo -performance-constant-propagation -simplify-cfg -sil-combine -jumpthread-simplify-cfg -sil-combine -devirtualizer -generic-specializer %s | %FileCheck %s
//
// <rdar://problem/46322928> Failure to devirtualize a protocol method applied to an opened existential blocks implementation of
// DataProtocol.
sil_stage canonical
import Builtin
import Swift
import SwiftShims
public protocol HasFoo {
func foo()
}
@inline(never) func testHasFoo<T>(_ t: T)
struct S1<T> {
init(_: T)
}
extension S1 : HasFoo where T == UInt8 {
func foo()
}
// ConstantPropagation converts checked_cast_addr to unconditional_checked_cast_addr.
// SimplifyCFG removes the trivial branch.
// SILCombine replaces the unconditional_checked_cast_addr with init_existential_addr + copy_addr
// and simplifies the switch condition.
// JumpThreadSimplifyCFG eliminates the dead switch condition.
// SILCombine specializes the witness_method instruction to S1<UInt8>.
// Devirtualization replaces the witness invocation with a direct call.
//
// CHECK-LABEL: sil shared [noinline] @testSpecializedS1 : $@convention(thin) (S1<UInt8>) -> () {
// CHECK: bb0(%0 : $S1<UInt8>):
// CHECK: [[EXIS:%.*]] = alloc_stack $any HasFoo
// CHECK: [[S1:%.*]] = alloc_stack $S1<UInt8>
// CHECK: store %0 to [[S1]] : $*S1<UInt8>
// CHECK: [[HASFOO:%.*]] = alloc_stack $any HasFoo
// CHECK: [[EXIS_ADDR:%.*]] = init_existential_addr [[HASFOO]] : $*any HasFoo, $S1<UInt8>
// CHECK: copy_addr [take] [[S1]] to [init] [[EXIS_ADDR]] : $*S1<UInt8>
// CHECK: copy_addr [take] [[HASFOO]] to [init] [[EXIS]] : $*any HasFoo
// CHECK: [[OPEN_EXIS_ADDR:%.*]] = open_existential_addr immutable_access [[EXIS]] : $*any HasFoo to $*@opened("4E16CBC0-FD9F-11E8-A311-D0817AD9F6DD", any HasFoo) Self
// CHECK: [[OPEN_ADDR:%.*]] = unchecked_addr_cast [[OPEN_EXIS_ADDR]] : $*@opened("4E16CBC0-FD9F-11E8-A311-D0817AD9F6DD", any HasFoo) Self to $*S1<UInt8>
// CHECK: [[F:%.*]] = function_ref @witnessS1 : $@convention(witness_method: HasFoo) (@in_guaranteed S1<UInt8>) -> ()
// CHECK: apply [[F]]([[OPEN_ADDR]]) : $@convention(witness_method: HasFoo) (@in_guaranteed S1<UInt8>) -> ()
// CHECK-LABEL: } // end sil function 'testSpecializedS1'
sil shared [noinline] @testSpecializedS1 : $@convention(thin) (S1<UInt8>) -> () {
bb0(%0 : $S1<UInt8>):
debug_value %0 : $S1<UInt8>, let, name "t", argno 1
debug_value %0 : $S1<UInt8>, let, name "t", argno 1
%3 = alloc_stack $HasFoo
%4 = alloc_stack $S1<UInt8>
store %0 to %4 : $*S1<UInt8>
%6 = alloc_stack $Optional<HasFoo>
%7 = init_enum_data_addr %6 : $*Optional<HasFoo>, #Optional.some!enumelt
checked_cast_addr_br take_always S1<UInt8> in %4 : $*S1<UInt8> to HasFoo in %7 : $*HasFoo, bb1, bb2
bb1:
inject_enum_addr %6 : $*Optional<HasFoo>, #Optional.some!enumelt
br bb3
bb2:
inject_enum_addr %6 : $*Optional<HasFoo>, #Optional.none!enumelt
br bb3
bb3:
switch_enum_addr %6 : $*Optional<HasFoo>, case #Optional.some!enumelt: bb4, case #Optional.none!enumelt: bb5
bb4:
%14 = unchecked_take_enum_data_addr %6 : $*Optional<HasFoo>, #Optional.some!enumelt
copy_addr [take] %14 to [init] %3 : $*HasFoo
dealloc_stack %6 : $*Optional<HasFoo>
dealloc_stack %4 : $*S1<UInt8>
%18 = open_existential_addr immutable_access %3 : $*HasFoo to $*@opened("4E16CBC0-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self
%19 = witness_method $@opened("4E16CBC0-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self, #HasFoo.foo : <Self where Self : HasFoo> (Self) -> () -> (), %18 : $*@opened("4E16CBC0-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self : $@convention(witness_method: HasFoo) <τ_0_0 where τ_0_0 : HasFoo> (@in_guaranteed τ_0_0) -> ()
%20 = apply %19<@opened("4E16CBC0-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self>(%18) : $@convention(witness_method: HasFoo) <τ_0_0 where τ_0_0 : HasFoo> (@in_guaranteed τ_0_0) -> ()
destroy_addr %3 : $*HasFoo
br bb6
bb5:
destroy_addr %6 : $*Optional<HasFoo>
dealloc_stack %6 : $*Optional<HasFoo>
dealloc_stack %4 : $*S1<UInt8>
br bb6
bb6:
dealloc_stack %3 : $*HasFoo
%28 = tuple ()
return %28 : $()
}
// CHECK-LABEL: sil shared [noinline] @testSpecializedS1Negative : $@convention(thin) (S1<Int8>) -> () {
// CHECK: bb0(%0 : $S1<Int8>):
// CHECK: [[EXIS:%.*]] = alloc_stack $any HasFoo
// CHECK: [[VAL:%.*]] = alloc_stack $S1<Int8>
// CHECK: store %0 to [[VAL]] : $*S1<Int8>
// CHECK: [[OPT:%.*]] = alloc_stack $Optional<any HasFoo>
// CHECK: [[IEDA:%.*]] = init_enum_data_addr [[OPT]] : $*Optional<any HasFoo>, #Optional.some!enumelt
// CHECK: checked_cast_addr_br take_always S1<Int8> in [[VAL]] : $*S1<Int8> to any HasFoo in [[IEDA]] : $*any HasFoo, bb1, bb2
// bbs...
// CHECK: [[UNWRAP:%.*]] = unchecked_take_enum_data_addr [[OPT]] : $*Optional<any HasFoo>, #Optional.some!enumelt
// CHECK: copy_addr [take] [[UNWRAP]] to [init] [[EXIS]] : $*any HasFoo
// CHECK: [[OPEN:%.*]] = open_existential_addr immutable_access [[EXIS]] : $*any HasFoo to $*@opened("5E16CBC0-FD9F-11E8-A311-D0817AD9F6DD", any HasFoo) Self
// CHECK: [[WM:%.*]] = witness_method $@opened("5E16CBC0-FD9F-11E8-A311-D0817AD9F6DD", any HasFoo) Self, #HasFoo.foo : <Self where Self : HasFoo> (Self) -> () -> (), [[OPEN]] : $*@opened("5E16CBC0-FD9F-11E8-A311-D0817AD9F6DD", any HasFoo) Self : $@convention(witness_method: HasFoo) <τ_0_0 where τ_0_0 : HasFoo> (@in_guaranteed τ_0_0) -> ()
// CHECK: apply [[WM]]<@opened("5E16CBC0-FD9F-11E8-A311-D0817AD9F6DD", any HasFoo) Self>([[OPEN]]) : $@convention(witness_method: HasFoo) <τ_0_0 where τ_0_0 : HasFoo> (@in_guaranteed τ_0_0) -> ()
// CHECK-LABEL: } // end sil function 'testSpecializedS1Negative'
sil shared [noinline] @testSpecializedS1Negative : $@convention(thin) (S1<Int8>) -> () {
bb0(%0 : $S1<Int8>):
debug_value %0 : $S1<Int8>, let, name "t", argno 1
debug_value %0 : $S1<Int8>, let, name "t", argno 1
%3 = alloc_stack $HasFoo
%4 = alloc_stack $S1<Int8>
store %0 to %4 : $*S1<Int8>
%6 = alloc_stack $Optional<HasFoo>
%7 = init_enum_data_addr %6 : $*Optional<HasFoo>, #Optional.some!enumelt
checked_cast_addr_br take_always S1<Int8> in %4 : $*S1<Int8> to HasFoo in %7 : $*HasFoo, bb1, bb2
bb1:
inject_enum_addr %6 : $*Optional<HasFoo>, #Optional.some!enumelt
br bb3
bb2:
inject_enum_addr %6 : $*Optional<HasFoo>, #Optional.none!enumelt
br bb3
bb3:
switch_enum_addr %6 : $*Optional<HasFoo>, case #Optional.some!enumelt: bb4, case #Optional.none!enumelt: bb5
bb4:
%14 = unchecked_take_enum_data_addr %6 : $*Optional<HasFoo>, #Optional.some!enumelt
copy_addr [take] %14 to [init] %3 : $*HasFoo
dealloc_stack %6 : $*Optional<HasFoo>
dealloc_stack %4 : $*S1<Int8>
%18 = open_existential_addr immutable_access %3 : $*HasFoo to $*@opened("5E16CBC0-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self
%19 = witness_method $@opened("5E16CBC0-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self, #HasFoo.foo : <Self where Self : HasFoo> (Self) -> () -> (), %18 : $*@opened("5E16CBC0-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self : $@convention(witness_method: HasFoo) <τ_0_0 where τ_0_0 : HasFoo> (@in_guaranteed τ_0_0) -> ()
%20 = apply %19<@opened("5E16CBC0-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self>(%18) : $@convention(witness_method: HasFoo) <τ_0_0 where τ_0_0 : HasFoo> (@in_guaranteed τ_0_0) -> ()
destroy_addr %3 : $*HasFoo
br bb6
bb5:
destroy_addr %6 : $*Optional<HasFoo>
dealloc_stack %6 : $*Optional<HasFoo>
dealloc_stack %4 : $*S1<Int8>
br bb6
bb6:
dealloc_stack %3 : $*HasFoo
%28 = tuple ()
return %28 : $()
}
struct S2<T> {
init(_: T) {}
}
protocol P {}
extension S2 : HasFoo where T : P {
func foo() {}
}
struct IsP : P {}
// CHECK-LABEL: sil shared [noinline] @testSpecializedS2 : $@convention(thin) (S2<IsP>) -> () {
// CHECK: bb0(%0 : $S2<IsP>):
// CHECK: [[EXIS:%.*]] = alloc_stack $any HasFoo
// CHECK: [[S2:%.*]] = alloc_stack $S2<IsP>
// CHECK: store %0 to [[S2]] : $*S2<IsP>
// CHECK: [[HASFOO:%.*]] = alloc_stack $any HasFoo
// CHECK: [[EXIS_ADDR:%.*]] = init_existential_addr [[HASFOO]] : $*any HasFoo, $S2<IsP>
// CHECK: copy_addr [take] [[S2]] to [init] [[EXIS_ADDR]] : $*S2<IsP>
// CHECK: copy_addr [take] [[HASFOO]] to [init] [[EXIS]] : $*any HasFoo
// CHECK: [[OPEN_EXIS_ADDR:%.*]] = open_existential_addr immutable_access [[EXIS]] : $*any HasFoo to $*@opened("4E16D1CE-FD9F-11E8-A311-D0817AD9F6DD", any HasFoo) Self
// CHECK: [[OPEN_ADDR:%.*]] = unchecked_addr_cast [[OPEN_EXIS_ADDR]] : $*@opened("4E16D1CE-FD9F-11E8-A311-D0817AD9F6DD", any HasFoo) Self to $*S2<IsP>
// CHECK: [[F:%.*]] = function_ref @$s9witnessS24main3IsPV_Tg5 : $@convention(witness_method: HasFoo) (S2<IsP>) -> ()
// CHECK: [[ARG:%.*]] = load [[OPEN_ADDR]] : $*S2<IsP>
// CHECK: apply [[F]]([[ARG]]) : $@convention(witness_method: HasFoo) (S2<IsP>) -> ()
// CHECK-LABEL: } // end sil function 'testSpecializedS2'
sil shared [noinline] @testSpecializedS2 : $@convention(thin) (S2<IsP>) -> () {
bb0(%0 : $S2<IsP>):
debug_value %0 : $S2<IsP>, let, name "t", argno 1
debug_value %0 : $S2<IsP>, let, name "t", argno 1
%3 = alloc_stack $HasFoo
%4 = alloc_stack $S2<IsP>
store %0 to %4 : $*S2<IsP>
%6 = alloc_stack $Optional<HasFoo>
%7 = init_enum_data_addr %6 : $*Optional<HasFoo>, #Optional.some!enumelt
checked_cast_addr_br take_always S2<IsP> in %4 : $*S2<IsP> to HasFoo in %7 : $*HasFoo, bb1, bb2
bb1:
inject_enum_addr %6 : $*Optional<HasFoo>, #Optional.some!enumelt
br bb3
bb2:
inject_enum_addr %6 : $*Optional<HasFoo>, #Optional.none!enumelt
br bb3
bb3:
switch_enum_addr %6 : $*Optional<HasFoo>, case #Optional.some!enumelt: bb4, case #Optional.none!enumelt: bb5
bb4:
%14 = unchecked_take_enum_data_addr %6 : $*Optional<HasFoo>, #Optional.some!enumelt
copy_addr [take] %14 to [init] %3 : $*HasFoo
dealloc_stack %6 : $*Optional<HasFoo>
dealloc_stack %4 : $*S2<IsP>
%18 = open_existential_addr immutable_access %3 : $*HasFoo to $*@opened("4E16D1CE-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self
%19 = witness_method $@opened("4E16D1CE-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self, #HasFoo.foo : <Self where Self : HasFoo> (Self) -> () -> (), %18 : $*@opened("4E16D1CE-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self : $@convention(witness_method: HasFoo) <τ_0_0 where τ_0_0 : HasFoo> (@in_guaranteed τ_0_0) -> ()
%20 = apply %19<@opened("4E16D1CE-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self>(%18) : $@convention(witness_method: HasFoo) <τ_0_0 where τ_0_0 : HasFoo> (@in_guaranteed τ_0_0) -> ()
destroy_addr %3 : $*HasFoo
br bb6
bb5:
destroy_addr %6 : $*Optional<HasFoo>
dealloc_stack %6 : $*Optional<HasFoo>
dealloc_stack %4 : $*S2<IsP>
br bb6
bb6:
dealloc_stack %3 : $*HasFoo
%28 = tuple ()
return %28 : $()
}
class C {
init() {}
}
struct S3<T> {
init(_: T) {}
}
extension S3 : HasFoo where T : AnyObject {
func foo() {}
}
// CHECK-LABEL: sil shared [noinline] @testSpecializedS3 : $@convention(thin) (S3<C>) -> () {
// CHECK: bb0(%0 : $S3<C>):
// CHECK: [[EXIS:%.*]] = alloc_stack $any HasFoo
// CHECK: [[S3:%.*]] = alloc_stack $S3<C>
// CHECK: store %0 to [[S3]] : $*S3<C>
// CHECK: [[HASFOO:%.*]] = alloc_stack $any HasFoo
// CHECK: [[EXIS_ADDR:%.*]] = init_existential_addr [[HASFOO]] : $*any HasFoo, $S3<C>
// CHECK: copy_addr [take] [[S3]] to [init] [[EXIS_ADDR]] : $*S3<C>
// CHECK: copy_addr [take] [[HASFOO]] to [init] [[EXIS]] : $*any HasFoo
// CHECK: [[OPEN_EXIS_ADDR:%.*]] = open_existential_addr immutable_access [[EXIS]] : $*any HasFoo to $*@opened("4E16D5E8-FD9F-11E8-A311-D0817AD9F6DD", any HasFoo) Self
// CHECK: [[OPEN_ADDR:%.*]] = unchecked_addr_cast [[OPEN_EXIS_ADDR]] : $*@opened("4E16D5E8-FD9F-11E8-A311-D0817AD9F6DD", any HasFoo) Self to $*S3<C>
// CHECK: [[F:%.*]] = function_ref @$s9witnessS34main1CC_Tg5 : $@convention(witness_method: HasFoo) (S3<C>) -> ()
// CHECK: [[ARG:%.*]] = load [[OPEN_ADDR]] : $*S3<C>
// CHECK: apply [[F]]([[ARG]]) : $@convention(witness_method: HasFoo) (S3<C>) -> ()
// CHECK-LABEL: } // end sil function 'testSpecializedS3'
sil shared [noinline] @testSpecializedS3 : $@convention(thin) (S3<C>) -> () {
bb0(%0 : $S3<C>):
debug_value %0 : $S3<C>, let, name "t", argno 1
debug_value %0 : $S3<C>, let, name "t", argno 1
%3 = alloc_stack $HasFoo
%4 = alloc_stack $S3<C>
store %0 to %4 : $*S3<C>
%6 = alloc_stack $Optional<HasFoo>
%7 = init_enum_data_addr %6 : $*Optional<HasFoo>, #Optional.some!enumelt
checked_cast_addr_br take_always S3<C> in %4 : $*S3<C> to HasFoo in %7 : $*HasFoo, bb1, bb2
bb1:
inject_enum_addr %6 : $*Optional<HasFoo>, #Optional.some!enumelt
br bb3
bb2:
inject_enum_addr %6 : $*Optional<HasFoo>, #Optional.none!enumelt
br bb3
bb3:
switch_enum_addr %6 : $*Optional<HasFoo>, case #Optional.some!enumelt: bb4, case #Optional.none!enumelt: bb5
bb4:
%14 = unchecked_take_enum_data_addr %6 : $*Optional<HasFoo>, #Optional.some!enumelt
copy_addr [take] %14 to [init] %3 : $*HasFoo
dealloc_stack %6 : $*Optional<HasFoo>
dealloc_stack %4 : $*S3<C>
%18 = open_existential_addr immutable_access %3 : $*HasFoo to $*@opened("4E16D5E8-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self
%19 = witness_method $@opened("4E16D5E8-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self, #HasFoo.foo : <Self where Self : HasFoo> (Self) -> () -> (), %18 : $*@opened("4E16D5E8-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self : $@convention(witness_method: HasFoo) <τ_0_0 where τ_0_0 : HasFoo> (@in_guaranteed τ_0_0) -> ()
%20 = apply %19<@opened("4E16D5E8-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self>(%18) : $@convention(witness_method: HasFoo) <τ_0_0 where τ_0_0 : HasFoo> (@in_guaranteed τ_0_0) -> ()
destroy_addr %3 : $*HasFoo
br bb6
bb5:
destroy_addr %6 : $*Optional<HasFoo>
dealloc_stack %6 : $*Optional<HasFoo>
dealloc_stack %4 : $*S3<C>
br bb6
bb6:
dealloc_stack %3 : $*HasFoo
%28 = tuple ()
return %28 : $()
}
class SubC : C {}
struct S4<T> {
init(_: T) {}
}
extension S4 : HasFoo where T : C {
func foo() {}
}
// CHECK-LABEL: sil shared [noinline] @testSpecializedS4 : $@convention(thin) (S4<SubC>) -> () {
// CHECK: bb0(%0 : $S4<SubC>):
// CHECK: [[EXIS:%.*]] = alloc_stack $any HasFoo
// CHECK: [[S3:%.*]] = alloc_stack $S4<SubC>
// CHECK: store %0 to [[S3]] : $*S4<SubC>
// CHECK: [[HASFOO:%.*]] = alloc_stack $any HasFoo
// CHECK: [[EXIS_ADDR:%.*]] = init_existential_addr [[HASFOO]] : $*any HasFoo, $S4<SubC>
// CHECK: copy_addr [take] [[S3]] to [init] [[EXIS_ADDR]] : $*S4<SubC>
// CHECK: copy_addr [take] [[HASFOO]] to [init] [[EXIS]] : $*any HasFoo
// CHECK: [[OPEN_EXIS_ADDR:%.*]] = open_existential_addr immutable_access [[EXIS]] : $*any HasFoo to $*@opened("4E16E402-FD9F-11E8-A311-D0817AD9F6DD", any HasFoo) Self
// CHECK: [[OPEN_ADDR:%.*]] = unchecked_addr_cast [[OPEN_EXIS_ADDR]] : $*@opened("4E16E402-FD9F-11E8-A311-D0817AD9F6DD", any HasFoo) Self to $*S4<SubC>
// CHECK: [[F:%.*]] = function_ref @$s9witnessS44main4SubCC_Tg5 : $@convention(witness_method: HasFoo) (S4<SubC>) -> ()
// CHECK: [[ARG:%.*]] = load [[OPEN_ADDR]] : $*S4<SubC>
// CHECK: apply [[F]]([[ARG]]) : $@convention(witness_method: HasFoo) (S4<SubC>) -> ()
// CHECK: } // end sil function 'testSpecializedS4'
sil shared [noinline] @testSpecializedS4 : $@convention(thin) (S4<SubC>) -> () {
bb0(%0 : $S4<SubC>):
debug_value %0 : $S4<SubC>, let, name "t", argno 1
debug_value %0 : $S4<SubC>, let, name "t", argno 1
%3 = alloc_stack $HasFoo
%4 = alloc_stack $S4<SubC>
store %0 to %4 : $*S4<SubC>
%6 = alloc_stack $Optional<HasFoo>
%7 = init_enum_data_addr %6 : $*Optional<HasFoo>, #Optional.some!enumelt
checked_cast_addr_br take_always S4<SubC> in %4 : $*S4<SubC> to HasFoo in %7 : $*HasFoo, bb1, bb2
bb1:
inject_enum_addr %6 : $*Optional<HasFoo>, #Optional.some!enumelt
br bb3
bb2:
inject_enum_addr %6 : $*Optional<HasFoo>, #Optional.none!enumelt
br bb3
bb3:
switch_enum_addr %6 : $*Optional<HasFoo>, case #Optional.some!enumelt: bb4, case #Optional.none!enumelt: bb5
bb4:
%14 = unchecked_take_enum_data_addr %6 : $*Optional<HasFoo>, #Optional.some!enumelt
copy_addr [take] %14 to [init] %3 : $*HasFoo
dealloc_stack %6 : $*Optional<HasFoo>
dealloc_stack %4 : $*S4<SubC>
%18 = open_existential_addr immutable_access %3 : $*HasFoo to $*@opened("4E16E402-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self
%19 = witness_method $@opened("4E16E402-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self, #HasFoo.foo : <Self where Self : HasFoo> (Self) -> () -> (), %18 : $*@opened("4E16E402-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self : $@convention(witness_method: HasFoo) <τ_0_0 where τ_0_0 : HasFoo> (@in_guaranteed τ_0_0) -> ()
%20 = apply %19<@opened("4E16E402-FD9F-11E8-A311-D0817AD9F6DD", HasFoo) Self>(%18) : $@convention(witness_method: HasFoo) <τ_0_0 where τ_0_0 : HasFoo> (@in_guaranteed τ_0_0) -> ()
destroy_addr %3 : $*HasFoo
br bb6
bb5:
destroy_addr %6 : $*Optional<HasFoo>
dealloc_stack %6 : $*Optional<HasFoo>
dealloc_stack %4 : $*S4<SubC>
br bb6
bb6:
dealloc_stack %3 : $*HasFoo
%28 = tuple ()
return %28 : $()
}
sil private [transparent] [thunk] @witnessS1 : $@convention(witness_method: HasFoo) (@in_guaranteed S1<UInt8>) -> () {
bb0(%0 : $*S1<UInt8>):
%1 = tuple ()
return %1 : $()
}
sil private [transparent] [thunk] @witnessS2 : $@convention(witness_method: HasFoo) <τ_0_0 where τ_0_0 : P> (@in_guaranteed S2<τ_0_0>) -> () {
bb0(%0 : $*S2<τ_0_0>):
%1 = tuple ()
return %1 : $()
}
sil private [transparent] [thunk] @witnessS3 : $@convention(witness_method: HasFoo) <τ_0_0 where τ_0_0 : AnyObject> (@in_guaranteed S3<τ_0_0>) -> () {
bb0(%0 : $*S3<τ_0_0>):
%1 = tuple ()
return %1 : $()
}
sil private [transparent] [thunk] @witnessS4 : $@convention(witness_method: HasFoo) <τ_0_0 where τ_0_0 : C> (@in_guaranteed S4<τ_0_0>) -> () {
bb0(%0 : $*S4<τ_0_0>):
%1 = tuple ()
return %1 : $()
}
sil_vtable C {}
sil_vtable SubC {}
sil_witness_table hidden <T where T == UInt8> S1<T>: HasFoo module tot {
method #HasFoo.foo: <Self where Self : HasFoo> (Self) -> () -> () : @witnessS1
}
sil_witness_table hidden <T where T : P> S2<T>: HasFoo module tot {
method #HasFoo.foo: <Self where Self : HasFoo> (Self) -> () -> () : @witnessS2
conditional_conformance (T: P): dependent T
}
sil_witness_table hidden IsP: P module tot {
}
sil_witness_table hidden <T where T : AnyObject> S3<T>: HasFoo module tot {
method #HasFoo.foo: <Self where Self : HasFoo> (Self) -> () -> () : @witnessS3
}
sil_witness_table hidden <T where T : C> S4<T>: HasFoo module tot {
method #HasFoo.foo: <Self where Self : HasFoo> (Self) -> () -> () : @witnessS4
}