// RUN: %empty-directory(%t)

// RUN: %target-swift-frontend -emit-module -emit-module-path %t/OtherActors.swiftmodule -module-name OtherActors %S/Inputs/OtherActors.swift -target %target-swift-5.1-abi-triple
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/GlobalVariables.swiftmodule -module-name GlobalVariables %S/Inputs/GlobalVariables.swift -target %target-swift-5.1-abi-triple -parse-as-library

// RUN: %target-swift-frontend -I %t  -target %target-swift-5.1-abi-triple -strict-concurrency=complete -parse-as-library -emit-sil -o /dev/null -verify -verify-ignore-unrelated -enable-upcoming-feature GlobalActorIsolatedTypesUsability %s

// REQUIRES: concurrency
// REQUIRES: swift_feature_GlobalActorIsolatedTypesUsability

import GlobalVariables
import OtherActors // expected-warning{{add '@preconcurrency' to suppress 'Sendable'-related warnings from module 'OtherActors'}}{{1-1=@preconcurrency }}

let immutableGlobal: String = "hello"

@available(SwiftStdlib 5.1, *)
func globalFunc() { }
@available(SwiftStdlib 5.1, *)
func acceptClosure<T>(_: () -> T) { }
@available(SwiftStdlib 5.1, *)
func acceptConcurrentClosure<T>(_: @Sendable () -> T) { }
@available(SwiftStdlib 5.1, *)
func acceptEscapingClosure<T>(_: @escaping () -> T) { }
@available(SwiftStdlib 5.1, *)
func acceptEscapingClosure<T>(_: @escaping (String) -> ()) async -> T? { nil }

@available(SwiftStdlib 5.1, *)
@discardableResult func acceptAsyncClosure<T>(_: () async -> T) -> T { }
@available(SwiftStdlib 5.1, *)
func acceptEscapingAsyncClosure<T>(_: @escaping () async -> T) { }
@available(SwiftStdlib 5.1, *)
func acceptInout<T>(_: inout T) {}


// ----------------------------------------------------------------------
// Actor state isolation restrictions
// ----------------------------------------------------------------------
@available(SwiftStdlib 5.1, *)
actor MySuperActor {
  var superState: Int = 25 // expected-note {{mutation of this property is only permitted within the actor}}


  func superMethod() { // expected-note {{calls to instance method 'superMethod()' from outside of its actor context are implicitly asynchronous}}
    self.superState += 5
  }

  func superAsyncMethod() async { }

  subscript (index: Int) -> String {
    "\(index)"
  }
}

class Point { // expected-note 5{{class 'Point' does not conform to the 'Sendable' protocol}}
  var x : Int = 0
  var y : Int = 0
}

@available(SwiftStdlib 5.1, *)
actor MyActor: MySuperActor { // expected-error{{actor types do not support inheritance}}
  let immutable: Int = 17
  // expected-note@+2 2{{property declared here}}
  // expected-note@+1 6{{mutation of this property is only permitted within the actor}}
  var mutable: Int = 71

  // expected-note@+2 3 {{mutation of this property is only permitted within the actor}}
  // expected-note@+1 4{{property declared here}}
  var text: [String] = []

  let point : Point = Point()

  @MainActor
  var name : String = "koala" // expected-note{{property declared here}}

  func accessProp() -> String {
    return self.name // expected-error{{main actor-isolated property 'name' can not be referenced on a different actor instance}}
  }

  static func synchronousClass() { }
  static func synchronousStatic() { }

  func synchronous() -> String { text.first ?? "nothing" } // expected-note 9{{calls to instance method 'synchronous()' from outside of its actor context are implicitly asynchronous}}
  func asynchronous() async -> String {
    super.superState += 4
    return synchronous()
  }
}

@available(SwiftStdlib 5.1, *)
actor Camera {
  func accessProp(act : MyActor) async -> String {
    return await act.name
  }
}

@available(SwiftStdlib 5.1, *)
func checkAsyncPropertyAccess() async {
  let act = MyActor()
  let _ : Int = await act.mutable + act.mutable
  act.mutable += 1  // expected-error {{actor-isolated property 'mutable' can not be mutated from a nonisolated context}}
  // expected-note@-1{{consider declaring an isolated method on 'MyActor' to perform the mutation}}

  act.superState += 1 // expected-error {{actor-isolated property 'superState' can not be mutated from a nonisolated context}}
  // expected-note@-1{{consider declaring an isolated method on 'MySuperActor' to perform the mutation}}

  act.text[0].append("hello") // expected-error{{actor-isolated property 'text' can not be mutated from a nonisolated context}}
  // expected-note@-1{{consider declaring an isolated method on 'MyActor' to perform the mutation}}

  // this is not the same as the above, because Array is a value type
  var arr = await act.text
  arr[0].append("hello")

  act.text.append("no") // expected-error{{actor-isolated property 'text' can not be mutated from a nonisolated context}}
  // expected-note@-1{{consider declaring an isolated method on 'MyActor' to perform the mutation}}

  act.text[0] += "hello" // expected-error{{actor-isolated property 'text' can not be mutated from a nonisolated context}}
  // expected-note@-1{{consider declaring an isolated method on 'MyActor' to perform the mutation}}

  _ = act.point  // expected-warning{{non-Sendable type 'Point' of property 'point' cannot exit actor-isolated context}}
  // expected-warning@-1 {{actor-isolated property 'point' cannot be accessed from outside of the actor}} {{7-7=await }}
}

/// ------------------------------------------------------------------
/// -- Value types do not need isolation on their stored properties --
protocol MainCounter {
  @MainActor var counter: Int { get set }
  @MainActor var ticker: Int { get set }
}

struct InferredFromConformance: MainCounter {
  var counter = 0
  var ticker: Int {
    get { 1 }
    set {}
  }
}

@MainActor
struct InferredFromContext {
  var point = Point()
  var polygon: [Point] {
    get { [] }
  }

  nonisolated var status: Bool = true // okay

  nonisolated let flag: Bool = false

  subscript(_ i: Int) -> Int { return i }

  static var stuff: [Int] = []
}

func checkIsolationValueType(_ formance: InferredFromConformance,
                             _ ext: InferredFromContext,
                             _ anno: NoGlobalActorValueType) async {
  // these still do need an await in Swift 5
  _ = await ext.point // expected-warning {{non-Sendable type 'Point' of property 'point' cannot exit main actor-isolated context}}
  _ = await anno.point // expected-warning {{non-Sendable type 'Point' of property 'point' cannot exit global actor 'SomeGlobalActor'-isolated context}}
  // expected-warning@-1 {{non-Sendable type 'NoGlobalActorValueType' cannot be sent into global actor 'SomeGlobalActor'-isolated context in call to property 'point'}}

  _ = formance.counter
  _ = anno.counter

  // these will always need an await
  _ = await (formance as MainCounter).counter // expected-warning {{non-Sendable type 'any MainCounter' cannot be sent into main actor-isolated context in call to property 'counter'}}
  _ = await ext[1]
  _ = await formance.ticker
  _ = await ext.polygon // expected-warning {{non-Sendable type '[Point]' of property 'polygon' cannot exit main actor-isolated context}}
  _ = await InferredFromContext.stuff
  _ = await NoGlobalActorValueType.polygon // expected-warning {{non-Sendable type '[Point]' of static property 'polygon' cannot exit main actor-isolated context}}
}

// expected-warning@+2 {{memberwise initializer for 'NoGlobalActorValueType' cannot be both nonisolated and global actor 'SomeGlobalActor'-isolated; this is an error in the Swift 6 language mode}}
// expected-note@+1 {{consider making struct 'NoGlobalActorValueType' conform to the 'Sendable' protocol}}
struct NoGlobalActorValueType {
  @SomeGlobalActor var point: Point
  // expected-note@-1 {{initializer for property 'point' is global actor 'SomeGlobalActor'-isolated}}

  @MainActor let counter: Int

  @MainActor static var polygon: [Point] = []
}

/// -----------------------------------------------------------------

@available(SwiftStdlib 5.1, *)
extension MyActor {
  nonisolated var actorIndependentVar: Int {
    get { 5 }
    set { }
  }

  // expected-warning@+1{{'nonisolated(unsafe)' has no effect on instance method 'nonisolatedUnsafe(otherActor:)', consider using 'nonisolated'}}{{3-14=nonisolated}}
  nonisolated(unsafe) func nonisolatedUnsafe(otherActor: MyActor) -> Int { }

  nonisolated func actorIndependentFunc(otherActor: MyActor) -> Int {
    _ = immutable
    _ = mutable // expected-error{{actor-isolated property 'mutable' can not be referenced from a nonisolated}}
    _ = text[0] // expected-error{{actor-isolated property 'text' can not be referenced from a nonisolated context}}
    _ = synchronous() // expected-error{{call to actor-isolated instance method 'synchronous()' in a synchronous nonisolated context}}

    // nonisolated
    _ = actorIndependentFunc(otherActor: self)
    _ = actorIndependentVar

    actorIndependentVar = 17
    _ = self.actorIndependentFunc(otherActor: self)
    _ = self.actorIndependentVar
    self.actorIndependentVar = 17

    // nonisolated on another actor
    _ = otherActor.actorIndependentFunc(otherActor: self)
    _ = otherActor.actorIndependentVar
    otherActor.actorIndependentVar = 17

    // async promotion
    _ = synchronous() // expected-error{{call to actor-isolated instance method 'synchronous()' in a synchronous nonisolated context}}

    // Global actors
    syncGlobalActorFunc() /// expected-error{{call to global actor 'SomeGlobalActor'-isolated global function 'syncGlobalActorFunc()' in a synchronous nonisolated context}}
    _ = syncGlobalActorFunc

    // Global data is okay if it is immutable.
    _ = immutableGlobal
    _ = mutableGlobal // expected-warning{{reference to var 'mutableGlobal' is not concurrency-safe because it involves shared mutable state}}

    // Partial application
    _ = synchronous  // expected-error{{actor-isolated instance method 'synchronous()' can not be partially applied}}

    // FIXME: The reference here isn't strictly a call
    _ = super.superMethod // expected-error{{call to actor-isolated instance method 'superMethod()' in a synchronous nonisolated context}}
    acceptClosure(synchronous) // expected-error{{actor-isolated instance method 'synchronous()' can not be referenced from a nonisolated context}}
    acceptClosure(self.synchronous) // expected-error{{actor-isolated instance method 'synchronous()' can not be referenced from a nonisolated context}}
    acceptClosure(otherActor.synchronous) // expected-error{{actor-isolated instance method 'synchronous()' can not be referenced from a nonisolated context}}
    acceptEscapingClosure(synchronous) // expected-error{{actor-isolated instance method 'synchronous()' can not be partially applied}}
    acceptEscapingClosure(self.synchronous) // expected-error{{actor-isolated instance method 'synchronous()' can not be partially applied}}
    acceptEscapingClosure(otherActor.synchronous) // expected-error{{actor-isolated instance method 'synchronous()' can not be partially applied}}

    return 5
  }

  func testAsynchronous(otherActor: MyActor) async {
    _ = immutable
    _ = mutable
    mutable = 0
    _ = synchronous()
    _ = text[0]
    acceptInout(&mutable)

    // Accesses on 'self' are okay.
    _ = self.immutable
    _ = self.mutable
    self.mutable = 0
    _ = self.synchronous()
    _ = await self.asynchronous()
    _ = self.text[0]
    acceptInout(&self.mutable)
    _ = self[0]

    // Accesses on 'super' are okay.
    _ = super.superState
    super.superState = 0
    acceptInout(&super.superState)
    super.superMethod()
    await super.superAsyncMethod()
    _ = super[0]

    // Accesses on other actors can only reference immutable data synchronously,
    // otherwise the access is treated as async
    _ = otherActor.immutable // okay
    _ = otherActor.mutable  // expected-error{{actor-isolated property 'mutable' cannot be accessed from outside of the actor}}{{9-9=await }}
    _ = await otherActor.mutable
    otherActor.mutable = 0  // expected-error{{actor-isolated property 'mutable' can not be mutated on a nonisolated actor instance}}
    // expected-note@-1{{consider declaring an isolated method on 'MyActor' to perform the mutation}}
    acceptInout(&otherActor.mutable)  // expected-error{{actor-isolated property 'mutable' can not be used 'inout' on a nonisolated actor instance}}
    // expected-error@+3{{actor-isolated property 'mutable' can not be mutated on a nonisolated actor instance}}
    // expected-warning@+2{{no 'async' operations occur within 'await' expression}}{{5-11=}}
    // expected-note@+1{{consider declaring an isolated method on 'MyActor' to perform the mutation}}
    await otherActor.mutable = 0

    _ = otherActor.synchronous()
    // expected-error@-1{{actor-isolated instance method 'synchronous()' cannot be called from outside of the actor}}{{9-9=await }}

    _ = await otherActor.asynchronous()
    _ = otherActor.text[0]
    // expected-error@-1{{actor-isolated property 'text' cannot be accessed from outside of the actor}}{{9-9=await }}

    _ = await otherActor.text[0] // okay

    // Global data is okay if it is immutable.
    _ = immutableGlobal
    _ = mutableGlobal // expected-warning{{reference to var 'mutableGlobal' is not concurrency-safe because it involves shared mutable state}}

    // Global functions are not actually safe, but we allow them for now.
    globalFunc()

    // Class methods are okay.
    Self.synchronousClass()
    Self.synchronousStatic()

    // Global actors
    syncGlobalActorFunc() // expected-error{{global actor 'SomeGlobalActor'-isolated global function 'syncGlobalActorFunc()' cannot be called from outside of the actor}}{{5-5=await }}

    await asyncGlobalActorFunc()

    // Closures.
    let localConstant = 17
    var localVar = 17

    // Non-escaping closures are okay.
    acceptClosure {
      _ = text[0]
      _ = self.synchronous()
      _ = localVar
      _ = localConstant
    }

    // Concurrent closures might run... concurrently.
    var otherLocalVar = 12
    acceptConcurrentClosure { [otherLocalVar] in
      defer {
        _ = otherLocalVar
      }

      _ = self.text[0] // expected-error{{actor-isolated property 'text' can not be referenced from a Sendable closure}}
      _ = self.mutable // expected-error{{actor-isolated property 'mutable' can not be referenced from a Sendable closure}}
      self.mutable = 0 // expected-error{{actor-isolated property 'mutable' can not be mutated from a Sendable closure}}
      acceptInout(&self.mutable) // expected-error{{actor-isolated property 'mutable' can not be used 'inout' from a Sendable closure}}
      _ = self.immutable
      _ = self.synchronous() // expected-error{{call to actor-isolated instance method 'synchronous()' in a synchronous nonisolated context}}
      _ = localVar // expected-warning{{reference to captured var 'localVar' in concurrently-executing code}}
      localVar = 25 // expected-warning{{mutation of captured var 'localVar' in concurrently-executing code}}
      _ = localConstant

      _ = otherLocalVar
    }
    otherLocalVar = 17

    acceptConcurrentClosure { [weak self, otherLocalVar] in
      defer {
        _ = self?.actorIndependentVar
      }

      _ = otherLocalVar
    }

    // Escaping closures are still actor-isolated
    acceptEscapingClosure {
      _ = self.text[0]
      _ = self.mutable
      self.mutable = 0
      acceptInout(&self.mutable)
      _ = self.immutable
      _ = self.synchronous()
      _ = localVar
      _ = localConstant
    }

    // Local functions might run concurrently.
    @Sendable func localFn1() {
      _ = self.text[0] // expected-error{{actor-isolated property 'text' can not be referenced from a Sendable function}}
      _ = self.synchronous() // expected-error{{call to actor-isolated instance method 'synchronous()' in a synchronous nonisolated context}}
      _ = localVar // expected-warning{{reference to captured var 'localVar' in concurrently-executing code}}
      localVar = 25 // expected-warning{{mutation of captured var 'localVar' in concurrently-executing code}}
      _ = localConstant
    }

    @Sendable func localFn2() {
      acceptClosure {
        _ = text[0]  // expected-error{{actor-isolated property 'text' can not be referenced from a nonisolated context}}
        _ = self.synchronous() // expected-error{{call to actor-isolated instance method 'synchronous()' in a synchronous nonisolated context}}
        _ = localVar // expected-warning{{reference to captured var 'localVar' in concurrently-executing code}}
        localVar = 25 // expected-warning{{mutation of captured var 'localVar' in concurrently-executing code}}
        _ = localConstant
      }
    }

    acceptEscapingClosure {
      localFn1()
      localFn2()
    }

    localVar = 0

    // Partial application
    _ = synchronous
    _ = super.superMethod
    acceptClosure(synchronous)
    acceptClosure(self.synchronous)
    acceptClosure(otherActor.synchronous) // expected-error{{actor-isolated instance method 'synchronous()' can not be referenced on a nonisolated actor instance}}
    acceptEscapingClosure(synchronous)
    acceptEscapingClosure(self.synchronous)
    acceptEscapingClosure(otherActor.synchronous) // expected-error{{actor-isolated instance method 'synchronous()' can not be partially applied}}

    acceptAsyncClosure(self.asynchronous)
    acceptEscapingAsyncClosure(self.asynchronous)
  }
}

// ----------------------------------------------------------------------
// Global actor isolation restrictions
// ----------------------------------------------------------------------
@available(SwiftStdlib 5.1, *)
actor SomeActor { }

@globalActor
@available(SwiftStdlib 5.1, *)
struct SomeGlobalActor {
  static let shared = SomeActor()
}

@globalActor
@available(SwiftStdlib 5.1, *)
struct SomeOtherGlobalActor {
  static let shared = SomeActor()
}

@globalActor
@available(SwiftStdlib 5.1, *)
struct GenericGlobalActor<T> {
  static var shared: SomeActor { SomeActor() }
}

@available(SwiftStdlib 5.1, *)
@SomeGlobalActor func onions_sga() {} // expected-note 2{{calls to global function 'onions_sga()' from outside of its actor context are implicitly asynchronous}}

@available(SwiftStdlib 5.1, *)
@MainActor func beets_ma() { onions_sga() } // expected-error{{call to global actor 'SomeGlobalActor'-isolated global function 'onions_sga()' in a synchronous main actor-isolated context}}
// expected-note@-1 4{{calls to global function 'beets_ma()' from outside of its actor context are implicitly asynchronous}}

@available(SwiftStdlib 5.1, *)
actor Crystal {
  // expected-note@+2 {{property declared here}}
  // expected-note@+1 2 {{mutation of this property is only permitted within the actor}}
  @SomeGlobalActor var globActorVar : Int = 0

  // expected-note@+1 {{mutation of this property is only permitted within the actor}}
  @SomeGlobalActor var globActorProp : Int {
    get { return 0 }
    set {}
  }

  @SomeGlobalActor func foo(_ x : inout Int) {}

  func referToGlobProps() async {
    _ = await globActorVar + globActorProp

    globActorProp = 20 // expected-error {{global actor 'SomeGlobalActor'-isolated property 'globActorProp' can not be mutated on a different actor instance}}
    // expected-note@-1{{consider declaring an isolated method on 'SomeGlobalActor' to perform the mutation}}

    globActorVar = 30 // expected-error {{global actor 'SomeGlobalActor'-isolated property 'globActorVar' can not be mutated on a different actor instance}}
    // expected-note@-1{{consider declaring an isolated method on 'SomeGlobalActor' to perform the mutation}}

    // expected-error@+2 {{global actor 'SomeGlobalActor'-isolated property 'globActorVar' can not be used 'inout' on a different actor instance}}
    // expected-error@+1 {{actor-isolated property 'globActorVar' cannot be passed 'inout' to implicitly 'async' function call}}
    await self.foo(&globActorVar)

    _ = self.foo
  }
}

@available(SwiftStdlib 5.1, *)
@SomeGlobalActor func syncGlobalActorFunc() { syncGlobalActorFunc() } // expected-note {{calls to global function 'syncGlobalActorFunc()' from outside of its actor context are implicitly asynchronous}}
@available(SwiftStdlib 5.1, *)
@SomeGlobalActor func asyncGlobalActorFunc() async { await asyncGlobalActorFunc() }

@available(SwiftStdlib 5.1, *)
@SomeOtherGlobalActor func syncOtherGlobalActorFunc() { }

@available(SwiftStdlib 5.1, *)
@SomeOtherGlobalActor func asyncOtherGlobalActorFunc() async {
  await syncGlobalActorFunc()
  await asyncGlobalActorFunc()
}

func crossIsolationBoundary(_ closure: () -> Void) async {}

@available(SwiftStdlib 5.1, *)
func testGlobalActorClosures() {
  let _: Int = acceptAsyncClosure { @SomeGlobalActor in
    syncGlobalActorFunc()
    syncOtherGlobalActorFunc() // expected-error{{global actor 'SomeOtherGlobalActor'-isolated global function 'syncOtherGlobalActorFunc()' cannot be called from outside of the actor}}{{5-5=await }}

    await syncOtherGlobalActorFunc()
    return 17
  }

  acceptConcurrentClosure { @SomeGlobalActor in 5 } // expected-warning {{converting function value of type '@SomeGlobalActor @Sendable () -> Int' to '@Sendable () -> Int' loses global actor 'SomeGlobalActor'}}

  @MainActor func test() async {
    let closure = { @MainActor @Sendable in
      MainActor.assertIsolated()
    }

    await crossIsolationBoundary(closure)
    // expected-warning@-1 {{converting function value of type '@MainActor @Sendable () -> ()' to '() -> Void' loses global actor 'MainActor'; this is an error in the Swift 6 language mode}}
  }
}

@available(SwiftStdlib 5.1, *)
extension MyActor {
  @SomeGlobalActor func onGlobalActor(otherActor: MyActor) async {
    // Access to other functions in this actor are okay.
    syncGlobalActorFunc()
    await asyncGlobalActorFunc()

    // Other global actors are ok if marked with 'await'
    await syncOtherGlobalActorFunc()
    await asyncOtherGlobalActorFunc()

    _ = immutable
    _ = mutable // expected-error{{actor-isolated property 'mutable' cannot be accessed from outside of the actor}}{{9-9=await }}
    _ = await mutable
    _ = synchronous() // expected-error{{actor-isolated instance method 'synchronous()' cannot be called from outside of the actor}}{{9-9=await }}
    _ = await synchronous()
    _ = text[0] // expected-error{{actor-isolated property 'text' cannot be accessed from outside of the actor}} {{9-9=await }}

    _ = await text[0]

    // Accesses on 'self' are only okay for immutable and asynchronous, because
    // we are outside of the actor instance.
    _ = self.immutable
    _ = self.synchronous() // expected-error{{actor-isolated instance method 'synchronous()' cannot be called from outside of the actor}}{{9-9=await }}
    _ = await self.synchronous()

    _ = await self.asynchronous()
    _ = self.text[0] // expected-error{{actor-isolated property 'text' cannot be accessed from outside of the actor}}{{9-9=await }}
    _ = self[0] // expected-error{{actor-isolated subscript 'subscript(_:)' cannot be accessed from outside of the actor}}{{9-9=await }}
    _ = await self.text[0]
    _ = await self[0]

    // Accesses on 'super' are not okay without 'await'; we're outside of the actor.
    _ = super.superState // expected-error{{actor-isolated property 'superState' cannot be accessed from outside of the actor}}{{9-9=await }}
    _ = await super.superState
    super.superMethod() // expected-error{{actor-isolated instance method 'superMethod()' cannot be called from outside of the actor}}{{5-5=await }}

    await super.superMethod()
    await super.superAsyncMethod()
    _ = super[0] // expected-error{{actor-isolated subscript 'subscript(_:)' cannot be accessed from outside of the actor}}{{9-9=await }}
    _ = await super[0]

    // Accesses on other actors can only reference immutable data or
    // call asynchronous methods
    _ = otherActor.immutable // okay
    _ = otherActor.synchronous() // expected-error{{actor-isolated instance method 'synchronous()' cannot be called from outside of the actor}}{{9-9=await }}
    _ = otherActor.synchronous  // expected-error{{actor-isolated instance method 'synchronous()' can not be partially applied}}
    _ = await otherActor.asynchronous()
    _ = otherActor.text[0] // expected-error{{actor-isolated property 'text' cannot be accessed from outside of the actor}}{{9-9=await }}
    _ = await otherActor.text[0]
  }
}

func testBadImplicitGlobalActorClosureCall() async {
  { @MainActor in  }() // expected-error{{expression is 'async' but is not marked with 'await'}}
  // expected-note@-1{{calls function of type '@MainActor @Sendable () -> ()' from outside of its actor context are implicitly asynchronous}}
}


@available(SwiftStdlib 5.1, *)
struct GenericStruct<T> {
  @GenericGlobalActor<T> func f() { } // expected-note {{calls to instance method 'f()' from outside of its actor context are implicitly asynchronous}}

  @GenericGlobalActor<T> func g() {
    f() // okay
  }

  @GenericGlobalActor<String> func h() {
    f() // expected-error{{call to global actor 'GenericGlobalActor<T>'-isolated instance method 'f()' in a synchronous global actor 'GenericGlobalActor<String>'-isolated context}}
    let fn = f // expected-note{{calls to let 'fn' from outside of its actor context are implicitly asynchronous}}
    fn() // expected-error{{call to global actor 'GenericGlobalActor<T>'-isolated let 'fn' in a synchronous global actor 'GenericGlobalActor<String>'-isolated context}}
  }
}

@available(SwiftStdlib 5.1, *)
extension GenericStruct where T == String {
  @GenericGlobalActor<T>
  func h2() {
    f()
    g()
    h()
  }
}

@SomeGlobalActor
var number: Int = 42 // expected-note {{var declared here}}

// expected-note@+1 {{add '@SomeGlobalActor' to make global function 'badNumberUser()' part of global actor 'SomeGlobalActor'}}
func badNumberUser() {
  //expected-error@+1{{global actor 'SomeGlobalActor'-isolated var 'number' can not be referenced from a nonisolated context}}
  print("The protected number is: \(number)")
}

@available(SwiftStdlib 5.1, *)
func asyncBadNumberUser() async {
  print("The protected number is: \(await number)")
}

// ----------------------------------------------------------------------
// Non-actor code isolation restrictions
// ----------------------------------------------------------------------
@available(SwiftStdlib 5.1, *)
func testGlobalRestrictions(actor: MyActor) async {
  let _ = MyActor()

  // references to sync methods must be fully applied.
  _ = actor.synchronous // expected-error{{actor-isolated instance method 'synchronous()' can not be partially applied}}
  _ = actor.asynchronous

  // any kind of method can be called from outside the actor, so long as it's marked with 'await'
  _ = actor.synchronous() // expected-error{{actor-isolated instance method 'synchronous()' cannot be called from outside of the actor}}{{7-7=await }}
  _ = actor.asynchronous() // expected-error{{actor-isolated instance method 'asynchronous()' cannot be called from outside of the actor}}{{7-7=await }}

  _ = await actor.synchronous()
  _ = await actor.asynchronous()

  // stored and computed properties can be accessed. Only immutable stored properties can be accessed without 'await'
  _ = actor.immutable
  _ = await actor.immutable // expected-warning {{no 'async' operations occur within 'await' expression}}{{7-13=}}
  _ = actor.mutable  // expected-error{{actor-isolated property 'mutable' cannot be accessed from outside of the actor}}{{7-7=await }}
  _ = await actor.mutable
  _ = actor.text[0] // expected-error{{actor-isolated property 'text' cannot be accessed from outside of the actor}}{{7-7=await }}
  _ = await actor.text[0]
  _ = actor[0] // expected-error{{actor-isolated subscript 'subscript(_:)' cannot be accessed from outside of the actor}}{{7-7=await }}
  _ = await actor[0]

  // nonisolated declarations are permitted.
  _ = actor.actorIndependentFunc(otherActor: actor)
  _ = actor.actorIndependentVar
  actor.actorIndependentVar = 5

  // Operations on non-instances are permitted.
  MyActor.synchronousStatic()
  MyActor.synchronousClass()

  // Global mutable state cannot be accessed.
  _ = mutableGlobal // expected-warning{{reference to var 'mutableGlobal' is not concurrency-safe because it involves shared mutable state}}

  // Local mutable variables cannot be accessed from concurrently-executing
  // code.
  var i = 17
  acceptConcurrentClosure {
    _ = i // expected-warning{{reference to captured var 'i' in concurrently-executing code}}
    i = 42 // expected-warning{{mutation of captured var 'i' in concurrently-executing code}}
  }
  print(i)

  acceptConcurrentClosure { [i] in
    _ = i
  }

  print("\(number)") //expected-error {{global actor 'SomeGlobalActor'-isolated var 'number' cannot be accessed from outside of the actor}}{{12-12=await }}

}

@available(SwiftStdlib 5.1, *)
func f() {
  acceptConcurrentClosure {
    _ = mutableGlobal // expected-warning{{reference to var 'mutableGlobal' is not concurrency-safe because it involves shared mutable state}}
  }

  @Sendable func g() {
    _ = mutableGlobal // expected-warning{{reference to var 'mutableGlobal' is not concurrency-safe because it involves shared mutable state}}
  }
}

// ----------------------------------------------------------------------
// Local function isolation restrictions
// ----------------------------------------------------------------------
@available(SwiftStdlib 5.1, *)
actor AnActorWithClosures {
  var counter: Int = 0 // expected-note 2 {{mutation of this property is only permitted within the actor}}
  func exec() {
    acceptEscapingClosure { [unowned self] in
      self.counter += 1

      acceptEscapingClosure {
        self.counter += 1

        acceptEscapingClosure { [self] in
          self.counter += 1
        }

        acceptConcurrentClosure { [self] in
          self.counter += 1 // expected-error{{actor-isolated property 'counter' can not be mutated from a Sendable closure}}

          acceptEscapingClosure {
            self.counter += 1 // expected-error{{actor-isolated property 'counter' can not be mutated from a nonisolated context}}
          }
        }
      }
    }
  }
}

// ----------------------------------------------------------------------
// Local function isolation restrictions
// ----------------------------------------------------------------------
@available(SwiftStdlib 5.1, *)
func checkLocalFunctions() async {
  var i = 0
  var j = 0

  func local1() {
    i = 17
  }

  func local2() { // expected-warning{{concurrently-executed local function 'local2()' must be marked as '@Sendable'}}{{3-3=@Sendable }}
    j = 42
  }

  // Okay to call locally.
  local1()
  local2()

  // non-Sendable closures don't cause problems.
  acceptClosure {
    local1()
    local2()
  }

  // Escaping closures can make the local function execute concurrently.
  acceptConcurrentClosure {
    local2() // expected-warning{{capture of 'local2()' with non-Sendable type '() -> ()' in a '@Sendable' closure}}
    // expected-note@-1{{a function type must be marked '@Sendable' to conform to 'Sendable'}}
  }

  print(i)
  print(j)

  var k = 17
  func local4() {
    acceptConcurrentClosure {
      local3() // expected-warning{{capture of 'local3()' with non-Sendable type '() -> ()' in a '@Sendable' closure}}
      // expected-note@-1{{a function type must be marked '@Sendable' to conform to 'Sendable'}}
    }
  }

  func local3() { // expected-warning{{concurrently-executed local function 'local3()' must be marked as '@Sendable'}}
    k = 25 // expected-warning{{mutation of captured var 'k' in concurrently-executing code}}
  }

  print(k)
}

func callee(_: () -> ()) {}

@available(SwiftStdlib 5.1, *)
actor LocalFunctionIsolatedActor {
  func a() -> Bool { // expected-note{{calls to instance method 'a()' from outside of its actor context are implicitly asynchronous}}
    return true
  }

  func b() -> Bool {
    func c() -> Bool {
      return true && a() // okay, c is isolated
    }
    return c()
  }

  func b2() -> Bool {
    @Sendable func c() -> Bool {
      return true && a() // expected-error{{call to actor-isolated instance method 'a()' in a synchronous nonisolated context}}
    }
    return c()
  }

  func hasRecursiveLocalFunction() {
    func recursiveLocalFunction(n: Int) {
      _ = a()
      callee { _ = a() }
      if n > 0 { recursiveLocalFunction(n: n - 1) }
    }

    recursiveLocalFunction(n: 10)
  }

  func hasRecursiveLocalFunctions() {
    recursiveLocalFunction()

    func recursiveLocalFunction() {
      anotherRecursiveLocalFunction()
    }

    func anotherRecursiveLocalFunction() {
      callee { _ = a() }
      _ = a()
    }
  }

}

// ----------------------------------------------------------------------
// Lazy properties with initializers referencing 'self'
// ----------------------------------------------------------------------

@available(SwiftStdlib 5.1, *)
actor LazyActor {
    var v: Int = 0

    let l: Int = 0

    lazy var l11: Int = { v }()
    lazy var l12: Int = v
    lazy var l13: Int = { self.v }()
    lazy var l14: Int = self.v
    lazy var l15: Int = { [unowned self] in self.v }()

    lazy var l21: Int = { l }()
    lazy var l22: Int = l
    lazy var l23: Int = { self.l }()
    lazy var l24: Int = self.l
    lazy var l25: Int = { [unowned self] in self.l }()

    nonisolated lazy var l31: Int = { v }()
    // expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
    // expected-warning@-2 {{actor-isolated default value in a nonisolated context; this is an error in the Swift 6 language mode}}
    nonisolated lazy var l32: Int = v
    // expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
    nonisolated lazy var l33: Int = { self.v }()
    // expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
    // expected-warning@-2 {{actor-isolated default value in a nonisolated context; this is an error in the Swift 6 language mode}}
    nonisolated lazy var l34: Int = self.v
    // expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
    nonisolated lazy var l35: Int = { [unowned self] in self.v }()
    // expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
    // expected-warning@-2 {{actor-isolated default value in a nonisolated context; this is an error in the Swift 6 language mode}}

    nonisolated lazy var l41: Int = { l }()
    // expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
    nonisolated lazy var l42: Int = l
    // expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
    nonisolated lazy var l43: Int = { self.l }()
    // expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
    nonisolated lazy var l44: Int = self.l
    // expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
    nonisolated lazy var l45: Int = { [unowned self] in self.l }()
    // expected-warning@-1 {{'nonisolated' cannot be applied to mutable stored properties; this is an error in the Swift 6 language mode}}
}

// Infer global actors from context only for instance members.
@available(SwiftStdlib 5.1, *)
@MainActor
class SomeClassInActor {
  enum ID: String { case best }

  func inActor() { } // expected-note{{calls to instance method 'inActor()' from outside of its actor context are implicitly asynchronous}}
}

@available(SwiftStdlib 5.1, *)
extension SomeClassInActor.ID {
  func f(_ object: SomeClassInActor) { // expected-note{{add '@MainActor' to make instance method 'f' part of global actor 'MainActor'}}
    object.inActor() // expected-error{{call to main actor-isolated instance method 'inActor()' in a synchronous nonisolated context}}
  }
}

// ----------------------------------------------------------------------
// Initializers (through typechecking only)
// ----------------------------------------------------------------------
@available(SwiftStdlib 5.1, *)
actor SomeActorWithInits {
  // expected-note@+2 2 {{property declared here}}
  // expected-note@+1 4 {{mutation of this property is only permitted within the actor}}
  var mutableState: Int = 17
  var otherMutableState: Int
  // expected-note@+1 {{mutation of this property is only permitted within the actor}}
  let nonSendable: SomeClass

  // Sema should not complain about referencing non-Sendable members
  // in an actor init or deinit, as those are diagnosed later by flow-isolation.
  init(_ x: SomeClass) {
    self.nonSendable = x
  }

  init(i1: Bool) {
    self.mutableState = 42
    self.otherMutableState = 17

    self.isolated() // expected-warning{{actor-isolated instance method 'isolated()' can not be referenced from a nonisolated context; this is an error in the Swift 6 language mode}}
    self.nonisolated()

    defer {
      isolated() // expected-warning{{actor-isolated instance method 'isolated()' can not be referenced from a nonisolated context; this is an error in the Swift 6 language mode}}
      mutableState += 1 // okay through typechecking, since flow-isolation will verify it.
      nonisolated()
    }

    func local() {
      isolated() // expected-warning{{actor-isolated instance method 'isolated()' can not be referenced from a nonisolated context; this is an error in the Swift 6 language mode}}
      mutableState += 1 // expected-warning{{actor-isolated property 'mutableState' can not be mutated from a nonisolated context; this is an error in the Swift 6 language mode}}
      nonisolated()
    }
    local()

    func localAsync() async {
      isolated() // expected-warning{{actor-isolated instance method 'isolated()' can not be referenced from a nonisolated context; this is an error in the Swift 6 language mode}}
      mutableState += 1 // expected-warning{{actor-isolated property 'mutableState' can not be mutated from a nonisolated context; this is an error in the Swift 6 language mode}}
      // expected-note@-1{{consider declaring an isolated method on 'SomeActorWithInits' to perform the mutation}}
      nonisolated()
    }
    Task { await localAsync() }

    let _ = {
      defer {
        isolated() // expected-warning{{actor-isolated instance method 'isolated()' can not be referenced from a nonisolated context; this is an error in the Swift 6 language mode}}
        mutableState += 1  // expected-warning{{actor-isolated property 'mutableState' can not be mutated from a nonisolated context; this is an error in the Swift 6 language mode}}
        nonisolated()
      }
      nonisolated()
    }()
  }

  init(i2: Bool) async {
    self.mutableState = 0
    self.otherMutableState = 1

    self.isolated()
    self.nonisolated()
  }

  convenience init(i3: Bool) { // expected-warning{{initializers in actors are not marked with 'convenience'; this is an error in the Swift 6 language mode}}{{3-15=}}
    self.init(i1: i3)
    _ = mutableState    // expected-error{{actor-isolated property 'mutableState' can not be referenced from a nonisolated context}}
    self.isolated()     // expected-error{{call to actor-isolated instance method 'isolated()' in a synchronous nonisolated context}}
    self.nonisolated()
  }

  convenience init(i4: Bool) async { // expected-warning{{initializers in actors are not marked with 'convenience'; this is an error in the Swift 6 language mode}}{{3-15=}}
    self.init(i1: i4)
    _ = mutableState
    self.isolated()
    self.nonisolated()
  }

  @MainActor init(i5 x: SomeClass) {
    self.mutableState = 42
    self.otherMutableState = 17
    self.nonSendable = x // expected-warning {{actor-isolated property 'nonSendable' can not be mutated from the main actor; this is an error in the Swift 6 language mode}}

    self.isolated() // expected-warning{{actor-isolated instance method 'isolated()' can not be referenced from the main actor; this is an error in the Swift 6 language mode}}
    self.nonisolated()
  }

  @MainActor init(i6: Bool) async {
    self.mutableState = 42
    self.otherMutableState = 17

    await self.isolated()
    self.nonisolated()

    _ = mutableState // will be caught by flow-isolation
  }

  @MainActor convenience init(i7: Bool) { // expected-warning{{initializers in actors are not marked with 'convenience'; this is an error in the Swift 6 language mode}}{{14-26=}}
    self.init(i1: i7)
    _ = mutableState    // expected-error{{actor-isolated property 'mutableState' can not be referenced from the main actor}}
    self.isolated()     // expected-error{{call to actor-isolated instance method 'isolated()' in a synchronous main actor-isolated context}}
    self.nonisolated()
  }

  @MainActor convenience init(i8: Bool) async { // expected-warning{{initializers in actors are not marked with 'convenience'; this is an error in the Swift 6 language mode}}{{14-26=}}
    self.init(i1: i8)
    _ = await mutableState
    await self.isolated()
    self.nonisolated()
  }

  nonisolated init(i9: Bool) async {
    self.mutableState = 0
    self.otherMutableState = 1

    await self.isolated()
    self.nonisolated()

    _ = mutableState  // will be caught by flow-isolation
  }

  deinit {
    let _ = self.nonSendable // OK only through typechecking, not SIL.

    defer {
      isolated() // expected-warning{{actor-isolated instance method 'isolated()' can not be referenced from a nonisolated context; this is an error in the Swift 6 language mode}}
      mutableState += 1 // okay
      nonisolated()
    }

    let _ = {
      defer {
        isolated() // expected-warning{{actor-isolated instance method 'isolated()' can not be referenced from a nonisolated context; this is an error in the Swift 6 language mode}}
        mutableState += 1  // expected-warning{{actor-isolated property 'mutableState' can not be mutated from a nonisolated context; this is an error in the Swift 6 language mode}}
        nonisolated()
      }
      nonisolated()
    }()
  }

  func isolated() { } // expected-note 10 {{calls to instance method 'isolated()' from outside of its actor context are implicitly asynchronous}}
  nonisolated func nonisolated() {}
}

@available(SwiftStdlib 5.1, *)
@MainActor
class SomeClassWithInits {
  var mutableState: Int = 17
  var otherMutableState: Int

  static var shared = SomeClassWithInits() // expected-note 2{{static property declared here}}

  init() { // expected-note{{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}}
    self.mutableState = 42
    self.otherMutableState = 17

    self.isolated()
  }

  deinit {
    print(mutableState) // Okay, we're actor-isolated
    print(SomeClassWithInits.shared) // expected-error{{main actor-isolated static property 'shared' can not be referenced from a nonisolated context}}
    beets_ma() //expected-error{{call to main actor-isolated global function 'beets_ma()' in a synchronous nonisolated context}}
  }

  func isolated() { }

  static func staticIsolated() { // expected-note{{calls to static method 'staticIsolated()' from outside of its actor context are implicitly asynchronous}}
    _ = SomeClassWithInits.shared
  }

  func hasDetached() {
    Task.detached {
      // okay
      await self.isolated()
      self.isolated()
      // expected-error@-1{{main actor-isolated instance method 'isolated()' cannot be called from outside of the actor}}{{7-7=await }}

      print(await self.mutableState)
    }
  }
}

@available(SwiftStdlib 5.1, *)
func outsideSomeClassWithInits() { // expected-note 3 {{add '@MainActor' to make global function 'outsideSomeClassWithInits()' part of global actor 'MainActor'}}
  _ = SomeClassWithInits() // expected-error{{call to main actor-isolated initializer 'init()' in a synchronous nonisolated context}}
  _ = SomeClassWithInits.shared // expected-error{{main actor-isolated static property 'shared' can not be referenced from a nonisolated context}}
  SomeClassWithInits.staticIsolated() // expected-error{{call to main actor-isolated static method 'staticIsolated()' in a synchronous nonisolated context}}
}

// ----------------------------------------------------------------------
// nonisolated let and cross-module let
// ----------------------------------------------------------------------
func testCrossModuleLets(actor: OtherModuleActor) async {
  _ = actor.a         // expected-error{{actor-isolated property 'a' cannot be accessed from outside of the actor}} {{7-7=await }}
  _ = await actor.a   // okay
  _ = actor.b         // okay
  _ = actor.c // expected-error{{actor-isolated property 'c' cannot be accessed from outside of the actor}} {{7-7=await }}
  // expected-warning@-1{{non-Sendable type 'SomeClass' of property 'c' cannot exit actor-isolated context}}
  _ = await actor.c // expected-warning{{non-Sendable type 'SomeClass' of property 'c' cannot exit actor-isolated context}}
  _ = await actor.d // okay
}

func testCrossModuleAsIsolated(actor: isolated OtherModuleActor) {
  _ = actor.a
  _ = actor.b
  _ = actor.c
  _ = actor.d
}

extension OtherModuleActor {
  func testCrossModuleInExtension() {
    _ = self.a
    _ = self.b
    _ = self.c
    _ = self.d
  }
}

actor CrossModuleFromInitsActor {
  init(v1 actor: OtherModuleActor) {
    _ = actor.a   // expected-error {{actor-isolated property 'a' can not be referenced from a nonisolated context}}
    _ = actor.b   // okay

    _ = actor.c   // expected-error {{actor-isolated property 'c' can not be referenced from a nonisolated context}}
  }

  init(v2 actor: OtherModuleActor) async {
    _ = actor.a         // expected-error{{actor-isolated property 'a' cannot be accessed from outside of the actor}} {{9-9=await }}
    _ = await actor.a   // okay
    _ = actor.b         // okay
    _ = actor.c // expected-error{{actor-isolated property 'c' cannot be accessed from outside of the actor}} {{9-9=await }}
    // expected-warning@-1{{non-Sendable type 'SomeClass' of property 'c' cannot exit actor-isolated context}}
    _ = await actor.c // expected-warning{{non-Sendable type 'SomeClass' of property 'c' cannot exit actor-isolated context}}
    _ = await actor.d // okay
  }
}


// ----------------------------------------------------------------------
// Actor protocols.
// ----------------------------------------------------------------------

@available(SwiftStdlib 5.1, *)
actor A: Actor { // ok
}

@available(SwiftStdlib 5.1, *)
class C: Actor, UnsafeSendable {
  // expected-error@-1{{non-actor type 'C' cannot conform to the 'Actor' protocol}}
  // expected-warning@-2{{'UnsafeSendable' is deprecated: Use @unchecked Sendable instead}}
  nonisolated var unownedExecutor: UnownedSerialExecutor {
    fatalError()
  }
}

@available(SwiftStdlib 5.1, *)
protocol P: Actor {
  func f()
}

@available(SwiftStdlib 5.1, *)
extension P {
  func g() { f() }
}

@available(SwiftStdlib 5.1, *)
actor MyActorP: P {
  func f() { }

  func h() { g() }
}

@available(SwiftStdlib 5.1, *)
protocol SP {
  static func s()
}

@available(SwiftStdlib 5.1, *)
actor ASP: SP {
  static func s() { }
}

@available(SwiftStdlib 5.1, *)
protocol SPD {
  static func sd()
}
@available(SwiftStdlib 5.1, *)
extension SPD {
  static func sd() { }
}

@available(SwiftStdlib 5.1, *)
actor ASPD: SPD {
}

@available(SwiftStdlib 5.1, *)
func testCrossActorProtocol<T: P>(t: T) async {
  await t.f()
  await t.g()
  t.f()
  // expected-error@-1{{actor-isolated instance method 'f()' cannot be called from outside of the actor}}{{3-3=await }}
  t.g()
  // expected-error@-1{{actor-isolated instance method 'g()' cannot be called from outside of the actor}}{{3-3=await }}
  ASP.s()
  ASPD.sd()
}

@available(SwiftStdlib 5.1, *)
protocol Server {
  func send<Message: Codable & Sendable>(message: Message) async throws -> String
}

@available(SwiftStdlib 5.1, *)
actor MyServer : Server {
  // okay, asynchronously accessed from clients of the protocol
  func send<Message: Codable & Sendable>(message: Message) throws -> String { "" }
}

// ----------------------------------------------------------------------
// @_inheritActorContext
// ----------------------------------------------------------------------
@available(SwiftStdlib 5.1, *)
func acceptAsyncSendableClosure<T>(_: @Sendable () async -> T) { }
@available(SwiftStdlib 5.1, *)
func acceptAsyncSendableClosureInheriting<T>(@_inheritActorContext _: @Sendable () async -> T) { }
@available(SwiftStdlib 5.1, *)
func acceptAsyncSendableClosureInheritingAlways<T>(@_inheritActorContext(always) _: @Sendable () async -> T) { }

@available(SwiftStdlib 5.1, *)
extension MyActor {
  func testSendableAndInheriting() {
    var counter = 0

    acceptAsyncSendableClosure {
      _ = synchronous() // expected-error{{actor-isolated instance method 'synchronous()' cannot be called from outside of the actor}} {{11-11=await }}

      counter += 1 // expected-warning{{mutation of captured var 'counter' in concurrently-executing code}}
    }

    acceptAsyncSendableClosure {
      _ = await synchronous() // ok
      counter += 1 // expected-warning{{mutation of captured var 'counter' in concurrently-executing code}}
    }

    acceptAsyncSendableClosureInheriting {
      _ = synchronous() // okay
      counter += 1 // okay
    }

    acceptAsyncSendableClosureInheriting {
      _ = await synchronous() // expected-warning{{no 'async' operations occur within 'await' expression}}{{11-17=}}
      counter += 1 // okay
    }

    acceptAsyncSendableClosureInheritingAlways {
      counter += 1 // Ok
    }
  }
}

@available(SwiftStdlib 5.1, *)
@SomeGlobalActor
func testGlobalActorInheritance() {
  var counter = 0

  acceptAsyncSendableClosure {
    counter += 1 // expected-warning{{mutation of captured var 'counter' in concurrently-executing code}}
  }

  acceptAsyncSendableClosure { @SomeGlobalActor in
    counter += 1 // ok
  }


  acceptAsyncSendableClosureInheriting {
    counter += 1 // ok
  }

  acceptAsyncSendableClosureInheritingAlways {
    counter += 1 // ok
  }
}

@available(SwiftStdlib 5.1, *)
func testIsolatedParameter1(_: isolated any Actor, v: inout Int) {
  acceptAsyncSendableClosureInheriting {
    v += 1 // expected-warning {{mutable capture of 'inout' parameter 'v' is not allowed in concurrently-executing code}}
  }

  acceptAsyncSendableClosureInheritingAlways {
    v += 1 // Ok
  }
}

@available(SwiftStdlib 5.1, *)
func testIsolatedParameter2(_: isolated (any Actor)? = #isolation, v: inout Int) {
  acceptAsyncSendableClosureInheriting {
    v += 1 // expected-warning {{mutable capture of 'inout' parameter 'v' is not allowed in concurrently-executing code}}
  }

  acceptAsyncSendableClosureInheritingAlways {
    v += 1 // Ok
  }
}

@available(SwiftStdlib 5.1, *)
@MainActor // expected-note {{'GloballyIsolatedProto' is isolated to global actor 'MainActor' here}}
protocol GloballyIsolatedProto {
}

// rdar://75849035 - trying to conform an actor to a global-actor-isolated protocol should result in an error
func test_conforming_actor_to_global_actor_protocol() {
  @available(SwiftStdlib 5.1, *)
  actor MyValue : GloballyIsolatedProto {}
  // expected-error@-1 {{actor 'MyValue' cannot conform to global-actor-isolated protocol 'GloballyIsolatedProto'}}
}

func test_nonisolated_variable() {
  struct S: GloballyIsolatedProto {
    nonisolated var x: Int = 0 // okay
  }
}

func test_invalid_reference_to_actor_member_without_a_call_note() {
  actor A {
    func partial() { }
  }

  actor Test {
    func returnPartial(other: A) async -> () async -> () {
      let a = other.partial
      // expected-error@-1 {{actor-isolated instance method 'partial()' can not be partially applied}}
      return a
    }
  }
}

// Actor isolation and initializers through typechecking only, not flow-isolation.
actor Counter {
  var counter: Int = 0

  // expected-note@+2{{mutation of this property is only permitted within the actor}}
  // expected-note@+1{{property declared here}}
  var computedProp : Int {
      get { 0 }
      set { }
  }

  func next() -> Int { // expected-note 2 {{calls to instance method 'next()' from outside of its actor context are implicitly asynchronous}}
    defer {
      counter = counter + 1
    }

    return counter
  }

  func localNext() -> Int {
    func doIt() {
      counter = counter + 1
    }
    doIt()

    return counter
  }

  init() {
    _ = self.next() // expected-warning {{actor-isolated instance method 'next()' can not be referenced from a nonisolated context; this is an error in the Swift 6 language mode}}
    defer { _ = self.next() } // expected-warning {{actor-isolated instance method 'next()' can not be referenced from a nonisolated context; this is an error in the Swift 6 language mode}}

    _ = computedProp  // expected-warning {{actor-isolated property 'computedProp' can not be referenced from a nonisolated context; this is an error in the Swift 6 language mode}}
    computedProp = 1  // expected-warning {{actor-isolated property 'computedProp' can not be mutated from a nonisolated context; this is an error in the Swift 6 language mode}}

  }

  init(material: Int) async {
    self.init()
    self.counter = 10
  }
}

/// Superclass checks for global actor-qualified class types.
class C2 { }

@SomeGlobalActor
class C3: C2 {
  func requireSendableSelf() {
    // self is Sendable here.
    Task.detached {
      _ = self
    }
  }
}

@GenericGlobalActor<U>
class GenericSuper<U> { }

@GenericGlobalActor<[T]>
class GenericSub1<T>: GenericSuper<[T]> { }

@GenericGlobalActor<T>
class GenericSub2<T>: GenericSuper<[T]> { } // expected-error{{global actor 'GenericGlobalActor<T>'-isolated class 'GenericSub2' has different actor isolation from global actor 'GenericGlobalActor<U>'-isolated superclass 'GenericSuper'}}

/// Diagnostics for `nonisolated` on an actor initializer.
actor Butterfly {
  var flapsPerSec = 0 // expected-note 3{{mutation of this property is only permitted within the actor}}

  nonisolated init() {} // expected-warning {{'nonisolated' on an actor's synchronous initializer is invalid; this is an error in the Swift 6 language mode}} {{3-15=}}

  nonisolated init(async: Void) async {}

  nonisolated init(icecream: Void) { // expected-warning {{'nonisolated' on an actor's synchronous initializer is invalid; this is an error in the Swift 6 language mode}} {{3-15=}}
    self.init()
    self.flapsPerSec += 1 // expected-error {{actor-isolated property 'flapsPerSec' can not be mutated from a nonisolated context}}
  }

  nonisolated init(cookies: Void) async {
    self.init()
    self.flapsPerSec += 1 // expected-error {{actor-isolated property 'flapsPerSec' can not be mutated from a nonisolated context}}
    // expected-note@-1 {{consider declaring an isolated method on 'Butterfly' to perform the mutation}}
  }

  init(brownies: Void) {
    self.init()
    self.flapsPerSec = 0 // expected-error {{actor-isolated property 'flapsPerSec' can not be mutated from a nonisolated context}}
  }
}

// expected-note@+1 2 {{calls to global function 'takeIsolated' from outside of its actor context are implicitly asynchronous}}
func takeIsolated(_ val: isolated SelfParamIsolationNonMethod) {}
func take(_ val: SelfParamIsolationNonMethod) {}

actor SelfParamIsolationNonMethod {
  init(s0: Void) {
    // expected-error@+1 {{actor-isolated instance method 'f()' cannot be called from outside of the actor}} {{44-44=await }}
    acceptAsyncSendableClosureInheriting { self.f() }

    // expected-error@+1 {{actor-isolated instance method 'f()' cannot be called from outside of the actor}} {{34-34=await }}
    acceptAsyncSendableClosure { self.f() }

    // expected-error@+1 {{call to actor-isolated global function 'takeIsolated' in a synchronous nonisolated context}}
    takeIsolated(self)

    take(self)
  }

  @MainActor init(s1: Void) {
    // expected-error@+1 {{actor-isolated instance method 'f()' cannot be called from outside of the actor}} {{44-44=await }}
    acceptAsyncSendableClosureInheriting { self.f() }

    // expected-error@+1 {{actor-isolated instance method 'f()' cannot be called from outside of the actor}} {{34-34=await }}
    acceptAsyncSendableClosure { self.f() }
  }

  init(a1: Void) async {
    acceptAsyncSendableClosureInheriting { self.f() }

    // expected-error@+1 {{actor-isolated instance method 'f()' cannot be called from outside of the actor}} {{34-34=await }}
    acceptAsyncSendableClosure { self.f() }

    takeIsolated(self)

    take(self)
  }

  @MainActor init(a2: Void) async {
    // expected-error@+1 {{actor-isolated instance method 'f()' cannot be called from outside of the actor}} {{44-44=await }}
    acceptAsyncSendableClosureInheriting { self.f() }

    // expected-error@+1 {{actor-isolated instance method 'f()' cannot be called from outside of the actor}} {{34-34=await }}
    acceptAsyncSendableClosure { self.f() }
  }

  nonisolated init(a3: Void) async {
    // expected-error@+1 {{actor-isolated instance method 'f()' cannot be called from outside of the actor}} {{44-44=await }}
    acceptAsyncSendableClosureInheriting { self.f() }

    // expected-error@+1 {{actor-isolated instance method 'f()' cannot be called from outside of the actor}} {{34-34=await }}
    acceptAsyncSendableClosure { self.f() }
  }

  deinit {
    // expected-error@+1 {{actor-isolated instance method 'f()' cannot be called from outside of the actor}} {{44-44=await }}
    acceptAsyncSendableClosureInheriting { self.f() }

    // expected-error@+1 {{actor-isolated instance method 'f()' cannot be called from outside of the actor}} {{34-34=await }}
    acceptAsyncSendableClosure { self.f() }

    // expected-error@+1 {{call to actor-isolated global function 'takeIsolated' in a synchronous nonisolated context}}
    takeIsolated(self)

    take(self)
  }

  func f() {}
}

@MainActor
final class MainActorInit: Sendable {
  init() {
    acceptAsyncSendableClosureInheriting { self.f() }

    // expected-error@+1 {{actor-isolated instance method 'f()' cannot be called from outside of the actor}} {{34-34=await }}
    acceptAsyncSendableClosure { self.f() }
  }

  deinit {
    // expected-error@+1 {{actor-isolated instance method 'f()' cannot be called from outside of the actor}} {{44-44=await }}
    acceptAsyncSendableClosureInheriting { self.f() }

    // expected-error@+1 {{actor-isolated instance method 'f()' cannot be called from outside of the actor}} {{34-34=await }}
    acceptAsyncSendableClosure { self.f() }
  }

  func f() {}
}

actor DunkTracker {
  private var lebron: Int?
  private var curry: Int? // expected-note {{property declared here}}

  deinit {
    // expected-warning@+1 {{actor-isolated property 'curry' can not be referenced from a nonisolated autoclosure; this is an error in the Swift 6 language mode}}
    if lebron != nil || curry != nil {
      
    }
  }
}

@MainActor
class MA {
  func method() {}
}

@SomeGlobalActor class SGA: MA {} // expected-error {{global actor 'SomeGlobalActor'-isolated class 'SGA' has different actor isolation from main actor-isolated superclass 'MA'}}

protocol SGA_Proto {
  @SomeGlobalActor func method()
}

// try to override a MA method with inferred isolation from a protocol requirement
// expected-warning@+1{{conformance of 'SGA_MA' to protocol 'SGA_Proto' involves isolation mismatches and can cause data races}}
class SGA_MA: MA, SGA_Proto {
  // expected-note@-1{{mark all declarations used in the conformance 'nonisolated'}}
  // expected-note@-2{{turn data races into runtime errors with '@preconcurrency'}}
  
  // expected-error@+2 {{call to global actor 'SomeGlobalActor'-isolated global function 'onions_sga()' in a synchronous main actor-isolated context}}
  // expected-note@+1 {{main actor-isolated instance method 'method()' cannot satisfy global actor 'SomeGlobalActor'-isolated requirement}}
  override func method() { onions_sga() }
}

class None_MA: MA {
  override func method() { beets_ma() }
}

class None {
  func method() {} // expected-note{{overridden declaration is here}}
}

// try to add inferred isolation while overriding
@MainActor
class MA_None1: None {
  override func method() {
    beets_ma() // expected-error {{call to main actor-isolated global function 'beets_ma()' in a synchronous nonisolated context}}
  }
}

class MA_None2: None {
  @MainActor
  override func method() { // expected-error {{main actor-isolated instance method 'method()' has different actor isolation from nonisolated overridden declaration}}
    beets_ma()
  }
}

class MADirect {
  @MainActor func method1() {}
  @MainActor func method2() {}
}

class None_MADirect: MADirect {
  // default-isolation vs overridden-MainActor = mainactor
  override func method1() { beets_ma() }

  // directly-nonisolated vs overridden mainactor = nonisolated
  nonisolated override func method2() { beets_ma() } // expected-error {{call to main actor-isolated global function 'beets_ma()' in a synchronous nonisolated context}}
}

@SomeGlobalActor
class SGA_MADirect: MADirect {

  // inferred-SomeGlobalActor vs overridden-MainActor = mainactor
  override func method1() { beets_ma() }

  // directly-nonisolated vs overridden-MainActor = nonisolated
  nonisolated override func method2() { beets_ma() } // expected-error {{call to main actor-isolated global function 'beets_ma()' in a synchronous nonisolated context}}
}

// Actor isolation allows capture
extension MyActor {
  func testNonSendableCaptures(sc: SomeClass) {
    Task {
      _ = self
      _ = sc

      Task { [sc,self] in
        _ = self
        _ = sc

        // A test that validates that we treat this as a true send was added
        // into transfernonsendable.swift.
        Task {
          _ = sc
        }
      }
    }
  }
}

@MainActor
class SuperWithNonisolatedInit {
  static func isolatedToMainActor() {}

  // expected-note@+1 2 {{mutation of this property is only permitted within the actor}}
  var x: Int = 0 {
    didSet {
      SuperWithNonisolatedInit.isolatedToMainActor()
    }
  }

  nonisolated init() {}
}

class OverridesNonsiolatedInit: SuperWithNonisolatedInit {
  override nonisolated init() {
    super.init()

    // expected-error@+1 {{main actor-isolated property 'x' can not be mutated from a nonisolated context}}
    super.x = 10
  }

  nonisolated func f() {
    // expected-error@+1 {{main actor-isolated property 'x' can not be mutated from a nonisolated context}}
    super.x = 10
  }
}

// expected-note@+1 {{class 'NonSendable' does not conform to the 'Sendable' protocol}}
class NonSendable {}

protocol NonisolatedProtocol {
  var ns: NonSendable { get }
}

// expected-warning@+1{{conformance of 'ActorWithNonSendableLet' to protocol 'NonisolatedProtocol' crosses into actor-isolated code and can cause data races}}
actor ActorWithNonSendableLet: NonisolatedProtocol {
  // expected-note@-1{{turn data races into runtime errors with '@preconcurrency'}}{{32-32=@preconcurrency }}

  // expected-note@+1 {{actor-isolated property 'ns' cannot satisfy nonisolated requirement}}
  let ns = NonSendable()
}

actor ProtectNonSendable {
  // expected-note@+1 2 {{property declared here}}
  let ns = NonSendable()

  init() {}

  @MainActor init(fromMain: Void) {
    // expected-warning@+1 {{actor-isolated property 'ns' can not be referenced from the main actor; this is an error in the Swift 6 language mode}}
    _ = self.ns
  }
}

@MainActor
class ReferenceActor {
  let a: ProtectNonSendable

  init() async {
    self.a = ProtectNonSendable()

    // expected-warning@+2 {{non-Sendable type 'NonSendable' of property 'ns' cannot exit actor-isolated context}}
    // expected-warning@+1 {{actor-isolated property 'ns' cannot be accessed from outside of the actor}} {{9-9=await }}
    _ = a.ns
  }
}

actor AnotherActor {
  let a: ProtectNonSendable

  init() {
    self.a = ProtectNonSendable()

    // expected-warning@+1 {{actor-isolated property 'ns' can not be referenced from a nonisolated context}}
    _ = a.ns
  }
}

@MainActor
class MainActorIsolated {
  init() {}

  // expected-note@+1 {{static property declared here}}
  static let shared = MainActorIsolated()
}

nonisolated func accessAcrossActors() {
  // expected-warning@+1 {{main actor-isolated static property 'shared' can not be referenced from a nonisolated context; this is an error in the Swift 6 language mode}}
  let _ = MainActorIsolated.shared
}

@available(SwiftStdlib 5.1, *)
actor Iterator: AsyncIteratorProtocol {
  init() {}
  func next() throws -> Int? { nil }
}

@available(SwiftStdlib 5.1, *)
actor SafeMutatingCall {
  private let iterator: Iterator

  public init() async throws {
    self.iterator = Iterator()
    _ = try await self.iterator.next()
  }
}


@MainActor
func testLocalFunctionIsolation() {
  func isolatedLocalFn() {}
  // expected-note@-1 {{calls to local function 'isolatedLocalFn()' from outside of its actor context are implicitly asynchronous}}
  // expected-note@-2 {{main actor isolation inferred from enclosing context}}


  nonisolated func nonisolatedLocalFn() {
    isolatedLocalFn()
    // expected-error@-1 {{call to main actor-isolated local function 'isolatedLocalFn()' in a synchronous nonisolated context}}
  }
}

class SuperWithIsolatedMethod {
  @MainActor
  func isolatedMethod() {}
}

class InferIsolationViaOverride: SuperWithIsolatedMethod {
  override func isolatedMethod() {}
  // expected-note@-1 {{calls to instance method 'isolatedMethod()' from outside of its actor context are implicitly asynchronous}}
  // expected-note@-2 {{main actor isolation inferred from overridden superclass method}}

  nonisolated func callIsolated() {
    isolatedMethod()
    // expected-error@-1 {{call to main actor-isolated instance method 'isolatedMethod()' in a synchronous nonisolated context}}
  }
}

struct ReferenceSelfDotMethods {
  @MainActor
  func mainActorAffinedFunction() {}

  nonisolated
  private func testCurry() -> (Self) -> (@MainActor () -> Void) {
    let functionRef = Self.mainActorAffinedFunction
    // warning goes away with InferSendableFromCaptures, see actor_isolation_swift6.swift
    return functionRef // expected-warning {{converting non-Sendable function value to '@MainActor @Sendable () -> Void' may introduce data races}}
  }

  @MainActor
  private func callOnMainActorOk() {
    let mainActorAffinedClosure = testCurry()(self)
    mainActorAffinedClosure()
  }

  nonisolated
  private func nonisolatedCallErrors() {
    let mainActorAffinedClosure = testCurry()(self)
    // expected-note@-1 {{calls to let 'mainActorAffinedClosure' from outside of its actor context are implicitly asynchronous}}
    mainActorAffinedClosure()
    // expected-error@-1 {{call to main actor-isolated let 'mainActorAffinedClosure' in a synchronous nonisolated context}}
  }
}

actor UserDefinedActorSelfDotMethod {
  func actorAffinedFunc() {} // expected-note {{calls to instance method 'actorAffinedFunc()' from outside of its actor context are implicitly asynchronous}}

  // Unfortunately we can't express the desired isolation of this returned closure statically to
  // be able to call it on the desired actor. This may be possible with the acceptance of
  // https://forums.swift.org/t/closure-isolation-control/70378 but I think we need more expressivity
  // in the type system to express this sort of curry.
  nonisolated
  private func testCurry() -> (UserDefinedActorSelfDotMethod) -> (@isolated(any) () -> Void) {
    let functionRef = Self.actorAffinedFunc // expected-error {{call to actor-isolated instance method 'actorAffinedFunc()' in a synchronous nonisolated context}}
    // error message changes with InferSendabaleFromCaptures - see actor_isolation_swift6.swift
    return functionRef // expected-error {{cannot convert return expression of type '(isolated Self) -> () -> ()' to return type '(UserDefinedActorSelfDotMethod) -> @isolated(any) () -> Void'}}
  }
}

func requireSendableInheritContext(@_inheritActorContext _: @Sendable () -> ()) {}
// expected-warning@-1 {{@_inheritActorContext only applies to '@isolated(any)' parameters or parameters with asynchronous function types; this will be an error in a future Swift language mode}}

actor InvalidInheritedActorIsolation {
  func actorFunction() {} // expected-note {{calls to instance method 'actorFunction()' from outside of its actor context are implicitly asynchronous}}

  func test() {
    requireSendableInheritContext {
      self.actorFunction()
      // expected-error@-1 {{call to actor-isolated instance method 'actorFunction()' in a synchronous nonisolated context}}
    }
  }
}

@MainActor
class InvalidInheritedGlobalActorIsolation {
  func mainActorFunction() {} // expected-note {{calls to instance method 'mainActorFunction()' from outside of its actor context are implicitly asynchronous}}

  func test() {
    requireSendableInheritContext {
      self.mainActorFunction()
      // expected-error@-1 {{call to main actor-isolated instance method 'mainActorFunction()' in a synchronous nonisolated context}}
    }
  }
}
