mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This matches send non sendable but importantly also makes it clear that we are talking about something that doesn't conform to the Sendable protocol which is capitalized. rdar://151802975
160 lines
5.8 KiB
Swift
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 this candidate}}
|
|
func f(_ fn: @Sendable (Int) -> Int) { }
|
|
|
|
// Okay to overload @Sendable vs. not concurrent
|
|
// expected-note@+1{{found this candidate}}
|
|
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() }
|
|
}
|