-
Notifications
You must be signed in to change notification settings - Fork 10.5k
/
Copy pathattr_concurrent.swift
127 lines (101 loc) · 3.75 KB
/
attr_concurrent.swift
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
// RUN: %target-swift-frontend -typecheck -verify %s -enable-experimental-flow-sensitive-concurrent-captures
// REQUIRES: concurrency
// Concurrent attribute on a function type.
func f(_ fn: @Sendable (Int) -> Int) { }
// Okay to overload @Sendable vs. not concurrent
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-concurrent}}{{9-9=@Sendable }}
) {
// Okay due to overloading
f(cfn)
f(ncfn)
acceptsConcurrent(cfn) // okay
acceptsConcurrent(ncfn) // expected-error{{passing non-concurrent 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-concurrent
acceptsConcurrent(closure1) // expected-error{{converting non-concurrent 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-error{{mutation of captured var 'localInt' in concurrently-executing code}}
localInt += 1 // expected-error{{mutation of captured var 'localInt' in concurrently-executing code}}
localInt.makeNegative() // expected-error{{mutation of captured var 'localInt' in concurrently-executing code}}
_ = {
localInt = localInt + 12 // expected-error{{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-error{{mutation of captured var 'i' in concurrently-executing code}}
i.array[0] = 5 // expected-error{{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'}}
}