Skip to content

Commit 5154341

Browse files
committed
Make isolated parameter checking work with existential values.
We needed to look through opaque value expressions. Fixes rdar://84581926.
1 parent 246896f commit 5154341

File tree

2 files changed

+43
-6
lines changed

2 files changed

+43
-6
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,7 @@ namespace {
10251025
ASTContext &ctx;
10261026
SmallVector<const DeclContext *, 4> contextStack;
10271027
SmallVector<ApplyExpr*, 4> applyStack;
1028+
SmallVector<std::pair<OpaqueValueExpr *, Expr *>, 4> opaqueValues;
10281029

10291030
/// Keeps track of the capture context of variables that have been
10301031
/// explicitly captured in closures.
@@ -1244,6 +1245,13 @@ namespace {
12441245
}
12451246

12461247
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
1248+
if (auto *openExistential = dyn_cast<OpenExistentialExpr>(expr)) {
1249+
opaqueValues.push_back({
1250+
openExistential->getOpaqueValue(),
1251+
openExistential->getExistentialValue()});
1252+
return { true, expr };
1253+
}
1254+
12471255
if (auto *closure = dyn_cast<AbstractClosureExpr>(expr)) {
12481256
closure->setActorIsolation(determineClosureIsolation(closure));
12491257
contextStack.push_back(closure);
@@ -1363,6 +1371,12 @@ namespace {
13631371
}
13641372

13651373
Expr *walkToExprPost(Expr *expr) override {
1374+
if (auto *openExistential = dyn_cast<OpenExistentialExpr>(expr)) {
1375+
assert(opaqueValues.back().first == openExistential->getOpaqueValue());
1376+
opaqueValues.pop_back();
1377+
return expr;
1378+
}
1379+
13661380
if (auto *closure = dyn_cast<AbstractClosureExpr>(expr)) {
13671381
assert(contextStack.back() == closure);
13681382
contextStack.pop_back();
@@ -1398,7 +1412,7 @@ namespace {
13981412
private:
13991413
/// Find the directly-referenced parameter or capture of a parameter for
14001414
/// for the given expression.
1401-
static VarDecl *getReferencedParamOrCapture(Expr *expr) {
1415+
VarDecl *getReferencedParamOrCapture(Expr *expr) {
14021416
// Look through identity expressions and implicit conversions.
14031417
Expr *prior;
14041418
do {
@@ -1408,6 +1422,16 @@ namespace {
14081422

14091423
if (auto conversion = dyn_cast<ImplicitConversionExpr>(expr))
14101424
expr = conversion->getSubExpr();
1425+
1426+
// Map opaque values.
1427+
if (auto opaqueValue = dyn_cast<OpaqueValueExpr>(expr)) {
1428+
for (const auto &known : opaqueValues) {
1429+
if (known.first == opaqueValue) {
1430+
expr = known.second;
1431+
break;
1432+
}
1433+
}
1434+
}
14111435
} while (prior != expr);
14121436

14131437
// 'super' references always act on a 'self' variable.
@@ -1550,7 +1574,7 @@ namespace {
15501574
}
15511575

15521576
/// If the expression is a reference to `self`, the `self` declaration.
1553-
static VarDecl *getReferencedSelf(Expr *expr) {
1577+
VarDecl *getReferencedSelf(Expr *expr) {
15541578
if (auto selfVar = getReferencedParamOrCapture(expr))
15551579
if (selfVar->isSelfParameter() || selfVar->isSelfParamCapture())
15561580
return selfVar;
@@ -1593,8 +1617,8 @@ namespace {
15931617
// detect if it is a distributed actor, to provide better isolation notes
15941618

15951619
auto isDistributedActor = false;
1596-
if (auto dc = dyn_cast<ClassDecl>(decl->getDeclContext()))
1597-
isDistributedActor = dc->isDistributedActor();
1620+
if (auto nominal = decl->getDeclContext()->getSelfNominalTypeDecl())
1621+
isDistributedActor = nominal->isDistributedActor();
15981622

15991623
// FIXME: Make this diagnostic more sensitive to the isolation context of
16001624
// the declaration.
@@ -2538,8 +2562,8 @@ namespace {
25382562
case ActorIsolationRestriction::Unsafe:
25392563
// This case is hit when passing actor state inout to functions in some
25402564
// cases. The error is emitted by diagnoseInOutArg.
2541-
auto classDecl = dyn_cast<ClassDecl>(member->getDeclContext());
2542-
if (classDecl && classDecl->isDistributedActor()) {
2565+
auto nominal = member->getDeclContext()->getSelfNominalTypeDecl();
2566+
if (nominal && nominal->isDistributedActor()) {
25432567
auto funcDecl = dyn_cast<AbstractFunctionDecl>(member);
25442568
if (funcDecl && !funcDecl->isStatic()) {
25452569
member->diagnose(diag::distributed_actor_isolated_method);

test/Concurrency/isolated_parameters.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,16 @@ func testIsolatedClosureInference(a: A) {
131131
a2.f()
132132
}
133133
}
134+
135+
// "isolated" existential parameters.
136+
protocol P2: Actor {
137+
func m()
138+
}
139+
140+
@available(SwiftStdlib 5.1, *)
141+
func testExistentialIsolated(a: isolated P2, b: P2) async {
142+
a.m()
143+
await b.m()
144+
b.m() // expected-error{{expression is 'async' but is not marked with 'await'}}
145+
// expected-note@-1{{calls to instance method 'm()' from outside of its actor context are implicitly asynchronous}}
146+
}

0 commit comments

Comments
 (0)