@@ -3790,13 +3790,22 @@ class ExprAvailabilityWalker : public ASTWalker {
3790
3790
}
3791
3791
3792
3792
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);
3800
3809
return Action::SkipNode (S);
3801
3810
}
3802
3811
@@ -4396,26 +4405,29 @@ void swift::diagnoseExprAvailability(const Expr *E, DeclContext *DC) {
4396
4405
namespace {
4397
4406
4398
4407
class StmtAvailabilityWalker : public BaseDiagnosticWalker {
4408
+ const Stmt *TopLevelStmt;
4399
4409
DeclContext *DC;
4400
- bool WalkRecursively;
4401
4410
4402
4411
public:
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 ) {}
4405
4414
4406
4415
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);
4411
4419
}
4412
4420
4413
4421
PreWalkResult<Expr *> walkToExprPre (Expr *E) override {
4414
- if (WalkRecursively)
4415
- diagnoseExprAvailability (E, DC);
4422
+ // Handled by ExprAvailabilityWalker.
4416
4423
return Action::SkipNode (E);
4417
4424
}
4418
4425
4426
+ PreWalkAction walkToDeclPre (Decl *D) override {
4427
+ // Handled by DeclAvailabilityChecker.
4428
+ return Action::SkipNode ();
4429
+ }
4430
+
4419
4431
PreWalkAction walkToTypeReprPre (TypeRepr *T) override {
4420
4432
auto where = ExportContext::forFunctionBody (DC, T->getStartLoc ());
4421
4433
diagnoseTypeReprAvailability (T, where);
@@ -4434,13 +4446,8 @@ class StmtAvailabilityWalker : public BaseDiagnosticWalker {
4434
4446
};
4435
4447
}
4436
4448
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);
4444
4451
const_cast <Stmt*>(S)->walk (walker);
4445
4452
}
4446
4453
0 commit comments