@@ -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
@@ -3707,6 +3701,11 @@ class ExprAvailabilityWalker : public BaseDiagnosticWalker {
37073701 maybeDiagKeyPath (KP);
37083702 }
37093703 if (auto A = dyn_cast<AssignExpr>(E)) {
3704+ // Attempting to assign to a @preconcurrency declaration should
3705+ // downgrade Sendable conformance mismatches to warnings.
3706+ PreconcurrencyCalleeStack.push_back (
3707+ hasReferenceToPreconcurrencyDecl (A->getDest ()));
3708+
37103709 walkAssignExpr (A);
37113710 return Action::SkipChildren (E);
37123711 }
@@ -4038,6 +4037,41 @@ class ExprAvailabilityWalker : public BaseDiagnosticWalker {
40384037 Flags))
40394038 return ;
40404039 }
4040+
4041+ // / Check whether the given expression references any
4042+ // / @preconcurrency declarations.
4043+ // / Calls, subscripts, member references can have @preconcurrency
4044+ // / declarations at any point in their base chain.
4045+ bool hasReferenceToPreconcurrencyDecl (Expr *expr) {
4046+ if (auto declRef = expr->getReferencedDecl ()) {
4047+ if (declRef.getDecl ()->preconcurrency ())
4048+ return true ;
4049+ }
4050+
4051+ if (auto *selfApply = dyn_cast<SelfApplyExpr>(expr)) {
4052+ if (hasReferenceToPreconcurrencyDecl (selfApply->getFn ()))
4053+ return true ;
4054+
4055+ // Base could be a preconcurrency declaration i.e.
4056+ //
4057+ // @preconcurrency var x: [any Sendable]
4058+ // x.append(...)
4059+ //
4060+ // If thought `append` might not be `@preconcurrency`
4061+ // the "base" is.
4062+ return hasReferenceToPreconcurrencyDecl (selfApply->getBase ());
4063+ }
4064+
4065+ if (auto *LE = dyn_cast<LookupExpr>(expr)) {
4066+ // If subscript itself is not @preconcurrency, it's base could be.
4067+ return hasReferenceToPreconcurrencyDecl (LE->getBase ());
4068+ }
4069+
4070+ if (auto *apply = dyn_cast<ApplyExpr>(expr))
4071+ return hasReferenceToPreconcurrencyDecl (apply->getFn ());
4072+
4073+ return false ;
4074+ }
40414075};
40424076} // end anonymous namespace
40434077
0 commit comments