[cfe] String [] operator for const functions.

Change-Id: Ia1ad96cd77d94c096bf8a10aa0377f37c79ed398
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/195560
Commit-Queue: Kallen Tu <kallentu@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Jake Macdonald <jakemac@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index 5d38a56..315781f 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -2089,9 +2089,9 @@
     // This is a white-listed set of methods we need to support on constants.
     if (receiver is StringConstant) {
       if (arguments.length == 1) {
+        final Constant other = arguments[0];
         switch (op) {
           case '+':
-            final Constant other = arguments[0];
             if (other is StringConstant) {
               return canonicalize(
                   new StringConstant(receiver.value + other.value));
@@ -2104,6 +2104,32 @@
                     typeEnvironment.coreTypes.stringLegacyRawType,
                     other.getType(_staticTypeContext),
                     isNonNullableByDefault));
+          case '[]':
+            if (enableConstFunctions) {
+              if (intFolder.isInt(other)) {
+                int index;
+                if (intFolder is JsConstantIntFolder) {
+                  index = (other as DoubleConstant).value.toInt();
+                } else if (intFolder is VmConstantIntFolder) {
+                  index = (other as IntConstant).value;
+                }
+                assert(index != null);
+
+                if (index < 0 || index >= receiver.value.length) {
+                  return new _AbortDueToThrowConstant(
+                      node, new RangeError.index(index, receiver.value));
+                }
+                return canonicalize(new StringConstant(receiver.value[index]));
+              }
+              return createErrorConstant(
+                  node,
+                  templateConstEvalInvalidBinaryOperandType.withArguments(
+                      '[]',
+                      receiver,
+                      typeEnvironment.coreTypes.intNonNullableRawType,
+                      other.getType(_staticTypeContext),
+                      isNonNullableByDefault));
+            }
         }
       }
     } else if (intFolder.isInt(receiver)) {
@@ -3644,6 +3670,12 @@
               .firstWhere((Class klass) => klass.name == 'StateError');
           throwType =
               new InterfaceType(stateErrorClass, Nullability.nonNullable);
+        } else if (throwValue is RangeError) {
+          final Class rangeErrorClass = exprEvaluator
+              .coreTypes.coreLibrary.classes
+              .firstWhere((Class klass) => klass.name == 'RangeError');
+          throwType =
+              new InterfaceType(rangeErrorClass, Nullability.nonNullable);
         }
         assert(throwType != null);
 
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string.dart b/pkg/front_end/testcases/const_functions/const_functions_string.dart
new file mode 100644
index 0000000..e0f0f73
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2021, 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.
+
+// Tests string usage with const functions.
+
+import "package:expect/expect.dart";
+
+const String str = "str";
+const var1 = str[2];
+
+const var2 = fn();
+fn() {
+  String local = "str";
+  return local[0];
+}
+
+const var3 = "str"[0];
+
+const var4 = fn2();
+fn2() {
+  try {
+    var x = str[-1];
+  } on RangeError {
+    return 2;
+  }
+}
+
+void main() {
+  Expect.equals(var1, 'r');
+  Expect.equals(var2, 's');
+  Expect.equals(var3, 's');
+  Expect.equals(var4, 2);
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string.dart.strong.expect b/pkg/front_end/testcases/const_functions/const_functions_string.dart.strong.expect
new file mode 100644
index 0000000..f573022
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string.dart.strong.expect
@@ -0,0 +1,37 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+static const field core::String str = #C1;
+static const field core::String var1 = #C2;
+static const field dynamic var2 = #C3;
+static const field core::String var3 = #C3;
+static const field dynamic var4 = #C4;
+static method fn() → dynamic {
+  core::String local = "str";
+  return local.{core::String::[]}(0);
+}
+static method fn2() → dynamic {
+  try {
+    core::String x = (#C1).{core::String::[]}(1.{core::int::unary-}());
+  }
+  on core::RangeError catch(no-exception-var) {
+    return 2;
+  }
+}
+static method main() → void {
+  exp::Expect::equals(#C2, "r");
+  exp::Expect::equals(#C3, "s");
+  exp::Expect::equals(#C3, "s");
+  exp::Expect::equals(#C4, 2);
+}
+
+constants  {
+  #C1 = "str"
+  #C2 = "r"
+  #C3 = "s"
+  #C4 = 2
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string.dart.strong.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_string.dart.strong.transformed.expect
new file mode 100644
index 0000000..9ba5e5c
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string.dart.strong.transformed.expect
@@ -0,0 +1,41 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+static const field core::String str = #C1;
+static const field core::String var1 = #C2;
+static const field dynamic var2 = #C3;
+static const field core::String var3 = #C3;
+static const field dynamic var4 = #C4;
+static method fn() → dynamic {
+  core::String local = "str";
+  return local.{core::String::[]}(0);
+}
+static method fn2() → dynamic {
+  try {
+    core::String x = (#C1).{core::String::[]}(1.{core::int::unary-}());
+  }
+  on core::RangeError catch(no-exception-var) {
+    return 2;
+  }
+}
+static method main() → void {
+  exp::Expect::equals(#C2, "r");
+  exp::Expect::equals(#C3, "s");
+  exp::Expect::equals(#C3, "s");
+  exp::Expect::equals(#C4, 2);
+}
+
+constants  {
+  #C1 = "str"
+  #C2 = "r"
+  #C3 = "s"
+  #C4 = 2
+}
+
+Extra constant evaluation status:
+Evaluated: MethodInvocation @ org-dartlang-testcase:///const_functions_string.dart:23:17 -> IntConstant(-1)
+Extra constant evaluation: evaluated: 8, effectively constant: 1
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string.dart.textual_outline.expect b/pkg/front_end/testcases/const_functions/const_functions_string.dart.textual_outline.expect
new file mode 100644
index 0000000..07c61ae
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string.dart.textual_outline.expect
@@ -0,0 +1,10 @@
+import "package:expect/expect.dart";
+
+const String str = "str";
+const var1 = str[2];
+const var2 = fn();
+fn() {}
+const var3 = "str"[0];
+const var4 = fn2();
+fn2() {}
+void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/const_functions/const_functions_string.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..2785bbc
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string.dart.textual_outline_modelled.expect
@@ -0,0 +1,10 @@
+import "package:expect/expect.dart";
+
+const String str = "str";
+const var1 = str[2];
+const var2 = fn();
+const var3 = "str"[0];
+const var4 = fn2();
+fn() {}
+fn2() {}
+void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string.dart.weak.expect b/pkg/front_end/testcases/const_functions/const_functions_string.dart.weak.expect
new file mode 100644
index 0000000..f573022
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string.dart.weak.expect
@@ -0,0 +1,37 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+static const field core::String str = #C1;
+static const field core::String var1 = #C2;
+static const field dynamic var2 = #C3;
+static const field core::String var3 = #C3;
+static const field dynamic var4 = #C4;
+static method fn() → dynamic {
+  core::String local = "str";
+  return local.{core::String::[]}(0);
+}
+static method fn2() → dynamic {
+  try {
+    core::String x = (#C1).{core::String::[]}(1.{core::int::unary-}());
+  }
+  on core::RangeError catch(no-exception-var) {
+    return 2;
+  }
+}
+static method main() → void {
+  exp::Expect::equals(#C2, "r");
+  exp::Expect::equals(#C3, "s");
+  exp::Expect::equals(#C3, "s");
+  exp::Expect::equals(#C4, 2);
+}
+
+constants  {
+  #C1 = "str"
+  #C2 = "r"
+  #C3 = "s"
+  #C4 = 2
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string.dart.weak.outline.expect b/pkg/front_end/testcases/const_functions/const_functions_string.dart.weak.outline.expect
new file mode 100644
index 0000000..8da9073
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string.dart.weak.outline.expect
@@ -0,0 +1,22 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "package:expect/expect.dart";
+
+static const field core::String str = "str";
+static const field core::String var1 = self::str.{core::String::[]}(2);
+static const field dynamic var2 = self::fn();
+static const field core::String var3 = "str".{core::String::[]}(0);
+static const field dynamic var4 = self::fn2();
+static method fn() → dynamic
+  ;
+static method fn2() → dynamic
+  ;
+static method main() → void
+  ;
+
+
+Extra constant evaluation status:
+Evaluated: StaticGet @ org-dartlang-testcase:///const_functions_string.dart:10:14 -> StringConstant("str")
+Extra constant evaluation: evaluated: 5, effectively constant: 1
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string.dart.weak.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_string.dart.weak.transformed.expect
new file mode 100644
index 0000000..9ba5e5c
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string.dart.weak.transformed.expect
@@ -0,0 +1,41 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+static const field core::String str = #C1;
+static const field core::String var1 = #C2;
+static const field dynamic var2 = #C3;
+static const field core::String var3 = #C3;
+static const field dynamic var4 = #C4;
+static method fn() → dynamic {
+  core::String local = "str";
+  return local.{core::String::[]}(0);
+}
+static method fn2() → dynamic {
+  try {
+    core::String x = (#C1).{core::String::[]}(1.{core::int::unary-}());
+  }
+  on core::RangeError catch(no-exception-var) {
+    return 2;
+  }
+}
+static method main() → void {
+  exp::Expect::equals(#C2, "r");
+  exp::Expect::equals(#C3, "s");
+  exp::Expect::equals(#C3, "s");
+  exp::Expect::equals(#C4, 2);
+}
+
+constants  {
+  #C1 = "str"
+  #C2 = "r"
+  #C3 = "s"
+  #C4 = 2
+}
+
+Extra constant evaluation status:
+Evaluated: MethodInvocation @ org-dartlang-testcase:///const_functions_string.dart:23:17 -> IntConstant(-1)
+Extra constant evaluation: evaluated: 8, effectively constant: 1
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string_error.dart b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart
new file mode 100644
index 0000000..5f892a6
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2021, 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.
+
+// Tests erroneous string usage with const functions.
+
+import "package:expect/expect.dart";
+
+const String str = "str";
+const var1 = str[-1];
+const var2 = str[3];
+
+const var3 = fn();
+fn() {
+  String s = "str";
+  return str[-1];
+}
+
+const var4 = fn2();
+fn2() {
+  String s = "str";
+  return str[3];
+}
+
+const var5 = fn3();
+fn3() {
+  String s = "str";
+  return str[1.1];
+}
+
+void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.strong.expect b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.strong.expect
new file mode 100644
index 0000000..0cdd42f
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.strong.expect
@@ -0,0 +1,68 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:28:14: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
+//   return str[1.1];
+//              ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:10:17: Error: Constant evaluation error:
+// const var1 = str[-1];
+//                 ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:10:17: Context: Unhandled core exception: RangeError: Index out of range: index must not be negative: -1
+// const var1 = str[-1];
+//                 ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:11:17: Error: Constant evaluation error:
+// const var2 = str[3];
+//                 ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:11:17: Context: Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3
+// const var2 = str[3];
+//                 ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:13:14: Error: Constant evaluation error:
+// const var3 = fn();
+//              ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:16:13: Context: Unhandled core exception: RangeError: Index out of range: index must not be negative: -1
+//   return str[-1];
+//             ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:19:14: Error: Constant evaluation error:
+// const var4 = fn2();
+//              ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:22:13: Context: Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3
+//   return str[3];
+//             ^
+//
+import self as self;
+import "dart:core" as core;
+
+import "package:expect/expect.dart";
+
+static const field core::String str = #C1;
+static const field core::String var1 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index must not be negative: -1";
+static const field core::String var2 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3";
+static const field dynamic var3 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index must not be negative: -1";
+static const field dynamic var4 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3";
+static const field dynamic var5 = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_string_error.dart:28:14: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
+  return str[1.1];
+             ^";
+static method fn() → dynamic {
+  core::String s = "str";
+  return (#C1).{core::String::[]}(1.{core::int::unary-}());
+}
+static method fn2() → dynamic {
+  core::String s = "str";
+  return (#C1).{core::String::[]}(3);
+}
+static method fn3() → dynamic {
+  core::String s = "str";
+  return (#C1).{core::String::[]}(let final Never #t1 = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_string_error.dart:28:14: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
+  return str[1.1];
+             ^" in 1.1 as{TypeError,ForNonNullableByDefault} core::int);
+}
+static method main() → void {}
+
+constants  {
+  #C1 = "str"
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.strong.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.strong.transformed.expect
new file mode 100644
index 0000000..e7133c8
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.strong.transformed.expect
@@ -0,0 +1,72 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:28:14: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
+//   return str[1.1];
+//              ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:10:17: Error: Constant evaluation error:
+// const var1 = str[-1];
+//                 ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:10:17: Context: Unhandled core exception: RangeError: Index out of range: index must not be negative: -1
+// const var1 = str[-1];
+//                 ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:11:17: Error: Constant evaluation error:
+// const var2 = str[3];
+//                 ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:11:17: Context: Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3
+// const var2 = str[3];
+//                 ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:13:14: Error: Constant evaluation error:
+// const var3 = fn();
+//              ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:16:13: Context: Unhandled core exception: RangeError: Index out of range: index must not be negative: -1
+//   return str[-1];
+//             ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:19:14: Error: Constant evaluation error:
+// const var4 = fn2();
+//              ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:22:13: Context: Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3
+//   return str[3];
+//             ^
+//
+import self as self;
+import "dart:core" as core;
+
+import "package:expect/expect.dart";
+
+static const field core::String str = #C1;
+static const field core::String var1 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index must not be negative: -1";
+static const field core::String var2 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3";
+static const field dynamic var3 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index must not be negative: -1";
+static const field dynamic var4 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3";
+static const field dynamic var5 = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_string_error.dart:28:14: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
+  return str[1.1];
+             ^";
+static method fn() → dynamic {
+  core::String s = "str";
+  return (#C1).{core::String::[]}(1.{core::int::unary-}());
+}
+static method fn2() → dynamic {
+  core::String s = "str";
+  return (#C1).{core::String::[]}(3);
+}
+static method fn3() → dynamic {
+  core::String s = "str";
+  return (#C1).{core::String::[]}(let final Never #t1 = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_string_error.dart:28:14: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
+  return str[1.1];
+             ^" in 1.1 as{TypeError,ForNonNullableByDefault} core::int);
+}
+static method main() → void {}
+
+constants  {
+  #C1 = "str"
+}
+
+Extra constant evaluation status:
+Evaluated: MethodInvocation @ org-dartlang-testcase:///const_functions_string_error.dart:16:14 -> IntConstant(-1)
+Extra constant evaluation: evaluated: 6, effectively constant: 1
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.textual_outline.expect b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.textual_outline.expect
new file mode 100644
index 0000000..27583e1
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.textual_outline.expect
@@ -0,0 +1,12 @@
+import "package:expect/expect.dart";
+
+const String str = "str";
+const var1 = str[-1];
+const var2 = str[3];
+const var3 = fn();
+fn() {}
+const var4 = fn2();
+fn2() {}
+const var5 = fn3();
+fn3() {}
+void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..9227263
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.textual_outline_modelled.expect
@@ -0,0 +1,12 @@
+import "package:expect/expect.dart";
+
+const String str = "str";
+const var1 = str[-1];
+const var2 = str[3];
+const var3 = fn();
+const var4 = fn2();
+const var5 = fn3();
+fn() {}
+fn2() {}
+fn3() {}
+void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.weak.expect b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.weak.expect
new file mode 100644
index 0000000..0cdd42f
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.weak.expect
@@ -0,0 +1,68 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:28:14: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
+//   return str[1.1];
+//              ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:10:17: Error: Constant evaluation error:
+// const var1 = str[-1];
+//                 ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:10:17: Context: Unhandled core exception: RangeError: Index out of range: index must not be negative: -1
+// const var1 = str[-1];
+//                 ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:11:17: Error: Constant evaluation error:
+// const var2 = str[3];
+//                 ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:11:17: Context: Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3
+// const var2 = str[3];
+//                 ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:13:14: Error: Constant evaluation error:
+// const var3 = fn();
+//              ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:16:13: Context: Unhandled core exception: RangeError: Index out of range: index must not be negative: -1
+//   return str[-1];
+//             ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:19:14: Error: Constant evaluation error:
+// const var4 = fn2();
+//              ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:22:13: Context: Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3
+//   return str[3];
+//             ^
+//
+import self as self;
+import "dart:core" as core;
+
+import "package:expect/expect.dart";
+
+static const field core::String str = #C1;
+static const field core::String var1 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index must not be negative: -1";
+static const field core::String var2 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3";
+static const field dynamic var3 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index must not be negative: -1";
+static const field dynamic var4 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3";
+static const field dynamic var5 = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_string_error.dart:28:14: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
+  return str[1.1];
+             ^";
+static method fn() → dynamic {
+  core::String s = "str";
+  return (#C1).{core::String::[]}(1.{core::int::unary-}());
+}
+static method fn2() → dynamic {
+  core::String s = "str";
+  return (#C1).{core::String::[]}(3);
+}
+static method fn3() → dynamic {
+  core::String s = "str";
+  return (#C1).{core::String::[]}(let final Never #t1 = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_string_error.dart:28:14: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
+  return str[1.1];
+             ^" in 1.1 as{TypeError,ForNonNullableByDefault} core::int);
+}
+static method main() → void {}
+
+constants  {
+  #C1 = "str"
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.weak.outline.expect b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.weak.outline.expect
new file mode 100644
index 0000000..183676d
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.weak.outline.expect
@@ -0,0 +1,27 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "package:expect/expect.dart";
+
+static const field core::String str = "str";
+static const field core::String var1 = self::str.{core::String::[]}(1.{core::int::unary-}());
+static const field core::String var2 = self::str.{core::String::[]}(3);
+static const field dynamic var3 = self::fn();
+static const field dynamic var4 = self::fn2();
+static const field dynamic var5 = self::fn3();
+static method fn() → dynamic
+  ;
+static method fn2() → dynamic
+  ;
+static method fn3() → dynamic
+  ;
+static method main() → void
+  ;
+
+
+Extra constant evaluation status:
+Evaluated: StaticGet @ org-dartlang-testcase:///const_functions_string_error.dart:10:14 -> StringConstant("str")
+Evaluated: MethodInvocation @ org-dartlang-testcase:///const_functions_string_error.dart:10:18 -> IntConstant(-1)
+Evaluated: StaticGet @ org-dartlang-testcase:///const_functions_string_error.dart:11:14 -> StringConstant("str")
+Extra constant evaluation: evaluated: 8, effectively constant: 3
diff --git a/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.weak.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.weak.transformed.expect
new file mode 100644
index 0000000..e7133c8
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_string_error.dart.weak.transformed.expect
@@ -0,0 +1,72 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:28:14: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
+//   return str[1.1];
+//              ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:10:17: Error: Constant evaluation error:
+// const var1 = str[-1];
+//                 ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:10:17: Context: Unhandled core exception: RangeError: Index out of range: index must not be negative: -1
+// const var1 = str[-1];
+//                 ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:11:17: Error: Constant evaluation error:
+// const var2 = str[3];
+//                 ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:11:17: Context: Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3
+// const var2 = str[3];
+//                 ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:13:14: Error: Constant evaluation error:
+// const var3 = fn();
+//              ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:16:13: Context: Unhandled core exception: RangeError: Index out of range: index must not be negative: -1
+//   return str[-1];
+//             ^
+//
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:19:14: Error: Constant evaluation error:
+// const var4 = fn2();
+//              ^
+// pkg/front_end/testcases/const_functions/const_functions_string_error.dart:22:13: Context: Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3
+//   return str[3];
+//             ^
+//
+import self as self;
+import "dart:core" as core;
+
+import "package:expect/expect.dart";
+
+static const field core::String str = #C1;
+static const field core::String var1 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index must not be negative: -1";
+static const field core::String var2 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3";
+static const field dynamic var3 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index must not be negative: -1";
+static const field dynamic var4 = invalid-expression "Unhandled core exception: RangeError: Index out of range: index should be less than 3: 3";
+static const field dynamic var5 = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_string_error.dart:28:14: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
+  return str[1.1];
+             ^";
+static method fn() → dynamic {
+  core::String s = "str";
+  return (#C1).{core::String::[]}(1.{core::int::unary-}());
+}
+static method fn2() → dynamic {
+  core::String s = "str";
+  return (#C1).{core::String::[]}(3);
+}
+static method fn3() → dynamic {
+  core::String s = "str";
+  return (#C1).{core::String::[]}(let final Never #t1 = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_string_error.dart:28:14: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
+  return str[1.1];
+             ^" in 1.1 as{TypeError,ForNonNullableByDefault} core::int);
+}
+static method main() → void {}
+
+constants  {
+  #C1 = "str"
+}
+
+Extra constant evaluation status:
+Evaluated: MethodInvocation @ org-dartlang-testcase:///const_functions_string_error.dart:16:14 -> IntConstant(-1)
+Extra constant evaluation: evaluated: 6, effectively constant: 1
diff --git a/tests/language/const_functions/const_functions_string_error_test.dart b/tests/language/const_functions/const_functions_string_error_test.dart
new file mode 100644
index 0000000..2d89d66
--- /dev/null
+++ b/tests/language/const_functions/const_functions_string_error_test.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2021, 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.
+
+// Tests erroneous string usage with const functions.
+
+// SharedOptions=--enable-experiment=const-functions
+
+import "package:expect/expect.dart";
+
+const String str = "str";
+const var1 = str[-1];
+//           ^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+//              ^
+// [cfe] Constant evaluation error:
+const var2 = str[3];
+//           ^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+//              ^
+// [cfe] Constant evaluation error:
+
+const var3 = fn();
+//           ^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+// [cfe] Constant evaluation error:
+fn() {
+  String s = "str";
+  return str[-1];
+}
+
+const var4 = fn2();
+//           ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+// [cfe] Constant evaluation error:
+fn2() {
+  String s = "str";
+  return str[3];
+}
+
+const var5 = fn3();
+//           ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+fn3() {
+  String s = "str";
+  return str[1.1];
+  //         ^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  // [cfe] A value of type 'double' can't be assigned to a variable of type 'int'.
+}
diff --git a/tests/language/const_functions/const_functions_string_test.dart b/tests/language/const_functions/const_functions_string_test.dart
new file mode 100644
index 0000000..1cbc4396
--- /dev/null
+++ b/tests/language/const_functions/const_functions_string_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2021, 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.
+
+// Tests string usage with const functions.
+
+// SharedOptions=--enable-experiment=const-functions
+
+import "package:expect/expect.dart";
+
+const String str = "str";
+const var1 = str[2];
+//           ^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+
+const var2 = fn();
+//           ^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+fn() {
+  String local = "str";
+  return local[0];
+}
+
+const var3 = "str"[0];
+//           ^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+
+const var4 = fn2();
+//           ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+fn2() {
+  try {
+    var x = str[-1];
+  } on RangeError {
+    return 2;
+  }
+}
+
+void main() {
+  Expect.equals(var1, 'r');
+  Expect.equals(var2, 's');
+  Expect.equals(var3, 's');
+  Expect.equals(var4, 2);
+}