mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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.
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 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() }
|
|
}
|