// RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s struct Int { mutating func foo() {} } struct Foo { var f: (T) -> U var g: T } // CHECK-LABEL: sil hidden @_T020property_abstraction4getF{{[_0-9a-zA-Z]*}}Foo{{.*}}F : $@convention(thin) (@owned Foo) -> @owned @callee_owned (Int) -> Int { // CHECK: bb0([[X_ORIG:%.*]] : $Foo): // CHECK: [[BORROWED_X_ORIG:%.*]] = begin_borrow [[X_ORIG]] : $Foo // CHECK: [[F_ORIG:%.*]] = struct_extract [[BORROWED_X_ORIG]] : $Foo, #Foo.f // CHECK: [[F_ORIG_COPY:%.*]] = copy_value [[F_ORIG]] // CHECK: [[REABSTRACT_FN:%.*]] = function_ref @_T0{{.*}}TR : // CHECK: [[F_SUBST:%.*]] = partial_apply [[REABSTRACT_FN]]([[F_ORIG_COPY]]) // CHECK: end_borrow [[BORROWED_X_ORIG]] from [[X_ORIG]] // CHECK: destroy_value [[X_ORIG]] // CHECK: return [[F_SUBST]] // CHECK: } // end sil function '_T020property_abstraction4getF{{[_0-9a-zA-Z]*}}F' func getF(_ x: Foo) -> (Int) -> Int { return x.f } // CHECK-LABEL: sil hidden @_T020property_abstraction4setF{{[_0-9a-zA-Z]*}}F // CHECK: [[REABSTRACT_FN:%.*]] = function_ref @_T0{{.*}}TR : // CHECK: [[F_ORIG:%.*]] = partial_apply [[REABSTRACT_FN]]({{%.*}}) // CHECK: [[F_ADDR:%.*]] = struct_element_addr {{%.*}} : $*Foo, #Foo.f // CHECK: assign [[F_ORIG]] to [[F_ADDR]] func setF(_ x: inout Foo, f: @escaping (Int) -> Int) { x.f = f } func inOutFunc(_ f: inout ((Int) -> Int)) { } // CHECK-LABEL: sil hidden @_T020property_abstraction6inOutF{{[_0-9a-zA-Z]*}}F : // CHECK: bb0([[ARG:%.*]] : $Foo): // CHECK: [[XBOX:%.*]] = alloc_box ${ var Foo }, var, name "x" // CHECK: [[XBOX_PB:%.*]] = project_box [[XBOX]] : ${ var Foo }, 0 // CHECK: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]] // CHECK: [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]] // CHECK: store [[ARG_COPY]] to [init] [[XBOX_PB]] // CHECK: end_borrow [[BORROWED_ARG]] from [[ARG]] // CHECK: [[INOUTFUNC:%.*]] = function_ref @_T020property_abstraction9inOutFunc{{[_0-9a-zA-Z]*}}F // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[XBOX_PB]] : $*Foo // CHECK: [[F_ADDR:%.*]] = struct_element_addr [[WRITE]] : $*Foo, #Foo.f // CHECK: [[F_SUBST_MAT:%.*]] = alloc_stack // CHECK: [[F_ORIG:%.*]] = load [copy] [[F_ADDR]] // CHECK: [[REABSTRACT_FN:%.*]] = function_ref @_T0{{.*}}TR : // CHECK: [[F_SUBST_IN:%.*]] = partial_apply [[REABSTRACT_FN]]([[F_ORIG]]) // CHECK: store [[F_SUBST_IN]] to [init] [[F_SUBST_MAT]] // CHECK: apply [[INOUTFUNC]]([[F_SUBST_MAT]]) // CHECK: [[F_SUBST_OUT:%.*]] = load [take] [[F_SUBST_MAT]] // CHECK: [[REABSTRACT_FN:%.*]] = function_ref @_T0{{.*}}TR : // CHECK: [[F_ORIG:%.*]] = partial_apply [[REABSTRACT_FN]]([[F_SUBST_OUT]]) // CHECK: assign [[F_ORIG]] to [[F_ADDR]] // CHECK: destroy_value [[XBOX]] // CHECK: destroy_value [[ARG]] // CHECK: } // end sil function '_T020property_abstraction6inOutF{{[_0-9a-zA-Z]*}}F' func inOutF(_ x: Foo) { var x = x inOutFunc(&x.f) } // Don't produce a writeback for generic lvalues when there's no real // abstraction difference. // CHECK-LABEL: sil hidden @_T020property_abstraction23noAbstractionDifference{{[_0-9a-zA-Z]*}}F func noAbstractionDifference(_ x: Foo) { var x = x // CHECK: [[ADDR:%.*]] = struct_element_addr {{%.*}}, #Foo.g // CHECK: apply {{%.*}}([[ADDR]]) x.g.foo() } protocol P {} struct AddressOnlyLet { let f: (T) -> T let makeAddressOnly: P } // CHECK-LABEL: sil hidden @_T020property_abstraction34getAddressOnlyReabstractedProperty{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@in AddressOnlyLet) -> @owned @callee_owned (Int) -> Int // CHECK: bb0([[ARG:%.*]] : $*AddressOnlyLet): // CHECK: [[CLOSURE_ADDR:%.*]] = struct_element_addr {{%.*}} : $*AddressOnlyLet, #AddressOnlyLet.f // CHECK: [[CLOSURE_ORIG:%.*]] = load [copy] [[CLOSURE_ADDR]] // CHECK: [[REABSTRACT:%.*]] = function_ref // CHECK: [[CLOSURE_SUBST:%.*]] = partial_apply [[REABSTRACT]]([[CLOSURE_ORIG]]) // CHECK: destroy_addr [[ARG]] // CHECK: return [[CLOSURE_SUBST]] // CHECK: } // end sil function '_T020property_abstraction34getAddressOnlyReabstractedProperty{{[_0-9a-zA-Z]*}}F' func getAddressOnlyReabstractedProperty(_ x: AddressOnlyLet) -> (Int) -> Int { return x.f } enum Bar { case F((T) -> U) } func getF(_ x: Bar) -> (Int) -> Int { switch x { case .F(var f): return f } } func makeF(_ f: @escaping (Int) -> Int) -> Bar { return Bar.F(f) } struct ArrayLike { subscript(x: ()) -> T { get {} set {} } } typealias Test20341012 = (title: (), action: () -> ()) struct T20341012 { private var options: ArrayLike { get {} set {} } // CHECK-LABEL: sil hidden @_T020property_abstraction9T20341012V1t{{[_0-9a-zA-Z]*}}F // CHECK: [[TMP1:%.*]] = alloc_stack $(title: (), action: @callee_owned (@in ()) -> @out ()) // CHECK: apply {{.*}}<(title: (), action: () -> ())>([[TMP1]], mutating func t() { _ = self.options[].title } } class MyClass {} // When simply assigning to a property, reabstract the r-value and assign // to the base instead of materializing and then assigning. protocol Factory { associatedtype Product var builder : () -> Product { get set } } func setBuilder(_ factory: inout F) { factory.builder = { return MyClass() } } // CHECK: sil hidden @_T020property_abstraction10setBuilder{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@inout F) -> () // CHECK: bb0(%0 : $*F): // CHECK: [[F0:%.*]] = function_ref @_T020property_abstraction10setBuilder{{[_0-9a-zA-Z]*}} : $@convention(thin) () -> @owned MyClass // CHECK: [[F1:%.*]] = thin_to_thick_function [[F0]] // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*F // CHECK: [[SETTER:%.*]] = witness_method $F, #Factory.builder!setter.1 // CHECK: [[REABSTRACTOR:%.*]] = function_ref @_T0{{.*}}TR : // CHECK: [[F2:%.*]] = partial_apply [[REABSTRACTOR]]([[F1]]) // CHECK: apply [[SETTER]]([[F2]], [[WRITE]])