From a445fae68158275f5cda46e9b26e065200bc9dc2 Mon Sep 17 00:00:00 2001 From: Jens Johansen Date: Fri, 11 Aug 2023 09:19:31 +0000 Subject: [PATCH] [parser] Fix issue 52954 about nested record destructuring with shorthand Fixes https://github.com/dart-lang/sdk/issues/52954 Change-Id: I41e229380ccc16aa8bab0696fa79ca701a43220f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/317681 Reviewed-by: Brian Wilkerson Commit-Queue: Jens Johansen Reviewed-by: Johnni Winther --- .../lib/src/parser/parser_impl.dart | 7 +- .../patterns/issue_52954.dart | 5 + .../patterns/issue_52954.dart.expect | 94 +++++++ .../issue_52954.dart.intertwined.expect | 249 +++++++++++++++++ .../patterns/issue_52954.dart.parser.expect | 13 + .../patterns/issue_52954.dart.scanner.expect | 13 + .../patterns/issue_52954.equivalence_info | 8 + .../patterns/issue_52954_prime.dart | 5 + .../patterns/issue_52954_prime.dart.expect | 94 +++++++ .../issue_52954_prime.dart.intertwined.expect | 250 ++++++++++++++++++ .../issue_52954_prime.dart.parser.expect | 13 + .../issue_52954_prime.dart.scanner.expect | 13 + 12 files changed, 763 insertions(+), 1 deletion(-) create mode 100644 pkg/front_end/parser_testcases/patterns/issue_52954.dart create mode 100644 pkg/front_end/parser_testcases/patterns/issue_52954.dart.expect create mode 100644 pkg/front_end/parser_testcases/patterns/issue_52954.dart.intertwined.expect create mode 100644 pkg/front_end/parser_testcases/patterns/issue_52954.dart.parser.expect create mode 100644 pkg/front_end/parser_testcases/patterns/issue_52954.dart.scanner.expect create mode 100644 pkg/front_end/parser_testcases/patterns/issue_52954.equivalence_info create mode 100644 pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart create mode 100644 pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.expect create mode 100644 pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.intertwined.expect create mode 100644 pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.parser.expect create mode 100644 pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.scanner.expect diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart index 44e8b2b8387..df7f4516e7d 100644 --- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart +++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart @@ -9942,7 +9942,9 @@ class Parser { wasValidRecord = true; listener.handleNoName(token); colon = token = next; - } else if (optional(':', next.next!)) { + } else if (!optional('(', next) && optional(':', next.next!)) { + // We don't allow `next` to be `(` here because + // `((:a, :b), :c, :d)` (and similar) is fine. // Record with named expression. wasRecord = true; token = ensureIdentifier( @@ -10010,6 +10012,9 @@ class Parser { listener.handleNoName(token); colon = token = next; } else if (optional(':', next.next!)) { + // This is different from `parseParenthesizedPatternOrRecordPattern` + // because this isn't valid because of the missing name: + // `var Point((:x, :y), :z) = Point((x: 1, y: 2), 3);` token = ensureIdentifier(token, IdentifierContext.namedArgumentReference) .next!; diff --git a/pkg/front_end/parser_testcases/patterns/issue_52954.dart b/pkg/front_end/parser_testcases/patterns/issue_52954.dart new file mode 100644 index 00000000000..59a6e8593eb --- /dev/null +++ b/pkg/front_end/parser_testcases/patterns/issue_52954.dart @@ -0,0 +1,5 @@ +main() { + final record = ((a: 1, b: 2), 3); + final ((:a, :b), c) = record; + print("a = $a; b = $b, c = $c"); +} diff --git a/pkg/front_end/parser_testcases/patterns/issue_52954.dart.expect b/pkg/front_end/parser_testcases/patterns/issue_52954.dart.expect new file mode 100644 index 00000000000..d164a55d201 --- /dev/null +++ b/pkg/front_end/parser_testcases/patterns/issue_52954.dart.expect @@ -0,0 +1,94 @@ +beginCompilationUnit(main) + beginMetadataStar(main) + endMetadataStar(0) + beginTopLevelMember(main) + beginTopLevelMethod(, null, null) + handleNoType() + handleIdentifier(main, topLevelFunctionDeclaration) + handleNoTypeVariables(() + beginFormalParameters((, MemberKind.TopLevelMethod) + endFormalParameters(0, (, ), MemberKind.TopLevelMethod) + handleAsyncModifier(null, null) + beginBlockFunctionBody({) + beginMetadataStar(final) + endMetadataStar(0) + handleNoType(final) + beginVariablesDeclaration(record, null, final) + handleIdentifier(record, localVariableDeclaration) + beginInitializedIdentifier(record) + beginVariableInitializer(=) + beginParenthesizedExpressionOrRecordLiteral(() + beginParenthesizedExpressionOrRecordLiteral(() + handleIdentifier(a, namedRecordFieldReference) + handleLiteralInt(1) + handleNamedRecordField(:) + handleIdentifier(b, namedRecordFieldReference) + handleLiteralInt(2) + handleNamedRecordField(:) + endRecordLiteral((, 2, null) + handleLiteralInt(3) + endRecordLiteral((, 2, null) + endVariableInitializer(=) + endInitializedIdentifier(record) + endVariablesDeclaration(1, ;) + beginMetadataStar(final) + endMetadataStar(0) + beginPattern(final) + beginPattern(() + handleNoName(() + beginPattern(:) + handleNoType(a) + handleDeclaredVariablePattern(null, a, false) + endPattern(a) + handlePatternField(:) + handleNoName(,) + beginPattern(:) + handleNoType(b) + handleDeclaredVariablePattern(null, b, false) + endPattern(b) + handlePatternField(:) + handleRecordPattern((, 2) + endPattern()) + handlePatternField(null) + beginPattern(,) + handleNoType(c) + handleDeclaredVariablePattern(null, c, false) + endPattern(c) + handlePatternField(null) + handleRecordPattern((, 2) + endPattern()) + handleIdentifier(record, expression) + handleNoTypeArguments(;) + handleNoArguments(;) + handleSend(record, ;) + handlePatternVariableDeclarationStatement(final, =, ;) + handleIdentifier(print, expression) + handleNoTypeArguments(() + beginArguments(() + beginLiteralString("a = ) + handleIdentifier(a, expression) + handleNoTypeArguments(; b = ) + handleNoArguments(; b = ) + handleSend(a, ; b = ) + handleInterpolationExpression($, null) + handleStringPart(; b = ) + handleIdentifier(b, expression) + handleNoTypeArguments(, c = ) + handleNoArguments(, c = ) + handleSend(b, , c = ) + handleInterpolationExpression($, null) + handleStringPart(, c = ) + handleIdentifier(c, expression) + handleNoTypeArguments(") + handleNoArguments(") + handleSend(c, ") + handleInterpolationExpression($, null) + handleStringPart(") + endLiteralString(3, )) + endArguments(1, (, )) + handleSend(print, ;) + handleExpressionStatement(;) + endBlockFunctionBody(3, {, }) + endTopLevelMethod(main, null, }) + endTopLevelDeclaration() +endCompilationUnit(1, ) diff --git a/pkg/front_end/parser_testcases/patterns/issue_52954.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/issue_52954.dart.intertwined.expect new file mode 100644 index 00000000000..28187f30235 --- /dev/null +++ b/pkg/front_end/parser_testcases/patterns/issue_52954.dart.intertwined.expect @@ -0,0 +1,249 @@ +parseUnit(main) + skipErrorTokens(main) + listener: beginCompilationUnit(main) + syntheticPreviousToken(main) + parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext') + parseMetadataStar() + listener: beginMetadataStar(main) + listener: endMetadataStar(0) + parseTopLevelMemberImpl() + listener: beginTopLevelMember(main) + isReservedKeyword(() + parseTopLevelMethod(, null, null, , Instance of 'NoType', null, main, false) + listener: beginTopLevelMethod(, null, null) + listener: handleNoType() + ensureIdentifierPotentiallyRecovered(, topLevelFunctionDeclaration, false) + listener: handleIdentifier(main, topLevelFunctionDeclaration) + parseMethodTypeVar(main) + listener: handleNoTypeVariables(() + parseGetterOrFormalParameters(main, main, false, MemberKind.TopLevelMethod) + parseFormalParameters(main, MemberKind.TopLevelMethod) + parseFormalParametersRest((, MemberKind.TopLevelMethod) + listener: beginFormalParameters((, MemberKind.TopLevelMethod) + listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod) + parseAsyncModifierOpt()) + listener: handleAsyncModifier(null, null) + inPlainSync() + parseFunctionBody(), false, false) + listener: beginBlockFunctionBody({) + notEofOrValue(}, final) + parseStatement({) + parseStatementX({) + parseExpressionStatementOrDeclarationAfterModifiers(final, {, null, final, null, null) + skipOuterPattern(final) + skipObjectPatternRest(record) + looksLikeLocalFunction(record) + listener: beginMetadataStar(final) + listener: endMetadataStar(0) + listener: handleNoType(final) + listener: beginVariablesDeclaration(record, null, final) + parseVariablesDeclarationRest(final, true) + parseOptionallyInitializedIdentifier(final) + ensureIdentifier(final, localVariableDeclaration) + listener: handleIdentifier(record, localVariableDeclaration) + listener: beginInitializedIdentifier(record) + parseVariableInitializerOpt(record) + listener: beginVariableInitializer(=) + parseExpression(=) + looksLikeOuterPatternEquals(=) + skipOuterPattern(=) + parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none) + parseUnaryExpression(=, true, ConstantPatternContext.none) + parsePrimary(=, expression, ConstantPatternContext.none) + parseParenthesizedExpressionFunctionLiteralOrRecordLiteral(=, ConstantPatternContext.none) + parseParenthesizedExpressionOrRecordLiteral(=, null, ConstantPatternContext.none) + listener: beginParenthesizedExpressionOrRecordLiteral(() + parseExpression(() + looksLikeOuterPatternEquals(() + skipOuterPattern(() + parsePrecedenceExpression((, 1, true, ConstantPatternContext.none) + parseUnaryExpression((, true, ConstantPatternContext.none) + parsePrimary((, expression, ConstantPatternContext.none) + parseParenthesizedExpressionFunctionLiteralOrRecordLiteral((, ConstantPatternContext.none) + parseParenthesizedExpressionOrRecordLiteral((, null, ConstantPatternContext.none) + listener: beginParenthesizedExpressionOrRecordLiteral(() + ensureIdentifier((, namedRecordFieldReference) + listener: handleIdentifier(a, namedRecordFieldReference) + parseExpression(:) + looksLikeOuterPatternEquals(:) + skipOuterPattern(:) + parsePrecedenceExpression(:, 1, true, ConstantPatternContext.none) + parseUnaryExpression(:, true, ConstantPatternContext.none) + parsePrimary(:, expression, ConstantPatternContext.none) + parseLiteralInt(:) + listener: handleLiteralInt(1) + listener: handleNamedRecordField(:) + ensureIdentifier(,, namedRecordFieldReference) + listener: handleIdentifier(b, namedRecordFieldReference) + parseExpression(:) + looksLikeOuterPatternEquals(:) + skipOuterPattern(:) + parsePrecedenceExpression(:, 1, true, ConstantPatternContext.none) + parseUnaryExpression(:, true, ConstantPatternContext.none) + parsePrimary(:, expression, ConstantPatternContext.none) + parseLiteralInt(:) + listener: handleLiteralInt(2) + listener: handleNamedRecordField(:) + ensureCloseParen(2, () + listener: endRecordLiteral((, 2, null) + parseExpression(,) + looksLikeOuterPatternEquals(,) + skipOuterPattern(,) + parsePrecedenceExpression(,, 1, true, ConstantPatternContext.none) + parseUnaryExpression(,, true, ConstantPatternContext.none) + parsePrimary(,, expression, ConstantPatternContext.none) + parseLiteralInt(,) + listener: handleLiteralInt(3) + ensureCloseParen(3, () + listener: endRecordLiteral((, 2, null) + listener: endVariableInitializer(=) + listener: endInitializedIdentifier(record) + ensureSemicolon()) + listener: endVariablesDeclaration(1, ;) + notEofOrValue(}, final) + parseStatement(;) + parseStatementX(;) + parseExpressionStatementOrDeclarationAfterModifiers(final, ;, null, final, null, null) + skipOuterPattern(final) + listener: beginMetadataStar(final) + listener: endMetadataStar(0) + parsePatternVariableDeclarationStatement(final, ;, final) + parsePattern(final, PatternContext.declaration, precedence: 1) + listener: beginPattern(final) + parsePrimaryPattern(final, PatternContext.declaration) + parseParenthesizedPatternOrRecordPattern(final, PatternContext.declaration) + parsePattern((, PatternContext.declaration, precedence: 1) + listener: beginPattern(() + parsePrimaryPattern((, PatternContext.declaration) + parseParenthesizedPatternOrRecordPattern((, PatternContext.declaration) + listener: handleNoName(() + parsePattern(:, PatternContext.declaration, precedence: 1) + listener: beginPattern(:) + parsePrimaryPattern(:, PatternContext.declaration) + parseVariablePattern(:, PatternContext.declaration, typeInfo: Instance of 'NoType') + listener: handleNoType(a) + listener: handleDeclaredVariablePattern(null, a, false) + listener: endPattern(a) + listener: handlePatternField(:) + listener: handleNoName(,) + parsePattern(:, PatternContext.declaration, precedence: 1) + listener: beginPattern(:) + parsePrimaryPattern(:, PatternContext.declaration) + parseVariablePattern(:, PatternContext.declaration, typeInfo: Instance of 'NoType') + listener: handleNoType(b) + listener: handleDeclaredVariablePattern(null, b, false) + listener: endPattern(b) + listener: handlePatternField(:) + ensureCloseParen(b, () + listener: handleRecordPattern((, 2) + listener: endPattern()) + listener: handlePatternField(null) + parsePattern(,, PatternContext.declaration, precedence: 1) + listener: beginPattern(,) + parsePrimaryPattern(,, PatternContext.declaration) + parseVariablePattern(,, PatternContext.declaration, typeInfo: Instance of 'NoType') + listener: handleNoType(c) + listener: handleDeclaredVariablePattern(null, c, false) + listener: endPattern(c) + listener: handlePatternField(null) + ensureCloseParen(c, () + listener: handleRecordPattern((, 2) + listener: endPattern()) + parseExpression(=) + looksLikeOuterPatternEquals(=) + skipOuterPattern(=) + skipObjectPatternRest(record) + parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none) + parseUnaryExpression(=, true, ConstantPatternContext.none) + parsePrimary(=, expression, ConstantPatternContext.none) + parseSendOrFunctionLiteral(=, expression, ConstantPatternContext.none) + parseSend(=, expression, ConstantPatternContext.none) + isNextIdentifier(=) + ensureIdentifier(=, expression) + listener: handleIdentifier(record, expression) + listener: handleNoTypeArguments(;) + parseArgumentsOpt(record) + listener: handleNoArguments(;) + listener: handleSend(record, ;) + ensureSemicolon(record) + listener: handlePatternVariableDeclarationStatement(final, =, ;) + notEofOrValue(}, print) + parseStatement(;) + parseStatementX(;) + parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, null) + looksLikeLocalFunction(print) + parseExpressionStatement(;) + parseExpression(;) + looksLikeOuterPatternEquals(;) + skipOuterPattern(;) + skipObjectPatternRest(print) + parsePrecedenceExpression(;, 1, true, ConstantPatternContext.none) + parseUnaryExpression(;, true, ConstantPatternContext.none) + parsePrimary(;, expression, ConstantPatternContext.none) + parseSendOrFunctionLiteral(;, expression, ConstantPatternContext.none) + looksLikeFunctionBody(;) + parseSend(;, expression, ConstantPatternContext.none) + isNextIdentifier(;) + ensureIdentifier(;, expression) + listener: handleIdentifier(print, expression) + listener: handleNoTypeArguments(() + parseArgumentsOpt(print) + parseArguments(print) + parseArgumentsRest(() + listener: beginArguments(() + parseExpression(() + looksLikeOuterPatternEquals(() + skipOuterPattern(() + parsePrecedenceExpression((, 1, true, ConstantPatternContext.none) + parseUnaryExpression((, true, ConstantPatternContext.none) + parsePrimary((, expression, ConstantPatternContext.none) + parseLiteralString(() + parseSingleLiteralString(() + listener: beginLiteralString("a = ) + parseIdentifierExpression($) + parseSend($, expression, ConstantPatternContext.none) + isNextIdentifier($) + ensureIdentifier($, expression) + listener: handleIdentifier(a, expression) + listener: handleNoTypeArguments(; b = ) + parseArgumentsOpt(a) + listener: handleNoArguments(; b = ) + listener: handleSend(a, ; b = ) + listener: handleInterpolationExpression($, null) + parseStringPart(a) + listener: handleStringPart(; b = ) + parseIdentifierExpression($) + parseSend($, expression, ConstantPatternContext.none) + isNextIdentifier($) + ensureIdentifier($, expression) + listener: handleIdentifier(b, expression) + listener: handleNoTypeArguments(, c = ) + parseArgumentsOpt(b) + listener: handleNoArguments(, c = ) + listener: handleSend(b, , c = ) + listener: handleInterpolationExpression($, null) + parseStringPart(b) + listener: handleStringPart(, c = ) + parseIdentifierExpression($) + parseSend($, expression, ConstantPatternContext.none) + isNextIdentifier($) + ensureIdentifier($, expression) + listener: handleIdentifier(c, expression) + listener: handleNoTypeArguments(") + parseArgumentsOpt(c) + listener: handleNoArguments(") + listener: handleSend(c, ") + listener: handleInterpolationExpression($, null) + parseStringPart(c) + listener: handleStringPart(") + listener: endLiteralString(3, )) + listener: endArguments(1, (, )) + listener: handleSend(print, ;) + ensureSemicolon()) + listener: handleExpressionStatement(;) + notEofOrValue(}, }) + listener: endBlockFunctionBody(3, {, }) + listener: endTopLevelMethod(main, null, }) + listener: endTopLevelDeclaration() + reportAllErrorTokens(main) + listener: endCompilationUnit(1, ) diff --git a/pkg/front_end/parser_testcases/patterns/issue_52954.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/issue_52954.dart.parser.expect new file mode 100644 index 00000000000..8730a96dfad --- /dev/null +++ b/pkg/front_end/parser_testcases/patterns/issue_52954.dart.parser.expect @@ -0,0 +1,13 @@ +main() { +final record = ((a: 1, b: 2), 3); +final ((:a, :b), c) = record; +print("a = $a; b = $b, c = $c"); +} + + +main[StringToken]([BeginToken])[SimpleToken] {[BeginToken] +final[KeywordToken] record[StringToken] =[SimpleToken] ([BeginToken]([BeginToken]a[StringToken]:[SimpleToken] 1[StringToken],[SimpleToken] b[StringToken]:[SimpleToken] 2[StringToken])[SimpleToken],[SimpleToken] 3[StringToken])[SimpleToken];[SimpleToken] +final[KeywordToken] ([BeginToken]([BeginToken]:[SimpleToken]a[StringToken],[SimpleToken] :[SimpleToken]b[StringToken])[SimpleToken],[SimpleToken] c[StringToken])[SimpleToken] =[SimpleToken] record[StringToken];[SimpleToken] +print[StringToken]([BeginToken]"a = [StringToken]$[SimpleToken]a[StringToken]; b = [StringToken]$[SimpleToken]b[StringToken], c = [StringToken]$[SimpleToken]c[StringToken]"[StringToken])[SimpleToken];[SimpleToken] +}[SimpleToken] +[SimpleToken] diff --git a/pkg/front_end/parser_testcases/patterns/issue_52954.dart.scanner.expect b/pkg/front_end/parser_testcases/patterns/issue_52954.dart.scanner.expect new file mode 100644 index 00000000000..8730a96dfad --- /dev/null +++ b/pkg/front_end/parser_testcases/patterns/issue_52954.dart.scanner.expect @@ -0,0 +1,13 @@ +main() { +final record = ((a: 1, b: 2), 3); +final ((:a, :b), c) = record; +print("a = $a; b = $b, c = $c"); +} + + +main[StringToken]([BeginToken])[SimpleToken] {[BeginToken] +final[KeywordToken] record[StringToken] =[SimpleToken] ([BeginToken]([BeginToken]a[StringToken]:[SimpleToken] 1[StringToken],[SimpleToken] b[StringToken]:[SimpleToken] 2[StringToken])[SimpleToken],[SimpleToken] 3[StringToken])[SimpleToken];[SimpleToken] +final[KeywordToken] ([BeginToken]([BeginToken]:[SimpleToken]a[StringToken],[SimpleToken] :[SimpleToken]b[StringToken])[SimpleToken],[SimpleToken] c[StringToken])[SimpleToken] =[SimpleToken] record[StringToken];[SimpleToken] +print[StringToken]([BeginToken]"a = [StringToken]$[SimpleToken]a[StringToken]; b = [StringToken]$[SimpleToken]b[StringToken], c = [StringToken]$[SimpleToken]c[StringToken]"[StringToken])[SimpleToken];[SimpleToken] +}[SimpleToken] +[SimpleToken] diff --git a/pkg/front_end/parser_testcases/patterns/issue_52954.equivalence_info b/pkg/front_end/parser_testcases/patterns/issue_52954.equivalence_info new file mode 100644 index 00000000000..4584c2ce890 --- /dev/null +++ b/pkg/front_end/parser_testcases/patterns/issue_52954.equivalence_info @@ -0,0 +1,8 @@ +files: + - issue_52954.dart + - issue_52954_prime.dart +filters: + - ignoreListenerArguments +ignored: + - handleNoName + - handleIdentifier diff --git a/pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart b/pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart new file mode 100644 index 00000000000..3739340eb73 --- /dev/null +++ b/pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart @@ -0,0 +1,5 @@ +main() { + final record = ((a: 1, b: 2), 3); + final ((a: a, :b), c) = record; + print("a = $a; b = $b, c = $c"); +} diff --git a/pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.expect b/pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.expect new file mode 100644 index 00000000000..ec1d069f1e5 --- /dev/null +++ b/pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.expect @@ -0,0 +1,94 @@ +beginCompilationUnit(main) + beginMetadataStar(main) + endMetadataStar(0) + beginTopLevelMember(main) + beginTopLevelMethod(, null, null) + handleNoType() + handleIdentifier(main, topLevelFunctionDeclaration) + handleNoTypeVariables(() + beginFormalParameters((, MemberKind.TopLevelMethod) + endFormalParameters(0, (, ), MemberKind.TopLevelMethod) + handleAsyncModifier(null, null) + beginBlockFunctionBody({) + beginMetadataStar(final) + endMetadataStar(0) + handleNoType(final) + beginVariablesDeclaration(record, null, final) + handleIdentifier(record, localVariableDeclaration) + beginInitializedIdentifier(record) + beginVariableInitializer(=) + beginParenthesizedExpressionOrRecordLiteral(() + beginParenthesizedExpressionOrRecordLiteral(() + handleIdentifier(a, namedRecordFieldReference) + handleLiteralInt(1) + handleNamedRecordField(:) + handleIdentifier(b, namedRecordFieldReference) + handleLiteralInt(2) + handleNamedRecordField(:) + endRecordLiteral((, 2, null) + handleLiteralInt(3) + endRecordLiteral((, 2, null) + endVariableInitializer(=) + endInitializedIdentifier(record) + endVariablesDeclaration(1, ;) + beginMetadataStar(final) + endMetadataStar(0) + beginPattern(final) + beginPattern(() + handleIdentifier(a, namedRecordFieldReference) + beginPattern(:) + handleNoType(a) + handleDeclaredVariablePattern(null, a, false) + endPattern(a) + handlePatternField(:) + handleNoName(,) + beginPattern(:) + handleNoType(b) + handleDeclaredVariablePattern(null, b, false) + endPattern(b) + handlePatternField(:) + handleRecordPattern((, 2) + endPattern()) + handlePatternField(null) + beginPattern(,) + handleNoType(c) + handleDeclaredVariablePattern(null, c, false) + endPattern(c) + handlePatternField(null) + handleRecordPattern((, 2) + endPattern()) + handleIdentifier(record, expression) + handleNoTypeArguments(;) + handleNoArguments(;) + handleSend(record, ;) + handlePatternVariableDeclarationStatement(final, =, ;) + handleIdentifier(print, expression) + handleNoTypeArguments(() + beginArguments(() + beginLiteralString("a = ) + handleIdentifier(a, expression) + handleNoTypeArguments(; b = ) + handleNoArguments(; b = ) + handleSend(a, ; b = ) + handleInterpolationExpression($, null) + handleStringPart(; b = ) + handleIdentifier(b, expression) + handleNoTypeArguments(, c = ) + handleNoArguments(, c = ) + handleSend(b, , c = ) + handleInterpolationExpression($, null) + handleStringPart(, c = ) + handleIdentifier(c, expression) + handleNoTypeArguments(") + handleNoArguments(") + handleSend(c, ") + handleInterpolationExpression($, null) + handleStringPart(") + endLiteralString(3, )) + endArguments(1, (, )) + handleSend(print, ;) + handleExpressionStatement(;) + endBlockFunctionBody(3, {, }) + endTopLevelMethod(main, null, }) + endTopLevelDeclaration() +endCompilationUnit(1, ) diff --git a/pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.intertwined.expect new file mode 100644 index 00000000000..54da510fa5e --- /dev/null +++ b/pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.intertwined.expect @@ -0,0 +1,250 @@ +parseUnit(main) + skipErrorTokens(main) + listener: beginCompilationUnit(main) + syntheticPreviousToken(main) + parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext') + parseMetadataStar() + listener: beginMetadataStar(main) + listener: endMetadataStar(0) + parseTopLevelMemberImpl() + listener: beginTopLevelMember(main) + isReservedKeyword(() + parseTopLevelMethod(, null, null, , Instance of 'NoType', null, main, false) + listener: beginTopLevelMethod(, null, null) + listener: handleNoType() + ensureIdentifierPotentiallyRecovered(, topLevelFunctionDeclaration, false) + listener: handleIdentifier(main, topLevelFunctionDeclaration) + parseMethodTypeVar(main) + listener: handleNoTypeVariables(() + parseGetterOrFormalParameters(main, main, false, MemberKind.TopLevelMethod) + parseFormalParameters(main, MemberKind.TopLevelMethod) + parseFormalParametersRest((, MemberKind.TopLevelMethod) + listener: beginFormalParameters((, MemberKind.TopLevelMethod) + listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod) + parseAsyncModifierOpt()) + listener: handleAsyncModifier(null, null) + inPlainSync() + parseFunctionBody(), false, false) + listener: beginBlockFunctionBody({) + notEofOrValue(}, final) + parseStatement({) + parseStatementX({) + parseExpressionStatementOrDeclarationAfterModifiers(final, {, null, final, null, null) + skipOuterPattern(final) + skipObjectPatternRest(record) + looksLikeLocalFunction(record) + listener: beginMetadataStar(final) + listener: endMetadataStar(0) + listener: handleNoType(final) + listener: beginVariablesDeclaration(record, null, final) + parseVariablesDeclarationRest(final, true) + parseOptionallyInitializedIdentifier(final) + ensureIdentifier(final, localVariableDeclaration) + listener: handleIdentifier(record, localVariableDeclaration) + listener: beginInitializedIdentifier(record) + parseVariableInitializerOpt(record) + listener: beginVariableInitializer(=) + parseExpression(=) + looksLikeOuterPatternEquals(=) + skipOuterPattern(=) + parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none) + parseUnaryExpression(=, true, ConstantPatternContext.none) + parsePrimary(=, expression, ConstantPatternContext.none) + parseParenthesizedExpressionFunctionLiteralOrRecordLiteral(=, ConstantPatternContext.none) + parseParenthesizedExpressionOrRecordLiteral(=, null, ConstantPatternContext.none) + listener: beginParenthesizedExpressionOrRecordLiteral(() + parseExpression(() + looksLikeOuterPatternEquals(() + skipOuterPattern(() + parsePrecedenceExpression((, 1, true, ConstantPatternContext.none) + parseUnaryExpression((, true, ConstantPatternContext.none) + parsePrimary((, expression, ConstantPatternContext.none) + parseParenthesizedExpressionFunctionLiteralOrRecordLiteral((, ConstantPatternContext.none) + parseParenthesizedExpressionOrRecordLiteral((, null, ConstantPatternContext.none) + listener: beginParenthesizedExpressionOrRecordLiteral(() + ensureIdentifier((, namedRecordFieldReference) + listener: handleIdentifier(a, namedRecordFieldReference) + parseExpression(:) + looksLikeOuterPatternEquals(:) + skipOuterPattern(:) + parsePrecedenceExpression(:, 1, true, ConstantPatternContext.none) + parseUnaryExpression(:, true, ConstantPatternContext.none) + parsePrimary(:, expression, ConstantPatternContext.none) + parseLiteralInt(:) + listener: handleLiteralInt(1) + listener: handleNamedRecordField(:) + ensureIdentifier(,, namedRecordFieldReference) + listener: handleIdentifier(b, namedRecordFieldReference) + parseExpression(:) + looksLikeOuterPatternEquals(:) + skipOuterPattern(:) + parsePrecedenceExpression(:, 1, true, ConstantPatternContext.none) + parseUnaryExpression(:, true, ConstantPatternContext.none) + parsePrimary(:, expression, ConstantPatternContext.none) + parseLiteralInt(:) + listener: handleLiteralInt(2) + listener: handleNamedRecordField(:) + ensureCloseParen(2, () + listener: endRecordLiteral((, 2, null) + parseExpression(,) + looksLikeOuterPatternEquals(,) + skipOuterPattern(,) + parsePrecedenceExpression(,, 1, true, ConstantPatternContext.none) + parseUnaryExpression(,, true, ConstantPatternContext.none) + parsePrimary(,, expression, ConstantPatternContext.none) + parseLiteralInt(,) + listener: handleLiteralInt(3) + ensureCloseParen(3, () + listener: endRecordLiteral((, 2, null) + listener: endVariableInitializer(=) + listener: endInitializedIdentifier(record) + ensureSemicolon()) + listener: endVariablesDeclaration(1, ;) + notEofOrValue(}, final) + parseStatement(;) + parseStatementX(;) + parseExpressionStatementOrDeclarationAfterModifiers(final, ;, null, final, null, null) + skipOuterPattern(final) + listener: beginMetadataStar(final) + listener: endMetadataStar(0) + parsePatternVariableDeclarationStatement(final, ;, final) + parsePattern(final, PatternContext.declaration, precedence: 1) + listener: beginPattern(final) + parsePrimaryPattern(final, PatternContext.declaration) + parseParenthesizedPatternOrRecordPattern(final, PatternContext.declaration) + parsePattern((, PatternContext.declaration, precedence: 1) + listener: beginPattern(() + parsePrimaryPattern((, PatternContext.declaration) + parseParenthesizedPatternOrRecordPattern((, PatternContext.declaration) + ensureIdentifier((, namedRecordFieldReference) + listener: handleIdentifier(a, namedRecordFieldReference) + parsePattern(:, PatternContext.declaration, precedence: 1) + listener: beginPattern(:) + parsePrimaryPattern(:, PatternContext.declaration) + parseVariablePattern(:, PatternContext.declaration, typeInfo: Instance of 'NoType') + listener: handleNoType(a) + listener: handleDeclaredVariablePattern(null, a, false) + listener: endPattern(a) + listener: handlePatternField(:) + listener: handleNoName(,) + parsePattern(:, PatternContext.declaration, precedence: 1) + listener: beginPattern(:) + parsePrimaryPattern(:, PatternContext.declaration) + parseVariablePattern(:, PatternContext.declaration, typeInfo: Instance of 'NoType') + listener: handleNoType(b) + listener: handleDeclaredVariablePattern(null, b, false) + listener: endPattern(b) + listener: handlePatternField(:) + ensureCloseParen(b, () + listener: handleRecordPattern((, 2) + listener: endPattern()) + listener: handlePatternField(null) + parsePattern(,, PatternContext.declaration, precedence: 1) + listener: beginPattern(,) + parsePrimaryPattern(,, PatternContext.declaration) + parseVariablePattern(,, PatternContext.declaration, typeInfo: Instance of 'NoType') + listener: handleNoType(c) + listener: handleDeclaredVariablePattern(null, c, false) + listener: endPattern(c) + listener: handlePatternField(null) + ensureCloseParen(c, () + listener: handleRecordPattern((, 2) + listener: endPattern()) + parseExpression(=) + looksLikeOuterPatternEquals(=) + skipOuterPattern(=) + skipObjectPatternRest(record) + parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none) + parseUnaryExpression(=, true, ConstantPatternContext.none) + parsePrimary(=, expression, ConstantPatternContext.none) + parseSendOrFunctionLiteral(=, expression, ConstantPatternContext.none) + parseSend(=, expression, ConstantPatternContext.none) + isNextIdentifier(=) + ensureIdentifier(=, expression) + listener: handleIdentifier(record, expression) + listener: handleNoTypeArguments(;) + parseArgumentsOpt(record) + listener: handleNoArguments(;) + listener: handleSend(record, ;) + ensureSemicolon(record) + listener: handlePatternVariableDeclarationStatement(final, =, ;) + notEofOrValue(}, print) + parseStatement(;) + parseStatementX(;) + parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, null) + looksLikeLocalFunction(print) + parseExpressionStatement(;) + parseExpression(;) + looksLikeOuterPatternEquals(;) + skipOuterPattern(;) + skipObjectPatternRest(print) + parsePrecedenceExpression(;, 1, true, ConstantPatternContext.none) + parseUnaryExpression(;, true, ConstantPatternContext.none) + parsePrimary(;, expression, ConstantPatternContext.none) + parseSendOrFunctionLiteral(;, expression, ConstantPatternContext.none) + looksLikeFunctionBody(;) + parseSend(;, expression, ConstantPatternContext.none) + isNextIdentifier(;) + ensureIdentifier(;, expression) + listener: handleIdentifier(print, expression) + listener: handleNoTypeArguments(() + parseArgumentsOpt(print) + parseArguments(print) + parseArgumentsRest(() + listener: beginArguments(() + parseExpression(() + looksLikeOuterPatternEquals(() + skipOuterPattern(() + parsePrecedenceExpression((, 1, true, ConstantPatternContext.none) + parseUnaryExpression((, true, ConstantPatternContext.none) + parsePrimary((, expression, ConstantPatternContext.none) + parseLiteralString(() + parseSingleLiteralString(() + listener: beginLiteralString("a = ) + parseIdentifierExpression($) + parseSend($, expression, ConstantPatternContext.none) + isNextIdentifier($) + ensureIdentifier($, expression) + listener: handleIdentifier(a, expression) + listener: handleNoTypeArguments(; b = ) + parseArgumentsOpt(a) + listener: handleNoArguments(; b = ) + listener: handleSend(a, ; b = ) + listener: handleInterpolationExpression($, null) + parseStringPart(a) + listener: handleStringPart(; b = ) + parseIdentifierExpression($) + parseSend($, expression, ConstantPatternContext.none) + isNextIdentifier($) + ensureIdentifier($, expression) + listener: handleIdentifier(b, expression) + listener: handleNoTypeArguments(, c = ) + parseArgumentsOpt(b) + listener: handleNoArguments(, c = ) + listener: handleSend(b, , c = ) + listener: handleInterpolationExpression($, null) + parseStringPart(b) + listener: handleStringPart(, c = ) + parseIdentifierExpression($) + parseSend($, expression, ConstantPatternContext.none) + isNextIdentifier($) + ensureIdentifier($, expression) + listener: handleIdentifier(c, expression) + listener: handleNoTypeArguments(") + parseArgumentsOpt(c) + listener: handleNoArguments(") + listener: handleSend(c, ") + listener: handleInterpolationExpression($, null) + parseStringPart(c) + listener: handleStringPart(") + listener: endLiteralString(3, )) + listener: endArguments(1, (, )) + listener: handleSend(print, ;) + ensureSemicolon()) + listener: handleExpressionStatement(;) + notEofOrValue(}, }) + listener: endBlockFunctionBody(3, {, }) + listener: endTopLevelMethod(main, null, }) + listener: endTopLevelDeclaration() + reportAllErrorTokens(main) + listener: endCompilationUnit(1, ) diff --git a/pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.parser.expect new file mode 100644 index 00000000000..c84011e41b5 --- /dev/null +++ b/pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.parser.expect @@ -0,0 +1,13 @@ +main() { +final record = ((a: 1, b: 2), 3); +final ((a: a, :b), c) = record; +print("a = $a; b = $b, c = $c"); +} + + +main[StringToken]([BeginToken])[SimpleToken] {[BeginToken] +final[KeywordToken] record[StringToken] =[SimpleToken] ([BeginToken]([BeginToken]a[StringToken]:[SimpleToken] 1[StringToken],[SimpleToken] b[StringToken]:[SimpleToken] 2[StringToken])[SimpleToken],[SimpleToken] 3[StringToken])[SimpleToken];[SimpleToken] +final[KeywordToken] ([BeginToken]([BeginToken]a[StringToken]:[SimpleToken] a[StringToken],[SimpleToken] :[SimpleToken]b[StringToken])[SimpleToken],[SimpleToken] c[StringToken])[SimpleToken] =[SimpleToken] record[StringToken];[SimpleToken] +print[StringToken]([BeginToken]"a = [StringToken]$[SimpleToken]a[StringToken]; b = [StringToken]$[SimpleToken]b[StringToken], c = [StringToken]$[SimpleToken]c[StringToken]"[StringToken])[SimpleToken];[SimpleToken] +}[SimpleToken] +[SimpleToken] diff --git a/pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.scanner.expect b/pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.scanner.expect new file mode 100644 index 00000000000..c84011e41b5 --- /dev/null +++ b/pkg/front_end/parser_testcases/patterns/issue_52954_prime.dart.scanner.expect @@ -0,0 +1,13 @@ +main() { +final record = ((a: 1, b: 2), 3); +final ((a: a, :b), c) = record; +print("a = $a; b = $b, c = $c"); +} + + +main[StringToken]([BeginToken])[SimpleToken] {[BeginToken] +final[KeywordToken] record[StringToken] =[SimpleToken] ([BeginToken]([BeginToken]a[StringToken]:[SimpleToken] 1[StringToken],[SimpleToken] b[StringToken]:[SimpleToken] 2[StringToken])[SimpleToken],[SimpleToken] 3[StringToken])[SimpleToken];[SimpleToken] +final[KeywordToken] ([BeginToken]([BeginToken]a[StringToken]:[SimpleToken] a[StringToken],[SimpleToken] :[SimpleToken]b[StringToken])[SimpleToken],[SimpleToken] c[StringToken])[SimpleToken] =[SimpleToken] record[StringToken];[SimpleToken] +print[StringToken]([BeginToken]"a = [StringToken]$[SimpleToken]a[StringToken]; b = [StringToken]$[SimpleToken]b[StringToken], c = [StringToken]$[SimpleToken]c[StringToken]"[StringToken])[SimpleToken];[SimpleToken] +}[SimpleToken] +[SimpleToken]