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

ASF GitHub Bot commented on GROOVY-12755:
-----------------------------------------

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

   Thanks Scott. Typing `e.getClass()` as `Class<? extends |T|>` is the right 
fix, and it is needed on `GROOVY_6_0_X`: GROOVY-12714 is on that branch but not 
in the 6.0.0 tag, so the Grails shape compiles on 6.0.0 and fails on the branch 
today. I ran a set of `@CompileStatic` probes on the 6.0.0 release, on 
`GROOVY_6_0_X` and master, and on each with this branch applied (as a whole, 
not commit by commit). The headline cases behave as described. Some things I'd 
like addressed or decided before this goes in.
   
   **1. Static dispatch changes silently.**
   
   With overloads `f(Object)`, `f(CharSequence)` and `f(StringBuilder)`, and 
`<T> T mk(Class<T>)`:
   
   ```groovy
   f(x.getClass().cast(o))          // master: "object"   this branch: "sb"
   f(x.getClass().newInstance())    // master: "object"   this branch: "sb"
   def y = mk(x.getClass()); f(y)   // master: "object"   this branch: "sb"
   ```
   
   The new result is what dynamic Groovy picks and what javac would pick, so I 
think it is the right answer, but it is a runtime change with no compile error. 
Please add it to the COMPATIBILITY entry and add a test that records it.
   
   **2. Calls that javac accepts are now rejected.**
   
   These compile on 6.0.0, `GROOVY_6_0_X` and master, javac 25.0.5 accepts the 
Java forms, and this branch rejects them:
   
   ```groovy
   List<Class<?>> l = Collections.singletonList(x.getClass())
   List<Class<?>> l = Arrays.asList(a.getClass(), b.getClass())
   Optional<Class<?>> o = Optional.of(x.getClass())
   ```
   
   javac infers from the target type; STC infers `List<Class<? extends 
String>>` bottom-up and then fails the assignment. The Groovy forms fail the 
same way when returned or assigned as `List<Class<?>>`: `list.collect { 
it.getClass() }`, `list*.getClass()` and `list*.class`. A list literal and 
`List<Class>` still work. These are the cases I'm most concerned about, since 
they are not "as in Java" and the spread and `collect` forms are what people 
write. Can the assignment check accept a `Class<? extends X>` element for a 
`Class<?>` one here, or is there another way to keep them compiling?
   
   **3. The type-variable rule is uneven.**
   
   `<T> Class<? extends T> typeOf(T t) { t.getClass() }` and a field `Class<? 
extends T> type = t.getClass()` are now errors, as in javac. But `<T> Class<T> 
typeOf(T t) { t.getClass() }` still compiles (javac rejects it), and so does 
passing `t.getClass()` to `m(Class<? extends T>)` or to `Map<Class<? extends 
T>, T>.put` inside a generic class (javac rejects the `put`). So the more 
accurate declaration is the one that breaks, and only for assignment and 
return. I'd prefer these to be consistent one way or the other.
   
   **4. The raw-bound rule reaches well beyond `getClass()`.**
   
   These compile today and are errors on this branch, as in javac:
   
   ```groovy
   List<? extends Map<?, ?>> a = rows           // rows is a List<? extends Map>
   List<? extends Map<String, Object>> b = rows
   Class<? extends Enum<?>> c = type            // type is a Class<? extends 
Enum>
   m(closureType)                               // m(Class<? extends 
Closure<String>>), closureType is a Class<? extends Closure>
   ```
   
   Raw `Map`, `Closure`, `Comparable` and `Enum` are much more common in Groovy 
code than in Java, so I expect this to be the most widely felt part of the 
change. I'm fine with it for 7 given the COMPATIBILITY entry; see below for 6.
   
   **5. Backport to `GROOVY_6_0_X`.**
   
   I'd like to split this for the port rather than take it whole:
   
   - **Port:** the `getClass()` typing (`2ce6046aa3`, `f2d84108eb`), after 
GROOVY-12754. That is the regression fix. Items 1 and 2 come with it, so they 
need settling first.
   - **Master only:** the resolver change (`053e7ead2d`) and the 
unbounded/lower-bounded wildcard check (`2b99f21e83`). Neither is needed for 
the Grails case. The second makes `Enum.valueOf`, `EnumSet.allOf` and 
`getAnnotation` with a `Class<?>`, `Enum.valueOf(field.getType(), name)`, 
`Enum.valueOf(Class.forName(n), name)` and `Collections.sort(List<?>)` errors, 
which is a lot of working reflection code for a patch release.
   - **To discuss:** the raw-bound commits (`7807d56395`, `0750119074`). Daniel 
asked for them so that `Class<? extends List<String>> f(List<String> s) { 
s.getClass() }` does not compile. That return is unsound, but it also compiled 
on 6.0.0, and these commits bring items 3 and 4 to 6.0.x. My inclination is to 
leave them on master, but I'd like Daniel's view.
   
   For the record, the port does not fully restore 6.0.0 behaviour, which I 
think is acceptable but should be in the 6.0.1 notes. These compile on 6.0.0 
and remain errors on the branch with this change (javac rejects them too):
   
   ```groovy
   Class<String> c = s.getClass()
   Class<? extends Collection<?>> c = coll.getClass()
   reg(k.getClass())   // reg(Class<? extends Converter<?>>), k is a 
Converter<Integer>
   ```
   
   **The resolver change** was the part I expected trouble from, since it 
applies to dynamic code as well, and I found none. I ran 34 scenarios 
(linked-node classes, subclass overrides, `@Delegate`/`@Lazy`, closures, 
lambdas, anonymous classes, deep nesting), each dynamic and static, and all 
gave the same result as master. Reflection over the generated classes had no 
new failures, clients compiled against precompiled classes behaved the same, 
and joint compilation with Java using `Outer<String>.Inner` fails on master and 
works here. The `inClosure()` difference on 6.0.x reproduced as you described.
   




> STC: e.getClass() is typed Class<?>, so since GROOVY-12714 it is rejected 
> where a Class<? extends T> is expected
> ----------------------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12755
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12755
>             Project: Groovy
>          Issue Type: Bug
>          Components: Static Type Checker
>    Affects Versions: 7.0.0-alpha-1, 6.0.1
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> JLS 4.3.2 gives a call {{e.getClass()}} the type {{Class<? extends |T|>}}, 
> where {{|T|}} is the erasure of the static type of {{e}}. Static type 
> checking types it with the declared return type of {{Object#getClass()}}, 
> {{Class<?>}}. Until GROOVY-12714 the wildcard check accepted {{Class<?>}} 
> where a {{Class<? extends T>}} was expected. Since GROOVY-12714 (GROOVY_6_0_X 
> and master) it is rejected:
> {code:groovy}
> @groovy.transform.CompileStatic
> class C {
>     interface Store {}
>     static <T> T with(Class<? extends Store> type, Closure<T> body) { 
> body.call() }
>     static class Adapter { Adapter(Class<? extends Store> type) {} }
>     static Object viaMethod(Store store) { with(store.getClass()) { 1 } }
>     static Object viaProperty(Store store) { with(store.class) { 1 } }
>     static Object viaConstructor(Store store) { new Adapter(store.getClass()) 
> }
>     static Class<? extends Store> viaReturn(Store store) { store.getClass() }
> }
> {code}
> {noformat}
> [Static type checking] - Cannot call <T> C#with(java.lang.Class<? extends 
> C.Store>, groovy.lang.Closure<T>) with arguments [java.lang.Class<?>, 
> groovy.lang.Closure]
> [Static type checking] - Cannot call <T> C#with(java.lang.Class<? extends 
> C.Store>, groovy.lang.Closure<T>) with arguments [java.lang.Class<?>, 
> groovy.lang.Closure]
> [Static type checking] - Cannot call C$Adapter#<init>(java.lang.Class<? 
> extends C.Store>) with arguments [java.lang.Class<?>]
> [Static type checking] - Incompatible generic argument types. Cannot assign 
> java.lang.Class<?> to: java.lang.Class<? extends C.Store>
> {noformat}
> javac accepts the equivalent Java. Grails no longer compiles against 
> GROOVY_6_0_X: it passes {{datastore.getClass()}} to a {{Class<? extends 
> Datastore>}} parameter and {{registrar.getClass()}} to a {{Class<? extends 
> BeanRegistrar>}} one 
> (https://github.com/apache/grails-core/actions/runs/42702095261).
> Typing {{e.getClass()}} and {{e.class}} as {{Class<? extends |T|>}} makes 
> more calls pass an upper-bounded wildcard for a bounded type parameter, such 
> as {{foo(list.class)}} for {{<T extends List<Integer>> foo(Class<T>)}}, which 
> GROOVY-12754 rejected. So this depends on GROOVY-12754.
> The inferred type of {{list.class}} for a raw {{List list}} changes from 
> {{Class<? extends Object>}} to {{Class<? extends List>}}, and the GROOVY-5415 
> error for {{a.bar(this.getClass())}} now names {{Class<? extends ClassB>}}; 
> the two tests that assert those types are updated.
> PR: https://github.com/apache/groovy/pull/3286



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to