Skip to content

Commit 8f723ec

Browse files
stereotype441Commit Queue
authored andcommitted
[sound flow analysis] Language tests.
The tests that don't end in `_disabled_test.dart` exercise all the new behaviors introduced with the `sound-flow-analysis` feature. The tests that _do_ end in `_disabled_test.dart` verify that when the language version is 3.8, the old behavior of flow analysis is preserved. For the sake of thoroughness, I've also elected to include tests for a few behaviors that aren't new, just because they seem logically related to the new behaviors (for example, in the tests for the `==` and `!=` operator, I've included a test that `null == null` is known to evaluate to `true`, even though this behavior existed even before the `sound-flow-analysis` feature was implemented). These tests are marked with the comment "(this behavior predates sound-flow-analysis)" in the `_disabled_test.dart` files. Bug: #60438 Change-Id: If2895355bb1a2eeb2415a5a1012d73ae87c244dd Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/423040 Reviewed-by: Erik Ernst <[email protected]> Commit-Queue: Paul Berry <[email protected]>
1 parent 59587b0 commit 8f723ec

18 files changed

+4424
-0
lines changed

tests/language/sound_flow_analysis/equality_comparisons_disabled_test.dart

Lines changed: 631 additions & 0 deletions
Large diffs are not rendered by default.

tests/language/sound_flow_analysis/equality_comparisons_test.dart

Lines changed: 629 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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+
// Exercises flow analysis of if-null expressions (expressions involving `??`)
6+
// when `sound-flow-analysis` is disabled.
7+
8+
// @dart = 3.8
9+
10+
// ignore_for_file: dead_null_aware_expression
11+
12+
import '../static_type_helper.dart';
13+
14+
// `<nonNullable> ?? <expr>` is not known to skip <expr>.
15+
testIfNull({required int intValue, required int Function() intFunction}) {
16+
{
17+
// <var> ?? <expr>
18+
int? shouldBeDemoted = 0;
19+
intValue ?? (shouldBeDemoted = null, 0).$2;
20+
shouldBeDemoted.expectStaticType<Exactly<int?>>();
21+
}
22+
23+
{
24+
// <expr> ?? <expr>
25+
int? shouldBeDemoted = 0;
26+
intFunction() ?? (shouldBeDemoted = null, 0).$2;
27+
shouldBeDemoted.expectStaticType<Exactly<int?>>();
28+
}
29+
}
30+
31+
// `<nonNullable> ??= <expr>` is not known to skip <expr>.
32+
testIfNullAssign({required int intValue, required List<int> listOfIntValue}) {
33+
{
34+
// <var> ??= <expr>
35+
int? shouldBeDemoted = 0;
36+
intValue ??= (shouldBeDemoted = null, 0).$2;
37+
shouldBeDemoted.expectStaticType<Exactly<int?>>();
38+
}
39+
40+
{
41+
// <promotedVar> ??= <expr>
42+
int? nullableIntValue = 0; // promote to `int`
43+
int? shouldBeDemoted = 0;
44+
nullableIntValue ??= (shouldBeDemoted = null, 0).$2;
45+
shouldBeDemoted.expectStaticType<Exactly<int?>>();
46+
}
47+
48+
{
49+
// <property> ??= <expr>
50+
int? shouldBeDemoted = 0;
51+
listOfIntValue.first ??= (shouldBeDemoted = null, 0).$2;
52+
shouldBeDemoted.expectStaticType<Exactly<int?>>();
53+
}
54+
55+
{
56+
// <indexOperation> ??= <expr>
57+
int? shouldBeDemoted = 0;
58+
listOfIntValue[0] ??= (shouldBeDemoted = null, 0).$2;
59+
shouldBeDemoted.expectStaticType<Exactly<int?>>();
60+
}
61+
}
62+
63+
main() {
64+
testIfNull(intValue: 0, intFunction: () => 0);
65+
testIfNullAssign(intValue: 0, listOfIntValue: [0]);
66+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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+
// Exercises flow analysis of if-null expressions (expressions involving `??`)
6+
// when `sound-flow-analysis` is enabled.
7+
8+
// SharedOptions=--enable-experiment=sound-flow-analysis
9+
10+
// ignore_for_file: dead_null_aware_expression
11+
12+
import '../static_type_helper.dart';
13+
14+
// `<nonNullable> ?? <expr>` is known to skip <expr>.
15+
testIfNull({required int intValue, required int Function() intFunction}) {
16+
{
17+
// <var> ?? <expr>
18+
int? shouldNotBeDemoted = 0;
19+
intValue ?? (shouldNotBeDemoted = null, 0).$2;
20+
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
21+
}
22+
23+
{
24+
// <expr> ?? <expr>
25+
int? shouldNotBeDemoted = 0;
26+
intFunction() ?? (shouldNotBeDemoted = null, 0).$2;
27+
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
28+
}
29+
}
30+
31+
// `<nonNullable> ??= <expr>` is known to skip <expr>.
32+
testIfNullAssign({required int intValue, required List<int> listOfIntValue}) {
33+
{
34+
// <var> ??= <expr>
35+
int? shouldNotBeDemoted = 0;
36+
intValue ??= (shouldNotBeDemoted = null, 0).$2;
37+
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
38+
}
39+
40+
{
41+
// <promotedVar> ??= <expr>
42+
int? nullableIntValue = 0; // promote to `int`
43+
int? shouldNotBeDemoted = 0;
44+
nullableIntValue ??= (shouldNotBeDemoted = null, 0).$2;
45+
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
46+
}
47+
48+
{
49+
// <property> ??= <expr>
50+
int? shouldNotBeDemoted = 0;
51+
listOfIntValue.first ??= (shouldNotBeDemoted = null, 0).$2;
52+
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
53+
}
54+
55+
{
56+
// <indexOperation> ??= <expr>
57+
int? shouldNotBeDemoted = 0;
58+
listOfIntValue[0] ??= (shouldNotBeDemoted = null, 0).$2;
59+
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
60+
}
61+
}
62+
63+
main() {
64+
testIfNull(intValue: 0, intFunction: () => 0);
65+
testIfNullAssign(intValue: 0, listOfIntValue: [0]);
66+
}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
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+
// Exercises flow analysis of null aware accesses (expressions involving `?.`)
6+
// when `sound-flow-analysis` is disabled.
7+
8+
// @dart = 3.8
9+
10+
// ignore_for_file: invalid_null_aware_operator
11+
12+
import '../static_type_helper.dart';
13+
14+
// `<nonNullable>?.bitLength.gcd(<expr>)` is not known to invoke <expr>.
15+
testProperty({required int intValue, required int Function() intFunction}) {
16+
{
17+
// <var>?.bitLength.gcd(<expr>)
18+
int? shouldNotBePromoted;
19+
intValue?.bitLength.gcd(shouldNotBePromoted = 0);
20+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
21+
}
22+
23+
{
24+
// <expr>?.bitLength.gcd(<expr>)
25+
int? shouldNotBePromoted;
26+
intFunction()?.bitLength.gcd(shouldNotBePromoted = 0);
27+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
28+
}
29+
}
30+
31+
// `<nonNullable>?.gcd(<expr>)` is not known to invoke <expr>.
32+
testCall({required int intValue, required int Function() intFunction}) {
33+
{
34+
// <var>?.gcd(<expr>)
35+
int? shouldNotBePromoted;
36+
intValue?.gcd(shouldNotBePromoted = 0);
37+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
38+
}
39+
40+
{
41+
// <expr>?.gcd(<expr>)
42+
int? shouldNotBePromoted;
43+
intFunction()?.gcd(shouldNotBePromoted = 0);
44+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
45+
}
46+
}
47+
48+
// `<nonNullable>?[<expr>]` is not known to invoke <expr>.
49+
testIndexGet({
50+
required List<int> listOfIntValue,
51+
required List<int> Function() listOfIntFunction,
52+
}) {
53+
{
54+
// <var>?[<expr>]
55+
int? shouldNotBePromoted;
56+
listOfIntValue?[shouldNotBePromoted = 0];
57+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
58+
}
59+
60+
{
61+
// <expr>?[<expr>]
62+
int? shouldNotBePromoted;
63+
listOfIntFunction()?[shouldNotBePromoted = 0];
64+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
65+
}
66+
}
67+
68+
// `<nonNullable>?[<expr>] = 0` is not known to invoke <expr>.
69+
testIndexSet({
70+
required List<int> listOfIntValue,
71+
required List<int> Function() listOfIntFunction,
72+
}) {
73+
{
74+
// <var>?[<expr>] = 0
75+
int? shouldNotBePromoted;
76+
listOfIntValue?[shouldNotBePromoted = 0] = 0;
77+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
78+
}
79+
80+
{
81+
// <expr>?[<expr>] = 0
82+
int? shouldNotBePromoted;
83+
listOfIntFunction()?[shouldNotBePromoted = 0] = 0;
84+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
85+
}
86+
}
87+
88+
// `<nonNullable>?..bitLength.gcd(<expr>)` is not known to invoke <expr>.
89+
testCascadedProperty({
90+
required int intValue,
91+
required int Function() intFunction,
92+
}) {
93+
{
94+
// <var>?..bitLength.gcd(<expr>)
95+
int? shouldNotBePromoted;
96+
intValue?..bitLength.gcd(shouldNotBePromoted = 0);
97+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
98+
}
99+
100+
{
101+
// <expr>?..bitLength.gcd(<expr>)
102+
int? shouldNotBePromoted;
103+
intFunction()?..bitLength.gcd(shouldNotBePromoted = 0);
104+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
105+
}
106+
}
107+
108+
// `<nonNullable>?..gcd(<expr>)` is not known to invoke <expr>.
109+
testCascadedCall({required int intValue, required int Function() intFunction}) {
110+
{
111+
// <var>?..gcd(<expr>)
112+
int? shouldNotBePromoted;
113+
intValue?..gcd(shouldNotBePromoted = 0);
114+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
115+
}
116+
117+
{
118+
// <expr>?..gcd(<expr>)
119+
int? shouldNotBePromoted;
120+
intFunction()?..gcd(shouldNotBePromoted = 0);
121+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
122+
}
123+
}
124+
125+
// `<nonNullable>?..[<expr>]` is not known to invoke <expr>.
126+
testCascadedIndexGet({
127+
required List<int> listOfIntValue,
128+
required List<int> Function() listOfIntFunction,
129+
}) {
130+
{
131+
// <var>?..[<expr>]
132+
int? shouldNotBePromoted;
133+
listOfIntValue?..[shouldNotBePromoted = 0];
134+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
135+
}
136+
137+
{
138+
// <expr>?..[<expr>]
139+
int? shouldNotBePromoted;
140+
listOfIntFunction()?..[shouldNotBePromoted = 0];
141+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
142+
}
143+
}
144+
145+
// `<nonNullable>?..[<expr>] = 0` is not known to invoke <expr>.
146+
testCascadedIndexSet({
147+
required List<int> listOfIntValue,
148+
required List<int> Function() listOfIntFunction,
149+
}) {
150+
{
151+
// <var>?..[<expr>] = 0
152+
int? shouldNotBePromoted;
153+
listOfIntValue?..[shouldNotBePromoted = 0] = 0;
154+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
155+
}
156+
157+
{
158+
// <expr>?..[<expr>] = 0
159+
int? shouldNotBePromoted;
160+
listOfIntFunction()?..[shouldNotBePromoted = 0] = 0;
161+
shouldNotBePromoted.expectStaticType<Exactly<int?>>();
162+
}
163+
}
164+
165+
main() {
166+
testProperty(intValue: 0, intFunction: () => 0);
167+
testCall(intValue: 0, intFunction: () => 0);
168+
testIndexGet(listOfIntValue: [0], listOfIntFunction: () => [0]);
169+
testIndexSet(listOfIntValue: [0], listOfIntFunction: () => [0]);
170+
testCascadedProperty(intValue: 0, intFunction: () => 0);
171+
testCascadedCall(intValue: 0, intFunction: () => 0);
172+
testCascadedIndexGet(listOfIntValue: [0], listOfIntFunction: () => [0]);
173+
testCascadedIndexSet(listOfIntValue: [0], listOfIntFunction: () => [0]);
174+
}

0 commit comments

Comments
 (0)