Skip to content

Generalize accessor storage to preserve the original accessor list. #17238

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 1 commit into from
Jun 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
203 changes: 90 additions & 113 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3962,9 +3962,11 @@ enum class AccessorKind {
#include "swift/AST/AccessorKinds.def"
};

const unsigned NumAccessorKinds = unsigned(AccessorKind::Last) + 1;

static inline IntRange<AccessorKind> allAccessorKinds() {
return IntRange<AccessorKind>(AccessorKind(0),
AccessorKind(unsigned(AccessorKind::Last) + 1));
AccessorKind(NumAccessorKinds));
}

/// The safety semantics of this addressor.
Expand Down Expand Up @@ -4121,66 +4123,66 @@ class AbstractStorageDecl : public ValueDecl {
/// return the address at which the object is stored.
ComputedWithMutableAddress,
};

static const size_t MaxNumAccessors = 255;
private:
AbstractStorageDecl *OverriddenDecl;

struct GetSetRecord;

/// This is stored immediately before the GetSetRecord.
struct alignas(1 << 3) AddressorRecord {
AccessorDecl *Address = nullptr; // User-defined address accessor
AccessorDecl *MutableAddress = nullptr; // User-defined mutableAddress accessor

GetSetRecord *getGetSet() {
// Relies on not-strictly-portable ABI layout assumptions.
return reinterpret_cast<GetSetRecord*>(this+1);
}
};
void configureAddressorRecord(AddressorRecord *record,
AccessorDecl *addressor, AccessorDecl *mutableAddressor);
/// A record of the accessors for the declaration.
class alignas(1 << 3) AccessorRecord final :
private llvm::TrailingObjects<AccessorRecord, AccessorDecl*> {
friend TrailingObjects;

using AccessorIndex = uint8_t;
static const AccessorIndex InvalidIndex = 0;

struct alignas(1 << 3) GetSetRecord {
SourceRange Braces;
AccessorDecl *Get = nullptr; // User-defined getter
AccessorDecl *Set = nullptr; // User-defined setter
AccessorDecl *MaterializeForSet = nullptr; // optional materializeForSet accessor
AccessorIndex NumAccessors;

/// The storage capacity of this record for accessors. Always includes
/// enough space for adding opaque accessors to the record, which are the
/// only accessors that should ever be added retroactively; hence this
/// field is only here for the purposes of safety checks.
AccessorIndex AccessorsCapacity;

/// Either 0, meaning there is no registered accessor of the given kind,
/// or the index+1 of the accessor in the accessors array.
AccessorIndex AccessorIndices[NumAccessorKinds];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use llvm::TrailingObjects instead of a supposed fixed-sized array?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a fixed-size array; it's indexed by AccessorKinds. There is a trailing-objects use in that type, though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, my brain misread NumAccessorKinds as MaxNumAccessors. Sorry for the noise!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated to use TrailingObjects for the part that's actually a trailing array.


AccessorRecord(SourceRange braces, ArrayRef<AccessorDecl*> accessors,
AccessorIndex accessorsCapacity);
public:
static AccessorRecord *create(ASTContext &ctx, SourceRange braces,
ArrayRef<AccessorDecl*> accessors);

SourceRange getBracesRange() const { return Braces; }

inline AccessorDecl *getAccessor(AccessorKind kind) const;

AddressorRecord *getAddressors() {
// Relies on not-strictly-portable ABI layout assumptions.
return reinterpret_cast<AddressorRecord*>(this) - 1;
ArrayRef<AccessorDecl *> getAllAccessors() const {
return { getTrailingObjects<AccessorDecl*>(), NumAccessors };
}

void addOpaqueAccessor(AccessorDecl *accessor);

private:
MutableArrayRef<AccessorDecl *> getAccessorsBuffer() {
return { getTrailingObjects<AccessorDecl*>(), NumAccessors };
}

bool registerAccessor(AccessorDecl *accessor, AccessorIndex index);
};
void configureGetSetRecord(GetSetRecord *getSetRecord,
AccessorDecl *getter, AccessorDecl *setter,
AccessorDecl *materializeForSet);
void configureSetRecord(GetSetRecord *getSetInfo,
AccessorDecl *setter,
AccessorDecl *materializeForSet);

struct ObservingRecord : GetSetRecord {
AccessorDecl *WillSet = nullptr; // willSet(value):
AccessorDecl *DidSet = nullptr; // didSet:
};
void configureObservingRecord(ObservingRecord *record,
AccessorDecl *willSet, AccessorDecl *didSet);

llvm::PointerIntPair<GetSetRecord*, 3, OptionalEnum<AccessLevel>> GetSetInfo;
llvm::PointerIntPair<AccessorRecord*, 3, OptionalEnum<AccessLevel>> Accessors;
llvm::PointerIntPair<BehaviorRecord*, 3, OptionalEnum<AccessLevel>>
BehaviorInfo;

ObservingRecord &getDidSetInfo() const {
assert(hasObservers());
return *static_cast<ObservingRecord*>(GetSetInfo.getPointer());
}
AddressorRecord &getAddressorInfo() const {
assert(hasAddressors());
return *GetSetInfo.getPointer()->getAddressors();
}

void setStorageKind(StorageKindTy K) {
Bits.AbstractStorageDecl.StorageKind = unsigned(K);
}

void configureAccessor(AccessorDecl *accessor);

protected:
AbstractStorageDecl(DeclKind Kind, DeclContext *DC, DeclName Name,
SourceLoc NameLoc)
Expand Down Expand Up @@ -4308,55 +4310,26 @@ class AbstractStorageDecl : public ValueDecl {
Bits.AbstractStorageDecl.IsSetterMutating = isMutating;
}

AccessorDecl *getAccessorFunction(AccessorKind accessor) const;

/// \brief Push all of the accessor functions associated with this VarDecl
/// onto `decls`.
void getAllAccessorFunctions(SmallVectorImpl<Decl *> &decls) const;
AccessorDecl *getAccessorFunction(AccessorKind kind) const {
if (auto info = Accessors.getPointer())
return info->getAccessor(kind);
return nullptr;
}

/// \brief Turn this into a computed variable, providing a getter and setter.
void makeComputed(SourceLoc LBraceLoc, AccessorDecl *Get, AccessorDecl *Set,
AccessorDecl *MaterializeForSet, SourceLoc RBraceLoc);
ArrayRef<AccessorDecl*> getAllAccessorFunctions() const {
if (const auto *info = Accessors.getPointer())
return info->getAllAccessors();
return {};
}

/// \brief Turn this into a computed object, providing a getter and a mutable
/// addressor.
void makeComputedWithMutableAddress(SourceLoc lbraceLoc,
AccessorDecl *getter,
AccessorDecl *setter,
AccessorDecl *materializeForSet,
AccessorDecl *mutableAddressor,
SourceLoc rbraceLoc);
void setAccessors(StorageKindTy storageKind,
SourceLoc lbraceLoc, ArrayRef<AccessorDecl*> accessors,
SourceLoc rbraceLoc);

/// \brief Add trivial accessors to this Stored or Addressed object.
void addTrivialAccessors(AccessorDecl *Get, AccessorDecl *Set,
AccessorDecl *MaterializeForSet);

/// \brief Turn this into a stored-with-observers var, providing the
/// didSet/willSet specifiers.
void makeStoredWithObservers(SourceLoc LBraceLoc, AccessorDecl *WillSet,
AccessorDecl *DidSet, SourceLoc RBraceLoc);

/// \brief Turn this into an inherited-with-observers var, providing
/// the didSet/willSet specifiers.
void makeInheritedWithObservers(SourceLoc LBraceLoc, AccessorDecl *WillSet,
AccessorDecl *DidSet, SourceLoc RBraceLoc);

/// \brief Turn this into an addressed var.
void makeAddressed(SourceLoc LBraceLoc, AccessorDecl *Addressor,
AccessorDecl *MutableAddressor,
SourceLoc RBraceLoc);

/// \brief Turn this into an addressed var with observing accessors.
void makeAddressedWithObservers(SourceLoc LBraceLoc, AccessorDecl *Addressor,
AccessorDecl *MutableAddressor,
AccessorDecl *WillSet, AccessorDecl *DidSet,
SourceLoc RBraceLoc);

/// \brief Specify the synthesized get/set functions for a
/// StoredWithObservers or AddressedWithObservers var. This is used by Sema.
void setObservingAccessors(AccessorDecl *Get, AccessorDecl *Set,
AccessorDecl *MaterializeForSet);

/// \brief Add a setter to an existing Computed var.
///
/// This should only be used by the ClangImporter.
Expand All @@ -4370,39 +4343,30 @@ class AbstractStorageDecl : public ValueDecl {
/// This should only be used by Sema.
void setMaterializeForSetFunc(AccessorDecl *materializeForSet);

/// \brief Specify the braces range without adding accessors.
///
/// This is used to record the braces range if the accessors were rejected.
void setInvalidBracesRange(SourceRange BracesRange);

SourceRange getBracesRange() const {
if (auto info = GetSetInfo.getPointer())
return info->Braces;
if (auto info = Accessors.getPointer())
return info->getBracesRange();
return SourceRange();
}

/// \brief Retrieve the getter used to access the value of this variable.
AccessorDecl *getGetter() const {
if (auto info = GetSetInfo.getPointer())
return info->Get;
return nullptr;
return getAccessorFunction(AccessorKind::Get);
}

/// \brief Retrieve the setter used to mutate the value of this variable.
AccessorDecl *getSetter() const {
if (auto info = GetSetInfo.getPointer())
return info->Set;
return nullptr;
return getAccessorFunction(AccessorKind::Set);
}

AccessLevel getSetterFormalAccess() const {
assert(hasAccess());
assert(GetSetInfo.getInt().hasValue());
return GetSetInfo.getInt().getValue();
assert(Accessors.getInt().hasValue());
return Accessors.getInt().getValue();
}

void setSetterAccess(AccessLevel accessLevel) {
assert(!GetSetInfo.getInt().hasValue());
assert(!Accessors.getInt().hasValue());
overwriteSetterAccess(accessLevel);
}

Expand All @@ -4411,19 +4375,18 @@ class AbstractStorageDecl : public ValueDecl {
/// \brief Retrieve the materializeForSet function, if this
/// declaration has one.
AccessorDecl *getMaterializeForSetFunc() const {
if (auto info = GetSetInfo.getPointer())
return info->MaterializeForSet;
return nullptr;
return getAccessorFunction(AccessorKind::MaterializeForSet);
}

/// \brief Return the decl for the 'address' accessor if it
/// exists; this is only valid on a declaration with addressors.
AccessorDecl *getAddressor() const { return getAddressorInfo().Address; }
/// \brief Return the decl for the immutable addressor if it exists.
AccessorDecl *getAddressor() const {
return getAccessorFunction(AccessorKind::Address);
}

/// \brief Return the decl for the 'mutableAddress' accessors if
/// it exists; this is only valid on a declaration with addressors.
AccessorDecl *getMutableAddressor() const {
return getAddressorInfo().MutableAddress;
return getAccessorFunction(AccessorKind::MutableAddress);
}

/// \brief Return the appropriate addressor for the given access kind.
Expand All @@ -4435,11 +4398,15 @@ class AbstractStorageDecl : public ValueDecl {

/// \brief Return the decl for the willSet specifier if it exists, this is
/// only valid on a declaration with Observing storage.
AccessorDecl *getWillSetFunc() const { return getDidSetInfo().WillSet; }
AccessorDecl *getWillSetFunc() const {
return getAccessorFunction(AccessorKind::WillSet);
}

/// \brief Return the decl for the didSet specifier if it exists, this is
/// only valid on a declaration with Observing storage.
AccessorDecl *getDidSetFunc() const { return getDidSetInfo().DidSet; }
AccessorDecl *getDidSetFunc() const {
return getAccessorFunction(AccessorKind::DidSet);
}

/// Given that this is an Objective-C property or subscript declaration,
/// produce its getter selector.
Expand Down Expand Up @@ -5777,6 +5744,16 @@ inline ParameterList **FuncDecl::getParameterListBuffer() {
}
return reinterpret_cast<ParameterList**>(static_cast<AccessorDecl*>(this)+1);
}

inline AccessorDecl *
AbstractStorageDecl::AccessorRecord::getAccessor(AccessorKind kind) const {
if (auto optIndex = AccessorIndices[unsigned(kind)]) {
auto accessor = getAllAccessors()[optIndex - 1];
assert(accessor && accessor->getAccessorKind() == kind);
return accessor;
}
return nullptr;
}

/// \brief This represents a 'case' declaration in an 'enum', which may declare
/// one or more individual comma-separated EnumElementDecls.
Expand Down Expand Up @@ -6652,7 +6629,7 @@ ::operator()(Decl *decl) const {

inline void
AbstractStorageDecl::overwriteSetterAccess(AccessLevel accessLevel) {
GetSetInfo.setInt(accessLevel);
Accessors.setInt(accessLevel);
if (auto setter = getSetter())
setter->overwriteAccess(accessLevel);
if (auto materializeForSet = getMaterializeForSetFunc())
Expand Down
17 changes: 14 additions & 3 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,7 @@ class Parser {

struct ParsedAccessors {
SourceLoc LBLoc, RBLoc;
SmallVector<AccessorDecl*, 16> Accessors;

#define ACCESSOR(ID) AccessorDecl *ID = nullptr;
#include "swift/AST/AccessorKinds.def"
Expand All @@ -887,6 +888,17 @@ class Parser {
const DeclAttributes &attrs,
TypeLoc elementTy, ParameterList *indices,
SmallVectorImpl<Decl *> &decls);

AbstractStorageDecl::StorageKindTy
classify(Parser &P, AbstractStorageDecl *storage, bool invalid,
ParseDeclOptions flags, SourceLoc staticLoc,
const DeclAttributes &attrs,
TypeLoc elementTy, ParameterList *indices);

/// Add an accessor. If there's an existing accessor of this kind,
/// return it. The new accessor is still remembered but will be
/// ignored.
AccessorDecl *add(AccessorDecl *accessor);
};

void parseAccessorAttributes(DeclAttributes &Attributes);
Expand All @@ -898,15 +910,14 @@ class Parser {
ParsedAccessors &accessors,
AbstractStorageDecl *storage,
SourceLoc &LastValidLoc,
SourceLoc StaticLoc, SourceLoc VarLBLoc,
SmallVectorImpl<Decl *> &Decls);
SourceLoc StaticLoc, SourceLoc VarLBLoc);
bool parseGetSet(ParseDeclOptions Flags,
GenericParamList *GenericParams,
ParameterList *Indices,
TypeLoc ElementTy,
ParsedAccessors &accessors,
AbstractStorageDecl *storage,
SourceLoc StaticLoc, SmallVectorImpl<Decl *> &Decls);
SourceLoc StaticLoc);
void recordAccessors(AbstractStorageDecl *storage, ParseDeclOptions flags,
TypeLoc elementTy, const DeclAttributes &attrs,
SourceLoc staticLoc, ParsedAccessors &accessors);
Expand Down
Loading