Skip to content

Commit 13e1787

Browse files
authored
Merge pull request #84972 from rintaro/accessor-disambiguation-rdar140943107
[ASTPrinter/Parse] Disambiguate accessor block in .swiftinterface
2 parents 6ab8b56 + 6a1604b commit 13e1787

File tree

5 files changed

+60
-3
lines changed

5 files changed

+60
-3
lines changed

lib/AST/ASTPrinter.cpp

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2716,6 +2716,32 @@ void PrintAST::printAccessors(const AbstractStorageDecl *ASD) {
27162716
}
27172717
}
27182718

2719+
Printer << " {";
2720+
2721+
// For var decls, if it has an initializer, the parser only expects observing
2722+
// accessors. But sometimes for example in '.swiftinterface', we want to print
2723+
// both the initializer and the accessors. So when we print the initializer
2724+
// *and* the accessor block not starting with willSet/didSet, print an
2725+
// attribute as a disambiguation marker.
2726+
bool needsDisambiguationAttr = false;
2727+
if (auto *VD = dyn_cast<VarDecl>(ASD)) {
2728+
if (auto *PBD = VD->getParentPatternBinding()) {
2729+
AccessorDecl *firstAccessor = *accessorsToPrint.begin();
2730+
if (!firstAccessor->isObservingAccessor()) {
2731+
const auto i = PBD->getPatternEntryIndexForVarDecl(VD);
2732+
if (Options.PrintExprs) {
2733+
needsDisambiguationAttr |= bool(PBD->getInit(i));
2734+
} else if (Options.VarInitializers) {
2735+
needsDisambiguationAttr |= bool(PBD->hasInitStringRepresentation(i) &&
2736+
VD->isInitExposedToClients());
2737+
}
2738+
}
2739+
}
2740+
}
2741+
if (needsDisambiguationAttr) {
2742+
Printer << " @_accessorBlock";
2743+
}
2744+
27192745
// If we're not printing the accessor bodies and none of the accessors have
27202746
// attributes then we can print in a shorter, compact form.
27212747
bool PrintCompactAccessors =
@@ -2724,9 +2750,6 @@ void PrintAST::printAccessors(const AbstractStorageDecl *ASD) {
27242750
[](AccessorDecl *accessor) {
27252751
return accessor->getAttrs().isEmpty();
27262752
});
2727-
2728-
Printer << " {";
2729-
27302753
if (!PrintCompactAccessors)
27312754
Printer.printNewline();
27322755

lib/ASTGen/Sources/ASTGen/DeclAttrs.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,11 @@ extension ASTGenVisitor {
367367
break
368368

369369
case .none:
370+
// '@_accessorBlock' is a parser only disambiguation marker, ignore.
371+
if attrName == "_accessorBlock" {
372+
return
373+
}
374+
370375
// Fall back to CustomAttr.
371376
break
372377
}

lib/Parse/ParseDecl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8167,6 +8167,14 @@ ParserStatus Parser::parseGetSet(ParseDeclOptions Flags, ParameterList *Indices,
81678167
bool IsFirstAccessor = true;
81688168
bool hasEffectfulGet = false;
81698169
accessors.LBLoc = consumeToken(tok::l_brace);
8170+
8171+
// Skip accessor-block disambiguation attribute if exist.
8172+
if (Tok.is(tok::at_sign) &&
8173+
peekToken().isContextualKeyword("_accessorBlock")) {
8174+
consumeToken(tok::at_sign);
8175+
consumeToken();
8176+
}
8177+
81708178
while (!Tok.isAny(tok::r_brace, tok::eof)) {
81718179
// Parse introducer if possible.
81728180
DeclAttributes Attributes;

lib/Parse/ParseExpr.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,10 @@ bool Parser::isStartOfGetSetAccessor() {
11271127
// Eat the "{".
11281128
consumeToken(tok::l_brace);
11291129

1130+
// '@_accessorBlock' is a builtin disambiguation marker.
1131+
if (peekToken().isContextualKeyword("_accessorBlock"))
1132+
return true;
1133+
11301134
// Eat attributes, if present.
11311135
while (consumeIf(tok::at_sign)) {
11321136
if (!consumeIf(tok::identifier))
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -o %t/Test.swiftmodule -emit-module-interface-path %t/Test.swiftinterface -module-name Test %s
3+
// RUN: %target-swift-typecheck-module-from-interface(%t/Test.swiftinterface) -module-name Test
4+
5+
// RUN: %FileCheck %s --check-prefix INTERFACE --input-file %t/Test.swiftinterface
6+
7+
@frozen public struct Struct {
8+
public var values: [Int] = .init() {
9+
willSet {}
10+
}
11+
}
12+
// INTERFACE: @frozen public struct Struct {
13+
// INTERFACE-LABEL: @_hasStorage public var values: [Swift.Int] = .init() { @_accessorBlock
14+
// INTERFACE-NEXT: @_transparent get
15+
// INTERFACE-NEXT: set
16+
// INTERFACE-NEXT: }
17+
// INTERFACE: }

0 commit comments

Comments
 (0)