// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all -generic-specializer %s | %FileCheck %s // REQUIRES: swift_in_compiler sil_stage canonical import Builtin import Swift public protocol RefProto { associatedtype T var me: Ref { get } } public final class Ref : RefProto { public final var me: Ref { get } deinit init() } extension RefProto { public func merge(other: Ref) -> Ref<(Self.T, U)> } public protocol ValProto { associatedtype T var me: Val { get } } extension ValProto { public func merge(other: Val) -> Val<(Self.T, U)> } public struct Val : ValProto { public var me: Val { get } init() } class X {} sil @coerce : $@convention(thin) (@owned @callee_owned (@owned Ref) -> @owned @callee_owned (@owned Ref) -> @owned Ref) -> @owned @callee_owned (Val) -> Val sil @merge : $@convention(method) (@owned Ref, @in_guaranteed Self) -> @owned Ref<(Self.T, U)> { bb0(%0 : $Ref, %1 : $*Self): %2 = alloc_ref $Ref<(Self.T, U)> strong_release %0 : $Ref return %2 : $Ref<(Self.T, U)> } sil @merge_curried : $@convention(thin) (@in Self) -> @owned @callee_owned (@owned Ref) -> @owned Ref<(Self.T, U)> { bb0(%0 : $*Self): %1 = function_ref @merge : $@convention(method) <τ_0_0 where τ_0_0 : RefProto><τ_1_0> (@owned Ref<τ_1_0>, @in_guaranteed τ_0_0) -> @owned Ref<(τ_0_0.T, τ_1_0)> %2 = partial_apply %1(%0) : $@convention(method) <τ_0_0 where τ_0_0 : RefProto><τ_1_0> (@owned Ref<τ_1_0>, @in_guaranteed τ_0_0) -> @owned Ref<(τ_0_0.T, τ_1_0)> return %2 : $@callee_owned (@owned Ref) -> @owned Ref<(Self.T, U)> } sil [reabstraction_thunk] @reabstract : $@convention(thin) (@owned Ref, @owned @callee_owned (@in Ref) -> @owned @callee_owned (@owned Ref) -> @owned Ref<(Self.T, U)>) -> @owned @callee_owned (@owned Ref) -> @owned Ref<(Self.T, U)> { bb0(%0 : $Ref, %1 : $@callee_owned (@in Ref) -> @owned @callee_owned (@owned Ref) -> @owned Ref<(Self.T, U)>): %2 = alloc_stack $Ref store %0 to %2 : $*Ref %4 = apply %1(%2) : $@callee_owned (@in Ref) -> @owned @callee_owned (@owned Ref) -> @owned Ref<(Self.T, U)> dealloc_stack %2 : $*Ref return %4 : $@callee_owned (@owned Ref) -> @owned Ref<(Self.T, U)> } // CHECK-LABEL: sil @test sil @test : $@convention(thin) (Val, Val) -> Val<(Bool, Int)> { // CHECK: bb0 bb0(%0 : $Val, %1 : $Val): // CHECK: [[COERCE:%.*]] = function_ref @coerce %2 = function_ref @coerce : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2> (@owned @callee_owned (@owned Ref<τ_0_0>) -> @owned @callee_owned (@owned Ref<τ_0_1>) -> @owned Ref<τ_0_2>) -> @owned @callee_owned (Val<τ_0_1>) -> Val<τ_0_2> // CHECK: [[MERGE:%.*]] = function_ref @$s13merge_curried4main3RefCySbG_SiTg5 %3 = function_ref @merge_curried : $@convention(thin) <τ_0_0 where τ_0_0 : RefProto><τ_1_0> (@in τ_0_0) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)> // CHECK: [[PARTIAL:%.*]] = partial_apply [[MERGE]]() %4 = partial_apply %3, Int>() : $@convention(thin) <τ_0_0 where τ_0_0 : RefProto><τ_1_0> (@in τ_0_0) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)> // CHECK-NOT: function_ref @reabstract %5 = function_ref @reabstract : $@convention(thin) <τ_0_0 where τ_0_0 : ValProto><τ_1_0> (@owned Ref<τ_0_0.T>, @owned @callee_owned (@in Ref<τ_0_0.T>) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)>) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)> // CHECK-NOT: partial_apply %6 = partial_apply %5, Int>(%4) : $@convention(thin) <τ_0_0 where τ_0_0 : ValProto><τ_1_0> (@owned Ref<τ_0_0.T>, @owned @callee_owned (@in Ref<τ_0_0.T>) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)>) -> @owned @callee_owned (@owned Ref<τ_1_0>) -> @owned Ref<(τ_0_0.T, τ_1_0)> // CHECK: apply [[COERCE]]([[PARTIAL]]) %7 = apply %2(%6) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2> (@owned @callee_owned (@owned Ref<τ_0_0>) -> @owned @callee_owned (@owned Ref<τ_0_1>) -> @owned Ref<τ_0_2>) -> @owned @callee_owned (Val<τ_0_1>) -> Val<τ_0_2> %8 = apply %7(%1) : $@callee_owned (Val) -> Val<(Bool, Int)> return %8 : $Val<(Bool, Int)> } // CHECK-LABEL: sil shared @$s9coroutineSb_Tg5 : $@yield_once @convention(thin) (Bool) -> @yields @inout Bool { // CHECK: bb0(%0 : $Bool): // CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $Bool // CHECK-NEXT: store %0 to [[TEMP]] : $*Bool // CHECK-NEXT: yield [[TEMP]] : $*Bool, resume bb1, unwind bb2 // CHECK: bb1: // CHECK-NEXT: destroy_addr [[TEMP]] : $*Bool // CHECK-NEXT: [[RV:%.*]] = tuple () // CHECK-NEXT: dealloc_stack [[TEMP]] : $*Bool // CHECK-NEXT: return [[RV]] : $() // CHECK: bb2: // CHECK-NEXT: destroy_addr [[TEMP]] : $*Bool // CHECK-NEXT: dealloc_stack [[TEMP]] : $*Bool // CHECK-NEXT: unwind // CHECK-NEXT: } sil @coroutine : $@yield_once @convention(thin) (@in T) -> @yields @inout T { bb0(%0 : $*T): yield %0 : $*T, resume bb1, unwind bb2 bb1: destroy_addr %0 : $*T %rv = tuple () return %rv : $() bb2: destroy_addr %0 : $*T unwind } // CHECK-LABEL: @test_coroutine : $@convention(thin) (Bool) -> () { // CHECK: bb0(%0 : $Bool): // CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $Bool // CHECK-NEXT: store %0 to [[TEMP]] : $*Bool // CHECK-NEXT: // function_ref // CHECK-NEXT: [[CORO:%.*]] = function_ref @$s9coroutineSb_Tg5 : $@yield_once @convention(thin) (Bool) -> @yields @inout Bool // CHECK-NEXT: [[LOAD:%.*]] = load [[TEMP]] : $*Bool // CHECK-NEXT: ([[ADDR:%.*]], [[TOKEN:%.*]]) = begin_apply [[CORO]]([[LOAD]]) // CHECK-NEXT: end_apply [[TOKEN]] as $() // CHECK-NEXT: dealloc_stack [[TEMP]] : $*Bool // CHECK-NEXT: [[RV:%.*]] = tuple () // CHECK-NEXT: return [[RV]] : $() // CHECK-NEXT: } sil @test_coroutine : $@convention(thin) (Bool) -> () { bb0(%0 : $Bool): %coro = function_ref @coroutine : $@yield_once @convention(thin) (@in T) -> @yields @inout T %temp = alloc_stack $Bool store %0 to %temp : $*Bool (%addr, %token) = begin_apply %coro(%temp) : $@yield_once @convention(thin) (@in T) -> @yields @inout T end_apply %token as $() dealloc_stack %temp : $*Bool %rv = tuple () return %rv : $() } // CHECK-LABEL: sil shared @$s21arg_escapes_to_return4main1XC_Tg5 // CHECK-NEXT: [%0: escape -> %r] // CHECK-NEXT: {{^[^[]}} sil @arg_escapes_to_return : $@convention(thin) (@in_guaranteed T) -> @out T { [%1: escape -> %0] bb0(%0 : $*T, %1 : $*T): copy_addr %1 to [init] %0 : $*T %4 = tuple () return %4 : $() } // CHECK-LABEL: sil shared @$s015arg_escapes_to_A04main1XC_Tg5 // CHECK-NEXT: [%1: escape -> %0] // CHECK-NEXT: {{^[^[]}} sil @arg_escapes_to_arg : $@convention(thin) (@inout T, @in_guaranteed T) -> () { [%1: escape -> %0] bb0(%0 : $*T, %1 : $*T): copy_addr %1 to %0 : $*T %4 = tuple () return %4 : $() } sil @test_escape_effects : $@convention(thin) (@guaranteed X) -> @owned X { bb0(%0 : $X): %2 = alloc_stack $X %3 = alloc_stack $X store %0 to %3 : $*X %5 = function_ref @arg_escapes_to_return : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0 %6 = apply %5(%2, %3) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0 %7 = function_ref @arg_escapes_to_arg : $@convention(thin) <τ_0_0> (@inout τ_0_0, @in_guaranteed τ_0_0) -> () %8 = apply %7(%2, %3) : $@convention(thin) <τ_0_0> (@inout τ_0_0, @in_guaranteed τ_0_0) -> () dealloc_stack %3 : $*X %10 = load %2 : $*X dealloc_stack %2 : $*X return %10 : $X }