Skip to content

Commit f9452b2

Browse files
committed
implement parsing for effects specifiers on 'get' accessors
An effectful 'get' accessor must be the only accessor for the property.
1 parent 58f03e8 commit f9452b2

15 files changed

+226
-39
lines changed

include/swift/AST/Decl.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6327,16 +6327,18 @@ class AccessorDecl final : public FuncDecl {
63276327
AccessorDecl(SourceLoc declLoc, SourceLoc accessorKeywordLoc,
63286328
AccessorKind accessorKind, AbstractStorageDecl *storage,
63296329
SourceLoc staticLoc, StaticSpellingKind staticSpelling,
6330-
bool throws, SourceLoc throwsLoc,
6330+
bool async, SourceLoc asyncLoc, bool throws, SourceLoc throwsLoc,
63316331
bool hasImplicitSelfDecl, GenericParamList *genericParams,
63326332
DeclContext *parent)
63336333
: FuncDecl(DeclKind::Accessor,
63346334
staticLoc, staticSpelling, /*func loc*/ declLoc,
63356335
/*name*/ Identifier(), /*name loc*/ declLoc,
6336-
/*Async=*/false, SourceLoc(), throws, throwsLoc,
6336+
async, asyncLoc, throws, throwsLoc,
63376337
hasImplicitSelfDecl, genericParams, parent),
63386338
AccessorKeywordLoc(accessorKeywordLoc),
63396339
Storage(storage) {
6340+
assert(!async || accessorKind == AccessorKind::Get
6341+
&& "only get accessors can be async");
63406342
Bits.AccessorDecl.AccessorKind = unsigned(accessorKind);
63416343
}
63426344

@@ -6347,6 +6349,7 @@ class AccessorDecl final : public FuncDecl {
63476349
AbstractStorageDecl *storage,
63486350
SourceLoc staticLoc,
63496351
StaticSpellingKind staticSpelling,
6352+
bool async, SourceLoc asyncLoc,
63506353
bool throws, SourceLoc throwsLoc,
63516354
GenericParamList *genericParams,
63526355
DeclContext *parent,
@@ -6365,7 +6368,7 @@ class AccessorDecl final : public FuncDecl {
63656368
AccessorKind accessorKind,
63666369
AbstractStorageDecl *storage,
63676370
StaticSpellingKind staticSpelling,
6368-
bool throws,
6371+
bool async, bool throws,
63696372
GenericParamList *genericParams,
63706373
Type fnRetType, DeclContext *parent);
63716374

@@ -6375,6 +6378,7 @@ class AccessorDecl final : public FuncDecl {
63756378
AbstractStorageDecl *storage,
63766379
SourceLoc staticLoc,
63776380
StaticSpellingKind staticSpelling,
6381+
bool async, SourceLoc asyncLoc,
63786382
bool throws, SourceLoc throwsLoc,
63796383
GenericParamList *genericParams,
63806384
ParameterList *parameterList,

include/swift/AST/DiagnosticsParse.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,12 @@ ERROR(expected_lbrace_accessor,PointsToFirstBadToken,
278278
ERROR(expected_accessor_kw,none,
279279
"expected 'get', 'set', 'willSet', or 'didSet' keyword to "
280280
"start an accessor definition",())
281+
ERROR(invalid_accessor_specifier,none,
282+
"'%0' accessor cannot have specifier '%1'",
283+
(StringRef, StringRef))
284+
ERROR(invalid_accessor_with_effectful_get,none,
285+
"'%0' accessor is not allowed on property with 'get' accessor that is 'async' or 'throws'",
286+
(StringRef))
281287
ERROR(missing_getter,none,
282288
"%select{variable|subscript}0 with %1 must also have a getter",
283289
(unsigned, StringRef))

include/swift/AST/StorageImpl.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ enum class AccessorKind {
4545
#define ACCESSOR(ID) ID,
4646
#define LAST_ACCESSOR(ID) Last = ID
4747
#include "swift/AST/AccessorKinds.def"
48+
#undef ACCESSOR
49+
#undef LAST_ACCESSOR
4850
};
4951

5052
const unsigned NumAccessorKinds = unsigned(AccessorKind::Last) + 1;
@@ -54,6 +56,22 @@ static inline IntRange<AccessorKind> allAccessorKinds() {
5456
AccessorKind(NumAccessorKinds));
5557
}
5658

59+
/// \returns a user-readable string name for the accessor kind
60+
static inline StringRef accessorKindName(AccessorKind ak) {
61+
switch(ak) {
62+
63+
#define ACCESSOR(ID) ID
64+
#define SINGLETON_ACCESSOR(ID, KEYWORD) \
65+
case AccessorKind::ID: \
66+
return #KEYWORD;
67+
68+
#include "swift/AST/AccessorKinds.def"
69+
70+
#undef ACCESSOR_KEYWORD
71+
#undef SINGLETON_ACCESSOR
72+
}
73+
}
74+
5775
/// Whether an access to storage is for reading, writing, or both.
5876
enum class AccessKind : uint8_t {
5977
/// The access is just to read the current value.

include/swift/Parse/Parser.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,12 @@ class Parser {
11581158
bool hasInitializer,
11591159
const DeclAttributes &Attributes,
11601160
SmallVectorImpl<Decl *> &Decls);
1161+
ParserStatus parseGetEffectSpecifier(ParsedAccessors &accessors,
1162+
SourceLoc &asyncLoc,
1163+
SourceLoc &throwsLoc,
1164+
bool &hasEffectfulGet,
1165+
AccessorKind currentKind,
1166+
SourceLoc const& currentLoc);
11611167

11621168
void consumeAbstractFunctionBody(AbstractFunctionDecl *AFD,
11631169
const DeclAttributes &Attrs);

lib/AST/ASTPrinter.cpp

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,24 @@ static StaticSpellingKind getCorrectStaticSpelling(const Decl *D) {
10181018
}
10191019
}
10201020

1021+
static bool hasAsyncGetter(const AbstractStorageDecl *ASD) {
1022+
if (auto getter = ASD->getAccessor(AccessorKind::Get)) {
1023+
assert(!getter->getAttrs().hasAttribute<ReasyncAttr>());
1024+
return getter->hasAsync();
1025+
}
1026+
1027+
return false;
1028+
}
1029+
1030+
static bool hasThrowsGetter(const AbstractStorageDecl *ASD) {
1031+
if (auto getter = ASD->getAccessor(AccessorKind::Get)) {
1032+
assert(!getter->getAttrs().hasAttribute<RethrowsAttr>());
1033+
return getter->hasThrows();
1034+
}
1035+
1036+
return false;
1037+
}
1038+
10211039
static bool hasMutatingGetter(const AbstractStorageDecl *ASD) {
10221040
return ASD->getAccessor(AccessorKind::Get) && ASD->isGetterMutating();
10231041
}
@@ -1925,6 +1943,15 @@ void PrintAST::printAccessors(const AbstractStorageDecl *ASD) {
19251943
return;
19261944
}
19271945

1946+
// prints with a space prefixed
1947+
auto printWithSpace = [&](StringRef word) {
1948+
Printer << " ";
1949+
Printer.printKeyword(word, Options);
1950+
};
1951+
1952+
const bool asyncGet = hasAsyncGetter(ASD);
1953+
const bool throwsGet = hasThrowsGetter(ASD);
1954+
19281955
// We sometimes want to print the accessors abstractly
19291956
// instead of listing out how they're actually implemented.
19301957
bool inProtocol = isa<ProtocolDecl>(ASD->getDeclContext());
@@ -1935,27 +1962,27 @@ void PrintAST::printAccessors(const AbstractStorageDecl *ASD) {
19351962
bool nonmutatingSetter = hasNonMutatingSetter(ASD);
19361963

19371964
// We're about to print something like this:
1938-
// { mutating? get (nonmutating? set)? }
1965+
// { mutating? get async? throws? (nonmutating? set)? }
19391966
// But don't print "{ get set }" if we don't have to.
19401967
if (!inProtocol && !Options.PrintGetSetOnRWProperties &&
1941-
settable && !mutatingGetter && !nonmutatingSetter) {
1968+
settable && !mutatingGetter && !nonmutatingSetter
1969+
&& !asyncGet && !throwsGet) {
19421970
return;
19431971
}
19441972

19451973
Printer << " {";
1946-
if (mutatingGetter) {
1947-
Printer << " ";
1948-
Printer.printKeyword("mutating", Options);
1949-
}
1950-
Printer << " ";
1951-
Printer.printKeyword("get", Options);
1974+
if (mutatingGetter) printWithSpace("mutating");
1975+
1976+
printWithSpace("get");
1977+
1978+
if (asyncGet) printWithSpace("async");
1979+
1980+
if (throwsGet) printWithSpace("throws");
1981+
19521982
if (settable) {
1953-
if (nonmutatingSetter) {
1954-
Printer << " ";
1955-
Printer.printKeyword("nonmutating", Options);
1956-
}
1957-
Printer << " ";
1958-
Printer.printKeyword("set", Options);
1983+
if (nonmutatingSetter) printWithSpace("nonmutating");
1984+
1985+
printWithSpace("set");
19591986
}
19601987
Printer << " }";
19611988
return;
@@ -1983,7 +2010,8 @@ void PrintAST::printAccessors(const AbstractStorageDecl *ASD) {
19832010
!Options.PrintGetSetOnRWProperties &&
19842011
!Options.FunctionDefinitions &&
19852012
!ASD->isGetterMutating() &&
1986-
!ASD->getAccessor(AccessorKind::Set)->isExplicitNonMutating()) {
2013+
!ASD->getAccessor(AccessorKind::Set)->isExplicitNonMutating() &&
2014+
!asyncGet && !throwsGet) {
19872015
return;
19882016
}
19892017

@@ -1999,7 +2027,15 @@ void PrintAST::printAccessors(const AbstractStorageDecl *ASD) {
19992027
if (!PrintAccessorBody) {
20002028
Printer << " ";
20012029
printMutabilityModifiersIfNeeded(Accessor);
2030+
20022031
Printer.printKeyword(getAccessorLabel(Accessor->getAccessorKind()), Options);
2032+
2033+
// handle any effects specifiers
2034+
if (Accessor->getAccessorKind() == AccessorKind::Get) {
2035+
if (asyncGet) printWithSpace("async");
2036+
if (throwsGet) printWithSpace("throws");
2037+
}
2038+
20032039
} else {
20042040
{
20052041
IndentRAII IndentMore(*this);
@@ -2017,7 +2053,8 @@ void PrintAST::printAccessors(const AbstractStorageDecl *ASD) {
20172053
bool isOnlyGetter = impl.getReadImpl() == ReadImplKind::Get &&
20182054
ASD->getAccessor(AccessorKind::Get);
20192055
bool isGetterMutating = ASD->supportsMutation() || ASD->isGetterMutating();
2020-
if (isOnlyGetter && !isGetterMutating && PrintAccessorBody &&
2056+
bool hasEffects = asyncGet || throwsGet;
2057+
if (isOnlyGetter && !isGetterMutating && !hasEffects && PrintAccessorBody &&
20212058
Options.FunctionBody && Options.CollapseSingleGetterProperty) {
20222059
Options.FunctionBody(ASD->getAccessor(AccessorKind::Get), Printer);
20232060
indent();

lib/AST/Decl.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7420,6 +7420,7 @@ AccessorDecl *AccessorDecl::createImpl(ASTContext &ctx,
74207420
AbstractStorageDecl *storage,
74217421
SourceLoc staticLoc,
74227422
StaticSpellingKind staticSpelling,
7423+
bool async, SourceLoc asyncLoc,
74237424
bool throws, SourceLoc throwsLoc,
74247425
GenericParamList *genericParams,
74257426
DeclContext *parent,
@@ -7432,7 +7433,7 @@ AccessorDecl *AccessorDecl::createImpl(ASTContext &ctx,
74327433
!clangNode.isNull());
74337434
auto D = ::new (buffer)
74347435
AccessorDecl(declLoc, accessorKeywordLoc, accessorKind,
7435-
storage, staticLoc, staticSpelling, throws, throwsLoc,
7436+
storage, staticLoc, staticSpelling, async, asyncLoc, throws, throwsLoc,
74367437
hasImplicitSelfDecl, genericParams, parent);
74377438
if (clangNode)
74387439
D->setClangNode(clangNode);
@@ -7446,12 +7447,12 @@ AccessorDecl *
74467447
AccessorDecl::createDeserialized(ASTContext &ctx, AccessorKind accessorKind,
74477448
AbstractStorageDecl *storage,
74487449
StaticSpellingKind staticSpelling,
7449-
bool throws, GenericParamList *genericParams,
7450+
bool async, bool throws, GenericParamList *genericParams,
74507451
Type fnRetType, DeclContext *parent) {
74517452
assert(fnRetType && "Deserialized result type must not be null");
74527453
auto *const D = AccessorDecl::createImpl(
74537454
ctx, SourceLoc(), SourceLoc(), accessorKind, storage, SourceLoc(),
7454-
staticSpelling, throws, SourceLoc(), genericParams, parent, ClangNode());
7455+
staticSpelling, async, SourceLoc(), throws, SourceLoc(), genericParams, parent, ClangNode());
74557456
D->setResultInterfaceType(fnRetType);
74567457
return D;
74577458
}
@@ -7463,6 +7464,7 @@ AccessorDecl *AccessorDecl::create(ASTContext &ctx,
74637464
AbstractStorageDecl *storage,
74647465
SourceLoc staticLoc,
74657466
StaticSpellingKind staticSpelling,
7467+
bool async, SourceLoc asyncLoc,
74667468
bool throws, SourceLoc throwsLoc,
74677469
GenericParamList *genericParams,
74687470
ParameterList * bodyParams,
@@ -7471,7 +7473,7 @@ AccessorDecl *AccessorDecl::create(ASTContext &ctx,
74717473
ClangNode clangNode) {
74727474
auto *D = AccessorDecl::createImpl(
74737475
ctx, declLoc, accessorKeywordLoc, accessorKind, storage,
7474-
staticLoc, staticSpelling, throws, throwsLoc,
7476+
staticLoc, staticSpelling, async, asyncLoc, throws, throwsLoc,
74757477
genericParams, parent, clangNode);
74767478
D->setParameters(bodyParams);
74777479
D->setResultInterfaceType(fnRetType);

lib/ClangImporter/ImportDecl.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,11 @@ static FuncDecl *createFuncOrAccessor(ASTContext &ctx, SourceLoc funcLoc,
171171
/*accessorKeywordLoc*/ SourceLoc(),
172172
accessorInfo->Kind, accessorInfo->Storage,
173173
/*StaticLoc*/ SourceLoc(),
174-
StaticSpellingKind::None, throws,
175-
/*ThrowsLoc=*/SourceLoc(), genericParams,
176-
bodyParams, resultTy, dc, clangNode);
174+
StaticSpellingKind::None,
175+
throws, /*ThrowsLoc=*/SourceLoc(),
176+
async, /*AsyncLoc=*/SourceLoc(),
177+
genericParams, bodyParams,
178+
resultTy, dc, clangNode);
177179
} else {
178180
return FuncDecl::createImported(ctx, funcLoc, name, nameLoc, async, throws,
179181
bodyParams, resultTy, genericParams, dc,
@@ -606,6 +608,7 @@ static void makeEnumRawValueGetter(ClangImporter::Implementation &Impl,
606608
rawValueDecl,
607609
/*StaticLoc=*/SourceLoc(),
608610
StaticSpellingKind::None,
611+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
609612
/*Throws=*/false,
610613
/*ThrowsLoc=*/SourceLoc(),
611614
/*GenericParams=*/nullptr, params,
@@ -682,6 +685,7 @@ static AccessorDecl *makeStructRawValueGetter(
682685
computedVar,
683686
/*StaticLoc=*/SourceLoc(),
684687
StaticSpellingKind::None,
688+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
685689
/*Throws=*/false,
686690
/*ThrowsLoc=*/SourceLoc(),
687691
/*GenericParams=*/nullptr, params,
@@ -712,6 +716,7 @@ static AccessorDecl *makeFieldGetterDecl(ClangImporter::Implementation &Impl,
712716
importedFieldDecl,
713717
/*StaticLoc=*/SourceLoc(),
714718
StaticSpellingKind::None,
719+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
715720
/*Throws=*/false,
716721
/*ThrowsLoc=*/SourceLoc(),
717722
/*GenericParams=*/nullptr, params,
@@ -745,6 +750,7 @@ static AccessorDecl *makeFieldSetterDecl(ClangImporter::Implementation &Impl,
745750
importedFieldDecl,
746751
/*StaticLoc=*/SourceLoc(),
747752
StaticSpellingKind::None,
753+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
748754
/*Throws=*/false,
749755
/*ThrowsLoc=*/SourceLoc(),
750756
/*GenericParams=*/nullptr, params,
@@ -1690,6 +1696,7 @@ buildSubscriptGetterDecl(ClangImporter::Implementation &Impl,
16901696
subscript,
16911697
/*StaticLoc=*/SourceLoc(),
16921698
subscript->getStaticSpelling(),
1699+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
16931700
/*Throws=*/false,
16941701
/*ThrowsLoc=*/SourceLoc(),
16951702
/*GenericParams=*/nullptr,
@@ -1741,6 +1748,7 @@ buildSubscriptSetterDecl(ClangImporter::Implementation &Impl,
17411748
subscript,
17421749
/*StaticLoc=*/SourceLoc(),
17431750
subscript->getStaticSpelling(),
1751+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
17441752
/*Throws=*/false,
17451753
/*ThrowsLoc=*/SourceLoc(),
17461754
/*GenericParams=*/nullptr,
@@ -1926,6 +1934,7 @@ static bool addErrorDomain(NominalTypeDecl *swiftDecl,
19261934
errorDomainPropertyDecl,
19271935
/*StaticLoc=*/SourceLoc(),
19281936
StaticSpellingKind::None,
1937+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
19291938
/*Throws=*/false,
19301939
/*ThrowsLoc=*/SourceLoc(),
19311940
/*GenericParams=*/nullptr,
@@ -4281,6 +4290,7 @@ namespace {
42814290
auto accessor = AccessorDecl::create(
42824291
Impl.SwiftContext, SourceLoc(), SourceLoc(), AccessorKind::Get,
42834292
swiftVar, SourceLoc(), StaticSpellingKind::KeywordStatic,
4293+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
42844294
/*throws=*/false, SourceLoc(), /*genericParams*/ nullptr,
42854295
ParameterList::createEmpty(Impl.SwiftContext), swiftVar->getType(),
42864296
swiftVar->getDeclContext());
@@ -9121,6 +9131,7 @@ ClangImporter::Implementation::createConstant(Identifier name, DeclContext *dc,
91219131
var,
91229132
/*StaticLoc=*/SourceLoc(),
91239133
StaticSpellingKind::None,
9134+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
91249135
/*Throws=*/false,
91259136
/*ThrowsLoc=*/SourceLoc(),
91269137
/*GenericParams=*/nullptr,

0 commit comments

Comments
 (0)