diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 3f0dde90ebca4..aadd549ccaf33 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -6769,6 +6769,7 @@ class ConstructorDecl : public AbstractFunctionDecl { public: ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, bool Failable, SourceLoc FailabilityLoc, + bool Async, SourceLoc AsyncLoc, bool Throws, SourceLoc ThrowsLoc, ParameterList *BodyParams, GenericParamList *GenericParams, @@ -6776,8 +6777,10 @@ class ConstructorDecl : public AbstractFunctionDecl { static ConstructorDecl * createImported(ASTContext &ctx, ClangNode clangNode, DeclName name, - SourceLoc constructorLoc, bool failable, - SourceLoc failabilityLoc, bool throws, SourceLoc throwsLoc, + SourceLoc constructorLoc, + bool failable, SourceLoc failabilityLoc, + bool async, SourceLoc asyncLoc, + bool throws, SourceLoc throwsLoc, ParameterList *bodyParams, GenericParamList *genericParams, DeclContext *parent); diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 97bc41afe9d78..55b513c134528 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -762,7 +762,6 @@ ERROR(expected_dynamic_func_attr,none, ERROR(async_after_throws,none, "%select{'async'|'reasync'}0 must precede %select{'throws'|'rethrows'}1", (bool, bool)) -ERROR(async_init,none, "initializer cannot be marked 'async'", ()) ERROR(duplicate_effects_specifier,none, "'%0' has already been specified", (StringRef)) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 88fea2f7d701a..39b51e0e8d655 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2605,12 +2605,8 @@ ERROR(override_dynamic_self_mismatch,none, ERROR(override_class_declaration_in_extension,none, "cannot override a non-dynamic class declaration from an extension", ()) -ERROR(override_throws,none, - "cannot override non-throwing %select{method|initializer}0 with " - "throwing %select{method|initializer}0", (bool)) -// TODO: this really could be merged with the above. ERROR(override_with_more_effects,none, - "cannot override non-'%1' %0 with '%1' %0", + "cannot override non-%1 %0 with %1 %0", (DescriptiveDeclKind, StringRef)) ERROR(override_throws_objc,none, "overriding a throwing @objc %select{method|initializer}0 with " @@ -3903,6 +3899,11 @@ ERROR(return_init_non_nil,none, "'nil' is the only return value permitted in an initializer", ()) +ERROR(implicit_async_super_init,none, + "missing call to superclass's initializer; " + "'super.init' is 'async' and requires an explicit call", + ()) + WARNING(if_always_true,none, "'if' condition is always true", ()) WARNING(while_always_true,none, @@ -4285,7 +4286,7 @@ NOTE(note_add_globalactor_to_function,none, (StringRef, DescriptiveDeclKind, DeclName, Type)) FIXIT(insert_globalactor_attr, "@%0 ", (Type)) ERROR(not_objc_function_async,none, - "'async' function cannot be represented in Objective-C", ()) + "'async' %0 cannot be represented in Objective-C", (DescriptiveDeclKind)) NOTE(not_objc_function_type_async,none, "'async' function types cannot be represented in Objective-C", ()) ERROR(actor_isolated_objc,none, diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 03e910f329715..ac5f8d3d289fc 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -7672,13 +7672,13 @@ bool FuncDecl::isMainTypeMainMethod() const { ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, bool Failable, SourceLoc FailabilityLoc, - bool Throws, - SourceLoc ThrowsLoc, + bool Async, SourceLoc AsyncLoc, + bool Throws, SourceLoc ThrowsLoc, ParameterList *BodyParams, GenericParamList *GenericParams, DeclContext *Parent) : AbstractFunctionDecl(DeclKind::Constructor, Parent, Name, ConstructorLoc, - /*Async=*/false, SourceLoc(), Throws, ThrowsLoc, + Async, AsyncLoc, Throws, ThrowsLoc, /*HasImplicitSelfDecl=*/true, GenericParams), FailabilityLoc(FailabilityLoc), @@ -7696,13 +7696,17 @@ ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, ConstructorDecl *ConstructorDecl::createImported( ASTContext &ctx, ClangNode clangNode, DeclName name, SourceLoc constructorLoc, bool failable, SourceLoc failabilityLoc, + bool async, SourceLoc asyncLoc, bool throws, SourceLoc throwsLoc, ParameterList *bodyParams, GenericParamList *genericParams, DeclContext *parent) { void *declPtr = allocateMemoryForDecl( ctx, sizeof(ConstructorDecl), true); auto ctor = ::new (declPtr) - ConstructorDecl(name, constructorLoc, failable, failabilityLoc, throws, - throwsLoc, bodyParams, genericParams, parent); + ConstructorDecl(name, constructorLoc, + failable, failabilityLoc, + async, asyncLoc, + throws, throwsLoc, + bodyParams, genericParams, parent); ctor->setClangNode(clangNode); return ctor; } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 99545cb95ad56..8b61d09f1413a 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -535,6 +535,7 @@ makeEnumRawValueConstructor(ClangImporter::Implementation &Impl, auto *ctorDecl = new (C) ConstructorDecl(name, enumDecl->getLoc(), /*Failable=*/true, /*FailabilityLoc=*/SourceLoc(), + /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), paramPL, /*GenericParams=*/nullptr, enumDecl); @@ -1305,6 +1306,7 @@ createDefaultConstructor(ClangImporter::Implementation &Impl, auto constructor = new (context) ConstructorDecl( name, structDecl->getLoc(), /*Failable=*/false, /*FailabilityLoc=*/SourceLoc(), + /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), emptyPL, /*GenericParams=*/nullptr, structDecl); @@ -1432,6 +1434,7 @@ createValueConstructor(ClangImporter::Implementation &Impl, auto constructor = new (context) ConstructorDecl( name, structDecl->getLoc(), /*Failable=*/false, /*FailabilityLoc=*/SourceLoc(), + /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), paramList, /*GenericParams=*/nullptr, structDecl); @@ -4132,9 +4135,11 @@ namespace { DeclName ctorName(Impl.SwiftContext, DeclBaseName::createConstructor(), bodyParams); result = Impl.createDeclWithClangNode( - clangNode, AccessLevel::Public, ctorName, loc, /*failable=*/false, - /*FailabilityLoc=*/SourceLoc(), /*Throws=*/false, - /*ThrowsLoc=*/SourceLoc(), bodyParams, genericParams, dc); + clangNode, AccessLevel::Public, ctorName, loc, + /*failable=*/false, /*FailabilityLoc=*/SourceLoc(), + /*Async=*/false, /*AsyncLoc=*/SourceLoc(), + /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), + bodyParams, genericParams, dc); } else { auto resultTy = importedType.getType(); @@ -6514,6 +6519,7 @@ Decl *SwiftDeclConverter::importGlobalAsInitializer( auto result = Impl.createDeclWithClangNode( decl, AccessLevel::Public, name, /*NameLoc=*/SourceLoc(), failable, /*FailabilityLoc=*/SourceLoc(), + /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), parameterList, /*GenericParams=*/nullptr, dc); result->setImplicitlyUnwrappedOptional(isIUO); @@ -6998,6 +7004,7 @@ ConstructorDecl *SwiftDeclConverter::importConstructor( auto result = Impl.createDeclWithClangNode( objcMethod, AccessLevel::Public, importedName.getDeclName(), /*NameLoc=*/SourceLoc(), failability, /*FailabilityLoc=*/SourceLoc(), + /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/importedName.getErrorInfo().hasValue(), /*ThrowsLoc=*/SourceLoc(), bodyParams, /*GenericParams=*/nullptr, const_cast(dc)); diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 76898df5a39ce..16fadb01f50c9 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -1286,6 +1286,7 @@ NameImporter::considerAsyncImport( // Initializers cannot be 'async'. // FIXME: We might eventually allow this. + // TODO: should the restriction be lifted in ClangImporter? if (isInitializer) return notAsync("initializers cannot be async"); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 919ca4b83ad39..91ca73371010e 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -8005,19 +8005,12 @@ Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) { Attributes.add(new (Context) RethrowsAttr(throwsLoc)); } - // Initializers cannot be 'async'. - // FIXME: We should be able to lift this restriction. - if (asyncLoc.isValid()) { - diagnose(asyncLoc, diag::async_init) - .fixItRemove(asyncLoc); - asyncLoc = SourceLoc(); - } - diagnoseWhereClauseInGenericParamList(GenericParams); DeclName FullName(Context, DeclBaseName::createConstructor(), namePieces); auto *CD = new (Context) ConstructorDecl(FullName, ConstructorLoc, Failable, FailabilityLoc, + asyncLoc.isValid(), asyncLoc, throwsLoc.isValid(), throwsLoc, Params.get(), GenericParams, CurDeclContext); diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index 9372a637d04e6..439ec8306026c 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -12,6 +12,7 @@ #include "ArgumentSource.h" #include "Conversion.h" +#include "ExecutorBreadcrumb.h" #include "Initialization.h" #include "LValue.h" #include "RValue.h" @@ -350,13 +351,20 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) { SILValue selfLV = VarLocs[selfDecl].value; // Emit the prolog. - emitProlog(ctor->getParameters(), - /*selfParam=*/nullptr, - ctor->getResultInterfaceType(), ctor, - ctor->hasThrows(), - ctor->getThrowsLoc()); + emitBasicProlog(ctor->getParameters(), + /*selfParam=*/nullptr, + ctor->getResultInterfaceType(), ctor, + ctor->hasThrows(), + ctor->getThrowsLoc()); emitConstructorMetatypeArg(*this, ctor); + // Make sure we've hopped to the right global actor, if any. + if (ctor->hasAsync()) { + SILLocation prologueLoc(selfDecl); + prologueLoc.markAsPrologue(); + emitConstructorPrologActorHop(prologueLoc, getActorIsolation(ctor)); + } + // Create a basic block to jump to for the implicit 'self' return. // We won't emit this until after we've emitted the body. // The epilog takes a void return because the return of 'self' is implicit. @@ -662,6 +670,18 @@ static void emitDefaultActorInitialization(SILGenFunction &SGF, { self.borrow(SGF, loc).getValue() }); } +void SILGenFunction::emitConstructorPrologActorHop( + SILLocation loc, + Optional maybeIso) { + if (!maybeIso) + return; + + if (auto executor = emitExecutor(loc, *maybeIso, None)) { + ExpectedExecutor = *executor; + B.createHopToExecutor(loc, *executor); + } +} + void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) { MagicFunctionName = SILGenModule::getMagicFunctionName(ctor); @@ -717,13 +737,20 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) { // Emit the prolog for the non-self arguments. // FIXME: Handle self along with the other body patterns. - uint16_t ArgNo = emitProlog(ctor->getParameters(), /*selfParam=*/nullptr, - TupleType::getEmpty(F.getASTContext()), ctor, - ctor->hasThrows(), ctor->getThrowsLoc()); + uint16_t ArgNo = emitBasicProlog(ctor->getParameters(), /*selfParam=*/nullptr, + TupleType::getEmpty(F.getASTContext()), ctor, + ctor->hasThrows(), ctor->getThrowsLoc()); SILType selfTy = getLoweredLoadableType(selfDecl->getType()); ManagedValue selfArg = B.createInputFunctionArgument(selfTy, selfDecl); + // Make sure we've hopped to the right global actor, if any. + if (ctor->hasAsync() && !selfClassDecl->isActor()) { + SILLocation prologueLoc(selfDecl); + prologueLoc.markAsPrologue(); + emitConstructorPrologActorHop(prologueLoc, getActorIsolation(ctor)); + } + if (!NeedsBoxForSelf) { SILLocation PrologueLoc(selfDecl); PrologueLoc.markAsPrologue(); diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 80b935f875bc6..72e756abd493f 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -997,8 +997,8 @@ void SILGenFunction::emitGeneratorFunction(SILDeclRef function, VarDecl *var) { } } - emitProlog(/*paramList*/ nullptr, /*selfParam*/ nullptr, interfaceType, dc, - /*throws=*/false, SourceLoc()); + emitBasicProlog(/*paramList*/ nullptr, /*selfParam*/ nullptr, + interfaceType, dc, /*throws=*/ false,SourceLoc()); prepareEpilog(true, false, CleanupLocation(loc)); auto pbd = var->getParentPatternBinding(); diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index 85579a5735c2a..60e84a47001ec 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -839,6 +839,17 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction Optional actorIso, Optional actorSelf); + /// A version of `emitHopToTargetActor` that is specialized to the needs + /// of various types of ConstructorDecls, like class or value initializers, + /// because their prolog emission is not the same as for regular functions. + /// + /// This function emits the appropriate hop_to_executor for a constructor's + /// prologue. + /// + /// NOTE: this does not support actor initializers! + void emitConstructorPrologActorHop(SILLocation loc, + Optional actorIso); + /// Emit the executor for the given actor isolation. Optional emitExecutor(SILLocation loc, ActorIsolation isolation, @@ -876,10 +887,11 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction ParameterList *paramList, ParamDecl *selfParam, DeclContext *DC, Type resultType, bool throws, SourceLoc throwsLoc); - /// returns the number of variables in paramPatterns. - uint16_t emitProlog(ParameterList *paramList, ParamDecl *selfParam, - Type resultType, DeclContext *DC, - bool throws, SourceLoc throwsLoc); + /// A simpler version of emitProlog + /// \returns the number of variables in paramPatterns. + uint16_t emitBasicProlog(ParameterList *paramList, ParamDecl *selfParam, + Type resultType, DeclContext *DC, + bool throws, SourceLoc throwsLoc); /// Create SILArguments in the entry block that bind a single value /// of the given parameter suitably for being forwarded. diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index effe56f86f76c..3a7f6993cb5a2 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -411,8 +411,8 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo, Type resultType, bool throws, SourceLoc throwsLoc) { - uint16_t ArgNo = emitProlog(paramList, selfParam, resultType, - DC, throws, throwsLoc); + uint16_t ArgNo = emitBasicProlog(paramList, selfParam, resultType, + DC, throws, throwsLoc); // Emit the capture argument variables. These are placed last because they // become the first curry level of the SIL function. @@ -733,12 +733,12 @@ static void emitIndirectResultParameters(SILGenFunction &SGF, Type resultType, (void)arg; } -uint16_t SILGenFunction::emitProlog(ParameterList *paramList, - ParamDecl *selfParam, - Type resultType, - DeclContext *DC, - bool throws, - SourceLoc throwsLoc) { +uint16_t SILGenFunction::emitBasicProlog(ParameterList *paramList, + ParamDecl *selfParam, + Type resultType, + DeclContext *DC, + bool throws, + SourceLoc throwsLoc) { // Create the indirect result parameters. auto genericSig = DC->getGenericSignatureOfContext(); resultType = resultType->getCanonicalType(genericSig); diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 7ef126cb63f28..4f7277640fb4e 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -141,9 +141,11 @@ static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate( if (isa(oldDecl)) { DeclName ctorName(ctx, DeclBaseName::createConstructor(), newParamList); auto newCtorDecl = ConstructorDecl::createImported( - ctx, specialized, ctorName, oldDecl->getLoc(), /*failable=*/false, - /*failabilityLoc=*/SourceLoc(), /*throws=*/false, - /*throwsLoc=*/SourceLoc(), newParamList, /*genericParams=*/nullptr, + ctx, specialized, ctorName, oldDecl->getLoc(), + /*failable=*/false, /*failabilityLoc=*/SourceLoc(), + /*Async=*/false, /*AsyncLoc=*/SourceLoc(), + /*throws=*/false, /*throwsLoc=*/SourceLoc(), + newParamList, /*genericParams=*/nullptr, oldDecl->getDeclContext()); return ConcreteDeclRef(newCtorDecl); } diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 7b339f1c0293d..7c383c8695bcd 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -319,6 +319,7 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl, auto *ctor = new (ctx) ConstructorDecl(name, Loc, /*Failable=*/false, /*FailabilityLoc=*/SourceLoc(), + /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), paramList, /*GenericParams=*/nullptr, decl); @@ -744,6 +745,7 @@ createDesignatedInitOverride(ClassDecl *classDecl, classDecl->getBraces().Start, superclassCtor->isFailable(), /*FailabilityLoc=*/SourceLoc(), + /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/superclassCtor->hasThrows(), /*ThrowsLoc=*/SourceLoc(), bodyParams, genericParams, classDecl); diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp index 66085353f65e1..256e407b63219 100644 --- a/lib/Sema/DerivedConformanceCodable.cpp +++ b/lib/Sema/DerivedConformanceCodable.cpp @@ -1847,6 +1847,7 @@ static ValueDecl *deriveDecodable_init(DerivedConformance &derived) { auto *initDecl = new (C) ConstructorDecl(name, SourceLoc(), /*Failable=*/false,SourceLoc(), + /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/true, SourceLoc(), paramList, /*GenericParams=*/nullptr, conformanceDC); initDecl->setImplicit(); diff --git a/lib/Sema/DerivedConformanceCodingKey.cpp b/lib/Sema/DerivedConformanceCodingKey.cpp index 8cbef3a1cc2c4..13e46846d42ac 100644 --- a/lib/Sema/DerivedConformanceCodingKey.cpp +++ b/lib/Sema/DerivedConformanceCodingKey.cpp @@ -130,6 +130,7 @@ static ValueDecl *deriveInitDecl(DerivedConformance &derived, Type paramType, auto *initDecl = new (C) ConstructorDecl(name, SourceLoc(), /*Failable=*/true, /*FailabilityLoc=*/SourceLoc(), + /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), paramList, /*GenericParams=*/nullptr, parentDC); diff --git a/lib/Sema/DerivedConformanceRawRepresentable.cpp b/lib/Sema/DerivedConformanceRawRepresentable.cpp index 39f21a42819a6..d5e8ee32e5010 100644 --- a/lib/Sema/DerivedConformanceRawRepresentable.cpp +++ b/lib/Sema/DerivedConformanceRawRepresentable.cpp @@ -425,6 +425,7 @@ deriveRawRepresentable_init(DerivedConformance &derived) { auto initDecl = new (C) ConstructorDecl(name, SourceLoc(), /*Failable=*/ true, /*FailabilityLoc=*/SourceLoc(), + /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), paramList, /*GenericParams=*/nullptr, parentDC); diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index bfcb221d352ab..8bd9765a8b99a 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -682,7 +682,7 @@ bool swift::isRepresentableInObjC( // information into a completion handler. auto FD = dyn_cast(AFD); if (!FD) { - AFD->diagnose(diag::not_objc_function_async) + AFD->diagnose(diag::not_objc_function_async, AFD->getDescriptiveKind()) .highlight(AFD->getAsyncLoc()) .limitBehavior(behavior); describeObjCReason(AFD, Reason); diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index eab2a0295e05f..c0e947efce421 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1829,7 +1829,7 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) { return true; } else if (!overrideASD->isLessEffectfulThan(baseASD, EffectKind::Throws)) { diags.diagnose(overrideASD, diag::override_with_more_effects, - overrideASD->getDescriptiveKind(), "throws"); + overrideASD->getDescriptiveKind(), "throwing"); return true; } } @@ -1913,12 +1913,19 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) { } } // If the overriding declaration is 'throws' but the base is not, - // complain. + // complain. Do the same for 'async' if (auto overrideFn = dyn_cast(override)) { if (overrideFn->hasThrows() && !cast(base)->hasThrows()) { - diags.diagnose(override, diag::override_throws, - isa(override)); + diags.diagnose(override, diag::override_with_more_effects, + override->getDescriptiveKind(), "throwing"); + diags.diagnose(base, diag::overridden_here); + } + + if (overrideFn->hasAsync() && + !cast(base)->hasAsync()) { + diags.diagnose(override, diag::override_with_more_effects, + override->getDescriptiveKind(), "async"); diags.diagnose(base, diag::overridden_here); } diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index c573f558b75e6..aa0807af8d3c9 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -1597,6 +1597,9 @@ static Type getResultBuilderType(FuncDecl *FD) { return builderType; } +/// Attempts to build an implicit call within the provided constructor +/// to the provided class's zero-argument super initializer. +/// @returns nullptr if there was an error and a diagnostic was emitted. static Expr* constructCallToSuperInit(ConstructorDecl *ctor, ClassDecl *ClDecl) { ASTContext &Context = ctor->getASTContext(); @@ -1643,7 +1646,7 @@ static bool checkSuperInit(ConstructorDecl *fromCtor, } return true; } - + // For an implicitly generated super.init() call, make sure there's // only one designated initializer. if (implicitlyGenerated) { @@ -1681,6 +1684,13 @@ static bool checkSuperInit(ConstructorDecl *fromCtor, ctor->getDescriptiveKind(), ctor->getName(), superclassDecl->getName()); } + + // Not allowed to implicitly generate a super.init() call if the init + // is async; that would hide the 'await' from the programmer. + if (ctor->hasAsync()) { + fromCtor->diagnose(diag::implicit_async_super_init); + return true; // considered an error + } } diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index fa704a1311b4b..f9f2a6ce2e3cf 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -2742,7 +2742,7 @@ class DeclDeserializer { StringRef blobData) { DeclContextID contextID; bool isIUO, isFailable; - bool isImplicit, isObjC, hasStubImplementation, throws; + bool isImplicit, isObjC, hasStubImplementation, throws, async; GenericSignatureID genericSigID; uint8_t storedInitKind, rawAccessLevel; DeclID overriddenID; @@ -2753,7 +2753,7 @@ class DeclDeserializer { decls_block::ConstructorLayout::readRecord(scratch, contextID, isFailable, isIUO, isImplicit, isObjC, hasStubImplementation, - throws, storedInitKind, + async, throws, storedInitKind, genericSigID, overriddenID, rawAccessLevel, @@ -2808,6 +2808,8 @@ class DeclDeserializer { auto ctor = MF.createDecl(name, SourceLoc(), isFailable, /*FailabilityLoc=*/SourceLoc(), + /*Async=*/async, + /*AsyncLoc=*/SourceLoc(), /*Throws=*/throws, /*ThrowsLoc=*/SourceLoc(), /*BodyParams=*/nullptr, diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 8ce54a63b4549..43bbb4ce9645e 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 609; // extract_executor SIL inst +const uint16_t SWIFTMODULE_VERSION_MINOR = 610; // async initializers for nominal types /// A standard hash seed used for all string hashes in a serialized module. /// @@ -1264,6 +1264,7 @@ namespace decls_block { BCFixed<1>, // implicit? BCFixed<1>, // objc? BCFixed<1>, // stub implementation? + BCFixed<1>, // async? BCFixed<1>, // throws? CtorInitializerKindField, // initializer kind GenericSignatureIDField, // generic environment diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 827c1e6c9b36f..aef02c4ce5675 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3884,6 +3884,7 @@ class Serializer::DeclSerializer : public DeclVisitor { ctor->isImplicit(), ctor->isObjC(), ctor->hasStubImplementation(), + ctor->hasAsync(), ctor->hasThrows(), getStableCtorInitializerKind( ctor->getInitKind()), diff --git a/test/Concurrency/Runtime/async_initializer.swift b/test/Concurrency/Runtime/async_initializer.swift new file mode 100644 index 0000000000000..91084b9c33bba --- /dev/null +++ b/test/Concurrency/Runtime/async_initializer.swift @@ -0,0 +1,175 @@ +// RUN: %target-run-simple-swift(-parse-as-library -Xfrontend -enable-experimental-concurrency %import-libdispatch) | %FileCheck %s + +// REQUIRES: executable_test +// REQUIRES: concurrency +// REQUIRES: libdispatch + +// rdar://76038845 +// UNSUPPORTED: use_os_stdlib + +@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) +actor NameGenerator { + private var counter = 0 + private var prefix : String + init(_ title: String) { self.prefix = title } + func getName() -> String { + counter += 1 + return "\(prefix) \(counter)" + } +} + +@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) +protocol Person { + init() async + var name : String { get set } +} + +@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) +class EarthPerson : Person { + private static let oracle = NameGenerator("Earthling") + + var name : String + + required init() async { + self.name = await EarthPerson.oracle.getName() + } + + init(name: String) async { + self.name = await (detach { name }).get() + } +} + +@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) +class NorthAmericaPerson : EarthPerson { + private static let oracle = NameGenerator("NorthAmerican") + required init() async { + await super.init() + self.name = await NorthAmericaPerson.oracle.getName() + } + + override init(name: String) async { + await super.init(name: name) + } +} + +@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) +class PrecariousClass { + init?(nilIt : Int) async { + let _ : Optional = await (detach { nil }).get() + return nil + } + + init(throwIt : Double) async throws { + if await (detach { 0 }).get() != 1 { + throw Something.bogus + } + } + + init?(nilOrThrowIt shouldThrow: Bool) async throws { + let flag = await (detach { shouldThrow }).get() + if flag { + throw Something.bogus + } + return nil + } + + init!(crashOrThrowIt shouldThrow: Bool) async throws { + let flag = await (detach { shouldThrow }).get() + if flag { + throw Something.bogus + } + return nil + } +} + +enum Something : Error { + case bogus +} + +@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) +struct PrecariousStruct { + init?(nilIt : Int) async { + let _ : Optional = await (detach { nil }).get() + return nil + } + + init(throwIt : Double) async throws { + if await (detach { 0 }).get() != 1 { + throw Something.bogus + } + } +} + + + +// CHECK: Earthling 1 +// CHECK-NEXT: Alice +// CHECK-NEXT: Earthling 2 +// CHECK-NEXT: Bob +// CHECK-NEXT: Earthling 3 +// CHECK-NEXT: Alex +// CHECK-NEXT: NorthAmerican 1 +// CHECK-NEXT: NorthAmerican 2 +// CHECK-NEXT: Earthling 6 + +// CHECK-NEXT: class was nil +// CHECK-NEXT: class threw +// CHECK-NEXT: nilOrThrowIt init was nil +// CHECK-NEXT: nilOrThrowIt init threw +// CHECK-NEXT: crashOrThrowIt init threw +// CHECK-NEXT: struct was nil +// CHECK-NEXT: struct threw +// CHECK: done + +@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) +@main struct RunIt { + static func main() async { + let people : [Person] = [ + await EarthPerson(), + await NorthAmericaPerson(name: "Alice"), + await EarthPerson(), + await NorthAmericaPerson(name: "Bob"), + await EarthPerson(), + await NorthAmericaPerson(name: "Alex"), + await NorthAmericaPerson(), + await NorthAmericaPerson(), + await EarthPerson() + ] + + for p in people { + print(p.name) + } + + // ---- + + if await PrecariousClass(nilIt: 0) == nil { + print("class was nil") + } + + do { let _ = try await PrecariousClass(throwIt: 0.0) } catch { + print("class threw") + } + + if try! await PrecariousClass(nilOrThrowIt: false) == nil { + print("nilOrThrowIt init was nil") + } + + do { let _ = try await PrecariousClass(nilOrThrowIt: true) } catch { + print("nilOrThrowIt init threw") + } + + do { let _ = try await PrecariousClass(crashOrThrowIt: true) } catch { + print("crashOrThrowIt init threw") + } + + if await PrecariousStruct(nilIt: 0) == nil { + print("struct was nil") + } + + do { let _ = try await PrecariousStruct(throwIt: 0.0) } catch { + print("struct threw") + } + + print("done") + } +} diff --git a/test/Concurrency/async_initializer.swift b/test/Concurrency/async_initializer.swift new file mode 100644 index 0000000000000..1e65a34e1771c --- /dev/null +++ b/test/Concurrency/async_initializer.swift @@ -0,0 +1,165 @@ +// RUN: %target-typecheck-verify-swift -enable-experimental-concurrency +// REQUIRES: concurrency + + +//// +// some functions to play with + +func f() async { + let _ = Person() // expected-error {{call is 'async' but is not marked with 'await'}} {{11-11=await }} +} + +func g() {} + +//// +// test super.init interactions + +class Person { + init() async { + f() // expected-error {{call is 'async' but is not marked with 'await'}} {{5-5=await }} + } + + convenience init(_ s: String) async { + await self.init() + } +} + +class Bertrand: Person { + override init() {} // expected-error {{missing call to superclass's initializer; 'super.init' is 'async' and requires an explicit call}} + init(_ x: Int) async {} // expected-error {{missing call to superclass's initializer; 'super.init' is 'async' and requires an explicit call}} +} + +class Barbara: Person { + // expected-note@+2 {{add 'async' to function 'init(_:)' to make it asynchronous}} {{20-20= async}} + // expected-error@+1 {{missing call to superclass's initializer; 'super.init' is 'async' and requires an explicit call}} + init(_ d: Double) { + f() // expected-error{{'async' call in a function that does not support concurrency}} + } + + init(x: Int, y: Int) async { + await super.init() + } + + convenience init(a: Double, b: Double) async { + await self.init(x: 0, y: 0) + } +} + +class Fruit { + init() async {} + init(name: String) {} +} + +class Banana: Fruit { + override init() { + super.init(name: "banana") + } +} + +class Cat {} // expected-note {{overridden declaration is here}} + +class Calico: Cat { + override init() async {} // expected-error {{cannot override non-async initializer with async initializer}} +} + +func reconstruct(c: Cat) { + c.init() // expected-error {{'init' is a member of the type}} +} + +//// +// test reasync initializers + +class MyType { + init(_ f: () async -> Void) reasync { + await f() + } +} + +func beep() async { + let _ = MyType(f) // expected-error{{call is 'async' but is not marked with 'await'}} + let _ = await MyType(f) + + let _ = MyType(g) +} + +//// +// test other types with constructors + +actor A { + init() async { + await f() + } +} + +// NOTE: actor inheritance is probably being removed soon, so just remove this def of B +actor B: A { + init(x : String) async {} // expected-error {{missing call to superclass's initializer; 'super.init' is 'async' and requires an explicit call}} +} + +enum E { + init() async { + await f() + } +} + +struct SomeStruct { + @MainActor init(asyncMainActor: Int) async {} + @MainActor init(mainActor: Int) {} // expected-note {{calls to initializer 'init(mainActor:)' from outside of its actor context are implicitly asynchronous}} + @MainActor(unsafe) init(asyncMainActorUnsafe: Int) async {} + @MainActor(unsafe) init(mainActorUnsafe: Int) {} +} + +// expected-note@+2 {{add '@MainActor' to make global function 'globActorTest1()' part of global actor 'MainActor'}} +// expected-note@+1 2 {{add 'async' to function 'globActorTest1()' to make it asynchronous}} +func globActorTest1() { + _ = SomeStruct(asyncMainActor: 0) // expected-error {{'async' call in a function that does not support concurrency}} + + _ = SomeStruct(mainActor: 0) // expected-error {{initializer 'init(mainActor:)' isolated to global actor 'MainActor' can not be referenced from this synchronous context}} + + _ = SomeStruct(asyncMainActorUnsafe: 0) // expected-error {{'async' call in a function that does not support concurrency}} + + _ = SomeStruct(mainActorUnsafe: 0) +} + +func globActorTestAsyncEdition() async { + _ = await SomeStruct(asyncMainActor: 0) + _ = await SomeStruct(mainActor: 0) + _ = await SomeStruct(asyncMainActorUnsafe: 0) + _ = await SomeStruct(mainActorUnsafe: 0) +} + +//// +// check protocol conformance & inheritance + +protocol AsyncDefaultConstructable { + init() async +} + +protocol DefaultConstructable { + init() // expected-note {{protocol requires initializer 'init()' with type '()'; do you want to add a stub?}} {{43-43=\n init() {\n <#code#>\n \}\n}} +} + +struct Location { + var x : Int + var y : Int + init() async { // expected-note {{candidate is 'async', but protocol requirement is not}} + self.x = 0 + self.y = 0 + } +} + +extension Location: DefaultConstructable {} // expected-error {{type 'Location' does not conform to protocol 'DefaultConstructable'}} + +extension Location: AsyncDefaultConstructable {} + +protocol Plain { + // expected-note@+2 {{overridden declaration is here}} + // expected-note@+1 {{attempt to override convenience initializer here}} + init() +} + +protocol Spicy: Plain { + // expected-error@+2 {{cannot override non-async initializer with async initializer}} + // expected-error@+1 {{initializer does not override a designated initializer from its parent protocol}} + override init() async +} \ No newline at end of file diff --git a/test/Concurrency/async_initializer_objc.swift b/test/Concurrency/async_initializer_objc.swift new file mode 100644 index 0000000000000..174dda7164ba9 --- /dev/null +++ b/test/Concurrency/async_initializer_objc.swift @@ -0,0 +1,11 @@ +// RUN: %target-typecheck-verify-swift -enable-experimental-concurrency +// REQUIRES: concurrency +// REQUIRES: objc_interop + +import Foundation + +class X: NSObject { + // expected-error@+1 {{'async' initializer cannot be represented in Objective-C}} + @objc init(_ i : Int) async { } +} + diff --git a/test/IDE/complete_asyncannotation.swift b/test/IDE/complete_asyncannotation.swift index dac6f593262e7..12f943ab010a0 100644 --- a/test/IDE/complete_asyncannotation.swift +++ b/test/IDE/complete_asyncannotation.swift @@ -65,9 +65,9 @@ func testMemberAsyncRethrows(_ x: HasAsyncMembers) async { func testAsyncIntiializers() async { HasAsyncMembers(#^CHECK_initializers^# // CHECK_initializers: Begin completions -// CHECK_initializers-DAG: Decl[Constructor]/CurrNominal: ['('][')'][#HasAsyncMembers#]; name= -// CHECK_initializers-DAG: Decl[Constructor]/CurrNominal: ['(']{#withAsync: Int#}[')'][#HasAsyncMembers#]; name=withAsync: Int -// CHECK_initializers-DAG: Decl[Constructor]/CurrNominal: ['(']{#withAsyncThrows: Int#}[')'][' throws'][#HasAsyncMembers#]; name=withAsyncThrows: Int throws -// CHECK_initializers-DAG: Decl[Constructor]/CurrNominal: ['(']{#withAsyncRethrows: () async throws -> Void##() async throws -> Void#}[')'][' rethrows'][#HasAsyncMembers#]; name=withAsyncRethrows: () async throws -> Void rethrows +// CHECK_initializers-DAG: Decl[Constructor]/CurrNominal: ['('][')'][' async'][#HasAsyncMembers#]; name= async +// CHECK_initializers-DAG: Decl[Constructor]/CurrNominal: ['(']{#withAsync: Int#}[')'][' async'][#HasAsyncMembers#]; name=withAsync: Int async +// CHECK_initializers-DAG: Decl[Constructor]/CurrNominal: ['(']{#withAsyncThrows: Int#}[')'][' async'][' throws'][#HasAsyncMembers#]; name=withAsyncThrows: Int async throws +// CHECK_initializers-DAG: Decl[Constructor]/CurrNominal: ['(']{#withAsyncRethrows: () async throws -> Void##() async throws -> Void#}[')'][' async'][' rethrows'][#HasAsyncMembers#]; name=withAsyncRethrows: () async throws -> Void async rethrows // CHECK_initializers: End completions } diff --git a/test/Parse/async.swift b/test/Parse/async.swift index 977644aa55e8a..8912000825852 100644 --- a/test/Parse/async.swift +++ b/test/Parse/async.swift @@ -28,7 +28,7 @@ func asyncGlobal8() async throws async -> async Int async {} // expected-error@-3{{'async' has already been specified}} {{53-59=}} class X { - init() async { } // expected-error{{initializer cannot be marked 'async'}} + init() async { } deinit async { } // expected-error{{deinitializers cannot have a name}} diff --git a/test/SILGen/async_initializer.swift b/test/SILGen/async_initializer.swift new file mode 100644 index 0000000000000..dcd4076c846d1 --- /dev/null +++ b/test/SILGen/async_initializer.swift @@ -0,0 +1,156 @@ +// RUN: %target-swift-frontend -emit-silgen %s -module-name initializers -swift-version 5 -enable-experimental-concurrency | %FileCheck --enable-var-scope %s +// REQUIRES: concurrency + +// CHECK: protocol Person { +// CHECK-NEXT: init() async +// CHECK-NEXT: } + +// CHECK: struct MyStruct { +// CHECK-NEXT: init() async +// CHECK-NEXT: } + +// CHECK: enum MyEnum { +// CHECK-NEXT: init() async +// CHECK-NEXT: } + +// CHECK: actor MyActor { +// CHECK-NEXT: init() async + + +// CHECK: class EarthPerson : Person { +// CHECK-NEXT: required init() async +// CHECK-NEXT: init(name: String) async + +// CHECK: @_inheritsConvenienceInitializers class NorthAmericaPerson : EarthPerson { +// CHECK-NEXT: required init() async +// CHECK-NEXT: override init(name: String) async + +// CHECK: class Cat { +// CHECK-NEXT: @MainActor init() +// CHECK-NEXT: @MainActor init(name: String) + +// CHECK: struct Dog { +// CHECK-NEXT: @MainActor init() async +// CHECK-NEXT: @MainActor init(name: String) +// CHECK-NEXT: } + +// CHECK: enum Birb { +// CHECK-NEXT: @MainActor init() async +// CHECK-NEXT: @MainActor init(name: String) +// CHECK-NEXT: } + + + +protocol Person { + init() async +} + +struct MyStruct { + // CHECK-DAG: sil hidden [ossa] @$s12initializers8MyStructVACyYacfC : $@convention(method) @async (@thin MyStruct.Type) -> MyStruct + init() async {} +} + +enum MyEnum { + // CHECK-DAG: sil hidden [ossa] @$s12initializers6MyEnumOACyYacfC : $@convention(method) @async (@thin MyEnum.Type) -> MyEnum + init() async {} +} + +actor MyActor { + // CHECK-DAG: sil hidden [ossa] @$s12initializers7MyActorCACyYacfc : $@convention(method) @async (@owned MyActor) -> @owned MyActor + // CHECK-NOT: hop_to_executor + // CHECK-DAG: } // end sil function '$s12initializers7MyActorCACyYacfc' + init() async {} +} + +class EarthPerson : Person { + // CHECK-DAG: sil hidden [ossa] @$s12initializers11EarthPersonCACyYacfc : $@convention(method) @async (@owned EarthPerson) -> @owned EarthPerson + required init() async {} + + // CHECK-DAG: sil hidden [ossa] @$s12initializers11EarthPersonC4nameACSS_tYacfc : $@convention(method) @async (@owned String, @owned EarthPerson) -> @owned EarthPerson + init(name: String) async {} + + // CHECK-DAG: sil private [transparent] [thunk] [ossa] @$s12initializers11EarthPersonCAA0C0A2aDPxyYacfCTW : $@convention(witness_method: Person) @async (@thick EarthPerson.Type) -> @out EarthPerson +} + +class NorthAmericaPerson : EarthPerson { + // CHECK-DAG: sil hidden [ossa] @$s12initializers18NorthAmericaPersonCACyYacfc : $@convention(method) @async (@owned NorthAmericaPerson) -> @owned NorthAmericaPerson + required init() async { await super.init() } + + // CHECK-DAG: sil hidden [ossa] @$s12initializers18NorthAmericaPersonC4nameACSS_tYacfc : $@convention(method) @async (@owned String, @owned NorthAmericaPerson) -> @owned NorthAmericaPerson + override init(name: String) async { await super.init(name: name) } +} + +//// +// check that of global-actor isolation is preserved in async initializers. +// there's also coverage for sync global-actor-isolated initializers + +func someAsyncFn() async {} + +class Cat { + // CHECK-LABEL: sil hidden [ossa] @$s12initializers3CatCACyYacfc : $@convention(method) @async (@owned Cat) -> @owned Cat { + // CHECK: hop_to_executor {{%[0-9]+}} : $MainActor + // CHECK: {{%[0-9]+}} = function_ref @$s12initializers11someAsyncFnyyYaF : $@convention(thin) @async () -> () + // CHECK: {{%[0-9]+}} = apply {{%[0-9]+}}() : $@convention(thin) @async () -> () + // CHECK-NEXT: hop_to_executor {{%[0-9]+}} : $MainActor + // CHECK: } // end sil function '$s12initializers3CatCACyYacfc' + @MainActor init() async { + await someAsyncFn() + } + + @MainActor init(name: String) {} +} + +struct Dog { + // CHECK-LABEL: sil hidden [ossa] @$s12initializers3DogVACyYacfC : $@convention(method) @async (@thin Dog.Type) -> Dog { + // CHECK: hop_to_executor {{%[0-9]+}} : $MainActor + // CHECK: {{%[0-9]+}} = function_ref @$s12initializers11someAsyncFnyyYaF : $@convention(thin) @async () -> () + // CHECK: {{%[0-9]+}} = apply {{%[0-9]+}}() : $@convention(thin) @async () -> () + // CHECK-NEXT: hop_to_executor {{%[0-9]+}} : $MainActor + // CHECK: } // end sil function '$s12initializers3DogVACyYacfC' + @MainActor init() async { + await someAsyncFn() + } + + @MainActor init(name: String) {} +} + +enum Birb { + // CHECK-LABEL: sil hidden [ossa] @$s12initializers4BirbOACyYacfC : $@convention(method) @async (@thin Birb.Type) -> Birb { + // CHECK: hop_to_executor {{%[0-9]+}} : $MainActor + // CHECK: {{%[0-9]+}} = function_ref @$s12initializers11someAsyncFnyyYaF : $@convention(thin) @async () -> () + // CHECK: {{%[0-9]+}} = apply {{%[0-9]+}}() : $@convention(thin) @async () -> () + // CHECK-NEXT: hop_to_executor {{%[0-9]+}} : $MainActor + // CHECK: } // end sil function '$s12initializers4BirbOACyYacfC' + @MainActor init() async { + await someAsyncFn() + } + + @MainActor init(name: String) {} +} + +// CHECK-LABEL: sil hidden [ossa] @$s12initializers7makeCatyyYaF : $@convention(thin) @async () -> () { +// CHECK: hop_to_executor {{%[0-9]+}} : $MainActor +// CHECK-NEXT: {{%[0-9]+}} = apply {{%[0-9]+}}({{%[0-9]+}}, {{%[0-9]+}}) : $@convention(method) (@owned String, @thick Cat.Type) -> @owned Cat +// CHECK-NEXT: hop_to_executor {{%[0-9]+}} : $Builtin.Executor +// CHECK: } // end sil function '$s12initializers7makeCatyyYaF' +func makeCat() async { + _ = await Cat(name: "Socks") +} + +// CHECK-LABEL: sil hidden [ossa] @$s12initializers7makeDogyyYaF : $@convention(thin) @async () -> () { +// CHECK: hop_to_executor {{%[0-9]+}} : $MainActor +// CHECK-NEXT: {{%[0-9]+}} = apply {{%[0-9]+}}({{%[0-9]+}}, {{%[0-9]+}}) : $@convention(method) (@owned String, @thin Dog.Type) -> Dog +// CHECK-NEXT: hop_to_executor {{%[0-9]+}} : $Builtin.Executor +// CHECK: } // end sil function '$s12initializers7makeDogyyYaF' +func makeDog() async { + _ = await Dog(name: "Lassie") +} + +// CHECK-LABEL: sil hidden [ossa] @$s12initializers8makeBirbyyYaF : $@convention(thin) @async () -> () { +// CHECK: hop_to_executor {{%[0-9]+}} : $MainActor +// CHECK-NEXT: {{%[0-9]+}} = apply {{%[0-9]+}}({{%[0-9]+}}, {{%[0-9]+}}) : $@convention(method) (@owned String, @thin Birb.Type) -> Birb +// CHECK-NEXT: hop_to_executor {{%[0-9]+}} : $Builtin.Executor +// CHECK: } // end sil function '$s12initializers8makeBirbyyYaF' +func makeBirb() async { + _ = await Birb(name: "Chirpy") +} \ No newline at end of file diff --git a/test/Serialization/async_initializers.swift b/test/Serialization/async_initializers.swift new file mode 100644 index 0000000000000..b3ca0457c69c0 --- /dev/null +++ b/test/Serialization/async_initializers.swift @@ -0,0 +1,44 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -enable-experimental-concurrency -emit-module-path %t/a.swiftmodule -module-name a %s +// RUN: %target-swift-ide-test -print-module -module-to-print a -source-filename x -I %t | %FileCheck -check-prefix MODULE-CHECK %s +// RUN: %target-swift-frontend -enable-experimental-concurrency -emit-module-path %t/b.swiftmodule -module-name a %t/a.swiftmodule +// RUN: cmp -s %t/a.swiftmodule %t/b.swiftmodule + +// REQUIRES: concurrency + +/////////// +// This test checks for correct serialization & deserialization of +// async initializers + +// look for correct members in module's deserialization pretty-print: + +// MODULE-CHECK: actor A { +// MODULE-CHECK-NEXT: init() async + +actor A { + init() async {} +} + +// MODULE-CHECK: class C { +// MODULE-CHECK-NEXT: init() async +class C { + init() async {} +} + +// MODULE-CHECK: struct S { +// MODULE-CHECK-NEXT: init() async +struct S { + init() async {} +} + +// ignore-----MODULE-CHECK: enum E { +// ignore-----MODULE-CHECK-NEXT: case nothing +// ignore-----MODULE-CHECK-NEXT: init() async + +// FIXME: until rdar://76678907 is fixed, this won't work. +// enum E { +// case nothing +// init() async { +// self = .nothing +// } +// } diff --git a/test/decl/class/effectful_properties.swift b/test/decl/class/effectful_properties.swift index 72b75768d34a2..9c893138398c5 100644 --- a/test/decl/class/effectful_properties.swift +++ b/test/decl/class/effectful_properties.swift @@ -36,7 +36,7 @@ class Presidio : GolfCourse { set { yardsFromBackTees = newValue } } - override var holes : Int { // expected-error {{cannot override non-'async' property with 'async' property}} + override var holes : Int { // expected-error {{cannot override non-async property with async property}} get async { 18 } } @@ -50,11 +50,11 @@ class Presidio : GolfCourse { } class PresidioBackNine : Presidio { - override var par : Int { // expected-error{{cannot override non-'throws' property with 'throws' property}} + override var par : Int { // expected-error{{cannot override non-throwing property with throwing property}} get throws { 36 } // attempts to put the 'throws' effect back } - override subscript(_ i : Int) -> Int { // expected-error{{cannot override non-'async' subscript with 'async' subscript}} + override subscript(_ i : Int) -> Int { // expected-error{{cannot override non-async subscript with async subscript}} get async throws { 0 } } } diff --git a/test/decl/func/rethrows.swift b/test/decl/func/rethrows.swift index d1b5ea30b927d..5dc3fb05bc38a 100644 --- a/test/decl/func/rethrows.swift +++ b/test/decl/func/rethrows.swift @@ -71,10 +71,10 @@ class C1 : Super { class C2 : Super { override func tf() throws {} - override func nf() throws {} // expected-error {{cannot override non-throwing method with throwing method}} + override func nf() throws {} // expected-error {{cannot override non-throwing instance method with throwing instance method}} override func thf(_ f: () throws -> ()) throws {} - override func nhf(_ f: () throws -> ()) throws {} // expected-error {{cannot override non-throwing method with throwing method}} + override func nhf(_ f: () throws -> ()) throws {} // expected-error {{cannot override non-throwing instance method with throwing instance method}} override func rhf(_ f: () throws -> ()) throws {} // expected-error {{override of 'rethrows' method should also be 'rethrows'}} } @@ -83,7 +83,7 @@ class C3 : Super { override func nf() {} override func thf(_ f: () throws -> ()) rethrows {} - override func nhf(_ f: () throws -> ()) rethrows {} // expected-error {{cannot override non-throwing method with throwing method}} + override func nhf(_ f: () throws -> ()) rethrows {} // expected-error {{cannot override non-throwing instance method with throwing instance method}} override func rhf(_ f: () throws -> ()) rethrows {} } diff --git a/test/decl/protocol/effectful_properties.swift b/test/decl/protocol/effectful_properties.swift index ae6ce7fb363da..f83500f2e5807 100644 --- a/test/decl/protocol/effectful_properties.swift +++ b/test/decl/protocol/effectful_properties.swift @@ -314,12 +314,12 @@ protocol HammeredDulcimer { } protocol Santur : HammeredDulcimer { - override subscript(_ note : Int) -> Int { get throws } // expected-error{{cannot override non-'throws' subscript with 'throws' subscript}} + override subscript(_ note : Int) -> Int { get throws } // expected-error{{cannot override non-throwing subscript with throwing subscript}} override var bridges : Int { get throws } } protocol Santoor : Santur { - override var bridges : Int { get async throws } // expected-error{{cannot override non-'async' property with 'async' property}} + override var bridges : Int { get async throws } // expected-error{{cannot override non-async property with async property}} } protocol Yangqin : HammeredDulcimer { @@ -328,5 +328,5 @@ protocol Yangqin : HammeredDulcimer { protocol Hackbrett : HammeredDulcimer { override var bridges : Int { get } // no effects are OK - override subscript(_ note : Int) -> Int { get async throws } // expected-error {{cannot override non-'async' subscript with 'async' subscript}} + override subscript(_ note : Int) -> Int { get async throws } // expected-error {{cannot override non-async subscript with async subscript}} } \ No newline at end of file