Skip to content

Commit 8e89d37

Browse files
committed
[Macros] Accessor macros can decide not to emit getter/setter if the property has one
If an accessor macro is placed on a computed property, then opts not to produce a getter/setter, we would produce an error because the macro didn't make the computed property... computed. Fix that; it's already computed, and it's fine not to add accessors. Fixes rdar://111586568.
1 parent b04b4ef commit 8e89d37

File tree

3 files changed

+59
-5
lines changed

3 files changed

+59
-5
lines changed

lib/Sema/TypeCheckMacros.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,11 +1347,7 @@ Optional<unsigned> swift::expandAccessors(
13471347
// declaration, so there is nothing further to do.
13481348
bool foundNonObservingAccessor = false;
13491349
bool foundInitAccessor = false;
1350-
for (auto decl : macroSourceFile->getTopLevelItems()) {
1351-
auto accessor = dyn_cast_or_null<AccessorDecl>(decl.dyn_cast<Decl *>());
1352-
if (!accessor)
1353-
continue;
1354-
1350+
for (auto accessor : storage->getAllAccessors()) {
13551351
if (accessor->isInitAccessor())
13561352
foundInitAccessor = true;
13571353

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,55 @@ extension PropertyWrapperMacro: PeerMacro {
467467
}
468468
}
469469

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+
470519
public struct WrapAllProperties: MemberAttributeMacro {
471520
public static func expansion(
472521
of node: AttributeSyntax,

test/Macros/accessor_macros.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
macro myPropertyWrapper() =
2424
#externalMacro(module: "MacroDefinition", type: "PropertyWrapperMacro")
2525

26+
@attached(accessor)
27+
macro myPropertyWrapperSkipsComputed() =
28+
#externalMacro(module: "MacroDefinition", type: "PropertyWrapperSkipsComputedMacro")
29+
2630
struct Date { }
2731

2832
struct MyWrapperThingy<T> {
@@ -64,6 +68,11 @@ struct MyStruct {
6468
// CHECK-DUMP: set {
6569
// CHECK-DUMP: _birthDate.wrappedValue = newValue
6670
// CHECK-DUMP: }
71+
72+
@myPropertyWrapperSkipsComputed
73+
var age: Int? {
74+
get { nil }
75+
}
6776
}
6877

6978
// Test that the fake-property-wrapper-introduced accessors execute properly at

0 commit comments

Comments
 (0)