paulk-asert commented on PR #3285:
URL: https://github.com/apache/groovy/pull/3285#issuecomment-6793082468

   Thanks Scott, the capture-based revision is a big improvement. I ran a set 
of `@CompileStatic` probes against master and against this branch (and the same 
patch applied to `GROOVY_6_0_X`; results were identical on both). The headline 
cases behave as described, and subtype arguments, multi-parameter methods, 
constructors, class-level bounds and DGM calls on wildcard receivers all came 
out fine. Two things before this goes further.
   
   **1. A bound that names another type parameter is skipped and never 
checked.**
   
   In `compatibleCapture`:
   
   ```java
   if (bound.isGenericsPlaceHolder()) continue; // another type parameter
   ```
   
   Both of these are rejected on master and compile on this branch:
   
   ```groovy
   static <T extends Number, U extends T> U v(List<U> b) { b.get(0) }
   static g(List<? extends String> l) { Number n = v(l); n }
   // g(['x']) -> GroovyCastException: Cannot cast object 'x' with class 
'java.lang.String' to class 'java.lang.Number'
   
   static <T extends Number, U extends List<T>> int v(Class<U> c) { 1 }
   static g(Class<? extends ArrayList<String>> c) { v(c) }
   ```
   
   javac 25.0.5 rejects both ("inference variable T has incompatible bounds"), 
and accepts the same calls with `List<? extends Integer>` and `Class<? extends 
ArrayList<Integer>>`. Could you add them to `GenericsSTCTest` and 
`GenericsJavaCompatibilityTest` and resolve the bound through the other type 
parameter's own bound rather than skipping it? This is the same kind of hole as 
`narrow`, on calls the PR newly accepts, so I'd like it closed before merging 
to master.
   
   **2. Backport to `GROOVY_6_0_X`.**
   
   I'd prefer not to cherry-pick this as it stands. Matching javac here means 
that code which compiles and runs correctly on 6.0.0 becomes a compile error in 
a patch release:
   
   - `Enum.valueOf(type, name)` and `EnumSet.allOf(type)` with a `Class<? 
extends Enum<?>>`, which is a natural way to type an "any enum class" parameter 
or field
   - `Collections.sort(list)` with a `List<? extends Comparable<?>>`
   - any wildcard declared looser than the method needs, e.g. a `Class<? 
extends Runnable>` holding `Thread` passed to `<T extends Thread> m(Class<T>)`
   
   The workarounds are easy and the COMPATIBILITY entry describes them well, 
but that entry is rightly headed "Groovy 7", and #3286 extends the same 
tightening to `Class<?>` and `List<?>`.
   
   If GROOVY-12755 needs the accepting half on 6.0.x, one option is an 
accept-only variant for that branch: when the capture check fails, fall through 
to the existing `compatibleConnection` path instead of returning incompatible. 
That admits the calls that were wrongly rejected without rejecting anything 
6.0.0 accepts. It leaves the `narrow` miscompile in place on 6, which is 
existing behaviour. I haven't built that variant, so treat it as a suggestion; 
happy to hear other views, @daniellansun included, since this differs from the 
earlier "cherry-pick once it matches javac".
   
   One observation, not a request: with `m(List<T extends Integer>)` and 
`m(Collection<?>)`, passing a `List<? extends Number>` is now an error rather 
than selecting the second overload as javac would. That's how the checker 
already treats a failed generics check, and it does mean there is no silent 
re-dispatch, so I'm fine leaving it.
   


-- 
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]

Reply via email to