Skip to content
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

[WIP] Property delegates #23440

Closed
wants to merge 46 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
9a1a9e8
[Parse] Parsing and basic AST representation for property behaviors.
DougGregor Mar 9, 2019
0661d1b
[Type checker] Apply property behavior to the storage type of a varia…
DougGregor Mar 10, 2019
49862d4
[WIP] Create backing storage for property behaviors.
DougGregor Mar 17, 2019
bc75807
[Property behaviors] Side-allocate attached property behaviors.
DougGregor Mar 19, 2019
8b6f21c
[Property behaviors] Improve discovery of property behavior types.
DougGregor Mar 20, 2019
757091e
[Property behaviors] Add the @propertyBehavior attribute.
DougGregor Mar 20, 2019
8fbc169
[Property behaviors] Consistently check properties with behaviors.
DougGregor Mar 20, 2019
c503352
Rename "Property Behaviors" to "Property Delegates".
DougGregor Mar 20, 2019
9c5449a
[Property delegates] Implement support for init(initialValue:).
DougGregor Mar 20, 2019
f04f4a2
[Property delegates] Support direct initialization of property delega…
DougGregor Mar 20, 2019
b465ed3
Update IDE test output for @propertyDelegate attribute.
DougGregor Mar 20, 2019
37bcc5c
Add missing header file.
DougGregor Mar 20, 2019
23b9a11
[AST] Generalize PatternBindingEntry's "Lazy" flag to "Subsumed"
DougGregor Mar 20, 2019
7eff6f7
[Property delegates] Associate initializer with the backing storage p…
DougGregor Mar 20, 2019
c354b78
[Property behaviors] Adjust memberwise initializer type.
DougGregor Mar 21, 2019
d927663
[Property delegates] Suppress default inits when appropriate.
DougGregor Mar 21, 2019
e674377
[Property delegates] SILGen support for memberwise initializers of st…
DougGregor Mar 22, 2019
7840527
[Parser] Consistently use consumeIdentifier() for normal identifiers.
DougGregor Mar 22, 2019
ef09e4e
[Parser] Allow use of $ declarations in all modes.
DougGregor Mar 22, 2019
41985d2
[Property delegates] Support nested property delegates
DougGregor Mar 22, 2019
bd13ddd
[Property delegates] Fix SILGen for directly-formed structs.
DougGregor Mar 22, 2019
56e0742
[Property delegates] Check access of the property behavior type.
DougGregor Mar 23, 2019
2538425
[Property delegates] Allow the backing property access to be specified.
DougGregor Mar 23, 2019
5113aaf
[Property delegates] The access for the delegate type is based on the…
DougGregor Mar 23, 2019
7cd6b37
[Property delegates] Adjust memberwise initializer access level.
DougGregor Mar 23, 2019
e3e17c4
[Property delegates] (De-)serialize delegates of properties.
DougGregor Mar 23, 2019
19abc3c
[Property delegates] Print delegate attached to properties when needed.
DougGregor Mar 24, 2019
d9ca581
[Property delegates] Walk the property delegate type in ASTWalker.
DougGregor Mar 24, 2019
a17ff53
[Property delegates] Don't contextualize property initializer twice.
DougGregor Mar 25, 2019
789dad4
[Property delegates] Diagnose protocol/enum/extension restrictions.
DougGregor Mar 25, 2019
fb8c6a6
[Property delegates] Diagnose final/override restrictions on properties.
DougGregor Mar 25, 2019
513aa6d
[Property delegates] Diagnose conflicting attributes/modifiers.
DougGregor Mar 25, 2019
f6c8a82
[Property delegate] A property with a delegate may not declare access…
DougGregor Mar 25, 2019
05b6db7
[Type checker] Don't complain about missing 'override' that we deleted.
DougGregor Mar 25, 2019
c6e530a
Remove now-obsolete -verify-sil-ownership flag
DougGregor Mar 26, 2019
1adb066
[Property delegates] Allow explicit get/set in a property with a dele…
DougGregor Mar 26, 2019
9848419
[Property delegates] Disable default arguments for the memberwise ini…
DougGregor Mar 26, 2019
4bfb212
[Property delegates] Clean up & test handling of mutating/nonmutating.
DougGregor Mar 26, 2019
9017c7e
[Property delegates] Don't implicitly reference a private(set) 'value'.
DougGregor Mar 27, 2019
78e8a36
[Property delegates] Diagnose too-restrictive 'value' and 'init(initi…
DougGregor Mar 27, 2019
00d6964
[Property delegates] Model delegate backing storage access as a “target”
DougGregor Mar 27, 2019
32430ec
[Property delegates] Support didSet/willSet.
DougGregor Mar 27, 2019
43b3c59
Move simple_display(... PropertyDelegateTypeInfo ...) into libswiftAST.
DougGregor Mar 27, 2019
4feb812
[Property delegates] Reject delegates on local properties.
DougGregor Mar 28, 2019
23a76d4
[Experimental] Parse custom attributes that can refer to property del…
DougGregor Mar 29, 2019
4107789
Restrict custom attributes to those that start with an uppercase letter
DougGregor Mar 29, 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
19 changes: 19 additions & 0 deletions include/swift/AST/ASTTypeIDZone.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//===--- ASTTypeIDZone.def - Define the AST TypeID Zone ---------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This definition file describes the types in the "AST" TypeID zone,
// for use with the TypeID template.
//
//===----------------------------------------------------------------------===//
SWIFT_TYPEID_NAMED(NominalTypeDecl *, NominalTypeDecl)
SWIFT_TYPEID_NAMED(VarDecl *, VarDecl)
SWIFT_TYPEID(PropertyDelegateTypeInfo)
36 changes: 36 additions & 0 deletions include/swift/AST/ASTTypeIDs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===--- ASTTypeIDs.h - AST Type Ids ----------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines TypeID support for AST types.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_AST_ASTTYPEIDS_H
#define SWIFT_AST_ASTTYPEIDS_H

#include "swift/Basic/TypeID.h"
namespace swift {

class NominalTypeDecl;
struct PropertyDelegateTypeInfo;
class VarDecl;

#define SWIFT_AST_TYPEID_ZONE 1

// Define the AST type zone (zone 1)
#define SWIFT_TYPEID_ZONE SWIFT_AST_TYPEID_ZONE
#define SWIFT_TYPEID_HEADER "swift/AST/ASTTypeIDZone.def"
#include "swift/Basic/DefineTypeIDZone.h"

} // end namespace swift

#endif /* SWIFT_AST_ASTTYPEIDS_H */
6 changes: 6 additions & 0 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,12 @@ DECL_ATTR(_private, PrivateImport,
SIMPLE_DECL_ATTR(_alwaysEmitIntoClient, AlwaysEmitIntoClient,
OnVar | OnSubscript | OnAbstractFunction | UserInaccessible,
83)
SIMPLE_DECL_ATTR(propertyDelegate, PropertyDelegate,
OnStruct | OnClass | OnEnum,
84)
DECL_ATTR(_custom, Custom,
OnAnyDecl | UserInaccessible,
85)

#undef TYPE_ATTR
#undef DECL_ATTR_ALIAS
Expand Down
52 changes: 52 additions & 0 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "swift/AST/Ownership.h"
#include "swift/AST/PlatformKind.h"
#include "swift/AST/Requirement.h"
#include "swift/AST/TrailingCallArguments.h"
#include "swift/AST/TypeLoc.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
Expand All @@ -49,6 +50,7 @@ class FuncDecl;
class ClassDecl;
class GenericFunctionType;
class LazyConformanceLoader;
class PatternBindingInitializer;
class TrailingWhereClause;

/// TypeAttributes - These are attributes that may be applied to types.
Expand Down Expand Up @@ -1408,6 +1410,54 @@ class ClangImporterSynthesizedTypeAttr : public DeclAttribute {
}
};

/// Defines a custom attribute.
class CustomAttr final : public DeclAttribute,
public TrailingCallArguments<CustomAttr> {
TypeLoc type;
Expr *arg;
PatternBindingInitializer *initContext;

unsigned hasArgLabelLocs : 1;
unsigned numArgLabels : 16;

CustomAttr(SourceLoc atLoc, SourceRange range, TypeLoc type,
PatternBindingInitializer *initContext, Expr *arg,
ArrayRef<Identifier> argLabels, ArrayRef<SourceLoc> argLabelLocs,
bool implicit);

public:
static CustomAttr *create(ASTContext &ctx, SourceLoc atLoc, TypeLoc type,
bool implicit = false) {
return create(ctx, atLoc, type, false, nullptr, SourceLoc(), { }, { }, { },
SourceLoc(), implicit);
}

static CustomAttr *create(ASTContext &ctx, SourceLoc atLoc, TypeLoc type,
bool hasInitializer,
PatternBindingInitializer *initContext,
SourceLoc lParenLoc,
ArrayRef<Expr *> args,
ArrayRef<Identifier> argLabels,
ArrayRef<SourceLoc> argLabelLocs,
SourceLoc rParenLoc,
bool implicit = false);

unsigned getNumArguments() const { return numArgLabels; }
bool hasArgumentLabelLocs() const { return hasArgLabelLocs; }

TypeLoc &getTypeLoc() { return type; }
const TypeLoc &getTypeLoc() const { return type; }

Expr *getArg() const { return arg; }
void setArg(Expr *newArg) { arg = newArg; }

PatternBindingInitializer *getInitContext() const { return initContext; }

static bool classof(const DeclAttribute *DA) {
return DA->getKind() == DAK_Custom;
}
};

/// Attributes that may be applied to declarations.
class DeclAttributes {
/// Linked list of declaration attributes.
Expand Down Expand Up @@ -1584,6 +1634,8 @@ class DeclAttributes {
SourceLoc getStartLoc(bool forModifiers = false) const;
};

void simple_display(llvm::raw_ostream &out, const DeclAttribute *attr);

} // end namespace swift

#endif
111 changes: 91 additions & 20 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ class alignas(1 << DeclAlignInBits) Decl {
ValidKeyPathComponent : 1
);

SWIFT_INLINE_BITFIELD(VarDecl, AbstractStorageDecl, 1+4+1+1+1+1,
SWIFT_INLINE_BITFIELD(VarDecl, AbstractStorageDecl, 1+4+1+1+1+1+1+1,
/// Whether this property is a type property (currently unfortunately
/// called 'static').
IsStatic : 1,
Expand All @@ -379,7 +379,13 @@ class alignas(1 << DeclAlignInBits) Decl {

/// Whether this is a property defined in the debugger's REPL.
/// FIXME: Remove this once LLDB has proper support for resilience.
IsREPLVar : 1
IsREPLVar : 1,

/// Whether this property has an associated property delegate.
HasPropertyDelegate : 1,

/// Whether this is the backing storage for a property delegate.
IsPropertyDelegateBackingProperty : 1
);

SWIFT_INLINE_BITFIELD(ParamDecl, VarDecl, 1 + NumDefaultArgumentKindBits,
Expand Down Expand Up @@ -1887,15 +1893,21 @@ class PatternBindingEntry {
enum class Flags {
Checked = 1 << 0,
Removed = 1 << 1,
Lazy = 1 << 2
/// Whether the contents of this initializer were subsumed by
/// some other initialization, e.g., a lazy property's initializer
/// gets subsumed by the getter body.
Subsumed = 1 << 2
};
llvm::PointerIntPair<Pattern *, 3, OptionSet<Flags>> PatternAndFlags;

struct ExprAndEqualLoc {
// When the initializer is removed we don't actually clear the pointer
// because we might need to get initializer's source range. Since the
// initializer is ASTContext-allocated it is safe.
Expr *Node;
//
// The bit indicates whether the initializer is for an attached property
// delegate.
llvm::PointerIntPair<Expr *, 1, bool> NodeAndPropertyDelegateInit;
/// The location of the equal '=' token.
SourceLoc EqualLoc;
};
Expand All @@ -1915,8 +1927,10 @@ class PatternBindingEntry {

public:
PatternBindingEntry(Pattern *P, SourceLoc EqualLoc, Expr *E,
bool InitIsPropertyDelegateInit,
DeclContext *InitContext)
: PatternAndFlags(P, {}), InitExpr({E, EqualLoc}),
: PatternAndFlags(P, {}),
InitExpr({{E, InitIsPropertyDelegateInit}, EqualLoc}),
InitContextAndIsText({InitContext, false}) {
}

Expand All @@ -1926,13 +1940,21 @@ class PatternBindingEntry {
if (PatternAndFlags.getInt().contains(Flags::Removed) ||
InitContextAndIsText.getInt())
return nullptr;
return InitExpr.Node;
return InitExpr.NodeAndPropertyDelegateInit.getPointer();
}
bool isPropertyDelegateInit() const {
return InitExpr.NodeAndPropertyDelegateInit.getInt();
}
Expr *getNonLazyInit() const {
return isInitializerLazy() ? nullptr : getInit();
/// Retrieve the initializer if it should be executed to initialize this
/// particular pattern binding.
Expr *getExecutableInit() const {
return isInitializerSubsumed() ? nullptr : getInit();
}
SourceRange getOrigInitRange() const;
void setInit(Expr *E);
void setIsPropertyDelegateInit(bool isPropertyDelegateInit) {
InitExpr.NodeAndPropertyDelegateInit.setInt(isPropertyDelegateInit);
}

/// Gets the text of the initializer expression, stripping out inactive
/// branches of any #ifs inside the expression.
Expand Down Expand Up @@ -1963,7 +1985,9 @@ class PatternBindingEntry {

/// Retrieve the initializer as it was written in the source.
Expr *getInitAsWritten() const {
return InitContextAndIsText.getInt() ? nullptr : InitExpr.Node;
return InitContextAndIsText.getInt()
? nullptr
: InitExpr.NodeAndPropertyDelegateInit.getPointer();
}

bool isInitializerChecked() const {
Expand All @@ -1973,11 +1997,11 @@ class PatternBindingEntry {
PatternAndFlags.setInt(PatternAndFlags.getInt() | Flags::Checked);
}

bool isInitializerLazy() const {
return PatternAndFlags.getInt().contains(Flags::Lazy);
bool isInitializerSubsumed() const {
return PatternAndFlags.getInt().contains(Flags::Subsumed);
}
void setInitializerLazy() {
PatternAndFlags.setInt(PatternAndFlags.getInt() | Flags::Lazy);
void setInitializerSubsumed() {
PatternAndFlags.setInt(PatternAndFlags.getInt() | Flags::Subsumed);
}

// Return the first variable initialized by this pattern.
Expand Down Expand Up @@ -2036,6 +2060,7 @@ class PatternBindingDecl final : public Decl,
StaticSpellingKind StaticSpelling,
SourceLoc VarLoc, Pattern *Pat,
SourceLoc EqualLoc, Expr *E,
bool IsPropertyDelegateInit,
DeclContext *Parent);

static PatternBindingDecl *createImplicit(ASTContext &Ctx,
Expand Down Expand Up @@ -2072,10 +2097,13 @@ class PatternBindingDecl final : public Decl,
Expr *getInit(unsigned i) const {
return getPatternList()[i].getInit();
}
Expr *getNonLazyInit(unsigned i) const {
return getPatternList()[i].getNonLazyInit();
Expr *getExecutableInit(unsigned i) const {
return getPatternList()[i].getExecutableInit();
}

bool isPropertyDelegateInit(unsigned i) const {
return getPatternList()[i].isPropertyDelegateInit();
}

SourceRange getOrigInitRange(unsigned i) const {
return getPatternList()[i].getOrigInitRange();
}
Expand Down Expand Up @@ -2114,12 +2142,12 @@ class PatternBindingDecl final : public Decl,
getMutablePatternList()[i].setInitializerChecked();
}

bool isInitializerLazy(unsigned i) const {
return getPatternList()[i].isInitializerLazy();
bool isInitializerSubsumed(unsigned i) const {
return getPatternList()[i].isInitializerSubsumed();
}

void setInitializerLazy(unsigned i) {
getMutablePatternList()[i].setInitializerLazy();
void setInitializerSubsumed(unsigned i) {
getMutablePatternList()[i].setInitializerSubsumed();
}

/// Does this binding declare something that requires storage?
Expand Down Expand Up @@ -4600,6 +4628,8 @@ class VarDecl : public AbstractStorageDecl {
Bits.VarDecl.IsCaptureList = IsCaptureList;
Bits.VarDecl.IsDebuggerVar = false;
Bits.VarDecl.IsREPLVar = false;
Bits.VarDecl.HasPropertyDelegate = false;
Bits.VarDecl.IsPropertyDelegateBackingProperty = false;
Bits.VarDecl.HasNonPatternBindingInit = false;
}

Expand Down Expand Up @@ -4872,6 +4902,47 @@ class VarDecl : public AbstractStorageDecl {
Bits.VarDecl.IsREPLVar = IsREPLVar;
}

/// Whether this variable has a property delegate attached.
bool hasPropertyDelegate() const;

/// For a property delegate, retrieve the source location for the
/// 'by' keyword.
SourceLoc getPropertyDelegateByLoc() const;

/// For a property delegate, retrieve the behavior type location
/// information.
TypeLoc &getPropertyDelegateTypeLoc();

/// For a property delegate, retrieve the behavior type location
/// information.
const TypeLoc &getPropertyDelegateTypeLoc() const;

/// Retrieve the formal access level for the attached property delegate.
AccessLevel getPropertyDelegateFormalAccess() const;

/// Retrieve the source location for access specifier of the property.
SourceLoc getPropertyDelegateAccessLoc() const;

/// Add a property delegate to this variable.
void addPropertyDelegate(SourceLoc byLoc,
AccessLevel access,
SourceLoc accessLoc,
TypeLoc typeLoc);

/// Retrieve the backing variable for the property delegate.
VarDecl *getPropertyDelegateBackingVar() const;

/// Set the backing variable for the property delegate.
void setPropertyDelegateBackingVar(VarDecl *backingVar);

/// Retrieve the property that delegates to this backing property,
/// or \c nullptr if this is not a backing property.
VarDecl *getOriginalDelegatedProperty() const;

/// Set the property that delegates to this property as it's backing
/// property.
void setOriginalDelegatedProperty(VarDecl *originalProperty);

/// Return the Objective-C runtime name for this property.
Identifier getObjCPropertyName() const;

Expand Down
14 changes: 12 additions & 2 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1099,14 +1099,14 @@ ERROR(invalid_postfix_operator,none,

ERROR(expected_member_name,PointsToFirstBadToken,
"expected member name following '.'", ())
ERROR(expected_dollar_numeric,none,
"expected numeric value following '$'", ())
ERROR(dollar_numeric_too_large,none,
"numeric value following '$' is too large", ())
ERROR(numeric_literal_numeric_member,none,
"expected named member of numeric literal", ())
ERROR(standalone_dollar_identifier,none,
"'$' is not an identifier; use backticks to escape it", ())
ERROR(dollar_identifier_decl,none,
"cannot declare entity %0 with a '$' prefix", (Identifier))

ERROR(anon_closure_arg_not_in_closure,none,
"anonymous closure argument not contained in a closure", ())
Expand Down Expand Up @@ -1620,6 +1620,16 @@ ERROR(pound_available_package_description_not_allowed, none,
ERROR(availability_query_repeated_platform, none,
"version for '%0' already specified", (StringRef))

//------------------------------------------------------------------------------
// MARK: property delegate diagnostics
//------------------------------------------------------------------------------
ERROR(property_delegate_not_named, none,
"property delegate can only by written on a single-variable pattern", ())
ERROR(expected_property_delegate_type_after_by,PointsToFirstBadToken,
"expected property delegate type after 'by'", ())
ERROR(property_delegate_local,none,
"property delegates are not yet supported on local properties", ())

//------------------------------------------------------------------------------
// MARK: syntax parsing diagnostics
//------------------------------------------------------------------------------
Expand Down
Loading