codeconsole opened a new pull request, #3091:
URL: https://github.com/apache/groovy/pull/3091
The type checker narrowed a variable after any `instanceof` check on it, for
the rest of the statement or condition, wherever the check was. Under
`@CompileStatic` that compiled code that fails:
```groovy
@CompileStatic
String f(CharSequence cs) { 'x' + (cs instanceof String) + cs.length() }
f(new StringBuilder('ab')) // ClassCastException
@CompileStatic
int h(Object x) { if ((x instanceof String) == false) { return x.length() };
0 }
h(42) // ClassCastException
@CompileStatic
int g(Object x) { while (x instanceof String) { break }; x.length() }
g(42) // ClassCastException
```
Three commits:
- An instanceof check now narrows only where its outcome guards what
follows: the condition of an `if`, `while`, `assert` or conditional expression,
an operand of `&&`, `||` or `!` there, and an operand of `&&` or `||` anywhere.
In `foo(cs instanceof String, cs.length())`, `[cs instanceof String, cs]` or
`(cs instanceof String) == cs.isEmpty()`, the later `cs` is no longer taken for
a `String`. The right operand of `&` no longer sees the narrowing of the left
one; both still apply after the `&`.
- A comparison of a check with a boolean literal, on either side, with `==`,
`!=`, `===` or `!==`, narrows like the check when it is true exactly when the
check is (`== true`, `!= false`), and like `!(check)` otherwise. Before, `==
false` narrowed its own branch to `T`, so the second example compiled and
failed; it is now a compile error, as with `!`, and the else branch and the
code after an `if` that returns are narrowed. An assigned check, a check cast
to `boolean`, and the condition of a classic `for` loop keep narrowing as they
did.
- The condition and the body of a `while`, `do`/`while` or classic `for`
loop get their own scope of temporary type information, as the branches of an
`if` do: the condition narrows in the loop and no longer after it. Assignments
in the loop still cancel, after it, what an enclosing check told about the
variable.
Code that relied on the narrowing outside a guard stops compiling. In each
such case, it compiled to a cast that fails for the other types.
## Tests
`TypeInferenceSTCTest.testInstanceOf30`, `testInstanceOf31` and
`testInstanceOf32`, also run statically compiled, fail without the change.
11,630 tests in the `groovy`, `gls`, `bugs` and STC/SC packages pass, apart
from six `@Grab` tests that pass on rerun. The Checkstyle and CodeNarc gates
pass.
The loop and `== false` cases fail in 4.0.33, 5.0.8 and 6.0.0; the first
example compiles and runs in 4.0.33 and fails in 5.0.8 and 6.0.0.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]