Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 15c8f28

Browse files
stereotype441Commit Queue
authored and
Commit Queue
committed
Fix parsing of single identifier patterns before when.
There's already logic for addressing similar issues before `as`; I just had to generalize it. Bug: dart-lang/sdk#50035 Change-Id: I09d9c69cd291fe8bc3ebea8181f632ddca0c49e8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/271580 Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Paul Berry <[email protected]>
1 parent ff18485 commit 15c8f28

File tree

42 files changed

+1786
-8
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1786
-8
lines changed

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

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -359,14 +359,15 @@ TypeInfo computeVariablePatternType(Token token) {
359359
if (!identical(afterType, token)) {
360360
Token next = afterType.next!;
361361
if (next.isIdentifier) {
362-
if (optional('as', next)) {
363-
// We've seen `TYPE as`. `as` is a built-in identifier, so this
364-
// *could* be a variable pattern. Or it could be that TYPE should
365-
// have been parsed as a pattern. It's probably not a variable
366-
// pattern (since `as` is an unusual variable name), so we'll only
367-
// treat it as a variable pattern if the token following `as` is
368-
// something that could legitimately follow a variable pattern (and
369-
// hence couldn't introduce a type).
362+
if (optional('as', next) || optional('when', next)) {
363+
// We've seen `TYPE as` or `TYPE when`. `as` is a built-in identifier
364+
// and `when` is a pseudo-keyword, so this *could* be a variable
365+
// pattern. Or it could be that TYPE should have been parsed as a
366+
// pattern. It's probably not a variable pattern (since `as` and `when`
367+
// are unusual variable names), so we'll only treat it as a variable
368+
// pattern if the token following `as` or `when` is something that could
369+
// legitimately follow a variable pattern (and hence couldn't introduce
370+
// a type).
370371
if (!mayFollowVariablePattern(next.next!)) {
371372
return noType;
372373
}
@@ -448,6 +449,7 @@ const Set<String> _allowedTokensAfterVariablePattern = {
448449
'}',
449450
']',
450451
'as',
452+
'when',
451453
'?',
452454
'!'
453455
};

pkg/analyzer/test/generated/patterns_parser_test.dart

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,6 +1340,29 @@ ConstantPattern
13401340
''');
13411341
}
13421342

1343+
test_constant_identifier_unprefixed_beforeWhen() {
1344+
_parse('''
1345+
void f(x) {
1346+
const y = 1;
1347+
switch (x) {
1348+
case y when true:
1349+
break;
1350+
}
1351+
}
1352+
''');
1353+
var node = findNode.singleGuardedPattern;
1354+
assertParsedNodeText(node, r'''
1355+
GuardedPattern
1356+
pattern: ConstantPattern
1357+
expression: SimpleIdentifier
1358+
token: y
1359+
whenClause: WhenClause
1360+
whenKeyword: when
1361+
expression: BooleanLiteral
1362+
literal: true
1363+
''');
1364+
}
1365+
13431366
test_constant_identifier_unprefixed_builtin() {
13441367
_parse('''
13451368
void f(x) {
@@ -7038,6 +7061,73 @@ PostfixPattern
70387061
''');
70397062
}
70407063

7064+
test_variable_typedNamedAs_absurd() {
7065+
_parse('''
7066+
void f(x) {
7067+
switch (x) {
7068+
case when as as when when as as when == as as when:
7069+
break;
7070+
}
7071+
}
7072+
''');
7073+
var node = findNode.singleGuardedPattern;
7074+
assertParsedNodeText(node, r'''
7075+
GuardedPattern
7076+
pattern: CastPattern
7077+
pattern: VariablePattern
7078+
type: NamedType
7079+
name: SimpleIdentifier
7080+
token: when
7081+
name: as
7082+
asToken: as
7083+
type: NamedType
7084+
name: SimpleIdentifier
7085+
token: when
7086+
whenClause: WhenClause
7087+
whenKeyword: when
7088+
expression: BinaryExpression
7089+
leftOperand: AsExpression
7090+
expression: SimpleIdentifier
7091+
token: as
7092+
asOperator: as
7093+
type: NamedType
7094+
name: SimpleIdentifier
7095+
token: when
7096+
operator: ==
7097+
rightOperand: AsExpression
7098+
expression: SimpleIdentifier
7099+
token: as
7100+
asOperator: as
7101+
type: NamedType
7102+
name: SimpleIdentifier
7103+
token: when
7104+
''');
7105+
}
7106+
7107+
test_variable_typedNamedAs_beforeWhen() {
7108+
_parse('''
7109+
void f(x) {
7110+
switch (x) {
7111+
case int as when true:
7112+
break;
7113+
}
7114+
}
7115+
''');
7116+
var node = findNode.singleGuardedPattern;
7117+
assertParsedNodeText(node, r'''
7118+
GuardedPattern
7119+
pattern: VariablePattern
7120+
type: NamedType
7121+
name: SimpleIdentifier
7122+
token: int
7123+
name: as
7124+
whenClause: WhenClause
7125+
whenKeyword: when
7126+
expression: BooleanLiteral
7127+
literal: true
7128+
''');
7129+
}
7130+
70417131
test_variable_typedNamedAs_insideCase() {
70427132
_parse('''
70437133
void f(x) {
@@ -7484,6 +7574,101 @@ VariablePattern
74847574
''');
74857575
}
74867576

7577+
test_variable_typedNamedWhen_absurd() {
7578+
_parse('''
7579+
void f(x) {
7580+
switch (x) {
7581+
case int when when when > 0:
7582+
break;
7583+
}
7584+
}
7585+
''');
7586+
var node = findNode.singleGuardedPattern;
7587+
assertParsedNodeText(node, r'''
7588+
GuardedPattern
7589+
pattern: VariablePattern
7590+
type: NamedType
7591+
name: SimpleIdentifier
7592+
token: int
7593+
name: when
7594+
whenClause: WhenClause
7595+
whenKeyword: when
7596+
expression: BinaryExpression
7597+
leftOperand: SimpleIdentifier
7598+
token: when
7599+
operator: >
7600+
rightOperand: IntegerLiteral
7601+
literal: 0
7602+
''');
7603+
}
7604+
7605+
test_variable_typedNamedWhen_beforeWhen() {
7606+
_parse('''
7607+
void f(x) {
7608+
switch (x) {
7609+
case int when when true:
7610+
break;
7611+
}
7612+
}
7613+
''');
7614+
var node = findNode.singleGuardedPattern;
7615+
assertParsedNodeText(node, r'''
7616+
GuardedPattern
7617+
pattern: VariablePattern
7618+
type: NamedType
7619+
name: SimpleIdentifier
7620+
token: int
7621+
name: when
7622+
whenClause: WhenClause
7623+
whenKeyword: when
7624+
expression: BooleanLiteral
7625+
literal: true
7626+
''');
7627+
}
7628+
7629+
test_variable_typedNamedWhen_insideCase() {
7630+
_parse('''
7631+
void f(x) {
7632+
switch (x) {
7633+
case int when:
7634+
break;
7635+
}
7636+
}
7637+
''');
7638+
var node = findNode.singleGuardedPattern.pattern;
7639+
assertParsedNodeText(node, r'''
7640+
VariablePattern
7641+
type: NamedType
7642+
name: SimpleIdentifier
7643+
token: int
7644+
name: when
7645+
''');
7646+
}
7647+
7648+
test_variable_typedNamedWhen_insideCast() {
7649+
_parse('''
7650+
void f(x) {
7651+
switch (x) {
7652+
case int when as Object:
7653+
break;
7654+
}
7655+
}
7656+
''');
7657+
var node = findNode.singleGuardedPattern.pattern;
7658+
assertParsedNodeText(node, r'''
7659+
CastPattern
7660+
pattern: VariablePattern
7661+
type: NamedType
7662+
name: SimpleIdentifier
7663+
token: int
7664+
name: when
7665+
asToken: as
7666+
type: NamedType
7667+
name: SimpleIdentifier
7668+
token: Object
7669+
''');
7670+
}
7671+
74877672
test_variable_var_insideCase() {
74887673
_parse('''
74897674
void f(x) {
@@ -7578,6 +7763,27 @@ PostfixPattern
75787763
''');
75797764
}
75807765

7766+
test_wildcard_bare_beforeWhen() {
7767+
_parse('''
7768+
void f(x) {
7769+
switch (x) {
7770+
case _ when true:
7771+
break;
7772+
}
7773+
}
7774+
''');
7775+
var node = findNode.singleGuardedPattern;
7776+
assertParsedNodeText(node, r'''
7777+
GuardedPattern
7778+
pattern: VariablePattern
7779+
name: _
7780+
whenClause: WhenClause
7781+
whenKeyword: when
7782+
expression: BooleanLiteral
7783+
literal: true
7784+
''');
7785+
}
7786+
75817787
test_wildcard_bare_insideCase() {
75827788
_parse('''
75837789
void f(x) {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
void f(x) {
2+
const y = 1;
3+
switch (x) {
4+
case y when true:
5+
break;
6+
}
7+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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+
beginMetadataStar(const)
21+
endMetadataStar(0)
22+
handleNoType(const)
23+
beginVariablesDeclaration(y, null, const)
24+
handleIdentifier(y, localVariableDeclaration)
25+
beginInitializedIdentifier(y)
26+
beginVariableInitializer(=)
27+
handleLiteralInt(1)
28+
endVariableInitializer(=)
29+
endInitializedIdentifier(y)
30+
endVariablesDeclaration(1, ;)
31+
beginSwitchStatement(switch)
32+
handleIdentifier(x, expression)
33+
handleNoTypeArguments())
34+
handleNoArguments())
35+
handleSend(x, ))
36+
handleParenthesizedCondition((, null, null)
37+
beginSwitchBlock({)
38+
beginCaseExpression(case)
39+
handleIdentifier(y, expression)
40+
handleNoTypeArguments(when)
41+
handleNoArguments(when)
42+
handleSend(y, when)
43+
handleConstantPattern(null)
44+
handleLiteralBool(true)
45+
endCaseExpression(case, when, :)
46+
beginSwitchCase(0, 1, case)
47+
handleBreakStatement(false, break, ;)
48+
endSwitchCase(0, 1, null, null, 1, case, })
49+
endSwitchBlock(1, {, })
50+
endSwitchStatement(switch, })
51+
endBlockFunctionBody(2, {, })
52+
endTopLevelMethod(void, null, })
53+
endTopLevelDeclaration()
54+
endCompilationUnit(1, )

0 commit comments

Comments
 (0)