[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() {}