diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index c036bf84b7e..b0893fc179d 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -3926,9 +3926,13 @@ public: NominalTypeDecl *getTypeWrapperStorageDecl() const; /// If this declaration is a type wrapper, retrieve - /// its required initializer - `init(storage:)`. + /// its required initializer - `init(storageWrapper:)`. ConstructorDecl *getTypeWrapperInitializer() const; + /// Get an initializer that accepts a type wrapper instance to + /// initialize the wrapped type. + ConstructorDecl *getTypeWrappedTypeStorageInitializer() const; + /// Get a memberwise initializer that could be used to instantiate a /// type wrapped type. ConstructorDecl *getTypeWrappedTypeMemberwiseInitializer() const; diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index 74f68dc6bef..9981d8ecfda 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -315,6 +315,7 @@ IDENTIFIER_WITH_NAME(TypeWrapperProperty, "$storage") IDENTIFIER(storageKeyPath) IDENTIFIER(propertyKeyPath) IDENTIFIER(wrappedSelf) +IDENTIFIER(storageWrapper) IDENTIFIER_WITH_NAME(localStorageVar, "_storage") // Attribute options diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index bf5a0b9fc9f..31e7ccd660e 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -3689,6 +3689,22 @@ public: bool isCached() const { return true; } }; +class SynthesizeTypeWrappedTypeStorageWrapperInitializer + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + ConstructorDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *) const; + +public: + bool isCached() const { return true; } +}; + class SynthesizeLocalVariableForTypeWrapperStorage : public SimpleRequest { diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 3e12f2caa33..83144e441b4 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -431,6 +431,9 @@ SWIFT_REQUEST(TypeChecker, IsPropertyAccessedViaTypeWrapper, SWIFT_REQUEST(TypeChecker, SynthesizeTypeWrappedTypeMemberwiseInitializer, ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, SynthesizeTypeWrappedTypeStorageWrapperInitializer, + ConstructorDecl *(NominalTypeDecl *), + Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, SynthesizeLocalVariableForTypeWrapperStorage, VarDecl *(ConstructorDecl *), Cached, NoLocationInfo) diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index a6a99b54227..28d8e0fc36c 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -232,6 +232,9 @@ enum class ImplicitConstructorKind { /// the instance variables from a parameter of the same type and /// name. Memberwise, + /// The constructor of a type wrapped type that accepts an instance of + /// type wrapper i.e. `init(storageWrapper: Wrapper)`. + TypeWrapperStorage, /// The memberwise constructor of a type wrapped type which is going to /// initialize underlying storage for all applicable properties. TypeWrapperMemberwise, @@ -358,6 +361,37 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl, params.push_back(arg); } + } else if (ICK == ImplicitConstructorKind::TypeWrapperStorage) { + accessLevel = AccessLevel::Public; + + auto *typeWrapper = decl->getTypeWrapper(); + + auto *arg = new (ctx) ParamDecl(SourceLoc(), Loc, ctx.Id_storageWrapper, + Loc, ctx.Id_storageWrapper, decl); + + auto typeWrapperType = typeWrapper->getDeclaredInterfaceType(); + + TypeSubstitutionMap subs; + { + auto genericParams = + typeWrapper->getGenericSignature().getInnermostGenericParams(); + // Wrapped -> wrapped type + subs[genericParams[0]->getCanonicalType()->castTo()] = + decl->getDeclaredInterfaceType(); + // Storage -> $Storage + subs[genericParams[1]->getCanonicalType()->castTo()] = + decl->getTypeWrapperStorageDecl()->getDeclaredInterfaceType(); + } + + auto paramType = typeWrapperType.subst(SubstitutionMap::get( + typeWrapper->getGenericSignature(), QueryTypeSubstitutionMap{subs}, + LookUpConformanceInModule(decl->getParentModule()))); + + arg->setSpecifier(ParamSpecifier::Default); + arg->setInterfaceType(paramType); + arg->setImplicit(); + + params.push_back(arg); } else if (ICK == ImplicitConstructorKind::TypeWrapperMemberwise) { // Access to the initializer should match that of its parent type. accessLevel = decl->getEffectiveAccess(); @@ -1247,6 +1281,11 @@ void TypeChecker::addImplicitConstructors(NominalTypeDecl *decl) { if (!shouldAttemptInitializerSynthesis(decl)) { if (decl->hasTypeWrapper()) { auto &ctx = decl->getASTContext(); + + // Synthesize a special `init(storageWrapper: )` + // initializer if possible. + (void)decl->getTypeWrappedTypeStorageInitializer(); + // If declaration is type wrapped and there are no // designated initializers, synthesize a special // memberwise initializer that would instantiate `$storage`. @@ -1574,6 +1613,34 @@ void swift::addNonIsolatedToSynthesized( value->getAttrs().add(new (ctx) NonisolatedAttr(/*isImplicit=*/true)); } +static std::pair +synthesizeTypeWrappedTypeStorageWrapperInitializerBody( + AbstractFunctionDecl *decl, void *) { + return {nullptr, /*isTypeChecked=*/false}; +} + +ConstructorDecl *SynthesizeTypeWrappedTypeStorageWrapperInitializer::evaluate( + Evaluator &evaluator, NominalTypeDecl *wrappedType) const { + if (!wrappedType->hasTypeWrapper()) + return nullptr; + + // `@typeWrapperIgnored` properties suppress this initializer. + if (llvm::any_of(wrappedType->getMembers(), [&](Decl *member) { + return member->getAttrs().hasAttribute(); + })) + return nullptr; + + // Create the implicit type wrapper storage constructor. + auto &ctx = wrappedType->getASTContext(); + auto ctor = createImplicitConstructor( + wrappedType, ImplicitConstructorKind::TypeWrapperStorage, ctx); + wrappedType->addMember(ctor); + + ctor->setBodySynthesizer( + synthesizeTypeWrappedTypeStorageWrapperInitializerBody); + return ctor; +} + static std::pair synthesizeTypeWrappedTypeMemberwiseInitializerBody(AbstractFunctionDecl *decl, void *) { diff --git a/lib/Sema/TypeCheckTypeWrapper.cpp b/lib/Sema/TypeCheckTypeWrapper.cpp index 650da7b4d8a..a2e6e53f5fa 100644 --- a/lib/Sema/TypeCheckTypeWrapper.cpp +++ b/lib/Sema/TypeCheckTypeWrapper.cpp @@ -151,6 +151,13 @@ VarDecl *NominalTypeDecl::getTypeWrapperProperty() const { GetTypeWrapperProperty{mutableSelf}, nullptr); } +ConstructorDecl *NominalTypeDecl::getTypeWrappedTypeStorageInitializer() const { + auto *mutableSelf = const_cast(this); + return evaluateOrDefault( + getASTContext().evaluator, + SynthesizeTypeWrappedTypeStorageWrapperInitializer{mutableSelf}, nullptr); +} + ConstructorDecl * NominalTypeDecl::getTypeWrappedTypeMemberwiseInitializer() const { auto *mutableSelf = const_cast(this);