Skip to content

Commit 6384392

Browse files
authored
Merge pull request #67221 from xedin/init-accessor-self-and-without-setters-5.9
[5.9][AST/Sema/SIL] Init accessor improvements
2 parents 27f4369 + 345b73d commit 6384392

38 files changed

+1237
-419
lines changed

include/swift/AST/Attr.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,48 @@ class AccessesAttr final
15941594
}
15951595
};
15961596

1597+
class StorageRestrictionsAttr final
1598+
: public DeclAttribute,
1599+
private llvm::TrailingObjects<StorageRestrictionsAttr, Identifier> {
1600+
friend TrailingObjects;
1601+
1602+
size_t NumInitializes;
1603+
size_t NumAccesses;
1604+
1605+
size_t numTrailingObjects(OverloadToken<Identifier>) const {
1606+
return NumInitializes + NumAccesses;
1607+
}
1608+
1609+
public:
1610+
StorageRestrictionsAttr(SourceLoc AtLoc, SourceRange Range,
1611+
ArrayRef<Identifier> initializes,
1612+
ArrayRef<Identifier> accesses, bool Implicit);
1613+
1614+
unsigned getNumInitializesProperties() const { return NumInitializes; }
1615+
1616+
unsigned getNumAccessesProperties() const { return NumAccesses; }
1617+
1618+
ArrayRef<Identifier> getInitializesNames() const {
1619+
return {getTrailingObjects<Identifier>(), NumInitializes};
1620+
}
1621+
1622+
ArrayRef<Identifier> getAccessesNames() const {
1623+
return {getTrailingObjects<Identifier>() + NumInitializes, NumAccesses};
1624+
}
1625+
1626+
ArrayRef<VarDecl *> getInitializesProperties(AccessorDecl *attachedTo) const;
1627+
ArrayRef<VarDecl *> getAccessesProperties(AccessorDecl *attachedTo) const;
1628+
1629+
static StorageRestrictionsAttr *create(ASTContext &ctx, SourceLoc atLoc,
1630+
SourceRange range,
1631+
ArrayRef<Identifier> initializes,
1632+
ArrayRef<Identifier> accesses);
1633+
1634+
static bool classof(const DeclAttribute *DA) {
1635+
return DA->getKind() == DAK_StorageRestrictions;
1636+
}
1637+
};
1638+
15971639
/// The @_implements attribute, which treats a decl as the implementation for
15981640
/// some named protocol requirement (but otherwise not-visible by that name).
15991641
class ImplementsAttr : public DeclAttribute {

include/swift/AST/Decl.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7652,6 +7652,13 @@ class AccessorDecl final : public FuncDecl {
76527652
/// for anything other than a getter or setter.
76537653
void printUserFacingName(llvm::raw_ostream &out) const;
76547654

7655+
/// If this is an init accessor, retrieve a list of instance properties
7656+
/// initialized by it.
7657+
ArrayRef<VarDecl *> getInitializedProperties() const;
7658+
/// If this is an init accessor, retrieve a list of instance properties
7659+
/// accessed by it.
7660+
ArrayRef<VarDecl *> getAccessedProperties() const;
7661+
76557662
static bool classof(const Decl *D) {
76567663
return D->getKind() == DeclKind::Accessor;
76577664
}

include/swift/AST/DiagnosticsParse.def

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2127,5 +2127,17 @@ ERROR(init_accessor_is_not_on_property,none,
21272127
"init accessors could only be associated with properties",
21282128
())
21292129

2130+
ERROR(missing_storage_restrictions_attr_label,none,
2131+
"missing label in @storageRestrictions attribute", ())
2132+
2133+
ERROR(invalid_storage_restrictions_attr_label,none,
2134+
"unexpected label %0 in @storageRestrictions attribute", (Identifier))
2135+
2136+
ERROR(duplicate_storage_restrictions_attr_label,none,
2137+
"duplicate label %0 in @storageRestrictions attribute", (Identifier))
2138+
2139+
ERROR(storage_restrictions_attr_expected_name,none,
2140+
"expected property name in @storageRestrictions list", ())
2141+
21302142
#define UNDEFINE_DIAGNOSTIC_MACROS
21312143
#include "DefineDiagnosticMacros.h"

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7384,6 +7384,9 @@ ERROR(init_accessor_initializes_attribute_on_other_declaration,none,
73847384
ERROR(init_accessor_accesses_attribute_on_other_declaration,none,
73857385
"accesses(...) attribute could only be used with init accessors",
73867386
())
7387+
ERROR(storage_restrictions_attribute_not_on_init_accessor,none,
7388+
"@storageRestrictions attribute could only be used with init accessors",
7389+
())
73877390
ERROR(init_accessor_property_both_init_and_accessed,none,
73887391
"property %0 cannot be both initialized and accessed",
73897392
(DeclName))

include/swift/Parse/Parser.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,11 @@ class Parser {
10721072
llvm::function_ref<bool(Parser &)> parseSILTargetName,
10731073
llvm::function_ref<bool(Parser &)> parseSILSIPModule);
10741074

1075+
/// Parse the @storageRestrictions(initializes:accesses:) attribute.
1076+
/// \p Attr is where to store the parsed attribute
1077+
ParserResult<StorageRestrictionsAttr>
1078+
parseStorageRestrictionsAttribute(SourceLoc AtLoc, SourceLoc Loc);
1079+
10751080
/// Parse the @_implements attribute.
10761081
/// \p Attr is where to store the parsed attribute
10771082
ParserResult<ImplementsAttr> parseImplementsAttribute(SourceLoc AtLoc,

include/swift/SIL/SILBuilder.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -958,12 +958,14 @@ class SILBuilder {
958958
getSILDebugLocation(Loc), Src, Dest, Initializer, Setter, mode));
959959
}
960960

961-
AssignOrInitInst *createAssignOrInit(SILLocation Loc, SILValue Src,
961+
AssignOrInitInst *createAssignOrInit(SILLocation Loc,
962+
SILValue Self,
963+
SILValue Src,
962964
SILValue Initializer,
963965
SILValue Setter,
964966
AssignOrInitInst::Mode Mode) {
965967
return insert(new (getModule()) AssignOrInitInst(
966-
getSILDebugLocation(Loc), Src, Initializer, Setter, Mode));
968+
getSILDebugLocation(Loc), Self, Src, Initializer, Setter, Mode));
967969
}
968970

969971
StoreBorrowInst *createStoreBorrow(SILLocation Loc, SILValue Src,

include/swift/SIL/SILCloner.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,6 +1360,7 @@ void SILCloner<ImplClass>::visitAssignOrInitInst(AssignOrInitInst *Inst) {
13601360
recordClonedInstruction(
13611361
Inst, getBuilder().createAssignOrInit(
13621362
getOpLocation(Inst->getLoc()),
1363+
getOpValue(Inst->getSelf()),
13631364
getOpValue(Inst->getSrc()),
13641365
getOpValue(Inst->getInitializer()),
13651366
getOpValue(Inst->getSetter()), Inst->getMode()));

include/swift/SIL/SILInstruction.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4933,7 +4933,7 @@ class AssignOrInitInst
49334933
friend SILBuilder;
49344934
USE_SHARED_UINT8;
49354935

4936-
FixedOperandList<3> Operands;
4936+
FixedOperandList<4> Operands;
49374937

49384938
/// Marks all of the properties in `initializes(...)` list that
49394939
/// have been initialized before this intruction to help Raw SIL
@@ -4953,14 +4953,14 @@ class AssignOrInitInst
49534953
};
49544954

49554955
private:
4956-
AssignOrInitInst(SILDebugLocation DebugLoc,
4957-
SILValue Src, SILValue Initializer,
4958-
SILValue Setter, Mode mode);
4956+
AssignOrInitInst(SILDebugLocation DebugLoc, SILValue Self, SILValue Src,
4957+
SILValue Initializer, SILValue Setter, Mode mode);
49594958

49604959
public:
4961-
SILValue getSrc() const { return Operands[0].get(); }
4962-
SILValue getInitializer() const { return Operands[1].get(); }
4963-
SILValue getSetter() { return Operands[2].get(); }
4960+
SILValue getSelf() const { return Operands[0].get(); }
4961+
SILValue getSrc() const { return Operands[1].get(); }
4962+
SILValue getInitializer() const { return Operands[2].get(); }
4963+
SILValue getSetter() { return Operands[3].get(); }
49644964

49654965
Mode getMode() const {
49664966
return Mode(sharedUInt8().AssignOrInitInst.mode);
@@ -4988,6 +4988,7 @@ class AssignOrInitInst
49884988
ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
49894989
MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
49904990

4991+
StringRef getPropertyName() const;
49914992
AccessorDecl *getReferencedInitAccessor() const;
49924993
};
49934994

lib/AST/Attr.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,8 @@ StringRef DeclAttribute::getAttrName() const {
15941594
return "initializes";
15951595
case DAK_Accesses:
15961596
return "accesses";
1597+
case DAK_StorageRestrictions:
1598+
return "storageRestrictions";
15971599
case DAK_Implements:
15981600
return "_implements";
15991601
case DAK_ClangImporterSynthesizedType:
@@ -2397,6 +2399,29 @@ AccessesAttr::create(ASTContext &ctx, SourceLoc atLoc, SourceRange range,
23972399
return new (mem) AccessesAttr(atLoc, range, properties);
23982400
}
23992401

2402+
StorageRestrictionsAttr::StorageRestrictionsAttr(
2403+
SourceLoc AtLoc, SourceRange Range, ArrayRef<Identifier> initializes,
2404+
ArrayRef<Identifier> accesses, bool Implicit)
2405+
: DeclAttribute(DAK_StorageRestrictions, AtLoc, Range, Implicit),
2406+
NumInitializes(initializes.size()),
2407+
NumAccesses(accesses.size()) {
2408+
std::uninitialized_copy(initializes.begin(), initializes.end(),
2409+
getTrailingObjects<Identifier>());
2410+
std::uninitialized_copy(accesses.begin(), accesses.end(),
2411+
getTrailingObjects<Identifier>() + NumInitializes);
2412+
}
2413+
2414+
StorageRestrictionsAttr *
2415+
StorageRestrictionsAttr::create(
2416+
ASTContext &ctx, SourceLoc atLoc, SourceRange range,
2417+
ArrayRef<Identifier> initializes, ArrayRef<Identifier> accesses) {
2418+
unsigned size =
2419+
totalSizeToAlloc<Identifier>(initializes.size() + accesses.size());
2420+
void *mem = ctx.Allocate(size, alignof(StorageRestrictionsAttr));
2421+
return new (mem) StorageRestrictionsAttr(atLoc, range, initializes, accesses,
2422+
/*implicit=*/false);
2423+
}
2424+
24002425
ImplementsAttr::ImplementsAttr(SourceLoc atLoc, SourceRange range,
24012426
TypeExpr *ProtocolType,
24022427
DeclName MemberName,
@@ -2571,6 +2596,26 @@ AccessesAttr::getPropertyDecls(AccessorDecl *attachedTo) const {
25712596
{});
25722597
}
25732598

2599+
ArrayRef<VarDecl *> StorageRestrictionsAttr::getInitializesProperties(
2600+
AccessorDecl *attachedTo) const {
2601+
auto &ctx = attachedTo->getASTContext();
2602+
return evaluateOrDefault(ctx.evaluator,
2603+
InitAccessorReferencedVariablesRequest{
2604+
const_cast<StorageRestrictionsAttr *>(this),
2605+
attachedTo, getInitializesNames()},
2606+
{});
2607+
}
2608+
2609+
ArrayRef<VarDecl *>
2610+
StorageRestrictionsAttr::getAccessesProperties(AccessorDecl *attachedTo) const {
2611+
auto &ctx = attachedTo->getASTContext();
2612+
return evaluateOrDefault(ctx.evaluator,
2613+
InitAccessorReferencedVariablesRequest{
2614+
const_cast<StorageRestrictionsAttr *>(this),
2615+
attachedTo, getAccessesNames()},
2616+
{});
2617+
}
2618+
25742619
void swift::simple_display(llvm::raw_ostream &out, const DeclAttribute *attr) {
25752620
if (attr)
25762621
attr->print(out);

lib/AST/Decl.cpp

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,10 +2413,15 @@ getDirectReadAccessStrategy(const AbstractStorageDecl *storage) {
24132413
static AccessStrategy
24142414
getDirectWriteAccessStrategy(const AbstractStorageDecl *storage) {
24152415
switch (storage->getWriteImpl()) {
2416-
case WriteImplKind::Immutable:
2416+
case WriteImplKind::Immutable: {
2417+
if (storage->hasInitAccessor())
2418+
return AccessStrategy::getAccessor(AccessorKind::Init,
2419+
/*dispatch=*/false);
2420+
24172421
assert(isa<VarDecl>(storage) && cast<VarDecl>(storage)->isLet() &&
24182422
"mutation of a immutable variable that isn't a let");
24192423
return AccessStrategy::getStorage();
2424+
}
24202425
case WriteImplKind::Stored:
24212426
return AccessStrategy::getStorage();
24222427
case WriteImplKind::StoredWithObservers:
@@ -2493,7 +2498,9 @@ getOpaqueReadAccessStrategy(const AbstractStorageDecl *storage, bool dispatch) {
24932498
}
24942499

24952500
static AccessStrategy
2496-
getOpaqueWriteAccessStrategy(const AbstractStorageDecl *storage, bool dispatch){
2501+
getOpaqueWriteAccessStrategy(const AbstractStorageDecl *storage, bool dispatch) {
2502+
if (storage->hasInitAccessor() && !storage->getAccessor(AccessorKind::Set))
2503+
return AccessStrategy::getAccessor(AccessorKind::Init, dispatch);
24972504
return AccessStrategy::getAccessor(AccessorKind::Set, dispatch);
24982505
}
24992506

@@ -4932,11 +4939,8 @@ void NominalTypeDecl::collectPropertiesInitializableByInitAccessors(
49324939
std::multimap<VarDecl *, VarDecl *> &result) const {
49334940
for (auto *property : getInitAccessorProperties()) {
49344941
auto *initAccessor = property->getAccessor(AccessorKind::Init);
4935-
if (auto *initAttr =
4936-
initAccessor->getAttrs().getAttribute<InitializesAttr>()) {
4937-
for (auto *subsumed : initAttr->getPropertyDecls(initAccessor))
4938-
result.insert({subsumed, property});
4939-
}
4942+
for (auto *subsumed : initAccessor->getInitializedProperties())
4943+
result.insert({subsumed, property});
49404944
}
49414945
}
49424946

@@ -6818,8 +6822,17 @@ bool VarDecl::isSettable(const DeclContext *UseDC,
68186822

68196823
// If this is a 'var' decl, then we're settable if we have storage or a
68206824
// setter.
6821-
if (!isLet())
6825+
if (!isLet()) {
6826+
if (hasInitAccessor()) {
6827+
if (auto *ctor = dyn_cast_or_null<ConstructorDecl>(UseDC)) {
6828+
if (base && ctor->getImplicitSelfDecl() != base->getDecl())
6829+
return supportsMutation();
6830+
return true;
6831+
}
6832+
}
6833+
68226834
return supportsMutation();
6835+
}
68236836

68246837
// Static 'let's are always immutable.
68256838
if (isStatic()) {
@@ -6843,21 +6856,15 @@ bool VarDecl::isSettable(const DeclContext *UseDC,
68436856
// designated initializer(s) or by init accessors.
68446857
if (isInstanceMember()) {
68456858
// Init accessors allow assignments to `let` properties if a
6846-
// property is part of `initializes(...)` list.
6859+
// property is part of `initializes` list.
68476860
if (auto *accessor =
68486861
dyn_cast<AccessorDecl>(const_cast<DeclContext *>(UseDC))) {
6849-
// Check whether this property is part of `initializes(...)` list,
6862+
// Check whether this property is part of `initializes` list,
68506863
// and allow assignment/mutation if so. DI would be responsible
68516864
// for checking for re-assignment.
6852-
if (auto *initAttr =
6853-
accessor->getAttrs().getAttribute<InitializesAttr>()) {
6854-
return llvm::is_contained(initAttr->getPropertyDecls(accessor),
6855-
const_cast<VarDecl *>(this));
6856-
}
6857-
6858-
// If there is no `initializes` attribute, no referenced properties
6859-
// can be assignment to or mutated.
6860-
return false;
6865+
return accessor->isInitAccessor() &&
6866+
llvm::is_contained(accessor->getInitializedProperties(),
6867+
const_cast<VarDecl *>(this));
68616868
}
68626869

68636870
auto *CD = dyn_cast<ConstructorDecl>(UseDC);
@@ -9520,6 +9527,32 @@ void AccessorDecl::printUserFacingName(raw_ostream &out) const {
95209527
out << ")";
95219528
}
95229529

9530+
ArrayRef<VarDecl *> AccessorDecl::getInitializedProperties() const {
9531+
assert(isInitAccessor());
9532+
9533+
if (auto *SR = getAttrs().getAttribute<StorageRestrictionsAttr>())
9534+
return SR->getInitializesProperties(const_cast<AccessorDecl *>(this));
9535+
9536+
// Fallback to old effect style declaration.
9537+
if (auto *initAttr = getAttrs().getAttribute<InitializesAttr>())
9538+
return initAttr->getPropertyDecls(const_cast<AccessorDecl *>(this));
9539+
9540+
return {};
9541+
}
9542+
9543+
ArrayRef<VarDecl *> AccessorDecl::getAccessedProperties() const {
9544+
assert(isInitAccessor());
9545+
9546+
if (auto *SR = getAttrs().getAttribute<StorageRestrictionsAttr>())
9547+
return SR->getAccessesProperties(const_cast<AccessorDecl *>(this));
9548+
9549+
// Fallback to old effect style declaration.
9550+
if (auto *accessAttr = getAttrs().getAttribute<AccessesAttr>())
9551+
return accessAttr->getPropertyDecls(const_cast<AccessorDecl *>(this));
9552+
9553+
return {};
9554+
}
9555+
95239556
StaticSpellingKind FuncDecl::getCorrectStaticSpelling() const {
95249557
assert(getDeclContext()->isTypeContext());
95259558
if (!isStatic())

0 commit comments

Comments
 (0)