| // RUN: %target-swift-emit-silgen %s | %FileCheck %s |
| |
| struct SimpleTest { |
| var stored: String |
| |
| var readable: String { |
| // CHECK-LABEL: sil hidden [ossa] @$s13read_accessor10SimpleTestV8readableSSvr |
| // CHECK-SAME: : $@yield_once @convention(method) (@guaranteed SimpleTest) -> @yields @guaranteed String { |
| // CHECK: [[T0:%.*]] = struct_extract %0 : $SimpleTest, #SimpleTest.stored |
| // CHECK-NEXT: yield [[T0]] : $String, resume bb1, unwind bb2 |
| // CHECK: bb1: |
| // CHECK-NEXT: [[RET:%.*]] = tuple () |
| // CHECK-NEXT: return [[RET]] : $() |
| // CHECK: bb2: |
| // CHECK-NEXT: unwind |
| _read { |
| yield stored |
| } |
| } |
| |
| // CHECK-LABEL: sil hidden [ossa] @$s13read_accessor10SimpleTestV3getSSyF |
| // CHECK: [[T0:%.*]] = begin_access [read] [unknown] %0 |
| // CHECK-NEXT: [[SELF:%.*]] = load [copy] [[T0]] : $*SimpleTest |
| // CHECK-NEXT: end_access [[T0]] |
| // CHECK-NEXT: [[SELF_BORROW:%.*]] = begin_borrow [[SELF]] |
| // CHECK-NEXT: // function_ref |
| // CHECK-NEXT: [[READFN:%.*]] = function_ref @$s13read_accessor10SimpleTestV8readableSSvr : $@yield_once @convention(method) (@guaranteed SimpleTest) -> @yields @guaranteed String |
| // CHECK-NEXT: ([[VALUE:%.*]], [[TOKEN:%.*]]) = begin_apply [[READFN]]([[SELF_BORROW]]) |
| // CHECK-NEXT: [[RET:%.*]] = copy_value [[VALUE]] : $String |
| // CHECK-NEXT: end_apply [[TOKEN]] |
| // CHECK-NEXT: end_borrow [[SELF_BORROW]] |
| // CHECK-NEXT: destroy_value [[SELF]] |
| // CHECK-NEXT: return [[RET]] : $String |
| mutating func get() -> String { |
| return readable |
| } |
| } |
| |
| class GetterSynthesis { |
| var stored: String = "hello" |
| var readable: String { |
| // CHECK-LABEL: sil hidden [transparent] [ossa] @$s13read_accessor15GetterSynthesisC8readableSSvg |
| // CHECK: [[READFN:%.*]] = function_ref @$s13read_accessor15GetterSynthesisC8readableSSvr |
| // CHECK-NEXT: ([[VALUE:%.*]], [[TOKEN:%.*]]) = begin_apply [[READFN]](%0) |
| // CHECK-NEXT: [[RET:%.*]] = copy_value [[VALUE]] : $String |
| // CHECK-NEXT: end_apply [[TOKEN]] |
| // CHECK-NEXT: return [[RET]] : $String |
| _read { |
| yield stored |
| } |
| } |
| } |
| |
| func void() {} |
| |
| struct TupleReader { |
| var stored: String |
| |
| subscript(i: Int) -> String { |
| _read { yield stored } |
| } |
| |
| func compute() -> String { return stored } |
| func index() -> Int { return 0 } |
| |
| var readable: ((String, ()), String, ()) { |
| // CHECK-LABEL: sil hidden [ossa] @$s13read_accessor11TupleReaderV8readableSS_ytt_SSyttvr |
| // CHECK: debug_value %0 |
| // CHECK-NEXT: // function_ref |
| // CHECK-NEXT: [[INDEXFN:%.*]] = function_ref @$s13read_accessor11TupleReaderV5indexSiyF |
| // CHECK-NEXT: [[INDEX:%.*]] = apply [[INDEXFN]](%0) |
| // CHECK-NEXT: // function_ref |
| // CHECK-NEXT: [[COMPUTEFN:%.*]] = function_ref @$s13read_accessor11TupleReaderV7computeSSyF |
| // CHECK-NEXT: [[COMPUTE:%.*]] = apply [[COMPUTEFN]](%0) |
| // CHECK-NEXT: // function_ref |
| // CHECK-NEXT: [[VOIDFN:%.*]] = function_ref @$s13read_accessor4voidyyF |
| // CHECK-NEXT: apply [[VOIDFN]]() |
| // CHECK-NEXT: // function_ref |
| // CHECK-NEXT: [[SUBREADFN:%.*]] = function_ref @$s13read_accessor11TupleReaderVySSSicir |
| // CHECK-NEXT: ([[SUBREAD:%.*]], [[SUBTOKEN:%.*]]) = begin_apply [[SUBREADFN]]([[INDEX]], %0) |
| // CHECK-NEXT: yield ([[SUBREAD]] : $String, [[COMPUTE]] : $String), resume bb1, unwind bb2 |
| // CHECK: bb1: |
| // CHECK-NEXT: end_apply [[SUBTOKEN]] |
| // CHECK-NEXT: destroy_value [[COMPUTE]] : $String |
| // CHECK-NEXT: [[T0:%.*]] = tuple () |
| // CHECK-NEXT: return [[T0]] : $() |
| // CHECK: bb2: |
| // Should this be an abort_apply? |
| // CHECK-NEXT: end_apply [[SUBTOKEN]] |
| // CHECK-NEXT: destroy_value [[COMPUTE]] : $String |
| // CHECK-NEXT: unwind |
| // CHECK-LABEL: } // end sil function '$s13read_accessor11TupleReaderV8readableSS_ytt_SSyttvr' |
| _read { |
| yield (((self[index()], ()), compute(), void())) |
| } |
| } |
| |
| // CHECK-LABEL: sil hidden [ossa] @$s13read_accessor11TupleReaderV11useReadableyyF |
| // CHECK: [[READFN:%.*]] = function_ref @$s13read_accessor11TupleReaderV8readableSS_ytt_SSyttvr |
| // CHECK-NEXT: ([[FIRST:%.*]], [[SECOND:%.*]], [[TOKEN:%.*]]) = begin_apply [[READFN]](%0) |
| // FIXME: this materialization is silly |
| // CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $((String, ()), String, ()) |
| // CHECK-NEXT: [[TEMP_0:%.*]] = tuple_element_addr [[TEMP]] : $*((String, ()), String, ()), 0 |
| // CHECK-NEXT: [[TEMP_1:%.*]] = tuple_element_addr [[TEMP]] : $*((String, ()), String, ()), 1 |
| // CHECK-NEXT: [[TEMP_2:%.*]] = tuple_element_addr [[TEMP]] : $*((String, ()), String, ()), 2 |
| // CHECK-NEXT: [[TEMP_0_0:%.*]] = tuple_element_addr [[TEMP_0]] : $*(String, ()), 0 |
| // CHECK-NEXT: [[TEMP_0_1:%.*]] = tuple_element_addr [[TEMP_0]] : $*(String, ()), 1 |
| // CHECK-NEXT: [[T0:%.*]] = copy_value [[FIRST]] : $String |
| // CHECK-NEXT: store [[T0]] to [init] [[TEMP_0_0]] |
| // CHECK-NEXT: [[T0:%.*]] = copy_value [[SECOND]] : $String |
| // CHECK-NEXT: store [[T0]] to [init] [[TEMP_1]] |
| // CHECK-NEXT: [[TUPLE:%.*]] = load [copy] [[TEMP]] |
| // CHECK-NEXT: destructure_tuple |
| // CHECK-NEXT: destructure_tuple |
| // CHECK-NEXT: end_apply |
| // CHECK-LABEL: } // end sil function '$s13read_accessor11TupleReaderV11useReadableyyF' |
| func useReadable() { |
| var v = readable |
| } |
| |
| var computed: String { |
| return compute() |
| } |
| |
| // CHECK-LABEL: sil hidden [ossa] @$s13read_accessor11TupleReaderV0A8ComputedSSvr |
| // CHECK: [[GETTER:%.*]] = function_ref @$s13read_accessor11TupleReaderV8computedSSvg |
| // CHECK-NEXT: [[VALUE:%.]] = apply [[GETTER]](%0) |
| // CHECK-NEXT: [[BORROW:%.*]] = begin_borrow [[VALUE]] : $String |
| // CHECK-NEXT: yield [[BORROW]] : $String, resume bb1 |
| // CHECK: bb1: |
| // CHECK-NEXT: end_borrow [[BORROW]] : $String |
| // CHECK-NEXT: destroy_value [[VALUE]] : $String |
| var readComputed : String { |
| _read { |
| yield computed |
| } |
| } |
| } |
| |
| struct TestKeyPath { |
| var readable: String { |
| _read { |
| yield "" |
| } |
| } |
| |
| func useKeyPath() -> String { |
| return self[keyPath: \.readable] |
| } |
| } |
| // Key-path getter for TestKeyPath.readable |
| // CHECK-LABEL: sil shared [thunk] [ossa] @$s13read_accessor11TestKeyPathV8readableSSvpACTK |
| // CHECK: bb0(%0 : $*String, %1 : $*TestKeyPath): |
| // CHECK-NEXT: [[SELF:%.*]] = load [trivial] %1 |
| // CHECK-NEXT: // function_ref |
| // CHECK-NEXT: [[READ:%.*]] = function_ref @$s13read_accessor11TestKeyPathV8readableSSvr |
| // CHECK-NEXT: ([[VALUE:%.*]], [[TOKEN:%.*]]) = begin_apply [[READ]]([[SELF]]) |
| // CHECK-NEXT: [[COPY:%.*]] = copy_value [[VALUE]] |
| // CHECK-NEXT: end_apply [[TOKEN]] |
| // CHECK-NEXT: store [[COPY]] to [init] %0 : $*String |
| // CHECK-NEXT: [[RET:%.*]] = tuple () |
| // CHECK-NEXT: return [[RET]] : $() |
| // CHECK-LABEL: } // end sil function '$s13read_accessor11TestKeyPathV8readableSSvpACTK' |
| |
| // Check that we emit a read coroutine but not a getter for this. |
| // This test assumes that we emit accessors in a particular order. |
| // CHECK-LABEL: sil [transparent] [ossa] @$s13read_accessor20TestBorrowedPropertyV14borrowedStringSSvpfi |
| // CHECK-NOT: sil [transparent] [serialized] [ossa] @$s13read_accessor20TestBorrowedPropertyV14borrowedStringSSvg |
| // CHECK: sil [transparent] [serialized] [ossa] @$s13read_accessor20TestBorrowedPropertyV14borrowedStringSSvr |
| // CHECK-NOT: sil [transparent] [serialized] [ossa] @$s13read_accessor20TestBorrowedPropertyV14borrowedStringSSvg |
| // CHECK-LABEL: sil [transparent] [serialized] [ossa] @$s13read_accessor20TestBorrowedPropertyV14borrowedStringSSvs |
| public struct TestBorrowedProperty { |
| @_borrowed |
| public var borrowedString = "" |
| } |
| |
| protocol ReadableTitle { |
| @_borrowed |
| var title: String { get } |
| } |
| class OverridableGetter : ReadableTitle { |
| var title: String = "" |
| } |
| // The concrete read accessor is generated on-demand and does a class dispatch to the getter. |
| // CHECK-LABEL: sil shared [ossa] @$s13read_accessor17OverridableGetterC5titleSSvr |
| // CHECK: class_method %0 : $OverridableGetter, #OverridableGetter.title!getter.1 |
| // CHECK-LABEL: // end sil function '$s13read_accessor17OverridableGetterC5titleSSvr' |
| // The read witness thunk does a direct call to the concrete read accessor. |
| // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s13read_accessor17OverridableGetterCAA13ReadableTitleA2aDP5titleSSvrTW |
| // CHECK: function_ref @$s13read_accessor17OverridableGetterC5titleSSvr |
| // CHECK-LABEL: // end sil function '$s13read_accessor17OverridableGetterCAA13ReadableTitleA2aDP5titleSSvrTW' |
| |
| protocol GettableTitle { |
| var title: String { get } |
| } |
| class OverridableReader : GettableTitle { |
| @_borrowed |
| var title: String = "" |
| } |
| // The concrete getter is generated on-demand and does a class dispatch to the read accessor. |
| // CHECK-LABEL: sil shared [ossa] @$s13read_accessor17OverridableReaderC5titleSSvg |
| // CHECK: class_method %0 : $OverridableReader, #OverridableReader.title!read.1 |
| // CHECK-LABEL: // end sil function '$s13read_accessor17OverridableReaderC5titleSSvg' |
| // The getter witness thunk does a direct call to the concrete getter. |
| // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s13read_accessor17OverridableReaderCAA13GettableTitleA2aDP5titleSSvgTW |
| // CHECK: function_ref @$s13read_accessor17OverridableReaderC5titleSSvg |
| // CHECK-LABEL: // end sil function '$s13read_accessor17OverridableReaderCAA13GettableTitleA2aDP5titleSSvgTW' |