Skip to content

Commit 7b41b62

Browse files
stereotype441Commit Queue
authored and
Commit Queue
committed
Add parser support for patternAssignment.
Bug: #50035, #50502, #50575 Change-Id: Idd3bdcae7cbb95c6f2016bb5d3efc638867f52af Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/272383 Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Paul Berry <[email protected]>
1 parent e1acab8 commit 7b41b62

File tree

396 files changed

+3311
-7
lines changed

Some content is hidden

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

396 files changed

+3311
-7
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1994,6 +1994,11 @@ class ForwardingListener implements Listener {
19941994
keyword, equals, semicolon);
19951995
}
19961996

1997+
@override
1998+
void handlePatternAssignment(Token equals) {
1999+
listener?.handlePatternAssignment(equals);
2000+
}
2001+
19972002
@override
19982003
void logEvent(String name) {
19992004
listener?.logEvent(name);

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,4 +2139,13 @@ class Listener implements UnescapeErrorListener {
21392139
Token keyword, Token equals, Token semicolon) {
21402140
logEvent('PatternVariableDeclarationStatement');
21412141
}
2142+
2143+
/// Called after the parser has processed a pattern assignment consisting of
2144+
/// `PATTERN EQUALS EXPRESSION`.
2145+
///
2146+
/// PATTERN may only be one of the patterns accepted by the `outerPattern`
2147+
/// grammar rule defined in the patterns spec.
2148+
void handlePatternAssignment(Token equals) {
2149+
logEvent("PatternAssignment");
2150+
}
21422151
}

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

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5466,10 +5466,14 @@ class Parser {
54665466
listener.handleIdentifier(token, IdentifierContext.expression);
54675467
}
54685468
} else {
5469-
token = optional('throw', token.next!)
5470-
? parseThrowExpression(token, /* allowCascades = */ true)
5471-
: parsePrecedenceExpression(
5472-
token, ASSIGNMENT_PRECEDENCE, /* allowCascades = */ true);
5469+
if (allowPatterns && looksLikeOuterPatternEquals(token)) {
5470+
token = parsePatternAssignment(token);
5471+
} else {
5472+
token = optional('throw', token.next!)
5473+
? parseThrowExpression(token, /* allowCascades = */ true)
5474+
: parsePrecedenceExpression(
5475+
token, ASSIGNMENT_PRECEDENCE, /* allowCascades = */ true);
5476+
}
54735477
}
54745478
expressionDepth--;
54755479
return token;
@@ -9796,7 +9800,8 @@ class Parser {
97969800
if (next.isIdentifier) {
97979801
return skipObjectPatternRest(next);
97989802
} else {
9799-
throw new UnimplementedError('TODO(paulberry)');
9803+
// IDENTIFIER `.` NON-IDENTIFIER (not a pattern)
9804+
return null;
98009805
}
98019806
}
98029807
TypeParamOrArgInfo typeParamOrArg = computeTypeParamOrArg(token);
@@ -9847,6 +9852,17 @@ class Parser {
98479852
return semicolon;
98489853
}
98499854

9855+
/// patternAssignment ::= outerPattern '=' expression
9856+
Token parsePatternAssignment(Token token) {
9857+
token = parsePattern(token, isRefutableContext: false);
9858+
Token equals = token.next!;
9859+
// Caller should have assured that the pattern was followed by an `=`.
9860+
assert(optional('=', equals));
9861+
token = parseExpression(equals);
9862+
listener.handlePatternAssignment(equals);
9863+
return token;
9864+
}
9865+
98509866
/// switchExpression ::= 'switch' '(' expression ')' '{'
98519867
/// switchExpressionCase ( ',' switchExpressionCase )*
98529868
/// ','? '}'

pkg/analyzer/lib/src/fasta/ast_builder.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4810,6 +4810,14 @@ class AstBuilder extends StackListener {
48104810
rightParenthesis: leftParenthesis.endGroup!));
48114811
}
48124812

4813+
@override
4814+
void handlePatternAssignment(Token equals) {
4815+
var expression = pop() as ExpressionImpl;
4816+
var pattern = pop() as DartPatternImpl;
4817+
push(PatternAssignmentImpl(
4818+
pattern: pattern, equals: equals, expression: expression));
4819+
}
4820+
48134821
@override
48144822
void handlePatternField(Token? colon) {
48154823
debugEvent("PatternField");

pkg/analyzer/test/generated/patterns_parser_test.dart

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2913,6 +2913,79 @@ f() {
29132913
]);
29142914
}
29152915

2916+
test_list_insideAssignment_typed_nonEmpty() {
2917+
_parse('''
2918+
void f(x) {
2919+
<int>[a, b] = x;
2920+
}
2921+
''');
2922+
var node = findNode.patternAssignment('= x').pattern;
2923+
assertParsedNodeText(node, r'''
2924+
ListPattern
2925+
typeArguments: TypeArgumentList
2926+
leftBracket: <
2927+
arguments
2928+
NamedType
2929+
name: SimpleIdentifier
2930+
token: int
2931+
rightBracket: >
2932+
leftBracket: [
2933+
elements
2934+
VariablePattern
2935+
name: a
2936+
VariablePattern
2937+
name: b
2938+
rightBracket: ]
2939+
''');
2940+
}
2941+
2942+
test_list_insideAssignment_untyped_empty() {
2943+
_parse('''
2944+
void f(x) {
2945+
[] = x;
2946+
}
2947+
''');
2948+
var node = findNode.patternAssignment('= x').pattern;
2949+
assertParsedNodeText(node, r'''
2950+
ListPattern
2951+
leftBracket: [
2952+
rightBracket: ]
2953+
''');
2954+
}
2955+
2956+
test_list_insideAssignment_untyped_emptyWithWhitespace() {
2957+
_parse('''
2958+
void f(x) {
2959+
[ ] = x;
2960+
}
2961+
''');
2962+
var node = findNode.patternAssignment('= x').pattern;
2963+
assertParsedNodeText(node, r'''
2964+
ListPattern
2965+
leftBracket: [
2966+
rightBracket: ]
2967+
''');
2968+
}
2969+
2970+
test_list_insideAssignment_untyped_nonEmpty() {
2971+
_parse('''
2972+
void f(x) {
2973+
[a, b] = x;
2974+
}
2975+
''');
2976+
var node = findNode.patternAssignment('= x').pattern;
2977+
assertParsedNodeText(node, r'''
2978+
ListPattern
2979+
leftBracket: [
2980+
elements
2981+
VariablePattern
2982+
name: a
2983+
VariablePattern
2984+
name: b
2985+
rightBracket: ]
2986+
''');
2987+
}
2988+
29162989
test_list_insideCase_typed_nonEmpty() {
29172990
_parse('''
29182991
void f(x) {
@@ -3817,6 +3890,90 @@ BinaryPattern
38173890
''');
38183891
}
38193892

3893+
test_map_insideAssignment_typed_nonEmpty() {
3894+
_parse('''
3895+
void f(x) {
3896+
<String, int>{'a': a, 'b': b} = x;
3897+
}
3898+
''');
3899+
var node = findNode.patternAssignment('= x').pattern;
3900+
assertParsedNodeText(node, r'''
3901+
MapPattern
3902+
typeArguments: TypeArgumentList
3903+
leftBracket: <
3904+
arguments
3905+
NamedType
3906+
name: SimpleIdentifier
3907+
token: String
3908+
NamedType
3909+
name: SimpleIdentifier
3910+
token: int
3911+
rightBracket: >
3912+
leftBracket: {
3913+
elements
3914+
MapPatternEntry
3915+
key: SimpleStringLiteral
3916+
literal: 'a'
3917+
separator: :
3918+
value: VariablePattern
3919+
name: a
3920+
MapPatternEntry
3921+
key: SimpleStringLiteral
3922+
literal: 'b'
3923+
separator: :
3924+
value: VariablePattern
3925+
name: b
3926+
rightBracket: }
3927+
''');
3928+
}
3929+
3930+
test_map_insideAssignment_untyped_empty() {
3931+
// Note: statements aren't allowed to start with `{` so we need parens
3932+
// around the assignment. See
3933+
// https://github.com/dart-lang/language/issues/2662.
3934+
_parse('''
3935+
void f(x) {
3936+
({} = x);
3937+
}
3938+
''');
3939+
var node = findNode.patternAssignment('= x').pattern;
3940+
assertParsedNodeText(node, r'''
3941+
MapPattern
3942+
leftBracket: {
3943+
rightBracket: }
3944+
''');
3945+
}
3946+
3947+
test_map_insideAssignment_untyped_nonEmpty() {
3948+
// Note: statements aren't allowed to start with `{` so we need parens
3949+
// around the assignment. See
3950+
// https://github.com/dart-lang/language/issues/2662.
3951+
_parse('''
3952+
void f(x) {
3953+
({'a': a, 'b': b} = x);
3954+
}
3955+
''');
3956+
var node = findNode.patternAssignment('= x').pattern;
3957+
assertParsedNodeText(node, r'''
3958+
MapPattern
3959+
leftBracket: {
3960+
elements
3961+
MapPatternEntry
3962+
key: SimpleStringLiteral
3963+
literal: 'a'
3964+
separator: :
3965+
value: VariablePattern
3966+
name: a
3967+
MapPatternEntry
3968+
key: SimpleStringLiteral
3969+
literal: 'b'
3970+
separator: :
3971+
value: VariablePattern
3972+
name: b
3973+
rightBracket: }
3974+
''');
3975+
}
3976+
38203977
test_map_insideCase_typed_nonEmpty() {
38213978
_parse('''
38223979
void f(x) {
@@ -4792,6 +4949,34 @@ RecordPattern
47924949
''');
47934950
}
47944951

4952+
test_object_prefixed_withTypeArgs_insideAssignment() {
4953+
_parse('''
4954+
void f(x) {
4955+
async.Future<int>() = x;
4956+
}
4957+
''');
4958+
var node = findNode.patternAssignment('= x').pattern;
4959+
assertParsedNodeText(node, r'''
4960+
ObjectPattern
4961+
type: NamedType
4962+
name: PrefixedIdentifier
4963+
prefix: SimpleIdentifier
4964+
token: async
4965+
period: .
4966+
identifier: SimpleIdentifier
4967+
token: Future
4968+
typeArguments: TypeArgumentList
4969+
leftBracket: <
4970+
arguments
4971+
NamedType
4972+
name: SimpleIdentifier
4973+
token: int
4974+
rightBracket: >
4975+
leftParenthesis: (
4976+
rightParenthesis: )
4977+
''');
4978+
}
4979+
47954980
test_object_prefixed_withTypeArgs_insideCase() {
47964981
_parse('''
47974982
import 'dart:async' as async;
@@ -5335,6 +5520,22 @@ ObjectPattern
53355520
''');
53365521
}
53375522

5523+
test_parenthesized_insideAssignment() {
5524+
_parse('''
5525+
f(x) {
5526+
(a) = x;
5527+
}
5528+
''');
5529+
var node = findNode.patternAssignment('= x').pattern;
5530+
assertParsedNodeText(node, r'''
5531+
ParenthesizedPattern
5532+
leftParenthesis: (
5533+
pattern: VariablePattern
5534+
name: a
5535+
rightParenthesis: )
5536+
''');
5537+
}
5538+
53385539
test_parenthesized_insideCase() {
53395540
_parse('''
53405541
f(x) {
@@ -6040,6 +6241,59 @@ PatternVariableDeclarationStatement
60406241
''');
60416242
}
60426243

6244+
test_record_insideAssignment_empty() {
6245+
_parse('''
6246+
void f(x) {
6247+
() = x;
6248+
}
6249+
''');
6250+
var node = findNode.patternAssignment('= x').pattern;
6251+
assertParsedNodeText(node, r'''
6252+
RecordPattern
6253+
leftParenthesis: (
6254+
rightParenthesis: )
6255+
''');
6256+
}
6257+
6258+
test_record_insideAssignment_oneField() {
6259+
_parse('''
6260+
void f(x) {
6261+
(a,) = x;
6262+
}
6263+
''');
6264+
var node = findNode.patternAssignment('= x').pattern;
6265+
assertParsedNodeText(node, r'''
6266+
RecordPattern
6267+
leftParenthesis: (
6268+
fields
6269+
RecordPatternField
6270+
pattern: VariablePattern
6271+
name: a
6272+
rightParenthesis: )
6273+
''');
6274+
}
6275+
6276+
test_record_insideAssignment_twoFields() {
6277+
_parse('''
6278+
void f(x) {
6279+
(a, b) = x;
6280+
}
6281+
''');
6282+
var node = findNode.patternAssignment('= x').pattern;
6283+
assertParsedNodeText(node, r'''
6284+
RecordPattern
6285+
leftParenthesis: (
6286+
fields
6287+
RecordPatternField
6288+
pattern: VariablePattern
6289+
name: a
6290+
RecordPatternField
6291+
pattern: VariablePattern
6292+
name: b
6293+
rightParenthesis: )
6294+
''');
6295+
}
6296+
60436297
test_record_insideCase_empty() {
60446298
_parse('''
60456299
void f(x) {

pkg/analyzer/test/src/dart/resolution/assignment_test.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -599,13 +599,16 @@ AssignmentExpression
599599
}
600600

601601
test_notLValue_parenthesized_simple() async {
602+
// TODO(paulberry): remove `// @dart = 2.18` - see
603+
// https://github.com/dart-lang/sdk/issues/50502
602604
await assertErrorsInCode(r'''
605+
// @dart = 2.18
603606
void f(int a, int b, double c) {
604607
(a + b) = c;
605608
}
606609
''', [
607-
error(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 35, 7),
608-
error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 35, 7),
610+
error(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 51, 7),
611+
error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 51, 7),
609612
]);
610613

611614
var assignment = findNode.assignment('= c');

0 commit comments

Comments
 (0)