// RUN: %target-typecheck-verify-swift

func markUsed<T>(_ t: T) {}

struct X { }
var _x: X

class SomeClass {}

func takeTrailingClosure(_ fn: () -> ()) -> Int {}
func takeIntTrailingClosure(_ fn: () -> Int) -> Int {}

//===---
// Stored properties
//===---

var stored_prop_1: Int = 0

var stored_prop_2: Int = takeTrailingClosure {}

//===---
// Computed properties -- basic parsing
//===---

var a1: X {
  get {
    return _x
  }
}

var a2: X {
  get {
    return _x
  }
  set {
    _x = newValue
  }
}

var a3: X {
  get {
    return _x
  }
  set(newValue) {
    _x = newValue
  }
}

var a4: X {
  set {
    _x = newValue
  }
  get {
    return _x
  }
}

var a5: X {
  set(newValue) {
    _x = newValue
  }
  get {
    return _x
  }
}

// Reading/writing properties
func accept_x(_ x: X) { }
func accept_x_inout(_ x: inout X) { }

func test_global_properties(_ x: X) {
  accept_x(a1)
  accept_x(a2)
  accept_x(a3)
  accept_x(a4)
  accept_x(a5)

  a1 = x // expected-error {{cannot assign to value: 'a1' is a get-only property}}
  a2 = x
  a3 = x
  a4 = x
  a5 = x

  accept_x_inout(&a1) // expected-error {{cannot pass immutable value as inout argument: 'a1' is a get-only property}}
  accept_x_inout(&a2)
  accept_x_inout(&a3)
  accept_x_inout(&a4)
  accept_x_inout(&a5)
}

//===--- Implicit 'get'.

var implicitGet1: X {
  return _x
}

var implicitGet2: Int {
  var zzz = 0
  // For the purpose of this test, any other function attribute work as well.
  @inline(__always)
  func foo() {}
  return 0
}

var implicitGet3: Int {
  @inline(__always)
  func foo() {}
  return 0
}

// Here we used apply weak to the getter itself, not to the variable.
var x15: Int {
  // For the purpose of this test we need to use an attribute that cannot be
  // applied to the getter.
  weak
  var foo: SomeClass? = SomeClass()  // expected-warning {{variable 'foo' was written to, but never read}}
  // expected-warning@-1 {{instance will be immediately deallocated because variable 'foo' is 'weak'}}
  // expected-note@-2 {{a strong reference is required to prevent the instance from being deallocated}}
  // expected-note@-3 {{'foo' declared here}}
  return 0
}


// Disambiguated as stored property with a trailing closure in the initializer.
//
var disambiguateGetSet1a: Int = 0 { // expected-error {{variable with getter/setter cannot have an initial value}}
  get {}
}
var disambiguateGetSet1b: Int = 0 { // expected-error {{variable with getter/setter cannot have an initial value}}
  get {
    return 42
  }
}
var disambiguateGetSet1c: Int = 0 { // expected-error {{variable with getter/setter cannot have an initial value}}
  set {} // expected-error {{variable with a setter must also have a getter}}
}
var disambiguateGetSet1d: Int = 0 { // expected-error {{variable with getter/setter cannot have an initial value}}
  set(newValue) {} // expected-error {{variable with a setter must also have a getter}}
}

// Disambiguated as stored property with a trailing closure in the initializer.
func disambiguateGetSet2() {
  func get(_ fn: () -> ()) {}
  var a: Int = takeTrailingClosure {
    get {}
  }
  // Check that the property is read-write.
  a = a + 42
}
func disambiguateGetSet2Attr() {
  func get(_ fn: () -> ()) {}
  var a: Int = takeTrailingClosure {
    @inline(__always)
    func foo() {}
    get {}
  }
  // Check that the property is read-write.
  a = a + 42
}

// Disambiguated as stored property with a trailing closure in the initializer.
func disambiguateGetSet3() {
  func set(_ fn: () -> ()) {}
  var a: Int = takeTrailingClosure {
    set {}
  }
  // Check that the property is read-write.
  a = a + 42
}
func disambiguateGetSet3Attr() {
  func set(_ fn: () -> ()) {}
  var a: Int = takeTrailingClosure {
    @inline(__always)
    func foo() {}
    set {}
  }
  // Check that the property is read-write.
  a = a + 42
}

// Disambiguated as stored property with a trailing closure in the initializer.
func disambiguateGetSet4() {
  func set(_ x: Int, fn: () -> ()) {}
  let newValue: Int = 0
  var a: Int = takeTrailingClosure {
    set(newValue) {}
  }
  // Check that the property is read-write.
  a = a + 42
}
func disambiguateGetSet4Attr() {
  func set(_ x: Int, fn: () -> ()) {}
  var newValue: Int = 0
  var a: Int = takeTrailingClosure {
    @inline(__always)
    func foo() {}
    set(newValue) {}
  }
  // Check that the property is read-write.
  a = a + 42
}

// Disambiguated as stored property with a trailing closure in the initializer.
var disambiguateImplicitGet1: Int = 0 { // expected-error {{variable with getter/setter cannot have an initial value}}
  return 42
}
var disambiguateImplicitGet2: Int = takeIntTrailingClosure {
  return 42
}


//===---
// Observed properties
//===---

class C {
  var prop1 = 42 {
    didSet { }
  }
  var prop2 = false {
    willSet { }
  }
  var prop3: Int? = nil {
    didSet { }
  }
  var prop4: Bool? = nil {
    willSet { }
  }
}

protocol TrivialInit {
  init()
}

class CT<T : TrivialInit> {
  var prop1 = 42 {
    didSet { }
  }
  var prop2 = false {
    willSet { }
  }
  var prop3: Int? = nil {
    didSet { }
  }
  var prop4: Bool? = nil {
    willSet { }
  }
  var prop5: T? = nil {
    didSet { }
  }
  var prop6: T? = nil {
    willSet { }
  }
  var prop7 = T() {
    didSet { }
  }
  var prop8 = T() {
    willSet { }
  }
}

//===---
// Parsing problems
//===---

var computed_prop_with_init_1: X {
  get {}
} = X()  // expected-error {{expected expression}} expected-error {{consecutive statements on a line must be separated by ';'}} {{2-2=;}}

var x2 { // expected-error{{computed property must have an explicit type}} {{7-7=: <# Type #>}} expected-error{{type annotation missing in pattern}}
  get {
    return _x
  }
}

var (x3): X { // expected-error{{getter/setter can only be defined for a single variable}}
  get {
    return _x
  }
}

var duplicateAccessors1: X {
  get { // expected-note {{previous definition of getter here}}
    return _x
  }
  set { // expected-note {{previous definition of setter here}}
    _x = newValue
  }
  get { // expected-error {{variable already has a getter}}
    return _x
  }
  set(v) { // expected-error {{variable already has a setter}}
    _x = v
  }
}

var duplicateAccessors2: Int = 0 {
  willSet { // expected-note {{previous definition of 'willSet' here}}
  }
  didSet { // expected-note {{previous definition of 'didSet' here}}
  }
  willSet { // expected-error {{variable already has 'willSet'}}
  }
  didSet { // expected-error {{variable already has 'didSet'}}
  }
}

var extraTokensInAccessorBlock1: X {
  get {}
  a // expected-error {{expected 'get', 'set', 'willSet', or 'didSet' keyword to start an accessor definition}}
}
var extraTokensInAccessorBlock2: X {
  get {}
  weak // expected-error {{expected 'get', 'set', 'willSet', or 'didSet' keyword to start an accessor definition}}
  a
}
var extraTokensInAccessorBlock3: X {
  get {}
  a = b // expected-error {{expected 'get', 'set', 'willSet', or 'didSet' keyword to start an accessor definition}}
  set {}
  get {}
}

var extraTokensInAccessorBlock4: X {
  get blah wibble // expected-error{{expected '{' to start getter definition}}
}
var extraTokensInAccessorBlock5: X {
  set blah wibble // expected-error{{expected '{' to start setter definition}}
}
var extraTokensInAccessorBlock6: X { // expected-error{{non-member observing properties require an initializer}}
  willSet blah wibble // expected-error{{expected '{' to start 'willSet' definition}}
}
var extraTokensInAccessorBlock7: X { // expected-error{{non-member observing properties require an initializer}}
  didSet blah wibble // expected-error{{expected '{' to start 'didSet' definition}}
}

var extraTokensInAccessorBlock8: X {
  foo // expected-error {{use of unresolved identifier 'foo'}}
  get {} // expected-error{{use of unresolved identifier 'get'}}
  set {} // expected-error{{use of unresolved identifier 'set'}}
}

var extraTokensInAccessorBlock9: Int {
  get // expected-error {{expected '{' to start getter definition}}
    var a = b
}

struct extraTokensInAccessorBlock10 {
  var x: Int {
    get // expected-error {{expected '{' to start getter definition}}
      var a = b
  }

  init() {}
}

var x9: X {
  get ( ) { // expected-error{{expected '{' to start getter definition}}
  }
}

var x10: X {
  set ( : ) { // expected-error{{expected setter parameter name}}
  }
  get {}
}

var x11 : X {
  set { // expected-error{{variable with a setter must also have a getter}}
  }
}

var x12: X {
  set(newValue %) { // expected-error {{expected ')' after setter parameter name}} expected-note {{to match this opening '('}}
  // expected-error@-1 {{expected '{' to start setter definition}}
  }
}

var x13: X {} // expected-error {{computed property must have accessors specified}}

// Type checking problems
struct Y { }
var y: Y
var x20: X {
  get {
    return y // expected-error{{cannot convert return expression of type 'Y' to return type 'X'}}
  }
  set {
    y = newValue // expected-error{{cannot assign value of type 'X' to type 'Y'}}
  }
}

var x21: X {
  get {
    return y // expected-error{{cannot convert return expression of type 'Y' to return type 'X'}}
  }
  set(v) {
    y = v // expected-error{{cannot assign value of type 'X' to type 'Y'}}
  }
}

var x23: Int, x24: Int { // expected-error{{'var' declarations with multiple variables cannot have explicit getters/setters}}
  return 42
}

var x25: Int { // expected-error{{'var' declarations with multiple variables cannot have explicit getters/setters}}
  return 42
}, x26: Int

// Properties of struct/enum/extensions
struct S {
  var _backed_x: X, _backed_x2: X
  var x: X {
    get {
      return _backed_x
    }
    mutating
    set(v) {
      _backed_x = v
    }
  }
}

extension S {
  var x2: X {
    get {
      return self._backed_x2
    }
    mutating
    set {
      _backed_x2 = newValue
    }
  }

  var x3: X {
    get {
      return self._backed_x2
    }
  }
}

struct StructWithExtension1 {
  var foo: Int
  static var fooStatic = 4
}
extension StructWithExtension1 {
  var fooExt: Int // expected-error {{extensions must not contain stored properties}}
  static var fooExtStatic = 4
}

class ClassWithExtension1 {
  var foo: Int = 0
  class var fooStatic = 4 // expected-error {{class stored properties not supported in classes; did you mean 'static'?}}
}
extension ClassWithExtension1 {
  var fooExt: Int // expected-error {{extensions must not contain stored properties}}
  class var fooExtStatic = 4 // expected-error {{class stored properties not supported in classes; did you mean 'static'?}}
}

enum EnumWithExtension1 {
  var foo: Int // expected-error {{enums must not contain stored properties}}
  static var fooStatic  = 4
}
extension EnumWithExtension1 {
  var fooExt: Int // expected-error {{extensions must not contain stored properties}}
  static var fooExtStatic = 4
}

protocol ProtocolWithExtension1 {
  var foo: Int { get }
  static var fooStatic : Int { get }
}
extension ProtocolWithExtension1 {
  var fooExt: Int // expected-error{{extensions must not contain stored properties}}
  static var fooExtStatic = 4 // expected-error{{static stored properties not supported in protocol extensions}}
}

protocol ProtocolWithExtension2 {
  var bar: String { get }
}

struct StructureImplementingProtocolWithExtension2: ProtocolWithExtension2 {
  let bar: String
}

extension ProtocolWithExtension2 {
  static let baz: ProtocolWithExtension2 = StructureImplementingProtocolWithExtension2(bar: "baz") // expected-error{{static stored properties not supported in protocol extensions}}
}

func getS() -> S {
  let s: S
  return s
}

func test_extension_properties(_ s: inout S, x: inout X) {
  accept_x(s.x)
  accept_x(s.x2)
  accept_x(s.x3)

  accept_x(getS().x)
  accept_x(getS().x2)
  accept_x(getS().x3)

  s.x = x
  s.x2 = x
  s.x3 = x // expected-error{{cannot assign to property: 'x3' is a get-only property}}

  getS().x = x // expected-error{{cannot assign to property: 'getS' returns immutable value}}
  getS().x2 = x // expected-error{{cannot assign to property: 'getS' returns immutable value}}
  getS().x3 = x // expected-error{{cannot assign to property: 'x3' is a get-only property}}

  accept_x_inout(&getS().x) // expected-error{{cannot pass immutable value as inout argument: 'getS' returns immutable value}}
  accept_x_inout(&getS().x2) // expected-error{{cannot pass immutable value as inout argument: 'getS' returns immutable value}}
  accept_x_inout(&getS().x3) // expected-error{{cannot pass immutable value as inout argument: 'x3' is a get-only property}}

  x = getS().x
  x = getS().x2
  x = getS().x3

  accept_x_inout(&s.x)
  accept_x_inout(&s.x2)
  accept_x_inout(&s.x3) // expected-error{{cannot pass immutable value as inout argument: 'x3' is a get-only property}}
}

extension S {
  mutating
  func test(other_x: inout X) {
    x = other_x
    x2 = other_x
    x3 = other_x // expected-error{{cannot assign to property: 'x3' is a get-only property}}

    other_x = x
    other_x = x2
    other_x = x3
  }
}

// Accessor on non-settable type

struct Aleph {
  var b: Beth {
    get {
      return Beth(c: 1)
    }
  }
}

struct Beth {
  var c: Int
}

func accept_int_inout(_ c: inout Int) { }
func accept_int(_ c: Int) { }

func test_settable_of_nonsettable(_ a: Aleph) {
  a.b.c = 1 // expected-error{{cannot assign}}
  let x:Int = a.b.c
  _ = x

  accept_int(a.b.c)
  accept_int_inout(&a.b.c) // expected-error {{cannot pass immutable value as inout argument: 'b' is a get-only property}}
}

// TODO: Static properties are only implemented for nongeneric structs yet.

struct MonoStruct {
  static var foo: Int = 0
  static var (bar, bas): (String, UnicodeScalar) = ("zero", "0")

  static var zim: UInt8 {
    return 0
  }

  static var zang = UnicodeScalar("\0")

  static var zung: UInt16 {
    get {
      return 0
    }
    set {}
  }

  var a: Double
  var b: Double
}

struct MonoStructOneProperty {
  static var foo: Int = 22
}

enum MonoEnum {
  static var foo: Int = 0

  static var zim: UInt8 {
    return 0
  }
}

struct GenStruct<T> {
  static var foo: Int = 0 // expected-error{{static stored properties not supported in generic types}}
}

class MonoClass {
  class var foo: Int = 0 // expected-error{{class stored properties not supported in classes; did you mean 'static'?}}
}

protocol Proto {
  static var foo: Int { get }
}

func staticPropRefs() -> (Int, Int, String, UnicodeScalar, UInt8) {
  return (MonoStruct.foo, MonoEnum.foo, MonoStruct.bar, MonoStruct.bas,
          MonoStruct.zim)
}

func staticPropRefThroughInstance(_ foo: MonoStruct) -> Int {
  return foo.foo //expected-error{{static member 'foo' cannot be used on instance of type 'MonoStruct'}}
}

func memberwiseInitOnlyTakesInstanceVars() -> MonoStruct {
  return MonoStruct(a: 1.2, b: 3.4)
}

func getSetStaticProperties() -> (UInt8, UInt16) {
  MonoStruct.zim = 12 // expected-error{{cannot assign}}
  MonoStruct.zung = 34

  return (MonoStruct.zim, MonoStruct.zung)
}


var selfRefTopLevel: Int {
  return selfRefTopLevel // expected-warning {{attempting to access 'selfRefTopLevel' within its own getter}}
}
var selfRefTopLevelSetter: Int {
  get {
    return 42
  }
  set {
    markUsed(selfRefTopLevelSetter) // no-warning
    selfRefTopLevelSetter = newValue // expected-warning {{attempting to modify 'selfRefTopLevelSetter' within its own setter}}
  }
}
var selfRefTopLevelSilenced: Int {
  get {
    return properties.selfRefTopLevelSilenced // no-warning
  }
  set {
    properties.selfRefTopLevelSilenced = newValue // no-warning
  }
}

class SelfRefProperties {
  var getter: Int {
    return getter // expected-warning {{attempting to access 'getter' within its own getter}}
    // expected-note@-1 {{access 'self' explicitly to silence this warning}} {{12-12=self.}}
  }
  var setter: Int {
    get {
      return 42
    }
    set {
      markUsed(setter) // no-warning
      var unused = setter + setter // expected-warning {{initialization of variable 'unused' was never used; consider replacing with assignment to '_' or removing it}} {{7-17=_}}
      setter = newValue // expected-warning {{attempting to modify 'setter' within its own setter}}
      // expected-note@-1 {{access 'self' explicitly to silence this warning}} {{7-7=self.}}
    }
  }
  var silenced: Int {
    get {
      return self.silenced // no-warning
    }
    set {
      self.silenced = newValue // no-warning
    }
  }

  var someOtherInstance: SelfRefProperties = SelfRefProperties()
  var delegatingVar: Int {
    // This particular example causes infinite access, but it's easily possible
    // for the delegating instance to do something else.
    return someOtherInstance.delegatingVar // no-warning
  }
}

func selfRefLocal() {
  var getter: Int {
    return getter // expected-warning {{attempting to access 'getter' within its own getter}}
  }
  var setter: Int {
    get {
      return 42
    }
    set {
      markUsed(setter) // no-warning
      setter = newValue // expected-warning {{attempting to modify 'setter' within its own setter}}
    }
  }
}


struct WillSetDidSetProperties {
  var a: Int {
    willSet {
      markUsed("almost")
    }
    didSet {
      markUsed("here")
    }
  }

  var b: Int {
    willSet {
      markUsed(b)
      markUsed(newValue)
    }
  }

  var c: Int {
    willSet(newC) {
      markUsed(c)
      markUsed(newC)
    }
  }

  var d: Int {
    didSet { // expected-error {{'didSet' cannot be provided together with a getter}}
      markUsed("woot")
    }
    get {
      return 4
    }
  }

  var e: Int {
    willSet { // expected-error {{'willSet' cannot be provided together with a setter}}
      markUsed("woot")
    }
    set { // expected-error {{variable with a setter must also have a getter}}
      return 4 // expected-error {{unexpected non-void return value in void function}}
    }
  }

  var f: Int {
    willSet(5) {} // expected-error {{expected willSet parameter name}}
    didSet(^) {} // expected-error {{expected didSet parameter name}}
  }

  var g: Int {
    willSet(newValue 5) {} // expected-error {{expected ')' after willSet parameter name}} expected-note {{to match this opening '('}}
    // expected-error@-1 {{expected '{' to start 'willSet' definition}}
  }
  var h: Int {
    didSet(oldValue ^) {} // expected-error {{expected ')' after didSet parameter name}} expected-note {{to match this opening '('}}
    // expected-error@-1 {{expected '{' to start 'didSet' definition}}
  }

  // didSet/willSet with initializers.
  // Disambiguate trailing closures.
  var disambiguate1: Int = 42 {   // simple initializer, simple label
    didSet {
      markUsed("eek")
    }
  }

  var disambiguate2: Int = 42 {    // simple initializer, complex label
    willSet(v) {
      markUsed("eek")
    }
  }

  var disambiguate3: Int = takeTrailingClosure {} {  // Trailing closure case.
    willSet(v) {
      markUsed("eek")
    }
  }

  var disambiguate4: Int = 42 {
    willSet {}
  }

  var disambiguate5: Int = 42 {
    didSet {}
  }

  var disambiguate6: Int = takeTrailingClosure {
    @inline(__always)
    func f() {}
    return ()
  }

  var inferred1 = 42 {
    willSet {
      markUsed("almost")
    }
    didSet {
      markUsed("here")
    }
  }

  var inferred2 = 40 {
    willSet {
      markUsed(b)
      markUsed(newValue)
    }
  }

  var inferred3 = 50 {
    willSet(newC) {
      markUsed(c)
      markUsed(newC)
    }
  }
}

// Disambiguated as accessor.
struct WillSetDidSetDisambiguate1 {
  var willSet: Int
  var x: (() -> ()) -> Int = takeTrailingClosure {
    willSet = 42 // expected-error {{expected '{' to start 'willSet' definition}}
  }
}
struct WillSetDidSetDisambiguate1Attr {
  var willSet: Int
  var x: (() -> ()) -> Int = takeTrailingClosure {
    willSet = 42 // expected-error {{expected '{' to start 'willSet' definition}}
  }
}

// Disambiguated as accessor.
struct WillSetDidSetDisambiguate2 {
  func willSet(_: () -> Int) {}
  var x: (() -> ()) -> Int = takeTrailingClosure {
    willSet {}
  }
}
struct WillSetDidSetDisambiguate2Attr {
  func willSet(_: () -> Int) {}
  var x: (() -> ()) -> Int = takeTrailingClosure {
    willSet {}
  }
}

// No need to disambiguate -- this is clearly a function call.
func willSet(_: () -> Int) {}
struct WillSetDidSetDisambiguate3 {
  var x: Int = takeTrailingClosure({
    willSet { 42 }
  })
}

protocol ProtocolGetSet1 {
  var a: Int // expected-error {{property in protocol must have explicit { get } or { get set } specifier}} {{13-13= { get <#set#> \}}}
}
protocol ProtocolGetSet2 {
  var a: Int {} // expected-error {{property in protocol must have explicit { get } or { get set } specifier}} {{14-16={ get <#set#> \}}}
}
protocol ProtocolGetSet3 {
  var a: Int { get }
}
protocol ProtocolGetSet4 {
  var a: Int { set } // expected-error {{variable with a setter must also have a getter}}
}
protocol ProtocolGetSet5 {
  var a: Int { get set }
}
protocol ProtocolGetSet6 {
  var a: Int { set get }
}

protocol ProtocolWillSetDidSet1 {
  var a: Int { willSet } // expected-error {{property in protocol must have explicit { get } or { get set } specifier}} {{14-25={ get <#set#> \}}} expected-error {{expected get or set in a protocol property}}
}
protocol ProtocolWillSetDidSet2 {
  var a: Int { didSet } // expected-error {{property in protocol must have explicit { get } or { get set } specifier}} {{14-24={ get <#set#> \}}} expected-error {{expected get or set in a protocol property}}
}
protocol ProtocolWillSetDidSet3 {
  var a: Int { willSet didSet } // expected-error {{property in protocol must have explicit { get } or { get set } specifier}} {{14-32={ get <#set#> \}}} expected-error 2 {{expected get or set in a protocol property}}

}
protocol ProtocolWillSetDidSet4 {
  var a: Int { didSet willSet } // expected-error {{property in protocol must have explicit { get } or { get set } specifier}} {{14-32={ get <#set#> \}}} expected-error 2 {{expected get or set in a protocol property}}
}
protocol ProtocolWillSetDidSet5 {
  let a: Int { didSet willSet }  // expected-error {{immutable property requirement must be declared as 'var' with a '{ get }' specifier}} {{3-6=var}} {{13-13= { get \}}} {{none}} expected-error 2 {{expected get or set in a protocol property}} expected-error {{'let' declarations cannot be computed properties}} {{3-6=var}}
}

var globalDidsetWillSet: Int {  // expected-error {{non-member observing properties require an initializer}}
  didSet {}
}
var globalDidsetWillSet2 : Int = 42 {
  didSet {}
}


class Box {
  var num: Int

  init(num: Int) {
    self.num = num
  }
}

func double(_ val: inout Int) {
  val *= 2
}

class ObservingPropertiesNotMutableInWillSet {
  var anotherObj : ObservingPropertiesNotMutableInWillSet
  
  init() {}
  var property: Int = 42 {
    willSet {
      // <rdar://problem/16826319> willSet immutability behavior is incorrect
      anotherObj.property = 19 // ok
      property = 19  // expected-warning {{attempting to store to property 'property' within its own willSet}}
      double(&property)  // expected-warning {{attempting to store to property 'property' within its own willSet}}
      double(&self.property)  // no-warning
    }
  }

  // <rdar://problem/21392221> - call to getter through BindOptionalExpr was not viewed as a load
  var _oldBox : Int
  weak var weakProperty: Box? {
    willSet {
      _oldBox = weakProperty?.num ?? -1
    }
  }

  func localCase() {
    var localProperty: Int = 42 {
      willSet {
        localProperty = 19   // expected-warning {{attempting to store to property 'localProperty' within its own willSet}}
      }
    }
  }
}

func doLater(_ fn : () -> ()) {}

// rdar://<rdar://problem/16264989> property not mutable in closure inside of its willSet
class MutableInWillSetInClosureClass {
    var bounds: Int = 0 {
    willSet {
        let oldBounds = bounds
        doLater { self.bounds = oldBounds }
    }
    }
}


// <rdar://problem/16191398> add an 'oldValue' to didSet so you can implement "didChange" properties
var didSetPropertyTakingOldValue : Int = 0 {
  didSet(oldValue) {
    markUsed(oldValue)
    markUsed(didSetPropertyTakingOldValue)
  }
}



// rdar://16280138 - synthesized getter is defined in terms of archetypes, not interface types
protocol AbstractPropertyProtocol {
  associatedtype Index
  var a : Index { get }
}
struct AbstractPropertyStruct<T> : AbstractPropertyProtocol {
  typealias Index = T
  var a : T
}

// Allow _silgen_name accessors without bodies.
var _silgen_nameGet1: Int {
  @_silgen_name("get1") get
  set { }
}

var _silgen_nameGet2: Int {
  set { }
  @_silgen_name("get2") get
}

var _silgen_nameGet3: Int {
  @_silgen_name("get3") get
}

var _silgen_nameGetSet: Int {
  @_silgen_name("get4") get
  @_silgen_name("set4") set
}



// <rdar://problem/16375910> reject observing properties overriding readonly properties
class Base16375910 {
  var x : Int {   // expected-note {{attempt to override property here}}
    return 42
  }
  
  var y : Int {          // expected-note {{attempt to override property here}}
    get { return 4 }
    set {}
  }
}

class Derived16375910 : Base16375910 {
  override init() {}
  override var x : Int { // expected-error {{cannot observe read-only property 'x'; it can't change}}
    willSet {
      markUsed(newValue)
    }
  }
}

// <rdar://problem/16382967> Observing properties have no storage, so shouldn't prevent initializer synth
class Derived16382967 : Base16375910 {
  override var y : Int {
    willSet {
      markUsed(newValue)
    }
  }
}

// <rdar://problem/16659058> Read-write properties can be made read-only in a property override
class Derived16659058 : Base16375910 {
  override var y : Int {  // expected-error {{cannot override mutable property with read-only property 'y'}}
    get { return 42 }
  }
}



// <rdar://problem/16406886> Observing properties don't work with ownership types
struct PropertiesWithOwnershipTypes {
  unowned var p1 : SomeClass {
    didSet {
    }
  }

  init(res: SomeClass) {
    p1 = res
  }
}


// <rdar://problem/16608609> Assert (and incorrect error message) when defining a constant stored property with observers
class Test16608609 {
   let constantStored: Int = 0 {  // expected-error {{'let' declarations cannot be observing properties}} {{4-7=var}}
      willSet {
      }
      didSet {
      }
   }
}

// <rdar://problem/16941124> Overriding property observers warn about using the property value "within its own getter"
class rdar16941124Base {
   var x = 0
}
class rdar16941124Derived : rdar16941124Base {
   var y = 0
   override var x: Int {
      didSet {
         y = x + 1  // no warning.
      }
   }
}


// Overrides of properties with custom ownership.
class OwnershipBase {
  class var defaultObject: AnyObject { fatalError("") }

  var strongVar: AnyObject? // expected-note{{overridden declaration is here}}
  weak var weakVar: AnyObject? // expected-note{{overridden declaration is here}}

  // FIXME: These should be optional to properly test overriding.
  unowned var unownedVar: AnyObject = defaultObject
  unowned var optUnownedVar: AnyObject? = defaultObject
  unowned(unsafe) var unownedUnsafeVar: AnyObject = defaultObject // expected-note{{overridden declaration is here}}
  unowned(unsafe) var optUnownedUnsafeVar: AnyObject? = defaultObject
}

class OwnershipExplicitSub : OwnershipBase {
  override var strongVar: AnyObject? {
    didSet {}
  }
  override weak var weakVar: AnyObject? {
    didSet {}
  }
  override unowned var unownedVar: AnyObject {
    didSet {}
  }
  override unowned var optUnownedVar: AnyObject? {
    didSet {}
  }
  override unowned(unsafe) var unownedUnsafeVar: AnyObject {
    didSet {}
  }
  override unowned(unsafe) var optUnownedUnsafeVar: AnyObject? {
    didSet {}
  }
}

class OwnershipImplicitSub : OwnershipBase {
  override var strongVar: AnyObject? {
    didSet {}
  }
  override weak var weakVar: AnyObject? {
    didSet {}
  }
  override unowned var unownedVar: AnyObject {
    didSet {}
  }
  override unowned var optUnownedVar: AnyObject? {
    didSet {}
  }
  override unowned(unsafe) var unownedUnsafeVar: AnyObject {
    didSet {}
  }
  override unowned(unsafe) var optUnownedUnsafeVar: AnyObject? {
    didSet {}
  }
}

class OwnershipBadSub : OwnershipBase {
  override weak var strongVar: AnyObject? { // expected-error {{cannot override 'strong' property with 'weak' property}}
    didSet {}
  }
  override unowned var weakVar: AnyObject? { // expected-error {{cannot override 'weak' property with 'unowned' property}}
    didSet {}
  }
  override weak var unownedVar: AnyObject { // expected-error {{'weak' variable should have optional type 'AnyObject?'}}
    didSet {}
  }
  override unowned var unownedUnsafeVar: AnyObject { // expected-error {{cannot override 'unowned(unsafe)' property with 'unowned' property}}
    didSet {}
  }
}



// <rdar://problem/17391625> Swift Compiler Crashes when Declaring a Variable and didSet in an Extension
class rdar17391625 {
  var prop = 42  // expected-note {{overri}}
}

extension rdar17391625 {
  var someStoredVar: Int       // expected-error {{extensions must not contain stored properties}}
  var someObservedVar: Int {   // expected-error {{extensions must not contain stored properties}}
  didSet {
  }
  }
}

class rdar17391625derived :  rdar17391625 {
}

extension rdar17391625derived {
  // Not a stored property, computed because it is an override.
  override var prop: Int { // expected-error {{overri}}
  didSet {
  }
  }
}

// <rdar://problem/27671033> Crash when defining property inside an invalid extension
// (This extension is no longer invalid.)
public protocol rdar27671033P {}
struct rdar27671033S<Key, Value> {}
extension rdar27671033S : rdar27671033P where Key == String {
  let d = rdar27671033S<Int, Int>() // expected-error {{extensions must not contain stored properties}}
}

// <rdar://problem/19874152> struct memberwise initializer violates new sanctity of previously set `let` property
struct r19874152S1 {
  let number : Int = 42
}
_ = r19874152S1(number:64)  // expected-error {{argument passed to call that takes no arguments}}
_ = r19874152S1()  // Ok

struct r19874152S2 {
  var number : Int = 42
}
_ = r19874152S2(number:64)  // Ok, property is a var.
_ = r19874152S2()  // Ok

struct r19874152S3 { // expected-note {{'init(flavor:)' declared here}}
  let number : Int = 42
  let flavor : Int
}
_ = r19874152S3(number:64)  // expected-error {{incorrect argument label in call (have 'number:', expected 'flavor:')}} {{17-23=flavor}}
_ = r19874152S3(number:64, flavor: 17)  // expected-error {{extra argument 'number' in call}}
_ = r19874152S3(flavor: 17)  // ok
_ = r19874152S3()  // expected-error {{missing argument for parameter 'flavor' in call}}

struct r19874152S4 {
  let number : Int? = nil
}
_ = r19874152S4(number:64)  // expected-error {{argument passed to call that takes no arguments}}
_ = r19874152S4()  // Ok


struct r19874152S5 {
}
_ = r19874152S5()  // ok


struct r19874152S6 {
  let (a,b) = (1,2)   // Cannot handle implicit synth of this yet.
}
_ = r19874152S5()  // ok



// <rdar://problem/24314506> QoI: Fix-it for dictionary initializer on required class var suggests [] instead of [:]
class r24314506 {  // expected-error {{class 'r24314506' has no initializers}}
  var myDict: [String: AnyObject]  // expected-note {{stored property 'myDict' without initial value prevents synthesized initializers}} {{34-34= = [:]}}
}


// https://bugs.swift.org/browse/SR-3893
// Generic type is not inferenced from its initial value for properties with
// will/didSet
struct SR3893Box<Foo> {
  let value: Foo
}

struct SR3893 {
  // Each of these "bad" properties used to produce errors.
  var bad: SR3893Box = SR3893Box(value: 0) {
    willSet {
      print(newValue.value)
    }
  }

  var bad2: SR3893Box = SR3893Box(value: 0) {
    willSet(new) {
      print(new.value)
    }
  }

  var bad3: SR3893Box = SR3893Box(value: 0) {
    didSet {
      print(oldValue.value)
    }
  }

  var good: SR3893Box<Int> = SR3893Box(value: 0) {
    didSet {
      print(oldValue.value)
    }
  }

  var plain: SR3893Box = SR3893Box(value: 0)
}

protocol WFI_P1 : class {}
protocol WFI_P2 : class {}

class WeakFixItTest {
  init() {}

  // expected-error @+1 {{'weak' variable should have optional type 'WeakFixItTest?'}} {{31-31=?}}
  weak var foo : WeakFixItTest

  // expected-error @+1 {{'weak' variable should have optional type '(WFI_P1 & WFI_P2)?'}} {{18-18=(}} {{33-33=)?}}
  weak var bar : WFI_P1 & WFI_P2
}

// SR-8811 (Warning)

let sr8811a = fatalError() // expected-warning {{constant 'sr8811a' inferred to have type 'Never', which is an enum with no cases}} expected-note {{add an explicit type annotation to silence this warning}}

let sr8811b: Never = fatalError() // Ok

let sr8811c = (16, fatalError()) // expected-warning {{constant 'sr8811c' inferred to have type '(Int, Never)', which contains an enum with no cases}} expected-note {{add an explicit type annotation to silence this warning}}

let sr8811d: (Int, Never) = (16, fatalError()) // Ok

// SR-10995

class SR_10995 {
  func makeDoubleOptionalNever() -> Never?? {
    return nil
  }

  func makeSingleOptionalNever() -> Never? {
    return nil
  }

  func sr_10995_foo() {
    let doubleOptionalNever = makeDoubleOptionalNever() // expected-warning {{constant 'doubleOptionalNever' inferred to have type 'Never??', which may be unexpected}} 
    // expected-note@-1 {{add an explicit type annotation to silence this warning}} 
    // expected-warning@-2 {{initialization of immutable value 'doubleOptionalNever' was never used; consider replacing with assignment to '_' or removing it}}
    let singleOptionalNever = makeSingleOptionalNever() // expected-warning {{constant 'singleOptionalNever' inferred to have type 'Never?', which may be unexpected}} 
    // expected-note@-1 {{add an explicit type annotation to silence this warning}} 
    // expected-warning@-2 {{initialization of immutable value 'singleOptionalNever' was never used; consider replacing with assignment to '_' or removing it}}
  }
}

// SR-9267

class SR_9267 {}
extension SR_9267 {
  var foo: String = { // expected-error {{extensions must not contain stored properties}} // expected-error {{function produces expected type 'String'; did you mean to call it with '()'?}} // expected-note {{Remove '=' to make 'foo' a computed property}}{{19-21=}}
    return "Hello"
  }
}

enum SR_9267_E {
  var SR_9267_prop: String = { // expected-error {{enums must not contain stored properties}} // expected-error {{function produces expected type 'String'; did you mean to call it with '()'?}} // expected-note {{Remove '=' to make 'SR_9267_prop' a computed property}}{{28-30=}}
    return "Hello"
  }
}

var SR_9267_prop_1: Int = { // expected-error {{function produces expected type 'Int'; did you mean to call it with '()'?}} // expected-note {{Remove '=' to make 'SR_9267_prop_1' a computed property}}{{25-27=}}
  return 0
}

class SR_9267_C {
  var SR_9267_prop_2: String = { // expected-error {{function produces expected type 'String'; did you mean to call it with '()'?}} // expected-note {{Remove '=' to make 'SR_9267_prop_2' a computed property}}{{30-32=}}
    return "Hello"
  }
}

class SR_9267_C2 {
  let SR_9267_prop_3: Int = { return 0 } // expected-error {{function produces expected type 'Int'; did you mean to call it with '()'?}} // expected-note {{Remove '=' to make 'SR_9267_prop_3' a computed property}}{{3-6=var}}{{27-29=}}
}

class LazyPropInClass {
  lazy var foo: Int = { return 0 } // expected-error {{function produces expected type 'Int'; did you mean to call it with '()'?}}
  // expected-note@-1 {{Remove '=' to make 'foo' a computed property}}{{21-23=}}{{3-8=}}
}
