mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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.
415 lines
18 KiB
Plaintext
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
|
|
}
|