Skip to content

Commit bdd7d83

Browse files
committed
Requestify @completionHandlerAsync typechecking
This patch puts the type-checking of @completionHandlerAsync behind a request. We need to be able to request that it gets computed when checking for warnings of top-level code and global variables that are closures. The current order that these get traversed for typechecking is in declaration ordering, so if we have a global async closure that calls the completion handler function declared before the completion handler function declaration, we won't have typechecked the attribute and resolved the async function declaration yet. This means that we won't emit the warning, which is bad. By requestifying it, we can request that the attribute get typechecked and resolved earlier and verify that the thing typechecks before we do anything else.
1 parent fe10f31 commit bdd7d83

File tree

3 files changed

+81
-39
lines changed

3 files changed

+81
-39
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2936,6 +2936,26 @@ class ConditionalRequirementsRequest
29362936
bool isCached() const { return true; }
29372937
};
29382938

2939+
class TypeCheckCompletionHandlerAsyncAttrRequest
2940+
: public SimpleRequest<TypeCheckCompletionHandlerAsyncAttrRequest,
2941+
bool(AbstractFunctionDecl *,
2942+
CompletionHandlerAsyncAttr *),
2943+
RequestFlags::Cached> {
2944+
public:
2945+
using SimpleRequest::SimpleRequest;
2946+
2947+
private:
2948+
friend SimpleRequest;
2949+
2950+
bool evaluate(Evaluator &evaluator,
2951+
AbstractFunctionDecl *attachedFucntionDecl,
2952+
CompletionHandlerAsyncAttr *attr) const;
2953+
2954+
public:
2955+
// Caching
2956+
bool isCached() const { return true; }
2957+
};
2958+
29392959
void simple_display(llvm::raw_ostream &out, Type value);
29402960
void simple_display(llvm::raw_ostream &out, const TypeRepr *TyR);
29412961
void simple_display(llvm::raw_ostream &out, ImplicitMemberAction action);

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,3 +323,6 @@ SWIFT_REQUEST(TypeChecker, SynthesizeMainFunctionRequest,
323323
SWIFT_REQUEST(TypeChecker, GetImplicitSendableRequest,
324324
NormalProtocolConformance *(NominalTypeDecl *),
325325
Cached, NoLocationInfo)
326+
SWIFT_REQUEST(TypeChecker, TypeCheckCompletionHandlerAsyncAttrRequest,
327+
bool (AbstractFunctionDecl *, CompletionHandlerAsyncAttr *),
328+
Cached, NoLocationInfo)

lib/Sema/TypeCheckAttr.cpp

Lines changed: 58 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5609,7 +5609,18 @@ void TypeChecker::checkClosureAttributes(ClosureExpr *closure) {
56095609

56105610
void AttributeChecker::visitCompletionHandlerAsyncAttr(
56115611
CompletionHandlerAsyncAttr *attr) {
5612+
AbstractFunctionDecl *AFD = dyn_cast<AbstractFunctionDecl>(D);
5613+
if (!AFD)
5614+
return;
5615+
5616+
evaluateOrDefault(Ctx.evaluator,
5617+
TypeCheckCompletionHandlerAsyncAttrRequest{AFD, attr}, {});
5618+
}
56125619

5620+
bool TypeCheckCompletionHandlerAsyncAttrRequest::evaluate(
5621+
Evaluator &evaluator, AbstractFunctionDecl *attachedFunctionDecl,
5622+
CompletionHandlerAsyncAttr *attr) const {
5623+
auto &Diags = attachedFunctionDecl->getASTContext().Diags;
56135624
// Check phases:
56145625
// 1. Attached function shouldn't be async and should have enough args
56155626
// to have a completion handler
@@ -5621,30 +5632,29 @@ void AttributeChecker::visitCompletionHandlerAsyncAttr(
56215632
// - Do some sanity checking on types
56225633

56235634
// Phase 1: Typecheck the function the attribute is attached to
5624-
auto attachedFunctionDecl = cast<AbstractFunctionDecl>(D);
56255635
if (attachedFunctionDecl->hasAsync()) {
5626-
diagnose(attr->getLocation(),
5627-
diag::attr_completion_handler_async_handler_not_func, attr);
5628-
diagnose(attachedFunctionDecl->getAsyncLoc(),
5629-
diag::note_attr_function_declared_async);
5630-
return;
5636+
Diags.diagnose(attr->getLocation(),
5637+
diag::attr_completion_handler_async_handler_not_func, attr);
5638+
Diags.diagnose(attachedFunctionDecl->getAsyncLoc(),
5639+
diag::note_attr_function_declared_async);
5640+
return false;
56315641
}
56325642

56335643
const ParameterList *attachedFunctionParams =
56345644
attachedFunctionDecl->getParameters();
56355645
assert(attachedFunctionParams && "Attached function has no parameter list");
56365646
if (attachedFunctionParams->size() == 0) {
5637-
diagnose(attr->getLocation(),
5638-
diag::attr_completion_handler_async_handler_not_func, attr);
5639-
return;
5647+
Diags.diagnose(attr->getLocation(),
5648+
diag::attr_completion_handler_async_handler_not_func, attr);
5649+
return false;
56405650
}
56415651
size_t completionHandlerIndex = attr->CompletionHandlerIndexLoc.isValid()
56425652
? attr->CompletionHandlerIndex
56435653
: attachedFunctionParams->size() - 1;
56445654
if (attachedFunctionParams->size() < completionHandlerIndex) {
5645-
diagnose(attr->CompletionHandlerIndexLoc,
5646-
diag::attr_completion_handler_async_handler_out_of_range);
5647-
return;
5655+
Diags.diagnose(attr->CompletionHandlerIndexLoc,
5656+
diag::attr_completion_handler_async_handler_out_of_range);
5657+
return false;
56485658
}
56495659

56505660
// Phase 2: Typecheck the completion handler
@@ -5654,14 +5664,17 @@ void AttributeChecker::visitCompletionHandlerAsyncAttr(
56545664
AnyFunctionType *handlerType =
56555665
completionHandlerParamDecl->getType()->getAs<AnyFunctionType>();
56565666
if (!handlerType) {
5657-
diagnose(attr->getLocation(),
5658-
diag::attr_completion_handler_async_handler_not_func, attr);
5659-
diagnose(completionHandlerParamDecl->getTypeRepr()->getLoc(),
5660-
diag::note_attr_completion_handler_async_type_is_not_function,
5661-
completionHandlerParamDecl->getType())
5667+
Diags.diagnose(attr->getLocation(),
5668+
diag::attr_completion_handler_async_handler_not_func,
5669+
attr);
5670+
Diags
5671+
.diagnose(
5672+
completionHandlerParamDecl->getTypeRepr()->getLoc(),
5673+
diag::note_attr_completion_handler_async_type_is_not_function,
5674+
completionHandlerParamDecl->getType())
56625675
.highlight(
56635676
completionHandlerParamDecl->getTypeRepr()->getSourceRange());
5664-
return;
5677+
return false;
56655678
}
56665679

56675680
auto handlerTypeRepr =
@@ -5678,27 +5691,31 @@ void AttributeChecker::visitCompletionHandlerAsyncAttr(
56785691
const bool hasError = missingVoid | hasAutoclosure | !hasEscaping;
56795692

56805693
if (hasError) {
5681-
diagnose(attr->getLocation(),
5682-
diag::attr_completion_handler_async_handler_not_func, attr);
5694+
Diags.diagnose(attr->getLocation(),
5695+
diag::attr_completion_handler_async_handler_not_func,
5696+
attr);
56835697

56845698
if (missingVoid)
5685-
diagnose(completionHandlerParamDecl->getLoc(),
5686-
diag::note_attr_completion_function_must_return_void)
5699+
Diags
5700+
.diagnose(completionHandlerParamDecl->getLoc(),
5701+
diag::note_attr_completion_function_must_return_void)
56875702
.highlight(
56885703
completionHandlerParamDecl->getTypeRepr()->getSourceRange());
56895704

56905705
if (!hasEscaping)
5691-
diagnose(completionHandlerParamDecl->getLoc(),
5692-
diag::note_attr_completion_handler_async_handler_attr_req,
5693-
true, "escaping")
5706+
Diags
5707+
.diagnose(completionHandlerParamDecl->getLoc(),
5708+
diag::note_attr_completion_handler_async_handler_attr_req,
5709+
true, "escaping")
56945710
.highlight(
56955711
completionHandlerParamDecl->getTypeRepr()->getSourceRange());
56965712

56975713
if (hasAutoclosure)
5698-
diagnose(handlerTypeAttrs->getLoc(TAK_autoclosure),
5699-
diag::note_attr_completion_handler_async_handler_attr_req,
5700-
false, "autoclosure");
5701-
return;
5714+
Diags.diagnose(
5715+
handlerTypeAttrs->getLoc(TAK_autoclosure),
5716+
diag::note_attr_completion_handler_async_handler_attr_req, false,
5717+
"autoclosure");
5718+
return false;
57025719
}
57035720
}
57045721

@@ -5747,21 +5764,23 @@ void AttributeChecker::visitCompletionHandlerAsyncAttr(
57475764
}
57485765

57495766
if (candidates.empty()) {
5750-
diagnose(attr->AsyncFunctionNameLoc,
5751-
diag::attr_completion_handler_async_no_suitable_function,
5752-
attr->getAsyncFunctionName());
5753-
return;
5767+
Diags.diagnose(attr->AsyncFunctionNameLoc,
5768+
diag::attr_completion_handler_async_no_suitable_function,
5769+
attr->getAsyncFunctionName());
5770+
return false;
57545771
} else if (candidates.size() > 1) {
5755-
diagnose(attr->AsyncFunctionNameLoc,
5756-
diag::attr_completion_handler_async_ambiguous_function, attr,
5757-
attr->getAsyncFunctionName());
5772+
Diags.diagnose(attr->AsyncFunctionNameLoc,
5773+
diag::attr_completion_handler_async_ambiguous_function,
5774+
attr, attr->getAsyncFunctionName());
57585775

57595776
for (AbstractFunctionDecl *candidate : candidates) {
5760-
diagnose(candidate->getLoc(), diag::decl_declared_here,
5761-
candidate->getName());
5777+
Diags.diagnose(candidate->getLoc(), diag::decl_declared_here,
5778+
candidate->getName());
57625779
}
5763-
return;
5780+
return false;
57645781
}
57655782
attr->AsyncFunctionDecl = candidates.front();
57665783
}
5784+
5785+
return true;
57675786
}

0 commit comments

Comments
 (0)