@@ -3790,13 +3790,22 @@ class ExprAvailabilityWalker : public ASTWalker {
37903790 }
37913791
37923792 PreWalkResult<Stmt *> walkToStmtPre (Stmt *S) override {
3793-
3794- // We end up here when checking the output of the result builder transform,
3795- // which includes closures that are not "separately typechecked" and yet
3796- // contain statements and declarations. We need to walk them recursively,
3797- // since these availability for these statements is not diagnosed from
3798- // typeCheckStmt() as usual.
3799- diagnoseStmtAvailability (S, Where.getDeclContext (), /* walkRecursively=*/ true );
3793+ // We need to recursively call diagnoseExprAvailability for any
3794+ // sub-expressions in the statement since the availability context may
3795+ // differ, e.g for things like `guard #available(...)`.
3796+ class StmtRecurseWalker : public BaseDiagnosticWalker {
3797+ DeclContext *DC;
3798+
3799+ public:
3800+ StmtRecurseWalker (DeclContext *DC) : DC(DC) {}
3801+
3802+ PreWalkResult<Expr *> walkToExprPre (Expr *E) override {
3803+ diagnoseExprAvailability (E, DC);
3804+ return Action::SkipNode (E);
3805+ }
3806+ };
3807+ StmtRecurseWalker W (Where.getDeclContext ());
3808+ S->walk (W);
38003809 return Action::SkipNode (S);
38013810 }
38023811
@@ -4396,26 +4405,29 @@ void swift::diagnoseExprAvailability(const Expr *E, DeclContext *DC) {
43964405namespace {
43974406
43984407class StmtAvailabilityWalker : public BaseDiagnosticWalker {
4408+ const Stmt *TopLevelStmt;
43994409 DeclContext *DC;
4400- bool WalkRecursively;
44014410
44024411public:
4403- explicit StmtAvailabilityWalker (DeclContext *dc, bool walkRecursively )
4404- : DC(dc ), WalkRecursively(walkRecursively ) {}
4412+ explicit StmtAvailabilityWalker (const Stmt *S, DeclContext *dc )
4413+ : TopLevelStmt(S ), DC(dc ) {}
44054414
44064415 PreWalkResult<Stmt *> walkToStmtPre (Stmt *S) override {
4407- if (!WalkRecursively && isa<BraceStmt>(S))
4408- return Action::SkipNode (S);
4409-
4410- return Action::Continue (S);
4416+ // `diagnoseStmtAvailability` is called for every statement, so we don't
4417+ // want to walk into any nested statements.
4418+ return Action::VisitNodeIf (S == TopLevelStmt, S);
44114419 }
44124420
44134421 PreWalkResult<Expr *> walkToExprPre (Expr *E) override {
4414- if (WalkRecursively)
4415- diagnoseExprAvailability (E, DC);
4422+ // Handled by ExprAvailabilityWalker.
44164423 return Action::SkipNode (E);
44174424 }
44184425
4426+ PreWalkAction walkToDeclPre (Decl *D) override {
4427+ // Handled by DeclAvailabilityChecker.
4428+ return Action::SkipNode ();
4429+ }
4430+
44194431 PreWalkAction walkToTypeReprPre (TypeRepr *T) override {
44204432 auto where = ExportContext::forFunctionBody (DC, T->getStartLoc ());
44214433 diagnoseTypeReprAvailability (T, where);
@@ -4434,13 +4446,8 @@ class StmtAvailabilityWalker : public BaseDiagnosticWalker {
44344446};
44354447}
44364448
4437- void swift::diagnoseStmtAvailability (const Stmt *S, DeclContext *DC,
4438- bool walkRecursively) {
4439- // We'll visit the individual statements when we check them.
4440- if (!walkRecursively && isa<BraceStmt>(S))
4441- return ;
4442-
4443- StmtAvailabilityWalker walker (DC, walkRecursively);
4449+ void swift::diagnoseStmtAvailability (const Stmt *S, DeclContext *DC) {
4450+ StmtAvailabilityWalker walker (S, DC);
44444451 const_cast <Stmt*>(S)->walk (walker);
44454452}
44464453
0 commit comments