-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
This code is erroneously accepted by the analyzer:
set v(Never value) {}
test(Object? x) {
if (x is! int) {
for (v in []) {}
}
print(x + 1);
}The reason the analyzer is accepting the code is because the first step it takes in analyzing for (v in []) {}, is to resolve the simple identifier v (this resolves to the setter v), then it takes the type of the setter (Never) and stores it into the AST node for v using ExpressionImpl.recordStaticType. A side effect of ExpressionImpl.recordStaticType is to mark the control flow path as unreachable if the type if Never. Therefore, it considers the "then" branch of the "if" statement to be dead code, and so it considers the "if" statement to promote x to int.
This is incorrect. The actual behavior of for (v in []) is a no-op, since the iterable expression is empty; therefore both branches of the "if" statement are live, and so it is not sound to promote x.
If you try to run this code using the front end, it correctly rejects it:
test.dart:6:11: Error: The operator '+' isn't defined for the class 'Object?'.
- 'Object' is from 'dart:core'.
Try correcting the operator to an existing operator, or defining a '+' operator.
print(x + 1);
^
Since it's hard to imagine this problem cropping up in real-world code, I'm inclined to classify it as a P3. However, it's a soundness bug, which we typically classify as fairly high priority. So I'm going to compromise and call it a P2.