// RUN: %target-swift-emit-silgen %s | %FileCheck %s

func readwrite(_ : inout String) {}

struct SimpleModify {
  var stored: String

  var modifiable: String {
    get {}
// CHECK-LABEL: sil hidden [ossa] @$s15modify_accessor12SimpleModifyV10modifiableSSvM
// CHECK-SAME:    : $@yield_once @convention(method) (@inout SimpleModify) -> @yields @inout String {
// CHECK:         [[SELF:%.*]] = begin_access [modify] [unknown] %0 : $*SimpleModify
// CHECK-NEXT:    [[FIELD:%.*]] = struct_element_addr [[SELF]] : $*SimpleModify, #SimpleModify.stored
// CHECK-NEXT:    yield [[FIELD]] : $*String, resume bb1, unwind bb2
// CHECK:       bb1:
// CHECK-NEXT:    end_access [[SELF]] : $*SimpleModify
// CHECK-NEXT:    [[RET:%.*]] = tuple ()
// CHECK-NEXT:    return [[RET]] : $()
// CHECK:       bb2:
// CHECK-NEXT:    end_access [[SELF]] : $*SimpleModify
// CHECK-NEXT:    unwind
    _modify {
      yield &stored
    }
  }

// CHECK-LABEL: sil hidden [ossa] @$s15modify_accessor12SimpleModifyV3set6stringySS_tF
// CHECK:         [[VALUE:%.*]] = copy_value %0 : $String
// CHECK-NEXT:    [[SELF:%.*]] = begin_access [modify] [unknown] %1 : $*SimpleModify
// CHECK-NEXT:    // function_ref
// CHECK-NEXT:    [[MODIFYFN:%.*]] = function_ref @$s15modify_accessor12SimpleModifyV10modifiableSSvM
// CHECK-NEXT:    ([[FIELD:%.*]], [[TOKEN:%.*]]) = begin_apply [[MODIFYFN]]([[SELF]])
// CHECK-NEXT:    assign [[VALUE]] to [[FIELD]] : $*String
// CHECK-NEXT:    end_apply [[TOKEN]]
// CHECK-NEXT:    end_access [[SELF]] : $*SimpleModify
// CHECK-NEXT:    [[RET:%.*]] = tuple ()
// CHECK-NEXT:    return [[RET]] : $()
mutating func set(string: String) {
    modifiable = string
  }

// CHECK-LABEL: sil hidden [ossa] @$s15modify_accessor12SimpleModifyV0A0yyF
// CHECK:         [[SELF:%.*]] = begin_access [modify] [unknown] %0 : $*SimpleModify
// CHECK-NEXT:    // function_ref
// CHECK-NEXT:    [[MODIFYFN:%.*]] = function_ref @$s15modify_accessor12SimpleModifyV10modifiableSSvM
// CHECK-NEXT:    ([[FIELD:%.*]], [[TOKEN:%.*]]) = begin_apply [[MODIFYFN]]([[SELF]])
// CHECK-NEXT:    // function_ref
// CHECK-NEXT:    [[READWRITE:%.*]] = function_ref @$s15modify_accessor9readwriteyySSzF
// CHECK-NEXT:    apply [[READWRITE]]([[FIELD]])
// CHECK-NEXT:    end_apply [[TOKEN]]
// CHECK-NEXT:    end_access [[SELF]] : $*SimpleModify
// CHECK-NEXT:    [[RET:%.*]] = tuple ()
// CHECK-NEXT:    return [[RET]] : $()
  mutating func modify() {
    readwrite(&modifiable)
  }
}

class SetterSynthesisFromModify {
  var stored: String = "test"
  var modifiable: String {
    get { return stored }
// CHECK: sil hidden [transparent] [ossa] @$s15modify_accessor25SetterSynthesisFromModifyC10modifiableSSvs
// CHECK:         [[VALUE_BORROW:%.*]] = begin_borrow [lexical] %0 : $String
// CHECK-NEXT:    debug_value
// CHECK-NEXT:    debug_value
// CHECK-NEXT:    [[VALUE:%.*]] = copy_value [[VALUE_BORROW]] : $String
// CHECK-NEXT:    // function_ref
// CHECK-NEXT:    [[MODIFYFN:%.*]] = function_ref @$s15modify_accessor25SetterSynthesisFromModifyC10modifiableSSvM
// CHECK-NEXT:    ([[FIELD:%.*]], [[TOKEN:%.*]]) = begin_apply [[MODIFYFN]](%1)
// CHECK-NEXT:    assign [[VALUE]] to [[FIELD]] : $*String
// CHECK-NEXT:    end_apply [[TOKEN]]
// CHECK-NEXT:    end_borrow [[VALUE_BORROW]]
// CHECK-NEXT:    destroy_value %0 : $String
// CHECK-NEXT:    [[RET:%.*]] = tuple ()
// CHECK-NEXT:    return [[RET]] : $()
    _modify {
      yield &stored
    }
  }
}

struct ModifyAndSet {
  var stored: String

  var modifiable: String {
    get { return stored }
    _modify { yield &stored }
    set(value) { stored = value }
  }

// CHECK-LABEL: sil hidden [ossa] @$s15modify_accessor12ModifyAndSetV3set6stringySS_tF
// CHECK:         [[VALUE:%.*]] = copy_value %0 : $String
// CHECK-NEXT:    [[SELF:%.*]] = begin_access [modify] [unknown] %1 : $*ModifyAndSet
// CHECK-NEXT:    // function_ref
// CHECK-NEXT:    [[SETTERFN:%.*]] = function_ref @$s15modify_accessor12ModifyAndSetV10modifiableSSvs
// CHECK-NEXT:    apply [[SETTERFN]]([[VALUE]], [[SELF]])
// CHECK-NEXT:    end_access [[SELF]] : $*ModifyAndSet
// CHECK-NEXT:    [[RET:%.*]] = tuple ()
// CHECK-NEXT:    return [[RET]] : $()
  mutating func set(string: String) {
    modifiable = string
  }

  // CHECK-LABEL: sil hidden [ossa] @$s15modify_accessor12ModifyAndSetV0A0yyF
  // CHECK:         [[SELF:%.*]] = begin_access [modify] [unknown] %0 : $*ModifyAndSet
  // CHECK-NEXT:    // function_ref
  // CHECK-NEXT:    [[MODIFYFN:%.*]] = function_ref @$s15modify_accessor12ModifyAndSetV10modifiableSSvM
  // CHECK-NEXT:    ([[FIELD:%.*]], [[TOKEN:%.*]]) = begin_apply [[MODIFYFN]]([[SELF]])
  // CHECK-NEXT:    // function_ref
  // CHECK-NEXT:    [[READWRITE:%.*]] = function_ref @$s15modify_accessor9readwriteyySSzF
  // CHECK-NEXT:    apply [[READWRITE]]([[FIELD]])
  // CHECK-NEXT:    end_apply [[TOKEN]]
  // CHECK-NEXT:    end_access [[SELF]] : $*ModifyAndSet
  // CHECK-NEXT:    [[RET:%.*]] = tuple ()
  // CHECK-NEXT:    return [[RET]] : $()
  mutating func modify() {
    readwrite(&modifiable)
  }
}
