[
https://issues.apache.org/jira/browse/GROOVY-8965?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17564321#comment-17564321
]
Eric Milles edited comment on GROOVY-8965 at 7/8/22 3:08 PM:
-------------------------------------------------------------
What I have -- I can push my branch if you'd like to look it over -- adds LUB
(which is just {{instanceof}} type in case of single) to receivers list, then
declared/inferred type, then bound types and self types and so on as before.
This means Number will be checked for floatValue in this example and will
succeed.
When you have "a instanceof Integer || a instanceof Double" the inferred type
is UnionType:Integer+Double and this gets added as the second receiver to
check. I did think about adding the original declared type (Object in this
case) by itself but that is mixed into the inferred type in the current
implementation. For example: "def m(CharSequence cs) \{ if (cs instanceof
Serializable) cs.something(); \}" Would check for "something()" against
UnionType:CharSequence+Serializable. (This is probably supposed to be the
other kind of type since it is both CharSequence *and* Serializable, but I lack
test cases for this kind of thing.)
The duck-typing case -- "(obj instanceof List || obj instanceof Map) ?
obj.size() : 1" -- will now produce an ambiguous method error. Old code added
List and Map separately before UnionType:List+Map, so only one of the two
needed to have "size()" for type-checking to pass. I think it would still pass
if only one has "size()"; I need to set up a test case for this. I am
exploring adding something in {{disambiguateMethods}} to switch to a dynamic
call for the duck-typing case. But I could push with what I have since before
you got a runtime exception under @CS when you pass one of the two types. So
the ambiguous method error at least gives you a chance at compile time to make
a change. Duck-typing works under @TypeChecked but as I noted can miss the
case where not all of the types can answer the call.
was (Author: emilles):
What I have -- I can push my branch if you'd like to look it over -- adds LUB
(which is just {{instanceof}} type in case of single) to receivers list, then
declared/inferred type, then bound types and self types and so on as before.
This means Number will be checked for floatValue in this example and will
succeed.
When you have "a instanceof Integer || a instanceof Double" the inferred type
is UnionType:Integer+Double and this gets added as the second receiver to
check. I did think about adding the original declared type (Object in this
case) by itself but that is mixed into the inferred type in the current
implementation. For example: "def m(CharSequence cs) \{ if (cs instanceof
Serializable) cs.something(); \}" Would check for "something()" against
UnionType:CharSequence+Serializable. (This is probably supposed to be the
other kind of type since it is both CharSequence *and* Serializable, but I lack
test cases for this kind of thing.)
The duck-typing case -- "(obj instanceof List || obj instanceof Map) ?
obj.size() : 1" -- will now produce an ambiguous method error. Old code added
List and Map separately before UnionType:List+Map, so only one of the two
needed to have "size()" for type-checking to pass. I think it would still pass
if only one has "size()"; I need to set up a test case for this. I am
exploring adding something in {{disambiguateMethods}} to switch to a dynamic
call for the duck-typing case. But I could push with what I have since before
you got a runtime exception under @CS when you pass one of the two types. So
the ambiguous method error at least gives you a chance at compile time to make
a change.
> instanceof with || inserts wrong cast
> -------------------------------------
>
> Key: GROOVY-8965
> URL: https://issues.apache.org/jira/browse/GROOVY-8965
> Project: Groovy
> Issue Type: Bug
> Components: Static compilation
> Affects Versions: 2.5.5
> Reporter: Daniil Ovchinnikov
> Assignee: Eric Milles
> Priority: Major
>
> {code:java}
> @groovy.transform.CompileStatic
> def foo(a) {
> if (a instanceof Integer || a instanceof Double) {
> a.floatValue() // expected: cast to Number; actual: cast to Integer
> }
> }
> println foo(1d).class // CCE: java.lang.Double cannot be cast to
> java.lang.Integer
> {code}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)