[parser] Set forIn = true when recovering 'in' written as ':'
Before this change the CFE crashed with an assert error.
Change-Id: Ide486388fbba8c6cda4bb75e5339ae3c10623351
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/161949
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
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 6508967..09d8ad1 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
@@ -6248,7 +6248,7 @@
token =
parseVariablesDeclarationRest(token, /* endWithSemicolon = */ false);
listener.handleForInitializerLocalVariableDeclaration(
- token, optional('in', token.next));
+ token, optional('in', token.next) || optional(':', token.next));
} else if (optional(';', token.next)) {
listener.handleForInitializerEmptyStatement(token.next);
} else {
diff --git a/pkg/front_end/parser_testcases/error_recovery/for_in_with_colon.dart b/pkg/front_end/parser_testcases/error_recovery/for_in_with_colon.dart
new file mode 100644
index 0000000..41b92d1
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/for_in_with_colon.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+main() {
+ for(int i : [1, 2, 3]) {
+ print(i);
+ }
+}
\ No newline at end of file
diff --git a/pkg/front_end/parser_testcases/error_recovery/for_in_with_colon.dart.expect b/pkg/front_end/parser_testcases/error_recovery/for_in_with_colon.dart.expect
new file mode 100644
index 0000000..6e185cd
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/for_in_with_colon.dart.expect
@@ -0,0 +1,59 @@
+Problems reported:
+
+parser/error_recovery/for_in_with_colon:6:13: For-in loops use 'in' rather than a colon.
+ for(int i : [1, 2, 3]) {
+ ^
+
+beginCompilationUnit(main)
+ beginMetadataStar(main)
+ endMetadataStar(0)
+ beginTopLevelMember(main)
+ beginTopLevelMethod(, null)
+ handleNoType()
+ handleIdentifier(main, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ beginForStatement(for)
+ beginMetadataStar(int)
+ endMetadataStar(0)
+ handleIdentifier(int, typeReference)
+ handleNoTypeArguments(i)
+ handleType(int, null)
+ beginVariablesDeclaration(i, null, null)
+ handleIdentifier(i, localVariableDeclaration)
+ beginInitializedIdentifier(i)
+ handleNoVariableInitializer(i)
+ endInitializedIdentifier(i)
+ endVariablesDeclaration(1, null)
+ handleForInitializerLocalVariableDeclaration(i, true)
+ handleRecoverableError(ColonInPlaceOfIn, :, :)
+ beginForInExpression([)
+ handleNoTypeArguments([)
+ handleLiteralInt(1)
+ handleLiteralInt(2)
+ handleLiteralInt(3)
+ handleLiteralList(3, [, null, ])
+ endForInExpression())
+ handleForInLoopParts(null, for, (, :)
+ beginForInBody({)
+ beginBlock({, BlockKind(statement))
+ handleIdentifier(print, expression)
+ handleNoTypeArguments(()
+ beginArguments(()
+ handleIdentifier(i, expression)
+ handleNoTypeArguments())
+ handleNoArguments())
+ handleSend(i, ))
+ endArguments(1, (, ))
+ handleSend(print, ;)
+ handleExpressionStatement(;)
+ endBlock(1, {, }, BlockKind(statement))
+ endForInBody(})
+ endForIn(})
+ endBlockFunctionBody(1, {, })
+ endTopLevelMethod(main, null, })
+ endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/error_recovery/for_in_with_colon.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/for_in_with_colon.dart.intertwined.expect
new file mode 100644
index 0000000..a363712
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/for_in_with_colon.dart.intertwined.expect
@@ -0,0 +1,138 @@
+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, , Instance of 'NoType', null, main, false)
+ listener: beginTopLevelMethod(, 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(}, for)
+ parseStatement({)
+ parseStatementX({)
+ parseForStatement({, null)
+ listener: beginForStatement(for)
+ parseForLoopPartsStart(null, for)
+ parseExpressionStatementOrDeclaration((, true)
+ parseExpressionStatementOrDeclarationAfterModifiers((, (, null, null, null, true)
+ listener: beginMetadataStar(int)
+ listener: endMetadataStar(0)
+ listener: handleIdentifier(int, typeReference)
+ listener: handleNoTypeArguments(i)
+ listener: handleType(int, null)
+ listener: beginVariablesDeclaration(i, null, null)
+ parseForLoopPartsMid(int, null, for)
+ parseVariablesDeclarationRest(int, false)
+ parseOptionallyInitializedIdentifier(int)
+ ensureIdentifier(int, localVariableDeclaration)
+ listener: handleIdentifier(i, localVariableDeclaration)
+ listener: beginInitializedIdentifier(i)
+ parseVariableInitializerOpt(i)
+ listener: handleNoVariableInitializer(i)
+ listener: endInitializedIdentifier(i)
+ listener: endVariablesDeclaration(1, null)
+ listener: handleForInitializerLocalVariableDeclaration(i, true)
+ reportRecoverableError(:, ColonInPlaceOfIn)
+ listener: handleRecoverableError(ColonInPlaceOfIn, :, :)
+ parseForInRest(i, null, for, i)
+ parseForInLoopPartsRest(i, null, for, i)
+ listener: beginForInExpression([)
+ parseExpression(:)
+ parsePrecedenceExpression(:, 1, true)
+ parseUnaryExpression(:, true)
+ parsePrimary(:, expression)
+ listener: handleNoTypeArguments([)
+ parseLiteralListSuffix(:, null)
+ parseExpression([)
+ parsePrecedenceExpression([, 1, true)
+ parseUnaryExpression([, true)
+ parsePrimary([, expression)
+ parseLiteralInt([)
+ listener: handleLiteralInt(1)
+ parseExpression(,)
+ parsePrecedenceExpression(,, 1, true)
+ parseUnaryExpression(,, true)
+ parsePrimary(,, expression)
+ parseLiteralInt(,)
+ listener: handleLiteralInt(2)
+ parseExpression(,)
+ parsePrecedenceExpression(,, 1, true)
+ parseUnaryExpression(,, true)
+ parsePrimary(,, expression)
+ parseLiteralInt(,)
+ listener: handleLiteralInt(3)
+ listener: handleLiteralList(3, [, null, ])
+ ensureCloseParen(], ()
+ listener: endForInExpression())
+ listener: handleForInLoopParts(null, for, (, :)
+ listener: beginForInBody({)
+ parseStatement())
+ parseStatementX())
+ parseBlock(), BlockKind(statement))
+ ensureBlock(), null, null)
+ listener: beginBlock({, BlockKind(statement))
+ notEofOrValue(}, print)
+ parseStatement({)
+ parseStatementX({)
+ parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+ looksLikeLocalFunction(print)
+ parseExpressionStatement({)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true)
+ parseUnaryExpression({, true)
+ parsePrimary({, expression)
+ parseSendOrFunctionLiteral({, expression)
+ looksLikeFunctionBody(;)
+ parseSend({, expression)
+ ensureIdentifier({, expression)
+ listener: handleIdentifier(print, expression)
+ listener: handleNoTypeArguments(()
+ parseArgumentsOpt(print)
+ parseArguments(print)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true)
+ parseUnaryExpression((, true)
+ parsePrimary((, expression)
+ parseSendOrFunctionLiteral((, expression)
+ parseSend((, expression)
+ ensureIdentifier((, expression)
+ listener: handleIdentifier(i, expression)
+ listener: handleNoTypeArguments())
+ parseArgumentsOpt(i)
+ listener: handleNoArguments())
+ listener: handleSend(i, ))
+ listener: endArguments(1, (, ))
+ listener: handleSend(print, ;)
+ ensureSemicolon())
+ listener: handleExpressionStatement(;)
+ notEofOrValue(}, })
+ listener: endBlock(1, {, }, BlockKind(statement))
+ listener: endForInBody(})
+ listener: endForIn(})
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(1, {, })
+ listener: endTopLevelMethod(main, null, })
+ listener: endTopLevelDeclaration()
+ reportAllErrorTokens(main)
+ listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/error_recovery/for_in_with_colon.dart.parser.expect b/pkg/front_end/parser_testcases/error_recovery/for_in_with_colon.dart.parser.expect
new file mode 100644
index 0000000..0bf6398
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/for_in_with_colon.dart.parser.expect
@@ -0,0 +1,11 @@
+main() {
+for(int i : [1, 2, 3]) {
+print(i);
+}
+}
+
+main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+for[KeywordToken]([BeginToken]int[StringToken] i[StringToken] :[SimpleToken] [[BeginToken]1[StringToken],[SimpleToken] 2[StringToken],[SimpleToken] 3[StringToken]][SimpleToken])[SimpleToken] {[BeginToken]
+print[StringToken]([BeginToken]i[StringToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken][SimpleToken]
diff --git a/pkg/front_end/parser_testcases/error_recovery/for_in_with_colon.dart.scanner.expect b/pkg/front_end/parser_testcases/error_recovery/for_in_with_colon.dart.scanner.expect
new file mode 100644
index 0000000..0bf6398
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/for_in_with_colon.dart.scanner.expect
@@ -0,0 +1,11 @@
+main() {
+for(int i : [1, 2, 3]) {
+print(i);
+}
+}
+
+main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+for[KeywordToken]([BeginToken]int[StringToken] i[StringToken] :[SimpleToken] [[BeginToken]1[StringToken],[SimpleToken] 2[StringToken],[SimpleToken] 3[StringToken]][SimpleToken])[SimpleToken] {[BeginToken]
+print[StringToken]([BeginToken]i[StringToken])[SimpleToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken][SimpleToken]
diff --git a/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart b/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart
new file mode 100644
index 0000000..41b92d1
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+main() {
+ for(int i : [1, 2, 3]) {
+ print(i);
+ }
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart.outline.expect b/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart.outline.expect
new file mode 100644
index 0000000..6a28c0d
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart.strong.expect b/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart.strong.expect
new file mode 100644
index 0000000..9124332
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart.strong.expect
@@ -0,0 +1,17 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart:6:13: Error: For-in loops use 'in' rather than a colon.
+// Try replacing the colon with the keyword 'in'.
+// for(int i : [1, 2, 3]) {
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+ for (core::int* i in <core::int*>[1, 2, 3]) {
+ core::print(i);
+ }
+}
diff --git a/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart.strong.transformed.expect b/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart.strong.transformed.expect
new file mode 100644
index 0000000..bcd06a8
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart.strong.transformed.expect
@@ -0,0 +1,23 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart:6:13: Error: For-in loops use 'in' rather than a colon.
+// Try replacing the colon with the keyword 'in'.
+// for(int i : [1, 2, 3]) {
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+ {
+ core::Iterator<core::int*>* :sync-for-iterator = <core::int*>[1, 2, 3].{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int* i = :sync-for-iterator.{core::Iterator::current};
+ {
+ core::print(i);
+ }
+ }
+ }
+}
diff --git a/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart.textual_outline.expect b/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart.textual_outline.expect
new file mode 100644
index 0000000..bae895a
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart.textual_outline.expect
@@ -0,0 +1 @@
+main() {}
diff --git a/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..bae895a
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_recovery/for_in_with_colon.dart.textual_outline_modelled.expect
@@ -0,0 +1 @@
+main() {}