Skip to content

Commit fe9596b

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Add language tests for flow analysis conservative de-promotion scope.
These tests verify the scope over which a variable can become de-promoted due conservative modeling of demotion. The conservative model of demotion is used for loops, closures, switch statements, and try blocks. The implementation of flow analysis already passes these tests. I will shortly be making a spec clarification that brings the spec in line with the implementation. Change-Id: I22a5584a808169fa228c2972c25844c432916c06 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/152920 Commit-Queue: Paul Berry <[email protected]> Reviewed-by: Leaf Petersen <[email protected]>
1 parent 0a5e69a commit fe9596b

7 files changed

+495
-0
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) 2020, 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+
// Verifies that variables assigned in closures and local functions are
6+
// de-promoted at the top of the closure, since the closure may be invoked
7+
// multiple times.
8+
9+
void functionExpression(Object x) {
10+
if (x is int) {
11+
print(x.isEven); // Verify that promotion occurred
12+
var f = () {
13+
// The assignment to x does de-promote because it happens after the top of
14+
// the closure, so flow analysis cannot check that the assigned value is
15+
// an int at the time de-promotion occurs.
16+
print(x.isEven);
17+
// ^^^^^^
18+
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
19+
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
20+
x = 0;
21+
};
22+
}
23+
}
24+
25+
void localFunction(Object x) {
26+
if (x is int) {
27+
print(x.isEven); // Verify that promotion occurred
28+
f() {
29+
// The assignment to x does de-promote because it happens after the top of
30+
// the closure, so flow analysis cannot check that the assigned value is
31+
// an int at the time de-promotion occurs.
32+
print(x.isEven);
33+
// ^^^^^^
34+
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
35+
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
36+
x = 0;
37+
}
38+
}
39+
}
40+
41+
main() {
42+
functionExpression(0);
43+
localFunction(0);
44+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// Copyright (c) 2020, 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+
// Verifies that variables assigned in loops are de-promoted at the top of the
6+
// loop body, since the loop body be executed multiple times.
7+
8+
void forLoopAssignInCondition(Object x) {
9+
if (x is int) {
10+
print(x.isEven); // Verify that promotion occurred
11+
for (; 0 == 0 ? (x = 0) == 0 : true;) {
12+
// The assignment to x does de-promote because it happens after the top of
13+
// the loop, so flow analysis cannot check that the assigned value is an
14+
// int at the time de-promotion occurs.
15+
print(x.isEven);
16+
// ^^^^^^
17+
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
18+
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
19+
}
20+
}
21+
}
22+
23+
void forLoopAssignInUpdater(Object x) {
24+
if (x is int) {
25+
print(x.isEven); // Verify that promotion occurred
26+
for (;; x = 0) {
27+
// The assignment to x does de-promote because it happens after the top of
28+
// the loop, so flow analysis cannot check that the assigned value is an
29+
// int at the time de-promotion occurs.
30+
print(x.isEven);
31+
// ^^^^^^
32+
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
33+
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
34+
}
35+
}
36+
}
37+
38+
void forLoopAssignInBody(Object x) {
39+
if (x is int) {
40+
print(x.isEven); // Verify that promotion occurred
41+
for (;;) {
42+
// The assignment to x does de-promote because it happens after the top of
43+
// the loop, so flow analysis cannot check that the assigned value is an
44+
// int at the time de-promotion occurs.
45+
print(x.isEven);
46+
// ^^^^^^
47+
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
48+
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
49+
x = 0;
50+
}
51+
}
52+
}
53+
54+
void forEachAssignInBody(Object x) {
55+
if (x is int) {
56+
print(x.isEven); // Verify that promotion occurred
57+
for (var y in [0]) {
58+
// The assignment to x does de-promote because it happens after the top of
59+
// the loop, so flow analysis cannot check that the assigned value is an
60+
// int at the time de-promotion occurs.
61+
print(x.isEven);
62+
// ^^^^^^
63+
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
64+
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
65+
x = 0;
66+
}
67+
}
68+
}
69+
70+
void whileAssignInCondition(Object x) {
71+
if (x is int) {
72+
print(x.isEven); // Verify that promotion occurred
73+
while (0 == 0 ? (x = 0) == 0 : true) {
74+
// The assignment to x does de-promote because it happens after the top of
75+
// the loop, so flow analysis cannot check that the assigned value is an
76+
// int at the time de-promotion occurs.
77+
print(x.isEven);
78+
// ^^^^^^
79+
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
80+
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
81+
}
82+
}
83+
}
84+
85+
void whileAssignInBody(Object x) {
86+
if (x is int) {
87+
print(x.isEven); // Verify that promotion occurred
88+
while (true) {
89+
// The assignment to x does de-promote because it happens after the top of
90+
// the loop, so flow analysis cannot check that the assigned value is an
91+
// int at the time de-promotion occurs.
92+
print(x.isEven);
93+
// ^^^^^^
94+
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
95+
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
96+
x = 0;
97+
}
98+
}
99+
}
100+
101+
void doAssignInCondition(Object x) {
102+
if (x is int) {
103+
print(x.isEven); // Verify that promotion occurred
104+
do {
105+
// The assignment to x does de-promote because it happens after the top of
106+
// the loop, so flow analysis cannot check that the assigned value is an
107+
// int at the time de-promotion occurs.
108+
print(x.isEven);
109+
// ^^^^^^
110+
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
111+
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
112+
} while ((x = 0) == 0);
113+
}
114+
}
115+
116+
void doAssignInBody(Object x) {
117+
if (x is int) {
118+
print(x.isEven); // Verify that promotion occurred
119+
do {
120+
// The assignment to x does de-promote because it happens after the top of
121+
// the loop, so flow analysis cannot check that the assigned value is an
122+
// int at the time de-promotion occurs.
123+
print(x.isEven);
124+
// ^^^^^^
125+
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
126+
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
127+
x = 0;
128+
} while (true);
129+
}
130+
}
131+
132+
main() {
133+
forLoopAssignInCondition(0);
134+
forLoopAssignInUpdater(0);
135+
forLoopAssignInBody(0);
136+
forEachAssignInBody(0);
137+
whileAssignInCondition(0);
138+
whileAssignInBody(0);
139+
doAssignInCondition(0);
140+
doAssignInBody(0);
141+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright (c) 2020, 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+
// Verifies that variables assigned in initialization parts of loops are not
6+
// de-promoted, since loop initialization only executes once.
7+
8+
void forLoopWithoutDecl(Object x) {
9+
if (x is int) {
10+
for (x = 0;;) {
11+
// The assignment to x does not de-promote x because it happens before the
12+
// top of the loop, and it assigns an int (which is compatible with the
13+
// promoted type).
14+
x.isEven;
15+
break;
16+
}
17+
}
18+
}
19+
20+
void forLoopWithoutDeclAssignInRHS(Object x) {
21+
if (x is int) {
22+
int y;
23+
for (y = (x = 0);;) {
24+
// The assignment to x does not de-promote x because it happens before the
25+
// top of the loop, and it assigns an int (which is compatible with the
26+
// promoted type).
27+
x.isEven;
28+
break;
29+
}
30+
}
31+
}
32+
33+
void forLoopWithDeclAssignInRHS(Object x) {
34+
if (x is int) {
35+
for (int y = (x = 0);;) {
36+
// The assignment to x does not de-promote x because it happens before the
37+
// top of the loop, and it assigns an int (which is compatible with the
38+
// promoted type).
39+
x.isEven;
40+
break;
41+
}
42+
}
43+
}
44+
45+
void forEachWithoutDecl(Object x) {
46+
if (x is int) {
47+
int y;
48+
for (y in [x = 0]) {
49+
// The assignment to x does not de-promote x because it happens before the
50+
// top of the loop, and it assigns an int (which is compatible with the
51+
// promoted type).
52+
x.isEven;
53+
break;
54+
}
55+
}
56+
}
57+
58+
void forEachWithDecl(Object x) {
59+
if (x is int) {
60+
for (int y in [x = 0]) {
61+
// The assignment to x does not de-promote x because it happens before the
62+
// top of the loop, and it assigns an int (which is compatible with the
63+
// promoted type).
64+
x.isEven;
65+
break;
66+
}
67+
}
68+
}
69+
70+
main() {
71+
forLoopWithoutDecl(0);
72+
forLoopWithoutDeclAssignInRHS(0);
73+
forLoopWithDeclAssignInRHS(0);
74+
forEachWithoutDecl(0);
75+
forEachWithDecl(0);
76+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) 2020, 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+
// Verifies that variables assigned in switch statement bodies are de-promoted
6+
// at the top of labelled case blocks, since the assignment may occur before a
7+
// branch to the labelled case block.
8+
9+
void switchWithLabelAssignInCase(Object x) {
10+
if (x is int) {
11+
print(x.isEven); // Verify that promotion occurred
12+
switch (x) {
13+
case 1:
14+
continue L;
15+
L:
16+
case 0:
17+
// The assignment to x does de-promote because it happens after the
18+
// label, so flow analysis cannot check that the assigned value is an
19+
// int at the time de-promotion occurs.
20+
print(x.isEven);
21+
// ^^^^^^
22+
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
23+
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
24+
x = 0;
25+
break;
26+
}
27+
}
28+
}
29+
30+
void switchWithLabelAssignInDefault(Object x) {
31+
if (x is int) {
32+
print(x.isEven); // Verify that promotion occurred
33+
switch (x) {
34+
case 1:
35+
continue L;
36+
L:
37+
default:
38+
// The assignment to x does de-promote because it happens after the
39+
// label, so flow analysis cannot check that the assigned value is an
40+
// int at the time de-promotion occurs.
41+
print(x.isEven);
42+
// ^^^^^^
43+
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
44+
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
45+
x = 0;
46+
break;
47+
}
48+
}
49+
}
50+
51+
main() {
52+
switchWithLabelAssignInCase(0);
53+
switchWithLabelAssignInDefault(0);
54+
}

0 commit comments

Comments
 (0)