@@ -3593,17 +3593,9 @@ class ExprAvailabilityWalker : public BaseDiagnosticWalker {
35933593
35943594 ExprStack.push_back (E);
35953595
3596- if (auto *apply = dyn_cast<ApplyExpr>(E)) {
3597- bool preconcurrency = false ;
3598- auto *fn = apply->getFn ();
3599- if (auto *selfApply = dyn_cast<SelfApplyExpr>(fn)) {
3600- fn = selfApply->getFn ();
3601- }
3602- auto declRef = fn->getReferencedDecl ();
3603- if (auto *decl = declRef.getDecl ()) {
3604- preconcurrency = decl->preconcurrency ();
3605- }
3606- PreconcurrencyCalleeStack.push_back (preconcurrency);
3596+ if (isa<ApplyExpr>(E)) {
3597+ PreconcurrencyCalleeStack.push_back (
3598+ hasReferenceToPreconcurrencyDecl (E));
36073599 }
36083600
36093601 if (auto DR = dyn_cast<DeclRefExpr>(E)) {
@@ -3629,6 +3621,8 @@ class ExprAvailabilityWalker : public BaseDiagnosticWalker {
36293621 if (S->hasDecl ()) {
36303622 diagnoseDeclRefAvailability (S->getDecl (), S->getSourceRange (), S);
36313623 maybeDiagStorageAccess (S->getDecl ().getDecl (), S->getSourceRange (), DC);
3624+ PreconcurrencyCalleeStack.push_back (
3625+ hasReferenceToPreconcurrencyDecl (S));
36323626 }
36333627 }
36343628
@@ -3677,6 +3671,11 @@ class ExprAvailabilityWalker : public BaseDiagnosticWalker {
36773671 maybeDiagKeyPath (KP);
36783672 }
36793673 if (auto A = dyn_cast<AssignExpr>(E)) {
3674+ // Attempting to assign to a @preconcurrency declaration should
3675+ // downgrade Sendable conformance mismatches to warnings.
3676+ PreconcurrencyCalleeStack.push_back (
3677+ hasReferenceToPreconcurrencyDecl (A->getDest ()));
3678+
36803679 walkAssignExpr (A);
36813680 return Action::SkipChildren (E);
36823681 }
@@ -4007,6 +4006,41 @@ class ExprAvailabilityWalker : public BaseDiagnosticWalker {
40074006 Flags))
40084007 return ;
40094008 }
4009+
4010+ // / Check whether the given expression references any
4011+ // / @preconcurrency declarations.
4012+ // / Calls, subscripts, member references can have @preconcurrency
4013+ // / declarations at any point in their base chain.
4014+ bool hasReferenceToPreconcurrencyDecl (Expr *expr) {
4015+ if (auto declRef = expr->getReferencedDecl ()) {
4016+ if (declRef.getDecl ()->preconcurrency ())
4017+ return true ;
4018+ }
4019+
4020+ if (auto *selfApply = dyn_cast<SelfApplyExpr>(expr)) {
4021+ if (hasReferenceToPreconcurrencyDecl (selfApply->getFn ()))
4022+ return true ;
4023+
4024+ // Base could be a preconcurrency declaration i.e.
4025+ //
4026+ // @preconcurrency var x: [any Sendable]
4027+ // x.append(...)
4028+ //
4029+ // If thought `append` might not be `@preconcurrency`
4030+ // the "base" is.
4031+ return hasReferenceToPreconcurrencyDecl (selfApply->getBase ());
4032+ }
4033+
4034+ if (auto *LE = dyn_cast<LookupExpr>(expr)) {
4035+ // If subscript itself is not @preconcurrency, it's base could be.
4036+ return hasReferenceToPreconcurrencyDecl (LE->getBase ());
4037+ }
4038+
4039+ if (auto *apply = dyn_cast<ApplyExpr>(expr))
4040+ return hasReferenceToPreconcurrencyDecl (apply->getFn ());
4041+
4042+ return false ;
4043+ }
40104044};
40114045} // end anonymous namespace
40124046
0 commit comments