On 04.06.20 17:07, Milles, Eric (TR Tech, Content & Ops) wrote:
There are a couple open bugs related to STC handling of closure shared
variables. When a shared variable is assigned a value within the
closure, the assigned type is not included in the inferred type outside
the closure/lambda and this leads to some problems.
If this behavior is changed to save the LUB(A,B) as the inferred type of
"x", as is suggested in 9516 and seems required by 9344, the second pass
checks for method calls will be replaced by no matching method errors.
That is "Cannot find matching method java.lang.Object#something().
Please check if the declared type is correct and if the method exists."
will replace "A closure shared variable [x] has been assigned with
various types and the method [charAt(int)] does not exist in the lowest
upper bound...".* Is this an acceptable change in STC behavior?*
@groovy.transform.CompileStatic
void test() {
def x = new A();
{ -> x = new B() } // may also be called immediately
x.something() // current STC infers typeof(x) == A
}
as this is currently failing you are suggesting to let it pass and use
the type A?
I think it was done this way because you could define the closure but
not call it (like above). Or call it asynchronously:
@groovy.transform.CompileStatic
void test() {
def x = new A();
Thread.start { -> x = new B() }
x.something() // current STC infers typeof(x) == A
}
would you not agree, just by looking at the realized flow here, that x
should not be A?
https://issues.apache.org/jira/browse/GROOVY-9516
this is
class A {}
class B extends A{ def b() {}}
class C extends A{}
@CompileStatic
static foo() {
def x = new B()
({ x = new C() })()
def z = x
z.b()
}
ah.. now I get the problem. but to say z is of type C is also wrong.
What we really need here is not really the LUB in the sense that
LUB(B,C) = A, iff B extends A && C extends A && B and C are siblings.
What we would really need is a type A plus all methods defined on B and
C. I vaguely remember that our LUB calculation does things like that..
but maybe I remember wrong. If I go by
https://docs.groovy-lang.org/latest/html/documentation/core-semantics.html#section-lub
then I am wrong. Of course I am well aware, that such a type is
difficult to realize. And of course the question is how to do the actual
method call in bytecode. If I cannot cast z to B or B, then I cannot
create the required invokevirtual. This means this must use an
invokedynamic, but a different one than we normally use.
What I am trying to say is that we can handle this case as I imagine it,
but the required implementation work is not small.
https://issues.apache.org/jira/browse/GROOVY-9344
This is
class A {}
class B {}
@groovy.transform.CompileStatic
def cs() {
def var
var = new A()
def c = {
var = new B() // Cannot cast object 'B@4e234c52' with class 'B' to
class 'A'
}
c()
var.toString()
}
assert cs() != null
which looks to me like a different problem, var is declared with "def",
so assigning a B should be valid. Only if the static type does no comply
with the assigned type it should cause an error. There should be also no
cast inserted.
https://issues.apache.org/jira/browse/GROOVY-5874
This is
@CompileStatic
static main(args)
{
def list = [1, 2, 3]
def sum = 0
list.each { int i -> sum += i }
println(sum)
sum = list.inject(0, { int x, int y -> x + y })
println(sum)
}
what I would imagine here is that in def sum, the flow type for sum is
int and for list it is List<Integer>. That means sum+=i should change
the flow type internally to Integer or keep int. The result of the
inject should be Integer and it should always be allowed to assign it to
sum, even if not.
bye Jochen