Skip to content

Commit 3de83ac

Browse files
committed
[ClangImporter] Add @completionHandlerAsync for imported decls
Implicitly add the @completionHandlerAsync attribute for ObjCMethodDecl that have a completion handler. Adds a link from the non-async to the async function for use in diagnostics and refactorings. Resolves rdar://74665226
1 parent 669a49a commit 3de83ac

File tree

15 files changed

+248
-101
lines changed

15 files changed

+248
-101
lines changed

include/swift/AST/Attr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ SIMPLE_DECL_ATTR(reasync, AtReasync,
625625
110)
626626

627627
DECL_ATTR(completionHandlerAsync, CompletionHandlerAsync,
628-
OnAbstractFunction | ConcurrencyOnly |
628+
OnAbstractFunction | ConcurrencyOnly | LongAttribute |
629629
ABIStableToAdd | ABIStableToRemove |
630630
APIStableToAdd | APIStableToRemove,
631631
111)

include/swift/AST/Attr.h

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2043,36 +2043,32 @@ class TransposeAttr final
20432043
/// alternative, optionally providing a name (for cases when the alternative
20442044
/// has a different name).
20452045
class CompletionHandlerAsyncAttr final : public DeclAttribute {
2046-
private:
2047-
/// DeclName of the async function in the attribute
2046+
public:
2047+
/// Reference to the async alternative function. Only set for deserialized
2048+
/// attributes or inferred attributes from ObjectiveC code.
2049+
AbstractFunctionDecl *AsyncFunctionDecl;
2050+
2051+
/// DeclName of the async function in the attribute. Only set from actual
2052+
/// Swift code, deserialization/ObjectiveC imports will set the decl instead.
20482053
const DeclNameRef AsyncFunctionName;
20492054

2050-
public:
20512055
/// Source location of the async function name in the attribute
20522056
const SourceLoc AsyncFunctionNameLoc;
20532057

2054-
/// Get the name of the async function
2055-
///
2056-
/// The name will come from the AsyncFunctionDecl if available, otherwise will
2057-
/// fall back on the user-provided name. If that is not defined, this function
2058-
/// will abort.
2059-
DeclNameRef getAsyncFunctionName() const;
2060-
20612058
/// The index of the completion handler
20622059
const size_t CompletionHandlerIndex;
20632060

20642061
/// Source location of the completion handler index passed to the index
20652062
const SourceLoc CompletionHandlerIndexLoc;
20662063

2067-
AbstractFunctionDecl *AsyncFunctionDecl = nullptr;
2068-
20692064
CompletionHandlerAsyncAttr(DeclNameRef asyncFunctionName,
20702065
SourceLoc asyncFunctionNameLoc,
20712066
size_t completionHandlerIndex,
20722067
SourceLoc completionHandlerIndexLoc,
20732068
SourceLoc atLoc, SourceRange range)
20742069
: DeclAttribute(DAK_CompletionHandlerAsync, atLoc, range,
20752070
/*implicit*/ false),
2071+
AsyncFunctionDecl(nullptr),
20762072
AsyncFunctionName(asyncFunctionName),
20772073
AsyncFunctionNameLoc(asyncFunctionNameLoc),
20782074
CompletionHandlerIndex(completionHandlerIndex),
@@ -2084,11 +2080,9 @@ class CompletionHandlerAsyncAttr final : public DeclAttribute {
20842080
SourceLoc atLoc, SourceRange range)
20852081
: DeclAttribute(DAK_CompletionHandlerAsync, atLoc, range,
20862082
/*implicit*/ false),
2083+
AsyncFunctionDecl(&asyncFunctionDecl) ,
20872084
CompletionHandlerIndex(completionHandlerIndex),
2088-
CompletionHandlerIndexLoc(completionHandlerIndexLoc),
2089-
AsyncFunctionDecl(&asyncFunctionDecl) {}
2090-
2091-
2085+
CompletionHandlerIndexLoc(completionHandlerIndexLoc) {}
20922086

20932087
static bool classof(const DeclAttribute *DA) {
20942088
return DA->getKind() == DAK_CompletionHandlerAsync;

include/swift/AST/Decl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6097,6 +6097,8 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
60976097
/// constructor.
60986098
bool hasDynamicSelfResult() const;
60996099

6100+
AbstractFunctionDecl *getAsyncAlternative() const;
6101+
61006102
using DeclContext::operator new;
61016103
using Decl::getASTContext;
61026104
};

include/swift/AST/TypeCheckRequests.h

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2954,23 +2954,20 @@ class ConditionalRequirementsRequest
29542954
bool isCached() const { return true; }
29552955
};
29562956

2957-
class TypeCheckCompletionHandlerAsyncAttrRequest
2958-
: public SimpleRequest<TypeCheckCompletionHandlerAsyncAttrRequest,
2959-
bool(AbstractFunctionDecl *,
2960-
CompletionHandlerAsyncAttr *),
2957+
class AsyncAlternativeRequest
2958+
: public SimpleRequest<AsyncAlternativeRequest,
2959+
AbstractFunctionDecl *(AbstractFunctionDecl *),
29612960
RequestFlags::Cached> {
29622961
public:
29632962
using SimpleRequest::SimpleRequest;
29642963

29652964
private:
29662965
friend SimpleRequest;
29672966

2968-
bool evaluate(Evaluator &evaluator,
2969-
AbstractFunctionDecl *attachedFucntionDecl,
2970-
CompletionHandlerAsyncAttr *attr) const;
2967+
AbstractFunctionDecl *evaluate(
2968+
Evaluator &evaluator, AbstractFunctionDecl *attachedFunctionDecl) const;
29712969

29722970
public:
2973-
// Caching
29742971
bool isCached() const { return true; }
29752972
};
29762973

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,6 @@ SWIFT_REQUEST(TypeChecker, SynthesizeMainFunctionRequest,
325325
SWIFT_REQUEST(TypeChecker, GetImplicitSendableRequest,
326326
NormalProtocolConformance *(NominalTypeDecl *),
327327
Cached, NoLocationInfo)
328-
SWIFT_REQUEST(TypeChecker, TypeCheckCompletionHandlerAsyncAttrRequest,
329-
bool (AbstractFunctionDecl *, CompletionHandlerAsyncAttr *),
328+
SWIFT_REQUEST(TypeChecker, AsyncAlternativeRequest,
329+
AbstractFunctionDecl *(AbstractFunctionDecl *),
330330
Cached, NoLocationInfo)

lib/AST/Attr.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,20 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
10811081
#include "swift/AST/Attr.def"
10821082
llvm_unreachable("handled above");
10831083

1084+
case DAK_CompletionHandlerAsync: {
1085+
auto *attr = cast<CompletionHandlerAsyncAttr>(this);
1086+
Printer.printAttrName("@completionHandlerAsync");
1087+
Printer << "(\"";
1088+
if (attr->AsyncFunctionDecl) {
1089+
Printer << attr->AsyncFunctionDecl->getName();
1090+
} else {
1091+
Printer << attr->AsyncFunctionName;
1092+
}
1093+
Printer << "\", completionHandleIndex: " <<
1094+
attr->CompletionHandlerIndex << ')';
1095+
break;
1096+
}
1097+
10841098
default:
10851099
assert(DeclAttribute::isDeclModifier(getKind()) &&
10861100
"handled above");
@@ -2003,11 +2017,3 @@ void swift::simple_display(llvm::raw_ostream &out, const DeclAttribute *attr) {
20032017
if (attr)
20042018
attr->print(out);
20052019
}
2006-
2007-
DeclNameRef CompletionHandlerAsyncAttr::getAsyncFunctionName() const {
2008-
if (AsyncFunctionDecl)
2009-
return DeclNameRef(AsyncFunctionDecl->getName());
2010-
if (AsyncFunctionName)
2011-
return AsyncFunctionName;
2012-
llvm_unreachable("completionHandlerAsync attr missing async function name");
2013-
}

lib/AST/Decl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6843,6 +6843,12 @@ bool AbstractFunctionDecl::hasDynamicSelfResult() const {
68436843
return isa<ConstructorDecl>(this);
68446844
}
68456845

6846+
AbstractFunctionDecl *AbstractFunctionDecl::getAsyncAlternative() const {
6847+
auto mutableFunc = const_cast<AbstractFunctionDecl *>(this);
6848+
return evaluateOrDefault(getASTContext().evaluator,
6849+
AsyncAlternativeRequest{mutableFunc}, nullptr);
6850+
}
6851+
68466852
bool AbstractFunctionDecl::argumentNameIsAPIByDefault() const {
68476853
// Initializers have argument labels.
68486854
if (isa<ConstructorDecl>(this))

lib/ClangImporter/ImportDecl.cpp

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7961,6 +7961,34 @@ static bool suppressOverriddenMethods(ClangImporter::Implementation &importer,
79617961
return false;
79627962
}
79637963

7964+
void addCompletionHandlerAttribute(Decl *asyncImport,
7965+
ArrayRef<Decl *> members,
7966+
ASTContext &SwiftContext) {
7967+
auto *ayncFunc = dyn_cast_or_null<AbstractFunctionDecl>(asyncImport);
7968+
if (!ayncFunc)
7969+
return;
7970+
7971+
auto errorConvention = ayncFunc->getForeignErrorConvention();
7972+
auto asyncConvention = ayncFunc->getForeignAsyncConvention();
7973+
if (!asyncConvention)
7974+
return;
7975+
7976+
unsigned completionIndex = asyncConvention->completionHandlerParamIndex();
7977+
if (errorConvention &&
7978+
completionIndex >= errorConvention->getErrorParameterIndex()) {
7979+
completionIndex--;
7980+
}
7981+
7982+
for (auto *member : members) {
7983+
if (member != asyncImport) {
7984+
member->getAttrs().add(
7985+
new (SwiftContext) CompletionHandlerAsyncAttr(
7986+
cast<AbstractFunctionDecl>(*asyncImport), completionIndex,
7987+
SourceLoc(), SourceLoc(), SourceRange()));
7988+
}
7989+
}
7990+
}
7991+
79647992
/// Given a set of methods with the same selector, each taken from a
79657993
/// different protocol in the protocol hierarchy of a class into which
79667994
/// we want to introduce mirror imports, import only the methods which
@@ -8003,6 +8031,8 @@ void SwiftDeclConverter::importNonOverriddenMirroredMethods(DeclContext *dc,
80038031
auto proto = entries[i].second;
80048032
if (auto imported =
80058033
Impl.importMirroredDecl(objcMethod, dc, getVersion(), proto)) {
8034+
size_t start = members.size();
8035+
80068036
members.push_back(imported);
80078037

80088038
for (auto alternate : Impl.getAlternateDecls(imported)) {
@@ -8014,8 +8044,13 @@ void SwiftDeclConverter::importNonOverriddenMirroredMethods(DeclContext *dc,
80148044
auto asyncVersion = getVersion().withConcurrency(true);
80158045
if (auto asyncImport = Impl.importMirroredDecl(
80168046
objcMethod, dc, asyncVersion, proto)) {
8017-
if (asyncImport != imported)
8047+
if (asyncImport != imported) {
8048+
addCompletionHandlerAttribute(
8049+
asyncImport,
8050+
llvm::makeArrayRef(members).drop_front(start),
8051+
Impl.SwiftContext);
80188052
members.push_back(asyncImport);
8053+
}
80198054
}
80208055
}
80218056
}
@@ -9661,7 +9696,10 @@ void ClangImporter::Implementation::loadAllMembersOfObjcContainer(
96619696

96629697
void ClangImporter::Implementation::insertMembersAndAlternates(
96639698
const clang::NamedDecl *nd, SmallVectorImpl<Decl *> &members) {
9699+
9700+
size_t start = members.size();
96649701
llvm::SmallPtrSet<Decl *, 4> knownAlternateMembers;
9702+
Decl *asyncImport = nullptr;
96659703
forEachDistinctName(
96669704
nd, [&](ImportedName name, ImportNameVersion nameVersion) -> bool {
96679705
auto member = importDecl(nd, nameVersion);
@@ -9682,8 +9720,18 @@ void ClangImporter::Implementation::insertMembersAndAlternates(
96829720
return true;
96839721

96849722
members.push_back(member);
9723+
if (nameVersion.supportsConcurrency()) {
9724+
assert(!asyncImport &&
9725+
"Should only have a single version with concurrency enabled");
9726+
asyncImport = member;
9727+
}
9728+
96859729
return true;
96869730
});
9731+
9732+
addCompletionHandlerAttribute(asyncImport,
9733+
llvm::makeArrayRef(members).drop_front(start),
9734+
SwiftContext);
96879735
}
96889736

96899737
void ClangImporter::Implementation::importInheritedConstructors(

lib/Sema/MiscDiagnostics.cpp

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4655,28 +4655,18 @@ class CompletionHandlerUsageChecker final : public ASTWalker {
46554655
if (expr->getType().isNull())
46564656
return {false, expr}; // Something failed to typecheck, bail out
46574657

4658-
if (ClosureExpr *closure = dyn_cast<ClosureExpr>(expr))
4658+
if (auto *closure = dyn_cast<ClosureExpr>(expr))
46594659
return {closure->isBodyAsync(), closure};
46604660

4661-
if (ApplyExpr *call = dyn_cast<ApplyExpr>(expr)) {
4662-
if (DeclRefExpr *fnDeclExpr = dyn_cast<DeclRefExpr>(call->getFn())) {
4663-
ValueDecl *fnDecl = fnDeclExpr->getDecl();
4664-
CompletionHandlerAsyncAttr *asyncAltAttr =
4665-
fnDecl->getAttrs().getAttribute<CompletionHandlerAsyncAttr>();
4666-
if (asyncAltAttr) {
4667-
// Ensure that the attribute typechecks,
4668-
// this also resolves the async function decl.
4669-
if (!evaluateOrDefault(
4670-
ctx.evaluator,
4671-
TypeCheckCompletionHandlerAsyncAttrRequest{
4672-
cast<AbstractFunctionDecl>(fnDecl), asyncAltAttr},
4673-
false)) {
4661+
if (auto *call = dyn_cast<ApplyExpr>(expr)) {
4662+
if (auto *fn = dyn_cast<DeclRefExpr>(call->getFn())) {
4663+
if (auto *afd = dyn_cast<AbstractFunctionDecl>(fn->getDecl())) {
4664+
auto *asyncFunc = afd->getAsyncAlternative();
4665+
if (!asyncFunc)
46744666
return {false, call};
4675-
}
46764667
ctx.Diags.diagnose(call->getLoc(), diag::warn_use_async_alternative);
4677-
ctx.Diags.diagnose(asyncAltAttr->AsyncFunctionDecl->getLoc(),
4678-
diag::decl_declared_here,
4679-
asyncAltAttr->AsyncFunctionDecl->getName());
4668+
ctx.Diags.diagnose(asyncFunc->getLoc(), diag::decl_declared_here,
4669+
asyncFunc->getName());
46804670
}
46814671
}
46824672
}

lib/Sema/TypeCheckAttr.cpp

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5653,17 +5653,20 @@ void TypeChecker::checkClosureAttributes(ClosureExpr *closure) {
56535653

56545654
void AttributeChecker::visitCompletionHandlerAsyncAttr(
56555655
CompletionHandlerAsyncAttr *attr) {
5656-
AbstractFunctionDecl *AFD = dyn_cast<AbstractFunctionDecl>(D);
5657-
if (!AFD)
5658-
return;
5659-
5660-
evaluateOrDefault(Ctx.evaluator,
5661-
TypeCheckCompletionHandlerAsyncAttrRequest{AFD, attr}, {});
5656+
if (AbstractFunctionDecl *AFD = dyn_cast<AbstractFunctionDecl>(D))
5657+
AFD->getAsyncAlternative();
56625658
}
56635659

5664-
bool TypeCheckCompletionHandlerAsyncAttrRequest::evaluate(
5665-
Evaluator &evaluator, AbstractFunctionDecl *attachedFunctionDecl,
5666-
CompletionHandlerAsyncAttr *attr) const {
5660+
AbstractFunctionDecl *AsyncAlternativeRequest::evaluate(
5661+
Evaluator &evaluator, AbstractFunctionDecl *attachedFunctionDecl) const {
5662+
auto attr = attachedFunctionDecl->getAttrs()
5663+
.getAttribute<CompletionHandlerAsyncAttr>();
5664+
if (!attr)
5665+
return nullptr;
5666+
5667+
if (attr->AsyncFunctionDecl)
5668+
return attr->AsyncFunctionDecl;
5669+
56675670
auto &Diags = attachedFunctionDecl->getASTContext().Diags;
56685671
// Check phases:
56695672
// 1. Attached function shouldn't be async and should have enough args
@@ -5681,7 +5684,7 @@ bool TypeCheckCompletionHandlerAsyncAttrRequest::evaluate(
56815684
diag::attr_completion_handler_async_handler_not_func, attr);
56825685
Diags.diagnose(attachedFunctionDecl->getAsyncLoc(),
56835686
diag::note_attr_function_declared_async);
5684-
return false;
5687+
return nullptr;
56855688
}
56865689

56875690
const ParameterList *attachedFunctionParams =
@@ -5690,15 +5693,15 @@ bool TypeCheckCompletionHandlerAsyncAttrRequest::evaluate(
56905693
if (attachedFunctionParams->size() == 0) {
56915694
Diags.diagnose(attr->getLocation(),
56925695
diag::attr_completion_handler_async_handler_not_func, attr);
5693-
return false;
5696+
return nullptr;
56945697
}
56955698
size_t completionHandlerIndex = attr->CompletionHandlerIndexLoc.isValid()
56965699
? attr->CompletionHandlerIndex
56975700
: attachedFunctionParams->size() - 1;
56985701
if (attachedFunctionParams->size() < completionHandlerIndex) {
56995702
Diags.diagnose(attr->CompletionHandlerIndexLoc,
57005703
diag::attr_completion_handler_async_handler_out_of_range);
5701-
return false;
5704+
return nullptr;
57025705
}
57035706

57045707
// Phase 2: Typecheck the completion handler
@@ -5718,7 +5721,7 @@ bool TypeCheckCompletionHandlerAsyncAttrRequest::evaluate(
57185721
completionHandlerParamDecl->getType())
57195722
.highlight(
57205723
completionHandlerParamDecl->getTypeRepr()->getSourceRange());
5721-
return false;
5724+
return nullptr;
57225725
}
57235726

57245727
auto handlerTypeRepr =
@@ -5759,7 +5762,7 @@ bool TypeCheckCompletionHandlerAsyncAttrRequest::evaluate(
57595762
handlerTypeAttrs->getLoc(TAK_autoclosure),
57605763
diag::note_attr_completion_handler_async_handler_attr_req, false,
57615764
"autoclosure");
5762-
return false;
5765+
return nullptr;
57635766
}
57645767
}
57655768

@@ -5793,7 +5796,7 @@ bool TypeCheckCompletionHandlerAsyncAttrRequest::evaluate(
57935796
// should return all of those types in a tuple
57945797

57955798
SmallVector<ValueDecl *, 2> allCandidates;
5796-
lookupReplacedDecl(attr->getAsyncFunctionName(), attr, attachedFunctionDecl,
5799+
lookupReplacedDecl(attr->AsyncFunctionName, attr, attachedFunctionDecl,
57975800
allCandidates);
57985801
SmallVector<AbstractFunctionDecl *, 2> candidates;
57995802
candidates.reserve(allCandidates.size());
@@ -5810,21 +5813,20 @@ bool TypeCheckCompletionHandlerAsyncAttrRequest::evaluate(
58105813
if (candidates.empty()) {
58115814
Diags.diagnose(attr->AsyncFunctionNameLoc,
58125815
diag::attr_completion_handler_async_no_suitable_function,
5813-
attr->getAsyncFunctionName());
5814-
return false;
5816+
attr->AsyncFunctionName);
5817+
return nullptr;
58155818
} else if (candidates.size() > 1) {
58165819
Diags.diagnose(attr->AsyncFunctionNameLoc,
58175820
diag::attr_completion_handler_async_ambiguous_function,
5818-
attr, attr->getAsyncFunctionName());
5821+
attr, attr->AsyncFunctionName);
58195822

58205823
for (AbstractFunctionDecl *candidate : candidates) {
58215824
Diags.diagnose(candidate->getLoc(), diag::decl_declared_here,
58225825
candidate->getName());
58235826
}
5824-
return false;
5827+
return nullptr;
58255828
}
5826-
attr->AsyncFunctionDecl = candidates.front();
5827-
}
58285829

5829-
return true;
5830+
return candidates.front();
5831+
}
58305832
}

0 commit comments

Comments
 (0)