Report CompileTimeErrorCode.FOR_IN_WITH_CONST_VARIABLE

R=brianwilkerson@google.com, paulberry@google.com

Bug: https://github.com/dart-lang/sdk/issues/25161
Change-Id: I27ebc09fd9fcd6d6d992268f158e80477c41d042
Reviewed-on: https://dart-review.googlesource.com/71424
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index e916ae7..b88db95 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -3897,8 +3897,10 @@
    * assigned variable in a for-in statement.
    */
   void _checkForInIterable(ForEachStatement node) {
+    DeclaredIdentifier loopVariable = node.loopVariable;
+
     // Ignore malformed for statements.
-    if (node.identifier == null && node.loopVariable == null) {
+    if (node.identifier == null && loopVariable == null) {
       return;
     }
 
@@ -3912,7 +3914,7 @@
     }
 
     // The type of the loop variable.
-    SimpleIdentifier variable = node.identifier ?? node.loopVariable.identifier;
+    SimpleIdentifier variable = node.identifier ?? loopVariable.identifier;
     DartType variableType = getStaticType(variable);
 
     // TODO(mfairhurst) Check and guard against `for(void x in _)`?
@@ -3940,6 +3942,19 @@
       }
     }
 
+    if (loopVariable != null) {
+      if (loopVariable.isConst) {
+        _errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.FOR_IN_WITH_CONST_VARIABLE, loopVariable);
+      }
+    } else if (node.identifier != null) {
+      Element variableElement = node.identifier.staticElement;
+      if (variableElement is VariableElement && variableElement.isConst) {
+        _errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.FOR_IN_WITH_CONST_VARIABLE, node.identifier);
+      }
+    }
+
     if (bestIterableType == null) {
       _errorReporter.reportTypeErrorForNode(
           StaticTypeWarningCode.FOR_IN_OF_INVALID_TYPE,
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
index fe9840b..0cd7e62 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
@@ -301,6 +301,12 @@
 
   @override
   @failingTest
+  test_forInWithConstVariable_forEach_identifier() async {
+    return super.test_forInWithConstVariable_forEach_identifier();
+  }
+
+  @override
+  @failingTest
   test_genericFunctionTypeArgument_class() async {
     await super.test_genericFunctionTypeArgument_class();
   }
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index 27a8c27..d2202d1 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -2965,6 +2965,27 @@
     verify([source]);
   }
 
+  test_forInWithConstVariable_forEach_identifier() async {
+    Source source = addSource(r'''
+f() {
+  const x = 0;
+  for (x in [0, 1, 2]) {}
+}''');
+    await computeAnalysisResult(source);
+    assertErrors(source, [CompileTimeErrorCode.FOR_IN_WITH_CONST_VARIABLE]);
+    verify([source]);
+  }
+
+  test_forInWithConstVariable_forEach_loopVariable() async {
+    Source source = addSource(r'''
+f() {
+  for (const x in [0, 1, 2]) {}
+}''');
+    await computeAnalysisResult(source);
+    assertErrors(source, [CompileTimeErrorCode.FOR_IN_WITH_CONST_VARIABLE]);
+    verify([source]);
+  }
+
   test_fromEnvironment_bool_badArgs() async {
     Source source = addSource(r'''
 var b1 = const bool.fromEnvironment(1);
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index 6853053..d5cd7ac 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -4667,7 +4667,8 @@
     computeResult(target, VERIFY_ERRORS, matcher: isVerifyUnitTask);
     // validate
     _fillErrorListener(VERIFY_ERRORS);
-    errorListener.assertNoErrors();
+    errorListener.assertErrorsWithCodes(
+        <ErrorCode>[CompileTimeErrorCode.FOR_IN_WITH_CONST_VARIABLE]);
   }
 
   test_perform_ConstantValidator_dependencyCycle() {
diff --git a/tests/language_2/language_2_analyzer.status b/tests/language_2/language_2_analyzer.status
index a8426c0..fd846a6 100644
--- a/tests/language_2/language_2_analyzer.status
+++ b/tests/language_2/language_2_analyzer.status
@@ -411,7 +411,6 @@
 conflicting_generic_interfaces_hierarchy_loop_infinite_test: Skip # Crashes or times out
 const_cast2_test/01: CompileTimeError
 const_cast2_test/none: CompileTimeError
-const_for_in_variable_test/01: MissingCompileTimeError # Issue 25161
 constructor9_test/01: MissingCompileTimeError # CFE Issue 33022
 default_implementation2_test: CompileTimeError # Issue 30855
 dynamic_prefix_core_test/01: MissingCompileTimeError
diff --git a/tests/language_2/language_2_dartdevc.status b/tests/language_2/language_2_dartdevc.status
index ab809ec..b11012f 100644
--- a/tests/language_2/language_2_dartdevc.status
+++ b/tests/language_2/language_2_dartdevc.status
@@ -36,7 +36,6 @@
 const_cast2_test/none: CompileTimeError
 const_constructor_mixin3_test/01: MissingCompileTimeError # Issue 33644
 const_constructor_mixin_test/01: MissingCompileTimeError # Issue 33644
-const_for_in_variable_test/01: MissingCompileTimeError
 constructor9_test/01: MissingCompileTimeError # CFE Issue 33022
 constructor_type_parameter_test/00: MissingCompileTimeError
 constructor_with_type_parameters_test/03: MissingCompileTimeError