1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
// 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() }
}
|