You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2023/10/03 10:32:32 UTC
[groovy] 01/07: GROOVY-8299: implement interfaces with default methods (initial commit)
This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 44d286e67ed2087238c304c75463fd897f039a63
Author: Jochen Theodorou <bl...@gmx.org>
AuthorDate: Mon Sep 11 14:38:30 2023 +0200
GROOVY-8299: implement interfaces with default methods (initial commit)
---
.../apache/groovy/parser/antlr4/AstBuilder.java | 10 +---
.../groovy/classgen/ClassCompletionVerifier.java | 2 +-
.../groovy/lang/DefaultInterfaceMethodsTest.groovy | 54 ++++++++++++++++++++++
3 files changed, 57 insertions(+), 9 deletions(-)
diff --git a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
index b5ba5258b9..733584e79f 100644
--- a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
+++ b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
@@ -1313,9 +1313,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
} else if (isNonSealed) {
classNode.addAnnotation(makeAnnotationNode(NonSealed.class));
}
- if (isInterfaceWithDefaultMethods || asBoolean(ctx.TRAIT())) {
- classNode.addAnnotation(makeAnnotationNode(Trait.class));
- }
+
classNode.addAnnotations(modifierManager.getAnnotations());
if (isRecord && classNode.getAnnotations().stream().noneMatch(a ->
a.getClassNode().getName().equals(RECORD_TYPE_NAME))) {
@@ -1338,10 +1336,6 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
classNode.setInterfaces(this.visitTypeList(ctx.is));
this.initUsingGenerics(classNode);
- } else if (isInterfaceWithDefaultMethods) { // GROOVY-9259
- classNode.setInterfaces(this.visitTypeList(ctx.scs));
- this.initUsingGenerics(classNode);
-
} else if (isInterface) {
classNode.setModifiers(classNode.getModifiers() | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT);
classNode.setInterfaces(this.visitTypeList(ctx.scs));
@@ -1877,7 +1871,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
}
- modifiers |= !modifierManager.containsAny(STATIC) && (classNode.isInterface() || (isTrue(classNode, IS_INTERFACE_WITH_DEFAULT_METHODS) && !modifierManager.containsAny(DEFAULT))) ? Opcodes.ACC_ABSTRACT : 0;
+ modifiers |= !modifierManager.containsAny(STATIC) && classNode.isInterface() && !(isTrue(classNode, IS_INTERFACE_WITH_DEFAULT_METHODS) && modifierManager.containsAny(DEFAULT)) ? Opcodes.ACC_ABSTRACT : 0;
MethodNode methodNode = new MethodNode(methodName, modifiers, returnType, parameters, exceptions, code);
classNode.addMethod(methodNode);
diff --git a/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java b/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
index 8ff9c1ef00..43abd86f23 100644
--- a/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
@@ -310,7 +310,7 @@ public class ClassCompletionVerifier extends ClassCodeVisitorSupport {
}
private void checkAbstractDeclaration(final MethodNode methodNode) {
- if (!methodNode.isAbstract() || currentClass.isAbstract()) return;
+ if (!methodNode.isAbstract() || currentClass.isAbstract() || methodNode.isDefault()) return;
addError("Can't have an abstract method in a non-abstract class." +
" The " + getDescription(currentClass) + " must be declared abstract or the method '" +
diff --git a/src/test/groovy/lang/DefaultInterfaceMethodsTest.groovy b/src/test/groovy/lang/DefaultInterfaceMethodsTest.groovy
new file mode 100644
index 0000000000..bc833b8069
--- /dev/null
+++ b/src/test/groovy/lang/DefaultInterfaceMethodsTest.groovy
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.lang
+
+import groovy.test.GroovyTestCase
+
+/**
+ * Test for the BenchmarkInterceptor
+ */
+class DefaultInterfaceMethodsTest extends GroovyTestCase {
+
+ void testSimpleDeclarationAndCall() {
+ assertScript '''
+ public interface InterfaceWithDefault {
+ default String hello() {
+ return 'Hello'
+ }
+ }
+ class UseDefault implements InterfaceWithDefault {}
+ assert new UseDefault().hello() == 'Hello'
+ '''
+ }
+ void testSimpleDeclarationAndOverride() {
+ assertScript '''
+ public interface InterfaceWithDefault {
+ default String hello() {
+ return 'Hello'
+ }
+ }
+ class OverrideDefault implements InterfaceWithDefault {
+ public String hello() {
+ return 'Bon jour'
+ }
+ }
+ assert new OverrideDefault().hello() == 'Bon jour'
+ '''
+ }
+}