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

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


The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
     new 674c94e867 GROOVY-10648: do not mix type parameter contexts when 
resolving
674c94e867 is described below

commit 674c94e8674ac1b08cd813ef613265c754d91909
Author: Eric Milles <[email protected]>
AuthorDate: Sat Mar 11 10:03:25 2023 -0600

    GROOVY-10648: do not mix type parameter contexts when resolving
    
      [1].stream().reduce(0, {r,e -> r + e})
          ^ Stream<Integer>   ^ ^ both Integer -- not int or unknown
    
      def <T extends Number> List<T> f(Class<T> t) {
        [t.newInstance(1)].stream().filter{n  ->  n.intValue() > 0}.toList()
                           ^ Stream<T ext Number> ^ T or Number not Object
    
    2_5_X backport
---
 .../codehaus/groovy/ast/tools/GenericsUtils.java   |   2 +
 .../transform/stc/StaticTypeCheckingSupport.java   |  60 +++---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 224 ++++++++++-----------
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 182 +++++++++--------
 .../transform/stc/TypeInferenceSTCTest.groovy      |   8 +-
 5 files changed, 248 insertions(+), 228 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 bc841f0645..8c4906dcb0 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -883,6 +883,8 @@ public class GenericsUtils {
 
     /**
      * Checks if the type has any placeholder (aka unresolved) generics.
+     * <p>
+     * Backported from 3.0.0
      *
      * @since 2.5.10
      */
diff --git 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
index 03433f68c7..cb024a3b4c 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1874,7 +1874,7 @@ public abstract class StaticTypeCheckingSupport {
         return newGTs;
     }
 
-    private static GenericsType applyGenericsContext(Map<GenericsTypeName, 
GenericsType> spec, GenericsType gt) {
+    private static GenericsType applyGenericsContext(final 
Map<GenericsTypeName, GenericsType> spec, final GenericsType gt) {
         if (gt.isPlaceholder()) {
             GenericsTypeName name = new GenericsTypeName(gt.getName());
             GenericsType specType = spec.get(name);
@@ -1895,7 +1895,9 @@ public abstract class StaticTypeCheckingSupport {
         if (type.isArray()) {
             newType = applyGenericsContext(spec, 
type.getComponentType()).makeArray();
         } else {
-            if (type.getGenericsTypes()==null) return gt;
+            if (type.getGenericsTypes() == null) {
+                return gt;
+            }
             newType = type.getPlainNodeReference();
             newType.setGenericsPlaceHolder(type.isGenericsPlaceHolder());
             newType.setGenericsTypes(applyGenericsContext(spec, 
type.getGenericsTypes()));
@@ -1903,13 +1905,18 @@ public abstract class StaticTypeCheckingSupport {
         return new GenericsType(newType);
     }
 
-    private static boolean hasNonTrivialBounds(GenericsType gt) {
+    private static boolean hasNonTrivialBounds(final GenericsType gt) {
+        if (gt.isWildcard()) {
+            return true;
+        }
+        if (gt.getLowerBound() != null) {
+            return true;
+        }
         ClassNode[] upperBounds = gt.getUpperBounds();
-        return gt.getLowerBound() != null || gt.isWildcard() ||
-                (upperBounds != null && (
-                        upperBounds.length != 1
-                                || upperBounds[0].isGenericsPlaceHolder()
-                                || !OBJECT_TYPE.equals(upperBounds[0])));
+        if (upperBounds != null) {
+            return (upperBounds.length != 1 || 
upperBounds[0].isGenericsPlaceHolder() || !OBJECT_TYPE.equals(upperBounds[0]));
+        }
+        return false;
     }
 
     static ClassNode[] applyGenericsContext(final Map<GenericsTypeName, 
GenericsType> spec, final ClassNode[] types) {
@@ -1929,27 +1936,30 @@ public abstract class StaticTypeCheckingSupport {
         if (type.isArray()) {
             return applyGenericsContext(spec, 
type.getComponentType()).makeArray();
         }
-        ClassNode newType = type.getPlainNodeReference();
-        GenericsType[] gt = type.getGenericsTypes();
-        if (spec != null) {
-            gt = applyGenericsContext(spec, gt);
-        }
-        newType.setGenericsTypes(gt);
-        if (type.isGenericsPlaceHolder()) {
-            boolean nonTrivial = hasNonTrivialBounds(gt[0]);
-            if (nonTrivial || !gt[0].isPlaceholder()) {
+
+        GenericsType[] gt = applyGenericsContext(spec, 
type.getGenericsTypes());
+
+        boolean typeVariable = type.isGenericsPlaceHolder();
+        if (typeVariable) {
+            if (!gt[0].isPlaceholder() || hasNonTrivialBounds(gt[0])) {
                 return getCombinedBoundType(gt[0]);
             }
-            String placeholderName = gt[0].getName();
-            if (!placeholderName.equals(newType.getUnresolvedName())) {
-                ClassNode clean = make(placeholderName);
-                clean.setGenericsTypes(gt);
-                clean.setRedirect(newType);
-                newType = clean;
+            String gt_name = gt[0].getName();
+            ClassNode gt_type = gt[0].getType();
+            if (!type.getUnresolvedName().equals(gt_name) || 
!type.equals(gt_type)) {
+                ClassNode cn = !gt_name.equals(gt_type.getName()) ? gt_type : 
type;
+                ClassNode tp = make(gt_name);
+                tp.setRedirect(cn);
+                tp.setGenericsTypes(gt);
+                tp.setGenericsPlaceHolder(true);
+                return tp;
             }
-            newType.setGenericsPlaceHolder(true);
         }
-        return newType;
+
+        ClassNode cn = type.getPlainNodeReference();
+        cn.setGenericsPlaceHolder(typeVariable);
+        cn.setGenericsTypes(gt);
+        return cn;
     }
 
     static ClassNode getCombinedBoundType(GenericsType genericsType) {
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 ffc67db72c..50e83b5b21 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -21,6 +21,7 @@ package org.codehaus.groovy.transform.stc;
 import groovy.lang.Closure;
 import groovy.lang.DelegatesTo;
 import groovy.lang.IntRange;
+import groovy.lang.Tuple2;
 import groovy.transform.NamedParam;
 import groovy.transform.NamedParams;
 import groovy.transform.TypeChecked;
@@ -238,6 +239,7 @@ import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.extrac
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findDGMMethodsForClassNode;
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findSetters;
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findTargetVariable;
+import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.fullyResolve;
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.fullyResolveType;
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getCombinedBoundType;
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getGenericsWithoutArray;
@@ -1033,15 +1035,9 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         if (rhsExpression instanceof ClosureExpression) {
             MethodNode abstractMethod = findSAM(lhsType);
             ClosureExpression closure = (ClosureExpression) rhsExpression;
-            Map<GenericsType, GenericsType> mappings = 
GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(abstractMethod.getDeclaringClass(),
 lhsType);
-
-            ClassNode[] samParameterTypes = 
extractTypesFromParameters(abstractMethod.getParameters());
-            for (int i = 0; i < samParameterTypes.length; i += 1) {
-                if (samParameterTypes[i].isGenericsPlaceHolder()) {
-                    samParameterTypes[i] = 
GenericsUtils.findActualTypeByGenericsPlaceholderName(samParameterTypes[i].getUnresolvedName(),
 mappings);
-                }
-            }
+            Tuple2<ClassNode[], ClassNode> signature = 
parameterizeSAM(abstractMethod, lhsType);
 
+            ClassNode[] samParameterTypes = signature.getFirst();
             Parameter[] closureParameters = getParametersSafe(closure);
             if (samParameterTypes.length == 1 && 
hasImplicitParameter(closure)) {
                 Variable it = 
closure.getVariableScope().getDeclaredVariable("it"); // GROOVY-7141
@@ -1057,15 +1053,11 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
                     }
                 }
             } else {
-                String descriptor = 
toMethodParametersString(findSAM(lhsType).getName(), samParameterTypes);
+                String descriptor = 
toMethodParametersString(abstractMethod.getName(), samParameterTypes);
                 addStaticTypeError("Wrong number of parameters for method 
target " + descriptor, rhsExpression);
             }
 
-            ClassNode returnType = abstractMethod.getReturnType();
-            if (returnType.isGenericsPlaceHolder()) {
-                returnType = 
GenericsUtils.findActualTypeByGenericsPlaceholderName(returnType.getUnresolvedName(),
 mappings);
-            }
-            storeInferredReturnType(rhsExpression, returnType);
+            storeInferredReturnType(rhsExpression, signature.getSecond());
 
         } else if (rhsExpression instanceof MapExpression) { // GROOVY-7141
             List<MapEntryExpression> spec = ((MapExpression) 
rhsExpression).getMapEntryExpressions();
@@ -1076,6 +1068,23 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         }
     }
 
+    // Backported from 3.0.0
+    private static Tuple2<ClassNode[], ClassNode> parameterizeSAM(final 
MethodNode abstractMethod, final ClassNode targetType) {
+        Map<GenericsType, GenericsType> mappings = 
GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(abstractMethod.getDeclaringClass(),
 targetType);
+
+        ClassNode[] paramTypes = 
extractTypesFromParameters(abstractMethod.getParameters());
+        for (int i = 0, n = paramTypes.length; i < n; i += 1) {
+            if (paramTypes[i].isGenericsPlaceHolder())
+                paramTypes[i] = 
GenericsUtils.findActualTypeByGenericsPlaceholderName(paramTypes[i].getUnresolvedName(),
 mappings);
+        }
+
+        ClassNode returnType = abstractMethod.getReturnType();
+        if (returnType.isGenericsPlaceHolder())
+            returnType = 
GenericsUtils.findActualTypeByGenericsPlaceholderName(returnType.getUnresolvedName(),
 mappings);
+
+        return new Tuple2<ClassNode[], ClassNode>(paramTypes, returnType);
+    }
+
     private static boolean isCompoundAssignment(final Expression exp) {
         if (!(exp instanceof BinaryExpression)) return false;
         int type = ((BinaryExpression) exp).getOperation().getType();
@@ -2990,7 +2999,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         if (typeX != null) {
             expectedType = typeX.getType();
         }
-        if (!entries.keySet().contains(name)) {
+        if (!entries.containsKey(name)) {
             if (required) {
                 addStaticTypeError("required named param '" + name + "' not 
found.", expression);
             }
@@ -3015,118 +3024,108 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
     }
 
     /**
-     * This method is responsible for performing type inference on closure 
argument types whenever code like this is
-     * found: <code>foo.collect { it.toUpperCase() }</code>.
-     * In this case, the type checker tries to find if the 
<code>collect</code> method has its {@link Closure} argument
-     * annotated with {@link groovy.transform.stc.ClosureParams}. If yes, then 
additional type inference can be performed
-     * and the type of <code>it</code> may be inferred.
+     * Performs type inference on closure argument types whenever code like 
this
+     * is found: <code>foo.collect { it.toUpperCase() }</code>.
+     * <p>
+     * In this case the type checker tries to find if the {@code collect} 
method
+     * has its {@link Closure} argument annotated with {@link ClosureParams}. 
If
+     * so, then additional type inference can be performed and the type of
+     * {@code it} may be inferred.
      *
      * @param receiver
      * @param arguments
-     * @param expression     a closure expression for which the argument types 
should be inferred
-     * @param param          the parameter where to look for a {@link 
groovy.transform.stc.ClosureParams} annotation.
-     * @param selectedMethod the method accepting a closure
+     * @param expression closure or lambda expression for which the argument 
types should be inferred
+     * @param target     parameter which may provide {@link ClosureParams} 
annotation or SAM type
+     * @param method     method that declares {@code target}
      */
-    protected void inferClosureParameterTypes(final ClassNode receiver, final 
Expression arguments, final ClosureExpression expression, final Parameter 
param, final MethodNode selectedMethod) {
-        List<AnnotationNode> annotations = 
param.getAnnotations(CLOSUREPARAMS_CLASSNODE);
+    protected void inferClosureParameterTypes(final ClassNode receiver, final 
Expression arguments, final ClosureExpression expression, final Parameter 
target, final MethodNode method) {
+        MethodNode abstractMethod;
+        List<AnnotationNode> annotations = 
target.getAnnotations(CLOSUREPARAMS_CLASSNODE);
         if (annotations != null && !annotations.isEmpty()) {
             for (AnnotationNode annotation : annotations) {
                 Expression hintClass = annotation.getMember("value");
                 if (hintClass instanceof ClassExpression) {
                     Expression options = annotation.getMember("options");
                     Expression resolverClass = 
annotation.getMember("conflictResolutionStrategy");
-                    doInferClosureParameterTypes(receiver, arguments, 
expression, selectedMethod, hintClass, resolverClass, options);
+                    doInferClosureParameterTypes(receiver, arguments, 
expression, method, hintClass, resolverClass, options);
                 }
             }
-        } else if (isSAMType(param.getOriginType())) {
-            // SAM coercion
-            inferSAMType(param, receiver, selectedMethod, 
InvocationWriter.makeArgumentList(arguments), expression);
-        }
-    }
-
-    private void inferSAMType(Parameter param, ClassNode receiver, MethodNode 
methodWithSAMParameter, ArgumentListExpression originalMethodCallArguments, 
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;
-        if (methodWithSAMParameter.isStatic()) {
-            targetMethodDeclarationClassConnections = new 
HashMap<GenericsTypeName, GenericsType>();
-        } else {
-            targetMethodDeclarationClassConnections = 
extractPlaceHolders(receiver, getDeclaringClass(methodWithSAMParameter, 
originalMethodCallArguments));
-        }
-        // then we use the method with the SAM parameter to get more 
information about the declaration
-        Parameter[] parametersOfMethodContainingSAM = 
methodWithSAMParameter.getParameters();
-        for (int i = 0, n = parametersOfMethodContainingSAM.length; i < n; i 
+= 1) {
-            // potentially skip empty varargs
-            if (i == n - 1
-                    && i == originalMethodCallArguments.getExpressions().size()
-                    && parametersOfMethodContainingSAM[i].getType().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);
-        }
-
-        // 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<GenericsTypeName, GenericsType>();
-        ClassNode classForSAM = paramTypeWithReceiverInformation.redirect();
-        extractGenericsConnections(SAMTypeConnections, 
paramTypeWithReceiverInformation, classForSAM);
-
-        // 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 = (ClassNode[]) 
openBlock.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
-        if (blockParameterTypes == 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) {
-                // implicit it
-                blockParameterTypes = parameterTypesForSAM;
+        } else if ((abstractMethod = findSAM(target.getOriginType())) != null) 
{
+            Map<GenericsTypeName, GenericsType> context;
+            if (method.isStatic()) {
+                context = new HashMap<GenericsTypeName, GenericsType>();
             } else {
-                blockParameterTypes = new ClassNode[p.length];
-                for (int i = 0; i < p.length; i++) {
-                    if (p[i] != null && !p[i].isDynamicTyped()) {
-                        blockParameterTypes[i] = p[i].getType();
-                    } else {
-                        blockParameterTypes[i] = 
typeOrNull(parameterTypesForSAM, i);
+                context = extractPlaceHoldersVisibleToDeclaration(receiver, 
method, arguments);
+            }
+            GenericsType[] typeParameters = method instanceof ConstructorNode 
? method.getDeclaringClass().getGenericsTypes() : applyGenericsContext(context, 
method.getGenericsTypes());
+
+            if (typeParameters != null) {
+                boolean typeParametersResolved = false;
+                // first check for explicit type arguments
+                Expression emc = typeCheckingContext.getEnclosingMethodCall();
+                if (emc instanceof MethodCallExpression) {
+                    MethodCallExpression mce = (MethodCallExpression) emc;
+                    if (mce.getArguments() == arguments) {
+                        GenericsType[] typeArguments = mce.getGenericsTypes();
+                        if (typeArguments != null) {
+                            int n = typeParameters.length;
+                            if (n == typeArguments.length) {
+                                typeParametersResolved = true;
+                                for (int i = 0; i < n; i += 1) {
+                                    context.put(new 
GenericsTypeName(typeParameters[i].getName()), typeArguments[i]);
+                                }
+                            }
+                        }
+                    }
+                }
+                if (!typeParametersResolved) {
+                    // check for implicit type arguments
+                    int i = -1; Parameter[] p = method.getParameters();
+                    for (Expression argument : (TupleExpression) arguments) { 
i += 1;
+                        if (argument instanceof ClosureExpression || 
isNullConstant(argument)) continue;
+
+                        ClassNode pType = p[Math.min(i, p.length - 
1)].getType();
+                        Map<GenericsTypeName, GenericsType> gc = new 
HashMap<>();
+                        extractGenericsConnections(gc, 
wrapTypeIfNecessary(getType(argument)), pType);
+
+                        for (Map.Entry<GenericsTypeName, GenericsType> entry : 
gc.entrySet()) {
+                            for (GenericsType tp : typeParameters) {
+                                GenericsTypeName name = entry.getKey();
+                                if (tp.getName().equals(name.getName()) && 
!context.containsKey(name)) {
+                                    context.put(name, entry.getValue());
+                                    break;
+                                }
+                            }
+                        }
+                    }
+
+                    for (GenericsType tp : typeParameters) {
+                        GenericsTypeName name = new 
GenericsTypeName(tp.getName());
+                        if (!context.containsKey(name)) context.put(name, 
fullyResolve(tp, context));
                     }
                 }
             }
-        }
-        for (int i = 0; i < blockParameterTypes.length; i++) {
-            extractGenericsConnections(SAMTypeConnections, 
blockParameterTypes[i], typeOrNull(parameterTypesForSAM, i));
-        }
 
-        // and finally we 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;
-        }
-        openBlock.putNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS, 
blockParameterTypes);
-    }
+            ClassNode[] samParamTypes = parameterizeSAM(abstractMethod, 
applyGenericsContext(context, target.getType())).getFirst();
 
-    private ClassNode typeOrNull(ClassNode[] parameterTypesForSAM, int i) {
-        return i < parameterTypesForSAM.length ? parameterTypesForSAM[i] : 
null;
+            ClassNode[] paramTypes = 
expression.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
+            if (paramTypes == null) {
+                int n; Parameter[] p = expression.getParameters();
+                if (p == null) {
+                    // zero parameters
+                    paramTypes = ClassNode.EMPTY_ARRAY;
+                } else if ((n = p.length) == 0) {
+                    // implicit parameter(s)
+                    paramTypes = samParamTypes;
+                } else {
+                    paramTypes = new ClassNode[n];
+                    for (int i = 0; i < n; i += 1) {
+                        paramTypes[i] = !p[i].isDynamicTyped() ? 
p[i].getOriginType() : (i < samParamTypes.length ? samParamTypes[i] : null);
+                    }
+                }
+                
expression.putNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS, paramTypes);
+            }
+        }
     }
 
     private List<ClassNode[]> getSignaturesFromHint(final ClosureExpression 
expression, final MethodNode selectedMethod, final Expression hintClass, final 
Expression options) {
@@ -3244,12 +3243,9 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
                             addError("Incorrect number of parameters. Expected 
" + inferred.length + " but found " + closureParams.length, expression);
                         }
                     }
-                    boolean lastArg = i == (n - 1);
-
-                    if (!typeCheckMethodArgumentWithGenerics(originType, 
inferredType, lastArg)) {
-                        addError("Expected parameter of type " + 
inferredType.toString(false) + " but got " + originType.toString(false), 
closureParam.getType());
+                    if (!typeCheckMethodArgumentWithGenerics(originType, 
inferredType, i == n-1)) {
+                        addError("Expected parameter of type " + 
prettyPrintType(inferredType) + " but got " + prettyPrintType(originType), 
closureParam.getType());
                     }
-
                     
typeCheckingContext.controlStructureVariables.put(closureParam, inferredType);
                 }
             }
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy 
b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index d7768e04be..3c8ce122d7 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -165,10 +165,10 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     void testReturnTypeInference2() {
         assertScript '''
-        Object m() {
-          def s = '1234'
-          println 'Hello'
-        }
+            Object m() {
+              def s = '1234'
+              println 'Hello'
+            }
         '''
     }
 
@@ -308,7 +308,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
                 Collections.singleton(x.newInstance(42))
             }
             def <T extends Number> List<T> g(Class<T> t) {
-                f(t).stream().filter{n -> n.intValue() > 0}.toList()
+                f(t).stream().filter{it.intValue() > 0}.toList()
             }
 
             def result = g(Integer)
@@ -316,6 +316,53 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-10053
+    @NotYetImplemented
+    void testReturnTypeInferenceWithMethodGenericsA() {
+        if (!GroovyAssert.isAtLeastJdk('1.8')) return
+
+        for (cast in ['t.&cast', '{ n -> t.cast(n) }', '{ n -> (N) n }']) {
+            assertScript """
+                Set<Number> f() {
+                    Collections.<Number>singleton(42)
+                }
+                def <N extends Number> Set<N> g(Class<N> t) {
+                    Set<N> result = new HashSet<>()
+                    f().stream().filter(t.&isInstance)
+                        .map($cast).forEach{result.add(it)}
+                    return result
+                }
+
+                def result = g(Integer)
+                assert result == [42] as Set
+            """
+        }
+    }
+
+    @NotYetImplemented
+    void testReturnTypeInferenceWithMethodGenericsB() {
+        if (!GroovyAssert.isAtLeastJdk('1.8')) return
+
+        assertScript '''
+            def <T> String test(Iterable<T> iterable) {
+                Iterator<T> it = iterable.iterator()
+                if (it.hasNext()) {
+                    List<String[]> table = []
+                    it.forEachRemaining { r ->
+                        if (r instanceof List) {
+                            String[] cells = ((List) 
r).stream().map{it?.toString()}
+                            table.add(cells)
+                        }
+                    }
+                    return table
+                }
+            }
+
+            String result = test([ ['x'], ['y'], [null] ])
+            assert result == '[[x], [y], [null]]'
+        '''
+    }
+
     // GROOVY-10051
     void testReturnTypeInferenceWithMethodGenerics10() {
         assertScript '''
@@ -423,10 +470,9 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9064
-    @NotYetImplemented
     void testReturnTypeInferenceWithMethodGenerics13() {
         assertScript '''
-            List getSomeRows() { [new String[]{'x'}] }
+            List getSomeRows() { [['x'] as String[]] }
             List<String[]> rows = getSomeRows()
             rows.each { row ->
                 def col = row[0].toUpperCase()
@@ -495,7 +541,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
               T p
               T m() {
                 Closure<T> x = { -> p }
-                x() // Cannot return value of type Object for method returning 
type T
+                x() // Cannot return value of type Object for method returning 
T
               }
             }
             assert new C<>(42).m() == 42
@@ -1250,7 +1296,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             class B<T1 extends Number, T2 extends A<C, ? extends T1>> {
                 T2 t
                 B(T2 t) {
-                    this.t  = t
+                    this.t = t
                 }
             }
             class C {
@@ -2190,93 +2236,65 @@ class GenericsSTCTest extends 
StaticTypeCheckingTestCase {
     // GROOVY-5415
     void testShouldUseMethodGenericType1() {
         assertScript '''import groovy.transform.stc.GenericsSTCTest.ClassA
-        class ClassB {
-            void bar() {
-                def ClassA<Long> a = new ClassA<Long>();
-                a.foo(this.getClass());
+            class ClassB {
+                void test() {
+                    def ClassA<Long> a = new ClassA<Long>()
+                    a.foo(this.getClass())
+                }
             }
-        }
-        new ClassB()
+            new ClassB().test()
         '''
     }
 
     // GROOVY-5415
     void testShouldUseMethodGenericType2() {
         shouldFailWithMessages '''import 
groovy.transform.stc.GenericsSTCTest.ClassA
-        class ClassB {
-            void bar() {
-                def ClassA<Long> a = new ClassA<Long>();
-                a.bar(this.getClass());
+            class ClassB {
+                void test() {
+                    def ClassA<Long> a = new ClassA<Long>()
+                    a.bar(this.getClass())
+                }
             }
-        }
-        new ClassB()
         ''',
         'Cannot call <X> groovy.transform.stc.GenericsSTCTest$ClassA 
<Long>#bar(java.lang.Class <Long>) with arguments [java.lang.Class <? extends 
java.lang.Object>]'
     }
 
     // GROOVY-8961
     void testShouldUseMethodGenericType3() {
-        assertScript '''
-            void setM(List<String> strings) {
-            }
-            void test() {
-              m = Collections.emptyList() // Cannot assign value of type 
List<T> to variable of List<String>
-            }
-            test()
-        '''
-        assertScript '''
-            void setM(Collection<String> strings) {
-            }
-            void test() {
-              m = Collections.emptyList()
-            }
-            test()
-        '''
-        assertScript '''
-            void setM(Iterable<String> strings) {
-            }
-            void test() {
-              m = Collections.emptyList()
-            }
-            test()
-        '''
-
-        shouldFailWithMessages '''
-            void setM(List<String> strings) {
+        for (mode in ['', 'static']) {
+            for (type in ['List', 'Collection', 'Iterable']) {
+                assertScript """
+                    $mode void setX(${type}<String> strings) { }
+                    x = Collections.emptyList()
+                """
             }
-            void test() {
-              m = Collections.<Integer>emptyList()
-            }
-        ''',
-        'Cannot assign value of type java.util.List <Integer> to variable of 
type java.util.List <String>'
+            shouldFailWithMessages """
+                $mode void setX(List<String> strings) { }
+                x = Collections.<Integer>emptyList()
+            """,
+            'Cannot assign value of type java.util.List <Integer> to variable 
of type java.util.List <String>'
+        }
     }
 
     // GROOVY-9734
     void testShouldUseMethodGenericType4() {
-        assertScript '''
-            void m(List<String> strings) {
-            }
-            void test() {
-              m(Collections.emptyList()) // Cannot call m(List<String>) with 
arguments [List<T>]
-            }
-            test()
-        '''
-        assertScript '''
-            void m(Collection<String> strings) {
-            }
-            void test() {
-              m(Collections.emptyList())
-            }
-            test()
-        '''
-        assertScript '''
-            void m(Iterable<String> strings) {
-            }
-            void test() {
-              m(Collections.emptyList())
-            }
-            test()
-        '''
+        for (type in ['List', 'Collection', 'Iterable']) {
+            assertScript """
+                def m(${type}<String> strings) { }
+                m(Collections.emptyList())
+            """
+        }
+    }
+
+    // GROOVY-9734
+    @NotYetImplemented
+    void testShouldUseMethodGenericType4a() {
+        for (type in ['List', 'Collection', 'Iterable']) {
+            assertScript """
+                static m(${type}<String> strings) { }
+                m(Collections.emptyList())
+            """
+        }
     }
 
     // GROOVY-9751
@@ -2529,7 +2547,6 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10648
-    @NotYetImplemented
     void testShouldUseMethodGenericType16() {
         assertScript '''
             def <T extends Number> Set<T> test(Iterable<T> iterable) {
@@ -2570,22 +2587,22 @@ class GenericsSTCTest extends 
StaticTypeCheckingTestCase {
     void testAddAllWithCollectionShouldBeAllowed() {
         assertScript '''import 
org.codehaus.groovy.transform.stc.ExtensionMethodNode
             List<String> list = ['a','b','c']
-            Collection<String> e = list.findAll { it }
+            Collection<String> strings = list.findAll { it }
             @ASTTest(phase=INSTRUCTION_SELECTION, value={
                 def dmt = 
node.rightExpression.getNodeMetaData(DIRECT_METHOD_CALL_TARGET)
                 assert dmt.declaringClass.implementsInterface(LIST_TYPE)
                 assert !(dmt instanceof ExtensionMethodNode)
                 assert dmt.name == 'addAll'
             })
-            boolean r = list.addAll(e)
+            boolean r = list.addAll(strings)
         '''
     }
 
     void testAddAllWithCollectionShouldNotBeAllowed() {
         shouldFailWithMessages '''
             List<String> list = ['a','b','c']
-            Collection<Integer> e = (Collection<Integer>) [1,2,3]
-            boolean r = list.addAll(e)
+            Collection<Integer> numbers = (Collection<Integer>) [1,2,3]
+            boolean r = list.addAll(numbers)
         ''',
         'Cannot call java.util.ArrayList 
<java.lang.String>#addAll(java.util.Collection <? extends java.lang.String>) 
with arguments [java.util.Collection <Integer>]'
     }
@@ -2794,7 +2811,6 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
             r.bindings2['a'] = 'A'
             r.bindings2.put('b', 'B')
-
         '''
     }
     void testInferDiamondForAssignment() {
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy 
b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index d4fe1c834f..87e985c935 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -1318,11 +1318,7 @@ class TypeInferenceSTCTest extends 
StaticTypeCheckingTestCase {
     // GROOVY-9077
     void testInferredTypeForPropertyThatResolvesToMethod() {
         assertScript '''
-            import groovy.transform.*
-            import static 
org.codehaus.groovy.transform.stc.StaticTypesMarker.DIRECT_METHOD_CALL_TARGET
-
-            @CompileStatic
-            void meth() {
+            void test() {
                 def items = [1, 2] as LinkedList
 
                 @ASTTest(phase=INSTRUCTION_SELECTION, value={
@@ -1344,7 +1340,7 @@ class TypeInferenceSTCTest extends 
StaticTypeCheckingTestCase {
                 def alsoOne = items.peek()
             }
 
-            meth()
+            test()
         '''
     }
 


Reply via email to