blob: 903f724b8950ac9a3b5064222eb81dc67390a9f1 [file] [log] [blame]
// RUN: %target-sil-opt -enable-sil-verify-all %s -sil-combine -inline -sil-combine | FileCheck %s
// Check that type propagation is performed correctly for existentials.
// The concrete type set in init_existential instructions should be propagated
// all the way down to witness_method instructions.
//
// If copy_addr instructions are used to copy one existential into another,
// the information about the concrete type should be still propagated
// correctly through it.
sil_stage canonical
import Builtin
import Swift
import SwiftShims
public protocol ReaderWriterType {
init()
func read(index: Int32) -> Int32
mutating func write(index: Int32, value: Int32)
}
public final class ArrayClassReaderWriter : ReaderWriterType {
@sil_stored private final var elements: [Int32] { get set }
@inline(never) public init()
@inline(never) public final func read(index: Int32) -> Int32
public final func write(index: Int32, value: Int32)
deinit
}
@inline(never) public func readValues() -> Int32
sil_global [fragile] @_swiftEmptyArrayStorage : $_SwiftEmptyArrayStorage
sil [noinline] @_TFC28existential_type_propagation22ArrayClassReaderWritercfMS0_FT_S0_ : $@convention(method) (@owned ArrayClassReaderWriter) -> @owned ArrayClassReaderWriter
sil [noinline] @_TFC28existential_type_propagation22ArrayClassReaderWriterCfMS0_FT_S0_ : $@convention(thin) (@thick ArrayClassReaderWriter.Type) -> @owned ArrayClassReaderWriter
sil [noinline] @_TFC28existential_type_propagation22ArrayClassReaderWriter4readfS0_FSiSi : $@convention(method) (Int32, @guaranteed ArrayClassReaderWriter) -> Int32
sil [transparent] [thunk] @_TTWC28existential_type_propagation22ArrayClassReaderWriterS_16ReaderWriterTypeS_FS1_CuRq_S1__fMq_FT_q_ : $@convention(witness_method) (@thick ArrayClassReaderWriter.Type) -> @out ArrayClassReaderWriter
sil [transparent] [thunk] @_TTWC28existential_type_propagation22ArrayClassReaderWriterS_16ReaderWriterTypeS_FS1_4readuRq_S1__fq_FSiSi : $@convention(witness_method) (Int32, @in_guaranteed ArrayClassReaderWriter) -> Int32
sil [transparent] [thunk] @_TTWC28existential_type_propagation22ArrayClassReaderWriterS_16ReaderWriterTypeS_FS1_5writeuRq_S1__fRq_FTSi5valueSi_T_ : $@convention(witness_method) (Int32, Int32, @inout ArrayClassReaderWriter) -> ()
// CHECK-LABEL: sil [noinline] @test_existential_type_propagation : $@convention(thin) () -> Int32
// CHECK-NOT: init_existential_addr
// CHECK-NOT: open_existential_addr
// CHECK-NOT: witness_method
// CHECK: function_ref @_TTWC28existential_type_propagation22ArrayClassReaderWriterS_16ReaderWriterTypeS_FS1_4readuRq_S1__fq_FSiSi : $@convention(witness_method) (Int32, @in_guaranteed ArrayClassReaderWriter) -> Int32
// CHECK: return
sil [noinline] @test_existential_type_propagation : $@convention(thin) () -> Int32 {
bb0:
%0 = alloc_stack $Int32
%1 = alloc_stack $ReaderWriterType
// Here we set the concrete type information.
%2 = init_existential_addr %1 : $*ReaderWriterType, $ArrayClassReaderWriter
%3 = function_ref @_TFC28existential_type_propagation22ArrayClassReaderWriterCfMS0_FT_S0_ : $@convention(thin) (@thick ArrayClassReaderWriter.Type) -> @owned ArrayClassReaderWriter
%4 = metatype $@thick ArrayClassReaderWriter.Type
%5 = apply %3(%4) : $@convention(thin) (@thick ArrayClassReaderWriter.Type) -> @owned ArrayClassReaderWriter
store %5 to %2 : $*ArrayClassReaderWriter
%7 = open_existential_addr %1 : $*ReaderWriterType to $*@opened("3305E696-5685-11E5-9393-B8E856428C60") ReaderWriterType
// Check that the type information reaches the witness_method instruction and allows for devirtualization.
%8 = witness_method $@opened("3305E696-5685-11E5-9393-B8E856428C60") ReaderWriterType, #ReaderWriterType.read!1, %7 : $*@opened("3305E696-5685-11E5-9393-B8E856428C60") ReaderWriterType : $@convention(witness_method) <τ_0_0 where τ_0_0 : ReaderWriterType> (Int32, @in_guaranteed τ_0_0) -> Int32
%9 = integer_literal $Builtin.Int32, 0
%10 = struct $Int32 (%9 : $Builtin.Int32)
%11 = apply %8<@opened("3305E696-5685-11E5-9393-B8E856428C60") ReaderWriterType>(%10, %7) : $@convention(witness_method) _0_0 where τ_0_0 : ReaderWriterType> (Int32, @in_guaranteed τ_0_0) -> Int32
%12 = integer_literal $Builtin.Int32, 0
%13 = struct $Int32 (%12 : $Builtin.Int32)
store %13 to %0 : $*Int32
destroy_addr %1 : $*ReaderWriterType
dealloc_stack %1 : $*ReaderWriterType
dealloc_stack %0 : $*Int32
return %13 : $Int32
}
// CHECK-LABEL: sil [noinline] @test_existential_type_propagation_via_copy_addr : $@convention(thin) () -> Int32
// CHECK-NOT: init_existential_addr
// CHECK-NOT: copy_addr
// CHECK-NOT: open_existential_addr
// CHECK-NOT: witness_method
// CHECK: function_ref @_TTWC28existential_type_propagation22ArrayClassReaderWriterS_16ReaderWriterTypeS_FS1_4readuRq_S1__fq_FSiSi : $@convention(witness_method) (Int32, @in_guaranteed ArrayClassReaderWriter) -> Int32
// CHECK: return
sil [noinline] @test_existential_type_propagation_via_copy_addr : $@convention(thin) () -> Int32 {
bb0:
%0 = alloc_stack $Int32
%1 = alloc_stack $ReaderWriterType
%2 = alloc_stack $ReaderWriterType
// Here we set the concrete type information.
%3 = init_existential_addr %1 : $*ReaderWriterType, $ArrayClassReaderWriter
%4 = function_ref @_TFC28existential_type_propagation22ArrayClassReaderWriterCfMS0_FT_S0_ : $@convention(thin) (@thick ArrayClassReaderWriter.Type) -> @owned ArrayClassReaderWriter
%5 = metatype $@thick ArrayClassReaderWriter.Type
%6 = apply %4(%5) : $@convention(thin) (@thick ArrayClassReaderWriter.Type) -> @owned ArrayClassReaderWriter
store %6 to %3 : $*ArrayClassReaderWriter
// Check that the type information set for %1 is propagated here to %2.
copy_addr %1 to [initialization] %2 : $*ReaderWriterType
%9 = open_existential_addr %2 : $*ReaderWriterType to $*@opened("3305E696-5685-11E5-9393-B8E856428C60") ReaderWriterType
// Check that the type information reaches the witness_method instruction and allows for devirtualization.
%10 = witness_method $@opened("3305E696-5685-11E5-9393-B8E856428C60") ReaderWriterType, #ReaderWriterType.read!1, %9 : $*@opened("3305E696-5685-11E5-9393-B8E856428C60") ReaderWriterType : $@convention(witness_method) <τ_0_0 where τ_0_0 : ReaderWriterType> (Int32, @in_guaranteed τ_0_0) -> Int32
%11 = integer_literal $Builtin.Int32, 0
%12 = struct $Int32 (%11 : $Builtin.Int32)
%13 = apply %10<@opened("3305E696-5685-11E5-9393-B8E856428C60") ReaderWriterType>(%12, %9) : $@convention(witness_method) _0_0 where τ_0_0 : ReaderWriterType> (Int32, @in_guaranteed τ_0_0) -> Int32
%14 = integer_literal $Builtin.Int32, 0
%15 = struct $Int32 (%14 : $Builtin.Int32)
store %15 to %0 : $*Int32
destroy_addr %2 : $*ReaderWriterType
dealloc_stack %2 : $*ReaderWriterType
destroy_addr %1 : $*ReaderWriterType
dealloc_stack %1 : $*ReaderWriterType
dealloc_stack %0 : $*Int32
return %15 : $Int32
}
protocol P {
func foo() -> Int64
}
struct X : P {
var xx : Int64
func foo() -> Int64
}
// CHECK-LABEL: sil @promote_over_control_flow
// CHECK: bb2:
// CHECK-NOT: open_existential_addr
// CHECK: = function_ref @foo_witness
// CHECK-NEXT: apply
// CHECK-NOT: open_existential_addr
// CHECK: return
sil @promote_over_control_flow : $@convention(thin) () -> Int64 {
bb0:
%2 = alloc_stack $P, let, name "p"
%3 = init_existential_addr %2 : $*P, $X
%6 = integer_literal $Builtin.Int64, 27
%7 = struct $Int64 (%6 : $Builtin.Int64)
%8 = struct $X (%7 : $Int64)
store %8 to %3 : $*X
cond_br undef, bb1, bb2
bb1:
br bb2
bb2:
%10 = open_existential_addr %2 : $*P to $*@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P
%11 = witness_method $@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P, #P.foo!1, %10 : $*@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
%12 = apply %11<@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P>(%10) : $@convention(witness_method) _0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
destroy_addr %2 : $*P
dealloc_stack %2 : $*P
return %12 : $Int64
}
// CHECK-LABEL: sil @existential_is_overwritten_by_store
// CHECK: open_existential_addr
// CHECK-NEXT: witness_method
// CHECK-NEXT: apply
sil @existential_is_overwritten_by_store : $@convention(thin) (@in P) -> Int64 {
bb0(%0 : $*P):
%2 = alloc_stack $P, let, name "p"
%3 = init_existential_addr %2 : $*P, $X
%6 = integer_literal $Builtin.Int64, 27
%7 = struct $Int64 (%6 : $Builtin.Int64)
%8 = struct $X (%7 : $Int64)
store %8 to %3 : $*X
destroy_addr %2 : $*P
copy_addr [take] %0 to %2 : $*P // id: %5
%10 = open_existential_addr %2 : $*P to $*@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P
%11 = witness_method $@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P, #P.foo!1, %10 : $*@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
%12 = apply %11<@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P>(%10) : $@convention(witness_method) _0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
dealloc_stack %2 : $*P
return %12 : $Int64
}
// CHECK-LABEL: sil @existential_is_overwritten_by_call
// CHECK: open_existential_addr
// CHECK-NEXT: witness_method
// CHECK-NEXT: apply
// CHECK: return
sil @existential_is_overwritten_by_call : $@convention(thin) () -> Int64 {
bb0:
%2 = alloc_stack $P, let, name "p"
%3 = init_existential_addr %2 : $*P, $X
%6 = integer_literal $Builtin.Int64, 27
%7 = struct $Int64 (%6 : $Builtin.Int64)
%8 = struct $X (%7 : $Int64)
store %8 to %3 : $*X
destroy_addr %2 : $*P
%f = function_ref @write_p : $@convention(thin) () -> @out P
%a = apply %f(%2) : $@convention(thin) () -> @out P
%10 = open_existential_addr %2 : $*P to $*@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P
%11 = witness_method $@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P, #P.foo!1, %10 : $*@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
%12 = apply %11<@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P>(%10) : $@convention(witness_method) _0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
dealloc_stack %2 : $*P
return %12 : $Int64
}
// CHECK-LABEL: sil @existential_is_not_overwritten_by_call
// CHECK-NOT: open_existential_addr
// CHECK: = function_ref @foo_witness
// CHECK-NEXT: apply
// CHECK-NOT: open_existential_addr
// CHECK: return
sil @existential_is_not_overwritten_by_call : $@convention(thin) () -> Int64 {
bb0:
%2 = alloc_stack $P, let, name "p"
%3 = init_existential_addr %2 : $*P, $X
%6 = integer_literal $Builtin.Int64, 27
%7 = struct $Int64 (%6 : $Builtin.Int64)
%8 = struct $X (%7 : $Int64)
store %8 to %3 : $*X
%f = function_ref @read_p : $@convention(thin) (@in P) -> ()
%a = apply %f(%2) : $@convention(thin) (@in P) -> ()
%10 = open_existential_addr %2 : $*P to $*@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P
%11 = witness_method $@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P, #P.foo!1, %10 : $*@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
%12 = apply %11<@opened("C22498FA-CABF-11E5-B9A9-685B35C48C83") P>(%10) : $@convention(witness_method) _0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
destroy_addr %2 : $*P
dealloc_stack %2 : $*P
return %12 : $Int64
}
sil @write_p : $@convention(thin) () -> @out P
sil @read_p : $@convention(thin) (@in P) -> ()
sil @foo_witness : $@convention(witness_method) (@in_guaranteed X) -> Int64
sil_witness_table hidden X: P module nix {
method #P.foo!1: @foo_witness
}
sil_vtable ArrayClassReaderWriter {
#ArrayClassReaderWriter.init!initializer.1: _TFC28existential_type_propagation22ArrayClassReaderWritercfMS0_FT_S0_
}
sil_witness_table public_external ArrayClassReaderWriter: ReaderWriterType module main {
method #ReaderWriterType.init!allocator.1: @_TTWC28existential_type_propagation22ArrayClassReaderWriterS_16ReaderWriterTypeS_FS1_CuRq_S1__fMq_FT_q_
method #ReaderWriterType.read!1: @_TTWC28existential_type_propagation22ArrayClassReaderWriterS_16ReaderWriterTypeS_FS1_4readuRq_S1__fq_FSiSi
method #ReaderWriterType.write!1: @_TTWC28existential_type_propagation22ArrayClassReaderWriterS_16ReaderWriterTypeS_FS1_5writeuRq_S1__fRq_FTSi5valueSi_T_
}