You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2026/04/08 18:56:22 UTC

(groovy) branch GROOVY-11907 created (now 19f38997a4)

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

emilles pushed a change to branch GROOVY-11907
in repository https://gitbox.apache.org/repos/asf/groovy.git


      at 19f38997a4 GROOVY-11907: trait field reference transform restructure

This branch includes the following new commits:

     new 19f38997a4 GROOVY-11907: trait field reference transform restructure

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(groovy) 01/01: GROOVY-11907: trait field reference transform restructure

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 19f38997a45ef17d77ecc5b188834e62948e07b1
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Apr 8 13:15:05 2026 -0500

    GROOVY-11907: trait field reference transform restructure
---
 .../transform/trait/TraitReceiverTransformer.java  | 93 +++++++++-------------
 1 file changed, 36 insertions(+), 57 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 99baf45201..f1f3ab30ff 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
@@ -51,9 +51,7 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.binX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.castX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.isInstanceOfX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.ternaryX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
 
 /**
@@ -71,18 +69,18 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
     private final VariableExpression weaved;
     private final SourceUnit unit;
     private final ClassNode traitClass;
-    private final ClassNode traitHelperClass;
+    private final ClassNode traitHelper;
     private final ClassNode fieldHelper;
     private final Collection<String> knownFields;
 
     private boolean inClosure;
 
     public TraitReceiverTransformer(final VariableExpression thisObject, final SourceUnit unit, final ClassNode traitClass,
-                                    final ClassNode traitHelperClass, final ClassNode fieldHelper, final Collection<String> knownFields) {
+                                    final ClassNode traitHelper, final ClassNode fieldHelper, final Collection<String> knownFields) {
         this.weaved = thisObject;
         this.unit = unit;
         this.traitClass = traitClass;
-        this.traitHelperClass = traitHelperClass;
+        this.traitHelper = traitHelper;
         this.fieldHelper = fieldHelper;
         this.knownFields = knownFields;
     }
@@ -94,9 +92,8 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
 
     @Override
     public Expression transform(final Expression exp) {
-        ClassNode weavedType = weaved.getOriginType();
         if (exp instanceof BinaryExpression) {
-            return transformBinaryExpression((BinaryExpression) exp, weavedType);
+            return transformBinaryExpression((BinaryExpression) exp);
         } else if (exp instanceof MethodCallExpression mce) {
             String obj = mce.getObjectExpression().getText();
             if ("super".equals(obj)) {
@@ -105,15 +102,13 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
                 return transformMethodCallOnThis(mce); // this.m(x) --> $self.m(x) or this.m($self, x)
             }
         } else if (exp instanceof FieldExpression) {
-            FieldNode fn = ((FieldExpression) exp).getField();
-            return transformFieldReference(exp, fn, fn.isStatic());
+            return transformFieldReference(exp, ((FieldExpression) exp).getField(), null);
         } else if (exp instanceof VariableExpression vexp) {
             Variable accessedVariable = vexp.getAccessedVariable();
             if (accessedVariable instanceof FieldNode || accessedVariable instanceof PropertyNode) {
                 if (knownFields.contains(vexp.getName())) {
-                    boolean isStatic = accessedVariable.isStatic();
                     return transformFieldReference(exp, accessedVariable instanceof FieldNode
-                            ? (FieldNode) accessedVariable : ((PropertyNode) accessedVariable).getField(), isStatic);
+                            ? (FieldNode) accessedVariable : ((PropertyNode) accessedVariable).getField(), null);
                 } else {
                     PropertyExpression propertyExpression = propX(varX(weaved), vexp.getName());
                     propertyExpression.getProperty().setSourcePosition(exp);
@@ -137,8 +132,8 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
             if (pexp.isImplicitThis() || "this".equals(obj)) {
                 String propName = pexp.getPropertyAsString();
                 if (knownFields.contains(propName)) {
-                    FieldNode fn = new FieldNode(propName, 0, ClassHelper.OBJECT_TYPE, weavedType, null);
-                    return transformFieldReference(exp, fn, false);
+                    FieldNode fn = new FieldNode(propName, 0, ClassHelper.OBJECT_TYPE, weaved.getOriginType(), null);
+                    return transformFieldReference(exp, fn, null);
                 }
             }
         } else if (exp instanceof ClosureExpression) {
@@ -164,7 +159,7 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
         return super.transform(exp);
     }
 
-    private Expression transformBinaryExpression(final BinaryExpression exp, final ClassNode weavedType) {
+    private Expression transformBinaryExpression(final BinaryExpression exp) {
         Expression leftExpression = exp.getLeftExpression();
         Expression rightExpression = exp.getRightExpression();
         Token operation = exp.getOperation();
@@ -179,29 +174,13 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
                 leftFieldName = ((PropertyExpression) leftExpression).getPropertyAsString();
             }
             if (leftFieldName != null) {
-                FieldNode staticField = tryGetFieldNode(weavedType, leftFieldName);
-                if (fieldHelper == null || staticField == null && !fieldHelper.hasPossibleMethod(Traits.helperSetterName(new FieldNode(leftFieldName, 0, ClassHelper.OBJECT_TYPE, weavedType, null)), rightExpression)) {
+                ClassNode weavedType = weaved.getOriginType();
+                FieldNode traitField = tryGetFieldNode(weavedType, leftFieldName);
+                FieldNode dummyField = new FieldNode(leftFieldName, 0, ClassHelper.OBJECT_TYPE, weavedType, null);
+                if (fieldHelper == null || traitField == null && !fieldHelper.hasPossibleMethod(Traits.helperSetterName(dummyField), rightExpression)) {
                     return binX(propX(varX(weaved), leftFieldName), operation, transform(rightExpression)); // GROOVY-7342, GROOVY-7456, GROOVY-9739, GROOVY-10143, et al.
                 }
-                FieldNode fn = weavedType.getDeclaredField(leftFieldName);
-                if (fn == null) {
-                    fn = new FieldNode(leftFieldName, 0, ClassHelper.OBJECT_TYPE, weavedType, null);
-                }
-                Expression receiver = createFieldHelperReceiver();
-                boolean isStatic = staticField != null && staticField.isStatic();
-                if (fn.isStatic()) { // DO NOT USE isStatic variable here!
-                    receiver = propX(receiver, "class");
-                }
-                String method = Traits.helperSetterName(fn);
-                MethodCallExpression mce = callX(
-                        receiver,
-                        method,
-                        super.transform(rightExpression)
-                );
-                mce.setImplicitThis(false);
-                mce.setSourcePosition(exp);
-                markDynamicCall(mce, staticField, isStatic);
-                return mce;
+                return transformFieldReference(exp, traitField != null ? traitField : dummyField, rightExpression);
             }
         }
 
@@ -214,23 +193,32 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
         return ret;
     }
 
-    private Expression transformFieldReference(final Expression exp, final FieldNode fn, final boolean isStatic) {
-        Expression receiver = createFieldHelperReceiver();
-        if (isStatic) {
-            receiver = asClass(receiver);
+    private Expression transformFieldReference(final Expression exp, final FieldNode fn, final Expression value) {
+        Expression receiver;
+        if (ClassHelper.isClassType(weaved.getOriginType())) {
+            receiver = varX(weaved); // $static$self
+        } else if (fn.isStatic()) {
+            var call = callX(varX(weaved), "getClass"); // $self.getClass()
+            call.setImplicitThis(false);
+            call.setMethodTarget(ClassHelper.OBJECT_TYPE.getGetterMethod("getClass", false));
+            receiver = call;
+        } else {
+            receiver = castX(fieldHelper, varX(weaved)); // (<trait class>$Trait$FieldHelper) $self
         }
 
-        MethodCallExpression mce = callX(receiver, Traits.helperGetterName(fn));
+        MethodCallExpression mce;
+        if (value == null) {
+            mce = callX(receiver, Traits.helperGetterName(fn));
+        } else {
+            mce = callX(receiver, Traits.helperSetterName(fn), transform(value));
+        }
         mce.setImplicitThis(false);
         mce.setSourcePosition(exp);
-        markDynamicCall(mce, fn, isStatic);
-        return mce;
-    }
 
-    private static void markDynamicCall(final MethodCallExpression mce, final FieldNode fn, final boolean isStatic) {
-        if (isStatic) {
-            mce.putNodeMetaData(TraitASTTransformation.DO_DYNAMIC, fn.getOriginType());
-        }
+        // GROOVY-7255: static fields are available via the implementing class, which is not checkable
+        if (fn.isStatic()) mce.putNodeMetaData(TraitASTTransformation.DO_DYNAMIC, fn.getOriginType());
+
+        return mce;
     }
 
     private static FieldNode tryGetFieldNode(final ClassNode weavedType, final String fieldName) {
@@ -287,7 +275,7 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
             if (methodNode != null) {
                 // this.m(x) --> (this or T$Trait$Helper).m($self or $static$self or (Class)$self.getClass(), x)
                 Expression selfClassOrObject = methodNode.isStatic() && !ClassHelper.isClassType(weaved.getOriginType()) ? castX(ClassHelper.CLASS_Type.getPlainNodeReference(), callX(weaved, "getClass")) : weaved;
-                MethodCallExpression newCall = callX(!inClosure ? thisExpr : classX(traitHelperClass), method, createArgumentList(selfClassOrObject, arguments));
+                MethodCallExpression newCall = callX(!inClosure ? thisExpr : classX(traitHelper), method, createArgumentList(selfClassOrObject, arguments));
                 newCall.setGenericsTypes(call.getGenericsTypes());
                 newCall.setSpreadSafe(call.isSpreadSafe());
                 newCall.setSourcePosition(call);
@@ -341,13 +329,4 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
         }
         return newArgs;
     }
-
-    private Expression createFieldHelperReceiver() {
-        return ClassHelper.isClassType(weaved.getOriginType()) ? weaved : castX(fieldHelper, weaved);
-    }
-
-    private Expression asClass(final Expression e) {
-        ClassNode rawClass = ClassHelper.CLASS_Type.getPlainNodeReference();
-        return ternaryX(isInstanceOfX(e, rawClass), e, callX(e, "getClass"));
-    }
 }