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/03/21 15:30:52 UTC

[groovy] branch GROOVY_3_0_X updated (6b8c3ad -> f2991ba)

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

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


    from 6b8c3ad  GROOVY-7288: fix for `@Delegate` target that implements trait(s) (port to 3_0_X)
     new fe84dd7  GROOVY-8243: support closure for functional interface that extends trait
     new f2991ba  minor edits

The 2 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.


Summary of changes:
 .../java/org/codehaus/groovy/ast/GenericsType.java |  9 ++--
 .../codehaus/groovy/ast/tools/GenericsUtils.java   |  7 ++-
 .../groovy/runtime/DefaultGroovyMethods.java       | 41 ++++++++---------
 .../groovy/runtime/ProxyGeneratorAdapter.java      | 51 +++++++++++-----------
 .../transform/DelegateASTTransformation.java       |  3 +-
 .../transform/stc/StaticTypeCheckingVisitor.java   |  4 +-
 .../traitx/TraitASTTransformationTest.groovy       | 32 +++++++++++---
 7 files changed, 80 insertions(+), 67 deletions(-)

[groovy] 02/02: minor edits

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

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

commit f2991ba9ee210ca00c1e79eed0efbb6d1d435124
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Mar 21 10:17:00 2022 -0500

    minor edits
---
 src/main/java/org/codehaus/groovy/ast/GenericsType.java          | 9 +++++----
 src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java   | 7 +++----
 .../org/codehaus/groovy/transform/DelegateASTTransformation.java | 3 +--
 .../codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java | 4 ++--
 4 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/GenericsType.java b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
index 378b054..e689249 100644
--- a/src/main/java/org/codehaus/groovy/ast/GenericsType.java
+++ b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
@@ -66,20 +66,21 @@ public class GenericsType extends ASTNode {
     }
 
     private static String toString(final GenericsType gt, final Set<String> visited) {
+        String name = gt.getName();
         ClassNode type = gt.getType();
         boolean wildcard = gt.isWildcard();
         boolean placeholder = gt.isPlaceholder();
         ClassNode lowerBound = gt.getLowerBound();
         ClassNode[] upperBounds = gt.getUpperBounds();
 
-        if (placeholder) visited.add(gt.getName());
+        if (placeholder) visited.add(name);
 
-        StringBuilder ret = new StringBuilder(wildcard || placeholder ? gt.getName() : genericsBounds(type, visited));
+        StringBuilder ret = new StringBuilder(wildcard || placeholder ? name : genericsBounds(type, visited));
         if (lowerBound != null) {
             ret.append(" super ").append(genericsBounds(lowerBound, visited));
         } else if (upperBounds != null
                 // T extends Object should just be printed as T
-                && !(placeholder && upperBounds.length == 1 && !upperBounds[0].isGenericsPlaceHolder() && upperBounds[0].getName().equals("java.lang.Object"))) {
+                && !(placeholder && upperBounds.length == 1 && !upperBounds[0].isGenericsPlaceHolder() && upperBounds[0].getName().equals(ClassHelper.OBJECT))) {
             ret.append(" extends ");
             for (int i = 0, n = upperBounds.length; i < n; i += 1) {
                 if (i != 0) ret.append(" & ");
@@ -444,7 +445,7 @@ public class GenericsType extends ASTNode {
                                         if (!match) break;
                                     }
                                 }
-                                continue;
+                                continue; // GROOVY-10010
                             }
                         }
                         match = redirectBoundType.isCompatibleWith(classNodeType.getType());
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
index 1961e00..84d328d 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -64,7 +64,7 @@ import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.implem
  */
 public class GenericsUtils {
     public static final GenericsType[] EMPTY_GENERICS_ARRAY = GenericsType.EMPTY_ARRAY;
-    public static final String JAVA_LANG_OBJECT = "java.lang.Object";
+    public static final String JAVA_LANG_OBJECT = ClassHelper.OBJECT;
 
     /**
      * Given a parameterized type and a generic type information, aligns actual type parameters. For example, if a
@@ -167,8 +167,8 @@ public class GenericsUtils {
         GenericsType[] parameterized = node.getGenericsTypes();
         if (parameterized == null || parameterized.length == 0) return;
         GenericsType[] redirectGenericsTypes = node.redirect().getGenericsTypes();
-        if (redirectGenericsTypes == null ||
-                (node.isGenericsPlaceHolder() && redirectGenericsTypes.length != parameterized.length) /* GROOVY-8609 */ ) {
+        if (redirectGenericsTypes == null || (node.isGenericsPlaceHolder() // GROOVY-8609
+                                              && redirectGenericsTypes.length != parameterized.length)) {
             redirectGenericsTypes = parameterized;
         }
         if (redirectGenericsTypes.length != parameterized.length) {
@@ -269,7 +269,6 @@ public class GenericsUtils {
         genericsSpec = createGenericsSpec(targetRedirect, genericsSpec);
         extractSuperClassGenerics(hint, targetRedirect, genericsSpec);
         return correctToGenericsSpecRecurse(genericsSpec, targetRedirect);
-
     }
 
     public static ClassNode nonGeneric(final ClassNode type) {
diff --git a/src/main/java/org/codehaus/groovy/transform/DelegateASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/DelegateASTTransformation.java
index 311edc3..5ee271f 100644
--- a/src/main/java/org/codehaus/groovy/transform/DelegateASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/DelegateASTTransformation.java
@@ -66,7 +66,6 @@ import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpec;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpecRecurse;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.extractSuperClassGenerics;
-import static org.codehaus.groovy.ast.tools.GenericsUtils.nonGeneric;
 import static org.codehaus.groovy.ast.tools.ParameterUtils.parametersEqual;
 
 /**
@@ -186,7 +185,7 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
             if (skipInterfaces) return;
 
             Set<ClassNode> addedInterfaces = getInterfacesAndSuperInterfaces(delegate.type);
-            addedInterfaces.removeIf(i -> (i.getModifiers() & (ACC_PUBLIC | ACC_SYNTHETIC)) != ACC_PUBLIC); // GROOVY-7288 and JDK16+
+            addedInterfaces.removeIf(i -> (i.getModifiers() & (ACC_PUBLIC | ACC_SYNTHETIC)) != ACC_PUBLIC); // GROOVY-7288
             if (!addedInterfaces.isEmpty()) {
                 Set<ClassNode> ownerInterfaces = getInterfacesAndSuperInterfaces(delegate.owner);
                 for (ClassNode i : addedInterfaces) {
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 72e97ea..ba44773 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -775,7 +775,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     : getInferredTypeFromTempInfo(rightExpression, getType(rightExpression));
             ClassNode resultType;
             if (op == ELVIS_EQUAL) {
-                Expression fullExpression = new ElvisOperatorExpression(leftExpression, rightExpression);
+                Expression fullExpression = elvisX(leftExpression, rightExpression);
                 fullExpression.setSourcePosition(expression);
                 fullExpression.visit(this);
 
@@ -4409,7 +4409,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             }
 
             if (leftExpression instanceof VariableExpression) {
-                ClassNode initialType = getOriginalDeclarationType(leftExpression).redirect();
+                ClassNode initialType = getOriginalDeclarationType(leftExpression);
 
                 if (isPrimitiveType(right) && initialType.isDerivedFrom(Number_TYPE)) {
                     return getWrapper(right);

[groovy] 01/02: GROOVY-8243: support closure for functional interface that extends trait

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

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

commit fe84dd763219f86cd28409f909c4522ed71c851d
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Mar 21 10:15:57 2022 -0500

    GROOVY-8243: support closure for functional interface that extends trait
---
 .../groovy/runtime/DefaultGroovyMethods.java       | 41 ++++++++---------
 .../groovy/runtime/ProxyGeneratorAdapter.java      | 51 +++++++++++-----------
 .../traitx/TraitASTTransformationTest.groovy       | 32 +++++++++++---
 3 files changed, 69 insertions(+), 55 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index b47fb41..69e6c3c 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -55,6 +55,7 @@ import groovy.util.OrderBy;
 import groovy.util.PermutationGenerator;
 import groovy.util.ProxyGenerator;
 import org.apache.groovy.io.StringBuilderWriter;
+import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.classgen.Verifier;
 import org.codehaus.groovy.reflection.ClassInfo;
 import org.codehaus.groovy.reflection.MixinInMetaClass;
@@ -12310,38 +12311,34 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Coerces the closure to an implementation of the given class.  The class
+     * Coerces the closure to an implementation of the given class. The class
      * is assumed to be an interface or class with a single method definition.
      * The closure is used as the implementation of that single method.
      *
-     * @param cl    the implementation of the single method
-     * @param clazz the target type
-     * @return a Proxy of the given type which wraps this closure.
+     * @param impl the implementation of the single method
+     * @param type the target type
+     * @return A proxy of the given type which wraps this closure.
+     *
      * @since 1.0
      */
-    @SuppressWarnings("unchecked")
-    public static <T> T asType(Closure cl, Class<T> clazz) {
-        if (clazz.isInterface() && !(clazz.isInstance(cl))) {
-            if (Traits.isTrait(clazz)) {
-                Method samMethod = CachedSAMClass.getSAMMethod(clazz);
-                if (samMethod!=null) {
-                    Map impl = Collections.singletonMap(samMethod.getName(),cl);
-                    return (T) ProxyGenerator.INSTANCE.instantiateAggregate(impl, Collections.singletonList(clazz));
+    public static <T> T asType(final Closure impl, final Class<T> type) {
+        if (type.isInterface() && !type.isInstance(impl)) {
+            if (Traits.isTrait(type) || ClassHelper.make(type).getAllInterfaces().stream().anyMatch(Traits::isTrait)) { // GROOVY-8243
+                Method sam = CachedSAMClass.getSAMMethod(type);
+                if (sam != null) {
+                    return (T) ProxyGenerator.INSTANCE.instantiateAggregate(Collections.singletonMap(sam.getName(), impl), Collections.singletonList(type));
                 }
             }
-            return (T) Proxy.newProxyInstance(
-                    clazz.getClassLoader(),
-                    new Class[]{clazz},
-                    new ConvertedClosure(cl));
+            return (T) Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, new ConvertedClosure(impl));
         }
+
         try {
-            return asType((Object) cl, clazz);
-        } catch (GroovyCastException ce) {
+            return asType((Object) impl, type);
+        } catch (GroovyCastException gce) {
             try {
-                return (T) ProxyGenerator.INSTANCE.instantiateAggregateFromBaseClass(cl, clazz);
-            } catch (GroovyRuntimeException cause) {
-                throw new GroovyCastException("Error casting closure to " + clazz.getName() +
-                        ", Reason: " + cause.getMessage());
+                return (T) ProxyGenerator.INSTANCE.instantiateAggregateFromBaseClass(impl, type);
+            } catch (GroovyRuntimeException gre) {
+                throw new GroovyCastException("Error casting closure to " + type.getName() + ", Reason: " + gre.getMessage());
             }
         }
     }
diff --git a/src/main/java/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java b/src/main/java/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java
index 23c4017..6869e83 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java
@@ -23,7 +23,6 @@ import groovy.lang.GeneratedGroovyProxy;
 import groovy.lang.GroovyClassLoader;
 import groovy.lang.GroovyObject;
 import groovy.lang.GroovyRuntimeException;
-import groovy.transform.Trait;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.classgen.asm.BytecodeHelper;
@@ -42,7 +41,6 @@ import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 
-import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -201,20 +199,16 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         cachedNoArgConstructor = constructor;
     }
 
-    private Class adjustSuperClass(Class superClass, final Class[] interfaces) {
-        boolean isSuperClassAnInterface = superClass.isInterface();
-        if (!isSuperClassAnInterface) {
+    private Class adjustSuperClass(final Class superClass, Class[] interfaces) {
+        if (!superClass.isInterface()) {
             return superClass;
         }
-        Class result = Object.class;
-        Set<ClassNode> traits = new LinkedHashSet<ClassNode>();
-        // check if it's a trait
-        collectTraits(superClass, traits);
-        if (interfaces != null) {
-            for (Class anInterface : interfaces) {
-                collectTraits(anInterface, traits);
-            }
+        if (interfaces == null || interfaces.length == 0) {
+            interfaces = new Class[]{superClass};
         }
+        assert Arrays.asList(interfaces).contains(superClass);
+
+        Set<ClassNode> traits = collectTraits(interfaces);
         if (!traits.isEmpty()) {
             String name = superClass.getName() + "$TraitAdapter";
             ClassNode cn = new ClassNode(name, ACC_PUBLIC | ACC_ABSTRACT, ClassHelper.OBJECT_TYPE, traits.toArray(ClassNode.EMPTY_ARRAY), null);
@@ -225,30 +219,35 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
             cu.compile(Phases.CONVERSION);
             su.getAST().addClass(cn);
             cu.compile(Phases.CLASS_GENERATION);
-            @SuppressWarnings("unchecked")
-            List<GroovyClass> classes = (List<GroovyClass>) cu.getClasses();
+            List<GroovyClass> classes = cu.getClasses();
             for (GroovyClass groovyClass : classes) {
                 if (groovyClass.getName().equals(name)) {
                     return loader.defineClass(name, groovyClass.getBytes());
                 }
             }
         }
-        return result;
+
+        return Object.class;
     }
 
-    private static void collectTraits(final Class clazz, final Set<ClassNode> traits) {
-        Annotation annotation = clazz.getAnnotation(Trait.class);
-        if (annotation != null) {
-            ClassNode trait = ClassHelper.make(clazz);
-            traits.add(trait.getPlainNodeReference());
-            LinkedHashSet<ClassNode> selfTypes = new LinkedHashSet<ClassNode>();
-            Traits.collectSelfTypes(trait, selfTypes, true, true);
-            for (ClassNode selfType : selfTypes) {
-                if (Traits.isTrait(selfType)) {
-                    traits.add(selfType.getPlainNodeReference());
+    private static Set<ClassNode> collectTraits(final Class[] interfaces) {
+        Set<ClassNode> traits = new LinkedHashSet<>();
+        for (Class face : interfaces) {
+            for (ClassNode node : ClassHelper.make(face).getAllInterfaces()) {
+                if (Traits.isTrait(node)) {
+                    traits.add(node.getPlainNodeReference());
+                    // check trait for @SelfType types that are / extend traits
+                    LinkedHashSet<ClassNode> selfTypes = new LinkedHashSet<>();
+                    Traits.collectSelfTypes(node, selfTypes, true, true);
+                    for (ClassNode selfType : selfTypes) {
+                        if (Traits.isTrait(selfType)) {
+                            traits.add(selfType.getPlainNodeReference());
+                        }
+                    }
                 }
             }
         }
+        return traits;
     }
 
     private static InnerLoader createInnerLoader(final ClassLoader parent, final Class[] interfaces) {
diff --git a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
index 228edeb..133b960 100644
--- a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
@@ -1484,7 +1484,7 @@ final class TraitASTTransformationTest {
     }
 
     @Test
-    void testSAMCoercionOfTraitOnAssignment() {
+    void testSAMCoercion1() {
         assertScript '''
             trait SAMTrait {
                 String foo() { bar()+bar() }
@@ -1508,7 +1508,7 @@ final class TraitASTTransformationTest {
     }
 
     @Test
-    void testSAMCoercionOfTraitOnMethod() {
+    void testSAMCoercion2() {
         assertScript '''
             trait SAMTrait {
                 String foo() { bar()+bar() }
@@ -1537,26 +1537,44 @@ final class TraitASTTransformationTest {
     }
 
     @Test
-    void testImplicitSAMCoercionBug() {
+    void testSAMCoercion3() {
         assertScript '''
             trait Greeter {
-                String greet() { "Hello $name" }
                 abstract String getName()
+                String greet() { "Hello $name" }
             }
             Greeter greeter = { 'Alice' }
             assert greeter.greet() == 'Hello Alice'
+            assert greeter.getName().equals('Alice')
         '''
     }
 
     @Test
-    void testExplicitSAMCoercionBug() {
+    void testSAMCoercion4() {
         assertScript '''
             trait Greeter {
-                String greet() { "Hello $name" }
                 abstract String getName()
+                String greet() { "Hello $name" }
             }
-            Greeter greeter = { 'Alice' } as Greeter
+            def greeter = { 'Alice' } as Greeter
             assert greeter.greet() == 'Hello Alice'
+            assert greeter.getName().equals('Alice')
+        '''
+    }
+
+    @Test // GROOVY-8243
+    void testSAMCoercion5() {
+        assertScript '''
+            trait T {
+                abstract def foo(int i)
+                def bar(double j) { "trait $j".toString() }
+            }
+            interface I extends T {
+            }
+
+            def obj = { "proxy $it".toString() } as I
+            assert obj.foo(123) == 'proxy 123'
+            assert obj.bar(4.5) == 'trait 4.5'
         '''
     }