Skip to content

Commit 4f37821

Browse files
stereotype441Commit Queue
authored and
Commit Queue
committed
Parser: Add assertions to check skipOuterPattern behaviour
The behaviour `skipOuterPattern` needs to be kept in sync with that of `parsePrimaryPattern`. To reduce the risk of these to going out of sync, I've added logic to `parsePrimaryPattern` so that after parsing an `outerPattern`, it asserts that `skipOuterPattern` would have behaved appropriately. This required adding some logic to `parser_test_parser.dart` so that these calls to `skipOuterPattern` don't show up in front_end parser expectations files. (If they did show up, they would lead to failures, since the bots run the front_end parser tests with assertions both enabled and disabled). Bug: #50035 Change-Id: Ida3a37532bb9a86837e70b5ec1aa2e557e3cb769 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/271163 Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Paul Berry <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent 0a7b6d1 commit 4f37821

File tree

5 files changed

+66
-5
lines changed

5 files changed

+66
-5
lines changed

pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,17 @@ class Parser {
335335
{this.useImplicitCreationExpression = true, this.allowPatterns = false})
336336
: assert(listener != null); // ignore:unnecessary_null_comparison
337337

338+
/// Executes [callback]; however if `this` is the `TestParser` (from
339+
/// `pkg/front_end/test/parser_test_parser.dart`) then no output is printed
340+
/// during its execution.
341+
///
342+
/// This is sometimes necessary inside `assert` statements, to ensure that the
343+
/// output of `TestParser` is the same regardless of whether assertions are
344+
/// enabled.
345+
T inhibitPrinting<T>(T Function() callback) {
346+
return callback();
347+
}
348+
338349
bool get inGenerator {
339350
return asyncState == AsyncModifier.AsyncStar ||
340351
asyncState == AsyncModifier.SyncStar;
@@ -9271,6 +9282,7 @@ class Parser {
92719282
/// | 'const' '(' expression ')'
92729283
/// objectPattern ::= typeName typeArguments? '(' patternFields? ')'
92739284
Token parsePrimaryPattern(Token token, {required bool isRefutableContext}) {
9285+
Token start = token;
92749286
TypeParamOrArgInfo typeArg =
92759287
computeTypeParamOrArg(token, /* inDeclaration = */ true);
92769288
Token next = typeArg.skip(token).next!;
@@ -9279,15 +9291,25 @@ class Parser {
92799291
case '[':
92809292
// listPattern ::= typeArguments? '[' patterns? ']'
92819293
token = typeArg.parseArguments(token, this);
9282-
return parseListPatternSuffix(token,
9294+
token = parseListPatternSuffix(token,
92839295
isRefutableContext: isRefutableContext);
9296+
// A list pattern is a valid form of outerPattern, so verify that
9297+
// skipOuterPattern would have skipped this pattern properly.
9298+
assert(
9299+
identical(inhibitPrinting(() => skipOuterPattern(start)), token));
9300+
return token;
92849301
case '{':
92859302
// mapPattern ::= typeArguments? '{' mapPatternEntries? '}'
92869303
// mapPatternEntries ::= mapPatternEntry ( ',' mapPatternEntry )* ','?
92879304
// mapPatternEntry ::= expression ':' pattern
92889305
token = typeArg.parseArguments(token, this);
9289-
return parseMapPatternSuffix(token,
9306+
token = parseMapPatternSuffix(token,
92909307
isRefutableContext: isRefutableContext);
9308+
// A map pattern is a valid form of outerPattern, so verify that
9309+
// skipOuterPattern would have skipped this pattern properly.
9310+
assert(
9311+
identical(inhibitPrinting(() => skipOuterPattern(start)), token));
9312+
return token;
92919313
}
92929314
// Whatever was after the optional type arguments didn't parse as a pattern
92939315
// that can start with type arguments, so back up and reparse assuming that
@@ -9306,11 +9328,17 @@ class Parser {
93069328
Token nextNext = next.next!;
93079329
if (optional(')', nextNext)) {
93089330
listener.handleRecordPattern(next, /* count = */ 0);
9309-
return nextNext;
9331+
token = nextNext;
93109332
} else {
9311-
return parseParenthesizedPatternOrRecordPattern(token,
9333+
token = parseParenthesizedPatternOrRecordPattern(token,
93129334
isRefutableContext: isRefutableContext);
93139335
}
9336+
// A record or parenthesized pattern is a valid form of outerPattern, so
9337+
// verify that skipOuterPattern would have skipped this pattern
9338+
// properly.
9339+
assert(
9340+
identical(inhibitPrinting(() => skipOuterPattern(start)), token));
9341+
return token;
93149342
case 'const':
93159343
// constantPattern ::= booleanLiteral
93169344
// | nullLiteral
@@ -9380,6 +9408,10 @@ class Parser {
93809408
token = parseObjectPatternRest(token,
93819409
isRefutableContext: isRefutableContext);
93829410
listener.handleObjectPattern(firstIdentifier, dot, secondIdentifier);
9411+
// An object pattern is a valid form of outerPattern, so verify that
9412+
// skipOuterPattern would have skipped this pattern properly.
9413+
assert(
9414+
identical(inhibitPrinting(() => skipOuterPattern(start)), token));
93839415
return token;
93849416
} else if (dot == null) {
93859417
// It's a single identifier. If it's a wildcard pattern or we're in an

pkg/front_end/test/parser_test_parser.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class TestParser extends Parser {
3030
int indent = 0;
3131
StringBuffer sb = new StringBuffer();
3232
final bool trace;
33+
bool _inhibitPrinting = false;
3334

3435
TestParser(Listener listener, this.trace, {required bool allowPatterns})
3536
: super(listener,
@@ -51,11 +52,23 @@ class TestParser extends Parser {
5152
}
5253

5354
void doPrint(String s) {
55+
if (_inhibitPrinting) return;
5456
String traceString = "";
5557
if (trace) traceString = " (${createTrace()})";
5658
sb.writeln((" " * indent) + s + traceString);
5759
}
5860

61+
@override
62+
T inhibitPrinting<T>(T Function() callback) {
63+
bool previousInhibitPrinting = _inhibitPrinting;
64+
_inhibitPrinting = true;
65+
try {
66+
return callback();
67+
} finally {
68+
_inhibitPrinting = previousInhibitPrinting;
69+
}
70+
}
71+
5972
@override
6073
Uri? get uri {
6174
doPrint('uri()');

pkg/front_end/test/parser_test_parser_creator.dart

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class TestParser extends Parser {
6767
int indent = 0;
6868
StringBuffer sb = new StringBuffer();
6969
final bool trace;
70+
bool _inhibitPrinting = false;
7071
7172
TestParser(Listener listener, this.trace, {required bool allowPatterns})
7273
: super(listener,
@@ -88,11 +89,22 @@ class TestParser extends Parser {
8889
}
8990
9091
void doPrint(String s) {
92+
if (_inhibitPrinting) return;
9193
String traceString = "";
9294
if (trace) traceString = " (${createTrace()})";
9395
sb.writeln((" " * indent) + s + traceString);
9496
}
9597
98+
@override
99+
T inhibitPrinting<T>(T Function() callback) {
100+
bool previousInhibitPrinting = _inhibitPrinting;
101+
_inhibitPrinting = true;
102+
try {
103+
return callback();
104+
} finally {
105+
_inhibitPrinting = previousInhibitPrinting;
106+
}
107+
}
96108
""");
97109

98110
ParserCreatorListener listener = new ParserCreatorListener(out);
@@ -154,7 +166,9 @@ class ParserCreatorListener extends Listener {
154166
@override
155167
void endClassMethod(Token? getOrSet, Token beginToken, Token beginParam,
156168
Token? beginInitializers, Token endToken) {
157-
if (insideParserClass && !currentMethodName!.startsWith("_")) {
169+
if (insideParserClass &&
170+
!currentMethodName!.startsWith("_") &&
171+
currentMethodName != 'inhibitPrinting') {
158172
Token token = beginToken;
159173
Token? latestToken;
160174
out.writeln(" @override");

pkg/front_end/test/spell_checking_list_code.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,7 @@ inferable
687687
influence
688688
informative
689689
infos
690+
inhibit
690691
init
691692
initializations
692693
initializer's

pkg/front_end/test/spell_checking_list_tests.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ incrementally
358358
increments
359359
indents
360360
ing
361+
inhibit
361362
inlinable
362363
inlineable
363364
insights

0 commit comments

Comments
 (0)