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 c42a509f64 GROOVY-10687: SC: replace access bridge methods with direct 
field access
c42a509f64 is described below

commit c42a509f64616f8ca8c97d37e79d713dfb99a8ac
Author: Eric Milles <eric.mil...@thomsonreuters.com>
AuthorDate: Mon Sep 23 14:17:35 2024 -0500

    GROOVY-10687: SC: replace access bridge methods with direct field access
---
 .../groovy/classgen/AsmClassGenerator.java         |  40 +++++++-
 .../codehaus/groovy/classgen/GeneratorContext.java |   5 +
 ...icTypesBinaryExpressionMultiTypeDispatcher.java |  62 ++++--------
 .../classgen/asm/sc/StaticTypesCallSiteWriter.java |  20 ++--
 .../sc/StaticCompilationMetadataKeys.java          |  29 ++++--
 .../transform/sc/StaticCompilationVisitor.java     |   1 +
 .../PropertyExpressionTransformer.java             |  27 ++++++
 .../VariableExpressionTransformer.java             |   8 +-
 .../transform/stc/StaticTypeCheckingVisitor.java   |   3 +-
 .../groovy/classgen/asm/NestHostTests.groovy       |  15 +++
 .../sc/FieldsAndPropertiesStaticCompileTest.groovy | 108 +++++++++++----------
 11 files changed, 200 insertions(+), 118 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java 
b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
index da58703feb..d4410759c9 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -27,6 +27,7 @@ import org.codehaus.groovy.ast.AnnotatedNode;
 import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
 import org.codehaus.groovy.ast.ConstructorNode;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.GenericsType;
@@ -138,6 +139,7 @@ import static 
org.apache.groovy.ast.tools.ClassNodeUtils.getNestHost;
 import static org.apache.groovy.ast.tools.ExpressionUtils.isNullConstant;
 import static org.apache.groovy.ast.tools.ExpressionUtils.isSuperExpression;
 import static org.codehaus.groovy.ast.ClassHelper.isClassType;
+import static org.codehaus.groovy.ast.ClassHelper.isFunctionalInterface;
 import static org.codehaus.groovy.ast.ClassHelper.isObjectType;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveBoolean;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveByte;
@@ -381,6 +383,7 @@ public class AsmClassGenerator extends ClassGenerator {
             // GROOVY-10687
             if (classNode.getOuterClass() == null && 
classNode.getInnerClasses().hasNext()) {
                 makeNestmateEntries(classNode);
+                moreNestmateEntries(classNode);
             }
             // GROOVY-4649, GROOVY-6750, GROOVY-6808
             for (Iterator<InnerClassNode> it = classNode.getInnerClasses(); 
it.hasNext(); ) {
@@ -460,6 +463,38 @@ public class AsmClassGenerator extends ClassGenerator {
         }
     }
 
+    private void moreNestmateEntries(final ClassNode classNode) {
+        // edge case: nest host closures-within-closures
+        int[] n = {this.context.getClosureClassIndex()};
+        for (ClassNode innerClass : getInnerClasses()) {
+            if (innerClass instanceof InterfaceHelperClassNode) continue;
+            var doCall = innerClass.getMethods().get(0);
+            doCall.getCode().visit(new CodeVisitorSupport() {
+                private String name = 
BytecodeHelper.getClassInternalName(innerClass);
+                private void visitNested(final String kind, final 
ClosureExpression expr) {
+                    String save = name;
+                    name += "$_" + kind + n[0]++;
+                    classVisitor.visitNestMember(name);
+                    super.visitClosureExpression(expr);
+                    name = save;
+                }
+                @Override
+                public  void visitClosureExpression(final ClosureExpression 
expression) {
+                    visitNested("closure", expression);
+                }
+                @Override
+                public  void visitLambdaExpression(final LambdaExpression 
expression) {
+                    if 
(Boolean.TRUE.equals(innerClass.getNodeMetaData(org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys.STATIC_COMPILE_NODE))
+                            && 
isFunctionalInterface(expression.getNodeMetaData(org.codehaus.groovy.transform.stc.StaticTypesMarker.PARAMETER_TYPE)))
 {
+                        visitNested("lambda", expression);
+                    } else {
+                        super.visitLambdaExpression(expression);
+                    }
+                }
+            });
+        }
+    }
+
     /*
      * See 
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.6-300-D.2-5
      * for what flags are allowed depending on the fact we are writing the 
inner class table
@@ -1063,8 +1098,9 @@ public class AsmClassGenerator extends ClassGenerator {
         // any member is accessible from the declaring class
         if (accessingClass.equals(declaringClass)) return true;
 
-        // a private member isn't accessible beyond the declaring class
-        if (Modifier.isPrivate(modifiers)) return false;
+        // a private member is accessible from any nestmates
+        if (Modifier.isPrivate(modifiers))
+            return 
getNestHost(accessingClass).equals(getNestHost(declaringClass));
 
         // a protected member is accessible from any subclass of the declaring 
class
         if (Modifier.isProtected(modifiers) && 
accessingClass.isDerivedFrom(declaringClass)) return true;
diff --git a/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java 
b/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java
index fcd115a280..0a0b78b270 100644
--- a/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java
+++ b/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java
@@ -43,6 +43,11 @@ public class GeneratorContext {
         this.innerClassIdx = innerClassOffset;
     }
 
+    // for ACG nestmate determination !
+           int getClosureClassIndex() {
+        return closureClassIdx;
+    }
+
     public int getNextInnerClassIdx() {
         return innerClassIdx++;
     }
diff --git 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
index 7e0284cd01..45c89d41df 100644
--- 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
+++ 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
@@ -48,23 +48,20 @@ import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import static org.apache.groovy.ast.tools.ExpressionUtils.isThisExpression;
-import static org.codehaus.groovy.ast.ClassHelper.CLOSURE_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.isNumberType;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveChar;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveDouble;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveFloat;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveLong;
+import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.binX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.callThisX;
 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.ctorX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.declX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.getSetterName;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.isOrImplements;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.nullX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
 import static 
org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys.PRIVATE_FIELDS_MUTATORS;
@@ -96,8 +93,6 @@ import static org.objectweb.asm.Opcodes.LSUB;
  */
 public class StaticTypesBinaryExpressionMultiTypeDispatcher extends 
BinaryExpressionMultiTypeDispatcher {
 
-    private static final MethodNode CLOSURE_GETTHISOBJECT_METHOD = 
CLOSURE_TYPE.getMethod("getThisObject", Parameter.EMPTY_ARRAY);
-
     private final AtomicInteger labelCounter = new AtomicInteger();
 
     public StaticTypesBinaryExpressionMultiTypeDispatcher(final 
WriterController wc) {
@@ -116,7 +111,7 @@ public class StaticTypesBinaryExpressionMultiTypeDispatcher 
extends BinaryExpres
         }
 
         ClassNode top = controller.getOperandStack().getTopOperand();
-        if (ClassHelper.isPrimitiveType(top) && (ClassHelper.isNumberType(top) 
|| isPrimitiveChar(top))) {
+        if (isPrimitiveType(top) && (isNumberType(top) || 
isPrimitiveChar(top))) {
             MethodVisitor mv = controller.getMethodVisitor();
             visitInsnByType(top, mv, ICONST_1, LCONST_1, FCONST_1, DCONST_1);
             if ("next".equals(method)) {
@@ -303,39 +298,24 @@ public class 
StaticTypesBinaryExpressionMultiTypeDispatcher extends BinaryExpres
     }
 
     private boolean makeSetPrivateFieldWithBridgeMethod(final Expression 
receiver, final ClassNode receiverType, final String fieldName, final 
Expression arguments, final boolean safe, final boolean spreadSafe, final 
boolean implicitThis) {
-        FieldNode field = receiverType.getField(fieldName);
-        ClassNode outerClass = receiverType.getOuterClass();
-        if (field == null && implicitThis && outerClass != null && 
!receiverType.isStaticClass()) {
-            Expression pexp;
-            if (controller.isInGeneratedFunction()) {
-                MethodCallExpression mce = callThisX("getThisObject");
-                mce.setImplicitThis(true);
-                mce.setMethodTarget(CLOSURE_GETTHISOBJECT_METHOD);
-                mce.putNodeMetaData(INFERRED_TYPE, controller.getThisType());
-                pexp = castX(controller.getThisType(), mce);
-            } else {
-                pexp = propX(classX(outerClass), "this");
-                ((PropertyExpression) pexp).setImplicitThis(true);
-            }
-            pexp.putNodeMetaData(INFERRED_TYPE, outerClass);
-            pexp.setSourcePosition(receiver);
-            return makeSetPrivateFieldWithBridgeMethod(pexp, outerClass, 
fieldName, arguments, safe, spreadSafe, true);
-        }
-        ClassNode classNode = controller.getClassNode();
-        if (field != null && field.isPrivate() && 
!receiverType.equals(classNode)
-                && 
(StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(receiverType, 
classNode)
-                    || 
StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(classNode, 
receiverType))) {
-            Map<String, MethodNode> mutators = 
receiverType.redirect().getNodeMetaData(PRIVATE_FIELDS_MUTATORS);
-            if (mutators != null) {
-                MethodNode methodNode = mutators.get(fieldName);
-                if (methodNode != null) {
-                    MethodCallExpression call = callX(receiver, 
methodNode.getName(), args(field.isStatic() ? nullX() : receiver, arguments));
-                    call.setImplicitThis(implicitThis);
-                    call.setMethodTarget(methodNode);
-                    call.setSafe(safe);
-                    call.setSpreadSafe(spreadSafe);
-                    call.visit(controller.getAcg());
-                    return true;
+        FieldNode fieldNode = receiverType.getField(fieldName);
+        if (fieldNode != null) {
+            ClassNode classNode = controller.getClassNode();
+            if (fieldNode.isPrivate() && !receiverType.equals(classNode)
+                    && 
(StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(receiverType, 
classNode)
+                        || 
StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(classNode, 
receiverType))) {
+                Map<String, MethodNode> mutators = 
receiverType.redirect().getNodeMetaData(PRIVATE_FIELDS_MUTATORS);
+                if (mutators != null) {
+                    MethodNode methodNode = mutators.get(fieldName);
+                    if (methodNode != null) {
+                        MethodCallExpression call = callX(receiver, 
methodNode.getName(), args(fieldNode.isStatic() ? nullX() : receiver, 
arguments));
+                        call.setImplicitThis(implicitThis);
+                        call.setMethodTarget(methodNode);
+                        call.setSafe(safe);
+                        call.setSpreadSafe(spreadSafe);
+                        call.visit(controller.getAcg());
+                        return true;
+                    }
                 }
             }
         }
diff --git 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
index 985e640108..1bb0415a61 100644
--- 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
+++ 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
@@ -827,28 +827,30 @@ public class StaticTypesCallSiteWriter extends 
CallSiteWriter {
         return receiverType;
     }
 
-    // this is just a simple set field handling static and non-static, but not 
Closure and inner classes
     private boolean setField(final PropertyExpression expression, final 
Expression objectExpression, final ClassNode receiverType, final String name) {
-        if (expression.isSafe()) return false;
+        if (expression.isSafe() || expression.isSpreadSafe()) return false;
+
         FieldNode fn = 
AsmClassGenerator.getDeclaredFieldOfCurrentClassOrAccessibleFieldOfSuper(controller.getClassNode(),
 receiverType, name, false);
         if (fn == null) return false;
-        OperandStack stack = controller.getOperandStack();
-        stack.doGroovyCast(fn.getType());
+
+        OperandStack os = controller.getOperandStack();
+        os.doGroovyCast(fn.getType());
 
         MethodVisitor mv = controller.getMethodVisitor();
         if (!fn.isStatic()) {
             controller.getCompileStack().pushLHS(false);
             objectExpression.visit(controller.getAcg());
             controller.getCompileStack().popLHS();
-            if (!receiverType.equals(stack.getTopOperand())) {
+            if (!receiverType.equals(os.getTopOperand())) {
                 BytecodeHelper.doCast(mv, receiverType);
-                stack.replace(receiverType);
+                os.replace(receiverType);
             }
-            stack.swap();
+            os.swap(); // stack: operand, receiver, ...
             mv.visitFieldInsn(PUTFIELD, 
BytecodeHelper.getClassInternalName(fn.getOwner()), name, 
BytecodeHelper.getTypeDescription(fn.getType()));
-            stack.remove(1);
-        } else {
+            os.remove(2);
+        } else { // stack: operand, ...
             mv.visitFieldInsn(PUTSTATIC, 
BytecodeHelper.getClassInternalName(receiverType), name, 
BytecodeHelper.getTypeDescription(fn.getType()));
+            os.remove(1);
         }
 
         return true;
diff --git 
a/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationMetadataKeys.java
 
b/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationMetadataKeys.java
index 7183bb3c04..8c32ebad55 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationMetadataKeys.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationMetadataKeys.java
@@ -22,13 +22,24 @@ package org.codehaus.groovy.transform.sc;
  * Static compilation AST node metadata keys.
  */
 public enum StaticCompilationMetadataKeys {
-    STATIC_COMPILE_NODE, // used to mark a section of code as to be statically 
compiled
-    BINARY_EXP_TARGET, // use to tell which method should be used in a binary 
expression
-    PRIVATE_BRIDGE_METHODS, // private bridge methods are methods used by an 
outer class to access an inner class method
-    PRIVATE_FIELDS_ACCESSORS, // private fields accessors are methods used by 
an inner class to access an outer class field
-    PRIVATE_FIELDS_MUTATORS, // private fields mutators are methods used by an 
inner class to set an outer class field
-    DYNAMIC_OUTER_NODE_CALLBACK, // callback for dynamic classes that contain 
statically compiled inner classes or methods
-    PROPERTY_OWNER, // the type of the class which owns the property
-    COMPONENT_TYPE, // for list.property expressions, we need the inferred 
component type
-    RECEIVER_OF_DYNAMIC_PROPERTY // if a receiver is the receiver of a dynamic 
property (for mixed mode compilation)
+    /** Marks a section of code for static compilation. */
+    STATIC_COMPILE_NODE,
+    /** Tells which method should be used in a binary expression. */
+    BINARY_EXP_TARGET,
+    /** Private bridge methods are methods used to access a nestmate's method. 
*/
+    PRIVATE_BRIDGE_METHODS,
+    /** Private fields accessors are methods used to read a nestmate's field. 
*/
+    @Deprecated(since = "5.0.0")
+    PRIVATE_FIELDS_ACCESSORS,
+    /** Private fields mutators are methods used to write a nestmate's field. 
*/
+    @Deprecated(since = "5.0.0")
+    PRIVATE_FIELDS_MUTATORS,
+    /** Callback for dynamic classes that contain statically compiled inner 
classes or methods. */
+    DYNAMIC_OUTER_NODE_CALLBACK,
+    /** The type of the class which owns the property. */
+    PROPERTY_OWNER,
+    /** For list.property expressions, we need the inferred component type. */
+    COMPONENT_TYPE,
+    /** If a receiver is the receiver of a dynamic property (for mixed-mode 
compilation). */
+    RECEIVER_OF_DYNAMIC_PROPERTY
 }
diff --git 
a/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java 
b/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
index 758731783b..462e49c3d0 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
@@ -429,6 +429,7 @@ public class StaticCompilationVisitor extends 
StaticTypeCheckingVisitor {
     /**
      * Adds special accessors and mutators for private fields so that inner 
classes can get/set them.
      */
+    @Deprecated(since = "5.0.0")
     private static void addPrivateFieldsAccessors(final ClassNode node) {
         Map<String, MethodNode> privateFieldAccessors = 
node.getNodeMetaData(PRIVATE_FIELDS_ACCESSORS);
         Map<String, MethodNode> privateFieldMutators = 
node.getNodeMetaData(PRIVATE_FIELDS_MUTATORS);
diff --git 
a/src/main/java/org/codehaus/groovy/transform/sc/transformers/PropertyExpressionTransformer.java
 
b/src/main/java/org/codehaus/groovy/transform/sc/transformers/PropertyExpressionTransformer.java
index fc54a954f9..f4811f5779 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/sc/transformers/PropertyExpressionTransformer.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/sc/transformers/PropertyExpressionTransformer.java
@@ -18,13 +18,18 @@
  */
 package org.codehaus.groovy.transform.sc.transformers;
 
+import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.expr.AttributeExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
 import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
 import org.codehaus.groovy.transform.stc.StaticTypesMarker;
 
+import static org.apache.groovy.ast.tools.ExpressionUtils.isThisExpression;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
 
 class PropertyExpressionTransformer {
 
@@ -48,6 +53,28 @@ class PropertyExpressionTransformer {
             return mce;
         }
 
+        FieldNode field = 
pe.getNodeMetaData(StaticTypesMarker.PV_FIELDS_ACCESS);
+        if (field == null) {
+            field = pe.getNodeMetaData(StaticTypesMarker.PV_FIELDS_MUTATION);
+        }
+        if (field != null) {
+            AttributeExpression ae;
+            if (field.isStatic()) {
+                ae = new 
AttributeExpression(classX(field.getDeclaringClass()), pe.getProperty());
+            } else if (!isThisExpression(pe.getObjectExpression())) {
+                ae = new 
AttributeExpression(scTransformer.transform(pe.getObjectExpression()), 
pe.getProperty(), pe.isSafe());
+            } else {
+                ae = new AttributeExpression(new 
PropertyExpression(classX(field.getDeclaringClass()), "this"), 
pe.getProperty(), pe.isSafe());
+
+                
ae.getObjectExpression().putNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER,
 field.getDeclaringClass());
+                
ae.getObjectExpression().putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, 
field.getDeclaringClass());
+            }
+            ae.setSpreadSafe(pe.isSpreadSafe());
+            ae.setSourcePosition(pe);
+            ae.copyNodeMetaData(pe);
+            return ae;
+        }
+
         return scTransformer.superTransform(pe);
     }
 }
diff --git 
a/src/main/java/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
 
b/src/main/java/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
index f15915513b..c2d3d44fa7 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
@@ -28,10 +28,10 @@ import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
 import org.codehaus.groovy.transform.stc.StaticTypesMarker;
 
+import static org.codehaus.groovy.ast.tools.GeneralUtils.attrX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callThisX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.thisPropX;
 
 class VariableExpressionTransformer {
 
@@ -86,9 +86,9 @@ class VariableExpressionTransformer {
             return null;
         }
 
-        // access to a private field from a section of code that normally 
doesn't have access to it, like a closure block or an inner class
-        PropertyExpression pe = !field.isStatic() ? thisPropX(true, 
ve.getName()) : propX(classX(field.getDeclaringClass()), ve.getName());
-        // store the declaring class so that the class writer knows that it 
will have to call a bridge method
+        // access to a private field from a section of code that normally 
doesn't have access to it, like a closure block or inner class
+        Expression fieldOwner = field.isStatic() ? 
classX(field.getDeclaringClass()) : propX(classX(field.getDeclaringClass()), 
"this");
+        PropertyExpression pe = attrX(fieldOwner, ve.getName()); // 
GROOVY-10687, GROOVY-11412: direct access
         
pe.getObjectExpression().putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, 
field.getDeclaringClass());
         pe.putNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE, 
field.getOriginType());
         pe.getProperty().setSourcePosition(ve);
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 2d46571a71..87ed4596a2 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -592,8 +592,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
             ClassNode declaringClass = fn.getDeclaringClass();
             ClassNode enclosingClass = 
typeCheckingContext.getEnclosingClassNode();
             if (declaringClass == enclosingClass ? 
typeCheckingContext.getEnclosingClosure() != null : getNestHost(declaringClass) 
== getNestHost(enclosingClass)) {
-                StaticTypesMarker accessKind = lhsOfAssignment ? 
PV_FIELDS_MUTATION : PV_FIELDS_ACCESS;
-                addPrivateFieldOrMethodAccess(source, declaringClass, 
accessKind, fn);
+                source.putNodeMetaData(lhsOfAssignment ? PV_FIELDS_MUTATION : 
PV_FIELDS_ACCESS, fn);
             }
         }
     }
diff --git a/src/test/org/codehaus/groovy/classgen/asm/NestHostTests.groovy 
b/src/test/org/codehaus/groovy/classgen/asm/NestHostTests.groovy
index 3ccf2a2f96..db63589cda 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/NestHostTests.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/NestHostTests.groovy
@@ -119,4 +119,19 @@ final class NestHostTests {
             assert type.nestMembers*.name.sort() == ['C', 'C$D', 
'C$D$_m_lambda1', 'C$D$_m_lambda1$_lambda2']
         }
     }
+
+    @Test
+    void testNestHost6() {
+        def types = compileScript '''
+            @groovy.transform.CompileStatic
+            class C {
+                def closure = { -> { -> Optional.empty().orElseGet(() -> 42) } 
}
+            }
+        '''
+
+        types.each { type ->
+            assert type.nestHost.name == 'C'
+            assert type.nestMembers*.name.sort() == ['C', 'C$_closure1', 
'C$_closure1$_closure2', 'C$_closure1$_closure2$_lambda3']
+        }
+    }
 }
diff --git 
a/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
 
b/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
index 4e2b2d5bd5..f9a5f17f8a 100644
--- 
a/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
+++ 
b/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
@@ -616,45 +616,35 @@ final class FieldsAndPropertiesStaticCompileTest extends 
FieldsAndPropertiesSTCT
             }
             new Bar().test()
         '''
-        String bar = astTrees['Bar'][1]
-        assert bar.contains('INVOKEVIRTUAL Bar.setX (Ljava/lang/Long;)V')
-        assert bar.contains('INVOKEVIRTUAL Bar.setX (Ljava/util/Date;)V')
+        String  bar = astTrees['Bar'][1]
+        assert  bar.contains('INVOKEVIRTUAL Bar.setX (Ljava/lang/Long;)V')
+        assert  bar.contains('INVOKEVIRTUAL Bar.setX (Ljava/util/Date;)V')
         assert !bar.contains('INVOKESTATIC 
org/codehaus/groovy/runtime/ScriptBytecodeAdapter.setGroovyObjectProperty ')
     }
 
-    void testPrivateFieldMutationInClosureUsesBridgeMethod() {
-        assertScript '''
-            class Foo {
-                private String s
-                Closure c = { this.s = 'abc' }
-
-                void test() {
-                    c()
-                    assert s == 'abc'
-                }
-            }
-            new Foo().test()
-        '''
-        assert astTrees['Foo$_closure1'][1].contains('INVOKESTATIC 
Foo.pfaccess$00 (LFoo;Ljava/lang/String;)Ljava/lang/String')
-    }
-
-    void testImplicitPrivateFieldMutationInClosureUsesBridgeMethod() {
-        assertScript '''
-            class Foo {
-                private String s
-                Closure c = { s = 'abc' }
+    // GROOVY-7705, GROOVY-10687
+    void testPrivateFieldMutationInClosureUsesDirectAccess() {
+        for (prefix in ['','this.','thisObject.','getThisObject().']) {
+            assertScript """
+                class Foo {
+                    Closure c = { -> ${prefix}s = 'abc' }
+                    private s
 
-                String test() {
-                    c()
-                    assert s == 'abc'
+                    void test() {
+                        c()
+                        assert s == 'abc'
+                    }
                 }
-            }
-            new Foo().test()
-        '''
-        assert astTrees['Foo$_closure1'][1].contains('INVOKESTATIC 
Foo.pfaccess$00 (LFoo;Ljava/lang/String;)Ljava/lang/String')
+                new Foo().test()
+            """
+            String  c = astTrees['Foo$_closure1'][1]
+            assert  c.contains('PUTFIELD Foo.s') // JEP 181: nestmate access
+            assert !c.contains('INVOKESTATIC Foo.pfaccess$00 
(LFoo;Ljava/lang/Object;)')
+        }
     }
 
-    void testPrivateStaticFieldMutationInClosureUsesBridgeMethod() {
+    // GROOVY-7705, GROOVY-10687
+    void testPrivateStaticFieldMutationInClosureUsesDirectAccess() {
         assertScript '''
             class Foo {
                 private static String s
@@ -667,10 +657,13 @@ final class FieldsAndPropertiesStaticCompileTest extends 
FieldsAndPropertiesSTCT
             }
             new Foo().test()
         '''
-        assert astTrees['Foo$_closure1'][1].contains('INVOKESTATIC 
Foo.pfaccess$00 (LFoo;Ljava/lang/String;)Ljava/lang/String')
+        String  c = astTrees['Foo$_closure1'][1]
+        assert  c.contains('PUTSTATIC Foo.s') // JEP 181: nestmate access
+        assert !c.contains('INVOKESTATIC Foo.pfaccess$00 
(LFoo;Ljava/lang/String;)')
     }
 
-    void testPrivateFieldMutationInAICUsesBridgeMethod() {
+    // GROOVY-7705, GROOVY-10687
+    void testPrivateFieldMutationInAICUsesDirectAccess() {
         assertScript '''
             class C {
                 private int x
@@ -682,10 +675,13 @@ final class FieldsAndPropertiesStaticCompileTest extends 
FieldsAndPropertiesSTCT
             }
             new C().test()
         '''
-        assert astTrees['C$1'][1].contains('INVOKESTATIC C.pfaccess$00 
(LC;I)I')
+        String  aic = astTrees['C$1'][1]
+        assert  aic.contains('PUTFIELD C.x') // direct access
+        assert !aic.contains('INVOKESTATIC C.pfaccess$00 (LC;I)I')
     }
 
-    void testImplicitPrivateFieldMutationInAICUsesBridgeMethod() {
+    // GROOVY-7705, GROOVY-10687
+    void testImplicitPrivateFieldMutationInAICUsesDirectAccess() {
         assertScript '''
             class C {
                 private int x
@@ -697,10 +693,13 @@ final class FieldsAndPropertiesStaticCompileTest extends 
FieldsAndPropertiesSTCT
             }
             new C().test()
         '''
-        assert astTrees['C$1'][1].contains('INVOKESTATIC C.pfaccess$00 
(LC;I)I')
+        String  aic = astTrees['C$1'][1]
+        assert  aic.contains('PUTFIELD C.x') // direct access
+        assert !aic.contains('INVOKESTATIC C.pfaccess$00 (LC;I)I')
     }
 
-    void testPrivateStaticFieldMutationInAICUsesBridgeMethod() {
+    // GROOVY-7705, GROOVY-10687
+    void testPrivateStaticFieldMutationInAICUsesDirectAccess() {
         assertScript '''
             class C {
                 private static int x
@@ -712,10 +711,13 @@ final class FieldsAndPropertiesStaticCompileTest extends 
FieldsAndPropertiesSTCT
             }
             new C().test()
         '''
-        assert astTrees['C$1'][1].contains('INVOKESTATIC C.pfaccess$00 
(LC;I)I')
+        String  aic = astTrees['C$1'][1]
+        assert  aic.contains('PUTSTATIC C.x') // direct access
+        assert !aic.contains('INVOKESTATIC C.pfaccess$00 (LC;I)I')
     }
 
-    void testMultiplePrivateFieldMutatorBridgeMethods() {
+    // GROOVY-7705, GROOVY-10687
+    void testMultiplePrivateFieldMutatorDirectAccess() {
         assertScript '''
             class C {
                 private int x
@@ -730,10 +732,14 @@ final class FieldsAndPropertiesStaticCompileTest extends 
FieldsAndPropertiesSTCT
             }
             new C().test()
         '''
-        assert astTrees['C$_closure1'][1].contains('INVOKESTATIC C.pfaccess$00 
(LC;I)I')
-        assert astTrees['C$_closure1'][1].contains('INVOKESTATIC C.pfaccess$01 
(LC;Ljava/lang/String;)Ljava/lang/String;')
+        String  closure = astTrees['C$_closure1'][1]
+        assert  closure.contains('PUTFIELD C.x') // direct access
+        assert  closure.contains('PUTFIELD C.y') // direct access
+        assert !closure.contains('INVOKESTATIC C.pfaccess$00 (LC;I)I')
+        assert !closure.contains('INVOKESTATIC C.pfaccess$01 
(LC;Ljava/lang/String;)Ljava/lang/String;')
     }
 
+    // GROOVY-7705, GROOVY-9385, GROOVY-10687
     void testPrivateFieldBridgeMethodsAreGeneratedAsNecessary() {
         assertScript '''
             class C {
@@ -754,16 +760,16 @@ final class FieldsAndPropertiesStaticCompileTest extends 
FieldsAndPropertiesSTCT
             }
             new C().test()
         '''
-        String dump = astTrees['C'][1]
-        assert dump.contains('pfaccess$0') // accessor bridge method for 
'accessed'
-        assert !dump.contains('pfaccess$00') // no mutator bridge method for 
'accessed'
-        assert dump.contains('pfaccess$01') // mutator bridge method for 
'mutated'
-        assert dump.contains('pfaccess$1') // accessor bridge method for 
'mutated' -- GROOVY-9385
-        assert dump.contains('pfaccess$2') // accessor bridge method for 
'accessedAndMutated'
-        assert dump.contains('pfaccess$02') // mutator bridge method for 
'accessedAndMutated'
+        String  dump = astTrees['C'][1]
+        assert !dump.contains('pfaccess$0')  // no access bridge method for 
'accessed'
+        assert !dump.contains('pfaccess$00') // no mutate bridge method for 
'accessed'
+        assert !dump.contains('pfaccess$01') // no mutate bridge method for 
'mutated'
+        assert !dump.contains('pfaccess$1')  // no access bridge method for 
'mutated'
+        assert !dump.contains('pfaccess$2')  // no access bridge method for 
'accessedAndMutated'
+        assert !dump.contains('pfaccess$02') // no mutate bridge method for 
'accessedAndMutated'
                dump = astTrees['C$_closure1'][1]
-        assert dump.contains('INVOKESTATIC C.pfaccess$2 
(LC;)Ljava/lang/String;')
-        assert dump.contains('INVOKESTATIC C.pfaccess$02 
(LC;Ljava/lang/String;)Ljava/lang/String;')
+        assert !dump.contains('INVOKESTATIC C.pfaccess$2 
(LC;)Ljava/lang/String;')
+        assert !dump.contains('INVOKESTATIC C.pfaccess$02 
(LC;Ljava/lang/String;)Ljava/lang/String;')
     }
 
     // GROOVY-8369

Reply via email to