Skip to content

Commit dabccf6

Browse files
committed
[Concurrency] Infer @asyncHandler from protocol requirements.
Similar to what we do with function builders, infer @asyncHandler from for witnesses to @asyncHandler protocol requirements.
1 parent 235be5e commit dabccf6

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

lib/Sema/TypeCheckAttr.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "swift/AST/NameLookupRequests.h"
3030
#include "swift/AST/ParameterList.h"
3131
#include "swift/AST/PropertyWrappers.h"
32+
#include "swift/AST/ProtocolConformance.h"
3233
#include "swift/AST/SourceFile.h"
3334
#include "swift/AST/StorageImpl.h"
3435
#include "swift/AST/TypeCheckRequests.h"
@@ -5248,5 +5249,58 @@ bool IsAsyncHandlerRequest::evaluate(
52485249
return true;
52495250
}
52505251

5252+
// Are we in a context where inference is possible?
5253+
auto dc = func->getDeclContext();
5254+
if (!dc->isTypeContext() || !dc->getParentSourceFile() ||
5255+
isa<ProtocolDecl>(dc) || !func->hasBody())
5256+
return false;
5257+
5258+
// Is it possible to infer @asyncHandler for this function at all?
5259+
if (checkAsyncHandler(func, /*diagnose=*/false))
5260+
return false;
5261+
5262+
// Add an implicit @asyncHandler attribute and return true. We're done.
5263+
auto addImplicitAsyncHandlerAttr = [&] {
5264+
func->getAttrs().add(new (func->getASTContext()) AsyncHandlerAttr(true));
5265+
return true;
5266+
};
5267+
5268+
// Check whether any of the conformances in the context of the function
5269+
// implies @asyncHandler.
5270+
{
5271+
auto idc = cast<IterableDeclContext>(dc->getAsDecl());
5272+
auto conformances = evaluateOrDefault(
5273+
dc->getASTContext().evaluator,
5274+
LookupAllConformancesInContextRequest{idc}, { });
5275+
5276+
for (auto conformance : conformances) {
5277+
auto protocol = conformance->getProtocol();
5278+
for (auto found : protocol->lookupDirect(func->getName())) {
5279+
if (!isa<ProtocolDecl>(found->getDeclContext()))
5280+
continue;
5281+
5282+
auto requirement = dyn_cast<FuncDecl>(found);
5283+
if (!requirement)
5284+
continue;
5285+
5286+
if (!requirement->isAsyncHandler())
5287+
continue;
5288+
5289+
auto witness = conformance->getWitnessDecl(requirement);
5290+
if (witness != func)
5291+
continue;
5292+
5293+
return addImplicitAsyncHandlerAttr();
5294+
}
5295+
}
5296+
}
5297+
5298+
// Look through dynamic replacements.
5299+
if (auto replaced = func->getDynamicallyReplacedDecl()) {
5300+
if (auto replacedFunc = dyn_cast<FuncDecl>(replaced))
5301+
if (replacedFunc->isAsyncHandler())
5302+
return addImplicitAsyncHandlerAttr();
5303+
}
5304+
52515305
return false;
52525306
}

test/attr/asynchandler.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,16 @@ struct X {
3737
@asyncHandler init() { }
3838
// expected-error@-1{{@asyncHandler may only be used on 'func' declarations}}
3939
}
40+
41+
42+
// Inference of @asyncHandler
43+
protocol P {
44+
@asyncHandler func callback()
45+
}
46+
47+
extension X: P {
48+
func callback() {
49+
// okay, it's an async context
50+
let _ = await globalAsyncFunction()
51+
}
52+
}

0 commit comments

Comments
 (0)