Skip to content

Commit 4f6eb85

Browse files
committed
allow type initializers to be 'async'
implicit calls to an async super.init are not allowed
1 parent 7089bf6 commit 4f6eb85

19 files changed

+74
-38
lines changed

include/swift/AST/Decl.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6769,15 +6769,18 @@ class ConstructorDecl : public AbstractFunctionDecl {
67696769
public:
67706770
ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc,
67716771
bool Failable, SourceLoc FailabilityLoc,
6772+
bool Async, SourceLoc AsyncLoc,
67726773
bool Throws, SourceLoc ThrowsLoc,
67736774
ParameterList *BodyParams,
67746775
GenericParamList *GenericParams,
67756776
DeclContext *Parent);
67766777

67776778
static ConstructorDecl *
67786779
createImported(ASTContext &ctx, ClangNode clangNode, DeclName name,
6779-
SourceLoc constructorLoc, bool failable,
6780-
SourceLoc failabilityLoc, bool throws, SourceLoc throwsLoc,
6780+
SourceLoc constructorLoc,
6781+
bool failable, SourceLoc failabilityLoc,
6782+
bool async, SourceLoc asyncLoc,
6783+
bool throws, SourceLoc throwsLoc,
67816784
ParameterList *bodyParams, GenericParamList *genericParams,
67826785
DeclContext *parent);
67836786

include/swift/AST/DiagnosticsParse.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,6 @@ ERROR(expected_dynamic_func_attr,none,
762762
ERROR(async_after_throws,none,
763763
"%select{'async'|'reasync'}0 must precede %select{'throws'|'rethrows'}1",
764764
(bool, bool))
765-
ERROR(async_init,none, "initializer cannot be marked 'async'", ())
766765
ERROR(duplicate_effects_specifier,none,
767766
"'%0' has already been specified", (StringRef))
768767

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2605,12 +2605,8 @@ ERROR(override_dynamic_self_mismatch,none,
26052605
ERROR(override_class_declaration_in_extension,none,
26062606
"cannot override a non-dynamic class declaration from an extension",
26072607
())
2608-
ERROR(override_throws,none,
2609-
"cannot override non-throwing %select{method|initializer}0 with "
2610-
"throwing %select{method|initializer}0", (bool))
2611-
// TODO: this really could be merged with the above.
26122608
ERROR(override_with_more_effects,none,
2613-
"cannot override non-'%1' %0 with '%1' %0",
2609+
"cannot override non-%1 %0 with %1 %0",
26142610
(DescriptiveDeclKind, StringRef))
26152611
ERROR(override_throws_objc,none,
26162612
"overriding a throwing @objc %select{method|initializer}0 with "
@@ -3903,6 +3899,11 @@ ERROR(return_init_non_nil,none,
39033899
"'nil' is the only return value permitted in an initializer",
39043900
())
39053901

3902+
ERROR(implicit_async_super_init,none,
3903+
"missing call to superclass's initializer; "
3904+
"'super.init' is 'async' and requires an explicit call",
3905+
())
3906+
39063907
WARNING(if_always_true,none,
39073908
"'if' condition is always true", ())
39083909
WARNING(while_always_true,none,
@@ -4285,7 +4286,7 @@ NOTE(note_add_globalactor_to_function,none,
42854286
(StringRef, DescriptiveDeclKind, DeclName, Type))
42864287
FIXIT(insert_globalactor_attr, "@%0 ", (Type))
42874288
ERROR(not_objc_function_async,none,
4288-
"'async' function cannot be represented in Objective-C", ())
4289+
"'async' %0 cannot be represented in Objective-C", (DescriptiveDeclKind))
42894290
NOTE(not_objc_function_type_async,none,
42904291
"'async' function types cannot be represented in Objective-C", ())
42914292
ERROR(actor_isolated_objc,none,

lib/AST/Decl.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7672,13 +7672,13 @@ bool FuncDecl::isMainTypeMainMethod() const {
76727672

76737673
ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc,
76747674
bool Failable, SourceLoc FailabilityLoc,
7675-
bool Throws,
7676-
SourceLoc ThrowsLoc,
7675+
bool Async, SourceLoc AsyncLoc,
7676+
bool Throws, SourceLoc ThrowsLoc,
76777677
ParameterList *BodyParams,
76787678
GenericParamList *GenericParams,
76797679
DeclContext *Parent)
76807680
: AbstractFunctionDecl(DeclKind::Constructor, Parent, Name, ConstructorLoc,
7681-
/*Async=*/false, SourceLoc(), Throws, ThrowsLoc,
7681+
Async, AsyncLoc, Throws, ThrowsLoc,
76827682
/*HasImplicitSelfDecl=*/true,
76837683
GenericParams),
76847684
FailabilityLoc(FailabilityLoc),
@@ -7696,13 +7696,17 @@ ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc,
76967696
ConstructorDecl *ConstructorDecl::createImported(
76977697
ASTContext &ctx, ClangNode clangNode, DeclName name,
76987698
SourceLoc constructorLoc, bool failable, SourceLoc failabilityLoc,
7699+
bool async, SourceLoc asyncLoc,
76997700
bool throws, SourceLoc throwsLoc, ParameterList *bodyParams,
77007701
GenericParamList *genericParams, DeclContext *parent) {
77017702
void *declPtr = allocateMemoryForDecl<ConstructorDecl>(
77027703
ctx, sizeof(ConstructorDecl), true);
77037704
auto ctor = ::new (declPtr)
7704-
ConstructorDecl(name, constructorLoc, failable, failabilityLoc, throws,
7705-
throwsLoc, bodyParams, genericParams, parent);
7705+
ConstructorDecl(name, constructorLoc,
7706+
failable, failabilityLoc,
7707+
async, asyncLoc,
7708+
throws, throwsLoc,
7709+
bodyParams, genericParams, parent);
77067710
ctor->setClangNode(clangNode);
77077711
return ctor;
77087712
}

lib/ClangImporter/ImportDecl.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,7 @@ makeEnumRawValueConstructor(ClangImporter::Implementation &Impl,
535535
auto *ctorDecl =
536536
new (C) ConstructorDecl(name, enumDecl->getLoc(),
537537
/*Failable=*/true, /*FailabilityLoc=*/SourceLoc(),
538+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
538539
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
539540
paramPL,
540541
/*GenericParams=*/nullptr, enumDecl);
@@ -1305,6 +1306,7 @@ createDefaultConstructor(ClangImporter::Implementation &Impl,
13051306
auto constructor = new (context) ConstructorDecl(
13061307
name, structDecl->getLoc(),
13071308
/*Failable=*/false, /*FailabilityLoc=*/SourceLoc(),
1309+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
13081310
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), emptyPL,
13091311
/*GenericParams=*/nullptr, structDecl);
13101312

@@ -1432,6 +1434,7 @@ createValueConstructor(ClangImporter::Implementation &Impl,
14321434
auto constructor = new (context) ConstructorDecl(
14331435
name, structDecl->getLoc(),
14341436
/*Failable=*/false, /*FailabilityLoc=*/SourceLoc(),
1437+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
14351438
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), paramList,
14361439
/*GenericParams=*/nullptr, structDecl);
14371440

@@ -4132,9 +4135,11 @@ namespace {
41324135
DeclName ctorName(Impl.SwiftContext, DeclBaseName::createConstructor(),
41334136
bodyParams);
41344137
result = Impl.createDeclWithClangNode<ConstructorDecl>(
4135-
clangNode, AccessLevel::Public, ctorName, loc, /*failable=*/false,
4136-
/*FailabilityLoc=*/SourceLoc(), /*Throws=*/false,
4137-
/*ThrowsLoc=*/SourceLoc(), bodyParams, genericParams, dc);
4138+
clangNode, AccessLevel::Public, ctorName, loc,
4139+
/*failable=*/false, /*FailabilityLoc=*/SourceLoc(),
4140+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
4141+
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
4142+
bodyParams, genericParams, dc);
41384143
} else {
41394144
auto resultTy = importedType.getType();
41404145

@@ -6514,6 +6519,7 @@ Decl *SwiftDeclConverter::importGlobalAsInitializer(
65146519
auto result = Impl.createDeclWithClangNode<ConstructorDecl>(
65156520
decl, AccessLevel::Public, name, /*NameLoc=*/SourceLoc(),
65166521
failable, /*FailabilityLoc=*/SourceLoc(),
6522+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
65176523
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), parameterList,
65186524
/*GenericParams=*/nullptr, dc);
65196525
result->setImplicitlyUnwrappedOptional(isIUO);
@@ -6998,6 +7004,7 @@ ConstructorDecl *SwiftDeclConverter::importConstructor(
69987004
auto result = Impl.createDeclWithClangNode<ConstructorDecl>(
69997005
objcMethod, AccessLevel::Public, importedName.getDeclName(),
70007006
/*NameLoc=*/SourceLoc(), failability, /*FailabilityLoc=*/SourceLoc(),
7007+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
70017008
/*Throws=*/importedName.getErrorInfo().hasValue(),
70027009
/*ThrowsLoc=*/SourceLoc(), bodyParams,
70037010
/*GenericParams=*/nullptr, const_cast<DeclContext *>(dc));

lib/ClangImporter/ImportName.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,6 +1286,7 @@ NameImporter::considerAsyncImport(
12861286

12871287
// Initializers cannot be 'async'.
12881288
// FIXME: We might eventually allow this.
1289+
// TODO: should the restriction be lifted in ClangImporter?
12891290
if (isInitializer)
12901291
return notAsync("initializers cannot be async");
12911292

lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8005,19 +8005,12 @@ Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
80058005
Attributes.add(new (Context) RethrowsAttr(throwsLoc));
80068006
}
80078007

8008-
// Initializers cannot be 'async'.
8009-
// FIXME: We should be able to lift this restriction.
8010-
if (asyncLoc.isValid()) {
8011-
diagnose(asyncLoc, diag::async_init)
8012-
.fixItRemove(asyncLoc);
8013-
asyncLoc = SourceLoc();
8014-
}
8015-
80168008
diagnoseWhereClauseInGenericParamList(GenericParams);
80178009

80188010
DeclName FullName(Context, DeclBaseName::createConstructor(), namePieces);
80198011
auto *CD = new (Context) ConstructorDecl(FullName, ConstructorLoc,
80208012
Failable, FailabilityLoc,
8013+
asyncLoc.isValid(), asyncLoc,
80218014
throwsLoc.isValid(), throwsLoc,
80228015
Params.get(), GenericParams,
80238016
CurDeclContext);

lib/Sema/CSApply.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,11 @@ static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate(
141141
if (isa<ConstructorDecl>(oldDecl)) {
142142
DeclName ctorName(ctx, DeclBaseName::createConstructor(), newParamList);
143143
auto newCtorDecl = ConstructorDecl::createImported(
144-
ctx, specialized, ctorName, oldDecl->getLoc(), /*failable=*/false,
145-
/*failabilityLoc=*/SourceLoc(), /*throws=*/false,
146-
/*throwsLoc=*/SourceLoc(), newParamList, /*genericParams=*/nullptr,
144+
ctx, specialized, ctorName, oldDecl->getLoc(),
145+
/*failable=*/false, /*failabilityLoc=*/SourceLoc(),
146+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
147+
/*throws=*/false, /*throwsLoc=*/SourceLoc(),
148+
newParamList, /*genericParams=*/nullptr,
147149
oldDecl->getDeclContext());
148150
return ConcreteDeclRef(newCtorDecl);
149151
}

lib/Sema/CodeSynthesis.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
319319
auto *ctor =
320320
new (ctx) ConstructorDecl(name, Loc,
321321
/*Failable=*/false, /*FailabilityLoc=*/SourceLoc(),
322+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
322323
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
323324
paramList, /*GenericParams=*/nullptr, decl);
324325

@@ -744,6 +745,7 @@ createDesignatedInitOverride(ClassDecl *classDecl,
744745
classDecl->getBraces().Start,
745746
superclassCtor->isFailable(),
746747
/*FailabilityLoc=*/SourceLoc(),
748+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
747749
/*Throws=*/superclassCtor->hasThrows(),
748750
/*ThrowsLoc=*/SourceLoc(),
749751
bodyParams, genericParams, classDecl);

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1847,6 +1847,7 @@ static ValueDecl *deriveDecodable_init(DerivedConformance &derived) {
18471847
auto *initDecl =
18481848
new (C) ConstructorDecl(name, SourceLoc(),
18491849
/*Failable=*/false,SourceLoc(),
1850+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
18501851
/*Throws=*/true, SourceLoc(), paramList,
18511852
/*GenericParams=*/nullptr, conformanceDC);
18521853
initDecl->setImplicit();

lib/Sema/DerivedConformanceCodingKey.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ static ValueDecl *deriveInitDecl(DerivedConformance &derived, Type paramType,
130130
auto *initDecl =
131131
new (C) ConstructorDecl(name, SourceLoc(),
132132
/*Failable=*/true, /*FailabilityLoc=*/SourceLoc(),
133+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
133134
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
134135
paramList,
135136
/*GenericParams=*/nullptr, parentDC);

lib/Sema/DerivedConformanceRawRepresentable.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ deriveRawRepresentable_init(DerivedConformance &derived) {
425425
auto initDecl =
426426
new (C) ConstructorDecl(name, SourceLoc(),
427427
/*Failable=*/ true, /*FailabilityLoc=*/SourceLoc(),
428+
/*Async=*/false, /*AsyncLoc=*/SourceLoc(),
428429
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
429430
paramList,
430431
/*GenericParams=*/nullptr, parentDC);

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,7 @@ bool swift::isRepresentableInObjC(
682682
// information into a completion handler.
683683
auto FD = dyn_cast<FuncDecl>(AFD);
684684
if (!FD) {
685-
AFD->diagnose(diag::not_objc_function_async)
685+
AFD->diagnose(diag::not_objc_function_async, AFD->getDescriptiveKind())
686686
.highlight(AFD->getAsyncLoc())
687687
.limitBehavior(behavior);
688688
describeObjCReason(AFD, Reason);

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1829,7 +1829,7 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) {
18291829
return true;
18301830
} else if (!overrideASD->isLessEffectfulThan(baseASD, EffectKind::Throws)) {
18311831
diags.diagnose(overrideASD, diag::override_with_more_effects,
1832-
overrideASD->getDescriptiveKind(), "throws");
1832+
overrideASD->getDescriptiveKind(), "throwing");
18331833
return true;
18341834
}
18351835
}
@@ -1913,12 +1913,19 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) {
19131913
}
19141914
}
19151915
// If the overriding declaration is 'throws' but the base is not,
1916-
// complain.
1916+
// complain. Do the same for 'async'
19171917
if (auto overrideFn = dyn_cast<AbstractFunctionDecl>(override)) {
19181918
if (overrideFn->hasThrows() &&
19191919
!cast<AbstractFunctionDecl>(base)->hasThrows()) {
1920-
diags.diagnose(override, diag::override_throws,
1921-
isa<ConstructorDecl>(override));
1920+
diags.diagnose(override, diag::override_with_more_effects,
1921+
override->getDescriptiveKind(), "throwing");
1922+
diags.diagnose(base, diag::overridden_here);
1923+
}
1924+
1925+
if (overrideFn->hasAsync() &&
1926+
!cast<AbstractFunctionDecl>(base)->hasAsync()) {
1927+
diags.diagnose(override, diag::override_with_more_effects,
1928+
override->getDescriptiveKind(), "async");
19221929
diags.diagnose(base, diag::overridden_here);
19231930
}
19241931

lib/Sema/TypeCheckStmt.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1597,6 +1597,9 @@ static Type getResultBuilderType(FuncDecl *FD) {
15971597
return builderType;
15981598
}
15991599

1600+
/// Attempts to build an implicit call within the provided constructor
1601+
/// to the provided class's zero-argument super initializer.
1602+
/// @returns nullptr if there was an error and a diagnostic was emitted.
16001603
static Expr* constructCallToSuperInit(ConstructorDecl *ctor,
16011604
ClassDecl *ClDecl) {
16021605
ASTContext &Context = ctor->getASTContext();
@@ -1643,7 +1646,7 @@ static bool checkSuperInit(ConstructorDecl *fromCtor,
16431646
}
16441647
return true;
16451648
}
1646-
1649+
16471650
// For an implicitly generated super.init() call, make sure there's
16481651
// only one designated initializer.
16491652
if (implicitlyGenerated) {
@@ -1681,6 +1684,13 @@ static bool checkSuperInit(ConstructorDecl *fromCtor,
16811684
ctor->getDescriptiveKind(), ctor->getName(),
16821685
superclassDecl->getName());
16831686
}
1687+
1688+
// Not allowed to implicitly generate a super.init() call if the init
1689+
// is async; that would hide the 'await' from the programmer.
1690+
if (ctor->hasAsync()) {
1691+
fromCtor->diagnose(diag::implicit_async_super_init);
1692+
return true; // considered an error
1693+
}
16841694
}
16851695

16861696

lib/Serialization/Deserialization.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2742,7 +2742,7 @@ class DeclDeserializer {
27422742
StringRef blobData) {
27432743
DeclContextID contextID;
27442744
bool isIUO, isFailable;
2745-
bool isImplicit, isObjC, hasStubImplementation, throws;
2745+
bool isImplicit, isObjC, hasStubImplementation, throws, async;
27462746
GenericSignatureID genericSigID;
27472747
uint8_t storedInitKind, rawAccessLevel;
27482748
DeclID overriddenID;
@@ -2753,7 +2753,7 @@ class DeclDeserializer {
27532753
decls_block::ConstructorLayout::readRecord(scratch, contextID,
27542754
isFailable, isIUO, isImplicit,
27552755
isObjC, hasStubImplementation,
2756-
throws, storedInitKind,
2756+
async, throws, storedInitKind,
27572757
genericSigID,
27582758
overriddenID,
27592759
rawAccessLevel,
@@ -2808,6 +2808,8 @@ class DeclDeserializer {
28082808

28092809
auto ctor = MF.createDecl<ConstructorDecl>(name, SourceLoc(), isFailable,
28102810
/*FailabilityLoc=*/SourceLoc(),
2811+
/*Async=*/async,
2812+
/*AsyncLoc=*/SourceLoc(),
28112813
/*Throws=*/throws,
28122814
/*ThrowsLoc=*/SourceLoc(),
28132815
/*BodyParams=*/nullptr,

lib/Serialization/ModuleFormat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5656
/// describe what change you made. The content of this comment isn't important;
5757
/// it just ensures a conflict if two people change the module format.
5858
/// Don't worry about adhering to the 80-column limit for this line.
59-
const uint16_t SWIFTMODULE_VERSION_MINOR = 609; // extract_executor SIL inst
59+
const uint16_t SWIFTMODULE_VERSION_MINOR = 610; // async initializers for nominal types
6060

6161
/// A standard hash seed used for all string hashes in a serialized module.
6262
///
@@ -1264,6 +1264,7 @@ namespace decls_block {
12641264
BCFixed<1>, // implicit?
12651265
BCFixed<1>, // objc?
12661266
BCFixed<1>, // stub implementation?
1267+
BCFixed<1>, // async?
12671268
BCFixed<1>, // throws?
12681269
CtorInitializerKindField, // initializer kind
12691270
GenericSignatureIDField, // generic environment

lib/Serialization/Serialization.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3884,6 +3884,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
38843884
ctor->isImplicit(),
38853885
ctor->isObjC(),
38863886
ctor->hasStubImplementation(),
3887+
ctor->hasAsync(),
38873888
ctor->hasThrows(),
38883889
getStableCtorInitializerKind(
38893890
ctor->getInitKind()),

test/Parse/async.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func asyncGlobal8() async throws async -> async Int async {}
2828
// expected-error@-3{{'async' has already been specified}} {{53-59=}}
2929

3030
class X {
31-
init() async { } // expected-error{{initializer cannot be marked 'async'}}
31+
init() async { }
3232

3333
deinit async { } // expected-error{{deinitializers cannot have a name}}
3434

0 commit comments

Comments
 (0)