This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch GROOVY-12117
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 5f40130b5d1c3b81fa143671f5ab8d7d9e204112
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.
      *

Reply via email to