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 2022/10/23 11:14:28 UTC

[groovy] branch GROOVY_4_0_X updated: GROOVY-9089: SC: no cast exception for implicit receiver

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

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


The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
     new 4fdcbb5c72 GROOVY-9089: SC: no cast exception for implicit receiver
4fdcbb5c72 is described below

commit 4fdcbb5c72f2682cf68ab51c8c069517c2904a91
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun Oct 23 05:49:50 2022 -0500

    GROOVY-9089: SC: no cast exception for implicit receiver
---
 .../classgen/asm/sc/StaticInvocationWriter.java    | 17 +++----
 .../groovy/transform/stc/ClosuresSTCTest.groovy    | 52 +++++++++++++++++++---
 2 files changed, 55 insertions(+), 14 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
index ea3c60f55c..2092c16f31 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
@@ -120,6 +120,10 @@ public class StaticInvocationWriter extends InvocationWriter {
 
     private MethodCallExpression currentCall;
 
+    public MethodCallExpression getCurrentCall() {
+        return currentCall;
+    }
+
     public StaticInvocationWriter(final WriterController wc) {
         super(wc);
     }
@@ -341,7 +345,7 @@ public class StaticInvocationWriter extends InvocationWriter {
             return true;
         }
 
-        Expression fixedReceiver = null;
+        Expression  fixedReceiver = receiver;
         boolean fixedImplicitThis = implicitThis;
         if (target.isProtected()) {
             ClassNode node = receiver == null ? ClassHelper.OBJECT_TYPE : controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
@@ -376,8 +380,9 @@ public class StaticInvocationWriter extends InvocationWriter {
             }
         }
         if (receiver != null && !isSuperExpression(receiver)) {
-            // in order to avoid calls to castToType, which is the dynamic behaviour, we make sure that we call CHECKCAST instead then replace the top operand type
-            return super.writeDirectMethodCall(target, fixedImplicitThis, new CheckcastReceiverExpression(fixedReceiver != null ? fixedReceiver : receiver, target), args);
+            // in order to avoid calls to castToType, which is the dynamic behaviour, make sure that we call CHECKCAST instead then replace the top operand type
+            if (currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER) == null) fixedReceiver = new CheckcastReceiverExpression(fixedReceiver, target);
+            return super.writeDirectMethodCall(target, fixedImplicitThis, fixedReceiver, args);
         }
         return super.writeDirectMethodCall(target, implicitThis, receiver, args);
     }
@@ -470,7 +475,7 @@ public class StaticInvocationWriter extends InvocationWriter {
                 } else {
                     controller.getSourceUnit().addFatalError("Binding failed" +
                             " for arguments [" + argumentList.stream().map(arg -> typeChooser.resolveType(arg, classNode).toString(false)).collect(Collectors.joining(", ")) + "]" +
-                            " and parameters [" + Arrays.stream(parameters).map(prm -> prm.getType().toString(false)).collect(Collectors.joining(", ")) + "]", getCurrentCall());
+                            " and parameters [" + Arrays.stream(parameters).map(prm -> prm.getType().toString(false)).collect(Collectors.joining(", ")) + "]", currentCall);
                 }
             }
             for (int i = 0; i < nArgs; i += 1) {
@@ -745,10 +750,6 @@ public class StaticInvocationWriter extends InvocationWriter {
         }
     }
 
-    public MethodCallExpression getCurrentCall() {
-        return currentCall;
-    }
-
     @Override
     protected boolean makeCachedCall(final Expression origin, final ClassExpression sender, final Expression receiver, final Expression message, final Expression arguments, final MethodCallerMultiAdapter adapter, final boolean safe, final boolean spreadSafe, final boolean implicitThis, final boolean containsSpreadExpression) {
         return false;
diff --git a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
index b233142aa3..c23c44626c 100644
--- a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
@@ -889,21 +889,61 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-6343
-    void testAccessStaticFieldFromNestedClosures() {
+    void testAccessStaticFieldFromNestedClosure() {
         assertScript '''
             class A {
-
               public static final CONST = "a"
 
-              public static List doSomething() {
-                return (0..1).collect{ int x ->
-                  (0..1).collect{ int y ->
+              static List doSomething() {
+                return (0..1).collect { int x ->
+                  (0..1).collect { int y ->
                     return CONST
                   }
                 }
               }
             }
-            A.doSomething()
+            def result = A.doSomething()
+            assert result == [['a','a'],['a','a']]
+        '''
+    }
+
+    // GROOVY-9089
+    void testOwnerVersusDelegateFromNestedClosure() {
+        String declarations = '''
+            class A {
+                def p = 'outer delegate'
+                def m() { return this.p }
+            }
+            class B {
+                def p = 'inner delegate'
+                def m() { return this.p }
+            }
+            void outer(@DelegatesTo(value=A, strategy=Closure.DELEGATE_FIRST) Closure block) {
+                new A().with(block)
+            }
+            void inner(@DelegatesTo(value=B, strategy=Closure.DELEGATE_FIRST) Closure block) {
+                new B().with(block)
+            }
+        '''
+
+        assertScript declarations + '''
+            outer {
+                inner {
+                    assert m() == 'inner delegate'
+                    assert owner.m() == 'outer delegate'
+                    assert delegate.m() == 'inner delegate'
+                }
+            }
+        '''
+
+        assertScript declarations + '''
+            outer {
+                inner {
+                    assert p == 'inner delegate'
+                    assert owner.p == 'outer delegate'
+                    assert delegate.p == 'inner delegate'
+                }
+            }
         '''
     }