Skip to content

Commit 05367ce

Browse files
committed
[TypeChecker] Make sure that @preconcurrency use is detected in base expressions
This expands swiftlang#77510 to base expressions of calls, subscripts and members to make sure that if the base has `@preconcurrency` declaration at some level. Otherwise, the availability checker won't appropriately downgrade unavailable `Sendable` conformances for `@preconcurrency` declarations. (cherry picked from commit aa0b356)
1 parent 96f484b commit 05367ce

File tree

2 files changed

+59
-11
lines changed

2 files changed

+59
-11
lines changed

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3623,17 +3623,9 @@ class ExprAvailabilityWalker : public BaseDiagnosticWalker {
36233623

36243624
ExprStack.push_back(E);
36253625

3626-
if (auto *apply = dyn_cast<ApplyExpr>(E)) {
3627-
bool preconcurrency = false;
3628-
auto *fn = apply->getFn();
3629-
if (auto *selfApply = dyn_cast<SelfApplyExpr>(fn)) {
3630-
fn = selfApply->getFn();
3631-
}
3632-
auto declRef = fn->getReferencedDecl();
3633-
if (auto *decl = declRef.getDecl()) {
3634-
preconcurrency = decl->preconcurrency();
3635-
}
3636-
PreconcurrencyCalleeStack.push_back(preconcurrency);
3626+
if (isa<ApplyExpr>(E)) {
3627+
PreconcurrencyCalleeStack.push_back(
3628+
hasReferenceToPreconcurrencyDecl(E));
36373629
}
36383630

36393631
if (auto DR = dyn_cast<DeclRefExpr>(E)) {
@@ -3659,6 +3651,8 @@ class ExprAvailabilityWalker : public BaseDiagnosticWalker {
36593651
if (S->hasDecl()) {
36603652
diagnoseDeclRefAvailability(S->getDecl(), S->getSourceRange(), S);
36613653
maybeDiagStorageAccess(S->getDecl().getDecl(), S->getSourceRange(), DC);
3654+
PreconcurrencyCalleeStack.push_back(
3655+
hasReferenceToPreconcurrencyDecl(S));
36623656
}
36633657
}
36643658

@@ -4038,6 +4032,41 @@ class ExprAvailabilityWalker : public BaseDiagnosticWalker {
40384032
Flags))
40394033
return;
40404034
}
4035+
4036+
/// Check whether the given expression references any
4037+
/// @preconcurrency declarations.
4038+
/// Calls, subscripts, member references can have @preconcurrency
4039+
/// declarations at any point in their base chain.
4040+
bool hasReferenceToPreconcurrencyDecl(Expr *expr) {
4041+
if (auto declRef = expr->getReferencedDecl()) {
4042+
if (declRef.getDecl()->preconcurrency())
4043+
return true;
4044+
}
4045+
4046+
if (auto *selfApply = dyn_cast<SelfApplyExpr>(expr)) {
4047+
if (hasReferenceToPreconcurrencyDecl(selfApply->getFn()))
4048+
return true;
4049+
4050+
// Base could be a preconcurrency declaration i.e.
4051+
//
4052+
// @preconcurrency var x: [any Sendable]
4053+
// x.append(...)
4054+
//
4055+
// If thought `append` might not be `@preconcurrency`
4056+
// the "base" is.
4057+
return hasReferenceToPreconcurrencyDecl(selfApply->getBase());
4058+
}
4059+
4060+
if (auto *LE = dyn_cast<LookupExpr>(expr)) {
4061+
// If subscript itself is not @preconcurrency, it's base could be.
4062+
return hasReferenceToPreconcurrencyDecl(LE->getBase());
4063+
}
4064+
4065+
if (auto *apply = dyn_cast<ApplyExpr>(expr))
4066+
return hasReferenceToPreconcurrencyDecl(apply->getFn());
4067+
4068+
return false;
4069+
}
40414070
};
40424071
} // end anonymous namespace
40434072

test/Concurrency/predates_concurrency_swift6.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,22 @@ func testErasureDowngrade(ns: NotSendable, us: UnavailableSendable, c: C) {
289289
// expected-error@-1 {{conformance of 'UnavailableSendable' to 'Sendable' is unavailable}}
290290
}
291291
}
292+
293+
// The member itself could be non-preconcurrency but the base could be.
294+
do {
295+
@preconcurrency var d: [String: any Sendable] = [:]
296+
297+
let data: [String: Any] = [:]
298+
d.merge(data, uniquingKeysWith: { _, rhs in rhs})
299+
// expected-warning@-1 {{type 'Any' does not conform to the 'Sendable' protocol}}
300+
301+
struct Test {
302+
@preconcurrency var info: [String: any Sendable] = [:]
303+
}
304+
305+
func test(s: inout Test) {
306+
s.info["hello"] = { }
307+
// expected-warning@-1 {{type '() -> ()' does not conform to the 'Sendable' protocol}}
308+
// expected-note@-2 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
309+
}
310+
}

0 commit comments

Comments
 (0)