Skip to content

Commit f5427ea

Browse files
authored
Merge pull request #67148 from DougGregor/accessor-macros-finishing-touches
2 parents 3fab425 + 16bfd78 commit f5427ea

File tree

7 files changed

+210
-59
lines changed

7 files changed

+210
-59
lines changed

include/swift/AST/Decl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5238,6 +5238,8 @@ class AbstractStorageDecl : public ValueDecl {
52385238

52395239
void addOpaqueAccessor(AccessorDecl *accessor);
52405240

5241+
void removeAccessor(AccessorDecl *accessor);
5242+
52415243
private:
52425244
MutableArrayRef<AccessorDecl *> getAccessorsBuffer() {
52435245
return { getTrailingObjects<AccessorDecl*>(), NumAccessors };
@@ -5401,6 +5403,11 @@ class AbstractStorageDecl : public ValueDecl {
54015403
return {};
54025404
}
54035405

5406+
void removeAccessor(AccessorDecl *accessor) {
5407+
if (auto *info = Accessors.getPointer())
5408+
return info->removeAccessor(accessor);
5409+
}
5410+
54045411
/// This is the primary mechanism by which we can easily determine whether
54055412
/// this storage decl has any effects.
54065413
///
@@ -8915,6 +8922,9 @@ const ParamDecl *getParameterAt(const ValueDecl *source, unsigned index);
89158922
/// nullptr if the source does not have a parameter list.
89168923
const ParamDecl *getParameterAt(const DeclContext *source, unsigned index);
89178924

8925+
StringRef getAccessorNameForDiagnostic(AccessorDecl *accessor, bool article);
8926+
StringRef getAccessorNameForDiagnostic(AccessorKind accessorKind, bool article);
8927+
89188928
void simple_display(llvm::raw_ostream &out,
89198929
OptionSet<NominalTypeDecl::LookupDirectFlags> options);
89208930

lib/AST/Decl.cpp

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6421,6 +6421,38 @@ bool ProtocolDecl::hasCircularInheritedProtocols() const {
64216421
ctx.evaluator, HasCircularInheritedProtocolsRequest{mutableThis}, true);
64226422
}
64236423

6424+
/// Returns a descriptive name for the given accessor/addressor kind.
6425+
StringRef swift::getAccessorNameForDiagnostic(AccessorKind accessorKind,
6426+
bool article) {
6427+
switch (accessorKind) {
6428+
case AccessorKind::Get:
6429+
return article ? "a getter" : "getter";
6430+
case AccessorKind::Set:
6431+
return article ? "a setter" : "setter";
6432+
case AccessorKind::Address:
6433+
return article ? "an addressor" : "addressor";
6434+
case AccessorKind::MutableAddress:
6435+
return article ? "a mutable addressor" : "mutable addressor";
6436+
case AccessorKind::Read:
6437+
return article ? "a 'read' accessor" : "'read' accessor";
6438+
case AccessorKind::Modify:
6439+
return article ? "a 'modify' accessor" : "'modify' accessor";
6440+
case AccessorKind::WillSet:
6441+
return "'willSet'";
6442+
case AccessorKind::DidSet:
6443+
return "'didSet'";
6444+
case AccessorKind::Init:
6445+
return article ? "an init accessor" : "init accessor";
6446+
}
6447+
llvm_unreachable("bad accessor kind");
6448+
}
6449+
6450+
StringRef swift::getAccessorNameForDiagnostic(AccessorDecl *accessor,
6451+
bool article) {
6452+
return getAccessorNameForDiagnostic(accessor->getAccessorKind(),
6453+
article);
6454+
}
6455+
64246456
bool AbstractStorageDecl::hasStorage() const {
64256457
ASTContext &ctx = getASTContext();
64266458
return evaluateOrDefault(ctx.evaluator,
@@ -6488,7 +6520,8 @@ void AbstractStorageDecl::setAccessors(SourceLoc lbraceLoc,
64886520
auto record = Accessors.getPointer();
64896521
if (record) {
64906522
for (auto accessor : accessors) {
6491-
(void) record->addOpaqueAccessor(accessor);
6523+
if (!record->getAccessor(accessor->getAccessorKind()))
6524+
(void) record->addOpaqueAccessor(accessor);
64926525
}
64936526
} else {
64946527
record = AccessorRecord::create(getASTContext(),
@@ -6582,6 +6615,27 @@ void AbstractStorageDecl::AccessorRecord::addOpaqueAccessor(AccessorDecl *decl){
65826615
(void) isUnique;
65836616
}
65846617

6618+
void AbstractStorageDecl::AccessorRecord::removeAccessor(
6619+
AccessorDecl *accessor
6620+
) {
6621+
// Remove this accessor from the list of accessors.
6622+
assert(getAccessor(accessor->getAccessorKind()) == accessor);
6623+
std::remove(getAccessorsBuffer().begin(), getAccessorsBuffer().end(),
6624+
accessor);
6625+
6626+
// Clear out the accessor kind -> index mapping.
6627+
std::memset(AccessorIndices, 0, sizeof(AccessorIndices));
6628+
6629+
// Re-add all of the remaining accessors to build up the index mapping.
6630+
unsigned numAccessorsLeft = NumAccessors - 1;
6631+
NumAccessors = numAccessorsLeft;
6632+
auto buffer = getAccessorsBuffer();
6633+
NumAccessors = 0;
6634+
for (auto index : range(0, numAccessorsLeft)) {
6635+
addOpaqueAccessor(buffer[index]);
6636+
}
6637+
}
6638+
65856639
/// Register that we have an accessor of the given kind.
65866640
bool AbstractStorageDecl::AccessorRecord::registerAccessor(AccessorDecl *decl,
65876641
AccessorIndex index){

lib/Parse/ParseDecl.cpp

Lines changed: 8 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7010,38 +7010,6 @@ void Parser::skipAnyAttribute() {
70107010
(void)canParseCustomAttribute();
70117011
}
70127012

7013-
/// Returns a descriptive name for the given accessor/addressor kind.
7014-
static StringRef getAccessorNameForDiagnostic(AccessorKind accessorKind,
7015-
bool article) {
7016-
switch (accessorKind) {
7017-
case AccessorKind::Get:
7018-
return article ? "a getter" : "getter";
7019-
case AccessorKind::Set:
7020-
return article ? "a setter" : "setter";
7021-
case AccessorKind::Address:
7022-
return article ? "an addressor" : "addressor";
7023-
case AccessorKind::MutableAddress:
7024-
return article ? "a mutable addressor" : "mutable addressor";
7025-
case AccessorKind::Read:
7026-
return article ? "a 'read' accessor" : "'read' accessor";
7027-
case AccessorKind::Modify:
7028-
return article ? "a 'modify' accessor" : "'modify' accessor";
7029-
case AccessorKind::WillSet:
7030-
return "'willSet'";
7031-
case AccessorKind::DidSet:
7032-
return "'didSet'";
7033-
case AccessorKind::Init:
7034-
return article ? "an init accessor" : "init accessor";
7035-
}
7036-
llvm_unreachable("bad accessor kind");
7037-
}
7038-
7039-
static StringRef getAccessorNameForDiagnostic(AccessorDecl *accessor,
7040-
bool article) {
7041-
return getAccessorNameForDiagnostic(accessor->getAccessorKind(),
7042-
article);
7043-
}
7044-
70457013
static void diagnoseRedundantAccessors(Parser &P, SourceLoc loc,
70467014
AccessorKind accessorKind,
70477015
bool isSubscript,
@@ -7096,15 +7064,6 @@ struct Parser::ParsedAccessors {
70967064
func(accessor);
70977065
}
70987066

7099-
/// Find the first accessor that's not an observing accessor.
7100-
AccessorDecl *findFirstNonObserver() {
7101-
for (auto accessor : Accessors) {
7102-
if (!accessor->isObservingAccessor())
7103-
return accessor;
7104-
}
7105-
return nullptr;
7106-
}
7107-
71087067
/// Find the first accessor that can be used to perform mutation.
71097068
AccessorDecl *findFirstMutator() const {
71107069
if (Set) return Set;
@@ -7521,8 +7480,14 @@ void Parser::parseTopLevelAccessors(
75217480

75227481
bool hadLBrace = consumeIf(tok::l_brace);
75237482

7524-
ParserStatus status;
7483+
// Prepopulate the field for any accessors that were already parsed parsed accessors
75257484
ParsedAccessors accessors;
7485+
#define ACCESSOR(ID) \
7486+
if (auto accessor = storage->getAccessor(AccessorKind::ID)) \
7487+
accessors.ID = accessor;
7488+
#include "swift/AST/AccessorKinds.def"
7489+
7490+
ParserStatus status;
75267491
bool hasEffectfulGet = false;
75277492
bool parsingLimitedSyntax = false;
75287493
while (!Tok.isAny(tok::r_brace, tok::eof)) {
@@ -7794,16 +7759,10 @@ void Parser::ParsedAccessors::classify(Parser &P, AbstractStorageDecl *storage,
77947759
// The observing accessors have very specific restrictions.
77957760
// Prefer to ignore them.
77967761
if (WillSet || DidSet) {
7797-
// For now, we don't support the observing accessors on subscripts.
7762+
// We don't support the observing accessors on subscripts.
77987763
if (isa<SubscriptDecl>(storage)) {
77997764
diagnoseAndIgnoreObservers(P, *this,
78007765
diag::observing_accessor_in_subscript);
7801-
7802-
// The observing accessors cannot be combined with other accessors.
7803-
} else if (auto nonObserver = findFirstNonObserver()) {
7804-
diagnoseAndIgnoreObservers(P, *this,
7805-
diag::observing_accessor_conflicts_with_accessor,
7806-
getAccessorNameForDiagnostic(nonObserver, /*article*/ true));
78077766
}
78087767
}
78097768

lib/Sema/TypeCheckMacros.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,23 +1345,24 @@ llvm::Optional<unsigned> swift::expandAccessors(AbstractStorageDecl *storage,
13451345
// side effect of registering those accessor declarations with the storage
13461346
// declaration, so there is nothing further to do.
13471347
bool foundNonObservingAccessor = false;
1348+
bool foundNonObservingAccessorInMacro = false;
13481349
bool foundInitAccessor = false;
1349-
for (auto decl : macroSourceFile->getTopLevelItems()) {
1350-
auto accessor = dyn_cast_or_null<AccessorDecl>(decl.dyn_cast<Decl *>());
1351-
if (!accessor)
1352-
continue;
1353-
1350+
for (auto accessor : storage->getAllAccessors()) {
13541351
if (accessor->isInitAccessor())
13551352
foundInitAccessor = true;
13561353

1357-
if (!accessor->isObservingAccessor())
1354+
if (!accessor->isObservingAccessor()) {
13581355
foundNonObservingAccessor = true;
1356+
1357+
if (accessor->isInMacroExpansionInContext())
1358+
foundNonObservingAccessorInMacro = true;
1359+
}
13591360
}
13601361

13611362
auto roleAttr = macro->getMacroRoleAttr(MacroRole::Accessor);
13621363
bool expectedNonObservingAccessor =
13631364
!accessorMacroOnlyIntroducesObservers(macro, roleAttr);
1364-
if (foundNonObservingAccessor) {
1365+
if (foundNonObservingAccessorInMacro) {
13651366
// If any non-observing accessor was added, mark the initializer as
13661367
// subsumed unless it has init accessor, because the initializer in
13671368
// such cases could be used for memberwise initialization.
@@ -1372,6 +1373,13 @@ llvm::Optional<unsigned> swift::expandAccessors(AbstractStorageDecl *storage,
13721373
binding->setInitializerSubsumed(index);
13731374
}
13741375
}
1376+
1377+
// Also remove didSet and willSet, because they are subsumed by a
1378+
// macro expansion that turns a stored property into a computed one.
1379+
if (auto accessor = storage->getParsedAccessor(AccessorKind::WillSet))
1380+
storage->removeAccessor(accessor);
1381+
if (auto accessor = storage->getParsedAccessor(AccessorKind::DidSet))
1382+
storage->removeAccessor(accessor);
13751383
}
13761384

13771385
// Make sure we got non-observing accessors exactly where we expected to.

lib/Sema/TypeCheckStorage.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3626,6 +3626,37 @@ StorageImplInfoRequest::evaluate(Evaluator &evaluator,
36263626

36273627
bool hasWillSet = storage->getParsedAccessor(AccessorKind::WillSet);
36283628
bool hasDidSet = storage->getParsedAccessor(AccessorKind::DidSet);
3629+
if ((hasWillSet || hasDidSet) && !isa<SubscriptDecl>(storage)) {
3630+
// Observers conflict with non-observers.
3631+
AccessorDecl *firstNonObserver = nullptr;
3632+
for (auto accessor : storage->getAllAccessors()) {
3633+
if (!accessor->isImplicit() && !accessor->isObservingAccessor()) {
3634+
firstNonObserver = accessor;
3635+
break;
3636+
}
3637+
}
3638+
3639+
if (firstNonObserver) {
3640+
if (auto willSet = storage->getParsedAccessor(AccessorKind::WillSet)) {
3641+
willSet->diagnose(
3642+
diag::observing_accessor_conflicts_with_accessor, 0,
3643+
getAccessorNameForDiagnostic(
3644+
firstNonObserver->getAccessorKind(), /*article=*/ true));
3645+
willSet->setInvalid();
3646+
hasWillSet = false;
3647+
}
3648+
3649+
if (auto didSet = storage->getParsedAccessor(AccessorKind::DidSet)) {
3650+
didSet->diagnose(
3651+
diag::observing_accessor_conflicts_with_accessor, 1,
3652+
getAccessorNameForDiagnostic(
3653+
firstNonObserver->getAccessorKind(), /*article=*/ true));
3654+
didSet->setInvalid();
3655+
hasDidSet = false;
3656+
}
3657+
}
3658+
}
3659+
36293660
bool hasSetter = storage->getParsedAccessor(AccessorKind::Set);
36303661
bool hasModify = storage->getParsedAccessor(AccessorKind::Modify);
36313662
bool hasMutableAddress = storage->getParsedAccessor(AccessorKind::MutableAddress);

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,8 +422,7 @@ extension PropertyWrapperMacro: AccessorMacro, Macro {
422422
) throws -> [AccessorDeclSyntax] {
423423
guard let varDecl = declaration.as(VariableDeclSyntax.self),
424424
let binding = varDecl.bindings.first,
425-
let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier,
426-
binding.accessor == nil
425+
let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier
427426
else {
428427
return []
429428
}
@@ -468,6 +467,55 @@ extension PropertyWrapperMacro: PeerMacro {
468467
}
469468
}
470469

470+
extension PatternBindingSyntax.Accessor {
471+
var hasGetter: Bool {
472+
switch self {
473+
case .accessors(let accessors):
474+
for accessor in accessors.accessors {
475+
if accessor.accessorKind.text == "get" {
476+
return true
477+
}
478+
}
479+
480+
return false
481+
case .getter:
482+
return true
483+
}
484+
}
485+
}
486+
487+
public struct PropertyWrapperSkipsComputedMacro {}
488+
489+
extension PropertyWrapperSkipsComputedMacro: AccessorMacro, Macro {
490+
public static func expansion(
491+
of node: AttributeSyntax,
492+
providingAccessorsOf declaration: some DeclSyntaxProtocol,
493+
in context: some MacroExpansionContext
494+
) throws -> [AccessorDeclSyntax] {
495+
guard let varDecl = declaration.as(VariableDeclSyntax.self),
496+
let binding = varDecl.bindings.first,
497+
let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier, !(binding.accessor?.hasGetter ?? false)
498+
else {
499+
return []
500+
}
501+
502+
return [
503+
"""
504+
505+
get {
506+
_\(identifier).wrappedValue
507+
}
508+
""",
509+
"""
510+
511+
set {
512+
_\(identifier).wrappedValue = newValue
513+
}
514+
""",
515+
]
516+
}
517+
}
518+
471519
public struct WrapAllProperties: MemberAttributeMacro {
472520
public static func expansion(
473521
of node: AttributeSyntax,

0 commit comments

Comments
 (0)