Skip to content

Commit c32eddd

Browse files
chloestefantsovaCommit Queue
authored andcommitted
[cfe] Report "!" in constant expressions as error
Closes #59800 Change-Id: I06d68eb1d0608a0a865002c88f7665415159f468 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/405901 Commit-Queue: Chloe Stefantsova <[email protected]> Reviewed-by: Johnni Winther <[email protected]> Reviewed-by: Mayank Patke <[email protected]>
1 parent bfc2fc0 commit c32eddd

19 files changed

+491
-109
lines changed

pkg/compiler/test/model/cfe_constant_evaluation_common.dart

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -604,9 +604,6 @@ class B extends A {
604604
final b;
605605
const D(c) : b = c + 2, super(c + 1);
606606
}
607-
class E {
608-
const E() : assert(true_!);
609-
}
610607
''',
611608
[
612609
ConstantData(r'const A()', 'ConstructedConstant(A())'),
@@ -615,7 +612,6 @@ class B extends A {
615612
r'const D(0)',
616613
'ConstructedConstant(D(a=IntConstant(1),b=IntConstant(2)))',
617614
),
618-
ConstantData(r'const E()', 'ConstructedConstant(E())'),
619615
],
620616
),
621617
TestData(

pkg/front_end/lib/src/kernel/constant_evaluator.dart

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4716,16 +4716,20 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
47164716

47174717
@override
47184718
Constant visitNullCheck(NullCheck node) {
4719-
final Constant constant = _evaluateSubexpression(node.operand);
4720-
if (constant is AbortConstant) return constant;
4721-
if (constant is NullConstant) {
4722-
return createEvaluationErrorConstant(node, messageConstEvalNonNull);
4723-
}
4724-
if (shouldBeUnevaluated) {
4719+
if (enableConstFunctions) {
47254720
// Coverage-ignore-block(suite): Not run.
4726-
return unevaluated(node, new NullCheck(_wrap(constant)));
4721+
final Constant constant = _evaluateSubexpression(node.operand);
4722+
if (constant is AbortConstant) return constant;
4723+
if (constant is NullConstant) {
4724+
return createEvaluationErrorConstant(node, messageConstEvalNonNull);
4725+
}
4726+
if (shouldBeUnevaluated) {
4727+
return unevaluated(node, new NullCheck(_wrap(constant)));
4728+
}
4729+
return constant;
4730+
} else {
4731+
return _notAConstantExpression(node);
47274732
}
4728-
return constant;
47294733
}
47304734

47314735
@override

pkg/front_end/lib/src/kernel/expression_generator.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,6 @@ abstract class Generator {
205205
} else {
206206
if (_helper.constantContext != ConstantContext.none &&
207207
selector.name != lengthName) {
208-
// Coverage-ignore-block(suite): Not run.
209208
_helper.addProblem(
210209
messageNotAConstantExpression, fileOffset, token.length);
211210
}

pkg/front_end/test/coverage_suite_expected.dart

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,10 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
148148
hitCount: 97,
149149
missCount: 0,
150150
),
151-
// 99.88331388564761%.
151+
// 100.0%.
152152
"package:front_end/src/base/incremental_compiler.dart": (
153153
hitCount: 856,
154-
missCount: 1,
154+
missCount: 0,
155155
),
156156
// 100.0%.
157157
"package:front_end/src/base/incremental_serializer.dart": (
@@ -183,10 +183,10 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
183183
hitCount: 31,
184184
missCount: 0,
185185
),
186-
// 99.26470588235294%.
186+
// 100.0%.
187187
"package:front_end/src/base/modifiers.dart": (
188188
hitCount: 135,
189-
missCount: 1,
189+
missCount: 0,
190190
),
191191
// 100.0%.
192192
"package:front_end/src/base/name_space.dart": (
@@ -208,10 +208,10 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
208208
hitCount: 260,
209209
missCount: 0,
210210
),
211-
// 99.38837920489296%.
211+
// 100.0%.
212212
"package:front_end/src/base/scope.dart": (
213213
hitCount: 650,
214-
missCount: 4,
214+
missCount: 0,
215215
),
216216
// 100.0%.
217217
"package:front_end/src/base/ticker.dart": (
@@ -615,7 +615,7 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
615615
),
616616
// 100.0%.
617617
"package:front_end/src/kernel/constant_evaluator.dart": (
618-
hitCount: 3735,
618+
hitCount: 3731,
619619
missCount: 0,
620620
),
621621
// 100.0%.
@@ -640,7 +640,7 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
640640
),
641641
// 100.0%.
642642
"package:front_end/src/kernel/expression_generator.dart": (
643-
hitCount: 2522,
643+
hitCount: 2527,
644644
missCount: 0,
645645
),
646646
// 100.0%.
@@ -944,10 +944,10 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
944944
hitCount: 1003,
945945
missCount: 0,
946946
),
947-
// 97.91666666666666%.
947+
// 100.0%.
948948
"package:front_end/src/source/source_function_builder.dart": (
949949
hitCount: 47,
950-
missCount: 1,
950+
missCount: 0,
951951
),
952952
// 100.0%.
953953
"package:front_end/src/source/source_library_builder.dart": (
@@ -1109,10 +1109,10 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
11091109
hitCount: 20,
11101110
missCount: 0,
11111111
),
1112-
// 92.0%.
1112+
// 100.0%.
11131113
"package:front_end/src/util/local_stack.dart": (
11141114
hitCount: 23,
1115-
missCount: 2,
1115+
missCount: 0,
11161116
),
11171117
// 100.0%.
11181118
"package:front_end/src/util/parser_ast.dart": (
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
class A {
6+
final int? foo;
7+
const A(this.foo);
8+
}
9+
10+
const int? CNull = null;
11+
const int? CInt = 0;
12+
const A CANull = const A(null);
13+
const A CAInt = const A(0);
14+
15+
const int C1 = 0!; // Error.
16+
const int C2 = null!; // Error.
17+
const int C3 = CInt!; // Error.
18+
const int C4 = CNull!; // Error.
19+
const int C5 = CAInt.foo!; // Error.
20+
const int C6 = CANull.foo!; // Error.
21+
const int C7 = "".length!; // Error.
22+
const int C8 = ""!.length; // Error.
23+
const int C9 = ""!.length!; // Error.
24+
25+
test() {
26+
return [C1, C2, C3, C4, C5, C6, C7, C8, C9];
27+
}
28+
29+
main() {}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/general/issue59800.dart:19:16: Error: Not a constant expression.
6+
// const int C5 = CAInt.foo!; // Error.
7+
// ^^^^^
8+
//
9+
// pkg/front_end/testcases/general/issue59800.dart:20:16: Error: Not a constant expression.
10+
// const int C6 = CANull.foo!; // Error.
11+
// ^^^^^^
12+
//
13+
// pkg/front_end/testcases/general/issue59800.dart:15:17: Error: Not a constant expression.
14+
// const int C1 = 0!; // Error.
15+
// ^
16+
//
17+
// pkg/front_end/testcases/general/issue59800.dart:16:20: Error: Not a constant expression.
18+
// const int C2 = null!; // Error.
19+
// ^
20+
//
21+
// pkg/front_end/testcases/general/issue59800.dart:17:20: Error: Not a constant expression.
22+
// const int C3 = CInt!; // Error.
23+
// ^
24+
//
25+
// pkg/front_end/testcases/general/issue59800.dart:18:21: Error: Not a constant expression.
26+
// const int C4 = CNull!; // Error.
27+
// ^
28+
//
29+
// pkg/front_end/testcases/general/issue59800.dart:19:25: Error: Not a constant expression.
30+
// const int C5 = CAInt.foo!; // Error.
31+
// ^
32+
//
33+
// pkg/front_end/testcases/general/issue59800.dart:20:26: Error: Not a constant expression.
34+
// const int C6 = CANull.foo!; // Error.
35+
// ^
36+
//
37+
// pkg/front_end/testcases/general/issue59800.dart:21:25: Error: Not a constant expression.
38+
// const int C7 = "".length!; // Error.
39+
// ^
40+
//
41+
// pkg/front_end/testcases/general/issue59800.dart:22:18: Error: Not a constant expression.
42+
// const int C8 = ""!.length; // Error.
43+
// ^
44+
//
45+
// pkg/front_end/testcases/general/issue59800.dart:23:26: Error: Not a constant expression.
46+
// const int C9 = ""!.length!; // Error.
47+
// ^
48+
//
49+
import self as self;
50+
import "dart:core" as core;
51+
52+
class A extends core::Object /*hasConstConstructor*/ {
53+
final field core::int? foo;
54+
const constructor •(core::int? foo) → self::A
55+
: self::A::foo = foo, super core::Object::•()
56+
;
57+
}
58+
static const field core::int? CNull = #C1;
59+
static const field core::int? CInt = #C2;
60+
static const field self::A CANull = #C3;
61+
static const field self::A CAInt = #C4;
62+
static const field core::int C1 = invalid-expression "Not a constant expression.";
63+
static const field core::int C2 = invalid-expression "Not a constant expression.";
64+
static const field core::int C3 = invalid-expression "Not a constant expression.";
65+
static const field core::int C4 = invalid-expression "Not a constant expression.";
66+
static const field core::int C5 = invalid-expression "Not a constant expression.";
67+
static const field core::int C6 = invalid-expression "Not a constant expression.";
68+
static const field core::int C7 = invalid-expression "Not a constant expression.";
69+
static const field core::int C8 = invalid-expression "Not a constant expression.";
70+
static const field core::int C9 = invalid-expression "Not a constant expression.";
71+
static method test() → dynamic {
72+
return <core::int>[invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression."];
73+
}
74+
static method main() → dynamic {}
75+
76+
constants {
77+
#C1 = null
78+
#C2 = 0
79+
#C3 = self::A {foo:#C1}
80+
#C4 = self::A {foo:#C2}
81+
}
82+
83+
84+
Constructor coverage from constants:
85+
org-dartlang-testcase:///issue59800.dart:
86+
- A. (from org-dartlang-testcase:///issue59800.dart:7:9)
87+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/general/issue59800.dart:19:16: Error: Not a constant expression.
6+
// const int C5 = CAInt.foo!; // Error.
7+
// ^^^^^
8+
//
9+
// pkg/front_end/testcases/general/issue59800.dart:20:16: Error: Not a constant expression.
10+
// const int C6 = CANull.foo!; // Error.
11+
// ^^^^^^
12+
//
13+
// pkg/front_end/testcases/general/issue59800.dart:15:17: Error: Not a constant expression.
14+
// const int C1 = 0!; // Error.
15+
// ^
16+
//
17+
// pkg/front_end/testcases/general/issue59800.dart:16:20: Error: Not a constant expression.
18+
// const int C2 = null!; // Error.
19+
// ^
20+
//
21+
// pkg/front_end/testcases/general/issue59800.dart:17:20: Error: Not a constant expression.
22+
// const int C3 = CInt!; // Error.
23+
// ^
24+
//
25+
// pkg/front_end/testcases/general/issue59800.dart:18:21: Error: Not a constant expression.
26+
// const int C4 = CNull!; // Error.
27+
// ^
28+
//
29+
// pkg/front_end/testcases/general/issue59800.dart:19:25: Error: Not a constant expression.
30+
// const int C5 = CAInt.foo!; // Error.
31+
// ^
32+
//
33+
// pkg/front_end/testcases/general/issue59800.dart:20:26: Error: Not a constant expression.
34+
// const int C6 = CANull.foo!; // Error.
35+
// ^
36+
//
37+
// pkg/front_end/testcases/general/issue59800.dart:21:25: Error: Not a constant expression.
38+
// const int C7 = "".length!; // Error.
39+
// ^
40+
//
41+
// pkg/front_end/testcases/general/issue59800.dart:22:18: Error: Not a constant expression.
42+
// const int C8 = ""!.length; // Error.
43+
// ^
44+
//
45+
// pkg/front_end/testcases/general/issue59800.dart:23:26: Error: Not a constant expression.
46+
// const int C9 = ""!.length!; // Error.
47+
// ^
48+
//
49+
import self as self;
50+
import "dart:core" as core;
51+
52+
class A extends core::Object /*hasConstConstructor*/ {
53+
final field core::int? foo;
54+
const constructor •(core::int? foo) → self::A
55+
: self::A::foo = foo, super core::Object::•()
56+
;
57+
}
58+
static const field core::int? CNull = #C1;
59+
static const field core::int? CInt = #C2;
60+
static const field self::A CANull = #C3;
61+
static const field self::A CAInt = #C4;
62+
static const field core::int C1 = invalid-expression "Not a constant expression.";
63+
static const field core::int C2 = invalid-expression "Not a constant expression.";
64+
static const field core::int C3 = invalid-expression "Not a constant expression.";
65+
static const field core::int C4 = invalid-expression "Not a constant expression.";
66+
static const field core::int C5 = invalid-expression "Not a constant expression.";
67+
static const field core::int C6 = invalid-expression "Not a constant expression.";
68+
static const field core::int C7 = invalid-expression "Not a constant expression.";
69+
static const field core::int C8 = invalid-expression "Not a constant expression.";
70+
static const field core::int C9 = invalid-expression "Not a constant expression.";
71+
static method test() → dynamic {
72+
return <core::int>[invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression.", invalid-expression "Not a constant expression."];
73+
}
74+
static method main() → dynamic {}
75+
76+
constants {
77+
#C1 = null
78+
#C2 = 0
79+
#C3 = self::A {foo:#C1}
80+
#C4 = self::A {foo:#C2}
81+
}
82+
83+
84+
Constructor coverage from constants:
85+
org-dartlang-testcase:///issue59800.dart:
86+
- A. (from org-dartlang-testcase:///issue59800.dart:7:9)
87+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/general/issue59800.dart:19:16: Error: Not a constant expression.
6+
// const int C5 = CAInt.foo!; // Error.
7+
// ^^^^^
8+
//
9+
// pkg/front_end/testcases/general/issue59800.dart:20:16: Error: Not a constant expression.
10+
// const int C6 = CANull.foo!; // Error.
11+
// ^^^^^^
12+
//
13+
import self as self;
14+
import "dart:core" as core;
15+
16+
class A extends core::Object /*hasConstConstructor*/ {
17+
final field core::int? foo;
18+
const constructor •(core::int? foo) → self::A
19+
: self::A::foo = foo, super core::Object::•()
20+
;
21+
}
22+
static const field core::int? CNull = null;
23+
static const field core::int? CInt = 0;
24+
static const field self::A CANull = const self::A::•(null);
25+
static const field self::A CAInt = const self::A::•(0);
26+
static const field core::int C1 = 0!;
27+
static const field core::int C2 = null!;
28+
static const field core::int C3 = self::CInt!;
29+
static const field core::int C4 = self::CNull!;
30+
static const field core::int C5 = self::CAInt.{self::A::foo}{core::int?}!;
31+
static const field core::int C6 = self::CANull.{self::A::foo}{core::int?}!;
32+
static const field core::int C7 = "".{core::String::length}{core::int}!;
33+
static const field core::int C8 = ""!.{core::String::length}{core::int};
34+
static const field core::int C9 = ""!.{core::String::length}{core::int}!;
35+
static method test() → dynamic
36+
;
37+
static method main() → dynamic
38+
;
39+
40+
41+
Extra constant evaluation status:
42+
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///issue59800.dart:12:24 -> InstanceConstant(const A{A.foo: null})
43+
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///issue59800.dart:13:23 -> InstanceConstant(const A{A.foo: 0})
44+
Evaluated: StaticGet @ org-dartlang-testcase:///issue59800.dart:17:16 -> IntConstant(0)
45+
Evaluated: StaticGet @ org-dartlang-testcase:///issue59800.dart:18:16 -> NullConstant(null)
46+
Evaluated: StaticGet @ org-dartlang-testcase:///issue59800.dart:19:16 -> InstanceConstant(const A{A.foo: 0})
47+
Evaluated: StaticGet @ org-dartlang-testcase:///issue59800.dart:20:16 -> InstanceConstant(const A{A.foo: null})
48+
Evaluated: InstanceGet @ org-dartlang-testcase:///issue59800.dart:21:19 -> IntConstant(0)
49+
Extra constant evaluation: evaluated: 22, effectively constant: 7

0 commit comments

Comments
 (0)