This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new a3c5939497 GROOVY-11550: check method for name clash (same erasure, 
different type)
a3c5939497 is described below

commit a3c59394977fd9feb5220812f62b6fd0b60a0739
Author: Eric Milles <[email protected]>
AuthorDate: Sun Mar 9 16:30:12 2025 -0500

    GROOVY-11550: check method for name clash (same erasure, different type)
---
 .../apache/groovy/ast/tools/ClassNodeUtils.java    | 16 ++--
 .../apache/groovy/ast/tools/MethodNodeUtils.java   | 48 ++++++++---
 .../codehaus/groovy/ast/tools/GenericsUtils.java   |  2 +-
 .../groovy/classgen/ClassCompletionVerifier.java   | 94 +++++++++++++++++++---
 .../org/codehaus/groovy/classgen/EnumVisitor.java  |  2 +-
 .../org/codehaus/groovy/classgen/Verifier.java     | 38 +++++----
 .../transform/trait/TraitASTTransformation.java    |  2 +
 .../codehaus/groovy/transform/trait/Traits.java    | 16 ++--
 src/test/gls/invocation/CovariantReturnTest.groovy | 36 ++++++---
 src/test/groovy/OverrideTest.groovy                | 18 ++---
 src/test/groovy/bugs/Groovy10236.groovy            |  4 +-
 src/test/groovy/bugs/Groovy10281.groovy            |  2 +-
 src/test/groovy/bugs/Groovy10305.groovy            |  2 +-
 src/test/groovy/bugs/Groovy10381.groovy            |  2 +-
 src/test/groovy/bugs/Groovy11272.groovy            |  2 +-
 src/test/groovy/bugs/Groovy11292.groovy            |  2 +-
 src/test/groovy/bugs/Groovy11293.groovy            |  2 +-
 .../transform/TupleConstructorTransformTest.groovy |  4 +-
 .../traitx/TraitASTTransformationTest.groovy       |  4 +-
 19 files changed, 206 insertions(+), 90 deletions(-)

diff --git a/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java 
b/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
index e1d848ee2b..e91bc8f651 100644
--- a/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
+++ b/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
@@ -75,20 +75,20 @@ public class ClassNodeUtils {
      */
     public static String formatTypeName(final ClassNode cNode) {
         if (cNode.isArray()) {
-            ClassNode it = cNode;
             int dim = 0;
-            while (it.isArray()) {
-                dim++;
-                it = it.getComponentType();
+            ClassNode cn = cNode;
+            while (cn.isArray()) {
+                dim += 1;
+                cn = cn.getComponentType();
             }
-            StringBuilder sb = new StringBuilder(it.getName().length() + 2 * 
dim);
-            sb.append(it.getName());
-            for (int i = 0; i < dim; i++) {
+            StringBuilder sb = new StringBuilder(cn.getName().length() + (2 * 
dim));
+            sb.append(formatTypeName(cn));
+            for (int i = 0; i < dim; i += 1) {
                 sb.append("[]");
             }
             return sb.toString();
         }
-        return cNode.getName();
+        return cNode.isGenericsPlaceHolder() ? cNode.getUnresolvedName() : 
cNode.getName();
     }
 
     /**
diff --git a/src/main/java/org/apache/groovy/ast/tools/MethodNodeUtils.java 
b/src/main/java/org/apache/groovy/ast/tools/MethodNodeUtils.java
index 40b7f83fb2..3c5de04919 100644
--- a/src/main/java/org/apache/groovy/ast/tools/MethodNodeUtils.java
+++ b/src/main/java/org/apache/groovy/ast/tools/MethodNodeUtils.java
@@ -18,6 +18,7 @@
  */
 package org.apache.groovy.ast.tools;
 
+import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.ConstructorNode;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
@@ -40,6 +41,14 @@ public class MethodNodeUtils {
 
     private MethodNodeUtils() { }
 
+    private static void appendTypeName(final StringBuilder sb, ClassNode cn) {
+        while (cn.isArray()) {
+            cn = cn.getComponentType();
+            sb.append('[');
+        }
+        sb.append(cn.getName());
+    }
+
     /**
      * Return the method node's descriptor including its
      * name and parameter types without generics.
@@ -51,7 +60,8 @@ public class MethodNodeUtils {
         StringBuilder sb = new StringBuilder();
         sb.append(mNode.getName()).append(':');
         for (Parameter p : mNode.getParameters()) {
-            sb.append(ClassNodeUtils.formatTypeName(p.getType())).append(',');
+            appendTypeName(sb, p.getType());
+            sb.append(';');
         }
         return sb.toString();
     }
@@ -75,26 +85,38 @@ public class MethodNodeUtils {
      * @param pretty whether to quote a name with spaces
      * @return the method node's descriptor
      */
-    public static String methodDescriptor(final MethodNode mNode, boolean 
pretty) {
+    public static String methodDescriptor(final MethodNode mNode, final 
boolean pretty) {
         String name = mNode.getName();
-        if (pretty) pretty = name.contains(" ");
         Parameter[] parameters = mNode.getParameters();
-        int nParameters = parameters == null ? 0 : parameters.length;
-
-        StringBuilder sb = new StringBuilder(name.length() * 2 + nParameters * 
10);
-        sb.append(ClassNodeUtils.formatTypeName(mNode.getReturnType()));
-        sb.append(' ');
-        if (pretty) sb.append('"');
-        sb.append(name);
-        if (pretty) sb.append('"');
+        int nParameters = (parameters == null ? 0 : parameters.length);
+
+        StringBuilder sb = new StringBuilder((name.length() * 2) + 
(nParameters * 10));
+        if (pretty && !mNode.isConstructor()) {
+            sb.append(ClassNodeUtils.formatTypeName(mNode.getReturnType()));
+            sb.append(' ');
+        }
+        if (name.contains(" ")) {
+            sb.append('"').append(name).append('"');
+        } else {
+            sb.append(name);
+        }
         sb.append('(');
         for (int i = 0; i < nParameters; i += 1) {
             if (i > 0) {
-                sb.append(", ");
+                sb.append(',');
+                if (pretty) sb.append(' ');
+            }
+            if (pretty) {
+                
sb.append(ClassNodeUtils.formatTypeName(parameters[i].getType()));
+            } else {
+                appendTypeName(sb, parameters[i].getType());
             }
-            sb.append(ClassNodeUtils.formatTypeName(parameters[i].getType()));
         }
         sb.append(')');
+        if (!pretty && !mNode.isConstructor()) {
+            sb.append(':');
+            appendTypeName(sb, mNode.getReturnType());
+        }
         return sb.toString();
     }
 
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java 
b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
index aa5ced7702..908974881b 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -597,7 +597,7 @@ public class GenericsUtils {
         } else {
             ClassNode superClass = getSuperClass(type, target);
             if (superClass != null) {
-                if (hasUnresolvedGenerics(superClass)) {
+                if (type.isRedirectNode() && 
hasUnresolvedGenerics(superClass)) {
                     GenericsType[] tp = type.redirect().getGenericsTypes();
                     if (tp != null) {
                         GenericsType[] ta = type.getGenericsTypes();
diff --git 
a/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java 
b/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
index 100118cdd5..845c0dc5b3 100644
--- a/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
@@ -21,6 +21,7 @@ package org.codehaus.groovy.classgen;
 import groovy.transform.Sealed;
 import org.apache.groovy.ast.tools.AnnotatedNodeUtils;
 import org.apache.groovy.ast.tools.ClassNodeUtils;
+import org.apache.groovy.ast.tools.MethodNodeUtils;
 import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
 import org.codehaus.groovy.ast.ClassHelper;
@@ -55,6 +56,7 @@ import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static java.lang.reflect.Modifier.isFinal;
 import static java.lang.reflect.Modifier.isNative;
@@ -65,6 +67,10 @@ import static java.lang.reflect.Modifier.isStrict;
 import static java.lang.reflect.Modifier.isSynchronized;
 import static java.lang.reflect.Modifier.isTransient;
 import static java.lang.reflect.Modifier.isVolatile;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.addMethodGenerics;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.buildWildcardType;
+import static 
org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpecRecurse;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
 import static org.objectweb.asm.Opcodes.ACC_ABSTRACT;
 import static org.objectweb.asm.Opcodes.ACC_FINAL;
 import static org.objectweb.asm.Opcodes.ACC_NATIVE;
@@ -123,6 +129,7 @@ public class ClassCompletionVerifier extends 
ClassCodeVisitorSupport {
                 checkMethodsForIncorrectName(node);
                 checkMethodsForWeakerAccess(node);
                 checkMethodsForOverridingFinal(node);
+                checkMethodsForOverridingIssue(node);
                 checkNoAbstractMethodsNonAbstractClass(node);
                 checkClassExtendsOrImplementsSelfTypes(node);
                 checkNoStaticMethodWithSameSignatureAsNonStatic(node);
@@ -279,7 +286,7 @@ public class ClassCompletionVerifier extends 
ClassCodeVisitorSupport {
     }
 
     private static String getDescription(final MethodNode node) {
-        return "method '" + node.getTypeDescriptor() + "'";
+        return "method '" + MethodNodeUtils.methodDescriptor(node, true) + "'";
     }
 
     private static String getDescription(final FieldNode node) {
@@ -299,7 +306,7 @@ public class ClassCompletionVerifier extends 
ClassCodeVisitorSupport {
 
         addError("Can't have an abstract method in a non-abstract class." +
                 " The " + getDescription(currentClass) + " must be declared 
abstract or the method '" +
-                methodNode.getTypeDescriptor() + "' must not be abstract.", 
methodNode);
+                MethodNodeUtils.methodDescriptor(methodNode, true) + "' must 
not be abstract.", methodNode);
     }
 
     private void checkClassForExtendingFinalOrSealed(final ClassNode cn) {
@@ -404,28 +411,97 @@ public class ClassCompletionVerifier extends 
ClassCodeVisitorSupport {
     }
 
     private void checkMethodsForOverridingFinal(final ClassNode cn) {
+        final int skips = ACC_SYNTHETIC | ACC_STATIC | ACC_PRIVATE;
         for (MethodNode method : cn.getMethods()) {
-            if ((method.getModifiers() & ACC_SYNTHETIC) != 0) continue; // 
GROOVY-11579: bridge method
+            if ((method.getModifiers() & skips) != 0) continue; // GROOVY-11579
 
-            ClassNode sc = cn.getSuperClass();
             Parameter[] params = method.getParameters();
-            for (MethodNode superMethod : sc.getMethods(method.getName())) {
-                if (superMethod.isFinal()
+            for (MethodNode superMethod : 
cn.getSuperClass().getMethods(method.getName())) {
+                if ((superMethod.getModifiers() & skips + ACC_FINAL) == 
ACC_FINAL
                         && ParameterUtils.parametersEqual(params, 
superMethod.getParameters())) {
                     StringBuilder sb = new StringBuilder();
                     sb.append("You are not allowed to override the final 
method ");
-                    sb.append(method.getName());
+                    if (method.getName().contains(" ")) {
+                        sb.append('"').append(method.getName()).append('"');
+                    } else {
+                        sb.append(method.getName());
+                    }
                     appendParamsDescription(params, sb);
                     sb.append(" from ");
-                    sb.append(getDescription(sc));
+                    sb.append(getDescription(superMethod.getDeclaringClass()));
                     sb.append(".");
 
                     addError(sb.toString(), method.getLineNumber() > 0 ? 
method : cn);
+                    break;
                 }
             }
         }
     }
 
+    private void checkMethodsForOverridingIssue(final ClassNode cn) {
+        Set<ClassNode> superTypes = getAllSuperTypes(cn);
+        superTypes.remove(ClassHelper.GROOVY_OBJECT_TYPE);
+        superTypes.remove(ClassHelper.OBJECT_TYPE);
+        if (superTypes.isEmpty()) return;
+
+        for (MethodNode mn : cn.getMethods()) {
+            Parameter[] pa = mn.getParameters();
+            if (pa.length == 0 || (mn.getModifiers() & ACC_SYNTHETIC + 
ACC_STATIC + ACC_PRIVATE) != 0) continue;
+
+out:        for (ClassNode sc : superTypes) {
+                Map<String, ClassNode> cspec = createGenericsSpec(sc);
+                for (MethodNode sm : sc.getDeclaredMethods(mn.getName())) {
+                    if (!sm.isStatic() && !sm.isPrivate() && 
ParameterUtils.parametersEqual(pa, sm.getParameters())) {
+                        Map<String, ClassNode> mspec = addMethodGenerics(sm, 
cspec);
+                        for (int i = 0, n = pa.length; i < n; i += 1) {
+                            var t0 = sm.getParameters()[i].getType();
+                            var t1 = pa[i].getType();
+                            if (!t0.isGenericsPlaceHolder() && 
!ClassHelper.isPrimitiveType(t0)
+                                    && !t1.isGenericsPlaceHolder() && 
!ClassHelper.isPrimitiveType(t1)
+                                    && !buildWildcardType(t0 = 
correctToGenericsSpecRecurse(mspec, t0)).isCompatibleWith(t1)) {
+                                StringBuilder sb = new StringBuilder();
+                                sb.append("name clash: ");
+                                if (mn.getName().contains(" ")) {
+                                    
sb.append('"').append(mn.getName()).append('"');
+                                } else {
+                                    sb.append(mn.getName());
+                                }
+                                appendParamsDescription(pa, sb);
+                                sb.append(" in ");
+                                sb.append(getDescription(cn));
+                                sb.append(" and ");
+                                if (sm.getName().contains(" ")) {
+                                    
sb.append('"').append(sm.getName()).append('"');
+                                } else {
+                                    sb.append(sm.getName());
+                                }
+                                appendParamsDescription(sm.getParameters(), 
sb);
+                                sb.append(" in ");
+                                sb.append(getDescription(sc));
+                                sb.append(" have the same erasure, yet neither 
overrides the other.");
+
+                                addError(sb.toString(), mn.getLineNumber() > 0 
? mn : cn);
+                                break;
+                            }
+                        }
+                        break out;
+                    }
+                }
+            }
+        }
+    }
+
+    private static Set<ClassNode> getAllSuperTypes(ClassNode cn) {
+        Set<ClassNode> interfaces = 
GeneralUtils.getInterfacesAndSuperInterfaces(cn);
+        Set<ClassNode> superTypes = new LinkedHashSet<>();
+        interfaces.remove(cn);
+        while ((cn = cn.getSuperClass()) != null) {
+            superTypes.add(cn);
+        }
+        superTypes.addAll(interfaces);
+        return superTypes;
+    }
+
     private void appendParamsDescription(final Parameter[] parameters, final 
StringBuilder msg) {
         msg.append('(');
         boolean needsComma = false;
@@ -435,7 +511,7 @@ public class ClassCompletionVerifier extends 
ClassCodeVisitorSupport {
             } else {
                 needsComma = true;
             }
-            msg.append(parameter.getType());
+            msg.append(parameter.getType().toString(false));
         }
         msg.append(')');
     }
diff --git a/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java 
b/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java
index d73339304f..ab22c7ca25 100644
--- a/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java
@@ -285,7 +285,7 @@ public class EnumVisitor extends ClassCodeVisitorSupport {
                             if (!methodNode.isAbstract()) continue;
                             MethodNode enumConstMethod = 
inner.getMethod(methodNode.getName(), methodNode.getParameters());
                             if (enumConstMethod == null || 
enumConstMethod.isAbstract()) {
-                                addError(field, "Can't have an abstract method 
in enum constant " + field.getName() + ". Implement method '" + 
methodNode.getTypeDescriptor() + "'.");
+                                addError(field, "Can't have an abstract method 
in enum constant " + field.getName() + ". Implement method '" + 
methodNode.getTypeDescriptor(true) + "'.");
                             }
                         }
                         if (inner.getVariableScope() == null) {
diff --git a/src/main/java/org/codehaus/groovy/classgen/Verifier.java 
b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
index 29bc833155..f45013210c 100644
--- a/src/main/java/org/codehaus/groovy/classgen/Verifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
@@ -98,9 +98,6 @@ import static 
org.apache.groovy.ast.tools.AnnotatedNodeUtils.isGenerated;
 import static org.apache.groovy.ast.tools.AnnotatedNodeUtils.markAsGenerated;
 import static 
org.apache.groovy.ast.tools.ConstructorNodeUtils.getFirstIfSpecialConstructorCall;
 import static 
org.apache.groovy.ast.tools.ExpressionUtils.transformInlineConstants;
-import static org.apache.groovy.ast.tools.MethodNodeUtils.getCodeAsBlock;
-import static org.apache.groovy.ast.tools.MethodNodeUtils.getPropertyName;
-import static 
org.apache.groovy.ast.tools.MethodNodeUtils.methodDescriptorWithoutReturnType;
 import static org.codehaus.groovy.ast.ClassHelper.isObjectType;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveBoolean;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveDouble;
@@ -291,7 +288,7 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
                 .flatMap(i -> i.getAllDeclaredMethods().stream())
                 .filter(MethodNode::isDefault)
                 .forEach(m -> {
-                    String signature = methodDescriptorWithoutReturnType(m);
+                    String signature = 
MethodNodeUtils.methodDescriptorWithoutReturnType(m);
                     if (declared.contains(signature)) {
                         return;
                     }
@@ -308,7 +305,7 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
                             || 
currentDeclaringClass.implementsInterface(existingDeclaringClass))) {
                         throw new RuntimeParserException(
                                 (node.isInterface() ? "interface" : "class") + 
 " " + node.getName()
-                                        + " inherits unrelated defaults for " 
+ m.getTypeDescriptor()
+                                        + " inherits unrelated defaults for " 
+ MethodNodeUtils.methodDescriptor(m, true)
                                         + " from types " + 
existingDeclaringClass.getName()
                                         + " and " + 
currentDeclaringClass.getName(), node);
                     }
@@ -427,7 +424,7 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
         Set<String> descriptors = new HashSet<>();
         for (MethodNode mn : cn.getMethods()) {
             if (mn.isSynthetic()) continue;
-            String mySig = methodDescriptorWithoutReturnType(mn);
+            String mySig = 
MethodNodeUtils.methodDescriptorWithoutReturnType(mn);
             if (descriptors.contains(mySig)) {
                 if (mn.isScriptBody() || 
mySig.equals(scriptBodySignatureWithoutReturnType(cn))) {
                     throw new RuntimeParserException("The method " + 
mn.getText() +
@@ -444,7 +441,7 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
     private static void checkForDuplicateConstructors(final ClassNode cn) {
         Set<String> descriptors = new HashSet<>();
         for (ConstructorNode cons : cn.getDeclaredConstructors()) {
-            String mySig = methodDescriptorWithoutReturnType(cons);
+            String mySig = 
MethodNodeUtils.methodDescriptorWithoutReturnType(cons);
             if (descriptors.contains(mySig)) {
                 throw new RuntimeParserException("The constructor " + 
cons.getText() +
                     " duplicates another constructor of the same signature", 
sourceOf(cons));
@@ -455,7 +452,7 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
 
     private static String scriptBodySignatureWithoutReturnType(final ClassNode 
cn) {
         for (MethodNode mn : cn.getMethods()) {
-            if (mn.isScriptBody()) return 
methodDescriptorWithoutReturnType(mn);
+            if (mn.isScriptBody()) return 
MethodNodeUtils.methodDescriptorWithoutReturnType(mn);
         }
         return null;
     }
@@ -921,8 +918,8 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
             MethodNode oldMethod = type.getDeclaredMethod(method.getName(), 
params);
             if (oldMethod != null) {
                 throw new RuntimeParserException(
-                        "The method with default parameters \"" + 
method.getTypeDescriptor() +
-                                "\" defines a method \"" + 
newMethod.getTypeDescriptor() +
+                        "The method with default parameters \"" + 
MethodNodeUtils.methodDescriptor(method, true) +
+                                "\" defines a method \"" + 
MethodNodeUtils.methodDescriptor(newMethod, true) +
                                 "\" that is already defined.",
                         sourceOf(method));
             }
@@ -1057,7 +1054,7 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
                 addConstructor(params, (ConstructorNode) method, 
stmt(ctorThisX(arguments)), type);
             } else {
                 String warning = "Default argument(s) specify duplicate 
constructor: " +
-                        old.getTypeDescriptor().replace("void <init>", 
type.getNameWithoutPackage());
+                    
MethodNodeUtils.methodDescriptor(old,true).replace("<init>",type.getNameWithoutPackage());
                 type.getModule().getContext().addWarning(warning, 
method.getLineNumber() > 0 ? method : type);
             }
         });
@@ -1183,7 +1180,7 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
             }
         }
 
-        BlockStatement block = getCodeAsBlock(constructorNode);
+        BlockStatement block = MethodNodeUtils.getCodeAsBlock(constructorNode);
         List<Statement> blockStatements = block.getStatements();
         if (!blockStatements.isEmpty()) {
             if (specialCtorCall != null) {
@@ -1541,7 +1538,7 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
             if (ignoreError) return null;
             throw new RuntimeParserException(
                     "The return type of " +
-                            overrideCandidate.getTypeDescriptor() +
+                            
MethodNodeUtils.methodDescriptor(overrideCandidate, true) +
                             " in " + 
overrideCandidate.getDeclaringClass().getName() +
                             " is incompatible with " + omrCorrected.getName() +
                             " in " + oldMethod.getDeclaringClass().getName(),
@@ -1553,14 +1550,14 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
         if (oldMethod.isFinal()) {
             throw new RuntimeParserException(
                     "Cannot override final method " +
-                            oldMethod.getTypeDescriptor() +
+                            MethodNodeUtils.methodDescriptor(oldMethod, true) +
                             " in " + oldMethod.getDeclaringClass().getName(),
                     sourceOf(overrideCandidate));
         }
         if (oldMethod.isStatic() != overrideCandidate.isStatic()) {
             throw new RuntimeParserException(
                     "Cannot override method " +
-                            oldMethod.getTypeDescriptor() +
+                            MethodNodeUtils.methodDescriptor(oldMethod, true) +
                             " in " + oldMethod.getDeclaringClass().getName() +
                             " with disparate static modifier",
                     sourceOf(overrideCandidate));
@@ -1579,7 +1576,7 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
                 }
                 throw new RuntimeParserException(
                         "Cannot override method " +
-                                oldMethod.getTypeDescriptor() +
+                                MethodNodeUtils.methodDescriptor(oldMethod, 
true) +
                                 " in " + 
oldMethod.getDeclaringClass().getName() +
                                 message,
                         sourceOf(overrideCandidate));
@@ -1661,9 +1658,10 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
     }
 
     private static ClassNode cleanType(final ClassNode type) {
-        // TODO: Should this be directly handled by getPlainNodeReference?
-        if (type.isArray()) return 
cleanType(type.getComponentType()).makeArray();
-        return type.getPlainNodeReference();
+        if (type.isArray()) {
+            return cleanType(type.getComponentType()).makeArray();
+        }
+        return type.redirect().getPlainNodeReference();
     }
 
     private static boolean equalParametersNormal(final MethodNode m1, final 
MethodNode m2) {
@@ -1729,7 +1727,7 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
         if (methodNode.getLineNumber() < 1) {
             ClassNode declaringClass = methodNode.getDeclaringClass();
             if (methodNode.isSynthetic()) {
-                String propertyName = getPropertyName(methodNode);
+                String propertyName = 
MethodNodeUtils.getPropertyName(methodNode);
                 if (propertyName != null) {
                     PropertyNode propertyNode = 
declaringClass.getProperty(propertyName);
                     if (propertyNode != null && propertyNode.getLineNumber() > 
0) {
diff --git 
a/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java 
b/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
index e7c36a2a58..dde69b9efe 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
@@ -194,6 +194,7 @@ public class TraitASTTransformation extends 
AbstractASTTransformation implements
                 ClassNode.EMPTY_ARRAY,
                 null
         );
+        helper.setGenericsTypes(cNode.getGenericsTypes());
         helper.setStaticClass(true); // GROOVY-7242, GROOVY-7456, etc.
 
         MethodNode initializer = createInitMethod(false, helper);
@@ -226,6 +227,7 @@ public class TraitASTTransformation extends 
AbstractASTTransformation implements
                     ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | 
ACC_SYNTHETIC,
                     OBJECT_TYPE
             );
+            fieldHelper.setGenericsTypes(cNode.getGenericsTypes());
             fieldHelper.setStaticClass(true);
             if (hasStatic) {
                 staticFieldHelper = new InnerClassNode(
diff --git a/src/main/java/org/codehaus/groovy/transform/trait/Traits.java 
b/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
index 8a99930e39..31ca6a88e2 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
@@ -26,7 +26,7 @@ import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.FieldNode;
-import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.GenericsType;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.expr.ClassExpression;
 import org.codehaus.groovy.ast.expr.Expression;
@@ -42,7 +42,6 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.lang.reflect.Method;
 import java.util.Arrays;
-import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -130,10 +129,10 @@ public abstract class Traits {
         ClassNode helperClassNode = null;
         ClassNode fieldHelperClassNode = null;
         ClassNode staticFieldHelperClassNode = null;
-        Iterator<InnerClassNode> innerClasses = 
trait.redirect().getInnerClasses();
-        if (innerClasses != null && innerClasses.hasNext()) {
+        var innerClasses = trait.redirect().getInnerClasses();
+        if (innerClasses != null && innerClasses.hasNext() ) {
             // trait declared in same unit
-            while (innerClasses.hasNext()) {
+            do {
                 ClassNode icn = innerClasses.next();
                 if (icn.getName().endsWith(Traits.TRAIT_HELPER)) {
                     helperClassNode = icn;
@@ -142,7 +141,7 @@ public abstract class Traits {
                 } else if (icn.getName().endsWith(Traits.STATIC_FIELD_HELPER)) 
{
                     staticFieldHelperClassNode = icn;
                 }
-            }
+            } while (innerClasses.hasNext());
         } else {
             // precompiled trait
             try {
@@ -159,6 +158,11 @@ public abstract class Traits {
                 throw new GroovyBugError("Couldn't find trait helper classes 
on compile classpath!", e);
             }
         }
+        GenericsType[] typeArguments = trait.getGenericsTypes();
+        helperClassNode = GenericsUtils.makeClassSafe0(helperClassNode, 
typeArguments);
+        if (fieldHelperClassNode != null) {
+            fieldHelperClassNode = 
GenericsUtils.makeClassSafe0(fieldHelperClassNode, typeArguments);
+        }
         return new TraitHelpersTuple(helperClassNode, fieldHelperClassNode, 
staticFieldHelperClassNode);
     }
 
diff --git a/src/test/gls/invocation/CovariantReturnTest.groovy 
b/src/test/gls/invocation/CovariantReturnTest.groovy
index b67f87d2e2..acef4438b9 100644
--- a/src/test/gls/invocation/CovariantReturnTest.groovy
+++ b/src/test/gls/invocation/CovariantReturnTest.groovy
@@ -237,17 +237,17 @@ final class CovariantReturnTest {
     @Test
     void testCovariantArrayReturnType1() {
         assertScript '''
-            interface Base {}
-
-            interface Derived extends Base {}
-
+            interface A {
+            }
+            interface B extends A {
+            }
             interface I {
-                Base[] foo()
+                A[] foo()
             }
-
             class C implements I {
-                Derived[] foo() { null }
+                B[] foo() { null }
             }
+
             new C().foo()
         '''
     }
@@ -257,26 +257,42 @@ final class CovariantReturnTest {
     void testCovariantArrayReturnType2() {
         assertScript '''
             interface A<T> {
-                T[] process();
+                T[] process()
             }
-
             class B implements A<String> {
                 @Override
                 public String[] process() {
                     ['foo']
                 }
             }
-
             class C extends B {
                 @Override
                 String[] process() {
                     super.process()
                 }
             }
+
             assert new C().process()[0] == 'foo'
         '''
     }
 
+    // GROOVY-11579
+    @Test
+    void testCovariantBridgeReturnType() {
+        assertScript '''
+            interface I<T> {
+                T m()
+            }
+            abstract class A {
+                final String m() { 'A' }
+            }
+            class C extends A implements I<String> {
+            }
+
+            assert new C().m() == 'A'
+        '''
+    }
+
     // GROOVY-7495
     @Test
     void testCovariantReturnFromIndirectInterface() {
diff --git a/src/test/groovy/OverrideTest.groovy 
b/src/test/groovy/OverrideTest.groovy
index bbca486049..dfc658f583 100644
--- a/src/test/groovy/OverrideTest.groovy
+++ b/src/test/groovy/OverrideTest.groovy
@@ -225,21 +225,19 @@ final class OverrideTest {
         '''
     }
 
-    // GROOVY-11579
+    // GROOVY-11550
     @Test
-    void testCovariantReturnType() {
-        assertScript '''
+    void testCovariantParameterType6() {
+        def err = shouldFail '''
             interface I<T> {
-                T m()
-            }
-            abstract class A {
-                final String m() { 'A' }
+                void m(I<Object> i_of_object)
             }
-            class C extends A implements I<String> {
+            class C implements I<Object> {
+                void m(I<String> i_of_string) {
+                }
             }
-
-            assert new C().m() == 'A'
         '''
+        assert err =~ /name clash: m\(I<java.lang.String>\) in class 'C' and 
m\(I<java.lang.Object>\) in interface 'I' have the same erasure, yet neither 
overrides the other./
     }
 
     @Test
diff --git a/src/test/groovy/bugs/Groovy10236.groovy 
b/src/test/groovy/bugs/Groovy10236.groovy
index 2ffac11c0b..2747b43aae 100644
--- a/src/test/groovy/bugs/Groovy10236.groovy
+++ b/src/test/groovy/bugs/Groovy10236.groovy
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package bugs
+package groovy.bugs
 
 import groovy.transform.CompileStatic
 import org.junit.Test
@@ -30,7 +30,7 @@ final class Groovy10236 {
     void testOmittingParenthesesInLambdaBody() {
         assertScript '''
             def same(obj) { obj }
-            
+
             assert ['1', '2', '3'] == [1, 2, 3].stream().map(num -> same 
"$num").toList()
         '''
     }
diff --git a/src/test/groovy/bugs/Groovy10281.groovy 
b/src/test/groovy/bugs/Groovy10281.groovy
index 9f59928d44..e3b916b76a 100644
--- a/src/test/groovy/bugs/Groovy10281.groovy
+++ b/src/test/groovy/bugs/Groovy10281.groovy
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package bugs
+package groovy.bugs
 
 import groovy.transform.CompileStatic
 import org.codehaus.groovy.control.CompilationUnit
diff --git a/src/test/groovy/bugs/Groovy10305.groovy 
b/src/test/groovy/bugs/Groovy10305.groovy
index db2a9b5d25..28ea4ecb98 100644
--- a/src/test/groovy/bugs/Groovy10305.groovy
+++ b/src/test/groovy/bugs/Groovy10305.groovy
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package bugs
+package groovy.bugs
 
 import org.junit.Test
 
diff --git a/src/test/groovy/bugs/Groovy10381.groovy 
b/src/test/groovy/bugs/Groovy10381.groovy
index 568bb9b87c..8a0138efd2 100644
--- a/src/test/groovy/bugs/Groovy10381.groovy
+++ b/src/test/groovy/bugs/Groovy10381.groovy
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package bugs
+package groovy.bugs
 
 import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit
diff --git a/src/test/groovy/bugs/Groovy11272.groovy 
b/src/test/groovy/bugs/Groovy11272.groovy
index 237359d66c..2ffea4a110 100644
--- a/src/test/groovy/bugs/Groovy11272.groovy
+++ b/src/test/groovy/bugs/Groovy11272.groovy
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package bugs
+package groovy.bugs
 
 import org.junit.Test
 
diff --git a/src/test/groovy/bugs/Groovy11292.groovy 
b/src/test/groovy/bugs/Groovy11292.groovy
index b4421e7800..d6acfd9dc1 100644
--- a/src/test/groovy/bugs/Groovy11292.groovy
+++ b/src/test/groovy/bugs/Groovy11292.groovy
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package bugs
+package groovy.bugs
 
 import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit
diff --git a/src/test/groovy/bugs/Groovy11293.groovy 
b/src/test/groovy/bugs/Groovy11293.groovy
index 37ee96e9d0..6c1cf3d750 100644
--- a/src/test/groovy/bugs/Groovy11293.groovy
+++ b/src/test/groovy/bugs/Groovy11293.groovy
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package bugs
+package groovy.bugs
 
 import org.junit.Test
 
diff --git 
a/src/test/org/codehaus/groovy/transform/TupleConstructorTransformTest.groovy 
b/src/test/org/codehaus/groovy/transform/TupleConstructorTransformTest.groovy
index b790f9208c..790592a7e8 100644
--- 
a/src/test/org/codehaus/groovy/transform/TupleConstructorTransformTest.groovy
+++ 
b/src/test/org/codehaus/groovy/transform/TupleConstructorTransformTest.groovy
@@ -373,8 +373,8 @@ final class TupleConstructorTransformTest {
             @ASTTest(phase=CANONICALIZATION, value={
                 assert node.constructors.size() == 2
                 node.constructors.each {
-                    assert (it.typeDescriptor == 'void 
<init>(java.lang.String)' && isProtected(it.modifiers)) ||
-                            (it.typeDescriptor == 'void <init>(int)' && 
isPrivate(it.modifiers))
+                    assert (it.typeDescriptor == '<init>(java.lang.String)' && 
isProtected(it.modifiers))
+                        || (it.typeDescriptor == '<init>(int)' && 
isPrivate(it.modifiers))
                 }
             })
             class Person {
diff --git 
a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
 
b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
index b09550f321..3c8c2445ab 100644
--- 
a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
+++ 
b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
@@ -3238,12 +3238,12 @@ final class TraitASTTransformationTest {
             def mn = cn.getMethods('m')[0]
             def td = mn.typeDescriptor
 
-            assert td == 'java.lang.Object m(java.lang.Class, 
java.lang.Object[])'
+            assert td == 
'm(java.lang.Class,[java.lang.Object):java.lang.Object'
         """
 
         
System.setProperty('spock.iKnowWhatImDoing.disableGroovyVersionCheck','true')
         assertScript shell, """
-            @Grab('org.spockframework:spock-core:2.4-M1-groovy-4.0')
+            @Grab('org.spockframework:spock-core:2.4-M5-groovy-4.0')
             @GrabExclude('org.apache.groovy:*')
             import spock.lang.Specification
 


Reply via email to