Skip to content

Property delegates as custom attributes #23701

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f9c716d
Add support for the @propertyDelegate attribute.
DougGregor Mar 31, 2019
96279c7
Use custom attributes to apply property delegates to variables.
DougGregor Apr 1, 2019
53b9e25
Implement initialization of properties with attached delegates.
DougGregor Apr 1, 2019
9c62420
[AST] Generalize PatternBindingEntry's "Lazy" flag to "Subsumed"
DougGregor Mar 20, 2019
32b0245
[Parser] Consistently use consumeIdentifier() for normal identifiers.
DougGregor Mar 22, 2019
7f293f6
[Parser] Allow use of $ declarations in all modes.
DougGregor Mar 22, 2019
b8061ea
Synthesize backing storage property for properties with attached dele…
DougGregor Apr 3, 2019
b18a290
Implement access control for property delegates
DougGregor Apr 3, 2019
6526cfa
Memberwise initializer synthesis for properties with attached delegates.
DougGregor Apr 4, 2019
198751e
Improve test for nonmutating due to a reference-type delegate
DougGregor Apr 5, 2019
cc68b12
[SILGen] Initialization of instance properties with property delegates
DougGregor Apr 11, 2019
9e22400
Add missing header file
DougGregor Apr 11, 2019
2e01b0e
SIL: add assign_by_delegate instruction
eeckstein Apr 4, 2019
86fb74a
DI: support assign_by_delegate instruction
eeckstein Apr 4, 2019
24e28ca
Fix an assert in AccessEnformentSelections to support assign_by_delegate
eeckstein Apr 4, 2019
e167423
RawSILInstLowering: lower assign_by_delegate
eeckstein Apr 4, 2019
573a82b
SILGen: generate assign_by_delegate for property delegates
eeckstein Apr 4, 2019
4f56db2
[Property delegates] Implement support for storageValue
DougGregor Apr 13, 2019
f187d92
[Type checker] Don't allow a 'let' to have a property delegate.
DougGregor Apr 13, 2019
03704fc
[Definite initialization] Avoid performing DI via nonmutating setters.
DougGregor Apr 13, 2019
03f6740
Eliminate a use-after-free in assign_by_delegate lowering.
DougGregor Apr 15, 2019
2e9f8cf
Capture a placeholder opaque value expression when needed.
DougGregor Apr 15, 2019
261b879
[Property delegates] Rename storageValue to delegateValue
DougGregor Apr 15, 2019
7df6955
[Property delegates] Fix printing of memberwise initializer default a…
DougGregor Apr 16, 2019
99d4e80
[Index] Handle memberwise initializers with defaulted arguments.
DougGregor Apr 16, 2019
fcd2fd9
[Property delegates] Don't create backing var for ill-formed delegate…
DougGregor Apr 18, 2019
56d450b
[Property delegates] Contextualize direct initializers of custom attr…
DougGregor Apr 23, 2019
7ace136
ASTWalker support for custom attributes on properties.
DougGregor Apr 23, 2019
faa176f
Record and walk the semantic initializer for a custom attribute.
DougGregor Apr 23, 2019
6218673
[Property delegates] Use $$foo for the backing storage and make it pr…
DougGregor Apr 24, 2019
0c26e43
Underscore the @propertyDelegate attribute to indicate that it's expe…
DougGregor Apr 25, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2333,6 +2333,32 @@ with a sequence that also correctly destroys the current value.
This instruction is only valid in Raw SIL and is rewritten as appropriate
by the definitive initialization pass.

assign_by_delegate
``````````````````
::

sil-instruction ::= 'assign_by_delegate' sil-operand 'to' sil-operand ',' 'init' sil-operand ',' 'set' sil-operand

assign_by_delegate %0 : $S to %1 : $*T, init %2 : $F, set %3 : $G
// $S can be a value or address type
// $T must be the type of a property delegate.
// $F must be a function type, taking $S as a single argument and returning $T
// $G must be a function type, taking $S as a single argument and with not return value

Similar to the ``assign`` instruction, but the assignment is done via a
delegate.

In case of an initialization, the function ``%2`` is called with ``%0`` as
argument. The result is stored to ``%1``. In case ``%2`` is an address type,
it is simply passed as a first out-argument to ``%2``.

In case of a re-assignment, the function ``%3`` is called with ``%0`` as
argument. As ``%3`` is a setter (e.g. for the property in the containing
nominal type), the destination address ``%1`` is not used in this case.

This instruction is only valid in Raw SIL and is rewritten as appropriate
by the definitive initialization pass.

mark_uninitialized
``````````````````
::
Expand Down
7 changes: 7 additions & 0 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,13 @@ class ASTContext final {
const IterableDeclContext *idc,
LazyMemberLoader *lazyLoader);

/// Access the side cache for property delegate backing property types,
/// used because TypeChecker::typeCheckBinding() needs somewhere to stash
/// the backing property type.
Type getSideCachedPropertyDelegateBackingPropertyType(VarDecl *var) const;
void setSideCachedPropertyDelegateBackingPropertyType(VarDecl *var,
Type type);

/// Returns memory usage of this ASTContext.
size_t getTotalMemory() const;

Expand Down
5 changes: 4 additions & 1 deletion include/swift/AST/ASTTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@
//===----------------------------------------------------------------------===//
SWIFT_TYPEID_NAMED(NominalTypeDecl *, NominalTypeDecl)
SWIFT_TYPEID_NAMED(VarDecl *, VarDecl)
SWIFT_TYPEID(PropertyBehaviorTypeInfo)
SWIFT_TYPEID(Type)
SWIFT_TYPEID(PropertyDelegateBackingPropertyInfo)
SWIFT_TYPEID(PropertyDelegateTypeInfo)
SWIFT_TYPEID_NAMED(CustomAttr *, CustomAttr)
5 changes: 4 additions & 1 deletion include/swift/AST/ASTTypeIDs.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@
#include "swift/Basic/TypeID.h"
namespace swift {

class CustomAttr;
class NominalTypeDecl;
struct PropertyBehaviorTypeInfo;
struct PropertyDelegateBackingPropertyInfo;
struct PropertyDelegateTypeInfo;
class Type;
class VarDecl;

#define SWIFT_AST_TYPEID_ZONE 1
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,9 @@ SIMPLE_DECL_ATTR(_implementationOnly, ImplementationOnly,
DECL_ATTR(_custom, Custom,
OnAnyDecl | UserInaccessible,
85)
SIMPLE_DECL_ATTR(_propertyDelegate, PropertyDelegate,
OnStruct | OnClass | OnEnum,
86)

#undef TYPE_ATTR
#undef DECL_ATTR_ALIAS
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1428,6 +1428,7 @@ class CustomAttr final : public DeclAttribute,
TypeLoc type;
Expr *arg;
PatternBindingInitializer *initContext;
Expr *semanticInit = nullptr;

unsigned hasArgLabelLocs : 1;
unsigned numArgLabels : 16;
Expand Down Expand Up @@ -1463,6 +1464,9 @@ class CustomAttr final : public DeclAttribute,
Expr *getArg() const { return arg; }
void setArg(Expr *newArg) { arg = newArg; }

Expr *getSemanticInit() const { return semanticInit; }
void setSemanticInit(Expr *expr) { semanticInit = expr; }

PatternBindingInitializer *getInitContext() const { return initContext; }

static bool classof(const DeclAttribute *DA) {
Expand Down
49 changes: 40 additions & 9 deletions include/swift/AST/CaptureInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "swift/AST/TypeAlignments.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
#include <vector>

namespace swift {
Expand All @@ -31,13 +32,20 @@ template <> struct DenseMapInfo<swift::CapturedValue>;
namespace swift {
class ValueDecl;
class FuncDecl;
class OpaqueValueExpr;

/// CapturedValue includes both the declaration being captured, along with flags
/// that indicate how it is captured.
class CapturedValue {
llvm::PointerIntPair<ValueDecl*, 2, unsigned> Value;
public:
using Storage =
llvm::PointerIntPair<llvm::PointerUnion<ValueDecl*, OpaqueValueExpr*>, 2,
unsigned>;

private:
Storage Value;

explicit CapturedValue(llvm::PointerIntPair<ValueDecl*, 2, unsigned> V) : Value(V) {}
explicit CapturedValue(Storage V) : Value(V) {}

public:
friend struct llvm::DenseMapInfo<CapturedValue>;
Expand All @@ -53,16 +61,21 @@ class CapturedValue {
IsNoEscape = 1 << 1
};

CapturedValue(ValueDecl *D, unsigned Flags) : Value(D, Flags) {}
CapturedValue(llvm::PointerUnion<ValueDecl*, OpaqueValueExpr*> Ptr,
unsigned Flags)
: Value(Ptr, Flags) {}

static CapturedValue getDynamicSelfMetadata() {
return CapturedValue(nullptr, 0);
return CapturedValue((ValueDecl *)nullptr, 0);
}

bool isDirect() const { return Value.getInt() & IsDirect; }
bool isNoEscape() const { return Value.getInt() & IsNoEscape; }

bool isDynamicSelfMetadata() const { return !Value.getPointer(); }
bool isOpaqueValue() const {
return Value.getPointer().is<OpaqueValueExpr *>();
}

CapturedValue mergeFlags(CapturedValue cv) {
assert(Value.getPointer() == cv.Value.getPointer() &&
Expand All @@ -73,7 +86,13 @@ class CapturedValue {
ValueDecl *getDecl() const {
assert(Value.getPointer() && "dynamic Self metadata capture does not "
"have a value");
return Value.getPointer();
return Value.getPointer().dyn_cast<ValueDecl *>();
}

OpaqueValueExpr *getOpaqueValue() const {
assert(Value.getPointer() && "dynamic Self metadata capture does not "
"have a value");
return Value.getPointer().dyn_cast<OpaqueValueExpr *>();
}

unsigned getFlags() const { return Value.getInt(); }
Expand All @@ -98,8 +117,7 @@ namespace llvm {
template <> struct DenseMapInfo<swift::CapturedValue> {
using CapturedValue = swift::CapturedValue;

using PtrIntPairDenseMapInfo =
DenseMapInfo<llvm::PointerIntPair<swift::ValueDecl *, 2, unsigned>>;
using PtrIntPairDenseMapInfo = DenseMapInfo<CapturedValue::Storage>;

static inline swift::CapturedValue getEmptyKey() {
return CapturedValue{PtrIntPairDenseMapInfo::getEmptyKey()};
Expand Down Expand Up @@ -128,19 +146,20 @@ class DynamicSelfType;
class CaptureInfo {
const CapturedValue *Captures;
DynamicSelfType *DynamicSelf;
OpaqueValueExpr *OpaqueValue;
unsigned Count = 0;
bool GenericParamCaptures : 1;
bool Computed : 1;

public:
CaptureInfo()
: Captures(nullptr), DynamicSelf(nullptr), Count(0),
: Captures(nullptr), DynamicSelf(nullptr), OpaqueValue(nullptr), Count(0),
GenericParamCaptures(0), Computed(0) { }

bool hasBeenComputed() { return Computed; }

bool isTrivial() {
return Count == 0 && !GenericParamCaptures && !DynamicSelf;
return Count == 0 && !GenericParamCaptures && !DynamicSelf && !OpaqueValue;
}

ArrayRef<CapturedValue> getCaptures() const {
Expand Down Expand Up @@ -184,6 +203,18 @@ class CaptureInfo {
DynamicSelf = dynamicSelf;
}

bool hasOpaqueValueCapture() const {
return OpaqueValue != nullptr;
}

OpaqueValueExpr *getOpaqueValue() const {
return OpaqueValue;
}

void setOpaqueValue(OpaqueValueExpr *OVE) {
OpaqueValue = OVE;
}

void dump() const;
void print(raw_ostream &OS) const;
};
Expand Down
Loading