Skip to content

Commit 9df15d4

Browse files
committed
[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.
1 parent 7dac156 commit 9df15d4

File tree

6 files changed

+99
-1
lines changed

6 files changed

+99
-1
lines changed

include/swift/AST/Decl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3882,9 +3882,13 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
38823882
NominalTypeDecl *getTypeWrapperStorageDecl() const;
38833883

38843884
/// If this declaration is a type wrapper, retrieve
3885-
/// its required initializer - `init(storage:)`.
3885+
/// its required initializer - `init(storageWrapper:)`.
38863886
ConstructorDecl *getTypeWrapperInitializer() const;
38873887

3888+
/// Get an initializer that accepts a type wrapper instance to
3889+
/// initialize the wrapped type.
3890+
ConstructorDecl *getTypeWrappedTypeStorageInitializer() const;
3891+
38883892
/// Get a memberwise initializer that could be used to instantiate a
38893893
/// type wrapped type.
38903894
ConstructorDecl *getTypeWrappedTypeMemberwiseInitializer() const;

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ IDENTIFIER_WITH_NAME(TypeWrapperProperty, "$storage")
315315
IDENTIFIER(storageKeyPath)
316316
IDENTIFIER(propertyKeyPath)
317317
IDENTIFIER(wrappedSelf)
318+
IDENTIFIER(storageWrapper)
318319
IDENTIFIER_WITH_NAME(localStorageVar, "_storage")
319320

320321
// Attribute options

include/swift/AST/TypeCheckRequests.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3689,6 +3689,22 @@ class SynthesizeTypeWrappedTypeMemberwiseInitializer
36893689
bool isCached() const { return true; }
36903690
};
36913691

3692+
class SynthesizeTypeWrappedTypeStorageWrapperInitializer
3693+
: public SimpleRequest<SynthesizeTypeWrappedTypeStorageWrapperInitializer,
3694+
ConstructorDecl *(NominalTypeDecl *),
3695+
RequestFlags::Cached> {
3696+
public:
3697+
using SimpleRequest::SimpleRequest;
3698+
3699+
private:
3700+
friend SimpleRequest;
3701+
3702+
ConstructorDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *) const;
3703+
3704+
public:
3705+
bool isCached() const { return true; }
3706+
};
3707+
36923708
class SynthesizeLocalVariableForTypeWrapperStorage
36933709
: public SimpleRequest<SynthesizeLocalVariableForTypeWrapperStorage,
36943710
VarDecl *(ConstructorDecl *), RequestFlags::Cached> {

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,9 @@ SWIFT_REQUEST(TypeChecker, IsPropertyAccessedViaTypeWrapper,
431431
SWIFT_REQUEST(TypeChecker, SynthesizeTypeWrappedTypeMemberwiseInitializer,
432432
ConstructorDecl *(NominalTypeDecl *),
433433
Cached, NoLocationInfo)
434+
SWIFT_REQUEST(TypeChecker, SynthesizeTypeWrappedTypeStorageWrapperInitializer,
435+
ConstructorDecl *(NominalTypeDecl *),
436+
Cached, NoLocationInfo)
434437
SWIFT_REQUEST(TypeChecker, SynthesizeLocalVariableForTypeWrapperStorage,
435438
VarDecl *(ConstructorDecl *),
436439
Cached, NoLocationInfo)

lib/Sema/CodeSynthesis.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ enum class ImplicitConstructorKind {
246246
/// the instance variables from a parameter of the same type and
247247
/// name.
248248
Memberwise,
249+
/// The constructor of a type wrapped type that accepts an instance of
250+
/// type wrapper i.e. `init(storageWrapper: Wrapper<Self, $Storage>)`.
251+
TypeWrapperStorage,
249252
/// The memberwise constructor of a type wrapped type which is going to
250253
/// initialize underlying storage for all applicable properties.
251254
TypeWrapperMemberwise,
@@ -372,6 +375,37 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
372375

373376
params.push_back(arg);
374377
}
378+
} else if (ICK == ImplicitConstructorKind::TypeWrapperStorage) {
379+
accessLevel = AccessLevel::Public;
380+
381+
auto *typeWrapper = decl->getTypeWrapper();
382+
383+
auto *arg = new (ctx) ParamDecl(SourceLoc(), Loc, ctx.Id_storageWrapper,
384+
Loc, ctx.Id_storageWrapper, decl);
385+
386+
auto typeWrapperType = typeWrapper->getDeclaredInterfaceType();
387+
388+
TypeSubstitutionMap subs;
389+
{
390+
auto genericParams =
391+
typeWrapper->getGenericSignature().getInnermostGenericParams();
392+
// Wrapped -> wrapped type
393+
subs[genericParams[0]->getCanonicalType()->castTo<SubstitutableType>()] =
394+
decl->getDeclaredInterfaceType();
395+
// Storage -> $Storage
396+
subs[genericParams[1]->getCanonicalType()->castTo<SubstitutableType>()] =
397+
decl->getTypeWrapperStorageDecl()->getDeclaredInterfaceType();
398+
}
399+
400+
auto paramType = typeWrapperType.subst(SubstitutionMap::get(
401+
typeWrapper->getGenericSignature(), QueryTypeSubstitutionMap{subs},
402+
LookUpConformanceInModule(decl->getParentModule())));
403+
404+
arg->setSpecifier(ParamSpecifier::Default);
405+
arg->setInterfaceType(paramType);
406+
arg->setImplicit();
407+
408+
params.push_back(arg);
375409
} else if (ICK == ImplicitConstructorKind::TypeWrapperMemberwise) {
376410
// Access to the initializer should match that of its parent type.
377411
accessLevel = decl->getEffectiveAccess();
@@ -1261,6 +1295,11 @@ void TypeChecker::addImplicitConstructors(NominalTypeDecl *decl) {
12611295
if (!shouldAttemptInitializerSynthesis(decl)) {
12621296
if (decl->hasTypeWrapper()) {
12631297
auto &ctx = decl->getASTContext();
1298+
1299+
// Synthesize a special `init(storageWrapper: <Wrapper>)`
1300+
// initializer if possible.
1301+
(void)decl->getTypeWrappedTypeStorageInitializer();
1302+
12641303
// If declaration is type wrapped and there are no
12651304
// designated initializers, synthesize a special
12661305
// memberwise initializer that would instantiate `$storage`.
@@ -1588,6 +1627,34 @@ void swift::addNonIsolatedToSynthesized(
15881627
value->getAttrs().add(new (ctx) NonisolatedAttr(/*isImplicit=*/true));
15891628
}
15901629

1630+
static std::pair<BraceStmt *, /*isTypeChecked=*/bool>
1631+
synthesizeTypeWrappedTypeStorageWrapperInitializerBody(
1632+
AbstractFunctionDecl *decl, void *) {
1633+
return {nullptr, /*isTypeChecked=*/false};
1634+
}
1635+
1636+
ConstructorDecl *SynthesizeTypeWrappedTypeStorageWrapperInitializer::evaluate(
1637+
Evaluator &evaluator, NominalTypeDecl *wrappedType) const {
1638+
if (!wrappedType->hasTypeWrapper())
1639+
return nullptr;
1640+
1641+
// `@typeWrapperIgnored` properties suppress this initializer.
1642+
if (llvm::any_of(wrappedType->getMembers(), [&](Decl *member) {
1643+
return member->getAttrs().hasAttribute<TypeWrapperIgnoredAttr>();
1644+
}))
1645+
return nullptr;
1646+
1647+
// Create the implicit type wrapper storage constructor.
1648+
auto &ctx = wrappedType->getASTContext();
1649+
auto ctor = createImplicitConstructor(
1650+
wrappedType, ImplicitConstructorKind::TypeWrapperStorage, ctx);
1651+
wrappedType->addMember(ctor);
1652+
1653+
ctor->setBodySynthesizer(
1654+
synthesizeTypeWrappedTypeStorageWrapperInitializerBody);
1655+
return ctor;
1656+
}
1657+
15911658
static std::pair<BraceStmt *, /*isTypeChecked=*/bool>
15921659
synthesizeTypeWrappedTypeMemberwiseInitializerBody(AbstractFunctionDecl *decl,
15931660
void *) {

lib/Sema/TypeCheckTypeWrapper.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,13 @@ VarDecl *NominalTypeDecl::getTypeWrapperProperty() const {
151151
GetTypeWrapperProperty{mutableSelf}, nullptr);
152152
}
153153

154+
ConstructorDecl *NominalTypeDecl::getTypeWrappedTypeStorageInitializer() const {
155+
auto *mutableSelf = const_cast<NominalTypeDecl *>(this);
156+
return evaluateOrDefault(
157+
getASTContext().evaluator,
158+
SynthesizeTypeWrappedTypeStorageWrapperInitializer{mutableSelf}, nullptr);
159+
}
160+
154161
ConstructorDecl *
155162
NominalTypeDecl::getTypeWrappedTypeMemberwiseInitializer() const {
156163
auto *mutableSelf = const_cast<NominalTypeDecl *>(this);

0 commit comments

Comments
 (0)