Skip to content

Commit f6e9f35

Browse files
committed
[Concurrency] Add async to the Swift type system.
Add `async` to the type system. `async` can be written as part of a function type or function declaration, following the parameter list, e.g., func doSomeWork() async { ... } `async` functions are distinct from non-`async` functions and there are no conversions amongst them. At present, `async` functions do not *do* anything, but this commit fully supports them as a distinct kind of function throughout: * Parsing of `async` * AST representation of `async` in declarations and types * Syntactic type representation of `async` * (De-/re-)mangling of function types involving 'async' * Runtime type representation and reconstruction of function types involving `async`. * Dynamic casting restrictions for `async` function types * (De-)serialization of `async` function types * Disabling overriding, witness matching, and conversions with differing `async`
1 parent 8a45c9c commit f6e9f35

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+555
-151
lines changed

docs/ABI/Mangling.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,13 +527,14 @@ Types
527527
FUNCTION-KIND ::= 'H' // @differentiable(linear) function type
528528
FUNCTION-KIND ::= 'I' // @differentiable(linear) function type (escaping)
529529

530-
function-signature ::= params-type params-type throws? // results and parameters
530+
function-signature ::= params-type params-type async? throws? // results and parameters
531531

532532
params-type ::= type 'z'? 'h'? // tuple in case of multiple parameters or a single parameter with a single tuple type
533533
// with optional inout convention, shared convention. parameters don't have labels,
534534
// they are mangled separately as part of the entity.
535535
params-type ::= empty-list // shortcut for no parameters
536536

537+
async ::= 'Y' // 'async' annotation on function types
537538
throws ::= 'K' // 'throws' annotation on function types
538539

539540
type-list ::= list-type '_' list-type* // list of types

include/swift/ABI/Metadata.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1634,6 +1634,7 @@ struct TargetFunctionTypeMetadata : public TargetMetadata<Runtime> {
16341634
FunctionMetadataConvention getConvention() const {
16351635
return Flags.getConvention();
16361636
}
1637+
bool async() const { return Flags.async(); }
16371638
bool throws() const { return Flags.throws(); }
16381639
bool hasParameterFlags() const { return Flags.hasParameterFlags(); }
16391640
bool isEscaping() const { return Flags.isEscaping(); }

include/swift/ABI/MetadataValues.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -794,8 +794,9 @@ class TargetFunctionTypeFlags {
794794
ThrowsMask = 0x01000000U,
795795
ParamFlagsMask = 0x02000000U,
796796
EscapingMask = 0x04000000U,
797-
DifferentiableMask = 0x08000000U,
798-
LinearMask = 0x10000000U
797+
DifferentiableMask = 0x08000000U,
798+
LinearMask = 0x10000000U,
799+
AsyncMask = 0x20000000U,
799800
};
800801
int_type Data;
801802

@@ -813,7 +814,13 @@ class TargetFunctionTypeFlags {
813814
return TargetFunctionTypeFlags((Data & ~ConventionMask)
814815
| (int_type(c) << ConventionShift));
815816
}
816-
817+
818+
constexpr TargetFunctionTypeFlags<int_type>
819+
withAsync(bool async) const {
820+
return TargetFunctionTypeFlags<int_type>((Data & ~AsyncMask) |
821+
(async ? AsyncMask : 0));
822+
}
823+
817824
constexpr TargetFunctionTypeFlags<int_type>
818825
withThrows(bool throws) const {
819826
return TargetFunctionTypeFlags<int_type>((Data & ~ThrowsMask) |
@@ -847,7 +854,11 @@ class TargetFunctionTypeFlags {
847854
FunctionMetadataConvention getConvention() const {
848855
return FunctionMetadataConvention((Data&ConventionMask) >> ConventionShift);
849856
}
850-
857+
858+
bool async() const {
859+
return bool(Data & AsyncMask);
860+
}
861+
851862
bool throws() const {
852863
return bool(Data & ThrowsMask);
853864
}

include/swift/AST/Decl.h

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ class alignas(1 << DeclAlignInBits) Decl {
385385
SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2,
386386
StaticSpelling : 2
387387
);
388-
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1,
388+
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1+1,
389389
/// \see AbstractFunctionDecl::BodyKind
390390
BodyKind : 3,
391391

@@ -398,6 +398,9 @@ class alignas(1 << DeclAlignInBits) Decl {
398398
/// Whether we are overridden later.
399399
Overridden : 1,
400400

401+
/// Whether the function is async.
402+
Async : 1,
403+
401404
/// Whether the function body throws.
402405
Throws : 1,
403406

@@ -5822,6 +5825,9 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
58225825

58235826
CaptureInfo Captures;
58245827

5828+
/// Location of the 'async' token.
5829+
SourceLoc AsyncLoc;
5830+
58255831
/// Location of the 'throws' token.
58265832
SourceLoc ThrowsLoc;
58275833

@@ -5831,15 +5837,17 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
58315837
} LazySemanticInfo = { };
58325838

58335839
AbstractFunctionDecl(DeclKind Kind, DeclContext *Parent, DeclName Name,
5834-
SourceLoc NameLoc, bool Throws, SourceLoc ThrowsLoc,
5840+
SourceLoc NameLoc, bool Async, SourceLoc AsyncLoc,
5841+
bool Throws, SourceLoc ThrowsLoc,
58355842
bool HasImplicitSelfDecl,
58365843
GenericParamList *GenericParams)
58375844
: GenericContext(DeclContextKind::AbstractFunctionDecl, Parent, GenericParams),
58385845
ValueDecl(Kind, Parent, Name, NameLoc),
5839-
Body(nullptr), ThrowsLoc(ThrowsLoc) {
5846+
Body(nullptr), AsyncLoc(AsyncLoc), ThrowsLoc(ThrowsLoc) {
58405847
setBodyKind(BodyKind::None);
58415848
Bits.AbstractFunctionDecl.HasImplicitSelfDecl = HasImplicitSelfDecl;
58425849
Bits.AbstractFunctionDecl.Overridden = false;
5850+
Bits.AbstractFunctionDecl.Async = Async;
58435851
Bits.AbstractFunctionDecl.Throws = Throws;
58445852
Bits.AbstractFunctionDecl.Synthesized = false;
58455853
Bits.AbstractFunctionDecl.HasSingleExpressionBody = false;
@@ -5899,9 +5907,15 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
58995907
Bits.AbstractFunctionDecl.IAMStatus = newValue.getRawValue();
59005908
}
59015909

5910+
/// Retrieve the location of the 'async' keyword, if present.
5911+
SourceLoc getAsyncLoc() const { return AsyncLoc; }
5912+
59025913
/// Retrieve the location of the 'throws' keyword, if present.
59035914
SourceLoc getThrowsLoc() const { return ThrowsLoc; }
59045915

5916+
/// Returns true if the function is async.
5917+
bool hasAsync() const { return Bits.AbstractFunctionDecl.Async; }
5918+
59055919
/// Returns true if the function body throws.
59065920
bool hasThrows() const { return Bits.AbstractFunctionDecl.Throws; }
59075921

@@ -6147,11 +6161,13 @@ class FuncDecl : public AbstractFunctionDecl {
61476161
SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
61486162
SourceLoc FuncLoc,
61496163
DeclName Name, SourceLoc NameLoc,
6164+
bool Async, SourceLoc AsyncLoc,
61506165
bool Throws, SourceLoc ThrowsLoc,
61516166
bool HasImplicitSelfDecl,
61526167
GenericParamList *GenericParams, DeclContext *Parent)
61536168
: AbstractFunctionDecl(Kind, Parent,
61546169
Name, NameLoc,
6170+
Async, AsyncLoc,
61556171
Throws, ThrowsLoc,
61566172
HasImplicitSelfDecl, GenericParams),
61576173
StaticLoc(StaticLoc), FuncLoc(FuncLoc) {
@@ -6173,6 +6189,7 @@ class FuncDecl : public AbstractFunctionDecl {
61736189
StaticSpellingKind StaticSpelling,
61746190
SourceLoc FuncLoc,
61756191
DeclName Name, SourceLoc NameLoc,
6192+
bool Async, SourceLoc AsyncLoc,
61766193
bool Throws, SourceLoc ThrowsLoc,
61776194
GenericParamList *GenericParams,
61786195
DeclContext *Parent,
@@ -6198,6 +6215,7 @@ class FuncDecl : public AbstractFunctionDecl {
61986215
StaticSpellingKind StaticSpelling,
61996216
SourceLoc FuncLoc,
62006217
DeclName Name, SourceLoc NameLoc,
6218+
bool Async, SourceLoc AsyncLoc,
62016219
bool Throws, SourceLoc ThrowsLoc,
62026220
GenericParamList *GenericParams,
62036221
DeclContext *Parent);
@@ -6206,6 +6224,7 @@ class FuncDecl : public AbstractFunctionDecl {
62066224
StaticSpellingKind StaticSpelling,
62076225
SourceLoc FuncLoc,
62086226
DeclName Name, SourceLoc NameLoc,
6227+
bool Async, SourceLoc AsyncLoc,
62096228
bool Throws, SourceLoc ThrowsLoc,
62106229
GenericParamList *GenericParams,
62116230
ParameterList *ParameterList,
@@ -6347,7 +6366,8 @@ class AccessorDecl final : public FuncDecl {
63476366
: FuncDecl(DeclKind::Accessor,
63486367
staticLoc, staticSpelling, /*func loc*/ declLoc,
63496368
/*name*/ Identifier(), /*name loc*/ declLoc,
6350-
throws, throwsLoc, hasImplicitSelfDecl, genericParams, parent),
6369+
/*Async=*/false, SourceLoc(), throws, throwsLoc,
6370+
hasImplicitSelfDecl, genericParams, parent),
63516371
AccessorKeywordLoc(accessorKeywordLoc),
63526372
Storage(storage) {
63536373
Bits.AccessorDecl.AccessorKind = unsigned(accessorKind);

include/swift/AST/DiagnosticsParse.def

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -727,10 +727,9 @@ ERROR(generic_non_function,PointsToFirstBadToken,
727727
ERROR(rethrowing_function_type,none,
728728
"only function declarations may be marked 'rethrows'; "
729729
"did you mean 'throws'?", ())
730-
ERROR(throws_in_wrong_position,none,
731-
"'throws' may only occur before '->'", ())
732-
ERROR(rethrows_in_wrong_position,none,
733-
"'rethrows' may only occur before '->'", ())
730+
ERROR(async_or_throws_in_wrong_position,none,
731+
"%select{'throws'|'rethrows'|'async'}0 may only occur before '->'",
732+
(unsigned))
734733
ERROR(throw_in_function_type,none,
735734
"expected throwing specifier; did you mean 'throws'?", ())
736735
ERROR(expected_type_before_arrow,none,
@@ -742,6 +741,9 @@ ERROR(function_type_argument_label,none,
742741
(Identifier))
743742
ERROR(expected_dynamic_func_attr,none,
744743
"expected a dynamically_replaceable function", ())
744+
ERROR(async_after_throws,none,
745+
"'async' must precede %select{'throws'|'rethrows'}0", (bool))
746+
ERROR(async_init,none, "initializer cannot be marked 'async'", ())
745747

746748
// Enum Types
747749
ERROR(expected_expr_enum_case_raw_value,PointsToFirstBadToken,

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2158,6 +2158,9 @@ NOTE(protocol_witness_settable_conflict,none,
21582158
"candidate is not settable, but protocol requires it", ())
21592159
NOTE(protocol_witness_rethrows_conflict,none,
21602160
"candidate is not 'rethrows', but protocol requires it", ())
2161+
NOTE(protocol_witness_async_conflict,none,
2162+
"candidate is %select{not |}0'async', but protocol requirement is%select{| not}0",
2163+
(bool))
21612164
NOTE(protocol_witness_throws_conflict,none,
21622165
"candidate throws, but protocol does not allow it", ())
21632166
NOTE(protocol_witness_not_objc,none,
@@ -4366,6 +4369,8 @@ NOTE(not_objc_generic_type_param,none,
43664369
NOTE(not_objc_function_type_param,none,
43674370
"function types cannot be represented in Objective-C unless their "
43684371
"parameters and returns can be", ())
4372+
NOTE(not_objc_function_type_async,none,
4373+
"'async' function types cannot be represented in Objective-C", ())
43694374
NOTE(not_objc_function_type_throwing,none,
43704375
"throwing function types cannot be represented in Objective-C", ())
43714376
NOTE(objc_inferring_on_objc_protocol_member,none,

include/swift/AST/Expr.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4791,32 +4791,38 @@ class CoerceExpr final : public ExplicitCastExpr {
47914791
/// may be preceded by the 'throws' keyword. Currently this only exists to be
47924792
/// transformed into a FunctionTypeRepr by simplifyTypeExpr() in Sema.
47934793
class ArrowExpr : public Expr {
4794+
SourceLoc AsyncLoc;
47944795
SourceLoc ThrowsLoc;
47954796
SourceLoc ArrowLoc;
47964797
Expr *Args;
47974798
Expr *Result;
47984799
public:
4799-
ArrowExpr(Expr *Args, SourceLoc ThrowsLoc, SourceLoc ArrowLoc, Expr *Result)
4800+
ArrowExpr(Expr *Args, SourceLoc AsyncLoc, SourceLoc ThrowsLoc,
4801+
SourceLoc ArrowLoc, Expr *Result)
48004802
: Expr(ExprKind::Arrow, /*implicit=*/false, Type()),
4801-
ThrowsLoc(ThrowsLoc), ArrowLoc(ArrowLoc), Args(Args), Result(Result)
4803+
AsyncLoc(AsyncLoc), ThrowsLoc(ThrowsLoc), ArrowLoc(ArrowLoc), Args(Args),
4804+
Result(Result)
48024805
{ }
48034806

4804-
ArrowExpr(SourceLoc ThrowsLoc, SourceLoc ArrowLoc)
4807+
ArrowExpr(SourceLoc AsyncLoc, SourceLoc ThrowsLoc, SourceLoc ArrowLoc)
48054808
: Expr(ExprKind::Arrow, /*implicit=*/false, Type()),
4806-
ThrowsLoc(ThrowsLoc), ArrowLoc(ArrowLoc), Args(nullptr), Result(nullptr)
4809+
AsyncLoc(AsyncLoc), ThrowsLoc(ThrowsLoc), ArrowLoc(ArrowLoc),
4810+
Args(nullptr), Result(nullptr)
48074811
{ }
48084812

48094813
Expr *getArgsExpr() const { return Args; }
48104814
void setArgsExpr(Expr *E) { Args = E; }
48114815
Expr *getResultExpr() const { return Result; }
48124816
void setResultExpr(Expr *E) { Result = E; }
4817+
SourceLoc getAsyncLoc() const { return AsyncLoc; }
48134818
SourceLoc getThrowsLoc() const { return ThrowsLoc; }
48144819
SourceLoc getArrowLoc() const { return ArrowLoc; }
48154820
bool isFolded() const { return Args != nullptr && Result != nullptr; }
48164821

48174822
SourceLoc getSourceLoc() const { return ArrowLoc; }
48184823
SourceLoc getStartLoc() const {
48194824
return isFolded() ? Args->getStartLoc() :
4825+
AsyncLoc.isValid() ? AsyncLoc :
48204826
ThrowsLoc.isValid() ? ThrowsLoc : ArrowLoc;
48214827
}
48224828
SourceLoc getEndLoc() const {

include/swift/AST/TypeRepr.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -482,12 +482,14 @@ class FunctionTypeRepr : public TypeRepr {
482482

483483
TupleTypeRepr *ArgsTy;
484484
TypeRepr *RetTy;
485-
SourceLoc ArrowLoc;
485+
SourceLoc AsyncLoc;
486486
SourceLoc ThrowsLoc;
487+
SourceLoc ArrowLoc;
487488

488489
public:
489490
FunctionTypeRepr(GenericParamList *genericParams, TupleTypeRepr *argsTy,
490-
SourceLoc throwsLoc, SourceLoc arrowLoc, TypeRepr *retTy,
491+
SourceLoc asyncLoc, SourceLoc throwsLoc, SourceLoc arrowLoc,
492+
TypeRepr *retTy,
491493
GenericParamList *patternGenericParams = nullptr,
492494
ArrayRef<TypeRepr *> patternSubs = {},
493495
ArrayRef<TypeRepr *> invocationSubs = {})
@@ -497,7 +499,7 @@ class FunctionTypeRepr : public TypeRepr {
497499
PatternGenericParams(patternGenericParams), PatternGenericEnv(nullptr),
498500
PatternSubs(patternSubs),
499501
ArgsTy(argsTy), RetTy(retTy),
500-
ArrowLoc(arrowLoc), ThrowsLoc(throwsLoc) {
502+
AsyncLoc(asyncLoc), ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc) {
501503
}
502504

503505
GenericParamList *getGenericParams() const { return GenericParams; }
@@ -527,10 +529,12 @@ class FunctionTypeRepr : public TypeRepr {
527529

528530
TupleTypeRepr *getArgsTypeRepr() const { return ArgsTy; }
529531
TypeRepr *getResultTypeRepr() const { return RetTy; }
532+
bool async() const { return AsyncLoc.isValid(); }
530533
bool throws() const { return ThrowsLoc.isValid(); }
531534

532-
SourceLoc getArrowLoc() const { return ArrowLoc; }
535+
SourceLoc getAsyncLoc() const { return AsyncLoc; }
533536
SourceLoc getThrowsLoc() const { return ThrowsLoc; }
537+
SourceLoc getArrowLoc() const { return ArrowLoc; }
534538

535539
static bool classof(const TypeRepr *T) {
536540
return T->getKind() == TypeReprKind::Function;

include/swift/AST/Types.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ class alignas(1 << TypeAlignInBits) TypeBase {
308308
}
309309

310310
protected:
311-
enum { NumAFTExtInfoBits = 8 };
311+
enum { NumAFTExtInfoBits = 9 };
312312
enum { NumSILExtInfoBits = 8 };
313313
union { uint64_t OpaqueBits;
314314

@@ -2969,7 +2969,7 @@ class AnyFunctionType : public TypeBase {
29692969
/// A class which abstracts out some details necessary for
29702970
/// making a call.
29712971
class ExtInfo {
2972-
// If bits are added or removed, then TypeBase::AnyFunctionTypeBits
2972+
// If bits are added or removed, then TypeBase::NumAFTExtInfoBits
29732973
// and NumMaskBits must be updated, and they must match.
29742974
//
29752975
// |representation|noEscape|throws|differentiability|
@@ -2978,10 +2978,11 @@ class AnyFunctionType : public TypeBase {
29782978
enum : unsigned {
29792979
RepresentationMask = 0xF << 0,
29802980
NoEscapeMask = 1 << 4,
2981-
ThrowsMask = 1 << 5,
2982-
DifferentiabilityMaskOffset = 6,
2981+
AsyncMask = 1 << 5,
2982+
ThrowsMask = 1 << 6,
2983+
DifferentiabilityMaskOffset = 7,
29832984
DifferentiabilityMask = 0x3 << DifferentiabilityMaskOffset,
2984-
NumMaskBits = 8
2985+
NumMaskBits = 9
29852986
};
29862987

29872988
unsigned Bits; // Naturally sized for speed.
@@ -3050,6 +3051,7 @@ class AnyFunctionType : public TypeBase {
30503051
}
30513052

30523053
bool isNoEscape() const { return Bits & NoEscapeMask; }
3054+
bool async() const { return Bits & AsyncMask; }
30533055
bool throws() const { return Bits & ThrowsMask; }
30543056
bool isDifferentiable() const {
30553057
return getDifferentiabilityKind() >
@@ -3119,6 +3121,11 @@ class AnyFunctionType : public TypeBase {
31193121
Other);
31203122
}
31213123
LLVM_NODISCARD
3124+
ExtInfo withAsync(bool Async = true) const {
3125+
return ExtInfo(Async ? (Bits | AsyncMask) : (Bits & ~AsyncMask),
3126+
Other);
3127+
}
3128+
LLVM_NODISCARD
31223129
ExtInfo withThrows(bool Throws = true) const {
31233130
return ExtInfo(Throws ? (Bits | ThrowsMask) : (Bits & ~ThrowsMask),
31243131
Other);
@@ -3377,6 +3384,10 @@ class AnyFunctionType : public TypeBase {
33773384
return getExtInfo().isNoEscape();
33783385
}
33793386

3387+
bool async() const {
3388+
return getExtInfo().async();
3389+
}
3390+
33803391
bool throws() const {
33813392
return getExtInfo().throws();
33823393
}

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ namespace swift {
235235
/// Enable experimental #assert feature.
236236
bool EnableExperimentalStaticAssert = false;
237237

238+
/// Enable experimental async concurrency model.
239+
bool EnableExperimentalAsync = false;
240+
238241
/// Should we check the target OSs of serialized modules to see that they're
239242
/// new enough?
240243
bool EnableTargetOSChecking = true;

0 commit comments

Comments
 (0)