Skip to content

Commit 05dcba1

Browse files
authored
Merge pull request #59655 from kavon/protocol-isolation-hole
prevent nonisolated mutation of isolated properties through an existential
2 parents 8b248f4 + e10a441 commit 05dcba1

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1693,6 +1693,11 @@ namespace {
16931693
return recordMutableVarParent(parent, inout->getSubExpr());
16941694
}
16951695

1696+
// Look through an expression that opens an existential
1697+
if (auto openExist = dyn_cast<OpenExistentialExpr>(subExpr)) {
1698+
return recordMutableVarParent(parent, openExist->getSubExpr());
1699+
}
1700+
16961701
return false;
16971702
}
16981703

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking
2+
// REQUIRES: concurrency
3+
4+
protocol P: Actor {
5+
func f()
6+
var prop: Int { get set } // expected-note 2 {{mutation of this property is only permitted within the actor}}
7+
}
8+
9+
actor A: P {
10+
var prop: Int = 0 // expected-note 2 {{mutation of this property is only permitted within the actor}}
11+
func f() {}
12+
}
13+
14+
func from_isolated_existential1(_ x: isolated any P) {
15+
x.f()
16+
x.prop += 1
17+
x.prop = 100
18+
}
19+
20+
func from_isolated_existential2(_ x: isolated any P) async {
21+
x.f()
22+
x.prop += 1
23+
x.prop = 100
24+
}
25+
26+
func from_nonisolated(_ x: any P) async {
27+
await x.f()
28+
x.prop += 1 // expected-error {{actor-isolated property 'prop' can not be mutated from a non-isolated context}}
29+
x.prop = 100 // expected-error {{actor-isolated property 'prop' can not be mutated from a non-isolated context}}
30+
}
31+
32+
func from_concrete(_ x: A) async {
33+
x.prop += 1 // expected-error {{actor-isolated property 'prop' can not be mutated from a non-isolated context}}
34+
x.prop = 100 // expected-error {{actor-isolated property 'prop' can not be mutated from a non-isolated context}}
35+
}
36+
37+
func from_isolated_concrete(_ x: isolated A) async {
38+
x.prop += 1
39+
x.prop = 100
40+
}
41+
42+
43+
// from https://github.com/apple/swift/issues/59573
44+
actor Act {
45+
var i = 0 // expected-note {{mutation of this property is only permitted within the actor}}
46+
}
47+
let act = Act()
48+
49+
func bad() async {
50+
// expected-warning@+2 {{no 'async' operations occur within 'await' expression}}
51+
// expected-error@+1 {{actor-isolated property 'i' can not be mutated from a non-isolated context}}
52+
await act.i = 666
53+
}
54+
55+
protocol Proto: Actor {
56+
var i: Int { get set } // expected-note 2 {{mutation of this property is only permitted within the actor}}
57+
}
58+
extension Act: Proto {}
59+
60+
func good() async {
61+
// expected-warning@+2 {{no 'async' operations occur within 'await' expression}}
62+
// expected-error@+1 {{actor-isolated property 'i' can not be mutated from a non-isolated context}}
63+
await (act as any Proto).i = 42
64+
let aIndirect: any Proto = act
65+
66+
// expected-warning@+2 {{no 'async' operations occur within 'await' expression}}
67+
// expected-error@+1 {{actor-isolated property 'i' can not be mutated from a non-isolated context}}
68+
await aIndirect.i = 777
69+
}

0 commit comments

Comments
 (0)