Skip to content

Commit 10fa19b

Browse files
authored
Merge pull request swiftlang#33674 from DougGregor/concurrency-objc-import-async
[Concurrency] Import Objective-C methods with completion handlers as async
2 parents 11eac12 + 6ad2757 commit 10fa19b

File tree

18 files changed

+584
-39
lines changed

18 files changed

+584
-39
lines changed

include/swift/AST/Decl.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ namespace swift {
6363
class Type;
6464
class Expr;
6565
class DeclRefExpr;
66+
class ForeignAsyncConvention;
6667
class ForeignErrorConvention;
6768
class LiteralExpr;
6869
class BraceStmt;
@@ -6148,7 +6149,15 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
61486149
/// being dropped altogether. `None` is returned for a normal function
61496150
/// or method.
61506151
Optional<int> getForeignFunctionAsMethodSelfParameterIndex() const;
6151-
6152+
6153+
/// Set information about the foreign async convention used by this
6154+
/// declaration.
6155+
void setForeignAsyncConvention(const ForeignAsyncConvention &convention);
6156+
6157+
/// Get information about the foreign async convention used by this
6158+
/// declaration, given that it is @objc and 'async'.
6159+
Optional<ForeignAsyncConvention> getForeignAsyncConvention() const;
6160+
61526161
static bool classof(const Decl *D) {
61536162
return D->getKind() >= DeclKind::First_AbstractFunctionDecl &&
61546163
D->getKind() <= DeclKind::Last_AbstractFunctionDecl;
@@ -6277,7 +6286,8 @@ class FuncDecl : public AbstractFunctionDecl {
62776286
DeclContext *Parent);
62786287

62796288
static FuncDecl *createImported(ASTContext &Context, SourceLoc FuncLoc,
6280-
DeclName Name, SourceLoc NameLoc, bool Throws,
6289+
DeclName Name, SourceLoc NameLoc,
6290+
bool Async, bool Throws,
62816291
ParameterList *BodyParams, Type FnRetType,
62826292
DeclContext *Parent, ClangNode ClangN);
62836293

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//===--- ForeignAsyncConvention.h - Async conventions -----------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines the ForeignAsyncConvention structure, which
14+
// describes the rules for how to detect that a foreign API is asynchronous.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_FOREIGN_ASYNC_CONVENTION_H
19+
#define SWIFT_FOREIGN_ASYNC_CONVENTION_H
20+
21+
#include "swift/AST/Type.h"
22+
23+
namespace swift {
24+
25+
/// A small structure describing the async convention of a foreign declaration.
26+
class ForeignAsyncConvention {
27+
/// The index of the completion handler parameters.
28+
unsigned CompletionHandlerParamIndex;
29+
30+
/// When non-zero, indicates which parameter to the completion handler is the
31+
/// Error? parameter (minus one) that makes this async function also throwing.
32+
unsigned CompletionHandlerErrorParamIndex;
33+
public:
34+
ForeignAsyncConvention()
35+
: CompletionHandlerParamIndex(0), CompletionHandlerErrorParamIndex(0) { }
36+
37+
ForeignAsyncConvention(unsigned completionHandlerParamIndex,
38+
Optional<unsigned> completionHandlerErrorParamIndex)
39+
: CompletionHandlerParamIndex(completionHandlerParamIndex),
40+
CompletionHandlerErrorParamIndex(
41+
completionHandlerErrorParamIndex
42+
? *completionHandlerErrorParamIndex + 1
43+
: 0) {}
44+
45+
/// Retrieve the index of the completion handler parameter, which will be
46+
/// erased from the Swift signature of the imported async function.
47+
unsigned completionHandlerParamIndex() const {
48+
return CompletionHandlerParamIndex;
49+
}
50+
51+
/// Retrieve the index of the \c Error? parameter in the completion handler's
52+
/// parameter list. When argument passed to this parameter is non-null, the
53+
/// provided error will be thrown by the async function.
54+
Optional<unsigned> completionHandlerErrorParamIndex() const {
55+
if (CompletionHandlerErrorParamIndex == 0)
56+
return None;
57+
58+
return CompletionHandlerErrorParamIndex - 1;
59+
}
60+
61+
/// Whether the async function is throwing due to the completion handler
62+
/// having an \c Error? parameter.
63+
///
64+
/// Equivalent to \c static_cast<bool>(completionHandlerErrorParamIndex()).
65+
bool isThrowing() const {
66+
return CompletionHandlerErrorParamIndex != 0;
67+
}
68+
69+
bool operator==(ForeignAsyncConvention other) const {
70+
return CompletionHandlerParamIndex == other.CompletionHandlerParamIndex
71+
&& CompletionHandlerErrorParamIndex ==
72+
other.CompletionHandlerErrorParamIndex;
73+
}
74+
bool operator!=(ForeignAsyncConvention other) const {
75+
return !(*this == other);
76+
}
77+
};
78+
79+
}
80+
81+
#endif

include/swift/AST/ForeignErrorConvention.h

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ class ForeignErrorConvention {
8181
}
8282

8383
Info() = default;
84+
85+
Kind getKind() const {
86+
return static_cast<Kind>(TheKind);
87+
}
8488
};
8589

8690
private:
@@ -178,11 +182,24 @@ class ForeignErrorConvention {
178182
/// Returns the physical result type of the function, for functions
179183
/// that completely erase this information.
180184
CanType getResultType() const {
181-
assert(getKind() == ZeroResult ||
182-
getKind() == NonZeroResult);
185+
assert(resultTypeErasedToVoid(getKind()));
183186
return ResultType;
184187
}
185-
188+
189+
/// Whether this kind of error import erases the result type to 'Void'.
190+
static bool resultTypeErasedToVoid(Kind kind) {
191+
switch (kind) {
192+
case ZeroResult:
193+
case NonZeroResult:
194+
return true;
195+
196+
case ZeroPreservedResult:
197+
case NilResult:
198+
case NonNilError:
199+
return false;
200+
}
201+
}
202+
186203
bool operator==(ForeignErrorConvention other) const {
187204
return info.TheKind == other.info.TheKind
188205
&& info.ErrorIsOwned == other.info.ErrorIsOwned

lib/AST/ASTContext.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "ClangTypeConverter.h"
1919
#include "ForeignRepresentationInfo.h"
2020
#include "SubstitutionMapStorage.h"
21+
#include "swift/AST/ForeignAsyncConvention.h"
2122
#include "swift/AST/ClangModuleLoader.h"
2223
#include "swift/AST/ConcreteDeclRef.h"
2324
#include "swift/AST/DiagnosticEngine.h"
@@ -281,6 +282,10 @@ struct ASTContext::Implementation {
281282
llvm::DenseMap<const AbstractFunctionDecl *,
282283
ForeignErrorConvention> ForeignErrorConventions;
283284

285+
/// Map from declarations to foreign async conventions.
286+
llvm::DenseMap<const AbstractFunctionDecl *,
287+
ForeignAsyncConvention> ForeignAsyncConventions;
288+
284289
/// Cache of previously looked-up precedence queries.
285290
AssociativityCacheType AssociativityCache;
286291

@@ -2239,6 +2244,24 @@ AbstractFunctionDecl::getForeignErrorConvention() const {
22392244
return it->second;
22402245
}
22412246

2247+
void AbstractFunctionDecl::setForeignAsyncConvention(
2248+
const ForeignAsyncConvention &conv) {
2249+
assert(hasAsync() && "setting error convention on non-throwing decl");
2250+
auto &conventionsMap = getASTContext().getImpl().ForeignAsyncConventions;
2251+
assert(!conventionsMap.count(this) && "error convention already set");
2252+
conventionsMap.insert({this, conv});
2253+
}
2254+
2255+
Optional<ForeignAsyncConvention>
2256+
AbstractFunctionDecl::getForeignAsyncConvention() const {
2257+
if (!hasAsync())
2258+
return None;
2259+
auto &conventionsMap = getASTContext().getImpl().ForeignAsyncConventions;
2260+
auto it = conventionsMap.find(this);
2261+
if (it == conventionsMap.end()) return None;
2262+
return it->second;
2263+
}
2264+
22422265
Optional<KnownFoundationEntity> swift::getKnownFoundationEntity(StringRef name){
22432266
return llvm::StringSwitch<Optional<KnownFoundationEntity>>(name)
22442267
#define FOUNDATION_ENTITY(Name) .Case(#Name, KnownFoundationEntity::Name)

lib/AST/Decl.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7255,13 +7255,14 @@ FuncDecl *FuncDecl::createImplicit(ASTContext &Context,
72557255

72567256
FuncDecl *FuncDecl::createImported(ASTContext &Context, SourceLoc FuncLoc,
72577257
DeclName Name, SourceLoc NameLoc,
7258-
bool Throws, ParameterList *BodyParams,
7258+
bool Async, bool Throws,
7259+
ParameterList *BodyParams,
72597260
Type FnRetType, DeclContext *Parent,
72607261
ClangNode ClangN) {
72617262
assert(ClangN && FnRetType);
72627263
auto *const FD = FuncDecl::createImpl(
72637264
Context, SourceLoc(), StaticSpellingKind::None, FuncLoc, Name, NameLoc,
7264-
/*Async=*/false, SourceLoc(), Throws, SourceLoc(),
7265+
Async, SourceLoc(), Throws, SourceLoc(),
72657266
/*GenericParams=*/nullptr, Parent, ClangN);
72667267
FD->setParameters(BodyParams);
72677268
FD->setResultInterfaceType(FnRetType);

lib/ClangImporter/ClangAdapter.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -714,8 +714,7 @@ bool importer::isUnavailableInSwift(
714714
return false;
715715
}
716716

717-
OptionalTypeKind importer::getParamOptionality(version::Version swiftVersion,
718-
const clang::ParmVarDecl *param,
717+
OptionalTypeKind importer::getParamOptionality(const clang::ParmVarDecl *param,
719718
bool knownNonNull) {
720719
auto &clangCtx = param->getASTContext();
721720

lib/ClangImporter/ClangAdapter.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,15 +161,11 @@ bool isUnavailableInSwift(const clang::Decl *decl, const PlatformAvailability &,
161161

162162
/// Determine the optionality of the given Clang parameter.
163163
///
164-
/// \param swiftLanguageVersion What version of Swift we're using, which affects
165-
/// how optionality is inferred.
166-
///
167164
/// \param param The Clang parameter.
168165
///
169166
/// \param knownNonNull Whether a function- or method-level "nonnull" attribute
170167
/// applies to this parameter.
171-
OptionalTypeKind getParamOptionality(version::Version swiftLanguageVersion,
172-
const clang::ParmVarDecl *param,
168+
OptionalTypeKind getParamOptionality(const clang::ParmVarDecl *param,
173169
bool knownNonNull);
174170
}
175171
}

lib/ClangImporter/ClangImporter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3681,6 +3681,7 @@ void ClangImporter::Implementation::lookupValue(
36813681
clangDecl->getMostRecentDecl();
36823682

36833683
CurrentVersion.forEachOtherImportNameVersion(
3684+
SwiftContext.LangOpts.EnableExperimentalConcurrency,
36843685
[&](ImportNameVersion nameVersion) {
36853686
if (anyMatching)
36863687
return;
@@ -3690,6 +3691,12 @@ void ClangImporter::Implementation::lookupValue(
36903691
if (!newName.getDeclName().matchesRef(name))
36913692
return;
36923693

3694+
// If we asked for an async import and didn't find one, skip this.
3695+
// This filters out duplicates.
3696+
if (nameVersion.supportsConcurrency() &&
3697+
!newName.getAsyncInfo())
3698+
return;
3699+
36933700
const clang::DeclContext *clangDC =
36943701
newName.getEffectiveContext().getAsDeclContext();
36953702
if (!clangDC || !clangDC->isFileContext())

0 commit comments

Comments
 (0)