Skip to content

Commit 720b89d

Browse files
hborlaxedin
authored andcommitted
[Parse/Sema/SIL] Implement init accessors feature
- Adds a new kind of accessor - init accessor - which could be used to initialize one or more stored properties of the type. - Just like getter and setter accessors, init accessor could be used on any computed property. - Init accessors can specify a set of properties they initialize and accesses (property that should be initialized already) via declaration attributes - `initializes` and `accesses`; - Example of init accessor that initializes a stored property: ```swift public struct Test { private var _a: Int public var a: Int { init(initialValue) initializes(_a) { _a = initialValue } get { _a } set { _a = newValue } } } ``` - Modifies memberwise initializers to take advantage of this new mechanism by replacing one or more stored property parameters with corresponding init accessor(s). - `struct Test` from previous example would get `init(a: Int) { self.a = a }`. - Adds a new SIL instruction - `assign_or_init`; Similar to `assign_by_wrapper` the "mode" is set by DI based on each use site. - New intruction also tracks "assignments" - fields that have been previously initialized and would re-assigned by invocation of init accessor, it enables as to call init accessors multiple times even before all fields have been initializes. - When used in an initializer body, init accessor (i.e. `self.a = a`) call becomes either an initialization (if all of the fields haven't been initialized yet), or a call to setter.
1 parent 7a32caf commit 720b89d

File tree

79 files changed

+2828
-53
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+2828
-53
lines changed

include/swift/AST/AccessorKinds.def

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,14 @@
100100
ANY_ADDRESSOR(ID, KEYWORD)
101101
#endif
102102

103+
/// INIT_ACCESSOR(ID, KEYWORD)
104+
/// The given accessor is an init accessor.
105+
///
106+
/// Defaults to SINGLETON_ACCESSOR(ID, KEYWORD).
107+
#ifndef INIT_ACCESSOR
108+
#define INIT_ACCESSOR(ID, KEYWORD) SINGLETON_ACCESSOR(ID, KEYWORD)
109+
#endif
110+
103111
// Suppress entries for accessors which can't be written in source code.
104112
#ifndef SUPPRESS_ARTIFICIAL_ACCESSORS
105113
#define SUPPRESS_ARTIFICIAL_ACCESSORS 0
@@ -174,11 +182,16 @@ IMMUTABLE_ADDRESSOR(Address, unsafeAddress)
174182
/// of the type).
175183
MUTABLE_ADDRESSOR(MutableAddress, unsafeMutableAddress)
176184

185+
/// This is an init accessor: a function that is called when DI
186+
/// re-writes assignment to initialization.
187+
INIT_ACCESSOR(Init, init)
188+
177189
#ifdef LAST_ACCESSOR
178-
LAST_ACCESSOR(MutableAddress)
190+
LAST_ACCESSOR(Init)
179191
#undef LAST_ACCESSOR
180192
#endif
181193

194+
#undef INIT_ACCESSOR
182195
#undef IMMUTABLE_ADDRESSOR
183196
#undef MUTABLE_ADDRESSOR
184197
#undef ANY_ADDRESSOR

include/swift/AST/Attr.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class Decl;
5555
class AbstractFunctionDecl;
5656
class FuncDecl;
5757
class ClassDecl;
58+
class AccessorDecl;
5859
class GenericFunctionType;
5960
class LazyConformanceLoader;
6061
class LazyMemberLoader;
@@ -1530,6 +1531,68 @@ class SpecializeAttr final
15301531
}
15311532
};
15321533

1534+
class InitializesAttr final
1535+
: public DeclAttribute,
1536+
private llvm::TrailingObjects<InitializesAttr, Identifier> {
1537+
friend TrailingObjects;
1538+
1539+
size_t numProperties;
1540+
1541+
InitializesAttr(SourceLoc atLoc, SourceRange range,
1542+
ArrayRef<Identifier> properties);
1543+
1544+
public:
1545+
static InitializesAttr *create(ASTContext &ctx,
1546+
SourceLoc atLoc, SourceRange range,
1547+
ArrayRef<Identifier> properties);
1548+
1549+
size_t numTrailingObjects(OverloadToken<Identifier>) const {
1550+
return numProperties;
1551+
}
1552+
1553+
unsigned getNumProperties() const { return numProperties; }
1554+
1555+
ArrayRef<Identifier> getProperties() const {
1556+
return {getTrailingObjects<Identifier>(), numProperties};
1557+
}
1558+
1559+
ArrayRef<VarDecl *> getPropertyDecls(AccessorDecl *attachedTo) const;
1560+
1561+
static bool classof(const DeclAttribute *DA) {
1562+
return DA->getKind() == DAK_Initializes;
1563+
}
1564+
};
1565+
1566+
class AccessesAttr final
1567+
: public DeclAttribute,
1568+
private llvm::TrailingObjects<AccessesAttr, Identifier> {
1569+
friend TrailingObjects;
1570+
1571+
size_t numProperties;
1572+
1573+
AccessesAttr(SourceLoc atLoc, SourceRange range,
1574+
ArrayRef<Identifier> properties);
1575+
1576+
public:
1577+
static AccessesAttr *create(ASTContext &ctx,
1578+
SourceLoc atLoc, SourceRange range,
1579+
ArrayRef<Identifier> properties);
1580+
1581+
size_t numTrailingObjects(OverloadToken<Identifier>) const {
1582+
return numProperties;
1583+
}
1584+
1585+
ArrayRef<Identifier> getProperties() const {
1586+
return {getTrailingObjects<Identifier>(), numProperties};
1587+
}
1588+
1589+
ArrayRef<VarDecl *> getPropertyDecls(AccessorDecl *attachedTo) const;
1590+
1591+
static bool classof(const DeclAttribute *DA) {
1592+
return DA->getKind() == DAK_Accesses;
1593+
}
1594+
};
1595+
15331596
/// The @_implements attribute, which treats a decl as the implementation for
15341597
/// some named protocol requirement (but otherwise not-visible by that name).
15351598
class ImplementsAttr : public DeclAttribute {

include/swift/AST/Decl.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include "swift/Basic/Range.h"
4747
#include "llvm/ADT/DenseSet.h"
4848
#include "llvm/Support/TrailingObjects.h"
49+
#include <map>
4950
#include <type_traits>
5051

5152
namespace swift {
@@ -183,6 +184,7 @@ enum class DescriptiveDeclKind : uint8_t {
183184
DistributedMethod,
184185
Getter,
185186
Setter,
187+
InitAccessor,
186188
Addressor,
187189
MutableAddressor,
188190
ReadAccessor,
@@ -3979,6 +3981,16 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
39793981
/// Return a collection of the stored member variables of this type.
39803982
ArrayRef<VarDecl *> getStoredProperties() const;
39813983

3984+
/// Return a collection of all properties with init accessors in
3985+
/// this type.
3986+
ArrayRef<VarDecl *> getInitAccessorProperties() const;
3987+
3988+
/// Establish a mapping between properties that could be iniitalized
3989+
/// via other properties by means of init accessors. This mapping is
3990+
/// one-to-many because we allow intersecting `initializes(...)`.
3991+
void collectPropertiesInitializableByInitAccessors(
3992+
std::multimap<VarDecl *, VarDecl *> &result) const;
3993+
39823994
/// Return a collection of the stored member variables of this type, along
39833995
/// with placeholders for unimportable stored properties.
39843996
ArrayRef<Decl *> getStoredPropertiesAndMissingMemberPlaceholders() const;
@@ -7564,6 +7576,10 @@ class AccessorDecl final : public FuncDecl {
75647576
llvm_unreachable("bad accessor kind");
75657577
}
75667578

7579+
bool isInitAccessor() const {
7580+
return (getAccessorKind() == AccessorKind::Init);
7581+
}
7582+
75677583
/// \returns true if this is non-mutating due to applying a 'mutating'
75687584
/// attribute. For example a "mutating set" accessor.
75697585
bool isExplicitNonMutating() const;

include/swift/AST/DiagnosticsParse.def

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,9 @@ ERROR(observing_accessor_in_subscript,none,
309309
ERROR(getset_cannot_be_implied,none,
310310
"variable with implied type cannot have implied getter/setter", ())
311311

312+
ERROR(init_accessor_expected_name,none,
313+
"expected property name in init accessor effect", ())
314+
312315
// Import
313316
ERROR(decl_expected_module_name,none,
314317
"expected module name in import declaration", ())
@@ -2116,5 +2119,13 @@ ERROR(sil_markuncheckedreferencebinding_requires_attribute,none,
21162119
ERROR(sil_markuncheckedreferencebinding_invalid_attribute,none,
21172120
"Attribute '[%0]' can not be applied to mark_unchecked_reference_binding", (StringRef))
21182121

2122+
//------------------------------------------------------------------------------
2123+
// MARK: Init accessors
2124+
//------------------------------------------------------------------------------
2125+
2126+
ERROR(init_accessor_is_not_on_property,none,
2127+
"init accessors could only be associated with properties",
2128+
())
2129+
21192130
#define UNDEFINE_DIAGNOSTIC_MACROS
21202131
#include "DefineDiagnosticMacros.h"

include/swift/AST/DiagnosticsSIL.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ ERROR(ivar_not_initialized_at_superinit,none,
189189
ERROR(ivar_not_initialized_at_implicit_superinit,none,
190190
"property '%0' not initialized at implicitly generated super.init call",
191191
(StringRef, bool))
192+
ERROR(ivar_not_initialized_by_init_accessor,none,
193+
"property %0 not initialized by init accessor",
194+
(DeclName))
192195

193196
ERROR(self_use_before_fully_init,none,
194197
"'self' used in %select{method call|property access}1 %0 before "

include/swift/AST/DiagnosticsSema.def

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5807,6 +5807,8 @@ ERROR(no_opaque_return_type_of,none,
58075807

58085808
ERROR(objc_observing_accessor, none,
58095809
"observing accessors are not allowed to be marked @objc", ())
5810+
ERROR(objc_init_accessor, none,
5811+
"init accessors cannot be marked @objc", ())
58105812
ERROR(objc_addressor, none,
58115813
"addressors are not allowed to be marked @objc", ())
58125814
ERROR(objc_coroutine_accessor, none,
@@ -7226,6 +7228,25 @@ NOTE(opt_out_from_missing_reflection_metadata_attr,none,
72267228
" unavailable extension",
72277229
(StringRef))
72287230

7231+
//------------------------------------------------------------------------------
7232+
// MARK: Init accessors
7233+
//------------------------------------------------------------------------------
7234+
7235+
ERROR(init_accessor_can_refer_only_to_properties,none,
7236+
"init accessor cannot refer to %0 %1; init accessors can refer only"
7237+
" to stored properties",
7238+
(DescriptiveDeclKind, DeclNameRef))
7239+
7240+
ERROR(init_accessor_initializes_attribute_on_other_declaration,none,
7241+
"initalizes(...) attribute could only be used with init accessors",
7242+
())
7243+
ERROR(init_accessor_accesses_attribute_on_other_declaration,none,
7244+
"accesses(...) attribute could only be used with init accessors",
7245+
())
7246+
ERROR(init_accessor_property_both_init_and_accessed,none,
7247+
"property %0 cannot be both initialized and accessed",
7248+
(DeclName))
7249+
72297250

72307251
#define UNDEFINE_DIAGNOSTIC_MACROS
72317252
#include "DefineDiagnosticMacros.h"

include/swift/AST/TypeCheckRequests.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,25 @@ class StoredPropertiesAndMissingMembersRequest :
16711671
bool isCached() const { return true; }
16721672
};
16731673

1674+
/// Request to obtain a list of computed properties with init accesors
1675+
/// in the given nominal type.
1676+
class InitAccessorPropertiesRequest :
1677+
public SimpleRequest<InitAccessorPropertiesRequest,
1678+
ArrayRef<VarDecl *>(NominalTypeDecl *),
1679+
RequestFlags::Cached> {
1680+
public:
1681+
using SimpleRequest::SimpleRequest;
1682+
1683+
private:
1684+
friend SimpleRequest;
1685+
1686+
ArrayRef<VarDecl *>
1687+
evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const;
1688+
1689+
public:
1690+
bool isCached() const { return true; }
1691+
};
1692+
16741693
class StorageImplInfoRequest :
16751694
public SimpleRequest<StorageImplInfoRequest,
16761695
StorageImplInfo(AbstractStorageDecl *),
@@ -4274,6 +4293,25 @@ class IsNonUserModuleRequest
42744293
bool isCached() const { return true; }
42754294
};
42764295

4296+
class InitAccessorReferencedVariablesRequest
4297+
: public SimpleRequest<InitAccessorReferencedVariablesRequest,
4298+
ArrayRef<VarDecl *>(DeclAttribute *, AccessorDecl *,
4299+
ArrayRef<Identifier>),
4300+
RequestFlags::Cached> {
4301+
public:
4302+
using SimpleRequest::SimpleRequest;
4303+
4304+
private:
4305+
friend SimpleRequest;
4306+
4307+
ArrayRef<VarDecl *> evaluate(Evaluator &evaluator, DeclAttribute *attr,
4308+
AccessorDecl *attachedTo,
4309+
ArrayRef<Identifier>) const;
4310+
4311+
public:
4312+
bool isCached() const { return true; }
4313+
};
4314+
42774315
#define SWIFT_TYPEID_ZONE TypeChecker
42784316
#define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def"
42794317
#include "swift/Basic/DefineTypeIDZone.h"

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,9 @@ SWIFT_REQUEST(TypeChecker, StoredPropertiesAndMissingMembersRequest,
306306
ArrayRef<Decl *>(NominalTypeDecl *), Cached, NoLocationInfo)
307307
SWIFT_REQUEST(TypeChecker, StoredPropertiesRequest,
308308
ArrayRef<VarDecl *>(NominalTypeDecl *), Cached, NoLocationInfo)
309+
SWIFT_REQUEST(TypeChecker, InitAccessorPropertiesRequest,
310+
ArrayRef<VarDecl *>(NominalTypeDecl *),
311+
Cached, NoLocationInfo)
309312
SWIFT_REQUEST(TypeChecker, StructuralTypeRequest, Type(TypeAliasDecl *), Cached,
310313
NoLocationInfo)
311314
SWIFT_REQUEST(TypeChecker, SuperclassTypeRequest,
@@ -481,3 +484,7 @@ SWIFT_REQUEST(TypeChecker, IsNonUserModuleRequest,
481484
SWIFT_REQUEST(TypeChecker, TypeCheckObjCImplementationRequest,
482485
unsigned(ExtensionDecl *),
483486
Cached, NoLocationInfo)
487+
SWIFT_REQUEST(TypeChecker, InitAccessorReferencedVariablesRequest,
488+
ArrayRef<VarDecl *>(DeclAttribute *, AccessorDecl *,
489+
ArrayRef<Identifier>),
490+
Cached, NoLocationInfo)

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ EXPERIMENTAL_FEATURE(NamedOpaqueTypes, false)
119119
EXPERIMENTAL_FEATURE(FlowSensitiveConcurrencyCaptures, false)
120120
EXPERIMENTAL_FEATURE(CodeItemMacros, true)
121121
EXPERIMENTAL_FEATURE(TupleConformances, false)
122+
EXPERIMENTAL_FEATURE(InitAccessors, false)
122123

123124
// FIXME: MoveOnlyClasses is not intended to be in production,
124125
// but our tests currently rely on it, and we want to run those

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ NODE(ImplErrorResult)
143143
NODE(InOut)
144144
NODE(InfixOperator)
145145
CONTEXT_NODE(Initializer)
146+
CONTEXT_NODE(InitAccessor)
146147
NODE(Isolated)
147148
NODE(KeyPathGetterThunkHelper)
148149
NODE(KeyPathSetterThunkHelper)

include/swift/Parse/Parser.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,6 +1265,10 @@ class Parser {
12651265
AccessorKind currentKind,
12661266
SourceLoc const& currentLoc);
12671267

1268+
ParserStatus parseInitAccessorEffects(ParsedAccessors &accessors,
1269+
AccessorKind currentKind,
1270+
DeclAttributes &Attributes);
1271+
12681272
/// Parse accessors provided as a separate list, for use in macro
12691273
/// expansions.
12701274
void parseTopLevelAccessors(

include/swift/SIL/InstructionUtils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ SILValue isPartialApplyOfReabstractionThunk(PartialApplyInst *PAI);
145145
/// init or set function.
146146
bool onlyUsedByAssignByWrapper(PartialApplyInst *PAI);
147147

148+
/// Returns true if \p PAI is only used by an \c assign_or_init
149+
/// instruction as init or set function.
150+
bool onlyUsedByAssignOrInit(PartialApplyInst *PAI);
151+
148152
/// Returns the runtime effects of \p inst.
149153
///
150154
/// Predicts which runtime calls are called in the generated code for `inst`.

include/swift/SIL/SILBuilder.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,14 @@ class SILBuilder {
955955
getSILDebugLocation(Loc), Src, Dest, Initializer, Setter, mode));
956956
}
957957

958+
AssignOrInitInst *createAssignOrInit(SILLocation Loc, SILValue Src,
959+
SILValue Initializer,
960+
SILValue Setter,
961+
AssignOrInitInst::Mode Mode) {
962+
return insert(new (getModule()) AssignOrInitInst(
963+
getSILDebugLocation(Loc), Src, Initializer, Setter, Mode));
964+
}
965+
958966
StoreBorrowInst *createStoreBorrow(SILLocation Loc, SILValue Src,
959967
SILValue DestAddr) {
960968
return insert(new (getModule())
@@ -1009,7 +1017,11 @@ class SILBuilder {
10091017
SILValue src) {
10101018
return createMarkUninitialized(Loc, src, MarkUninitializedInst::RootSelf);
10111019
}
1012-
1020+
MarkUninitializedInst *createMarkUninitializedOut(SILLocation Loc,
1021+
SILValue src) {
1022+
return createMarkUninitialized(Loc, src, MarkUninitializedInst::Out);
1023+
}
1024+
10131025
MarkFunctionEscapeInst *createMarkFunctionEscape(SILLocation Loc,
10141026
ArrayRef<SILValue> vars) {
10151027
return insert(

include/swift/SIL/SILCloner.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,6 +1353,17 @@ void SILCloner<ImplClass>::visitAssignByWrapperInst(AssignByWrapperInst *Inst) {
13531353
getOpValue(Inst->getSetter()), Inst->getMode()));
13541354
}
13551355

1356+
template <typename ImplClass>
1357+
void SILCloner<ImplClass>::visitAssignOrInitInst(AssignOrInitInst *Inst) {
1358+
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1359+
recordClonedInstruction(
1360+
Inst, getBuilder().createAssignOrInit(
1361+
getOpLocation(Inst->getLoc()),
1362+
getOpValue(Inst->getSrc()),
1363+
getOpValue(Inst->getInitializer()),
1364+
getOpValue(Inst->getSetter()), Inst->getMode()));
1365+
}
1366+
13561367
template<typename ImplClass>
13571368
void
13581369
SILCloner<ImplClass>::visitMarkUninitializedInst(MarkUninitializedInst *Inst) {

include/swift/SIL/SILDeclRef.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,9 @@ struct SILDeclRef {
382382
return kind == Kind::Initializer || kind == Kind::Destroyer;
383383
}
384384

385+
/// True if the SILDeclRef references an init accessor declaration.
386+
bool isInitAccessor() const;
387+
385388
/// True if the function should be treated as transparent.
386389
bool isTransparent() const;
387390
/// True if the function should have its body serialized.

0 commit comments

Comments
 (0)