[AST/Sema] TypeWrappers: Add a request skeleton to synthesize init(storageWrapper: <Wrapper>)

If there are no type wrapper ignored stored properties, the
compiler would synthesize a special public initializer that
allows to initialize a wrapped type by providing a fully
initialized wrapper instance.
This commit is contained in:
Pavel Yaskevich
2022-10-18 19:34:19 +01:00
parent b800b0b81b
commit 2ae0cb802a
6 changed files with 99 additions and 1 deletions

View File

@@ -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;

View File

@@ -315,6 +315,7 @@ IDENTIFIER_WITH_NAME(TypeWrapperProperty, "$storage")
IDENTIFIER(storageKeyPath)
IDENTIFIER(propertyKeyPath)
IDENTIFIER(wrappedSelf)
IDENTIFIER(storageWrapper)
IDENTIFIER_WITH_NAME(localStorageVar, "_storage")
// Attribute options

View File

@@ -3689,6 +3689,22 @@ public:
bool isCached() const { return true; }
};
class SynthesizeTypeWrappedTypeStorageWrapperInitializer
: public SimpleRequest<SynthesizeTypeWrappedTypeStorageWrapperInitializer,
ConstructorDecl *(NominalTypeDecl *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
private:
friend SimpleRequest;
ConstructorDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *) const;
public:
bool isCached() const { return true; }
};
class SynthesizeLocalVariableForTypeWrapperStorage
: public SimpleRequest<SynthesizeLocalVariableForTypeWrapperStorage,
VarDecl *(ConstructorDecl *), RequestFlags::Cached> {

View File

@@ -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)

View File

@@ -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<Self, $Storage>)`.
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<SubstitutableType>()] =
decl->getDeclaredInterfaceType();
// Storage -> $Storage
subs[genericParams[1]->getCanonicalType()->castTo<SubstitutableType>()] =
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: <Wrapper>)`
// 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<BraceStmt *, /*isTypeChecked=*/bool>
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<TypeWrapperIgnoredAttr>();
}))
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<BraceStmt *, /*isTypeChecked=*/bool>
synthesizeTypeWrappedTypeMemberwiseInitializerBody(AbstractFunctionDecl *decl,
void *) {

View File

@@ -151,6 +151,13 @@ VarDecl *NominalTypeDecl::getTypeWrapperProperty() const {
GetTypeWrapperProperty{mutableSelf}, nullptr);
}
ConstructorDecl *NominalTypeDecl::getTypeWrappedTypeStorageInitializer() const {
auto *mutableSelf = const_cast<NominalTypeDecl *>(this);
return evaluateOrDefault(
getASTContext().evaluator,
SynthesizeTypeWrappedTypeStorageWrapperInitializer{mutableSelf}, nullptr);
}
ConstructorDecl *
NominalTypeDecl::getTypeWrappedTypeMemberwiseInitializer() const {
auto *mutableSelf = const_cast<NominalTypeDecl *>(this);