This is an automated email from the ASF dual-hosted git repository.
paulk-asert 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 9d01e177d8 GROOVY-12117: replace super trait search with more complete
helper stub
9d01e177d8 is described below
commit 9d01e177d88d57516ce821531624eccd359af8b4
Author: Eric Milles <[email protected]>
AuthorDate: Wed Jul 8 10:42:17 2026 -0500
GROOVY-12117: replace super trait search with more complete helper stub
---
.../transform/trait/TraitReceiverTransformer.java | 13 -----
.../codehaus/groovy/transform/trait/Traits.java | 64 +++++++++++++++++++---
2 files changed, 55 insertions(+), 22 deletions(-)
diff --git
a/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
b/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
index 1176bb53d5..9e7a10bc3e 100644
---
a/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
+++
b/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
@@ -419,19 +419,6 @@ class TraitReceiverTransformer extends
ClassCodeExpressionTransformer {
return methodNode;
}
}
- // GROOVY-12117: when a co-compiled super trait has not been
transformed
- // yet, its helper is still an empty GROOVY-7909 stub, so the
lowered
- // static above is not found. The original static is still
declared on
- // the trait node at this point, so resolve it there. This keeps
the
- // rewrite independent of the order in which sibling traits are
- // transformed (GEP-22 P1' dispatch consistency); the helper
resolves
- // identically once every trait is lowered, so this only matters
for
- // the not-yet-lowered super trait.
- for (MethodNode methodNode :
superTrait.getDeclaredMethods(methodName)) {
- if (methodNode.isPublic() && methodNode.isStatic()) {
- return methodNode;
- }
- }
}
return null;
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 529b7d9dfd..9536b3c10c 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
@@ -28,6 +28,7 @@ import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.GenericsType;
import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.ListExpression;
@@ -319,15 +320,10 @@ public abstract class Traits {
GenericsType[] typeArguments = trait.getGenericsTypes();
if (helperClassNode != null) {
helperClassNode = GenericsUtils.makeClassSafe0(helperClassNode,
typeArguments);
- } else { // GROOVY-7909: stub helper
- helperClassNode = new ClassNode(
- Traits.helperClassName(trait),
- ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_SYNTHETIC,
- ClassHelper.OBJECT_TYPE
- ){{
- isPrimaryNode = false;
- setGenericsTypes(typeArguments);
- }};
+ } else {
+ // GROOVY-7909, GROOVY-12117: stub the helper
+ helperClassNode = new HelperClassStub(trait);
+ helperClassNode.setGenericsTypes(typeArguments);
}
if (fieldHelperClassNode != null) {
fieldHelperClassNode =
GenericsUtils.makeClassSafe0(fieldHelperClassNode, typeArguments);
@@ -336,6 +332,56 @@ public abstract class Traits {
return new TraitHelpersTuple(helperClassNode, fieldHelperClassNode,
staticFieldHelperClassNode);
}
+ /**
+ * GROOVY-7909, GROOVY-12117: When a co-compiled super trait hasn't yet
been
+ * transformed, its helper is stubbed so the lowered static methods can be
+ * found. This keeps the rewrite independent of the order in which sibling
+ * traits are transformed (GEP-22 dispatch consistency); the helper
resolves
+ * identically once every trait is lowered, so this only matters for the
+ * not-yet-lowered super trait.
+ */
+ private static class HelperClassStub extends ClassNode {
+
+ private final ClassNode trait;
+
+ @Override
+ public ClassNode getOuterClass() {
+ return trait;
+ }
+
+ HelperClassStub(final ClassNode trait) {
+ super(Traits.helperClassName(trait), ACC_PUBLIC | ACC_STATIC |
ACC_ABSTRACT | ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE);
+ this.isPrimaryNode = false;
+ this.trait = trait;
+
+ for (MethodNode m : trait.getMethods()) {
+ if ((m.isPublic() || m.isPrivate()) && !m.isAbstract() &&
!m.isStaticConstructor()) {
+ addMethod(helperMethod(m));
+ }
+ }
+ }
+
+ private MethodNode helperMethod(final MethodNode method) {
+ int mods = (method.isPublic() ? ACC_PUBLIC : ACC_PRIVATE) |
ACC_STATIC;
+ var self = !method.isStatic() ? trait :
GenericsUtils.makeClassSafe0(ClassHelper.CLASS_Type, new GenericsType(trait));
+
+ var methodParams = method.getParameters();
+ var helperParams = new Parameter[methodParams.length + 1];
+ helperParams[0] = new Parameter(self, "traitImplementer");
+ System.arraycopy(methodParams, 0, helperParams, 1,
methodParams.length);
+
+ var m = new MethodNode(method.getName(), mods,
method.getReturnType(), helperParams, method.getExceptions(), null);
+ for (AnnotationNode annotation : method.getAnnotations()) {
+ if
(!annotation.getClassNode().equals(ClassHelper.OVERRIDE_TYPE)) {
+ m.addAnnotation(annotation);
+ }
+ }
+ m.addAnnotation(Traits.IMPLEMENTED_CLASSNODE);
+ m.setGenericsTypes(method.getGenericsTypes());
+ return m;
+ }
+ }
+
/**
* Returns true if the specified class node is a trait.
*