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:36 UTC
[groovy] 05/07: GROOVY-8299: implement call to interface method using super with static compilation
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 cb33dc6c8d54b89f738baf95a48121273e269bad
Author: Jochen Theodorou <bl...@gmx.org>
AuthorDate: Mon Sep 25 21:38:01 2023 +0200
GROOVY-8299: implement call to interface method using super with static compilation
---
.../groovy/classgen/asm/InvocationWriter.java | 23 ++++++++++++++++++++--
.../classgen/asm/sc/StaticInvocationWriter.java | 10 +++++++++-
.../transform/stc/StaticTypeCheckingVisitor.java | 12 +++++++++++
3 files changed, 42 insertions(+), 3 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
index ce89bc4092..ed66155ed7 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
@@ -157,7 +157,10 @@ public class InvocationWriter {
if (!target.isStatic()) {
if (receiver != null) {
Expression objectExpression = receiver;
- if (implicitThis
+ if (!implicitThis && callSuperDefault(enclosingClass, target, receiver)) {
+ compileStack.pushImplicitThis(true);
+ objectExpression = new VariableExpression("this", declaringClass);
+ } else if (implicitThis
&& enclosingClass.getOuterClass() != null
&& !enclosingClass.isDerivedFrom(declaringClass)
&& !enclosingClass.implementsInterface(declaringClass)) {
@@ -181,7 +184,7 @@ public class InvocationWriter {
int opcode;
if (target.isStatic()) {
opcode = INVOKESTATIC;
- } else if (isSuperExpression(receiver)) {
+ } else if (isSuperExpression(receiver) || isClassWithSuper(receiver)) {
opcode = INVOKESPECIAL;
} else if (declaringClass.isInterface()) {
opcode = INVOKEINTERFACE;
@@ -227,6 +230,22 @@ public class InvocationWriter {
return true;
}
+ private boolean callSuperDefault(ClassNode enclosingClass, MethodNode target, Expression receiver) {
+ ClassNode declaringClass = target.getDeclaringClass();
+ if (declaringClass.isInterface() && enclosingClass.implementsInterface(declaringClass)) {
+ return isClassWithSuper(receiver);
+ }
+ return false;
+ }
+
+ private boolean isClassWithSuper(Expression exp) {
+ if (exp instanceof PropertyExpression) {
+ PropertyExpression pexp = (PropertyExpression) exp;
+ return pexp.getObjectExpression() instanceof ClassExpression && "super".equals(pexp.getPropertyAsString());
+ }
+ return false;
+ }
+
/**
* Supplements {@link org.apache.groovy.ast.tools.ExpressionUtils#isThisExpression isThisExpression}
* with the ability to see into {@code CheckcastReceiverExpression}.
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
index 4631287a4d..0aa0e28738 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
@@ -381,7 +381,7 @@ public class StaticInvocationWriter extends InvocationWriter {
}
}
}
- if (receiver != null && !isSuperExpression(receiver)) {
+ if (receiver != null && !isSuperExpression(receiver) && !isClassWithSuper(receiver)) {
// in order to avoid calls to castToType, which is the dynamic behaviour, make sure that we call CHECKCAST instead then replace the top operand type
if (currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER) == null) fixedReceiver = new CheckcastReceiverExpression(fixedReceiver, target);
return super.writeDirectMethodCall(target, fixedImplicitThis, fixedReceiver, args);
@@ -389,6 +389,14 @@ public class StaticInvocationWriter extends InvocationWriter {
return super.writeDirectMethodCall(target, implicitThis, receiver, args);
}
+ private boolean isClassWithSuper(Expression receiver) {
+ if (receiver instanceof PropertyExpression) {
+ PropertyExpression pexp = (PropertyExpression) receiver;
+ return pexp.getObjectExpression() instanceof ClassExpression && "super".equals(pexp.getPropertyAsString());
+ }
+ return false;
+ }
+
private boolean tryPrivateMethod(final MethodNode target, final boolean implicitThis, final Expression receiver, final TupleExpression args, final ClassNode classNode) {
ClassNode declaringClass = target.getDeclaringClass();
if ((isPrivateBridgeMethodsCallAllowed(declaringClass, classNode) || isPrivateBridgeMethodsCallAllowed(classNode, declaringClass))
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 0afd3f2765..f702ae6a15 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1533,6 +1533,18 @@ out: if ((samParameterTypes.length == 1 && isOrImplements(samParameterTypes[0
}
}
+ if (staticOnlyAccess && "super".equals(propertyName)) {
+ // handle "I.super" for default interface logic
+ ClassNode enclosingType = typeCheckingContext.getEnclosingClassNode();
+ ClassNode accessor = objectExpressionType.getGenericsTypes()[0].getType();
+ if (accessor.isInterface() && enclosingType.implementsInterface(accessor)) {
+ storeType(pexp, accessor);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
boolean foundGetterOrSetter = false;
String capName = capitalize(propertyName);
Set<ClassNode> handledNodes = new HashSet<>();