blob: b2728d6066f6dd2e793239798e91545fd5cd02b0 [file] [log] [blame]
// RUN: %target-sil-opt -enable-sil-verify-all %s -capture-promotion | %FileCheck %s
// Check to make sure that the process of promoting closure captures results in
// a correctly cloned and modified closure function body. This test
// intentionally only includes one promotable closure so that there is minimal
// ordering dependence in the checked output.
sil_stage raw
import Builtin
struct Int {
var value : Builtin.Int64
}
class Foo {
func foo() -> Int
}
class Bar {
}
struct Baz {
var bar: Bar
var x: Int
}
sil @convert_from_integer_literal : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int
sil @foo_allocating_init : $@convention(thin) (@thick Foo.Type) -> @owned Foo
sil @baz_init : $@convention(thin) (@thin Baz.Type) -> @owned Baz
sil @dummy_func : $@convention(thin) (Int, Int, Int) -> Int
sil @destructured_baz_user : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> ()
sil @guaranteed_nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
// CHECK-LABEL: sil [ossa] @test_capture_promotion
sil [ossa] @test_capture_promotion : $@convention(thin) () -> @owned @callee_owned () -> (Int, Builtin.Int64) {
bb0:
// CHECK: [[BOX1:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Foo>
// CHECK: [[MARKED_BOX1:%.*]] = mark_uninitialized [var] [[BOX1]]
%1 = alloc_box $_0_0> { var τ_0_0 } <Foo>
%1ab = mark_uninitialized [var] %1 : $_0_0> { var τ_0_0 } <Foo>
%1a = project_box %1ab : $_0_0> { var τ_0_0 } <Foo>, 0
%2 = function_ref @foo_allocating_init : $@convention(thin) (@thick Foo.Type) -> @owned Foo
%3 = metatype $@thick Foo.Type
%4 = apply %2(%3) : $@convention(thin) (@thick Foo.Type) -> @owned Foo
store %4 to [init] %1a : $*Foo
// CHECK: [[BOX2:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Baz>
%6 = alloc_box $_0_0> { var τ_0_0 } <Baz>
%6a = project_box %6 : $_0_0> { var τ_0_0 } <Baz>, 0
%7 = function_ref @baz_init : $@convention(thin) (@thin Baz.Type) -> @owned Baz
%8 = metatype $@thin Baz.Type
%9 = apply %7(%8) : $@convention(thin) (@thin Baz.Type) -> @owned Baz
store %9 to [init] %6a : $*Baz
// CHECK: [[BOX3:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
%11 = alloc_box $_0_0> { var τ_0_0 } <Int>
%11a = project_box %11 : $_0_0> { var τ_0_0 } <Int>, 0
%12 = function_ref @convert_from_integer_literal : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int
%13 = metatype $@thin Int.Type
%14 = integer_literal $Builtin.Word, 3
%15 = apply %12(%14, %13) : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int
store %15 to [trivial] %11a : $*Int
// CHECK: [[BOX1_COPY:%.*]] = copy_value [[MARKED_BOX1]]
// CHECK: [[BOX1_COPY_PB:%.*]] = project_box [[BOX1_COPY]]
// CHECK: [[BOX2_COPY:%.*]] = copy_value [[BOX2]]
// CHECK: [[BOX2_COPY_PB:%.*]] = project_box [[BOX2_COPY]]
// CHECK: [[BOX3_COPY:%.*]] = copy_value [[BOX3]]
// CHECK: [[BOX3_COPY_PB:%.*]] = project_box [[BOX3_COPY]]
// CHECK-NOT: function_ref @closure0 :
// CHECK: [[CLOSURE_PROMOTE:%.*]] = function_ref @$s8closure0Tf2iii_n
// CHECK-NOT: function_ref @closure0 :
// The Foo variable is loaded from and retained, because it is a reference type
// CHECK-NEXT: [[LOADFOO:%.*]] = load [copy] [[BOX1_COPY_PB]] : $*Foo
// CHECK-NEXT: destroy_value [[BOX1_COPY]]
//
// The Baz variable is loaded and copied, because it is a non-trivial
// aggregate type
// CHECK-NEXT: [[LOADBAZ:%.*]] = load [copy] [[BOX2_COPY_PB]] : $*Baz
// CHECK-NEXT: destroy_value [[BOX2_COPY]]
// The Int variable is loaded only, because it is trivial
// CHECK-NEXT: [[LOADINT:%.*]] = load [trivial] [[BOX3_COPY_PB]] : $*Int
// CHECK-NEXT: destroy_value [[BOX3_COPY]]
// The partial apply has one value argument for each pair of arguments that was
// previously used to capture and pass the variable by reference
// CHECK-NEXT: {{.*}} = partial_apply [[CLOSURE_PROMOTE]]([[LOADFOO]], [[LOADBAZ]], [[LOADINT]])
%17 = function_ref @closure0 : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Foo>, @owned _0_0> { var τ_0_0 } <Baz>, @owned _0_0> { var τ_0_0 } <Int>) -> (Int, Builtin.Int64)
%18 = copy_value %1ab : $_0_0> { var τ_0_0 } <Foo>
%19 = copy_value %6 : $_0_0> { var τ_0_0 } <Baz>
%20 = copy_value %11 : $_0_0> { var τ_0_0 } <Int>
%21 = partial_apply %17(%18, %19, %20) : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Foo>, @owned _0_0> { var τ_0_0 } <Baz>, @owned _0_0> { var τ_0_0 } <Int>) -> (Int, Builtin.Int64)
destroy_value %11 : $_0_0> { var τ_0_0 } <Int>
destroy_value %6 : $_0_0> { var τ_0_0 } <Baz>
destroy_value %1ab : $_0_0> { var τ_0_0 } <Foo>
return %21 : $@callee_owned () -> (Int, Builtin.Int64)
}
// CHECK-LABEL: sil [ossa] @test_capture_promotion_indirect
sil [ossa] @test_capture_promotion_indirect : $@convention(thin) () -> @owned @callee_owned () -> @out Int {
bb0:
// CHECK: [[BOX1:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Foo>
%1 = alloc_box $_0_0> { var τ_0_0 } <Foo>
%1a = project_box %1 : $_0_0> { var τ_0_0 } <Foo>, 0
%2 = function_ref @foo_allocating_init : $@convention(thin) (@thick Foo.Type) -> @owned Foo
%3 = metatype $@thick Foo.Type
%4 = apply %2(%3) : $@convention(thin) (@thick Foo.Type) -> @owned Foo
store %4 to [init] %1a : $*Foo
// CHECK: [[BOX2:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Baz>
%6 = alloc_box $_0_0> { var τ_0_0 } <Baz>
%6a = project_box %6 : $_0_0> { var τ_0_0 } <Baz>, 0
%7 = function_ref @baz_init : $@convention(thin) (@thin Baz.Type) -> @owned Baz
%8 = metatype $@thin Baz.Type
%9 = apply %7(%8) : $@convention(thin) (@thin Baz.Type) -> @owned Baz
store %9 to [init] %6a : $*Baz
// CHECK: [[BOX3:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
%11 = alloc_box $_0_0> { var τ_0_0 } <Int>
%11a = project_box %11 : $_0_0> { var τ_0_0 } <Int>, 0
%12 = function_ref @convert_from_integer_literal : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int
%13 = metatype $@thin Int.Type
%14 = integer_literal $Builtin.Word, 3
%15 = apply %12(%14, %13) : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int
store %15 to [trivial] %11a : $*Int
// CHECK: [[BOX1_COPY:%.*]] = copy_value [[BOX1]]
// CHECK: [[BOX1_COPY_PB:%.*]] = project_box [[BOX1_COPY]]
// CHECK: [[BOX2_COPY:%.*]] = copy_value [[BOX2]]
// CHECK: [[BOX2_COPY_PB:%.*]] = project_box [[BOX2_COPY]]
// CHECK: [[BOX3_COPY:%.*]] = copy_value [[BOX3]]
// CHECK: [[BOX3_COPY_PB:%.*]] = project_box [[BOX3_COPY]]
// CHECK-NOT: function_ref @closure_indirect_result :
// CHECK: [[CLOSURE_PROMOTE:%.*]] = function_ref @$s23closure_indirect_resultTf2niii_n
// CHECK-NOT: function_ref @closure_indirect_result :
%17 = function_ref @closure_indirect_result : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Foo>, @owned _0_0> { var τ_0_0 } <Baz>, @owned _0_0> { var τ_0_0 } <Int>) -> @out Int
// CHECK-NEXT: [[LOADFOO:%.*]] = load [copy] [[BOX1_COPY_PB]] : $*Foo
// CHECK-NEXT: destroy_value [[BOX1_COPY]]
// CHECK-NEXT: [[LOADBAZ:%.*]] = load [copy] [[BOX2_COPY_PB]] : $*Baz
// CHECK-NEXT: destroy_value [[BOX2_COPY]]
// CHECK-NEXT: [[LOADINT:%.*]] = load [trivial] [[BOX3_COPY_PB]] : $*Int
// CHECK-NEXT: destroy_value [[BOX3_COPY]]
%18 = copy_value %1 : $_0_0> { var τ_0_0 } <Foo>
%19 = copy_value %6 : $_0_0> { var τ_0_0 } <Baz>
%20 = copy_value %11 : $_0_0> { var τ_0_0 } <Int>
// The partial apply has one value argument for each pair of arguments that was
// previously used to capture and pass the variable by reference
// CHECK-NEXT: {{.*}} = partial_apply [[CLOSURE_PROMOTE]]([[LOADFOO]], [[LOADBAZ]], [[LOADINT]])
%21 = partial_apply %17(%18, %19, %20) : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Foo>, @owned _0_0> { var τ_0_0 } <Baz>, @owned _0_0> { var τ_0_0 } <Int>) -> @out Int
destroy_value %11 : $_0_0> { var τ_0_0 } <Int>
destroy_value %6 : $_0_0> { var τ_0_0 } <Baz>
destroy_value %1 : $_0_0> { var τ_0_0 } <Foo>
return %21 : $@callee_owned () -> @out Int
}
// CHECK-LABEL: sil private [ossa] @$s8closure0Tf2iii_n : $@convention(thin) (@owned Foo, @owned Baz, Int) -> (Int, Builtin.Int64) {
// CHECK: bb0([[ORIGINAL_ARG0:%.*]] : @owned $Foo, [[ORIGINAL_ARG1:%.*]] : @owned $Baz, [[ARG2:%.*]] : $Int):
// CHECK: [[ARG0:%.*]] = begin_borrow [[ORIGINAL_ARG0]]
// CHECK: [[ARG1:%.*]] = begin_borrow [[ORIGINAL_ARG1]]
// CHECK: [[DUMMY_FUNC:%.*]] = function_ref @dummy_func : $@convention(thin) (Int, Int, Int) -> Int
// CHECK: [[ARG0_COPY:%.*]] = copy_value [[ARG0]]
// CHECK: [[METHOD_FOO:%.*]] = class_method [[ARG0_COPY]] : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int
// CHECK: [[BORROWED_ARG0_COPY:%.*]] = begin_borrow [[ARG0_COPY]]
// CHECK: [[APPLY_FOO:%.*]] = apply [[METHOD_FOO]]([[BORROWED_ARG0_COPY]]) : $@convention(method) (@guaranteed Foo) -> Int
// CHECK: end_borrow [[BORROWED_ARG0_COPY]]
// CHECK: destroy_value [[ARG0_COPY]]
// CHECK: [[EXTRACT_BAZ_X:%.*]] = struct_extract [[ARG1]] : $Baz, #Baz.x
// CHECK: [[EXTRACT_INT_VALUE:%.*]] = struct_extract [[ARG2]] : $Int, #Int.value
// CHECK: [[RETVAL:%.*]] = apply [[DUMMY_FUNC]]([[APPLY_FOO]], [[EXTRACT_BAZ_X]], {{.*}}) : $@convention(thin) (Int, Int, Int) -> Int
// The release of %4 is removed because the Int type is trivial
// The release of %2 is replaced by a release_value of the Baz argument, since
// it is a non-trivial aggregate
// CHECK: end_borrow [[ARG1]]
// CHECK: destroy_value [[ORIGINAL_ARG1]] : $Baz
// The release of %0 is replaced by a strong_release of the Foo argument, since
// it is a reference type
// CHECK: end_borrow [[ARG0]]
// CHECK: destroy_value [[ORIGINAL_ARG0]]
// CHECK: [[RESULT:%.*]] = tuple ([[RETVAL]] : $Int, [[EXTRACT_INT_VALUE]] : $Builtin.Int64)
// CHECK: return [[RESULT]] : $(Int, Builtin.Int64)
// CHECK: } // end sil function '$s8closure0Tf2iii_n'
sil private [ossa] @closure0 : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Foo>, @owned _0_0> { var τ_0_0 } <Baz>, @owned _0_0> { var τ_0_0 } <Int>) -> (Int, Builtin.Int64) {
bb0(%0 : @owned $_0_0> { var τ_0_0 } <Foo>, %2 : @owned $_0_0> { var τ_0_0 } <Baz>, %4 : @owned $_0_0> { var τ_0_0 } <Int>):
%1 = project_box %0 : $_0_0> { var τ_0_0 } <Foo>, 0
%3 = project_box %2 : $_0_0> { var τ_0_0 } <Baz>, 0
%5 = project_box %4 : $_0_0> { var τ_0_0 } <Int>, 0
%6 = tuple ()
// function_ref test14.plus (a : Swift.Int, b : Swift.Int, c : Swift.Int) -> Swift.Int
%7 = function_ref @dummy_func : $@convention(thin) (Int, Int, Int) -> Int
%8 = load [copy] %1 : $*Foo
%10 = class_method %8 : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int
%9 = begin_borrow %8 : $Foo
%11 = apply %10(%9) : $@convention(method) (@guaranteed Foo) -> Int
end_borrow %9 : $Foo
destroy_value %8 : $Foo
%12 = struct_element_addr %3 : $*Baz, #Baz.x
%13 = load [trivial] %12 : $*Int
%14 = load [trivial] %5 : $*Int
%15 = struct_element_addr %5 : $*Int, #Int.value
%16 = load [trivial] %15 : $*Builtin.Int64
%17 = apply %7(%11, %13, %14) : $@convention(thin) (Int, Int, Int) -> Int
destroy_value %4 : $_0_0> { var τ_0_0 } <Int>
destroy_value %2 : $_0_0> { var τ_0_0 } <Baz>
destroy_value %0 : $_0_0> { var τ_0_0 } <Foo>
%18 = tuple(%17 : $Int, %16 : $Builtin.Int64)
return %18 : $(Int, Builtin.Int64)
}
// The closure in this function is not promotable because it mutates its argument
// CHECK-LABEL: sil [ossa] @test_unpromotable
sil [ossa] @test_unpromotable : $@convention(thin) () -> @owned @callee_owned () -> Int {
bb0:
%0 = tuple ()
%1 = alloc_box $_0_0> { var τ_0_0 } <Foo>
%1a = project_box %1 : $_0_0> { var τ_0_0 } <Foo>, 0
%2 = function_ref @foo_allocating_init : $@convention(thin) (@thick Foo.Type) -> @owned Foo
%3 = metatype $@thick Foo.Type
%4 = apply %2(%3) : $@convention(thin) (@thick Foo.Type) -> @owned Foo
store %4 to [init] %1a : $*Foo
%17 = function_ref @closure1 : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Foo>) -> Int
%18 = copy_value %1 : $_0_0> { var τ_0_0 } <Foo>
// CHECK: partial_apply {{%.*}}({{%.*}})
%21 = partial_apply %17(%18) : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Foo>) -> Int
destroy_value %1 : $_0_0> { var τ_0_0 } <Foo>
return %21 : $@callee_owned () -> Int
}
sil [ossa] @mutate_foo : $@convention(thin) (@inout Foo) -> ()
sil private [ossa] @closure1 : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Foo>) -> Int {
bb0(%0 : @owned $_0_0> { var τ_0_0 } <Foo>):
%1 = project_box %0 : $_0_0> { var τ_0_0 } <Foo>, 0
%6 = tuple ()
// function_ref test14.plus (a : Swift.Int, b : Swift.Int, c : Swift.Int) -> Swift.Int
%7 = function_ref @dummy_func : $@convention(thin) (Int, Int, Int) -> Int
%8 = load [copy] %1 : $*Foo
%10 = class_method %8 : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int
%9 = begin_borrow %8 : $Foo
%11 = apply %10(%9) : $@convention(method) (@guaranteed Foo) -> Int
end_borrow %9 : $Foo
destroy_value %8 : $Foo
%12 = function_ref @mutate_foo : $@convention(thin) (@inout Foo) -> ()
%13 = apply %12(%1) : $@convention(thin) (@inout Foo) -> ()
destroy_value %0 : $_0_0> { var τ_0_0 } <Foo>
return %11 : $Int
}
sil [ossa] @apply : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK-LABEL: sil [ossa] @captureWithinGeneric
sil [ossa] @captureWithinGeneric : $@convention(thin) <T> (@inout Int, @inout Int) -> () {
// CHECK: bb0
bb0(%0 : $*Int, %1 : $*Int):
%2 = alloc_box $_0_0> { var τ_0_0 } <Int>
%2a = project_box %2 : $_0_0> { var τ_0_0 } <Int>, 0
copy_addr %0 to [initialization] %2a : $*Int
%4 = alloc_box $_0_0> { var τ_0_0 } <Int>
%4a = project_box %4 : $_0_0> { var τ_0_0 } <Int>, 0
copy_addr %1 to [initialization] %4a : $*Int
%6 = function_ref @apply : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK: [[PROMOTED:%[0-9a-zA-Z]+]] = function_ref @$s27closureWithGenericSignatureTf2ni_n : $@convention(thin) <τ_0_0> (@owned <τ_0_0> { var τ_0_0 } <Int>, Int) -> ()
%7 = function_ref @closureWithGenericSignature : $@convention(thin) _0_0> (@owned _0_0> { var τ_0_0 } <Int>, @owned _0_0> { var τ_0_0 } <Int>) -> ()
%8 = copy_value %4 : $_0_0> { var τ_0_0 } <Int>
%9 = copy_value %2 : $_0_0> { var τ_0_0 } <Int>
// CHECK: partial_apply [[PROMOTED]]<{{[^>]+}}>(
%10 = partial_apply %7<T>(%8, %9) : $@convention(thin) _0_0> (@owned _0_0> { var τ_0_0 } <Int>, @owned _0_0> { var τ_0_0 } <Int>) -> ()
%11 = apply %6(%10) : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
copy_addr %4a to %1 : $*Int
destroy_value %4 : $_0_0> { var τ_0_0 } <Int>
copy_addr %2a to %0 : $*Int
destroy_value %2 : $_0_0> { var τ_0_0 } <Int>
%16 = tuple ()
return %16 : $()
}
// CHECK: sil [ossa] @$s27closureWithGenericSignatureTf2ni_n : $@convention(thin) <{{[^>]+}}> (@owned <τ_0_0> { var τ_0_0 } <Int>, Int) -> ()
sil [ossa] @closureWithGenericSignature : $@convention(thin) <T> (@owned _0_0> { var τ_0_0 } <Int>, @owned _0_0> { var τ_0_0 } <Int>) -> () {
bb0(%0 : @owned $_0_0> { var τ_0_0 } <Int>, %2 : @owned $_0_0> { var τ_0_0 } <Int>):
%1 = project_box %0 : $_0_0> { var τ_0_0 } <Int>, 0
%3 = project_box %2 : $_0_0> { var τ_0_0 } <Int>, 0
%4 = function_ref @$ss1poiyS2i_SitF : $@convention(thin) (Int, Int) -> Int
%5 = load [trivial] %3 : $*Int
%6 = load [trivial] %3 : $*Int
%7 = apply %4(%5, %6) : $@convention(thin) (Int, Int) -> Int
assign %7 to %1 : $*Int
destroy_value %2 : $_0_0> { var τ_0_0 } <Int>
destroy_value %0 : $_0_0> { var τ_0_0 } <Int>
%11 = tuple ()
return %11 : $()
}
sil [transparent] [serialized] @$ss1poiyS2i_SitF : $@convention(thin) (Int, Int) -> Int
sil private [ossa] @closure_indirect_result : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Foo>, @owned _0_0> { var τ_0_0 } <Baz>, @owned _0_0> { var τ_0_0 } <Int>) -> @out Int {
bb0(%0: $*Int, %1 : @owned $_0_0> { var τ_0_0 } <Foo>, %2 : @owned $_0_0> { var τ_0_0 } <Baz>, %4 : @owned $_0_0> { var τ_0_0 } <Int>):
%17 = project_box %1 : $_0_0> { var τ_0_0 } <Foo>, 0
%3 = project_box %2 : $_0_0> { var τ_0_0 } <Baz>, 0
%5 = project_box %4 : $_0_0> { var τ_0_0 } <Int>, 0
// function_ref test14.plus (a : Swift.Int, b : Swift.Int, c : Swift.Int) -> Swift.Int
%7 = function_ref @dummy_func : $@convention(thin) (Int, Int, Int) -> Int
%8 = load [copy] %17 : $*Foo
%10 = class_method %8 : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int
%9 = begin_borrow %8 : $Foo
%11 = apply %10(%9) : $@convention(method) (@guaranteed Foo) -> Int
end_borrow %9 : $Foo
destroy_value %8 : $Foo
%12 = struct_element_addr %3 : $*Baz, #Baz.x
%13 = load [trivial] %12 : $*Int
%14 = load [trivial] %5 : $*Int
%15 = apply %7(%11, %13, %14) : $@convention(thin) (Int, Int, Int) -> Int
destroy_value %4 : $_0_0> { var τ_0_0 } <Int>
destroy_value %2 : $_0_0> { var τ_0_0 } <Baz>
destroy_value %1 : $_0_0> { var τ_0_0 } <Foo>
store %15 to [trivial] %0 : $*Int
%16 = tuple()
return %16 : $()
}
// This test makes sure that we properly handle non load uses of
// struct_element_addr that always have load users with the load occurring before
// and after the element in the use list.
sil [ossa] @mutate_int : $@convention(thin) (@inout Int) -> ()
// CHECK-LABEL: sil [ossa] @test_closure_multiple_uses_of_struct_element_addr : $@convention(thin) () -> @owned @callee_owned () -> () {
// CHECK: [[FUNC:%.*]] = function_ref @closure_multiple_uses_of_struct_element_addr : $@convention(thin)
// CHECK: partial_apply [[FUNC]](
// CHECK: } // end sil function 'test_closure_multiple_uses_of_struct_element_addr'
sil [ossa] @test_closure_multiple_uses_of_struct_element_addr : $@convention(thin) () -> @owned @callee_owned () -> () {
bb0:
%0 = function_ref @baz_init : $@convention(thin) (@thin Baz.Type) -> @owned Baz
%1 = metatype $@thin Baz.Type
%2 = alloc_box $_0_0> { var τ_0_0 } <Baz>
%3 = project_box %2 : $_0_0> { var τ_0_0 } <Baz>, 0
%4 = apply %0(%1) : $@convention(thin) (@thin Baz.Type) -> @owned Baz
store %4 to [init] %3 : $*Baz
%5 = alloc_box $_0_0> { var τ_0_0 } <Baz>
%6 = project_box %5 : $_0_0> { var τ_0_0 } <Baz>, 0
%7 = apply %0(%1) : $@convention(thin) (@thin Baz.Type) -> @owned Baz
store %7 to [init] %6 : $*Baz
%8 = function_ref @closure_multiple_uses_of_struct_element_addr : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Baz>, @owned _0_0> { var τ_0_0 } <Baz>) -> ()
%9 = partial_apply %8(%2, %5) : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Baz>, @owned _0_0> { var τ_0_0 } <Baz>) -> ()
return %9 : $@callee_owned () -> ()
}
sil [ossa] @closure_multiple_uses_of_struct_element_addr : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Baz>, @owned _0_0> { var τ_0_0 } <Baz>) -> () {
bb0(%0 : @owned $_0_0> { var τ_0_0 } <Baz>, %1 : @owned $_0_0> { var τ_0_0 } <Baz>):
%2 = project_box %0 : $_0_0> { var τ_0_0 } <Baz>, 0
%3 = struct_element_addr %2 : $*Baz, #Baz.x
%4 = load [trivial] %3 : $*Int
%5 = function_ref @mutate_int : $@convention(thin) (@inout Int) -> ()
apply %5(%3) : $@convention(thin) (@inout Int) -> ()
%6 = project_box %1 : $_0_0> { var τ_0_0 } <Baz>, 0
%7 = struct_element_addr %6 : $*Baz, #Baz.x
apply %5(%7) : $@convention(thin) (@inout Int) -> ()
%8 = load [trivial] %7 : $*Int
destroy_value %1 : $_0_0> { var τ_0_0 } <Baz>
destroy_value %0 : $_0_0> { var τ_0_0 } <Baz>
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @test_capture_projection_test : $@convention(thin) () -> @owned @callee_owned () -> () {
sil [ossa] @test_capture_projection_test : $@convention(thin) () -> @owned @callee_owned () -> () {
bb0:
%0 = function_ref @baz_init : $@convention(thin) (@thin Baz.Type) -> @owned Baz
%1 = metatype $@thin Baz.Type
// CHECK: [[BOX1:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Baz>
%2 = alloc_box $_0_0> { var τ_0_0 } <Baz>
%3 = project_box %2 : $_0_0> { var τ_0_0 } <Baz>, 0
%4 = apply %0(%1) : $@convention(thin) (@thin Baz.Type) -> @owned Baz
store %4 to [init] %3 : $*Baz
// CHECK: [[BOX2:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Baz>
%5 = alloc_box $_0_0> { var τ_0_0 } <Baz>
%6 = project_box %5 : $_0_0> { var τ_0_0 } <Baz>, 0
%7 = apply %0(%1) : $@convention(thin) (@thin Baz.Type) -> @owned Baz
store %7 to [init] %6 : $*Baz
// CHECK: [[BOX1_COPY:%.*]] = copy_value [[BOX1]]
// CHECK: [[BOX2_COPY:%.*]] = copy_value [[BOX2]]
// CHECK: [[BOX2_COPY_PB:%.*]] = project_box [[BOX2_COPY]]
// CHECK-NOT: function_ref @closure_indirect_result :
// CHECK: [[SPECIALIZED_FUNC:%.*]] = function_ref @$s23closure_projection_testTf2ni_n : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Baz>, @owned Baz) -> ()
// CHECK-NOT: function_ref @closure_projection_test :
// CHECK: [[LOADBAZ:%.*]] = load [copy] [[BOX2_COPY_PB]] : $*Baz
// CHECK: destroy_value [[BOX2_COPY]]
%19 = copy_value %2 : $_0_0> { var τ_0_0 } <Baz>
%20 = copy_value %5 : $_0_0> { var τ_0_0 } <Baz>
%17 = function_ref @closure_projection_test : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Baz>, @owned _0_0> { var τ_0_0 } <Baz>) -> ()
// The partial apply has one value argument for each pair of arguments that was
// previously used to capture and pass the variable by reference
// CHECK: {{.*}} = partial_apply [[SPECIALIZED_FUNC]]([[BOX1_COPY]], [[LOADBAZ]])
%21 = partial_apply %17(%19, %20) : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Baz>, @owned _0_0> { var τ_0_0 } <Baz>) -> ()
destroy_value %2 : $_0_0> { var τ_0_0 } <Baz>
destroy_value %5 : $_0_0> { var τ_0_0 } <Baz>
return %21 : $@callee_owned () -> ()
}
// CHECK-LABEL: sil [ossa] @$s23closure_projection_testTf2ni_n : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Baz>, @owned Baz) -> () {
// CHECK: bb0([[UNPROMOTED_BAZ:%.*]] : @owned $<τ_0_0> { var τ_0_0 } <Baz>, [[BAZ:%.*]] : @owned $Baz):
// CHECK: [[BORROWED_BAZ:%.*]] = begin_borrow [[BAZ]] : $Baz
// CHECK: [[X:%.*]] = struct_extract [[BORROWED_BAZ]] : $Baz, #Baz.x
// CHECK: [[BAR:%.*]] = struct_extract [[BORROWED_BAZ]] : $Baz, #Baz.bar
// CHECK: [[BAR_COPY:%.*]] = copy_value [[BAR]]
// CHECK: [[BAR2:%.*]] = struct_extract [[BORROWED_BAZ]] : $Baz, #Baz.bar
// CHECK: [[BAR2_COPY:%.*]] = copy_value [[BAR2]]
// CHECK: [[BAR2_COPY_BORROW:%.*]] = begin_borrow [[BAR2_COPY]]
// CHECK: apply {{%.*}}([[BAR_COPY]], [[BAR2_COPY_BORROW]], [[X]])
// CHECK: end_borrow [[BAR2_COPY_BORROW]]
// CHECK: destroy_value [[BAR2_COPY]]
// CHECK: end_borrow [[BORROWED_BAZ]]
// CHECK: destroy_value [[BAZ]]
// CHECK: } // end sil function '$s23closure_projection_testTf2ni_n'
sil [ossa] @closure_projection_test : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Baz>, @owned _0_0> { var τ_0_0 } <Baz>) -> () {
bb0(%0 : @owned $_0_0> { var τ_0_0 } <Baz>, %1 : @owned $_0_0> { var τ_0_0 } <Baz>):
%0a = project_box %0 : $_0_0> { var τ_0_0 } <Baz>, 0
%2 = struct_element_addr %0a : $*Baz, #Baz.x
%3 = struct_element_addr %0a : $*Baz, #Baz.bar
%4 = load [trivial] %2 : $*Int
%5 = load [take] %3 : $*Bar
%6 = load [copy] %3 : $*Bar
%7 = begin_borrow %6 : $Bar
%8 = function_ref @destructured_baz_user : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> ()
apply %8(%5, %7, %4) : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> ()
end_borrow %7 : $Bar
destroy_value %6 : $Bar
%1a = project_box %1 : $_0_0> { var τ_0_0 } <Baz>, 0
%9 = struct_element_addr %1a : $*Baz, #Baz.x
%10 = struct_element_addr %1a : $*Baz, #Baz.bar
%11 = load [trivial] %9 : $*Int
%12 = load [copy] %10 : $*Bar
%13 = load [copy] %10 : $*Bar
%14 = begin_borrow %13 : $Bar
%15 = function_ref @destructured_baz_user : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> ()
apply %15(%12, %14, %11) : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> ()
end_borrow %14 : $Bar
destroy_value %13 : $Bar
destroy_value %1 : $_0_0> { var τ_0_0 } <Baz>
destroy_value %0 : $_0_0> { var τ_0_0 } <Baz>
%t = tuple()
return %t : $()
}
// Make sure that we properly handle guaranteed arguments when specializing here.
sil [ossa] @capture_promotion_callee_guaranteed_box : $@convention(thin) (@guaranteed { var Builtin.NativeObject }) -> () {
bb0(%0 : @guaranteed ${ var Builtin.NativeObject }):
%1 = project_box %0 : ${ var Builtin.NativeObject }, 0
%2 = begin_access [read] [unknown] %1 : $*Builtin.NativeObject
%3 = load [copy] %2 : $*Builtin.NativeObject
end_access %2 : $*Builtin.NativeObject
%4 = function_ref @guaranteed_nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %4(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %3 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// Just make sure that we specialized so that the ownership verifier can make
// sure we emitted ownership correctly.
//
// CHECK-LABEL: sil [ossa] @capture_promotion_caller_guaranteed_box : $@convention(thin) (@owned Builtin.NativeObject) -> @owned @callee_owned () -> () {
// CHECK: [[FUNC_REF:%.*]] = function_ref @$s39capture_promotion_callee_guaranteed_boxTf2i_n :
// CHECK: apply [[FUNC_REF]](
// CHECK: } // end sil function 'capture_promotion_caller_guaranteed_box'
sil [ossa] @capture_promotion_caller_guaranteed_box : $@convention(thin) (@owned Builtin.NativeObject) -> @owned @callee_owned () -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = alloc_box ${ var Builtin.NativeObject }
%2 = project_box %1 : ${ var Builtin.NativeObject }, 0
store %0 to [init] %2 : $*Builtin.NativeObject
%3 = function_ref @capture_promotion_callee_guaranteed_box : $@convention(thin) (@guaranteed { var Builtin.NativeObject }) -> ()
%pai = partial_apply %3(%1) : $@convention(thin) (@guaranteed { var Builtin.NativeObject }) -> ()
return %pai : $@callee_owned () -> ()
}