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 7671c2f0f5 GROOVY-11560: Invalid compiler error for class which 
overrides a method having duplicate default definitions from interfaces
7671c2f0f5 is described below

commit 7671c2f0f55cc0604eaf677e664b5890a833fe81
Author: Paul King <[email protected]>
AuthorDate: Sat Jan 25 14:55:21 2025 +1000

    GROOVY-11560: Invalid compiler error for class which overrides a method 
having duplicate default definitions from interfaces
---
 .../org/codehaus/groovy/classgen/Verifier.java     | 11 +++++++-
 src/test/groovy/bugs/Groovy10381.groovy            | 32 ++++++++++++++++++++++
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/Verifier.java 
b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
index 6f2c3d338e..1f766ce371 100644
--- a/src/main/java/org/codehaus/groovy/classgen/Verifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
@@ -28,6 +28,7 @@ import groovy.transform.NonSealed;
 import groovy.transform.Sealed;
 import groovy.transform.stc.POJO;
 import org.apache.groovy.ast.tools.ClassNodeUtils;
+import org.apache.groovy.ast.tools.MethodNodeUtils;
 import org.apache.groovy.util.BeanUtils;
 import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.ASTNode;
@@ -85,6 +86,7 @@ import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import static java.lang.reflect.Modifier.isFinal;
 import static java.lang.reflect.Modifier.isPrivate;
@@ -281,11 +283,18 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
         if (node.getInterfaces().length < 2) return;
 
         Map<String, MethodNode> defaultMethods = new HashMap<>(8);
+        Set<String> declared = node.getAllDeclaredMethods().stream()
+            .filter(m -> !m.isDefault())
+            .map(MethodNodeUtils::methodDescriptorWithoutReturnType)
+            .collect(Collectors.toSet());
         node.getAllInterfaces().stream()
                 .flatMap(i -> i.getAllDeclaredMethods().stream())
                 .filter(MethodNode::isDefault)
                 .forEach(m -> {
                     String signature = methodDescriptorWithoutReturnType(m);
+                    if (declared.contains(signature)) {
+                        return;
+                    }
                     MethodNode existing = defaultMethods.get(signature);
                     if (existing == null) {
                         defaultMethods.put(signature, m);
@@ -301,7 +310,7 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
                                 (node.isInterface() ? "interface" : "class") + 
 " " + node.getName()
                                         + " inherits unrelated defaults for " 
+ m.getTypeDescriptor()
                                         + " from types " + 
existingDeclaringClass.getName()
-                                        + " and " + 
currentDeclaringClass.getName(), sourceOf(m));
+                                        + " and " + 
currentDeclaringClass.getName(), node);
                     }
                 });
     }
diff --git a/src/test/groovy/bugs/Groovy10381.groovy 
b/src/test/groovy/bugs/Groovy10381.groovy
index a49867a722..568bb9b87c 100644
--- a/src/test/groovy/bugs/Groovy10381.groovy
+++ b/src/test/groovy/bugs/Groovy10381.groovy
@@ -22,9 +22,41 @@ import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit
 import org.junit.Test
 
+import static groovy.test.GroovyAssert.assertScript
 import static groovy.test.GroovyAssert.shouldFail
 
 final class Groovy10381 {
+    @Test
+    void testDuplicateDefaultMethodsFromGroovyClasses_implements0() {
+        assertScript '''
+            interface A {
+              default String m(String n) { n.toLowerCase() }
+            }
+
+            interface B {
+              default String m(String n) { n.toUpperCase() }
+            }
+
+            class C1 implements A, B {
+              @Override
+              String m(String n) { A.super.m(n) }
+            }
+            assert new C1().m('Hi') == 'hi'
+
+            class C2 implements A, B {
+              @Override
+              String m(String n) { B.super.m(n) }
+            }
+            assert new C2().m('Hi') == 'HI'
+
+            class C3 implements A, B {
+              @Override
+              String m(String n) { 'overridden' }
+            }
+            assert new C3().m('Hi') == 'overridden'
+        '''
+    }
+
     @Test
     void testDuplicateDefaultMethodsFromGroovyClasses_implements1() {
         def err = shouldFail '''

Reply via email to