[jira] [Comment Edited] (GROOVY-9059) Failed to parse/compile generic methods with "extends"
[ https://issues.apache.org/jira/browse/GROOVY-9059?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16822125#comment-16822125 ] Eric Milles edited comment on GROOVY-9059 at 4/19/19 6:58 PM: -- So by including the generics of {{oldMethod}}, {{equalParametersWithGenerics}} can get from {{O -> Object}} to {{O -> T -> Object}}. Since {{genericsSpec}} is only used to convert types from {{oldMethod}}, I removed the existing call {{addMethodGenerics(overridingMethod, genericsSpec)}}. {code:java} // org.codehaus.groovy.classgen.Verifier private MethodNode getCovariantImplementation(final MethodNode oldMethod, final MethodNode overridingMethod, Map genericsSpec, boolean ignoreError) { // method name if (!oldMethod.getName().equals(overridingMethod.getName())) return null; if ((overridingMethod.getModifiers() & ACC_BRIDGE) != 0) return null; if (oldMethod.isPrivate()) return null; // GRECLIPSE add -- GROOVY-9059 genericsSpec = GenericsUtils.addMethodGenerics(oldMethod, genericsSpec); // GRECLIPSE end // parameters boolean normalEqualParameters = equalParametersNormal(overridingMethod, oldMethod); boolean genericEqualParameters = equalParametersWithGenerics(overridingMethod, oldMethod, genericsSpec); if (!normalEqualParameters && !genericEqualParameters) return null; /* GRECLIPSE edit -- GROOVY-9059 //correct to method level generics for the overriding method genericsSpec = GenericsUtils.addMethodGenerics(overridingMethod, genericsSpec); */ // return type ClassNode mr = overridingMethod.getReturnType(); ClassNode omr = oldMethod.getReturnType(); boolean equalReturnType = mr.equals(omr); ClassNode testmr = correctToGenericsSpec(genericsSpec, omr); {code} >From there, it needs some help to use the entry {{T=T->java.lang.String}} from >{{genericsSpec}}. I did it using a special method from ClassNode that was >introduced for a previous fix: {code:java} // org.codehaus.groovy.ast.tools.GenericsUtils public static ClassNode correctToGenericsSpec(Map genericsSpec, ClassNode type) { if (type.isArray()) { return correctToGenericsSpec(genericsSpec, type.getComponentType()).makeArray(); } if (type.isGenericsPlaceHolder()) { String name = type.getGenericsTypes()[0].getName(); type = genericsSpec.get(name); // GRECLIPSE add -- GROOVY-9059 if (type != null && type.isGenericsPlaceHolder()) { type = type.asGenericsType().getUpperBounds()[0]; return correctToGenericsSpec(genericsSpec, type); } // GRECLIPSE end } if (type == null) type = ClassHelper.OBJECT_TYPE; return type; } {code} {code:java} // org.codehaus.groovy.ast.ClassNode public GenericsType asGenericsType() { if (!isGenericsPlaceHolder()) { return new GenericsType(this); } else { ClassNode upper = (redirect != null ? redirect : this); return new GenericsType(this, new ClassNode[]{upper}, null); } } {code} With that in place, you can do this without error: {code:groovy} class Why implements Y { @Override public CS foo(CS cs) { cs } } // or def why = new Y() { @Override public CS foo(CS cs) { cs } } {code} However, your example of using String and no method generics still produces 1 error (from groovyc) and 1 warning (from eclipse): 1. Method 'foo' from class 'Bar$1' does not override method from its superclass or interfaces but is annotated with @Override. 2. The return type String for foo(String) from the type new Y(){} needs unchecked conversion to conform to O from the type Y was (Author: emilles): So by including the generics of {{oldMethod}}, {{equalParametersWithGenerics}} can get from {{O -> Object}} to {{O -> T -> Object}}. Since {{genericsSpec}} is only used to convert types from {{oldMethod}}, I removed the existing call {{addMethodGenerics(overridingMethod, genericsSpec)}}. {code:java} // org.codehaus.groovy.classgen.Verifier private MethodNode getCovariantImplementation(final MethodNode oldMethod, final MethodNode overridingMethod, Map genericsSpec, boolean ignoreError) { // method name if (!oldMethod.getName().equals(overridingMethod.getName())) return null; if ((overridingMethod.getModifiers() & ACC_BRIDGE) != 0) return null; if (oldMethod.isPrivate()) return null; // GRECLIPSE add -- GROOVY-9059 genericsSpec = GenericsUtils.addMethodGenerics(oldMethod, genericsSpec); // GRECLIPSE end // parameters boolean normalEqualParameters = equalParametersNormal(overridingMethod, oldMethod); boolean genericEqualParameters = equalParameter
[jira] [Comment Edited] (GROOVY-9059) Failed to parse/compile generic methods with "extends"
[ https://issues.apache.org/jira/browse/GROOVY-9059?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16822125#comment-16822125 ] Eric Milles edited comment on GROOVY-9059 at 4/19/19 6:42 PM: -- So by including the generics of {{oldMethod}}, {{equalParametersWithGenerics}} can get from {{O -> Object}} to {{O -> T -> Object}}. Since {{genericsSpec}} is only used to convert types from {{oldMethod}}, I removed the existing call {{addMethodGenerics(overridingMethod, genericsSpec)}}. {code:java} // org.codehaus.groovy.classgen.Verifier private MethodNode getCovariantImplementation(final MethodNode oldMethod, final MethodNode overridingMethod, Map genericsSpec, boolean ignoreError) { // method name if (!oldMethod.getName().equals(overridingMethod.getName())) return null; if ((overridingMethod.getModifiers() & ACC_BRIDGE) != 0) return null; if (oldMethod.isPrivate()) return null; // GRECLIPSE add -- GROOVY-9059 genericsSpec = GenericsUtils.addMethodGenerics(oldMethod, genericsSpec); // GRECLIPSE end // parameters boolean normalEqualParameters = equalParametersNormal(overridingMethod, oldMethod); boolean genericEqualParameters = equalParametersWithGenerics(overridingMethod, oldMethod, genericsSpec); if (!normalEqualParameters && !genericEqualParameters) return null; /* GRECLIPSE edit -- GROOVY-9059 //correct to method level generics for the overriding method genericsSpec = GenericsUtils.addMethodGenerics(overridingMethod, genericsSpec); */ // return type ClassNode mr = overridingMethod.getReturnType(); ClassNode omr = oldMethod.getReturnType(); boolean equalReturnType = mr.equals(omr); ClassNode testmr = correctToGenericsSpec(genericsSpec, omr); {code} >From there, it needs some help to use the entry {{T=T->java.lang.String}} from >{{genericsSpec}}. I did it using a special method from ClassNode that was >introduced for a previous fix: {code:java} // org.codehaus.groovy.ast.tools.GenericsUtils public static ClassNode correctToGenericsSpec(Map genericsSpec, ClassNode type) { if (type.isArray()) { return correctToGenericsSpec(genericsSpec, type.getComponentType()).makeArray(); } if (type.isGenericsPlaceHolder()) { String name = type.getGenericsTypes()[0].getName(); type = genericsSpec.get(name); // GRECLIPSE add -- GROOVY-9059 if (type != null && type.isGenericsPlaceHolder()) { type = type.asGenericsType().getUpperBounds()[0]; return correctToGenericsSpec(genericsSpec, type); } // GRECLIPSE end } if (type == null) type = ClassHelper.OBJECT_TYPE; return type; } {code} {code:java} // org.codehaus.groovy.ast.ClassNode public GenericsType asGenericsType() { if (!isGenericsPlaceHolder()) { return new GenericsType(this); } else { ClassNode upper = (redirect != null ? redirect : this); return new GenericsType(this, new ClassNode[]{upper}, null); } } {code} With that in place, you can do this without error: {code:groovy} class Why implements Y { @Override public CS foo(CS s) { s } } // or def why = new Y() { @Override public CS foo(CS s) { s } } {code} However, your example of using String and no method generics still produces 1 error (from groovyc) and 1 warning (from eclipse): 1. Method 'foo' from class 'Bar$1' does not override method from its superclass or interfaces but is annotated with @Override. 2. The return type String for foo(String) from the type new Y(){} needs unchecked conversion to conform to O from the type Y was (Author: emilles): So by including the generics of {{oldMethod}}, {{equalParametersWithGenerics}} can get from {{O -> Object}} to {{O -> T -> Object}}. Since {{genericsSpec}} is only used to convert types from {{oldMethod}}, I removed the existing call {{addMethodGenerics(overridingMethod, genericsSpec)}}. {code:java} // org.codehaus.groovy.classgen.Verifier private MethodNode getCovariantImplementation(final MethodNode oldMethod, final MethodNode overridingMethod, Map genericsSpec, boolean ignoreError) { // method name if (!oldMethod.getName().equals(overridingMethod.getName())) return null; if ((overridingMethod.getModifiers() & ACC_BRIDGE) != 0) return null; if (oldMethod.isPrivate()) return null; // GRECLIPSE add -- GROOVY-9059 genericsSpec = GenericsUtils.addMethodGenerics(oldMethod, genericsSpec); // GRECLIPSE end // parameters boolean normalEqualParameters = equalParametersNormal(overridingMethod, oldMethod); boolean genericEqualParameters = equalParametersWit
[jira] [Comment Edited] (GROOVY-9059) Failed to parse/compile generic methods with "extends"
[ https://issues.apache.org/jira/browse/GROOVY-9059?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16822059#comment-16822059 ] Eric Milles edited comment on GROOVY-9059 at 4/19/19 5:03 PM: -- {code:java} private MethodNode getCovariantImplementation(final MethodNode oldMethod, final MethodNode overridingMethod, Map genericsSpec, boolean ignoreError) { // method name if (!oldMethod.getName().equals(overridingMethod.getName())) return null; if ((overridingMethod.getModifiers() & ACC_BRIDGE) != 0) return null; if (oldMethod.isPrivate()) return null; // GRECLIPSE add -- GROOVY-9059 // correct to method level generics for the overriding method genericsSpec = GenericsUtils.addMethodGenerics(overridingMethod, genericsSpec); // GRECLIPSE end // parameters boolean normalEqualParameters = equalParametersNormal(overridingMethod, oldMethod); boolean genericEqualParameters = equalParametersWithGenerics(overridingMethod, oldMethod, genericsSpec); if (!normalEqualParameters && !genericEqualParameters) return null; /* GRECLIPSE edit -- GROOVY-9059 //correct to method level generics for the overriding method genericsSpec = GenericsUtils.addMethodGenerics(overridingMethod, genericsSpec); */ {code} was (Author: emilles): {code:java} private MethodNode getCovariantImplementation(final MethodNode oldMethod, final MethodNode overridingMethod, Map genericsSpec, boolean ignoreError) { // method name if (!oldMethod.getName().equals(overridingMethod.getName())) return null; if ((overridingMethod.getModifiers() & ACC_BRIDGE) != 0) return null; if (oldMethod.isPrivate()) return null; // GRECLIPSE add -- GROOVY-9059 genericsSpec = GenericsUtils.addMethodGenerics(overridingMethod, genericsSpec); // GRECLIPSE end // parameters boolean normalEqualParameters = equalParametersNormal(overridingMethod, oldMethod); boolean genericEqualParameters = equalParametersWithGenerics(overridingMethod, oldMethod, genericsSpec); if (!normalEqualParameters && !genericEqualParameters) return null; /* GRECLIPSE edit -- GROOVY-9059 //correct to method level generics for the overriding method genericsSpec = GenericsUtils.addMethodGenerics(overridingMethod, genericsSpec); */ {code} > Failed to parse/compile generic methods with "extends" > -- > > Key: GROOVY-9059 > URL: https://issues.apache.org/jira/browse/GROOVY-9059 > Project: Groovy > Issue Type: Bug > Components: Static compilation >Affects Versions: 2.4.16, 3.0.0-alpha-4, 2.5.6 >Reporter: Xiaoguang Wang >Priority: Major > Attachments: image-2019-03-30-13-10-20-819.png > > > > {code:java} > import groovy.transform.CompileStatic > // This bug affects: groovy-2.4.16, groovy-2.5.6, groovy-3.0.0-alpha-4 > // This bug also affect IDEA's syntax parser > interface X { > // Intellij IDEA reports that 'public' is not necessary > // BUT without the 'public' modifier, there is a syntax error > public T foo(T o); > } > interface Y { > public O foo(O o); > } > @CompileStatic > class TestGroovyGeneric { > static void main(String[] args) { > def x = new X() { > // it compiles > // BUT: Intellij IDEA reports: ERROR: Method 'foo' is not > implemented > @Override > String foo(String o) { return o } > } > // Strangely, such code compiles > // BUT: Intellij IDEA reports: ERROR: Method 'foo' is not implemented > def y1 = new Y() { > @Override > public String foo(String o) { return o } > } > // Can not compile: > // BUT: Intellij IDEA reports no error > def y2 = new Y() { > @Override > String foo(String o) { return o } > } > } > } > {code} > !image-2019-03-30-13-10-20-819.png! > -- This message was sent by Atlassian JIRA (v7.6.3#76005)
[jira] [Comment Edited] (GROOVY-9059) Failed to parse/compile generic methods with "extends"
[ https://issues.apache.org/jira/browse/GROOVY-9059?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16805652#comment-16805652 ] Xiaoguang Wang edited comment on GROOVY-9059 at 3/30/19 6:12 AM: - Sorry I messed different problems together. The main problem here is about {code:java} interface Y { public O foo(O o); } def y2 = new Y() { @Override String foo(String o) { return o } } {code} It compiles in Java, and such code appears in Srping's code, eg: `org.springframework.security.config.annotation.ObjectPostProcessor` which has `{{https://docs.spring.io/spring-security/site/docs/4.2.10.RELEASE/apidocs/org/springframework/security/config/annotation/ObjectPostProcessor.html]>}} {{[postProcess|https://docs.spring.io/spring-security/site/docs/4.2.10.RELEASE/apidocs/org/springframework/security/config/annotation/ObjectPostProcessor.html#postProcess-O-](O object)}}` Such different behavior (groovy's error) makes developers do not know how to use Groovy with Spring. was (Author: wxiaoguang): Sorry I messed different problems together. The main problem here is about interface Y {public O foo(O o); } def y2 = new Y() \{ @Override String foo(String o) { return o } } It compiles in Java, and such code appears in Srping's code, eg: `org.springframework.security.config.annotation.ObjectPostProcessor` which has `{{https://docs.spring.io/spring-security/site/docs/4.2.10.RELEASE/apidocs/org/springframework/security/config/annotation/ObjectPostProcessor.html]>}} {{[postProcess|https://docs.spring.io/spring-security/site/docs/4.2.10.RELEASE/apidocs/org/springframework/security/config/annotation/ObjectPostProcessor.html#postProcess-O-](O object)}}` Such different behavior makes developers do not know how to use Groovy with Spring. > Failed to parse/compile generic methods with "extends" > -- > > Key: GROOVY-9059 > URL: https://issues.apache.org/jira/browse/GROOVY-9059 > Project: Groovy > Issue Type: Bug > Components: Static compilation >Affects Versions: 2.4.16, 3.0.0-alpha-4, 2.5.6 >Reporter: Xiaoguang Wang >Priority: Major > Attachments: image-2019-03-30-13-10-20-819.png > > > > {code:java} > import groovy.transform.CompileStatic > // This bug affects: groovy-2.4.16, groovy-2.5.6, groovy-3.0.0-alpha-4 > // This bug also affect IDEA's syntax parser > interface X { > // Intellij IDEA reports that 'public' is not necessary > // BUT without the 'public' modifier, there is a syntax error > public T foo(T o); > } > interface Y { > public O foo(O o); > } > @CompileStatic > class TestGroovyGeneric { > static void main(String[] args) { > def x = new X() { > // it compiles > // BUT: Intellij IDEA reports: ERROR: Method 'foo' is not > implemented > @Override > String foo(String o) { return o } > } > // Strangely, such code compiles > // BUT: Intellij IDEA reports: ERROR: Method 'foo' is not implemented > def y1 = new Y() { > @Override > public String foo(String o) { return o } > } > // Can not compile: > // BUT: Intellij IDEA reports no error > def y2 = new Y() { > @Override > String foo(String o) { return o } > } > } > } > {code} > !image-2019-03-30-13-10-20-819.png! > -- This message was sent by Atlassian JIRA (v7.6.3#76005)