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