[analyzer] Issue 53163: Fix crash with unresolved object in String length for const expressions.

Unresolved types would throw in `stringLength` and we don't handle them the same way we do with the other operators. Throwing EvaluationExceptions is the problem here, but that's for another CL.

In the meantime, this CL makes `stringLength` consistent to the other operators in the DartObjectComputer.

Fixes https://github.com/dart-lang/sdk/issues/53163

Bug: https://github.com/dart-lang/sdk/issues/53163
Change-Id: Ib99b61736d699056fa3c379e4d9c79756a4425f3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/319562
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Kallen Tu <kallentu@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
index 370573e..50fb626 100644
--- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
+++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
@@ -421,6 +421,8 @@
   status: noFix
 CompileTimeErrorCode.CONST_EVAL_TYPE_NUM:
   status: noFix
+CompileTimeErrorCode.CONST_EVAL_TYPE_STRING:
+  status: noFix
 CompileTimeErrorCode.CONST_EVAL_TYPE_TYPE:
   status: noFix
 CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE:
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index 21e964c..92432f6 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -1538,7 +1538,7 @@
             errorNode, CompileTimeErrorCode.CONST_EVAL_PROPERTY_ACCESS,
             arguments: [identifier.name, targetType]);
       }
-      return targetResult.stringLength(typeSystem);
+      return _dartObjectComputer.stringLength(errorNode, targetResult);
     }
 
     // TODO(kallentu): Make a more specific error here if we aren't accessing
@@ -2173,6 +2173,16 @@
     }
   }
 
+  Constant stringLength(AstNode node, DartObjectImpl evaluationResult) {
+    try {
+      return evaluationResult.stringLength(_typeSystem);
+    } on EvaluationException catch (exception) {
+      // TODO(kallentu): Don't report error here.
+      _errorReporter.reportErrorForNode(exception.errorCode, node);
+      return InvalidConstant(node, exception.errorCode);
+    }
+  }
+
   Constant times(BinaryExpression node, DartObjectImpl leftOperand,
       DartObjectImpl rightOperand) {
     try {
diff --git a/pkg/analyzer/lib/src/dart/constant/value.dart b/pkg/analyzer/lib/src/dart/constant/value.dart
index d83f18b..578e289 100644
--- a/pkg/analyzer/lib/src/dart/constant/value.dart
+++ b/pkg/analyzer/lib/src/dart/constant/value.dart
@@ -1594,7 +1594,7 @@
   /// Throw an exception if the given [state] does not represent a String value.
   void assertString(InstanceState state) {
     if (state is! StringState) {
-      throw EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL);
+      throw EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_STRING);
     }
   }
 
diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart
index 02ad133..23d1d33 100644
--- a/pkg/analyzer/lib/src/error/codes.g.dart
+++ b/pkg/analyzer/lib/src/error/codes.g.dart
@@ -916,6 +916,14 @@
     "In constant expressions, operands of this operator must be of type 'num'.",
   );
 
+  ///  No parameters.
+  static const CompileTimeErrorCode CONST_EVAL_TYPE_STRING =
+      CompileTimeErrorCode(
+    'CONST_EVAL_TYPE_STRING',
+    "In constant expressions, operands of this operator must be of type "
+        "'String'.",
+  );
+
   static const CompileTimeErrorCode CONST_EVAL_TYPE_TYPE = CompileTimeErrorCode(
     'CONST_EVAL_TYPE_TYPE',
     "In constant expressions, operands of this operator must be of type "
diff --git a/pkg/analyzer/lib/src/error/error_code_values.g.dart b/pkg/analyzer/lib/src/error/error_code_values.g.dart
index 8b6ec3d..85671e8 100644
--- a/pkg/analyzer/lib/src/error/error_code_values.g.dart
+++ b/pkg/analyzer/lib/src/error/error_code_values.g.dart
@@ -126,6 +126,7 @@
   CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING,
   CompileTimeErrorCode.CONST_EVAL_TYPE_INT,
   CompileTimeErrorCode.CONST_EVAL_TYPE_NUM,
+  CompileTimeErrorCode.CONST_EVAL_TYPE_STRING,
   CompileTimeErrorCode.CONST_EVAL_TYPE_TYPE,
   CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE,
   CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE,
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index 91f67a9..a6dcdd4 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -2670,6 +2670,9 @@
       e2, e1 / e2, e1 ~/ e2, e1 > e2, e1 < e2, e1 >= e2, e1 <= e2 or e1 % e2,
       where e, e1 and e2 are constant expressions that evaluate to a numeric
       value or to null.
+  CONST_EVAL_TYPE_STRING:
+    problemMessage: "In constant expressions, operands of this operator must be of type 'String'."
+    comment: No parameters.
   CONST_EVAL_TYPE_TYPE:
     problemMessage: "In constant expressions, operands of this operator must be of type 'Type'."
   CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE:
diff --git a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
index bfa9ba2..350d532 100644
--- a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
@@ -2883,6 +2883,32 @@
     ]);
   }
 
+  test_visitPropertyAccess_length_unresolvedType() async {
+    await assertErrorsInCode('''
+class B {
+  final l;
+  const B(String o) : l = o.length;
+}
+
+const y = B(x);
+''', [
+      error(
+        CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION,
+        70,
+        4,
+        contextMessages: [
+          ExpectedContextMessage(testFile.path, 47, 8,
+              text:
+                  "The exception is 'In constant expressions, operands of this operator must be of type 'String'.' and occurs here."),
+        ],
+      ),
+      error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 72, 1),
+      error(CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT, 72, 1),
+      error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 72,
+          1),
+    ]);
+  }
+
   test_visitSimpleIdentifier_dynamic() async {
     await resolveTestCode('''
 const a = dynamic;
diff --git a/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart b/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart
index f0ee1e1..3898343 100644
--- a/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart
@@ -471,6 +471,32 @@
     ]);
   }
 
+  test_property_length_unresolvedType() async {
+    await assertErrorsInCode('''
+class B {
+  final l;
+  const B(String o) : l = o.length;
+}
+
+const y = B(x);
+''', [
+      error(
+        CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION,
+        70,
+        4,
+        contextMessages: [
+          ExpectedContextMessage(testFile.path, 47, 8,
+              text:
+                  "The exception is 'In constant expressions, operands of this operator must be of type 'String'.' and occurs here."),
+        ],
+      ),
+      error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 72, 1),
+      error(CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT, 72, 1),
+      error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 72,
+          1),
+    ]);
+  }
+
   test_redirectingConstructor_paramTypeMismatch() async {
     await assertErrorsInCode(r'''
 class A {