Skip to content

Commit 2ae0cb8

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 b800b0b commit 2ae0cb8

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
@@ -3926,9 +3926,13 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
39263926
NominalTypeDecl *getTypeWrapperStorageDecl() const;
39273927

39283928
/// If this declaration is a type wrapper, retrieve
3929-
/// its required initializer - `init(storage:)`.
3929+
/// its required initializer - `init(storageWrapper:)`.
39303930
ConstructorDecl *getTypeWrapperInitializer() const;
39313931

3932+
/// Get an initializer that accepts a type wrapper instance to
3933+
/// initialize the wrapped type.
3934+
ConstructorDecl *getTypeWrappedTypeStorageInitializer() const;
3935+
39323936
/// Get a memberwise initializer that could be used to instantiate a
39333937
/// type wrapped type.
39343938
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
@@ -232,6 +232,9 @@ enum class ImplicitConstructorKind {
232232
/// the instance variables from a parameter of the same type and
233233
/// name.
234234
Memberwise,
235+
/// The constructor of a type wrapped type that accepts an instance of
236+
/// type wrapper i.e. `init(storageWrapper: Wrapper<Self, $Storage>)`.
237+
TypeWrapperStorage,
235238
/// The memberwise constructor of a type wrapped type which is going to
236239
/// initialize underlying storage for all applicable properties.
237240
TypeWrapperMemberwise,
@@ -358,6 +361,37 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
358361

359362
params.push_back(arg);
360363
}
364+
} else if (ICK == ImplicitConstructorKind::TypeWrapperStorage) {
365+
accessLevel = AccessLevel::Public;
366+
367+
auto *typeWrapper = decl->getTypeWrapper();
368+
369+
auto *arg = new (ctx) ParamDecl(SourceLoc(), Loc, ctx.Id_storageWrapper,
370+
Loc, ctx.Id_storageWrapper, decl);
371+
372+
auto typeWrapperType = typeWrapper->getDeclaredInterfaceType();
373+
374+
TypeSubstitutionMap subs;
375+
{
376+
auto genericParams =
377+
typeWrapper->getGenericSignature().getInnermostGenericParams();
378+
// Wrapped -> wrapped type
379+
subs[genericParams[0]->getCanonicalType()->castTo<SubstitutableType>()] =
380+
decl->getDeclaredInterfaceType();
381+
// Storage -> $Storage
382+
subs[genericParams[1]->getCanonicalType()->castTo<SubstitutableType>()] =
383+
decl->getTypeWrapperStorageDecl()->getDeclaredInterfaceType();
384+
}
385+
386+
auto paramType = typeWrapperType.subst(SubstitutionMap::get(
387+
typeWrapper->getGenericSignature(), QueryTypeSubstitutionMap{subs},
388+
LookUpConformanceInModule(decl->getParentModule())));
389+
390+
arg->setSpecifier(ParamSpecifier::Default);
391+
arg->setInterfaceType(paramType);
392+
arg->setImplicit();
393+
394+
params.push_back(arg);
361395
} else if (ICK == ImplicitConstructorKind::TypeWrapperMemberwise) {
362396
// Access to the initializer should match that of its parent type.
363397
accessLevel = decl->getEffectiveAccess();
@@ -1247,6 +1281,11 @@ void TypeChecker::addImplicitConstructors(NominalTypeDecl *decl) {
12471281
if (!shouldAttemptInitializerSynthesis(decl)) {
12481282
if (decl->hasTypeWrapper()) {
12491283
auto &ctx = decl->getASTContext();
1284+
1285+
// Synthesize a special `init(storageWrapper: <Wrapper>)`
1286+
// initializer if possible.
1287+
(void)decl->getTypeWrappedTypeStorageInitializer();
1288+
12501289
// If declaration is type wrapped and there are no
12511290
// designated initializers, synthesize a special
12521291
// memberwise initializer that would instantiate `$storage`.
@@ -1574,6 +1613,34 @@ void swift::addNonIsolatedToSynthesized(
15741613
value->getAttrs().add(new (ctx) NonisolatedAttr(/*isImplicit=*/true));
15751614
}
15761615

1616+
static std::pair<BraceStmt *, /*isTypeChecked=*/bool>
1617+
synthesizeTypeWrappedTypeStorageWrapperInitializerBody(
1618+
AbstractFunctionDecl *decl, void *) {
1619+
return {nullptr, /*isTypeChecked=*/false};
1620+
}
1621+
1622+
ConstructorDecl *SynthesizeTypeWrappedTypeStorageWrapperInitializer::evaluate(
1623+
Evaluator &evaluator, NominalTypeDecl *wrappedType) const {
1624+
if (!wrappedType->hasTypeWrapper())
1625+
return nullptr;
1626+
1627+
// `@typeWrapperIgnored` properties suppress this initializer.
1628+
if (llvm::any_of(wrappedType->getMembers(), [&](Decl *member) {
1629+
return member->getAttrs().hasAttribute<TypeWrapperIgnoredAttr>();
1630+
}))
1631+
return nullptr;
1632+
1633+
// Create the implicit type wrapper storage constructor.
1634+
auto &ctx = wrappedType->getASTContext();
1635+
auto ctor = createImplicitConstructor(
1636+
wrappedType, ImplicitConstructorKind::TypeWrapperStorage, ctx);
1637+
wrappedType->addMember(ctor);
1638+
1639+
ctor->setBodySynthesizer(
1640+
synthesizeTypeWrappedTypeStorageWrapperInitializerBody);
1641+
return ctor;
1642+
}
1643+
15771644
static std::pair<BraceStmt *, /*isTypeChecked=*/bool>
15781645
synthesizeTypeWrappedTypeMemberwiseInitializerBody(AbstractFunctionDecl *decl,
15791646
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)