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

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


The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
     new a66bc2f  Revert "GROOVY-7232: check resolve strategy of each closure 
during method search"
a66bc2f is described below

commit a66bc2facb0f018c807493379aeca50455b77f52
Author: Daniel Sun <[email protected]>
AuthorDate: Sat Aug 1 19:24:53 2020 +0800

    Revert "GROOVY-7232: check resolve strategy of each closure during method 
search"
    
    This is a breaking change and should not appear in a maintenance branch
    This reverts commit 4d04c10b
---
 .../groovy/runtime/metaclass/ClosureMetaClass.java | 76 +++++++++++-----------
 src/test/gls/closures/ResolveStrategyTest.groovy   | 38 +++++------
 src/test/groovy/lang/ClosureResolvingTest.groovy   | 41 ------------
 3 files changed, 57 insertions(+), 98 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java 
b/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java
index 1b97ef9..af0bf2b 100644
--- a/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java
+++ b/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java
@@ -47,6 +47,7 @@ import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
@@ -243,7 +244,6 @@ public final class ClosureMetaClass extends MetaClassImpl {
 
         MetaMethod method = null;
         final Closure closure = (Closure) object;
-        final int resolveStrategy = closure.getResolveStrategy();
 
         if (CLOSURE_DO_CALL_METHOD.equals(methodName) || 
CLOSURE_CALL_METHOD.equals(methodName)) {
             method = pickClosureMethod(argClasses);
@@ -255,7 +255,7 @@ public final class ClosureMetaClass extends MetaClassImpl {
             if (method == null) throw new MissingMethodException(methodName, 
theClass, arguments, false);
         }
 
-        boolean shouldDefer = resolveStrategy == Closure.DELEGATE_ONLY && 
isInternalMethod(methodName);
+        boolean shouldDefer = closure.getResolveStrategy() == 
Closure.DELEGATE_ONLY && isInternalMethod(methodName);
         if (method == null && !shouldDefer) {
             method = CLOSURE_METACLASS.pickMethod(methodName, argClasses);
         }
@@ -267,6 +267,7 @@ public final class ClosureMetaClass extends MetaClassImpl {
         final Object owner = closure.getOwner();
         final Object delegate = closure.getDelegate();
         final Object thisObject = closure.getThisObject();
+        final int resolveStrategy = closure.getResolveStrategy();
         boolean invokeOnDelegate = false;
         boolean invokeOnOwner = false;
         boolean ownerFirst = true;
@@ -287,21 +288,48 @@ public final class ClosureMetaClass extends MetaClassImpl 
{
                 if (method == null) {
                     invokeOnOwner = owner != closure && (owner instanceof 
GroovyObject);
                 }
+
                 break;
-            default: // Closure.*_FIRST:
-                for (Object candidate : ownersAndDelegatesOf(closure, new 
ArrayList<>())) {
-                    method = getDelegateMethod(closure, candidate, methodName, 
argClasses);
-                    callObject = candidate;
-                    if (method != null) {
-                        break;
-                    }
+            case Closure.DELEGATE_FIRST:
+                method = getDelegateMethod(closure, delegate, methodName, 
argClasses);
+                callObject = delegate;
+                if (method == null) {
+                    method = getDelegateMethod(closure, owner, methodName, 
argClasses);
+                    callObject = owner;
                 }
                 if (method == null) {
                     invokeOnDelegate = delegate != closure && (delegate 
instanceof GroovyObject);
                     invokeOnOwner = owner != closure && (owner instanceof 
GroovyObject);
-                    ownerFirst = resolveStrategy != Closure.DELEGATE_FIRST;
+                    ownerFirst = false;
                 }
                 break;
+            default: // owner first
+                // owner first means we start with the outer most owner that 
is not a generated closure
+                // this owner is equal to the this object, so we check that 
one first.
+                method = getDelegateMethod(closure, thisObject, methodName, 
argClasses);
+                callObject = thisObject;
+                if (method == null) {
+                    // try finding a delegate that has that method... we start 
from
+                    // outside building a stack and try each delegate
+                    LinkedList list = new LinkedList();
+                    for (Object current = closure; current != thisObject;) {
+                        if (!(current instanceof Closure)) break;
+                        Closure currentClosure = (Closure) current;
+                        if (currentClosure.getDelegate() != null) 
list.add(current);
+                        current = currentClosure.getOwner();
+                    }
+
+                    while (!list.isEmpty() && method == null) {
+                        Closure closureWithDelegate = (Closure) 
list.removeLast();
+                        Object currentDelegate = 
closureWithDelegate.getDelegate();
+                        method = getDelegateMethod(closureWithDelegate, 
currentDelegate, methodName, argClasses);
+                        callObject = currentDelegate;
+                    }
+                }
+                if (method == null) {
+                    invokeOnDelegate = delegate != closure && (delegate 
instanceof GroovyObject);
+                    invokeOnOwner = owner != closure && (owner instanceof 
GroovyObject);
+                }
         }
         if (method == null && (invokeOnOwner || invokeOnDelegate)) {
             try {
@@ -351,34 +379,6 @@ public final class ClosureMetaClass extends MetaClassImpl {
         return arguments;
     }
 
-    private static List ownersAndDelegatesOf(Closure closure, List 
ownersAndDelegates) {
-        switch (closure.getResolveStrategy()) {
-        case Closure.TO_SELF:
-            ownersAndDelegates.add(closure);
-            break;
-        case Closure.OWNER_ONLY:
-            ownersAndDelegates.add(closure.getOwner());
-            break;
-        case Closure.DELEGATE_ONLY:
-            ownersAndDelegates.add(closure.getDelegate());
-            break;
-        case Closure.DELEGATE_FIRST:
-            ownersAndDelegates.add(closure.getDelegate());
-            ownersAndDelegates.add(closure.getOwner());
-            if (closure.getOwner() instanceof Closure) {
-                ownersAndDelegatesOf((Closure) closure.getOwner(), 
ownersAndDelegates);
-            }
-            break;
-        default: // Closure.OWNER_FIRST:
-            ownersAndDelegates.add(closure.getOwner());
-            if (closure.getOwner() instanceof Closure) {
-                ownersAndDelegatesOf((Closure) closure.getOwner(), 
ownersAndDelegates);
-            }
-            ownersAndDelegates.add(closure.getDelegate());
-        }
-        return ownersAndDelegates;
-    }
-
     private static Throwable unwrap(GroovyRuntimeException gre) {
         Throwable th = gre;
         if (th.getCause() != null && th.getCause() != gre) th = th.getCause();
diff --git a/src/test/gls/closures/ResolveStrategyTest.groovy 
b/src/test/gls/closures/ResolveStrategyTest.groovy
index 1a8111d..e9cb637 100644
--- a/src/test/gls/closures/ResolveStrategyTest.groovy
+++ b/src/test/gls/closures/ResolveStrategyTest.groovy
@@ -20,31 +20,30 @@ package gls.closures
 
 import groovy.test.GroovyTestCase
 import groovy.transform.CompileStatic
-
 import static groovy.lang.Closure.*
 
 class ResolveStrategyTest extends GroovyTestCase {
     void testDynamicSettingOfResolveStrategy() {
         new MyClass().with {
-            assert run(OWNER_ONLY) == 1234 // (*)
-            assert runOwnerOnly { m1() + m2() + m3() + m4() } == 1234 // (*)
-
             assert run(DELEGATE_ONLY) == 12340000 // (*)
-            assert runDelegateOnly { m1() + m2() + m3() + m4() } == 12340000 
// (*)
-
-            // (*) involves methodMissing as forced by ONLY strategy (no 
equivalent CS case below)
-
+            assert run(DELEGATE_FIRST) == 12040030
+            assert run(OWNER_ONLY) == 1234 // (*)
             assert run(OWNER_FIRST) == 41230
-            assert runOwnerFirst { m1() + m2() + m3() + m4() } == 41230
 
-            assert run(DELEGATE_FIRST) == 12040030
-            assert runDelegateFirst { m1() + m2() + m3() + m4() } == 12040030
+            assert runOwnerOnly { m1() + m2() + m3() } == 1230
+            assert runOwnerOnly { m1() + m2() + m3() + m4() } == 1234 // (*)
+            assert runOwnerFirst { m1() + m2() + m3() + m4() } == 41230
+            assert runDelegateOnly { m1() + m2() + m3() + m4() } == 12340000 
// (*)
+            assert runDelegateOnly { m1() + m2() + m4() } == 12040000
+            assert runDelegateFirst { m1() + m2() + m3() + m4() } == 12340000 
// (**)
 
             // nested cases
+            assert runDelegateFirst { runOwnerFirst { m1() + m2() + m3() + 
m4() } } == 41230
+            assert runOwnerFirst { runDelegateFirst { m1() + m2() + m3() + 
m4() } } == 12340000 // (**)
             assert runOwnerFirst { runOwnerFirst { m1() + m2() + m3() + m4() } 
} == 41230
-            assert runOwnerFirst { runDelegateFirst { m1() + m2() + m3() + 
m4() } } == 12040030
-            assert runDelegateFirst { runOwnerFirst { m1() + m2() + m3() + 
m4() } } == 12040030
-            assert runDelegateFirst { runDelegateFirst { m1() + m2() + m3() + 
m4() } } == 12040030
+            assert runDelegateFirst { runDelegateFirst { m1() + m2() + m3() + 
m4() } } == 12340000 // (**)
+            // (*) involves methodMissing as forced by ONLY strategy (no 
equivalent CS case below)
+            // (**) involves methodMissing since delegate methodMissing has 
precedence over explicit owner method
         }
     }
 
@@ -54,13 +53,14 @@ class ResolveStrategyTest extends GroovyTestCase {
             assert runOwnerOnly { m1() + m2() + m3() } == 1230
             assert runOwnerFirst { m1() + m2() + m3() + m4() } == 41230
             assert runDelegateOnly { m1() + m2() + m4() } == 12040000
-            assert runDelegateFirst { m1() + m2() + m3() + m4() } == 12040030
+            assert runDelegateFirst { m1() + m2() + m3() + m4() } == 12040030 
// (*)
 
-            // GROOVY-9086: nested cases
+            // nested cases (GROOVY-9086)
+            assert runDelegateFirst { runOwnerFirst { m1() + m2() + m3() + 
m4() } } == 12040030 // (*)
+            assert runOwnerFirst { runDelegateFirst { m1() + m2() + m3() + 
m4() } } == 12040030 // (*)
             assert runOwnerFirst { runOwnerFirst { m1() + m2() + m3() + m4() } 
} == 41230
-            assert runDelegateFirst { runOwnerFirst { m1() + m2() + m3() + 
m4() } } == 12040030
-            assert runOwnerFirst { runDelegateFirst { m1() + m2() + m3() + 
m4() } } == 12040030
-            assert runDelegateFirst { runDelegateFirst { m1() + m2() + m3() + 
m4() } } == 12040030
+            assert runDelegateFirst { runDelegateFirst { m1() + m2() + m3() + 
m4() } } == 12040030 // (*)
+            // (*) different to dynamic since static assumes no methodMissing
         }
     }
 }
diff --git a/src/test/groovy/lang/ClosureResolvingTest.groovy 
b/src/test/groovy/lang/ClosureResolvingTest.groovy
index e266647..69d2932 100644
--- a/src/test/groovy/lang/ClosureResolvingTest.groovy
+++ b/src/test/groovy/lang/ClosureResolvingTest.groovy
@@ -203,47 +203,6 @@ class ClosureResolvingTest extends GroovyTestCase {
         cout()
     }
 
-    // GROOVY-7232
-    void testOwnerDelegateChain2() {
-        assertScript '''
-            def outer = { ->
-                def inner = { ->
-                    [x, keySet()]
-                }
-                inner.resolveStrategy = Closure.DELEGATE_ONLY
-                inner.delegate = [x: 1, f: 0]
-                inner.call()
-            }
-            //outer.resolveStrategy = Closure.OWNER_FIRST
-            outer.delegate = [x: 0, g: 0]
-            def result = outer.call()
-
-            assert result.flatten() == [1, 'x', 'f']
-        '''
-    }
-
-    // GROOVY-7232
-    void testOwnerDelegateChain3() {
-        assertScript '''
-            def outer = { ->
-                def inner = { ->
-                    def inner_inner = { ->
-                        [x, keySet()]
-                    }
-                    //inner_inner.resolveStrategy = Closure.OWNER_FIRST
-                    return inner_inner.call()
-                }
-                inner.resolveStrategy = Closure.DELEGATE_ONLY
-                inner.delegate = [x: 1, f: 0]
-                inner()
-            }
-            //outer.resolveStrategy = Closure.OWNER_FIRST
-            outer.delegate = [x: 0, g: 0]
-            def result = outer.call()
-
-            assert result.flatten() == [1, 'x', 'f']
-        '''
-    }
 }
 
 class TestResolve1 {

Reply via email to