Skip to content

Commit db4b6a5

Browse files
committed
[AST/Sema] TypeWrappers: Implement type wrappers on protocols
Adding a type wrapper attribute on a protocol does two things: - Synthesizes `associatedtype $Storage` declaration with `internal` access - Synthesizes `var $storage: <#Wrapper#><Self, Self.$Storage>` value requirement
1 parent 2d052a0 commit db4b6a5

File tree

11 files changed

+60
-25
lines changed

11 files changed

+60
-25
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3909,8 +3909,9 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
39093909

39103910
/// If this declaration has a type wrapper, return `$Storage`
39113911
/// declaration that contains all the stored properties managed
3912-
/// by the wrapper.
3913-
NominalTypeDecl *getTypeWrapperStorageDecl() const;
3912+
/// by the wrapper. Note that if this type is a protocol them
3913+
/// this method returns an associated type for $Storage.
3914+
TypeDecl *getTypeWrapperStorageDecl() const;
39143915

39153916
/// If this declaration is a type wrapper, retrieve
39163917
/// its required initializer - `init(storageWrapper:)`.

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6605,7 +6605,7 @@ ERROR(type_wrappers_are_experimental,none,
66056605
"type wrappers are an experimental feature", ())
66066606

66076607
ERROR(type_wrapper_attribute_not_allowed_here,none,
6608-
"type wrapper attribute %0 can only be applied to a class, struct",
6608+
"type wrapper attribute %0 can only be applied to a class, struct, or protocol",
66096609
(Identifier))
66106610

66116611
ERROR(type_wrapper_requires_two_generic_params,none,

include/swift/AST/TypeCheckRequests.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3552,16 +3552,15 @@ class GetTypeWrapperType
35523552
/// Inject or get `$Storage` type which has all of the stored properties
35533553
/// of the given type with a type wrapper.
35543554
class GetTypeWrapperStorage
3555-
: public SimpleRequest<GetTypeWrapperStorage,
3556-
NominalTypeDecl *(NominalTypeDecl *),
3555+
: public SimpleRequest<GetTypeWrapperStorage, TypeDecl *(NominalTypeDecl *),
35573556
RequestFlags::Cached> {
35583557
public:
35593558
using SimpleRequest::SimpleRequest;
35603559

35613560
private:
35623561
friend SimpleRequest;
35633562

3564-
NominalTypeDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *) const;
3563+
TypeDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *) const;
35653564

35663565
public:
35673566
bool isCached() const { return true; }

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ SWIFT_REQUEST(TypeChecker, GetTypeWrapperType,
408408
Type(NominalTypeDecl *),
409409
Cached, NoLocationInfo)
410410
SWIFT_REQUEST(TypeChecker, GetTypeWrapperStorage,
411-
NominalTypeDecl *(NominalTypeDecl *),
411+
TypeDecl *(NominalTypeDecl *),
412412
Cached, NoLocationInfo)
413413
SWIFT_REQUEST(TypeChecker, GetTypeWrapperProperty,
414414
VarDecl *(NominalTypeDecl *),

lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,8 @@ bool DIMemoryObjectInfo::isElementLetProperty(unsigned Element) const {
480480
assert(Element < storageVarType->getNumElements());
481481
auto propertyName = storageVarType->getElement(Element).getName();
482482

483-
auto *storageDecl = wrappedType->getTypeWrapperStorageDecl();
483+
auto *storageDecl =
484+
cast<NominalTypeDecl>(wrappedType->getTypeWrapperStorageDecl());
484485
auto *property = storageDecl->lookupDirect(propertyName).front();
485486
return cast<VarDecl>(property)->isLet();
486487
}

lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1093,7 +1093,8 @@ void LifetimeChecker::injectTypeWrapperStorageInitalization() {
10931093

10941094
auto *ctor = cast<ConstructorDecl>(storageVar->getDeclContext()->getAsDecl());
10951095
auto *parentType = ctor->getDeclContext()->getSelfNominalTypeDecl();
1096-
auto *storageDecl = parentType->getTypeWrapperStorageDecl();
1096+
auto *storageDecl =
1097+
cast<NominalTypeDecl>(parentType->getTypeWrapperStorageDecl());
10971098

10981099
for (auto *point : points) {
10991100
SILBuilderWithScope::insertAfter(point, [&](SILBuilder &b) {

lib/Sema/CodeSynthesis.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1646,6 +1646,9 @@ synthesizeTypeWrappedTypeStorageWrapperInitializerBody(
16461646

16471647
ConstructorDecl *SynthesizeTypeWrappedTypeStorageWrapperInitializer::evaluate(
16481648
Evaluator &evaluator, NominalTypeDecl *wrappedType) const {
1649+
if (isa<ProtocolDecl>(wrappedType))
1650+
return nullptr;
1651+
16491652
if (!wrappedType->hasTypeWrapper())
16501653
return nullptr;
16511654

@@ -1673,8 +1676,11 @@ synthesizeTypeWrappedTypeMemberwiseInitializerBody(AbstractFunctionDecl *decl,
16731676
auto &ctx = ctor->getASTContext();
16741677
auto *parent = ctor->getDeclContext()->getSelfNominalTypeDecl();
16751678

1679+
assert(!isa<ProtocolDecl>(parent));
1680+
16761681
// self.$storage = .init(storage: $Storage(...))
1677-
auto *storageType = parent->getTypeWrapperStorageDecl();
1682+
auto *storageType =
1683+
cast<NominalTypeDecl>(parent->getTypeWrapperStorageDecl());
16781684
assert(storageType);
16791685

16801686
auto *typeWrapperVar = parent->getTypeWrapperProperty();
@@ -1775,6 +1781,9 @@ synthesizeTypeWrappedTypeMemberwiseInitializerBody(AbstractFunctionDecl *decl,
17751781

17761782
ConstructorDecl *SynthesizeTypeWrappedTypeMemberwiseInitializer::evaluate(
17771783
Evaluator &evaluator, NominalTypeDecl *wrappedType) const {
1784+
if (isa<ProtocolDecl>(wrappedType))
1785+
return nullptr;
1786+
17781787
if (!wrappedType->hasTypeWrapper())
17791788
return nullptr;
17801789

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3597,7 +3597,7 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
35973597
}
35983598

35993599
if (nominal->getAttrs().hasAttribute<TypeWrapperAttr>()) {
3600-
if (!(isa<ClassDecl>(D) || isa<StructDecl>(D))) {
3600+
if (!(isa<ClassDecl>(D) || isa<StructDecl>(D) || isa<ProtocolDecl>(D))) {
36013601
diagnose(attr->getLocation(),
36023602
diag::type_wrapper_attribute_not_allowed_here,
36033603
nominal->getName());

lib/Sema/TypeCheckStorage.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3424,6 +3424,12 @@ StorageImplInfoRequest::evaluate(Evaluator &evaluator,
34243424
readWriteImpl = ReadWriteImplKind::MaterializeToTemporary;
34253425
} else if (storage->getParsedAccessor(AccessorKind::Get)) {
34263426
readImpl = ReadImplKind::Get;
3427+
} else if (storage->getName() ==
3428+
storage->getASTContext().Id_TypeWrapperProperty) {
3429+
// Type wrapper `$storage` property is `get set` requirement.
3430+
readImpl = ReadImplKind::Get;
3431+
writeImpl = WriteImplKind::Set;
3432+
readWriteImpl = ReadWriteImplKind::Modify;
34273433
}
34283434

34293435
StorageImplInfo info(readImpl, writeImpl, readWriteImpl);

lib/Sema/TypeCheckTypeWrapper.cpp

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -173,25 +173,36 @@ NominalTypeDecl::getTypeWrappedTypeMemberwiseInitializer() const {
173173
SynthesizeTypeWrappedTypeMemberwiseInitializer{mutableSelf}, nullptr);
174174
}
175175

176-
NominalTypeDecl *NominalTypeDecl::getTypeWrapperStorageDecl() const {
176+
TypeDecl *NominalTypeDecl::getTypeWrapperStorageDecl() const {
177177
auto *mutableSelf = const_cast<NominalTypeDecl *>(this);
178178
return evaluateOrDefault(getASTContext().evaluator,
179179
GetTypeWrapperStorage{mutableSelf}, nullptr);
180180
}
181181

182-
NominalTypeDecl *
183-
GetTypeWrapperStorage::evaluate(Evaluator &evaluator,
184-
NominalTypeDecl *parent) const {
182+
TypeDecl *GetTypeWrapperStorage::evaluate(Evaluator &evaluator,
183+
NominalTypeDecl *parent) const {
185184
if (!parent->hasTypeWrapper())
186185
return nullptr;
187186

188187
auto &ctx = parent->getASTContext();
189188

190-
auto *storage =
191-
new (ctx) StructDecl(/*StructLoc=*/SourceLoc(), ctx.Id_TypeWrapperStorage,
192-
/*NameLoc=*/SourceLoc(),
193-
/*Inheritted=*/{},
194-
/*GenericParams=*/nullptr, parent);
189+
TypeDecl *storage = nullptr;
190+
if (isa<ProtocolDecl>(parent)) {
191+
// If type wrapper is associated with a protocol, we need to
192+
// inject a new associated type - $Storage.
193+
storage = new (ctx)
194+
AssociatedTypeDecl(parent, /*keywordLoc=*/SourceLoc(),
195+
ctx.Id_TypeWrapperStorage, /*nameLoc=*/SourceLoc(),
196+
/*defaultDefinition=*/nullptr,
197+
/*trailingWhere=*/nullptr);
198+
} else {
199+
// For classes and structs we inject a new member struct - $Storage.
200+
storage = new (ctx)
201+
StructDecl(/*StructLoc=*/SourceLoc(), ctx.Id_TypeWrapperStorage,
202+
/*NameLoc=*/SourceLoc(),
203+
/*Inheritted=*/{},
204+
/*GenericParams=*/nullptr, parent);
205+
}
195206

196207
storage->setImplicit();
197208
storage->setSynthesized();
@@ -223,7 +234,7 @@ GetTypeWrapperProperty::evaluate(Evaluator &evaluator,
223234
auto propertyTy = BoundGenericType::get(
224235
typeWrapper, /*Parent=*/typeWrapperType->getParent(),
225236
/*genericArgs=*/
226-
{parent->getDeclaredInterfaceType(),
237+
{parent->getSelfInterfaceType(),
227238
storage->getDeclaredInterfaceType()});
228239

229240
return injectProperty(parent, ctx.Id_TypeWrapperProperty, propertyTy,
@@ -240,7 +251,10 @@ VarDecl *GetTypeWrapperStorageForProperty::evaluate(Evaluator &evaluator,
240251
if (!property->isAccessedViaTypeWrapper())
241252
return nullptr;
242253

243-
auto *storage = wrappedType->getTypeWrapperStorageDecl();
254+
assert(!isa<ProtocolDecl>(wrappedType));
255+
256+
auto *storage =
257+
cast<NominalTypeDecl>(wrappedType->getTypeWrapperStorageDecl());
244258
assert(storage);
245259

246260
// Type wrapper variables are never initialized directly,
@@ -456,7 +470,11 @@ VarDecl *SynthesizeLocalVariableForTypeWrapperStorage::evaluate(
456470
if (!(DC && DC->hasTypeWrapper()))
457471
return nullptr;
458472

459-
auto *storageDecl = DC->getTypeWrapperStorageDecl();
473+
// Default protocol initializers do not get transformed.
474+
if (isa<ProtocolDecl>(DC))
475+
return nullptr;
476+
477+
auto *storageDecl = cast<NominalTypeDecl>(DC->getTypeWrapperStorageDecl());
460478
assert(storageDecl);
461479

462480
SmallVector<TupleTypeElt, 4> members;

0 commit comments

Comments
 (0)