Skip to content

Commit 134007a

Browse files
stereotype441Commit Queue
authored and
Commit Queue
committed
Patterns parsing: make it an error to use var before a type in a variable pattern.
Bug: #50035 Change-Id: I46b23ef0d1856401eac4b0a05c6bc6008711d35a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/291780 Commit-Queue: Paul Berry <[email protected]> Reviewed-by: Jens Johansen <[email protected]>
1 parent de2abc6 commit 134007a

File tree

34 files changed

+1170
-4
lines changed

34 files changed

+1170
-4
lines changed

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9832,9 +9832,6 @@ class Parser {
98329832
if (optional('var', next) || optional('final', next)) {
98339833
token = keyword = next;
98349834
bool nextIsParen = optional("(", token.next!);
9835-
// TODO(paulberry): this accepts `var <type> name` as a variable
9836-
// pattern. We want to accept that for error recovery, but don't forget
9837-
// to report the appropriate error.
98389835
typeInfo = computeVariablePatternType(token, nextIsParen);
98399836
token = typeInfo.parseType(token, this);
98409837
} else {
@@ -9860,7 +9857,11 @@ class Parser {
98609857
}
98619858
break;
98629859
case PatternContext.matching:
9863-
// All forms of variable patterns are valid in a matching context.
9860+
// All forms of variable patterns are valid in a matching context. But
9861+
// we do need to check for redundant `var`.
9862+
if (typeInfo != noType && keyword != null && optional('var', keyword)) {
9863+
reportRecoverableError(keyword, codes.messageTypeAfterVar);
9864+
}
98649865
break;
98659866
case PatternContext.assignment:
98669867
// It is a compile-time error if a variable pattern appears in an

pkg/analyzer/test/generated/patterns_parser_test.dart

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3035,6 +3035,35 @@ PatternAssignment
30353035
''');
30363036
}
30373037

3038+
test_declaredVariable_inPatternAssignment_usingVarAndType() {
3039+
_parse('''
3040+
void f() {
3041+
[a, var int d] = y;
3042+
}
3043+
''', errors: [
3044+
error(ParserErrorCode.PATTERN_ASSIGNMENT_DECLARES_VARIABLE, 25, 1),
3045+
]);
3046+
var node = findNode.patternAssignment('=');
3047+
assertParsedNodeText(node, r'''
3048+
PatternAssignment
3049+
pattern: ListPattern
3050+
leftBracket: [
3051+
elements
3052+
AssignedVariablePattern
3053+
name: a
3054+
DeclaredVariablePattern
3055+
keyword: var
3056+
type: NamedType
3057+
name: SimpleIdentifier
3058+
token: int
3059+
name: d
3060+
rightBracket: ]
3061+
equals: =
3062+
expression: SimpleIdentifier
3063+
token: y
3064+
''');
3065+
}
3066+
30383067
test_errorRecovery_afterQuestionSuffixInExpression() {
30393068
// Based on co19 test `Language/Expressions/Conditional/syntax_t06.dart`.
30403069
// Even though we now support suffix `?` in patterns, we need to make sure
@@ -9189,6 +9218,98 @@ NullCheckPattern
91899218
''');
91909219
}
91919220

9221+
test_varKeywordInTypedVariablePattern_declarationContext() {
9222+
_parse('''
9223+
void f(int x) {
9224+
var (var int y) = x;
9225+
}
9226+
''', errors: [
9227+
error(ParserErrorCode.VARIABLE_PATTERN_KEYWORD_IN_DECLARATION_CONTEXT, 23,
9228+
3),
9229+
]);
9230+
var node = findNode.patternVariableDeclaration('= x').pattern;
9231+
assertParsedNodeText(node, r'''
9232+
ParenthesizedPattern
9233+
leftParenthesis: (
9234+
pattern: DeclaredVariablePattern
9235+
keyword: var
9236+
type: NamedType
9237+
name: SimpleIdentifier
9238+
token: int
9239+
name: y
9240+
rightParenthesis: )
9241+
''');
9242+
}
9243+
9244+
test_varKeywordInTypedVariablePattern_declarationContext_wildcard() {
9245+
_parse('''
9246+
void f(x) {
9247+
var (var int _) = x;
9248+
}
9249+
''', errors: [
9250+
error(ParserErrorCode.VARIABLE_PATTERN_KEYWORD_IN_DECLARATION_CONTEXT, 19,
9251+
3),
9252+
]);
9253+
var node = findNode.patternVariableDeclaration('= x').pattern;
9254+
assertParsedNodeText(node, r'''
9255+
ParenthesizedPattern
9256+
leftParenthesis: (
9257+
pattern: WildcardPattern
9258+
keyword: var
9259+
type: NamedType
9260+
name: SimpleIdentifier
9261+
token: int
9262+
name: _
9263+
rightParenthesis: )
9264+
''');
9265+
}
9266+
9267+
test_varKeywordInTypedVariablePattern_matchingContext() {
9268+
_parse('''
9269+
void f(x) {
9270+
switch (x) {
9271+
case var int y:
9272+
break;
9273+
}
9274+
}
9275+
''', errors: [
9276+
error(ParserErrorCode.VAR_AND_TYPE, 36, 3),
9277+
]);
9278+
var node = findNode.singleGuardedPattern;
9279+
assertParsedNodeText(node, r'''
9280+
GuardedPattern
9281+
pattern: DeclaredVariablePattern
9282+
keyword: var
9283+
type: NamedType
9284+
name: SimpleIdentifier
9285+
token: int
9286+
name: y
9287+
''');
9288+
}
9289+
9290+
test_varKeywordInTypedVariablePattern_matchingContext_wildcard() {
9291+
_parse('''
9292+
void f(x) {
9293+
switch (x) {
9294+
case var int _:
9295+
break;
9296+
}
9297+
}
9298+
''', errors: [
9299+
error(ParserErrorCode.VAR_AND_TYPE, 36, 3),
9300+
]);
9301+
var node = findNode.singleGuardedPattern;
9302+
assertParsedNodeText(node, r'''
9303+
GuardedPattern
9304+
pattern: WildcardPattern
9305+
keyword: var
9306+
type: NamedType
9307+
name: SimpleIdentifier
9308+
token: int
9309+
name: _
9310+
''');
9311+
}
9312+
91929313
test_wildcard_bare_beforeWhen() {
91939314
_parse('''
91949315
void f(x) {
@@ -9634,6 +9755,35 @@ PatternAssignment
96349755
''');
96359756
}
96369757

9758+
test_wildcard_inPatternAssignment_usingVarAndType() {
9759+
_parse('''
9760+
void f() {
9761+
[a, var int _] = y;
9762+
}
9763+
''', errors: [
9764+
error(ParserErrorCode.PATTERN_ASSIGNMENT_DECLARES_VARIABLE, 25, 1),
9765+
]);
9766+
var node = findNode.patternAssignment('=');
9767+
assertParsedNodeText(node, r'''
9768+
PatternAssignment
9769+
pattern: ListPattern
9770+
leftBracket: [
9771+
elements
9772+
AssignedVariablePattern
9773+
name: a
9774+
WildcardPattern
9775+
keyword: var
9776+
type: NamedType
9777+
name: SimpleIdentifier
9778+
token: int
9779+
name: _
9780+
rightBracket: ]
9781+
equals: =
9782+
expression: SimpleIdentifier
9783+
token: y
9784+
''');
9785+
}
9786+
96379787
test_wildcard_typed_insideCase() {
96389788
_parse('''
96399789
void f(x) {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
void f() {
2+
[a, var int d] = y;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
Problems reported:
2+
3+
parser/patterns/declaredVariable_inPatternAssignment_usingVarAndType:2:15: Variable 'd' can't be declared in a pattern assignment.
4+
[a, var int d] = y;
5+
^
6+
7+
beginCompilationUnit(void)
8+
beginMetadataStar(void)
9+
endMetadataStar(0)
10+
beginTopLevelMember(void)
11+
beginTopLevelMethod(, null, null)
12+
handleVoidKeyword(void)
13+
handleIdentifier(f, topLevelFunctionDeclaration)
14+
handleNoTypeVariables(()
15+
beginFormalParameters((, MemberKind.TopLevelMethod)
16+
endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
17+
handleAsyncModifier(null, null)
18+
beginBlockFunctionBody({)
19+
handleNoTypeArguments([)
20+
handleAssignedVariablePattern(a)
21+
handleIdentifier(int, typeReference)
22+
handleNoTypeArguments(d)
23+
handleType(int, null)
24+
handleRecoverableError(Message[PatternAssignmentDeclaresVariable, Variable 'd' can't be declared in a pattern assignment., Try using a preexisting variable or changing the assignment to a pattern variable declaration., {name: d}], d, d)
25+
handleDeclaredVariablePattern(var, d, true)
26+
handleListPattern(2, [, ])
27+
handleIdentifier(y, expression)
28+
handleNoTypeArguments(;)
29+
handleNoArguments(;)
30+
handleSend(y, ;)
31+
handlePatternAssignment(=)
32+
handleExpressionStatement(;)
33+
endBlockFunctionBody(1, {, })
34+
endTopLevelMethod(void, null, })
35+
endTopLevelDeclaration()
36+
endCompilationUnit(1, )
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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+
listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
23+
parseAsyncModifierOpt())
24+
listener: handleAsyncModifier(null, null)
25+
inPlainSync()
26+
parseFunctionBody(), false, false)
27+
listener: beginBlockFunctionBody({)
28+
notEofOrValue(}, [)
29+
parseStatement({)
30+
parseStatementX({)
31+
parseExpressionStatementOrDeclaration({, null)
32+
parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, null)
33+
looksLikeLocalFunction([)
34+
parseExpressionStatement({)
35+
parseExpression({)
36+
looksLikeOuterPatternEquals({)
37+
skipOuterPattern({)
38+
parsePatternAssignment({)
39+
parsePattern({, PatternContext.assignment, precedence: 1)
40+
parsePrimaryPattern({, PatternContext.assignment)
41+
listener: handleNoTypeArguments([)
42+
parseListPatternSuffix({, PatternContext.assignment)
43+
parsePattern([, PatternContext.assignment, precedence: 1)
44+
parsePrimaryPattern([, PatternContext.assignment)
45+
parseVariablePattern([, PatternContext.assignment, typeInfo: Instance of 'NoType')
46+
listener: handleAssignedVariablePattern(a)
47+
parsePattern(,, PatternContext.assignment, precedence: 1)
48+
parsePrimaryPattern(,, PatternContext.assignment)
49+
parseVariablePattern(,, PatternContext.assignment, typeInfo: Instance of 'NoType')
50+
listener: handleIdentifier(int, typeReference)
51+
listener: handleNoTypeArguments(d)
52+
listener: handleType(int, null)
53+
reportRecoverableError(d, Message[PatternAssignmentDeclaresVariable, Variable 'd' can't be declared in a pattern assignment., Try using a preexisting variable or changing the assignment to a pattern variable declaration., {name: d}])
54+
listener: handleRecoverableError(Message[PatternAssignmentDeclaresVariable, Variable 'd' can't be declared in a pattern assignment., Try using a preexisting variable or changing the assignment to a pattern variable declaration., {name: d}], d, d)
55+
listener: handleDeclaredVariablePattern(var, d, true)
56+
listener: handleListPattern(2, [, ])
57+
parseExpression(=)
58+
looksLikeOuterPatternEquals(=)
59+
skipOuterPattern(=)
60+
skipObjectPatternRest(y)
61+
parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
62+
parseUnaryExpression(=, true, ConstantPatternContext.none)
63+
parsePrimary(=, expression, ConstantPatternContext.none)
64+
parseSendOrFunctionLiteral(=, expression, ConstantPatternContext.none)
65+
parseSend(=, expression, ConstantPatternContext.none)
66+
isNextIdentifier(=)
67+
ensureIdentifier(=, expression)
68+
listener: handleIdentifier(y, expression)
69+
listener: handleNoTypeArguments(;)
70+
parseArgumentsOpt(y)
71+
listener: handleNoArguments(;)
72+
listener: handleSend(y, ;)
73+
listener: handlePatternAssignment(=)
74+
ensureSemicolon(y)
75+
listener: handleExpressionStatement(;)
76+
notEofOrValue(}, })
77+
listener: endBlockFunctionBody(1, {, })
78+
listener: endTopLevelMethod(void, null, })
79+
listener: endTopLevelDeclaration()
80+
reportAllErrorTokens(void)
81+
listener: endCompilationUnit(1, )
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
void f() {
2+
[a, var int d] = y;
3+
}
4+
5+
6+
void[KeywordToken] f[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
7+
[[BeginToken]a[StringToken],[SimpleToken] var[KeywordToken] int[StringToken] d[StringToken]][SimpleToken] =[SimpleToken] y[StringToken];[SimpleToken]
8+
}[SimpleToken]
9+
[SimpleToken]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
void f() {
2+
[a, var int d] = y;
3+
}
4+
5+
6+
void[KeywordToken] f[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
7+
[[BeginToken]a[StringToken],[SimpleToken] var[KeywordToken] int[StringToken] d[StringToken]][SimpleToken] =[SimpleToken] y[StringToken];[SimpleToken]
8+
}[SimpleToken]
9+
[SimpleToken]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
void f(int x) {
2+
var (var int y) = x;
3+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
Problems reported:
2+
3+
parser/patterns/varKeywordInTypedVariablePattern_declarationContext:2:8: Variable patterns in declaration context can't specify 'var' or 'final' keyword.
4+
var (var int y) = x;
5+
^^^
6+
7+
beginCompilationUnit(void)
8+
beginMetadataStar(void)
9+
endMetadataStar(0)
10+
beginTopLevelMember(void)
11+
beginTopLevelMethod(, null, null)
12+
handleVoidKeyword(void)
13+
handleIdentifier(f, topLevelFunctionDeclaration)
14+
handleNoTypeVariables(()
15+
beginFormalParameters((, MemberKind.TopLevelMethod)
16+
beginMetadataStar(int)
17+
endMetadataStar(0)
18+
beginFormalParameter(int, MemberKind.TopLevelMethod, null, null, null)
19+
handleIdentifier(int, typeReference)
20+
handleNoTypeArguments(x)
21+
handleType(int, null)
22+
handleIdentifier(x, formalParameterDeclaration)
23+
handleFormalParameterWithoutValue())
24+
endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
25+
endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
26+
handleAsyncModifier(null, null)
27+
beginBlockFunctionBody({)
28+
beginMetadataStar(var)
29+
endMetadataStar(0)
30+
handleIdentifier(int, typeReference)
31+
handleNoTypeArguments(y)
32+
handleType(int, null)
33+
handleRecoverableError(VariablePatternKeywordInDeclarationContext, var, var)
34+
handleDeclaredVariablePattern(var, y, false)
35+
handleParenthesizedPattern(()
36+
handleIdentifier(x, expression)
37+
handleNoTypeArguments(;)
38+
handleNoArguments(;)
39+
handleSend(x, ;)
40+
handlePatternVariableDeclarationStatement(var, =, ;)
41+
endBlockFunctionBody(1, {, })
42+
endTopLevelMethod(void, null, })
43+
endTopLevelDeclaration()
44+
endCompilationUnit(1, )

0 commit comments

Comments
 (0)