Files
swift-mirror/test/attr/attr_concurrent.swift
Kathy Gray 97dfc82255 Update tests to reflect type information in ambiguity resolution
All but 7 tests now passing. Those 7 tests either do not refer to these circumstances or do not seem to pass even when modified to accept type specifications.
2025-10-10 17:46:22 +01:00

160 lines
5.8 KiB
Swift

// RUN: %target-swift-frontend -typecheck -verify %s -enable-experimental-flow-sensitive-concurrent-captures
// REQUIRES: concurrency
// Concurrent attribute on a function type.
// expected-note@+1{{found candidate with type '(@Sendable (Int) -> Int) -> ()'}}
func f(_ fn: @Sendable (Int) -> Int) { }
// Okay to overload @Sendable vs. not concurrent
// expected-note@+1{{found candidate with type '((Int) -> Int) -> ()'}}
func f(_ fn: (Int) -> Int) { }
// Concurrent attribute with other function attributes.
func onEscaping(_ fn: @escaping @Sendable (Int) -> Int) { }
func onEscaping2(_ fn: @Sendable @escaping (Int) -> Int) { }
func onAutoclosure(_ fn: @autoclosure @Sendable () -> Int) { }
func onAutoclosure2(_ fn: @Sendable @autoclosure () -> Int) { }
func onEscapingAutoclosure(_ fn: @Sendable @autoclosure @escaping () -> Int) { }
func onEscapingAutoclosure2(_ fn: @escaping @autoclosure @Sendable () -> Int) { }
func acceptsConcurrent(_ fn: @Sendable (Int) -> Int) { }
func acceptsNonConcurrent(_ fn: (Int) -> Int) { }
@Sendable func negate(_ x: Int) -> Int { -x }
func passingConcurrentOrNot(
_ cfn: @Sendable (Int) -> Int,
ncfn: (Int) -> Int // expected-note{{parameter 'ncfn' is implicitly non-Sendable}}{{9-9=@Sendable }}
) {
// Ambiguous because preconcurrency code doesn't consider `@Sendable`.
f(cfn) // expected-error{{ambiguous use of 'f'}}
// Okay due to overloading
f(ncfn)
acceptsConcurrent(cfn) // okay
acceptsConcurrent(ncfn) // expected-warning{{passing non-Sendable parameter 'ncfn' to function expecting a '@Sendable' closure}}
acceptsNonConcurrent(cfn) // okay
acceptsNonConcurrent(ncfn) // okay
acceptsConcurrent(negate)
acceptsNonConcurrent(negate)
let _: Int = negate // expected-error{{cannot convert value of type '@Sendable (Int) -> Int' to specified type 'Int'}}
}
func closures() {
// Okay, inferring @Sendable
acceptsConcurrent { $0 }
acceptsConcurrent({ $0 })
acceptsConcurrent({ i in i })
acceptsConcurrent({ (i: Int) -> Int in
print(i)
return i
})
let closure1 = { $0 + 1 } // inferred to be non-Sendable
acceptsConcurrent(closure1) // expected-warning{{converting non-Sendable function value to '@Sendable (Int) -> Int' may introduce data races}}
}
// Mutation of captured locals from within @Sendable functions.
extension Int {
mutating func makeNegative() {
self = -self
}
func printMe() {
print(self)
}
}
func mutationOfLocal() {
var localInt = 17
acceptsConcurrent { i in
// Non-mutating accesses are okay
print(localInt + 17)
localInt.printMe()
// Mutations of locally-defined variables are fine.
var localResult = localInt + 1
print(localResult)
_ = {
localResult = localResult + 1
}()
// Mutations of captured variables executing concurrently are bad.
localInt = 17 // expected-warning{{mutation of captured var 'localInt' in concurrently-executing code}}
localInt += 1 // expected-warning{{mutation of captured var 'localInt' in concurrently-executing code}}
localInt.makeNegative() // expected-warning{{mutation of captured var 'localInt' in concurrently-executing code}}
_ = {
localInt = localInt + 12 // expected-warning{{mutation of captured var 'localInt' in concurrently-executing code}}
}()
return i + localInt
}
localInt = 20
}
struct NonTrivialValueType {
var int: Int = 0
var array: [Int] = []
var optArray: [Int]? = nil
}
func testCaseNonTrivialValue() {
var i = NonTrivialValueType()
var j = 0
acceptsConcurrent { value in
print(i.int)
print(i.array[0])
print(i.array[j])
print(i.optArray?[j] ?? 0)
print(i.optArray![j])
i.int = 5 // expected-warning{{mutation of captured var 'i' in concurrently-executing code}}
i.array[0] = 5 // expected-warning{{mutation of captured var 'i' in concurrently-executing code}}
return value
}
j = 17
}
func testExplicitConcurrentClosure() {
let fn = { @Sendable in
17
}
let _: String = fn // expected-error{{cannot convert value of type '@Sendable () -> Int' to specified type 'String'}}
}
class SuperSendable {
func runsInBackground(_: @Sendable () -> Void) {}
func runsInForeground(_: () -> Void) {} // expected-note {{overridden declaration is here}}
func runnableInBackground() -> @Sendable () -> Void { fatalError() } // expected-note {{overridden declaration is here}}
func runnableInForeground() -> () -> Void { fatalError() }
}
class SubSendable: SuperSendable {
override func runsInBackground(_: () -> Void) {}
override func runsInForeground(_: @Sendable () -> Void) {} // expected-warning {{declaration 'runsInForeground' has a type with different sendability from any potential overrides}}
override func runnableInBackground() -> () -> Void { fatalError() } // expected-warning {{declaration 'runnableInBackground()' has a type with different sendability from any potential overrides}}
override func runnableInForeground() -> @Sendable () -> Void { fatalError() }
}
protocol AbstractSendable {
func runsInBackground(_: @Sendable () -> Void)
func runsInForeground(_: () -> Void) // expected-note {{expected sendability to match requirement here}}
func runnableInBackground() -> @Sendable () -> Void // expected-note {{expected sendability to match requirement here}}
func runnableInForeground() -> () -> Void
}
struct ConcreteSendable: AbstractSendable {
func runsInBackground(_: () -> Void) {}
func runsInForeground(_: @Sendable () -> Void) {} // expected-warning {{sendability of function types in instance method 'runsInForeground' does not match requirement in protocol 'AbstractSendable'}}
func runnableInBackground() -> () -> Void { fatalError() } // expected-warning {{sendability of function types in instance method 'runnableInBackground()' does not match requirement in protocol 'AbstractSendable'}}
func runnableInForeground() -> @Sendable () -> Void { fatalError() }
}