Skip to content

Commit 8ba8222

Browse files
author
Harlan
authored
[InterfaceGen] Print abstract accessors in protocols (#19379)
* [InterfaceGen] Print abstract accessors in protocols This patch slightly cleans up printing accessors and ensures we print accessors abstractly in protocol context for textual interfaces. It also removes some assuptions around the FunctionBody callback and makes them more explicit. * Print getter and setter for didSet decls * Test _read and _modify * Fix logic for skipping willSet/didSet * Update 'final' test for new getter printing behavior
1 parent bbbf02e commit 8ba8222

File tree

5 files changed

+128
-28
lines changed

5 files changed

+128
-28
lines changed

include/swift/AST/PrintOptions.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,32 @@ struct PrintOptions {
135135
/// \brief Whether to print *any* accessors on properties.
136136
bool PrintPropertyAccessors = true;
137137

138-
/// \brief Whether to print the accessors of a property abstractly,
139-
/// i.e. always as get and set rather than the specific accessors
140-
/// actually used to implement the property.
138+
/// Whether to print the accessors of a property abstractly,
139+
/// i.e. always as:
140+
/// ```
141+
/// var x: Int { get set }
142+
/// ```
143+
/// rather than the specific accessors actually used to implement the
144+
/// property.
141145
///
142146
/// Printing function definitions takes priority over this setting.
143147
bool AbstractAccessors = true;
144148

149+
/// Whether to print a property with only a single getter using the shorthand
150+
/// ```
151+
/// var x: Int { return y }
152+
/// ```
153+
/// vs.
154+
/// ```
155+
/// var x: Int {
156+
/// get { return y }
157+
/// }
158+
/// ```
159+
bool CollapseSingleGetterProperty = true;
160+
161+
/// Whether to print the bodies of accessors in protocol context.
162+
bool PrintAccessorBodiesInProtocols = false;
163+
145164
/// \brief Whether to print type definitions.
146165
bool TypeDefinitions = false;
147166

lib/AST/ASTPrinter.cpp

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ PrintOptions PrintOptions::printTextualInterfaceFile() {
8080
result.FullyQualifiedTypes = true;
8181
result.SkipImports = true;
8282
result.OmitNameOfInaccessibleProperties = true;
83+
result.FunctionDefinitions = true;
84+
result.CollapseSingleGetterProperty = false;
8385

8486
result.FunctionBody = [](const ValueDecl *decl, ASTPrinter &printer) {
8587
auto AFD = dyn_cast<AbstractFunctionDecl>(decl);
@@ -1579,15 +1581,15 @@ void PrintAST::printAccessors(AbstractStorageDecl *ASD) {
15791581
return;
15801582
}
15811583

1582-
// AbstractAccessors is suppressed by FunctionDefinitions, but not the
1583-
// presence of an FunctionBody callback.
1584+
// AbstractAccessors is suppressed by FunctionDefinitions.
15841585
bool PrintAbstract =
15851586
Options.AbstractAccessors && !Options.FunctionDefinitions;
15861587

15871588
// We sometimes want to print the accessors abstractly
15881589
// instead of listing out how they're actually implemented.
15891590
bool inProtocol = isa<ProtocolDecl>(ASD->getDeclContext());
1590-
if (!Options.FunctionBody && (inProtocol || PrintAbstract)) {
1591+
if ((inProtocol && !Options.PrintAccessorBodiesInProtocols) ||
1592+
PrintAbstract) {
15911593
bool mutatingGetter = ASD->getGetter() && ASD->isGetterMutating();
15921594
bool settable = ASD->isSettable(nullptr);
15931595
bool nonmutatingSetter = false;
@@ -1650,12 +1652,13 @@ void PrintAST::printAccessors(AbstractStorageDecl *ASD) {
16501652
}
16511653

16521654
// Otherwise, print all the concrete defining accessors.
1655+
bool PrintAccessorBody = Options.FunctionDefinitions;
16531656

1654-
bool PrintAccessorBody = Options.FunctionDefinitions || Options.FunctionBody;
1655-
1656-
auto PrintAccessor = [&](AccessorDecl *Accessor) {
1657-
if (!Accessor)
1658-
return;
1657+
// Helper to print an accessor. Returns true if the
1658+
// accessor was present but skipped.
1659+
auto PrintAccessor = [&](AccessorDecl *Accessor) -> bool {
1660+
if (!Accessor || !shouldPrint(Accessor))
1661+
return true;
16591662
if (!PrintAccessorBody) {
16601663
if (isAccessorAssumedNonMutating(Accessor->getAccessorKind())) {
16611664
if (Accessor->isMutating()) {
@@ -1679,19 +1682,17 @@ void PrintAST::printAccessors(AbstractStorageDecl *ASD) {
16791682
indent();
16801683
Printer.printNewline();
16811684
}
1685+
return false;
16821686
};
16831687

1684-
if ((PrintAbstract ||
1685-
(impl.getReadImpl() == ReadImplKind::Get && ASD->getGetter())) &&
1686-
!ASD->supportsMutation() && !ASD->isGetterMutating() &&
1687-
PrintAccessorBody && !Options.FunctionDefinitions) {
1688-
// Omit the 'get' keyword. Directly print getter
1689-
if (auto BodyFunc = Options.FunctionBody) {
1690-
BodyFunc(ASD->getGetter(), Printer);
1691-
indent();
1692-
return;
1693-
}
1694-
Printer.printNewline();
1688+
// Determine if we should print the getter without the 'get { ... }'
1689+
// block around it.
1690+
bool isOnlyGetter = impl.getReadImpl() == ReadImplKind::Get &&
1691+
ASD->getGetter();
1692+
bool isGetterMutating = ASD->supportsMutation() || ASD->isGetterMutating();
1693+
if (isOnlyGetter && !isGetterMutating && PrintAccessorBody &&
1694+
Options.FunctionBody && Options.CollapseSingleGetterProperty) {
1695+
Options.FunctionBody(ASD->getGetter(), Printer);
16951696
indent();
16961697
return;
16971698
}
@@ -1726,10 +1727,15 @@ void PrintAST::printAccessors(AbstractStorageDecl *ASD) {
17261727
case WriteImplKind::Stored:
17271728
llvm_unreachable("simply-stored variable should have been filtered out");
17281729
case WriteImplKind::StoredWithObservers:
1729-
case WriteImplKind::InheritedWithObservers:
1730-
PrintAccessor(ASD->getWillSetFunc());
1731-
PrintAccessor(ASD->getDidSetFunc());
1730+
case WriteImplKind::InheritedWithObservers: {
1731+
bool skippedWillSet = PrintAccessor(ASD->getWillSetFunc());
1732+
bool skippedDidSet = PrintAccessor(ASD->getDidSetFunc());
1733+
if (skippedDidSet && skippedWillSet) {
1734+
PrintAccessor(ASD->getGetter());
1735+
PrintAccessor(ASD->getSetter());
1736+
}
17321737
break;
1738+
}
17331739
case WriteImplKind::Set:
17341740
PrintAccessor(ASD->getSetter());
17351741
if (!shouldHideModifyAccessor())
@@ -1751,9 +1757,6 @@ void PrintAST::printAccessors(AbstractStorageDecl *ASD) {
17511757

17521758
Printer << "}";
17531759

1754-
if (!PrintAbstract)
1755-
Printer.printNewline();
1756-
17571760
indent();
17581761
}
17591762

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2397,6 +2397,8 @@ printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter,
23972397
Options.AccessFilter = AccessLevel::Private;
23982398
Options.PrintAccess = false;
23992399
Options.SkipAttributes = true;
2400+
Options.FunctionDefinitions = true;
2401+
Options.PrintAccessorBodiesInProtocols = true;
24002402
Options.FunctionBody = [&](const ValueDecl *VD, ASTPrinter &Printer) {
24012403
Printer << " {";
24022404
Printer.printNewline();

test/ModuleInterface/final.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
// CHECK: final public class FinalClass {
77
public final class FinalClass {
88
// CHECK: @inlinable final public class var a: [[INT:(Swift.)?Int]] {
9+
// CHECK-NEXT: {{^}} get {
910
// CHECK-NEXT: return 3
1011
// CHECK-NEXT: }
12+
// CHECK-NEXT: }
1113
@inlinable
1214
public final class var a: Int {
1315
return 3

test/ModuleInterface/inlinable-function.swift

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@ public struct Foo: Hashable {
3737

3838

3939
// CHECK: @_transparent public var transparent: [[INT]] {
40+
// CHECK-NEXT: get {
4041
// CHECK-NEXT: return 34
4142
// CHECK-NEXT: }
43+
// CHECK-NEXT: }
4244
@_transparent
4345
public var transparent: Int {
4446
return 34
@@ -102,6 +104,78 @@ public struct Foo: Hashable {
102104
// CHECK-NEXT: }
103105
}
104106

107+
// CHECK: @inlinable public var inlinableReadAndModify: [[INT]] {
108+
@inlinable
109+
public var inlinableReadAndModify: Int {
110+
// CHECK: _read {
111+
// CHECK-NEXT: yield 0
112+
// CHECK-NEXT: }
113+
_read {
114+
yield 0
115+
}
116+
// CHECK: _modify {
117+
// CHECK-NEXT: var x = 0
118+
// CHECK-NEXT: yield &x
119+
// CHECK-NEXT: }
120+
_modify {
121+
var x = 0
122+
yield &x
123+
}
124+
// CHECK-NEXT: }
125+
}
126+
127+
// CHECK: public var inlinableReadNormalModify: [[INT]] {
128+
public var inlinableReadNormalModify: Int {
129+
// CHECK: @inlinable _read {
130+
// CHECK-NEXT: yield 0
131+
// CHECK-NEXT: }
132+
@inlinable _read {
133+
yield 0
134+
}
135+
136+
// CHECK: _modify{{$}}
137+
// CHECK-NOT: var x = 0
138+
// CHECK-NOT: yield &x
139+
// CHECK-NOT: }
140+
_modify {
141+
var x = 0
142+
yield &x
143+
}
144+
// CHECK-NEXT: }
145+
}
146+
147+
// CHECK: public var normalReadInlinableModify: [[INT]] {
148+
public var normalReadInlinableModify: Int {
149+
// CHECK: _read{{$}}
150+
// CHECK-NOT: yield 0
151+
// CHECK-NOT: }
152+
_read {
153+
yield 0
154+
}
155+
156+
// CHECK: @inlinable _modify {
157+
// CHECK-NEXT: var x = 0
158+
// CHECK-NEXT: yield &x
159+
// CHECK-NEXT: }
160+
@inlinable _modify {
161+
var x = 0
162+
yield &x
163+
}
164+
// CHECK-NEXT: }
165+
}
166+
167+
// CHECK: public var normalReadAndModify: [[INT]] {
168+
public var normalReadAndModify: Int {
169+
// CHECK-NEXT: _read{{$}}
170+
_read { yield 0 }
171+
// CHECK-NEXT: _modify{{$}}
172+
_modify {
173+
var x = 0
174+
yield &x
175+
}
176+
// CHECK-NEXT: }
177+
}
178+
105179
// CHECK: @inlinable public func inlinableMethod() {
106180
// CHECK-NOT: #if NO
107181
// CHECK-NOT: print("Hello, world!")

0 commit comments

Comments
 (0)