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 bd20770a98 GROOVY-7909, GROOVY-11743: stub trait helper in 
`Traits#findHelpers`
bd20770a98 is described below

commit bd20770a9891684b4d455b31184dac522d03fff6
Author: Eric Milles <[email protected]>
AuthorDate: Sat Feb 21 14:21:45 2026 -0600

    GROOVY-7909, GROOVY-11743: stub trait helper in `Traits#findHelpers`
---
 .../transform/trait/SuperCallTraitTransformer.java | 33 +---------
 .../transform/trait/TraitASTTransformation.java    | 25 ++-----
 .../groovy/transform/trait/TraitComposer.java      |  8 ++-
 .../transform/trait/TraitReceiverTransformer.java  |  1 -
 .../codehaus/groovy/transform/trait/Traits.java    | 42 ++++++++----
 src/test/groovy/bugs/Groovy7909Bug.groovy          | 76 ----------------------
 .../traitx/TraitASTTransformationTest.groovy       | 30 +++++++++
 7 files changed, 75 insertions(+), 140 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java
 
b/src/main/java/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java
index 2c25f97b6b..8ebe3b4277 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java
@@ -21,7 +21,6 @@ package org.codehaus.groovy.transform.trait;
 import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.InnerClassNode;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
@@ -46,10 +45,6 @@ import static 
org.codehaus.groovy.ast.tools.GeneralUtils.getGetterName;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.getSetterName;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.thisPropX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
-import static org.objectweb.asm.Opcodes.ACC_ABSTRACT;
-import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
-import static org.objectweb.asm.Opcodes.ACC_STATIC;
-import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
 
 /**
  * This transformer is used to transform calls to 
<code>SomeTrait.super.foo()</code> into the appropriate trait call.
@@ -58,8 +53,6 @@ import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
  */
 class SuperCallTraitTransformer extends ClassCodeExpressionTransformer {
 
-    static final String UNRESOLVED_HELPER_CLASS = "UNRESOLVED_HELPER_CLASS";
-
     private final SourceUnit unit;
 
     SuperCallTraitTransformer(final SourceUnit unit) {
@@ -98,7 +91,7 @@ class SuperCallTraitTransformer extends 
ClassCodeExpressionTransformer {
             if (bin.getOperation().getType() == Types.ASSIGN && 
bin.getLeftExpression() instanceof PropertyExpression leftExpression) {
                 ClassNode traitType = 
getTraitSuperTarget(leftExpression.getObjectExpression());
                 if (traitType != null) {
-                    ClassNode helperType = getHelper(traitType);
+                    ClassNode helperType = 
Traits.findHelper(traitType).getPlainNodeReference();
                     // TraitType.super.foo = ... -> 
TraitType$Trait$Helper.setFoo(this, ...)
 
                     String setterName = 
getSetterName(leftExpression.getPropertyAsString());
@@ -134,7 +127,7 @@ class SuperCallTraitTransformer extends 
ClassCodeExpressionTransformer {
         if (exp.getNodeMetaData("assign.target") == null) {
             ClassNode traitType = 
getTraitSuperTarget(exp.getObjectExpression());
             if (traitType != null) {
-                ClassNode helperType = getHelper(traitType);
+                ClassNode helperType = 
Traits.findHelper(traitType).getPlainNodeReference();
                 // TraitType.super.foo -> TraitType$Trait$Helper.getFoo(this)
 
                 Function<MethodNode, MethodCallExpression> xform = 
(methodNode) -> {
@@ -173,7 +166,7 @@ class SuperCallTraitTransformer extends 
ClassCodeExpressionTransformer {
     private Expression transformMethodCallExpression(final 
MethodCallExpression exp) {
         ClassNode traitType = getTraitSuperTarget(exp.getObjectExpression());
         if (traitType != null) {
-            ClassNode helperType = getHelper(traitType);
+            ClassNode helperType = 
Traits.findHelper(traitType).getPlainNodeReference();
             // TraitType.super.foo() -> TraitType$Trait$Helper.foo(this)
 
             List<MethodNode> targets = 
helperType.getMethods(exp.getMethodAsString());
@@ -200,26 +193,6 @@ class SuperCallTraitTransformer extends 
ClassCodeExpressionTransformer {
         return super.transform(exp);
     }
 
-    private ClassNode getHelper(final ClassNode traitType) {
-        // GROOVY-7909: A helper class in the same compilation unit may not 
have
-        // been created when referenced; create a placeholder to be resolved 
later.
-        if (!traitType.redirect().getInnerClasses().hasNext()
-                && 
getSourceUnit().getAST().getClasses().contains(traitType.redirect())) {
-            ClassNode helperType = new InnerClassNode(
-                    traitType,
-                    Traits.helperClassName(traitType),
-                    ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_SYNTHETIC,
-                    ClassHelper.OBJECT_TYPE,
-                    ClassNode.EMPTY_ARRAY,
-                    null
-            ).getPlainNodeReference();
-            helperType.setRedirect(null);
-            traitType.redirect().setNodeMetaData(UNRESOLVED_HELPER_CLASS, 
helperType);
-            return helperType;
-        }
-        return Traits.findHelper(traitType).getPlainNodeReference();
-    }
-
     private ClassNode getTraitSuperTarget(final Expression exp) {
         if (exp instanceof PropertyExpression pexp) {
             Expression objExp = pexp.getObjectExpression();
diff --git 
a/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java 
b/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
index 70daf4acff..60829e083a 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
@@ -94,7 +94,6 @@ import static 
org.codehaus.groovy.ast.tools.GeneralUtils.throwS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.tryCatchS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
 import static 
org.codehaus.groovy.ast.tools.PropertyNodeUtils.adjustPropertyModifiersForMethod;
-import static 
org.codehaus.groovy.transform.trait.SuperCallTraitTransformer.UNRESOLVED_HELPER_CLASS;
 import static org.objectweb.asm.Opcodes.ACC_ABSTRACT;
 import static org.objectweb.asm.Opcodes.ACC_FINAL;
 import static org.objectweb.asm.Opcodes.ACC_INTERFACE;
@@ -139,7 +138,11 @@ public class TraitASTTransformation extends 
AbstractASTTransformation implements
             checkExtendsClause(cNode);
             replaceExtendsByImplements(cNode);
             generateMethodsWithDefaultArgs(cNode);
-            resolveHelperClassIfNecessary(createHelperClass(cNode));
+
+            cNode.setModifiers(ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE
+                    | (cNode.getOuterClass() != null ? ACC_STATIC : 0)); // 
GROOVY-11600
+
+            createHelperClasses(cNode);
         }
     }
 
@@ -182,10 +185,7 @@ public class TraitASTTransformation extends 
AbstractASTTransformation implements
         }.addDefaultParameterMethods(cNode);
     }
 
-    private ClassNode createHelperClass(final ClassNode cNode) {
-        cNode.setModifiers(ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE
-                | (cNode.getOuterClass() != null ? ACC_STATIC : 0)); // 
GROOVY-11600
-
+    private void createHelperClasses(final ClassNode cNode) {
         ClassNode helper = new InnerClassNode(
                 cNode,
                 Traits.helperClassName(cNode),
@@ -252,7 +252,7 @@ public class TraitASTTransformation extends 
AbstractASTTransformation implements
             if (!methodNode.isSynthetic() && (methodNode.isProtected() || 
methodNode.isPackageScope())) {
                 sourceUnit.addError(new SyntaxException("Cannot have 
protected/package-private method in a trait (" + cNode.getName() + "#" + 
methodNode.getTypeDescriptor() + ")",
                         methodNode.getLineNumber(), 
methodNode.getColumnNumber()));
-                return null;
+                return;
             }
             if (!methodNode.isAbstract()) {
                 MethodNode newMethod = processMethod(cNode, helper, 
methodNode, fieldHelper, fieldNames);
@@ -317,17 +317,6 @@ public class TraitASTTransformation extends 
AbstractASTTransformation implements
                 resolveScope(staticFieldHelper);
             }
         }
-
-        return helper;
-    }
-
-    private void resolveHelperClassIfNecessary(final ClassNode helperClass) {
-        for (ClassNode cn : sourceUnit.getAST().getClasses()) {
-            ClassNode unresolvedHelperClass = 
cn.getNodeMetaData(UNRESOLVED_HELPER_CLASS);
-            if (unresolvedHelperClass != null && 
unresolvedHelperClass.getName().equals(helperClass.getName())) {
-                unresolvedHelperClass.setRedirect(helperClass);
-            }
-        }
     }
 
     
//--------------------------------------------------------------------------
diff --git 
a/src/main/java/org/codehaus/groovy/transform/trait/TraitComposer.java 
b/src/main/java/org/codehaus/groovy/transform/trait/TraitComposer.java
index 713617e71d..f60866c4b0 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/TraitComposer.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/TraitComposer.java
@@ -18,7 +18,6 @@
  */
 package org.codehaus.groovy.transform.trait;
 
-import groovy.transform.CompileStatic;
 import org.apache.groovy.ast.tools.MethodNodeUtils;
 import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.AnnotationNode;
@@ -47,6 +46,7 @@ import org.codehaus.groovy.runtime.InvokerHelper;
 import org.codehaus.groovy.runtime.MetaClassHelper;
 import org.codehaus.groovy.syntax.SyntaxException;
 import org.codehaus.groovy.transform.ASTTransformationCollectorCodeVisitor;
+import org.codehaus.groovy.transform.sc.StaticCompilationVisitor;
 import org.codehaus.groovy.transform.sc.StaticCompileTransformation;
 import org.codehaus.groovy.transform.stc.StaticTypesMarker;
 import org.objectweb.asm.Opcodes;
@@ -85,7 +85,11 @@ import static 
org.codehaus.groovy.ast.tools.GeneralUtils.varX;
  */
 public abstract class TraitComposer {
 
-    public static final ClassNode COMPILESTATIC_CLASSNODE = 
ClassHelper.make(CompileStatic.class);
+    /**
+     * @deprecated
+     */
+    @Deprecated(since = "6.0.0")
+    public static final ClassNode COMPILESTATIC_CLASSNODE = 
StaticCompilationVisitor.COMPILESTATIC_CLASSNODE;
 
     /**
      * Given a class node, if this class node implements a trait, then generate
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 787cf26543..99baf45201 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
@@ -317,7 +317,6 @@ class TraitReceiverTransformer extends 
ClassCodeExpressionTransformer {
 
         for (ClassNode superTrait : traits) {
             ClassNode traitHelper = Traits.findHelper(superTrait);
-            if (traitHelper == null) continue; // GROOVY-11743: order issue
             for (MethodNode methodNode : 
traitHelper.getDeclaredMethods(methodName)) {
                 if (methodNode.isPublic() && methodNode.isStatic()
                         // exclude public method with body as it's included in 
trait interface
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 1d2dc7ec1b..40ed22b110 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
@@ -34,7 +34,6 @@ import org.codehaus.groovy.ast.expr.ListExpression;
 import org.codehaus.groovy.ast.tools.GenericsUtils;
 import org.codehaus.groovy.classgen.asm.BytecodeHelper;
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
-import org.objectweb.asm.Opcodes;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -46,12 +45,21 @@ import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 
+import static org.objectweb.asm.Opcodes.ACC_ABSTRACT;
+import static org.objectweb.asm.Opcodes.ACC_FINAL;
+import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.ACC_STATIC;
+import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
+import static org.objectweb.asm.Opcodes.ACC_TRANSIENT;
+
 /**
  * A collection of utility methods used to deal with traits.
  *
  * @since 2.3.0
  */
 public abstract class Traits {
+
     public static final ClassNode IMPLEMENTED_CLASSNODE = 
ClassHelper.make(Implemented.class);
     public static final ClassNode TRAITBRIDGE_CLASSNODE = 
ClassHelper.make(TraitBridge.class);
     public static final Class<Trait> TRAIT_CLASS = Trait.class;
@@ -79,7 +87,7 @@ public abstract class Traits {
 //            (a ? hex('80') : 0) + (b ? hex('10') : 0) + (c ? hex('8') : 0) + 
(d ? hex('2') : hex('1'))
 //    }.sort()
     static final List<Integer> FIELD_PREFIXES = Arrays.asList(1, 2, 9, 10, 17, 
18, 25, 26, 129, 130, 137, 138, 145, 146, 153, 154);
-    static final int FIELD_PREFIX_MASK = Opcodes.ACC_PRIVATE | 
Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | 
Opcodes.ACC_TRANSIENT;
+    static final int FIELD_PREFIX_MASK = ACC_PRIVATE | ACC_PUBLIC | ACC_STATIC 
| ACC_FINAL | ACC_TRANSIENT;
     static final String SUPER_TRAIT_METHOD_PREFIX = "trait$super$";
 
     static String fieldHelperClassName(final ClassNode traitNode) {
@@ -129,11 +137,10 @@ public abstract class Traits {
         ClassNode helperClassNode = null;
         ClassNode fieldHelperClassNode = null;
         ClassNode staticFieldHelperClassNode = null;
-        var innerClasses = trait.redirect().getInnerClasses();
-        if (innerClasses != null && innerClasses.hasNext() ) {
-            // trait declared in same unit
-            do {
-                ClassNode icn = innerClasses.next();
+
+        if (trait.isPrimaryClassNode()) { // GROOVY-11743
+            var ici = trait.redirect().getInnerClasses();
+            while (ici.hasNext()) { ClassNode icn = ici.next();
                 if (icn.getName().endsWith(Traits.TRAIT_HELPER)) {
                     helperClassNode = icn;
                 } else if (icn.getName().endsWith(Traits.FIELD_HELPER)) {
@@ -141,30 +148,39 @@ public abstract class Traits {
                 } else if (icn.getName().endsWith(Traits.STATIC_FIELD_HELPER)) 
{
                     staticFieldHelperClassNode = icn;
                 }
-            } while (innerClasses.hasNext());
-        } else if (!trait.isPrimaryClassNode()) { // GROOVY-11743
-            // precompiled trait
+            }
+        } else { // pre-compiled trait
             try {
-                String helperClassName = Traits.helperClassName(trait);
                 ClassLoader classLoader = 
trait.getTypeClass().getClassLoader();
-                helperClassNode = 
ClassHelper.make(Class.forName(helperClassName, false, classLoader));
+                helperClassNode = 
ClassHelper.make(classLoader.loadClass(Traits.helperClassName(trait)));
                 try {
                     fieldHelperClassNode = 
ClassHelper.make(classLoader.loadClass(Traits.fieldHelperClassName(trait)));
                     staticFieldHelperClassNode = 
ClassHelper.make(classLoader.loadClass(Traits.staticFieldHelperClassName(trait)));
                 } catch (ClassNotFoundException e) {
-                    // not a problem, the field helpers may be absent
+                    // field helper(s) may be absent
                 }
             } catch (ClassNotFoundException e) {
                 throw new GroovyBugError("Couldn't find trait helper classes 
on compile classpath!", e);
             }
         }
+
         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);
+            }};
         }
         if (fieldHelperClassNode != null) {
             fieldHelperClassNode = 
GenericsUtils.makeClassSafe0(fieldHelperClassNode, typeArguments);
         }
+
         return new TraitHelpersTuple(helperClassNode, fieldHelperClassNode, 
staticFieldHelperClassNode);
     }
 
diff --git a/src/test/groovy/bugs/Groovy7909Bug.groovy 
b/src/test/groovy/bugs/Groovy7909Bug.groovy
deleted file mode 100644
index 71571ef6b4..0000000000
--- a/src/test/groovy/bugs/Groovy7909Bug.groovy
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- *  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 bugs
-
-import gls.CompilableTestSupport
-
-class Groovy7909Bug extends CompilableTestSupport {
-    void testDynamicCompile(){
-        shouldCompile '''
-trait Three implements One, Two {
-    def postMake() {
-        One.super.postMake()
-        Two.super.postMake()
-        println "Three"
-    }
-}
-trait One {
-    def postMake() { println "One"}
-}
-trait Two {
-    def postMake() { println "Two"}
-}
-class Four implements Three {
-    def make() {
-        Three.super.postMake()
-        println "All done?"
-    }
-}
-Four f = new Four()
-f.make()
-    '''
-    }
-    void testStaticCompile(){
-        shouldCompile '''
[email protected]
-trait Three implements One, Two {
-    def postMake() {
-        One.super.postMake()
-        Two.super.postMake()
-        println "Three"
-    }
-}
-trait One {
-    def postMake() { println "One"}
-}
-trait Two {
-    def postMake() { println "Two"}
-}
-class Four implements Three {
-    def make() {
-        Three.super.postMake()
-        println "All done?"
-    }
-}
-Four f = new Four()
-f.make()
-    '''
-    }
-}
-
diff --git 
a/src/test/groovy/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
 
b/src/test/groovy/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
index aeb2353c4d..e3151c340d 100644
--- 
a/src/test/groovy/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
+++ 
b/src/test/groovy/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
@@ -1212,6 +1212,36 @@ final class TraitASTTransformationTest {
         '''
     }
 
+    // GROOVY-7909
+    @CompileModesTest
+    void testTraitMethodOverloadAndOverride2(String mode) {
+        assertScript shell, """
+            $mode
+            trait Three implements One, Two {
+                def postMake() {
+                    '3' + Two.super.postMake() + One.super.postMake()
+                }
+            }
+            $mode
+            trait One {
+                def postMake() { '1' }
+            }
+            $mode
+            trait Two {
+                def postMake() { '2' }
+            }
+            $mode
+            class Four implements Three {
+                def make() {
+                    '4' + Three.super.postMake()
+                }
+            }
+
+            String result = new Four().make()
+            assert result == '4321'
+        """
+    }
+
     // GROOVY-9255
     @Test
     void testTraitSuperPropertyGet() {

Reply via email to