@@ -3623,17 +3623,9 @@ class ExprAvailabilityWalker : public BaseDiagnosticWalker {
3623
3623
3624
3624
ExprStack.push_back (E);
3625
3625
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));
3637
3629
}
3638
3630
3639
3631
if (auto DR = dyn_cast<DeclRefExpr>(E)) {
@@ -3659,6 +3651,8 @@ class ExprAvailabilityWalker : public BaseDiagnosticWalker {
3659
3651
if (S->hasDecl ()) {
3660
3652
diagnoseDeclRefAvailability (S->getDecl (), S->getSourceRange (), S);
3661
3653
maybeDiagStorageAccess (S->getDecl ().getDecl (), S->getSourceRange (), DC);
3654
+ PreconcurrencyCalleeStack.push_back (
3655
+ hasReferenceToPreconcurrencyDecl (S));
3662
3656
}
3663
3657
}
3664
3658
@@ -3707,6 +3701,11 @@ class ExprAvailabilityWalker : public BaseDiagnosticWalker {
3707
3701
maybeDiagKeyPath (KP);
3708
3702
}
3709
3703
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
+
3710
3709
walkAssignExpr (A);
3711
3710
return Action::SkipChildren (E);
3712
3711
}
@@ -4038,6 +4037,41 @@ class ExprAvailabilityWalker : public BaseDiagnosticWalker {
4038
4037
Flags))
4039
4038
return ;
4040
4039
}
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
+ }
4041
4075
};
4042
4076
} // end anonymous namespace
4043
4077
0 commit comments