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

Paul King commented on GROOVY-12437:
------------------------------------

Thanks for the clear reproducer. Confirmed, and the problem is a bit wider than 
the description suggests.

h3. Reproduction
Reporter's {{Base.groovy}}/{{Child.groovy}} compiled with 
{{FileSystemCompiler}} (Base first, then Child against Base's class files), 
Zulu JDK 17.0.20.1, Windows 11:

||Version||Child compiled separately||
|3.0.19 .. 4.0.33, 5.0.0-alpha-1 .. alpha-3|pass|
|5.0.0-alpha-4 .. 5.1.3, 6.0.0, master|{{unable to resolve class E}} (x2, no 
source position)|

Joint compilation passes on every version.

h3. Scope
* {{@CompileStatic}} is not needed: the same failure occurs with 
{{@TypeChecked}} or fully dynamic code. It is reported by {{ResolveVisitor}} 
during semantic analysis, not by the type checker.
* No separate compilation is needed for a JDK/library superclass, e.g. {{class 
Child extends javax.swing.JComboBox<String> \{ def m(boolean f) \{ f ? 
dataModel : dataModel \} \}}} fails on 5.x/6.x as a single file.
* It is not limited to the ternary. Any expression whose type is derived from 
an unqualified inherited generic field fails: elvis, prefix/postfix 
({{++value}}, {{num++}}), unary minus/plus, bitwise negation, spread 
({{\[*list\]}}, {{m(*list)}}) and spread-map ({{\[*:map\]}}), including bounded 
type variables ({{N extends Number}}).
* The non-ternary forms have failed since 3.0.20 / 4.0.0; the ternary/elvis 
forms since 5.0.0-alpha-4.
* Workaround: qualify the property, e.g. {{flag ? this.entries : 
this.otherEntries}}.

h3. Cause
* {{Java8.configureTypeVariableReference}} (used by both the ASM decompiler and 
the reflection path) builds the placeholder {{E}} with an inner 
{{GenericsType}} wrapping a second, bare {{E}}. The {{GenericsType}} 
constructor sets {{placeholder}} but not {{resolved}}.
* Before GROOVY-9998 ({{1c91d7c79b}}, 4.0.0-alpha-3; backported to 3.0.20 with 
GROOVY-11241) {{GenericsType.isResolved()}} returned {{resolved || 
isPlaceholder()}}, which hid this. Since then the inner {{E}} reports 
{{resolved=false}}.
* {{ResolveVisitor.transform}} resolves {{exp.getType()}} for expression kinds 
without a dedicated branch. Prefix/postfix/unary/bitwise/spread have always 
derived their type from the operand; GROOVY-10936 ({{689552a375}}, 
5.0.0-alpha-4) changed {{TernaryExpression.getType()}} from {{OBJECT_TYPE}} to 
the LUB of the branch types. For an unqualified inherited field, that type is 
the superclass's {{Map<String, E>}}, and resolving the unresolved inner {{E}} 
in the subclass's scope fails.
* When the superclass is compiled from source, its placeholders were already 
marked resolved, hence joint compilation passes.

h3. Proposed fix
PR #2973: mark the inner {{GenericsType}} created by 
{{configureTypeVariableReference}} as resolved. It includes 
{{bugs.Groovy12437}} (19 cases: the original reproducer with a runtime check, 
each expression form above against a precompiled superclass, and the 
{{JComboBox}} cases). All 19 fail without the fix and pass with it. Full 
{{./gradlew test}}: 24178 tests, the only failures being two timing-sensitive 
tests ({{Groovy5359}}, {{ActorTest.testConcurrentSendsAreSerialized}}) on a 
loaded machine.

Since the problem is not specific to incremental compilation or Groovy 5, the 
summary could be updated, e.g. "Unable to resolve superclass type parameter for 
expressions over inherited generic fields when superclass is precompiled", and 
Affects Version/s could include 3.0.20+ and 4.0.x.


> Groovy 5 Incremental Compilation Issue
> --------------------------------------
>
>                 Key: GROOVY-12437
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12437
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 5.0.0
>            Reporter: James Daugherty
>            Assignee: Paul King
>            Priority: Major
>
> A statically compiled subclass fails to compile against a precompiled generic 
> superclass when a ternary expression selects between two inherited generic 
> map properties. Compiling the same sources together succeeds.
> This was discovered during incremental compilation in a Grails application, 
> but {*}the reproducer uses only the standalone Groovy compiler{*}. Gradle, 
> Grails, application dependencies, compiler configuration scripts, and build 
> caches are not involved.
>  
> Reproducer is here: 
> [https://github.com/jdaugherty/groovy5-incrementa-compilation-issue] 



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to