Skip to content

Commit

Permalink
Add language tests for flow analysis conservative de-promotion scope.
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
stereotype441 authored and [email protected] committed Jul 9, 2020
1 parent 0a5e69a commit fe9596b
Show file tree
Hide file tree
Showing 7 changed files with 495 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) 2020, 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.

// Verifies that variables assigned in closures and local functions are
// de-promoted at the top of the closure, since the closure may be invoked
// multiple times.

void functionExpression(Object x) {
if (x is int) {
print(x.isEven); // Verify that promotion occurred
var f = () {
// The assignment to x does de-promote because it happens after the top of
// the closure, so flow analysis cannot check that the assigned value is
// an int at the time de-promotion occurs.
print(x.isEven);
// ^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
x = 0;
};
}
}

void localFunction(Object x) {
if (x is int) {
print(x.isEven); // Verify that promotion occurred
f() {
// The assignment to x does de-promote because it happens after the top of
// the closure, so flow analysis cannot check that the assigned value is
// an int at the time de-promotion occurs.
print(x.isEven);
// ^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
x = 0;
}
}
}

main() {
functionExpression(0);
localFunction(0);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// Copyright (c) 2020, 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.

// Verifies that variables assigned in loops are de-promoted at the top of the
// loop body, since the loop body be executed multiple times.

void forLoopAssignInCondition(Object x) {
if (x is int) {
print(x.isEven); // Verify that promotion occurred
for (; 0 == 0 ? (x = 0) == 0 : true;) {
// The assignment to x does de-promote because it happens after the top of
// the loop, so flow analysis cannot check that the assigned value is an
// int at the time de-promotion occurs.
print(x.isEven);
// ^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
}
}
}

void forLoopAssignInUpdater(Object x) {
if (x is int) {
print(x.isEven); // Verify that promotion occurred
for (;; x = 0) {
// The assignment to x does de-promote because it happens after the top of
// the loop, so flow analysis cannot check that the assigned value is an
// int at the time de-promotion occurs.
print(x.isEven);
// ^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
}
}
}

void forLoopAssignInBody(Object x) {
if (x is int) {
print(x.isEven); // Verify that promotion occurred
for (;;) {
// The assignment to x does de-promote because it happens after the top of
// the loop, so flow analysis cannot check that the assigned value is an
// int at the time de-promotion occurs.
print(x.isEven);
// ^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
x = 0;
}
}
}

void forEachAssignInBody(Object x) {
if (x is int) {
print(x.isEven); // Verify that promotion occurred
for (var y in [0]) {
// The assignment to x does de-promote because it happens after the top of
// the loop, so flow analysis cannot check that the assigned value is an
// int at the time de-promotion occurs.
print(x.isEven);
// ^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
x = 0;
}
}
}

void whileAssignInCondition(Object x) {
if (x is int) {
print(x.isEven); // Verify that promotion occurred
while (0 == 0 ? (x = 0) == 0 : true) {
// The assignment to x does de-promote because it happens after the top of
// the loop, so flow analysis cannot check that the assigned value is an
// int at the time de-promotion occurs.
print(x.isEven);
// ^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
}
}
}

void whileAssignInBody(Object x) {
if (x is int) {
print(x.isEven); // Verify that promotion occurred
while (true) {
// The assignment to x does de-promote because it happens after the top of
// the loop, so flow analysis cannot check that the assigned value is an
// int at the time de-promotion occurs.
print(x.isEven);
// ^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
x = 0;
}
}
}

void doAssignInCondition(Object x) {
if (x is int) {
print(x.isEven); // Verify that promotion occurred
do {
// The assignment to x does de-promote because it happens after the top of
// the loop, so flow analysis cannot check that the assigned value is an
// int at the time de-promotion occurs.
print(x.isEven);
// ^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
} while ((x = 0) == 0);
}
}

void doAssignInBody(Object x) {
if (x is int) {
print(x.isEven); // Verify that promotion occurred
do {
// The assignment to x does de-promote because it happens after the top of
// the loop, so flow analysis cannot check that the assigned value is an
// int at the time de-promotion occurs.
print(x.isEven);
// ^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
x = 0;
} while (true);
}
}

main() {
forLoopAssignInCondition(0);
forLoopAssignInUpdater(0);
forLoopAssignInBody(0);
forEachAssignInBody(0);
whileAssignInCondition(0);
whileAssignInBody(0);
doAssignInCondition(0);
doAssignInBody(0);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) 2020, 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.

// Verifies that variables assigned in initialization parts of loops are not
// de-promoted, since loop initialization only executes once.

void forLoopWithoutDecl(Object x) {
if (x is int) {
for (x = 0;;) {
// The assignment to x does not de-promote x because it happens before the
// top of the loop, and it assigns an int (which is compatible with the
// promoted type).
x.isEven;
break;
}
}
}

void forLoopWithoutDeclAssignInRHS(Object x) {
if (x is int) {
int y;
for (y = (x = 0);;) {
// The assignment to x does not de-promote x because it happens before the
// top of the loop, and it assigns an int (which is compatible with the
// promoted type).
x.isEven;
break;
}
}
}

void forLoopWithDeclAssignInRHS(Object x) {
if (x is int) {
for (int y = (x = 0);;) {
// The assignment to x does not de-promote x because it happens before the
// top of the loop, and it assigns an int (which is compatible with the
// promoted type).
x.isEven;
break;
}
}
}

void forEachWithoutDecl(Object x) {
if (x is int) {
int y;
for (y in [x = 0]) {
// The assignment to x does not de-promote x because it happens before the
// top of the loop, and it assigns an int (which is compatible with the
// promoted type).
x.isEven;
break;
}
}
}

void forEachWithDecl(Object x) {
if (x is int) {
for (int y in [x = 0]) {
// The assignment to x does not de-promote x because it happens before the
// top of the loop, and it assigns an int (which is compatible with the
// promoted type).
x.isEven;
break;
}
}
}

main() {
forLoopWithoutDecl(0);
forLoopWithoutDeclAssignInRHS(0);
forLoopWithDeclAssignInRHS(0);
forEachWithoutDecl(0);
forEachWithDecl(0);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) 2020, 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.

// Verifies that variables assigned in switch statement bodies are de-promoted
// at the top of labelled case blocks, since the assignment may occur before a
// branch to the labelled case block.

void switchWithLabelAssignInCase(Object x) {
if (x is int) {
print(x.isEven); // Verify that promotion occurred
switch (x) {
case 1:
continue L;
L:
case 0:
// The assignment to x does de-promote because it happens after the
// label, so flow analysis cannot check that the assigned value is an
// int at the time de-promotion occurs.
print(x.isEven);
// ^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
x = 0;
break;
}
}
}

void switchWithLabelAssignInDefault(Object x) {
if (x is int) {
print(x.isEven); // Verify that promotion occurred
switch (x) {
case 1:
continue L;
L:
default:
// The assignment to x does de-promote because it happens after the
// label, so flow analysis cannot check that the assigned value is an
// int at the time de-promotion occurs.
print(x.isEven);
// ^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'isEven' isn't defined for the class 'Object'.
x = 0;
break;
}
}
}

main() {
switchWithLabelAssignInCase(0);
switchWithLabelAssignInDefault(0);
}
Loading

0 comments on commit fe9596b

Please sign in to comment.