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:13:16 UTC

[groovy] branch master 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 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 dac95aef03 GROOVY-9089: SC: no cast exception for implicit receiver
dac95aef03 is described below

commit dac95aef0374abd569c10c0104c16d8b05dd80d3
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 fe19b35ecb..cd02b265c6 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
@@ -121,6 +121,10 @@ public class StaticInvocationWriter extends InvocationWriter {
 
     private MethodCallExpression currentCall;
 
+    public MethodCallExpression getCurrentCall() {
+        return currentCall;
+    }
+
     public StaticInvocationWriter(final WriterController wc) {
         super(wc);
     }
@@ -342,7 +346,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());
@@ -377,8 +381,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);
     }
@@ -478,7 +483,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) {
@@ -753,10 +758,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 99138e8351..570697e5c6 100644
--- a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
@@ -904,21 +904,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'
+                }
+            }
         '''
     }