groovy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sun...@apache.org
Subject [groovy] 01/02: minor edits
Date Sat, 21 Dec 2019 10:16:13 GMT
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

commit a3287b9a7d6fdb2ab847cda340972bb149e7b38e
Author: Eric Milles <eric.milles@thomsonreuters.com>
AuthorDate: Fri Dec 20 13:13:50 2019 -0600

    minor edits
    
    (cherry picked from commit 1026764fcbda84c96098c94a734d75f2720fa870)
---
 .../codehaus/groovy/ast/tools/GenericsUtils.java   |   4 +-
 .../transform/stc/StaticTypeCheckingVisitor.java   | 156 +++++++--------
 .../gls/generics/GenericsUsageOrderingTest.groovy  | 212 +++++++++++----------
 3 files changed, 186 insertions(+), 186 deletions(-)

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 07d0262..691a5c2 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -868,7 +868,7 @@ public class GenericsUtils {
     private static Map<GenericsType, GenericsType> connectGenericsTypes(Map<GenericsType,
GenericsType> genericsTypeMap) {
         Map<GenericsType, GenericsType> result = new LinkedHashMap<>();
 
-        outter:
+        outer:
         for (Map.Entry<GenericsType, GenericsType> entry : genericsTypeMap.entrySet())
{
             GenericsType key = entry.getKey();
             GenericsType value = entry.getValue();
@@ -878,7 +878,7 @@ public class GenericsUtils {
                     GenericsType genericsTypeMapEntryValue = genericsTypeMapEntry.getValue();
                     if (!genericsTypeMapEntryValue.isPlaceholder() && (genericsTypeMapEntry.getKey().getName().equals(value.getName())))
{
                         result.put(key, genericsTypeMapEntryValue); // connected to actual
type
-                        continue outter;
+                        continue outer;
                     }
                 }
             }
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 9fb0317..81bb15d 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -727,9 +727,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport
{
         BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
         typeCheckingContext.pushEnclosingBinaryExpression(expression);
         try {
+            int op = expression.getOperation().getType();
             Expression leftExpression = expression.getLeftExpression();
             Expression rightExpression = expression.getRightExpression();
-            int op = expression.getOperation().getType();
+
             leftExpression.visit(this);
             SetterInfo setterInfo = removeSetterInfo(leftExpression);
             ClassNode lType = null;
@@ -739,21 +740,17 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport
{
                 }
             } else {
                 lType = getType(leftExpression);
-
-                Expression constructedRightExpression = rightExpression;
-
-                boolean isMethodRefRHS = (rightExpression instanceof MethodReferenceExpression
&& isFunctionalInterface(lType));
-                if (isMethodRefRHS) {
-                    constructedRightExpression = constructLambdaExpressionForMethodReference(lType);
-                }
-
-                inferParameterAndReturnTypesOfClosureOnRHS(lType, constructedRightExpression,
op);
-
-                if (isMethodRefRHS) {
-                    LambdaExpression lambdaExpression = (LambdaExpression) constructedRightExpression;
+                boolean isFunctionalInterface = isFunctionalInterface(lType);
+                if (isFunctionalInterface && rightExpression instanceof MethodReferenceExpression)
{
+                    LambdaExpression lambdaExpression = constructLambdaExpressionForMethodReference(lType);
+                    if (op == ASSIGN) {
+                        inferParameterAndReturnTypesOfClosureOnRHS(lType, lambdaExpression);
+                    }
                     rightExpression.putNodeMetaData(CONSTRUCTED_LAMBDA_EXPRESSION, lambdaExpression);
-                    rightExpression.putNodeMetaData(CLOSURE_ARGUMENTS,
-                            Arrays.stream(lambdaExpression.getParameters()).map(Parameter::getType).toArray(ClassNode[]::new));
+                    rightExpression.putNodeMetaData(CLOSURE_ARGUMENTS, Arrays.stream(lambdaExpression.getParameters()).map(Parameter::getType).toArray(ClassNode[]::new));
+
+                } else if (op == ASSIGN && isFunctionalInterface && rightExpression
instanceof ClosureExpression) {
+                    inferParameterAndReturnTypesOfClosureOnRHS(lType, (ClosureExpression)
rightExpression);
                 }
 
                 rightExpression.visit(this);
@@ -913,29 +910,25 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport
{
         }
     }
 
-    private void inferParameterAndReturnTypesOfClosureOnRHS(final ClassNode lType, final
Expression rightExpression, final int op) {
-        if (ASSIGN == op) {
-            if (rightExpression instanceof ClosureExpression && isFunctionalInterface(lType))
{
-                Tuple2<ClassNode[], ClassNode> typeInfo = GenericsUtils.parameterizeSAM(lType);
-                ClassNode[] paramTypes = typeInfo.getV1();
-                ClosureExpression closureExpression = ((ClosureExpression) rightExpression);
-                Parameter[] closureParameters = getParametersSafe(closureExpression);
+    private void inferParameterAndReturnTypesOfClosureOnRHS(final ClassNode lhsType, final
ClosureExpression rhsExpression) {
+        Tuple2<ClassNode[], ClassNode> typeInfo = GenericsUtils.parameterizeSAM(lhsType);
+        Parameter[] closureParameters = getParametersSafe(rhsExpression);
+        ClassNode[] parameterTypes = typeInfo.getV1();
 
-                if (paramTypes.length == closureParameters.length) {
-                    for (int i = 0, n = closureParameters.length; i < n; i++) {
-                        Parameter parameter = closureParameters[i];
-                        if (parameter.isDynamicTyped()) {
-                            parameter.setType(paramTypes[i]);
-                            parameter.setOriginType(paramTypes[i]);
-                        }
-                    }
-                } else {
-                    addStaticTypeError("Wrong number of parameters: ", closureExpression);
+        int n = closureParameters.length;
+        if (n == parameterTypes.length) {
+            for (int i = 0; i < n; i += 1) {
+                Parameter parameter = closureParameters[i];
+                if (parameter.isDynamicTyped()) {
+                    parameter.setType(parameterTypes[i]);
+                    parameter.setOriginType(parameterTypes[i]);
                 }
-
-                storeInferredReturnType(rightExpression, typeInfo.getV2());
             }
+        } else {
+            addStaticTypeError("Wrong number of parameters: ", rhsExpression);
         }
+
+        storeInferredReturnType(rhsExpression, typeInfo.getV2());
     }
 
     /**
@@ -2743,84 +2736,82 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport
{
         }
     }
 
+    /**
+     * In a method call with SAM coercion the inference is to be understood as a
+     * two phase process.  We have the normal method call to the target method
+     * with the closure argument and we have the SAM method that will be called
+     * inside the normal target method.  To infer correctly we have to "simulate"
+     * this process. We know the call to the closure will be done through the SAM
+     * type, so the SAM type generics deliver information about the Closure.  At
+     * the same time the SAM class is used in the target method parameter,
+     * providing a connection from the SAM type and the target method's class.
+     */
     private void inferSAMType(final Parameter param, final ClassNode receiver, final MethodNode
methodWithSAMParameter, final ArgumentListExpression originalMethodCallArguments, final ClosureExpression
openBlock) {
-        // In a method call with SAM coercion the inference is to be
-        // understood as a two phase process. We have the normal method call
-        // to the target method with the closure argument and we have the
-        // SAM method that will be called inside the normal target method.
-        // To infer correctly we have to "simulate" this process. We know the
-        // call to the closure will be done through the SAM type, so the SAM
-        // type generics deliver information about the Closure. At the same
-        // time the SAM class is used in the target method parameter,
-        // providing a connection from the SAM type and the target method
-        // declaration class.
-
-        // First we try to get as much information about the declaration
-        // class through the receiver
-        Map<GenericsTypeName, GenericsType> targetMethodDeclarationClassConnections
= new HashMap<>();
-        extractGenericsConnections(targetMethodDeclarationClassConnections, receiver, receiver.redirect());
-        // then we use the method with the SAM parameter to get more information about the
declaration
+        // first we try to get as much information about the declaration class through the
receiver
+        Map<GenericsTypeName, GenericsType> targetMethodConnections = new HashMap<>();
+        extractGenericsConnections(targetMethodConnections, receiver, receiver.redirect());
+
+        // then we use the method with the SAM-type parameter to get more information about
the declaration
         Parameter[] parametersOfMethodContainingSAM = methodWithSAMParameter.getParameters();
-        for (int i = 0; i < parametersOfMethodContainingSAM.length; i++) {
+        for (int i = 0, n = parametersOfMethodContainingSAM.length; i < n; i += 1) {
+            ClassNode parameterType = parametersOfMethodContainingSAM[i].getType();
             // potentially skip empty varargs
-            if (i == parametersOfMethodContainingSAM.length - 1
-                    && i == originalMethodCallArguments.getExpressions().size()
-                    && parametersOfMethodContainingSAM[i].getType().isArray())
+            if (i == (n - 1) && i == originalMethodCallArguments.getExpressions().size()
&& parameterType.isArray()) {
                 continue;
+            }
             Expression callArg = originalMethodCallArguments.getExpression(i);
             // we look at the closure later in detail, so skip it here
-            if (callArg == openBlock) continue;
-            ClassNode parameterType = parametersOfMethodContainingSAM[i].getType();
-            extractGenericsConnections(targetMethodDeclarationClassConnections, getType(callArg),
parameterType);
+            if (callArg == openBlock) {
+                continue;
+            }
+            extractGenericsConnections(targetMethodConnections, getType(callArg), parameterType);
         }
 
         // To make a connection to the SAM class we use that new information
         // to replace the generics in the SAM type parameter of the target
         // method and than that to make the connections to the SAM type generics
-        ClassNode paramTypeWithReceiverInformation = applyGenericsContext(targetMethodDeclarationClassConnections,
param.getOriginType());
-        Map<GenericsTypeName, GenericsType> SAMTypeConnections = new HashMap<>();
-        ClassNode classForSAM = paramTypeWithReceiverInformation.redirect();
-        extractGenericsConnections(SAMTypeConnections, paramTypeWithReceiverInformation,
classForSAM);
+        ClassNode paramTypeWithReceiverInformation = applyGenericsContext(targetMethodConnections,
param.getOriginType());
+        Map<GenericsTypeName, GenericsType> samTypeConnections = new HashMap<>();
+        ClassNode samTypeRedirect = paramTypeWithReceiverInformation.redirect();
+        extractGenericsConnections(samTypeConnections, paramTypeWithReceiverInformation,
samTypeRedirect);
 
         // should the open block provide final information we apply that
         // to the corresponding parameters of the SAM type method
-        MethodNode methodForSAM = findSAM(classForSAM);
-        ClassNode[] parameterTypesForSAM = extractTypesFromParameters(methodForSAM.getParameters());
-        ClassNode[] blockParameterTypes = openBlock.getNodeMetaData(CLOSURE_ARGUMENTS);
-        if (blockParameterTypes == null) {
+        MethodNode abstractMethod = findSAM(samTypeRedirect);
+        ClassNode[] abstractMethodParamTypes = extractTypesFromParameters(abstractMethod.getParameters());
+        ClassNode[] blockParamTypes = openBlock.getNodeMetaData(CLOSURE_ARGUMENTS);
+        if (blockParamTypes == null) {
             Parameter[] p = openBlock.getParameters();
             if (p == null) {
                 // zero parameter closure e.g. { -> println 'no args' }
-                blockParameterTypes = ClassNode.EMPTY_ARRAY;
-            } else if (p.length == 0 && parameterTypesForSAM.length != 0) {
+                blockParamTypes = ClassNode.EMPTY_ARRAY;
+            } else if (p.length == 0 && abstractMethodParamTypes.length != 0) {
                 // implicit it
-                blockParameterTypes = parameterTypesForSAM;
+                blockParamTypes = abstractMethodParamTypes;
             } else {
-                blockParameterTypes = new ClassNode[p.length];
-                for (int i = 0; i < p.length; i++) {
+                blockParamTypes = new ClassNode[p.length];
+                for (int i = 0, n = p.length; i < n; i += 1) {
                     if (p[i] != null && !p[i].isDynamicTyped()) {
-                        blockParameterTypes[i] = p[i].getType();
+                        blockParamTypes[i] = p[i].getType();
                     } else {
-                        blockParameterTypes[i] = typeOrNull(parameterTypesForSAM, i);
+                        blockParamTypes[i] = typeOrNull(abstractMethodParamTypes, i);
                     }
                 }
             }
         }
-        for (int i = 0; i < blockParameterTypes.length; i++) {
-            extractGenericsConnections(SAMTypeConnections, blockParameterTypes[i], typeOrNull(parameterTypesForSAM,
i));
+        for (int i = 0, n = blockParamTypes.length; i < n; i += 1) {
+            extractGenericsConnections(samTypeConnections, blockParamTypes[i], typeOrNull(abstractMethodParamTypes,
i));
         }
 
-        // and finally we apply the generics information to the parameters and
+        // finally apply the generics information to the parameters and
         // store the type of parameter and block type as meta information
-        for (int i = 0; i < blockParameterTypes.length; i++) {
-            ClassNode resolvedParameter =
-                    applyGenericsContext(SAMTypeConnections, typeOrNull(parameterTypesForSAM,
i));
-            blockParameterTypes[i] = resolvedParameter;
+        for (int i = 0, n = blockParamTypes.length; i < n; i += 1) {
+            blockParamTypes[i] = applyGenericsContext(samTypeConnections, typeOrNull(abstractMethodParamTypes,
i));
         }
 
-        tryToInferUnresolvedBlockParameterType(paramTypeWithReceiverInformation, methodForSAM,
blockParameterTypes);
+        tryToInferUnresolvedBlockParameterType(paramTypeWithReceiverInformation, abstractMethod,
blockParamTypes);
 
-        openBlock.putNodeMetaData(CLOSURE_ARGUMENTS, blockParameterTypes);
+        openBlock.putNodeMetaData(CLOSURE_ARGUMENTS, blockParamTypes);
     }
 
     private void tryToInferUnresolvedBlockParameterType(final ClassNode paramTypeWithReceiverInformation,
final MethodNode methodForSAM, final ClassNode[] blockParameterTypes) {
@@ -3212,7 +3203,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport
{
         // if the call expression is a spread operator call, then we must make sure that
         // the call is made on a collection type
         if (call.isSpreadSafe()) {
-            //TODO check if this should not be change to iterator based call logic
+            // TODO: check if this should not be change to iterator based call logic
             ClassNode expressionType = getType(objectExpression);
             if (!implementsInterfaceOrIsSubclassOf(expressionType, Collection_TYPE) &&
!expressionType.isArray()) {
                 addStaticTypeError("Spread operator can only be used on collection types",
objectExpression);
@@ -3244,7 +3235,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport
{
 
         // for arguments, we need to visit closures *after* the method has been chosen
 
-
         ClassNode receiver = getType(objectExpression);
         visitMethodCallArguments(receiver, argumentList, false, null);
 
diff --git a/src/test/gls/generics/GenericsUsageOrderingTest.groovy b/src/test/gls/generics/GenericsUsageOrderingTest.groovy
index 3801d8d..0f58fbd 100644
--- a/src/test/gls/generics/GenericsUsageOrderingTest.groovy
+++ b/src/test/gls/generics/GenericsUsageOrderingTest.groovy
@@ -18,149 +18,159 @@
  */
 package gls.generics
 
-import gls.CompilableTestSupport
+import groovy.transform.CompileStatic
+import org.junit.Test
 
-// GROOVY-6167
-class GenericsUsageOrderingTest extends CompilableTestSupport {
+import static groovy.test.GroovyAssert.assertScript
+import static groovy.test.GroovyAssert.shouldFail
+
+@CompileStatic
+final class GenericsUsageOrderingTest {
+
+    @Test
     void testGroovy6167() {
-        shouldCompile '''
-        public class Foo<T extends List<X>, X extends Number> {}
+        assertScript '''
+            class Foo<T extends List<X>, X extends Number> {
+            }
+            assert true
         '''
     }
 
+    @Test
     void testIncompatibleType1() {
-        def errMsg = shouldFail '''
-        @groovy.transform.CompileStatic
-        public class Foo<T extends List<X>, X extends Number> {
-            static void main(String[] args) {
-                def f = new Foo<ArrayList<String>, String>()
+        def err = shouldFail '''
+            @groovy.transform.CompileStatic
+            class Foo<T extends List<X>, X extends Number> {
+                static main(args) {
+                    def f = new Foo<ArrayList<String>, String>()
+                }
             }
-        }
         '''
-
-        assert errMsg.contains('The type String is not a valid substitute for the bounded
parameter <X extends java.lang.Number>')
+        assert err.message.contains('The type String is not a valid substitute for the bounded
parameter <X extends java.lang.Number>')
     }
 
+    @Test
     void testIncompatibleType2() {
-        def errMsg = shouldFail '''
-        @groovy.transform.CompileStatic
-        public class Foo<T extends List<X>, X extends Number> {
-            static void main(String[] args) {
-                def f = new Foo<HashSet<Integer>, Integer>()
+        def err = shouldFail '''
+            @groovy.transform.CompileStatic
+            class Foo<T extends List<X>, X extends Number> {
+                static main(args) {
+                    def f = new Foo<HashSet<Integer>, Integer>()
+                }
             }
-        }
         '''
-
-        assert errMsg.contains('The type HashSet is not a valid substitute for the bounded
parameter <T extends java.util.List<X>>')
+        assert err.message.contains('The type HashSet is not a valid substitute for the bounded
parameter <T extends java.util.List<X>>')
     }
 
+    @Test
     void testParameter() {
         assertScript '''
-        @groovy.transform.CompileStatic
-        public class Foo<T extends List<X>, X extends Number> {
-            X getFirstElement(T t) {
-                X x = t.get(0)
-                return x
+            @groovy.transform.CompileStatic
+            class Foo<T extends List<X>, X extends Number> {
+                X getFirstElement(T t) {
+                    X x = t.get(0)
+                    return x
+                }
+
+                static main(args) {
+                    def f = new Foo<ArrayList<Integer>, Integer>()
+                    def list = new ArrayList<Integer>()
+                    list.add(123)
+                    assert f.getFirstElement(list) == 123
+                }
             }
-
-            static void main(String[] args) {
-                def f = new Foo<ArrayList<Integer>, Integer>()
-                def list = new ArrayList<Integer>()
-                list.add(123)
-                assert 123 == f.getFirstElement(list)
-            }
-        }
         '''
     }
 
+    @Test
     void testVariable() {
         assertScript '''
-        @groovy.transform.CompileStatic
-        public class Foo<T extends List<X>, X extends Number> {
-            X getFirstElement() {
-                def list = new ArrayList<Integer>()
-                list.add(123)
-                T t = list
-                X x = t.get(0)
-                return x
-            }
-
-            static void main(String[] args) {
-                def f = new Foo<ArrayList<Integer>, Integer>()
-                assert 123 == f.getFirstElement()
+            @groovy.transform.CompileStatic
+            class Foo<T extends List<X>, X extends Number> {
+                X getFirstElement() {
+                    def list = new ArrayList<Integer>()
+                    list.add(123)
+                    T t = list
+                    X x = t.get(0)
+                    return x
+                }
+
+                static main(args) {
+                    def f = new Foo<ArrayList<Integer>, Integer>()
+                    assert f.getFirstElement() == 123
+                }
             }
-        }
         '''
     }
 
+    @Test
     void testField() {
         assertScript '''
-        @groovy.transform.CompileStatic
-        public class Foo<T extends List<X>, X extends Number> {
-            T t
-
-            {
-                def list = new ArrayList<Integer>()
-                list.add(123)
-                t = list
-            }
-
-            X getFirstElement() {
-                X x = t.get(0)
-                return x
+            @groovy.transform.CompileStatic
+            class Foo<T extends List<X>, X extends Number> {
+                T t
+
+                {
+                    def list = new ArrayList<Integer>()
+                    list.add(123)
+                    t = list
+                }
+
+                X getFirstElement() {
+                    X x = t.get(0)
+                    return x
+                }
+
+                static main(args) {
+                    def f = new Foo<ArrayList<Integer>, Integer>()
+                    assert f.getFirstElement() == 123
+                }
             }
-
-            static void main(String[] args) {
-                def f = new Foo<ArrayList<Integer>, Integer>()
-                assert 123 == f.getFirstElement()
-            }
-        }
         '''
     }
 
+    @Test
     void testParameter2() {
         assertScript '''
-        @groovy.transform.CompileStatic
-        public class Foo<T extends List<X>, X extends Number> {
-            X getFirstElement(List<X> list) {
-                X x = list.get(0)
-
-                assert Number == x.getClass().getGenericSuperclass()
-
-                return x
-            }
-
-            Number getFirstNumber(T t) {
-                return getFirstElement(t)
+            @groovy.transform.CompileStatic
+            class Foo<T extends List<X>, X extends Number> {
+                X getFirstElement(List<X> list) {
+                    X x = list.get(0)
+                    assert Number == x.getClass().getGenericSuperclass()
+                    return x
+                }
+
+                Number getFirstNumber(T t) {
+                    return getFirstElement(t)
+                }
+
+                static main(args) {
+                    def f = new Foo<ArrayList<Integer>, Integer>()
+                    def list = new ArrayList<Integer>()
+                    list.add(123)
+                    assert f.getFirstNumber(list) == 123
+                }
             }
-
-            static void main(String[] args) {
-                def f = new Foo<ArrayList<Integer>, Integer>()
-                def list = new ArrayList<Integer>()
-                list.add(123)
-                assert 123 == f.getFirstNumber(list)
-            }
-        }
         '''
     }
 
+    @Test
     void testParameterAndVariable() {
         assertScript '''
-        @groovy.transform.CompileStatic
-        public class Foo<T extends List<X>, X extends Number> {
-            X getFirstElement(List<X> t) {
-                X x = t.get(0)
-                return x
+            @groovy.transform.CompileStatic
+            class Foo<T extends List<X>, X extends Number> {
+                X getFirstElement(List<X> t) {
+                    X x = t.get(0)
+                    return x
+                }
+
+                static main(args) {
+                    def f = new Foo<ArrayList<Integer>, Integer>()
+                    def list = new ArrayList<Integer>()
+                    list.add(123)
+                    assert f.getFirstElement(list) == 123
+                }
             }
-
-            static void main(String[] args) {
-                def f = new Foo<ArrayList<Integer>, Integer>()
-                def list = new ArrayList<Integer>()
-                list.add(123)
-                assert 123 == f.getFirstElement(list)
-            }
-        }
         '''
     }
-
 }


Mime
View raw message