Skip to content

Commit 5e17dc4

Browse files
committed
Only traverse closures once
So closures are in a PatternBindingDecl. Since we have an entry-point into PatternBindingDecl that gets hit for every one of them, we used to traverse the PBD's that are declared inside of the FunctionDecls twice. This patch stops us from actually traversing into the PBD from the checker, and instead pulling out the initializers of interest and walking each expression separately.
1 parent c3e725f commit 5e17dc4

File tree

2 files changed

+35
-10
lines changed

2 files changed

+35
-10
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3095,13 +3095,11 @@ class CompletionHandlerUsageChecker final : public ASTWalker {
30953095
public:
30963096
CompletionHandlerUsageChecker(ASTContext &ctx) : ctx(ctx) {}
30973097

3098+
bool walkToDeclPre(Decl *D) override { return !isa<PatternBindingDecl>(D); }
3099+
30983100
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
3099-
if (ClosureExpr *closure = dyn_cast<ClosureExpr>(expr)) {
3100-
if (closure->isBodyAsync())
3101-
return {true, closure};
3102-
else
3103-
return {true, nullptr};
3104-
}
3101+
if (ClosureExpr *closure = dyn_cast<ClosureExpr>(expr))
3102+
return {closure->isBodyAsync(), closure};
31053103

31063104
if (ApplyExpr *call = dyn_cast<ApplyExpr>(expr)) {
31073105
if (DeclRefExpr *fnDeclExpr = dyn_cast<DeclRefExpr>(call->getFn())) {
@@ -3116,8 +3114,7 @@ class CompletionHandlerUsageChecker final : public ASTWalker {
31163114
TypeCheckCompletionHandlerAsyncAttrRequest{
31173115
cast<AbstractFunctionDecl>(fnDecl), asyncAltAttr},
31183116
false)) {
3119-
return {true,
3120-
nullptr}; // This didn't typecheck, don't traverse down
3117+
return {false, call};
31213118
}
31223119
ctx.Diags.diagnose(call->getLoc(), diag::warn_use_async_alternative);
31233120
ctx.Diags.diagnose(asyncAltAttr->AsyncFunctionDecl->getLoc(),
@@ -3142,5 +3139,8 @@ void swift::checkFunctionAsyncUsage(AbstractFunctionDecl *decl) {
31423139

31433140
void swift::checkPatternBindingDeclAsyncUsage(PatternBindingDecl *decl) {
31443141
CompletionHandlerUsageChecker checker(decl->getASTContext());
3145-
decl->walk(checker);
3142+
for (Expr *init : decl->initializers()) {
3143+
if (auto closure = dyn_cast_or_null<ClosureExpr>(init))
3144+
closure->walk(checker);
3145+
}
31463146
}

test/attr/attr_completionhandlerasync.swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// Parsing
88
// ===================
99

10-
// expected-note@+1 3 {{'asyncFunc' declared here}}
10+
// expected-note@+1 4 {{'asyncFunc' declared here}}
1111
func asyncFunc(_ text: String) async -> Int { }
1212

1313
@completionHandlerAsync("asyncFunc(_:)", completionHandlerIndex: 1)
@@ -176,3 +176,28 @@ let asyncGlobalClosure = { () async -> () in
176176
// expected-warning@+1:3{{consider using asynchronous alternative function}}
177177
goodFunc1(value: "neat") { _ in }
178178
}
179+
180+
class ClassCallingAsyncStuff {
181+
// expected-note@+1 3 {{'asyncFunc()' declared here}}
182+
func asyncFunc() async {}
183+
184+
@completionHandlerAsync("asyncFunc()")
185+
func compHandlerFunc(handler: @escaping () -> ()) {}
186+
187+
@completionHandlerAsync("asyncFunc()")
188+
func compAsyncHandlerFunc(handler: @escaping () async -> ()) {}
189+
190+
func async1() async {
191+
// expected-warning@+1{{consider using asynchronous alternative function}}
192+
goodFunc1(value: "hi") { _ in }
193+
194+
// expected-warning@+1{{consider using asynchronous alternative function}}
195+
compAsyncHandlerFunc() { [self] () async -> () in
196+
// expected-warning@+1{{consider using asynchronous alternative function}}
197+
compAsyncHandlerFunc() { [self] () async -> () in
198+
// expected-warning@+1{{consider using asynchronous alternative function}}
199+
compHandlerFunc() { print("foo") }
200+
}
201+
}
202+
}
203+
}

0 commit comments

Comments
 (0)