Skip to content

Commit 701a0d2

Browse files
stereotype441Commit Queue
authored and
Commit Queue
committed
Add support for expression statements beginning with a map pattern.
Bug: #50035, dart-lang/language#2662 Change-Id: Ifb141cf563848fc0035423a625e27585cce2ea57 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/272523 Commit-Queue: Paul Berry <[email protected]> Reviewed-by: Jens Johansen <[email protected]>
1 parent 3e00e6a commit 701a0d2

12 files changed

+343
-1
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5240,7 +5240,12 @@ class Parser {
52405240
final String? value = token.next!.stringValue;
52415241
if (identical(value, '{')) {
52425242
// The scanner ensures that `{` always has a closing `}`.
5243-
return parseBlock(token, BlockKind.statement);
5243+
if (allowPatterns && optional('=', token.next!.endGroup!.next!)) {
5244+
// Expression statement beginning with a pattern assignment
5245+
return parseExpressionStatement(token);
5246+
} else {
5247+
return parseBlock(token, BlockKind.statement);
5248+
}
52445249
} else if (identical(value, 'return')) {
52455250
return parseReturnStatement(token);
52465251
} else if (identical(value, 'var') || identical(value, 'final')) {

pkg/analyzer/test/generated/patterns_parser_test.dart

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3944,6 +3944,20 @@ MapPattern
39443944
''');
39453945
}
39463946

3947+
test_map_insideAssignment_untyped_empty_beginningOfStatement() {
3948+
_parse('''
3949+
void f(x) {
3950+
{} = x;
3951+
}
3952+
''');
3953+
var node = findNode.patternAssignment('= x').pattern;
3954+
assertParsedNodeText(node, r'''
3955+
MapPattern
3956+
leftBracket: {
3957+
rightBracket: }
3958+
''');
3959+
}
3960+
39473961
test_map_insideAssignment_untyped_nonEmpty() {
39483962
// Note: statements aren't allowed to start with `{` so we need parens
39493963
// around the assignment. See
@@ -3974,6 +3988,33 @@ MapPattern
39743988
''');
39753989
}
39763990

3991+
test_map_insideAssignment_untyped_nonEmpty_beginningOfStatement() {
3992+
_parse('''
3993+
void f(x) {
3994+
{'a': a, 'b': b} = x;
3995+
}
3996+
''');
3997+
var node = findNode.patternAssignment('= x').pattern;
3998+
assertParsedNodeText(node, r'''
3999+
MapPattern
4000+
leftBracket: {
4001+
elements
4002+
MapPatternEntry
4003+
key: SimpleStringLiteral
4004+
literal: 'a'
4005+
separator: :
4006+
value: VariablePattern
4007+
name: a
4008+
MapPatternEntry
4009+
key: SimpleStringLiteral
4010+
literal: 'b'
4011+
separator: :
4012+
value: VariablePattern
4013+
name: b
4014+
rightBracket: }
4015+
''');
4016+
}
4017+
39774018
test_map_insideCase_typed_nonEmpty() {
39784019
_parse('''
39794020
void f(x) {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
void f(x) {
2+
{} = x;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
beginCompilationUnit(void)
2+
beginMetadataStar(void)
3+
endMetadataStar(0)
4+
beginTopLevelMember(void)
5+
beginTopLevelMethod(, null, null)
6+
handleVoidKeyword(void)
7+
handleIdentifier(f, topLevelFunctionDeclaration)
8+
handleNoTypeVariables(()
9+
beginFormalParameters((, MemberKind.TopLevelMethod)
10+
beginMetadataStar(x)
11+
endMetadataStar(0)
12+
beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
13+
handleNoType(()
14+
handleIdentifier(x, formalParameterDeclaration)
15+
handleFormalParameterWithoutValue())
16+
endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
17+
endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
18+
handleAsyncModifier(null, null)
19+
beginBlockFunctionBody({)
20+
handleNoTypeArguments({)
21+
handleMapPattern(0, {, })
22+
handleIdentifier(x, expression)
23+
handleNoTypeArguments(;)
24+
handleNoArguments(;)
25+
handleSend(x, ;)
26+
handlePatternAssignment(=)
27+
handleExpressionStatement(;)
28+
endBlockFunctionBody(1, {, })
29+
endTopLevelMethod(void, null, })
30+
endTopLevelDeclaration()
31+
endCompilationUnit(1, )
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
parseUnit(void)
2+
skipErrorTokens(void)
3+
listener: beginCompilationUnit(void)
4+
syntheticPreviousToken(void)
5+
parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
6+
parseMetadataStar()
7+
listener: beginMetadataStar(void)
8+
listener: endMetadataStar(0)
9+
parseTopLevelMemberImpl()
10+
listener: beginTopLevelMember(void)
11+
parseTopLevelMethod(, null, null, , Instance of 'VoidType', null, f, false)
12+
listener: beginTopLevelMethod(, null, null)
13+
listener: handleVoidKeyword(void)
14+
ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
15+
listener: handleIdentifier(f, topLevelFunctionDeclaration)
16+
parseMethodTypeVar(f)
17+
listener: handleNoTypeVariables(()
18+
parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
19+
parseFormalParameters(f, MemberKind.TopLevelMethod)
20+
parseFormalParametersRest((, MemberKind.TopLevelMethod)
21+
listener: beginFormalParameters((, MemberKind.TopLevelMethod)
22+
parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
23+
parseMetadataStar(()
24+
listener: beginMetadataStar(x)
25+
listener: endMetadataStar(0)
26+
listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
27+
listener: handleNoType(()
28+
ensureIdentifier((, formalParameterDeclaration)
29+
listener: handleIdentifier(x, formalParameterDeclaration)
30+
listener: handleFormalParameterWithoutValue())
31+
listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
32+
listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
33+
parseAsyncModifierOpt())
34+
listener: handleAsyncModifier(null, null)
35+
inPlainSync()
36+
parseFunctionBody(), false, false)
37+
listener: beginBlockFunctionBody({)
38+
notEofOrValue(}, {)
39+
parseStatement({)
40+
parseStatementX({)
41+
parseExpressionStatement({)
42+
parseExpression({)
43+
looksLikeOuterPatternEquals({)
44+
skipOuterPattern({)
45+
parsePatternAssignment({)
46+
parsePattern({, precedence: 1, isRefutableContext: false)
47+
parsePrimaryPattern({, isRefutableContext: false)
48+
listener: handleNoTypeArguments({)
49+
parseMapPatternSuffix({, isRefutableContext: false)
50+
listener: handleMapPattern(0, {, })
51+
parseExpression(=)
52+
looksLikeOuterPatternEquals(=)
53+
skipOuterPattern(=)
54+
skipObjectPatternRest(x)
55+
parsePrecedenceExpression(=, 1, true)
56+
parseUnaryExpression(=, true)
57+
parsePrimary(=, expression)
58+
parseSendOrFunctionLiteral(=, expression)
59+
parseSend(=, expression)
60+
isNextIdentifier(=)
61+
ensureIdentifier(=, expression)
62+
listener: handleIdentifier(x, expression)
63+
listener: handleNoTypeArguments(;)
64+
parseArgumentsOpt(x)
65+
listener: handleNoArguments(;)
66+
listener: handleSend(x, ;)
67+
listener: handlePatternAssignment(=)
68+
ensureSemicolon(x)
69+
listener: handleExpressionStatement(;)
70+
notEofOrValue(}, })
71+
listener: endBlockFunctionBody(1, {, })
72+
listener: endTopLevelMethod(void, null, })
73+
listener: endTopLevelDeclaration()
74+
reportAllErrorTokens(void)
75+
listener: endCompilationUnit(1, )
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
void f(x) {
2+
{} = x;
3+
}
4+
5+
6+
void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
7+
{[BeginToken]}[SimpleToken] =[SimpleToken] x[StringToken];[SimpleToken]
8+
}[SimpleToken]
9+
[SimpleToken]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
void f(x) {
2+
{} = x;
3+
}
4+
5+
6+
void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
7+
{[BeginToken]}[SimpleToken] =[SimpleToken] x[StringToken];[SimpleToken]
8+
}[SimpleToken]
9+
[SimpleToken]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
void f(x) {
2+
{'a': a, 'b': b} = x;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
beginCompilationUnit(void)
2+
beginMetadataStar(void)
3+
endMetadataStar(0)
4+
beginTopLevelMember(void)
5+
beginTopLevelMethod(, null, null)
6+
handleVoidKeyword(void)
7+
handleIdentifier(f, topLevelFunctionDeclaration)
8+
handleNoTypeVariables(()
9+
beginFormalParameters((, MemberKind.TopLevelMethod)
10+
beginMetadataStar(x)
11+
endMetadataStar(0)
12+
beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
13+
handleNoType(()
14+
handleIdentifier(x, formalParameterDeclaration)
15+
handleFormalParameterWithoutValue())
16+
endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
17+
endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
18+
handleAsyncModifier(null, null)
19+
beginBlockFunctionBody({)
20+
handleNoTypeArguments({)
21+
beginLiteralString('a')
22+
endLiteralString(0, :)
23+
handleNoType(:)
24+
handleVariablePattern(null, a)
25+
handleMapPatternEntry(:, ,)
26+
beginLiteralString('b')
27+
endLiteralString(0, :)
28+
handleNoType(:)
29+
handleVariablePattern(null, b)
30+
handleMapPatternEntry(:, })
31+
handleMapPattern(2, {, })
32+
handleIdentifier(x, expression)
33+
handleNoTypeArguments(;)
34+
handleNoArguments(;)
35+
handleSend(x, ;)
36+
handlePatternAssignment(=)
37+
handleExpressionStatement(;)
38+
endBlockFunctionBody(1, {, })
39+
endTopLevelMethod(void, null, })
40+
endTopLevelDeclaration()
41+
endCompilationUnit(1, )
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
parseUnit(void)
2+
skipErrorTokens(void)
3+
listener: beginCompilationUnit(void)
4+
syntheticPreviousToken(void)
5+
parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
6+
parseMetadataStar()
7+
listener: beginMetadataStar(void)
8+
listener: endMetadataStar(0)
9+
parseTopLevelMemberImpl()
10+
listener: beginTopLevelMember(void)
11+
parseTopLevelMethod(, null, null, , Instance of 'VoidType', null, f, false)
12+
listener: beginTopLevelMethod(, null, null)
13+
listener: handleVoidKeyword(void)
14+
ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
15+
listener: handleIdentifier(f, topLevelFunctionDeclaration)
16+
parseMethodTypeVar(f)
17+
listener: handleNoTypeVariables(()
18+
parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
19+
parseFormalParameters(f, MemberKind.TopLevelMethod)
20+
parseFormalParametersRest((, MemberKind.TopLevelMethod)
21+
listener: beginFormalParameters((, MemberKind.TopLevelMethod)
22+
parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
23+
parseMetadataStar(()
24+
listener: beginMetadataStar(x)
25+
listener: endMetadataStar(0)
26+
listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
27+
listener: handleNoType(()
28+
ensureIdentifier((, formalParameterDeclaration)
29+
listener: handleIdentifier(x, formalParameterDeclaration)
30+
listener: handleFormalParameterWithoutValue())
31+
listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
32+
listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
33+
parseAsyncModifierOpt())
34+
listener: handleAsyncModifier(null, null)
35+
inPlainSync()
36+
parseFunctionBody(), false, false)
37+
listener: beginBlockFunctionBody({)
38+
notEofOrValue(}, {)
39+
parseStatement({)
40+
parseStatementX({)
41+
parseExpressionStatement({)
42+
parseExpression({)
43+
looksLikeOuterPatternEquals({)
44+
skipOuterPattern({)
45+
parsePatternAssignment({)
46+
parsePattern({, precedence: 1, isRefutableContext: false)
47+
parsePrimaryPattern({, isRefutableContext: false)
48+
listener: handleNoTypeArguments({)
49+
parseMapPatternSuffix({, isRefutableContext: false)
50+
parseExpression({)
51+
looksLikeOuterPatternEquals({)
52+
skipOuterPattern({)
53+
parsePrecedenceExpression({, 1, true)
54+
parseUnaryExpression({, true)
55+
parsePrimary({, expression)
56+
parseLiteralString({)
57+
parseSingleLiteralString({)
58+
listener: beginLiteralString('a')
59+
listener: endLiteralString(0, :)
60+
parsePattern(:, precedence: 1, isRefutableContext: false)
61+
parsePrimaryPattern(:, isRefutableContext: false)
62+
parseVariablePattern(:, typeInfo: Instance of 'NoType')
63+
listener: handleNoType(:)
64+
listener: handleVariablePattern(null, a)
65+
listener: handleMapPatternEntry(:, ,)
66+
parseExpression(,)
67+
looksLikeOuterPatternEquals(,)
68+
skipOuterPattern(,)
69+
parsePrecedenceExpression(,, 1, true)
70+
parseUnaryExpression(,, true)
71+
parsePrimary(,, expression)
72+
parseLiteralString(,)
73+
parseSingleLiteralString(,)
74+
listener: beginLiteralString('b')
75+
listener: endLiteralString(0, :)
76+
parsePattern(:, precedence: 1, isRefutableContext: false)
77+
parsePrimaryPattern(:, isRefutableContext: false)
78+
parseVariablePattern(:, typeInfo: Instance of 'NoType')
79+
listener: handleNoType(:)
80+
listener: handleVariablePattern(null, b)
81+
listener: handleMapPatternEntry(:, })
82+
listener: handleMapPattern(2, {, })
83+
parseExpression(=)
84+
looksLikeOuterPatternEquals(=)
85+
skipOuterPattern(=)
86+
skipObjectPatternRest(x)
87+
parsePrecedenceExpression(=, 1, true)
88+
parseUnaryExpression(=, true)
89+
parsePrimary(=, expression)
90+
parseSendOrFunctionLiteral(=, expression)
91+
parseSend(=, expression)
92+
isNextIdentifier(=)
93+
ensureIdentifier(=, expression)
94+
listener: handleIdentifier(x, expression)
95+
listener: handleNoTypeArguments(;)
96+
parseArgumentsOpt(x)
97+
listener: handleNoArguments(;)
98+
listener: handleSend(x, ;)
99+
listener: handlePatternAssignment(=)
100+
ensureSemicolon(x)
101+
listener: handleExpressionStatement(;)
102+
notEofOrValue(}, })
103+
listener: endBlockFunctionBody(1, {, })
104+
listener: endTopLevelMethod(void, null, })
105+
listener: endTopLevelDeclaration()
106+
reportAllErrorTokens(void)
107+
listener: endCompilationUnit(1, )
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
void f(x) {
2+
{'a': a, 'b': b} = x;
3+
}
4+
5+
6+
void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
7+
{[BeginToken]'a'[StringToken]:[SimpleToken] a[StringToken],[SimpleToken] 'b'[StringToken]:[SimpleToken] b[StringToken]}[SimpleToken] =[SimpleToken] x[StringToken];[SimpleToken]
8+
}[SimpleToken]
9+
[SimpleToken]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
void f(x) {
2+
{'a': a, 'b': b} = x;
3+
}
4+
5+
6+
void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
7+
{[BeginToken]'a'[StringToken]:[SimpleToken] a[StringToken],[SimpleToken] 'b'[StringToken]:[SimpleToken] b[StringToken]}[SimpleToken] =[SimpleToken] x[StringToken];[SimpleToken]
8+
}[SimpleToken]
9+
[SimpleToken]

0 commit comments

Comments
 (0)