[cfe] Mutable lists and list add method in const functions.

Within constant evaluation, mutable lists can be created and altered with `add`.

Change-Id: I4ad86e3bea768844835dd732bff3ae135d6df8fb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/197280
Commit-Queue: Kallen Tu <kallentu@google.com>
Reviewed-by: Jake Macdonald <jakemac@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
This commit is contained in:
Kallen Tu 2021-04-29 17:52:36 +00:00 committed by commit-bot@chromium.org
parent e6a0238898
commit 68d133d949
20 changed files with 246 additions and 39 deletions

View file

@ -88,8 +88,15 @@ abstract class _ListOrSetConstantBuilder<L extends Expression> {
}
class ListConstantBuilder extends _ListOrSetConstantBuilder<ListLiteral> {
/// If [true], builds a [MutableListConstant].
///
/// [MutableListConstant]s can be modified during constant evaluation, but
/// still results in a normal constant list at runtime.
final bool isMutable;
ListConstantBuilder(
Expression original, DartType elementType, ConstantEvaluator evaluator)
Expression original, DartType elementType, ConstantEvaluator evaluator,
{this.isMutable: false})
: super(original, elementType, evaluator);
@override
@ -115,9 +122,13 @@ class ListConstantBuilder extends _ListOrSetConstantBuilder<ListLiteral> {
Constant build() {
if (parts.length == 1) {
// Fully evaluated
if (isMutable) {
return new MutableListConstant(elementType, parts.single);
}
return evaluator
.lowerListConstant(new ListConstant(elementType, parts.single));
}
// TODO(kallentu): Handle partially evaluated [isMutable] lists.
List<Expression> lists = <Expression>[];
for (Object part in parts) {
if (part is List<Constant>) {

View file

@ -1337,11 +1337,12 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
@override
Constant visitListLiteral(ListLiteral node) {
if (!node.isConst) {
if (!node.isConst && !enableConstFunctions) {
return createInvalidExpressionConstant(node, "Non-constant list literal");
}
final ListConstantBuilder builder =
new ListConstantBuilder(node, convertType(node.typeArgument), this);
final ListConstantBuilder builder = new ListConstantBuilder(
node, convertType(node.typeArgument), this,
isMutable: !node.isConst);
// These expressions are at the same level, so one of them being
// unevaluated doesn't mean a sibling is or has an unevaluated child.
// We therefore reset it before each call, combine it and set it correctly
@ -2259,6 +2260,12 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
typeEnvironment.coreTypes.intNonNullableRawType,
other.getType(_staticTypeContext),
isNonNullableByDefault));
case 'add':
if (receiver is MutableListConstant) {
receiver.entries.add(other);
return receiver;
}
return new _AbortDueToThrowConstant(node, new UnsupportedError(op));
}
}
} else if (receiver is MapConstant && enableConstFunctions) {
@ -4041,6 +4048,15 @@ class BreakStatus extends ExecutionStatus {
BreakStatus(this.target);
}
/// Mutable lists used within the [ConstantEvaluator].
class MutableListConstant extends ListConstant {
MutableListConstant(DartType typeArgument, List<Constant> entries)
: super(typeArgument, entries);
@override
String toString() => 'MutableListConstant(${toStringInternal()})';
}
/// An intermediate result that is used for invoking function nodes with their
/// respective environment within the [ConstantEvaluator].
class FunctionValue implements Constant {

View file

@ -110,6 +110,19 @@ int rangeErrorCatchFn() {
return 1;
}
const mutableListVar = mutableList();
List<int> mutableList() {
List<int> x = [1, 2];
return x;
}
const mutableListAddVar = mutableListAdd();
List<int> mutableListAdd() {
List<int> x = [1, 2];
x.add(3);
return x;
}
void main() {
Expect.equals(firstVar, 1);
Expect.equals(firstCatchVar, 0);
@ -124,4 +137,6 @@ void main() {
Expect.equals(typeVar, int);
Expect.equals(getWithIndexVar, 1);
Expect.equals(rangeErrorCatchVar, 0);
Expect.equals(mutableListVar, const [1, 2]);
Expect.equals(mutableListAddVar, const [1, 2, 3]);
}

View file

@ -19,12 +19,14 @@ static const field core::Type typeExample = #C6;
static const field core::Type typeVar = #C6;
static const field core::int getWithIndexVar = #C1;
static const field core::int rangeErrorCatchVar = #C2;
static const field core::List<core::int> mutableListVar = #C7;
static const field core::List<core::int> mutableListAddVar = #C9;
static method firstFn() → core::int {
return (#C7).{core::Iterable::first};
}
static method firstCatchFn() → core::int {
try {
core::int v = (#C8).{core::Iterable::first};
core::int v = (#C10).{core::Iterable::first};
}
on core::StateError catch(no-exception-var) {
return 0;
@ -42,7 +44,7 @@ static method lastFn() → core::int {
}
static method lastCatchFn() → core::int {
try {
core::int v = (#C8).{core::Iterable::last};
core::int v = (#C10).{core::Iterable::last};
}
on core::StateError catch(no-exception-var) {
return 0;
@ -53,11 +55,11 @@ static method lengthFn() → core::int {
return (#C7).{core::List::length};
}
static method singleFn() → core::int {
return (#C9).{core::Iterable::single};
return (#C11).{core::Iterable::single};
}
static method singleCatchFn() → core::int {
try {
core::int v = (#C8).{core::Iterable::single};
core::int v = (#C10).{core::Iterable::single};
}
on core::StateError catch(no-exception-var) {
return 0;
@ -77,17 +79,26 @@ static method typeFn() → core::Type {
return (#C7).{core::Object::runtimeType};
}
static method getWithIndexFn() → core::int {
return (#C9).{core::List::[]}(0);
return (#C11).{core::List::[]}(0);
}
static method rangeErrorCatchFn() → core::int {
try {
core::int v = (#C9).{core::List::[]}(1);
core::int v = (#C11).{core::List::[]}(1);
}
on core::RangeError catch(no-exception-var) {
return 0;
}
return 1;
}
static method mutableList() → core::List<core::int> {
core::List<core::int> x = <core::int>[1, 2];
return x;
}
static method mutableListAdd() → core::List<core::int> {
core::List<core::int> x = <core::int>[1, 2];
x.{core::List::add}(3);
return x;
}
static method main() → void {
exp::Expect::equals(#C1, 1);
exp::Expect::equals(#C2, 0);
@ -102,6 +113,8 @@ static method main() → void {
exp::Expect::equals(#C6, #C6);
exp::Expect::equals(#C1, 1);
exp::Expect::equals(#C2, 0);
exp::Expect::equals(#C7, #C7);
exp::Expect::equals(#C9, #C9);
}
constants {
@ -112,6 +125,8 @@ constants {
#C5 = 2
#C6 = TypeLiteralConstant(core::int)
#C7 = <core::int>[#C1, #C5]
#C8 = <core::int>[]
#C9 = <core::int>[#C1]
#C8 = 3
#C9 = <core::int>[#C1, #C5, #C8]
#C10 = <core::int>[]
#C11 = <core::int>[#C1]
}

View file

@ -19,12 +19,14 @@ static const field core::Type typeExample = #C6;
static const field core::Type typeVar = #C6;
static const field core::int getWithIndexVar = #C1;
static const field core::int rangeErrorCatchVar = #C2;
static const field core::List<core::int> mutableListVar = #C7;
static const field core::List<core::int> mutableListAddVar = #C9;
static method firstFn() → core::int {
return (#C7).{core::Iterable::first};
}
static method firstCatchFn() → core::int {
try {
core::int v = (#C8).{core::Iterable::first};
core::int v = (#C10).{core::Iterable::first};
}
on core::StateError catch(no-exception-var) {
return 0;
@ -42,7 +44,7 @@ static method lastFn() → core::int {
}
static method lastCatchFn() → core::int {
try {
core::int v = (#C8).{core::Iterable::last};
core::int v = (#C10).{core::Iterable::last};
}
on core::StateError catch(no-exception-var) {
return 0;
@ -53,11 +55,11 @@ static method lengthFn() → core::int {
return (#C7).{core::List::length};
}
static method singleFn() → core::int {
return (#C9).{core::Iterable::single};
return (#C11).{core::Iterable::single};
}
static method singleCatchFn() → core::int {
try {
core::int v = (#C8).{core::Iterable::single};
core::int v = (#C10).{core::Iterable::single};
}
on core::StateError catch(no-exception-var) {
return 0;
@ -77,17 +79,26 @@ static method typeFn() → core::Type {
return (#C7).{core::Object::runtimeType};
}
static method getWithIndexFn() → core::int {
return (#C9).{core::List::[]}(0);
return (#C11).{core::List::[]}(0);
}
static method rangeErrorCatchFn() → core::int {
try {
core::int v = (#C9).{core::List::[]}(1);
core::int v = (#C11).{core::List::[]}(1);
}
on core::RangeError catch(no-exception-var) {
return 0;
}
return 1;
}
static method mutableList() → core::List<core::int> {
core::List<core::int> x = core::_GrowableList::_literal2<core::int>(1, 2);
return x;
}
static method mutableListAdd() → core::List<core::int> {
core::List<core::int> x = core::_GrowableList::_literal2<core::int>(1, 2);
x.{core::List::add}(3);
return x;
}
static method main() → void {
exp::Expect::equals(#C1, 1);
exp::Expect::equals(#C2, 0);
@ -102,6 +113,8 @@ static method main() → void {
exp::Expect::equals(#C6, #C6);
exp::Expect::equals(#C1, 1);
exp::Expect::equals(#C2, 0);
exp::Expect::equals(#C7, #C7);
exp::Expect::equals(#C9, #C9);
}
constants {
@ -112,6 +125,8 @@ constants {
#C5 = 2
#C6 = TypeLiteralConstant(core::int)
#C7 = <core::int>[#C1, #C5]
#C8 = <core::int>[]
#C9 = <core::int>[#C1]
#C8 = 3
#C9 = <core::int>[#C1, #C5, #C8]
#C10 = <core::int>[]
#C11 = <core::int>[#C1]
}

View file

@ -27,4 +27,8 @@ const getWithIndexVar = getWithIndexFn();
int getWithIndexFn() {}
const rangeErrorCatchVar = rangeErrorCatchFn();
int rangeErrorCatchFn() {}
const mutableListVar = mutableList();
List<int> mutableList() {}
const mutableListAddVar = mutableListAdd();
List<int> mutableListAdd() {}
void main() {}

View file

@ -1,5 +1,7 @@
import "package:expect/expect.dart";
List<int> mutableList() {}
List<int> mutableListAdd() {}
Type typeFn() {}
bool isEmptyFn() {}
bool isNotEmptyFn() {}
@ -11,6 +13,8 @@ const isNotEmptyVar = isNotEmptyFn();
const lastCatchVar = lastCatchFn();
const lastVar = lastFn();
const lengthVar = lengthFn();
const mutableListAddVar = mutableListAdd();
const mutableListVar = mutableList();
const rangeErrorCatchVar = rangeErrorCatchFn();
const singleCatchVar = singleCatchFn();
const singleCatchVar2 = singleCatchFn2();

View file

@ -19,12 +19,14 @@ static const field core::Type typeExample = #C6;
static const field core::Type typeVar = #C6;
static const field core::int getWithIndexVar = #C1;
static const field core::int rangeErrorCatchVar = #C2;
static const field core::List<core::int> mutableListVar = #C7;
static const field core::List<core::int> mutableListAddVar = #C9;
static method firstFn() → core::int {
return (#C7).{core::Iterable::first};
}
static method firstCatchFn() → core::int {
try {
core::int v = (#C8).{core::Iterable::first};
core::int v = (#C10).{core::Iterable::first};
}
on core::StateError catch(no-exception-var) {
return 0;
@ -42,7 +44,7 @@ static method lastFn() → core::int {
}
static method lastCatchFn() → core::int {
try {
core::int v = (#C8).{core::Iterable::last};
core::int v = (#C10).{core::Iterable::last};
}
on core::StateError catch(no-exception-var) {
return 0;
@ -53,11 +55,11 @@ static method lengthFn() → core::int {
return (#C7).{core::List::length};
}
static method singleFn() → core::int {
return (#C9).{core::Iterable::single};
return (#C11).{core::Iterable::single};
}
static method singleCatchFn() → core::int {
try {
core::int v = (#C8).{core::Iterable::single};
core::int v = (#C10).{core::Iterable::single};
}
on core::StateError catch(no-exception-var) {
return 0;
@ -77,17 +79,26 @@ static method typeFn() → core::Type {
return (#C7).{core::Object::runtimeType};
}
static method getWithIndexFn() → core::int {
return (#C9).{core::List::[]}(0);
return (#C11).{core::List::[]}(0);
}
static method rangeErrorCatchFn() → core::int {
try {
core::int v = (#C9).{core::List::[]}(1);
core::int v = (#C11).{core::List::[]}(1);
}
on core::RangeError catch(no-exception-var) {
return 0;
}
return 1;
}
static method mutableList() → core::List<core::int> {
core::List<core::int> x = <core::int>[1, 2];
return x;
}
static method mutableListAdd() → core::List<core::int> {
core::List<core::int> x = <core::int>[1, 2];
x.{core::List::add}(3);
return x;
}
static method main() → void {
exp::Expect::equals(#C1, 1);
exp::Expect::equals(#C2, 0);
@ -102,6 +113,8 @@ static method main() → void {
exp::Expect::equals(#C6, #C6);
exp::Expect::equals(#C1, 1);
exp::Expect::equals(#C2, 0);
exp::Expect::equals(#C7, #C7);
exp::Expect::equals(#C9, #C9);
}
constants {
@ -112,6 +125,8 @@ constants {
#C5 = 2
#C6 = TypeLiteralConstant(core::int*)
#C7 = <core::int*>[#C1, #C5]
#C8 = <core::int*>[]
#C9 = <core::int*>[#C1]
#C8 = 3
#C9 = <core::int*>[#C1, #C5, #C8]
#C10 = <core::int*>[]
#C11 = <core::int*>[#C1]
}

View file

@ -18,6 +18,8 @@ static const field core::Type typeExample = core::int;
static const field core::Type typeVar = self::typeFn();
static const field core::int getWithIndexVar = self::getWithIndexFn();
static const field core::int rangeErrorCatchVar = self::rangeErrorCatchFn();
static const field core::List<core::int> mutableListVar = self::mutableList();
static const field core::List<core::int> mutableListAddVar = self::mutableListAdd();
static method firstFn() → core::int
;
static method firstCatchFn() → core::int
@ -44,10 +46,14 @@ static method getWithIndexFn() → core::int
;
static method rangeErrorCatchFn() → core::int
;
static method mutableList() → core::List<core::int>
;
static method mutableListAdd() → core::List<core::int>
;
static method main() → void
;
Extra constant evaluation status:
Evaluated: TypeLiteral @ org-dartlang-testcase:///const_functions_list.dart:89:21 -> TypeLiteralConstant(int*)
Extra constant evaluation: evaluated: 14, effectively constant: 1
Extra constant evaluation: evaluated: 16, effectively constant: 1

View file

@ -19,12 +19,14 @@ static const field core::Type typeExample = #C6;
static const field core::Type typeVar = #C6;
static const field core::int getWithIndexVar = #C1;
static const field core::int rangeErrorCatchVar = #C2;
static const field core::List<core::int> mutableListVar = #C7;
static const field core::List<core::int> mutableListAddVar = #C9;
static method firstFn() → core::int {
return (#C7).{core::Iterable::first};
}
static method firstCatchFn() → core::int {
try {
core::int v = (#C8).{core::Iterable::first};
core::int v = (#C10).{core::Iterable::first};
}
on core::StateError catch(no-exception-var) {
return 0;
@ -42,7 +44,7 @@ static method lastFn() → core::int {
}
static method lastCatchFn() → core::int {
try {
core::int v = (#C8).{core::Iterable::last};
core::int v = (#C10).{core::Iterable::last};
}
on core::StateError catch(no-exception-var) {
return 0;
@ -53,11 +55,11 @@ static method lengthFn() → core::int {
return (#C7).{core::List::length};
}
static method singleFn() → core::int {
return (#C9).{core::Iterable::single};
return (#C11).{core::Iterable::single};
}
static method singleCatchFn() → core::int {
try {
core::int v = (#C8).{core::Iterable::single};
core::int v = (#C10).{core::Iterable::single};
}
on core::StateError catch(no-exception-var) {
return 0;
@ -77,17 +79,26 @@ static method typeFn() → core::Type {
return (#C7).{core::Object::runtimeType};
}
static method getWithIndexFn() → core::int {
return (#C9).{core::List::[]}(0);
return (#C11).{core::List::[]}(0);
}
static method rangeErrorCatchFn() → core::int {
try {
core::int v = (#C9).{core::List::[]}(1);
core::int v = (#C11).{core::List::[]}(1);
}
on core::RangeError catch(no-exception-var) {
return 0;
}
return 1;
}
static method mutableList() → core::List<core::int> {
core::List<core::int> x = core::_GrowableList::_literal2<core::int>(1, 2);
return x;
}
static method mutableListAdd() → core::List<core::int> {
core::List<core::int> x = core::_GrowableList::_literal2<core::int>(1, 2);
x.{core::List::add}(3);
return x;
}
static method main() → void {
exp::Expect::equals(#C1, 1);
exp::Expect::equals(#C2, 0);
@ -102,6 +113,8 @@ static method main() → void {
exp::Expect::equals(#C6, #C6);
exp::Expect::equals(#C1, 1);
exp::Expect::equals(#C2, 0);
exp::Expect::equals(#C7, #C7);
exp::Expect::equals(#C9, #C9);
}
constants {
@ -112,6 +125,8 @@ constants {
#C5 = 2
#C6 = TypeLiteralConstant(core::int*)
#C7 = <core::int*>[#C1, #C5]
#C8 = <core::int*>[]
#C9 = <core::int*>[#C1]
#C8 = 3
#C9 = <core::int*>[#C1, #C5, #C8]
#C10 = <core::int*>[]
#C11 = <core::int*>[#C1]
}

View file

@ -54,4 +54,11 @@ int getWithIndexExceptionFn3() {
return x[0.1];
}
const constListAddException = constListAddExceptionFn();
List<int> constListAddExceptionFn() {
const List<int> x = [1, 2];
x.add(3);
return x;
}
void main() {}

View file

@ -54,6 +54,13 @@ library /*isNonNullableByDefault*/;
// return x[-1];
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:57:31: Error: Constant evaluation error:
// const constListAddException = constListAddExceptionFn();
// ^
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:60:5: Context: Unhandled core exception: Unsupported operation: add
// x.add(3);
// ^
//
import self as self;
import "dart:core" as core;
@ -73,6 +80,7 @@ static const field core::int getWithIndexException2 = invalid-expression "Unhand
static const field core::int getWithIndexException3 = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_list_error.dart:54:12: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
return x[0.1];
^";
static const field core::List<core::int> constListAddException = invalid-expression "Unhandled core exception: Unsupported operation: add";
static method firstExceptionFn() → core::int {
return (#C1).{core::Iterable::first};
}
@ -103,6 +111,10 @@ static method getWithIndexExceptionFn3() → core::int {
return x[0.1];
^" in 0.1 as{TypeError,ForNonNullableByDefault} core::int);
}
static method constListAddExceptionFn() → core::List<core::int> {
(#C4).{core::List::add}(3);
return #C4;
}
static method main() → void {}
constants {

View file

@ -54,6 +54,13 @@ library /*isNonNullableByDefault*/;
// return x[-1];
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:57:31: Error: Constant evaluation error:
// const constListAddException = constListAddExceptionFn();
// ^
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:60:5: Context: Unhandled core exception: Unsupported operation: add
// x.add(3);
// ^
//
import self as self;
import "dart:core" as core;
@ -73,6 +80,7 @@ static const field core::int getWithIndexException2 = invalid-expression "Unhand
static const field core::int getWithIndexException3 = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_list_error.dart:54:12: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
return x[0.1];
^";
static const field core::List<core::int> constListAddException = invalid-expression "Unhandled core exception: Unsupported operation: add";
static method firstExceptionFn() → core::int {
return (#C1).{core::Iterable::first};
}
@ -103,6 +111,10 @@ static method getWithIndexExceptionFn3() → core::int {
return x[0.1];
^" in 0.1 as{TypeError,ForNonNullableByDefault} core::int);
}
static method constListAddExceptionFn() → core::List<core::int> {
(#C4).{core::List::add}(3);
return #C4;
}
static method main() → void {}
constants {
@ -115,4 +127,4 @@ constants {
Extra constant evaluation status:
Evaluated: MethodInvocation @ org-dartlang-testcase:///const_functions_list_error.dart:48:12 -> IntConstant(-1)
Extra constant evaluation: evaluated: 10, effectively constant: 1
Extra constant evaluation: evaluated: 11, effectively constant: 1

View file

@ -16,4 +16,6 @@ const getWithIndexException2 = getWithIndexExceptionFn2();
int getWithIndexExceptionFn2() {}
const getWithIndexException3 = getWithIndexExceptionFn3();
int getWithIndexExceptionFn3() {}
const constListAddException = constListAddExceptionFn();
List<int> constListAddExceptionFn() {}
void main() {}

View file

@ -1,5 +1,7 @@
import "package:expect/expect.dart";
List<int> constListAddExceptionFn() {}
const constListAddException = constListAddExceptionFn();
const firstException = firstExceptionFn();
const getWithIndexException = getWithIndexExceptionFn();
const getWithIndexException2 = getWithIndexExceptionFn2();

View file

@ -54,6 +54,13 @@ library /*isNonNullableByDefault*/;
// return x[-1];
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:57:31: Error: Constant evaluation error:
// const constListAddException = constListAddExceptionFn();
// ^
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:60:5: Context: Unhandled core exception: Unsupported operation: add
// x.add(3);
// ^
//
import self as self;
import "dart:core" as core;
@ -73,6 +80,7 @@ static const field core::int getWithIndexException2 = invalid-expression "Unhand
static const field core::int getWithIndexException3 = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_list_error.dart:54:12: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
return x[0.1];
^";
static const field core::List<core::int> constListAddException = invalid-expression "Unhandled core exception: Unsupported operation: add";
static method firstExceptionFn() → core::int {
return (#C1).{core::Iterable::first};
}
@ -103,6 +111,10 @@ static method getWithIndexExceptionFn3() → core::int {
return x[0.1];
^" in 0.1 as{TypeError,ForNonNullableByDefault} core::int);
}
static method constListAddExceptionFn() → core::List<core::int> {
(#C4).{core::List::add}(3);
return #C4;
}
static method main() → void {}
constants {

View file

@ -12,6 +12,7 @@ static const field core::int invalidProperty = self::invalidPropertyFn();
static const field core::int getWithIndexException = self::getWithIndexExceptionFn();
static const field core::int getWithIndexException2 = self::getWithIndexExceptionFn2();
static const field core::int getWithIndexException3 = self::getWithIndexExceptionFn3();
static const field core::List<core::int> constListAddException = self::constListAddExceptionFn();
static method firstExceptionFn() → core::int
;
static method lastExceptionFn() → core::int
@ -28,5 +29,7 @@ static method getWithIndexExceptionFn2() → core::int
;
static method getWithIndexExceptionFn3() → core::int
;
static method constListAddExceptionFn() → core::List<core::int>
;
static method main() → void
;

View file

@ -54,6 +54,13 @@ library /*isNonNullableByDefault*/;
// return x[-1];
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:57:31: Error: Constant evaluation error:
// const constListAddException = constListAddExceptionFn();
// ^
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:60:5: Context: Unhandled core exception: Unsupported operation: add
// x.add(3);
// ^
//
import self as self;
import "dart:core" as core;
@ -73,6 +80,7 @@ static const field core::int getWithIndexException2 = invalid-expression "Unhand
static const field core::int getWithIndexException3 = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_list_error.dart:54:12: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
return x[0.1];
^";
static const field core::List<core::int> constListAddException = invalid-expression "Unhandled core exception: Unsupported operation: add";
static method firstExceptionFn() → core::int {
return (#C1).{core::Iterable::first};
}
@ -103,6 +111,10 @@ static method getWithIndexExceptionFn3() → core::int {
return x[0.1];
^" in 0.1 as{TypeError,ForNonNullableByDefault} core::int);
}
static method constListAddExceptionFn() → core::List<core::int> {
(#C4).{core::List::add}(3);
return #C4;
}
static method main() → void {}
constants {
@ -115,4 +127,4 @@ constants {
Extra constant evaluation status:
Evaluated: MethodInvocation @ org-dartlang-testcase:///const_functions_list_error.dart:48:12 -> IntConstant(-1)
Extra constant evaluation: evaluated: 10, effectively constant: 1
Extra constant evaluation: evaluated: 11, effectively constant: 1

View file

@ -83,3 +83,13 @@ int getWithIndexExceptionFn3() {
// [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// [cfe] A value of type 'double' can't be assigned to a variable of type 'int'.
}
const constListAddException = constListAddExceptionFn();
// ^^^^^^^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
// [cfe] Constant evaluation error:
List<int> constListAddExceptionFn() {
const List<int> x = [1, 2];
x.add(3);
return x;
}

View file

@ -158,6 +158,23 @@ int rangeErrorCatchFn() {
return 1;
}
const mutableListVar = mutableList();
// ^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
List<int> mutableList() {
List<int> x = [1, 2];
return x;
}
const mutableListAddVar = mutableListAdd();
// ^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
List<int> mutableListAdd() {
List<int> x = [1, 2];
x.add(3);
return x;
}
void main() {
Expect.equals(firstVar, 1);
Expect.equals(firstCatchVar, 0);
@ -173,4 +190,6 @@ void main() {
Expect.equals(typeVar, int);
Expect.equals(getWithIndexVar, 1);
Expect.equals(rangeErrorCatchVar, 0);
Expect.equals(mutableListVar, const [1, 2]);
Expect.equals(mutableListAddVar, const [1, 2, 3]);
}