[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);
+}