[ 
https://issues.apache.org/jira/browse/GROOVY-7363?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14969951#comment-14969951
 ] 

Frank Pavageau edited comment on GROOVY-7363 at 10/23/15 2:39 PM:
------------------------------------------------------------------

I've been running the {{StaticTypeCheckingVisitor}} on my test under the 
debugger, to understand how it works and where the problem might come from, and 
I think I've pinpointed the origin.

The reflection finds 2 methods {{getB()}} in {{ABC}}:
- the implemented method {{BC getB()}}
- a bridge method {{B getB()}}, with the original return type as declared in 
the {{A}} interface

As always with reflection, the order of the methods returned by 
{{Class.getDeclaredMethods()}} is undefined, which is why the failure can be 
flaky, even if my test reproduces it reliably on my machine. When the 
{{ClassNode}} for {{ABC}} is initialized (in {{lazyClassInit()}}), the bridge 
method is returned first, the implemented method second, and both are 
registered in {{ClassNode.methodsList}} and {{ClassNode.methods}}.

Then, when resolving the type of the {{a.b}} expression in 
{{StaticTypeCheckingVisitor.existsProperty()}}, the {{ClassNode}} returns the 
first getter matching the name and parameters of {{getB()}} ({{MethodNode 
getter = current.getGetterMethod("get" + capName)}}): the bridge method with a 
broader return type ({{B}}) than the actual, implemented method ({{BC}}).

So the question is: is there a point in keeping the bridge methods in the 
{{ClassNode}}? Are they ever needed? And even if they are, shouldn't the 
implemented methods have precedence in {{ClassNode.methods}} by being sorted 
first, so the exact types are always used? Because 
{{Class.getDeclaredMethods()}} returns an array with an undefined order, I 
think it's a bad idea to simply store them in the same order.

I'll try both scenarios and see if any existing test breaks (and if it fixes 
mine), but it's probably better if someone has a opinion on the best route.


was (Author: fpavageau):
I've been running the {{StaticTypeCheckingVisitor}} on my test under the 
debugger, to understand how it works and where the problem might come from, and 
I think I've pinpointed the origin.

The reflection finds 2 methods {{getB()}} in {{ABC}}:
- the implemented method {{BC getB()}}
- a bridge method {{B getB()}}, with the original return type as declared in 
the {{A}} interface

As always with reflection, the order of the methods returned by 
{{Class.getDeclaredMethods()}} is undefined, which is why the failure can be 
flaky, even if my test reproduces it reliably on my machine. When the 
{{ClassNode}} for {{ABC}} is initialized (in {{lazyClassInit()}}), the bridge 
method is returned first, the implemented method second, and both are 
registered in {{ClassNode.methodsList}} and {{ClassNode.methods}}.

Then, when resolving the type of the {{a.b}} expression in 
{{StaticTypeCheckingVisitor.existsProperty()}}, the {{ClassNode}} returns the 
first getter matching the name and parameters of {{getB()}} ({{MethodNode 
getter = current.getGetterMethod("get" + capName)}}}): the bridge method with a 
broader return type ({{B}}) than the actual, implemented method ({{BC}}).

So the question is: is there a point in keeping the bridge methods in the 
{{ClassNode}}? Are they ever needed? And even if they are, shouldn't the 
implemented methods have precedence in {{ClassNode.methods}} by being sorted 
first, so the exact types are always used? Because 
{{Class.getDeclaredMethods()}} returns an array with an undefined order, I 
think it's a bad idea to simply store them in the same order.

I'll try both scenarios and see if any existing test breaks (and if it fixes 
mine), but it's probably better if someone has a opinion on the best route.

> Frequent compilation error on cascading generic types
> -----------------------------------------------------
>
>                 Key: GROOVY-7363
>                 URL: https://issues.apache.org/jira/browse/GROOVY-7363
>             Project: Groovy
>          Issue Type: Bug
>          Components: Static Type Checker
>    Affects Versions: 2.4.2
>         Environment: MacOS X
> Oracle JDK 1.7u75 / 1.8u40
> Maven 3.0.5
>            Reporter: Frank Pavageau
>            Assignee: Cédric Champeau
>              Labels: test
>         Attachments: lost-cascading-types.tar.gz
>
>
> Most of the time, I get the following compilation error:
> {noformat}
> [ERROR] 
> /Users/fpavageau/devs/bugs/lost-cascading-types/src/main/groovy/BadType.groovy:
>  22: [Static type checking] - No such property: start for class: T
> [ERROR] @ line 22, column 22.
> [ERROR] println("" + rel.currentState.state.start)
> [ERROR] ^
> [ERROR] 
> [ERROR] 1 error
> {noformat}
> where {{rel}} is an instance of a non-parameterized (Java) class implementing 
> a generic interface with the {{currentState}} generic property. So the type 
> of the property should actually be known, but it's lost and I get a 
> compilation error because the {{start}} property is not part of the 
> lower-bound type of {{currentState}}.
> When I say "most of the time", it's because the compilation error is not 
> always triggered (so lots of debugging fun!). I've tried with Oracle JDK 
> 1.7u75 and 1.8u40, and I get around 87% of failures:
> {code:title=JDK 1.7}
> $ failures=0; for i in {1..100}; do mvn clean package > /dev/null 2>&1 || 
> ((failures++)); done; echo $failures
> 87
> {code}
> {code:title=JDK 1.8}
> $ failures=0; for i in {1..100}; do mvn clean package > /dev/null 2>&1 || 
> ((failures++)); done; echo $failures
> 88
> {code}
> I'm attaching a test case, which is also available on 
> [Github|https://github.com/fpavageau/lost-cascading-types].



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to