groovy git commit: GROOVY-8241 SAM parameter type inference for explicit parameter (closes #643)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

groovy git commit: GROOVY-8241 SAM parameter type inference for explicit parameter (closes #643)

Daniel.Sun
Repository: groovy
Updated Branches:
  refs/heads/GROOVY_2_4_X 3b66ce77c -> 714fb1053


GROOVY-8241 SAM parameter type inference for explicit parameter (closes #643)

(cherry picked from commit 46309e8)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/714fb105
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/714fb105
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/714fb105

Branch: refs/heads/GROOVY_2_4_X
Commit: 714fb10537397d5108fb7950ec80800dac9cbca8
Parents: 3b66ce7
Author: sunlan <[hidden email]>
Authored: Wed Dec 13 12:50:41 2017 +0800
Committer: sunlan <[hidden email]>
Committed: Wed Dec 13 12:53:21 2017 +0800

----------------------------------------------------------------------
 .../stc/StaticTypeCheckingVisitor.java          |  89 +++++++++------
 src/spec/test/typing/TypeCheckingTest.groovy    |   6 +-
 .../transform/stc/MethodCallsSTCTest.groovy     | 111 +++++++++++++++++++
 3 files changed, 172 insertions(+), 34 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/714fb105/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index b7f9aff..93ea99c 100644
--- a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -2584,7 +2584,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 // implicit it
                 blockParameterTypes = parameterTypesForSAM;
             } else {
-                blockParameterTypes = extractTypesFromParameters(p);
+                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);
+                    }
+                }
             }
         }
         for (int i=0; i<blockParameterTypes.length; i++) {
@@ -4212,19 +4219,22 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
     }
 
-    protected ClassNode getType(ASTNode exp) {
+    protected ClassNode getType(final ASTNode exp) {
         ClassNode cn = exp.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
-        if (cn != null) return cn;
+        if (cn != null) {
+            return cn;
+        }
         if (exp instanceof ClassExpression) {
             ClassNode node = CLASS_Type.getPlainNodeReference();
             node.setGenericsTypes(new GenericsType[]{
                     new GenericsType(((ClassExpression) exp).getType())
             });
             return node;
-        } else if (exp instanceof VariableExpression) {
-            VariableExpression vexp = (VariableExpression) exp;
+        }
+        if (exp instanceof VariableExpression) {
+            final VariableExpression vexp = (VariableExpression) exp;
             ClassNode selfTrait = isTraitSelf(vexp);
-            if (selfTrait!=null) return makeSelf(selfTrait);
+            if (selfTrait != null) return makeSelf(selfTrait);
             if (vexp == VariableExpression.THIS_EXPRESSION) return makeThis();
             if (vexp == VariableExpression.SUPER_EXPRESSION) return makeSuper();
             final Variable variable = vexp.getAccessedVariable();
@@ -4245,24 +4255,22 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 }
                 // now check for closure override
                 TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
-                ClassNode[] closureParamTypes = (ClassNode[])(enclosingClosure!=null?enclosingClosure.getClosureExpression().getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS):null);
-                if (type==null && enclosingClosure !=null && "it".equals(variable.getName()) && closureParamTypes!=null) {
-                    final Parameter[] parameters = enclosingClosure.getClosureExpression().getParameters();
-                    if (parameters.length == 0 && temporaryTypesForExpression == null && closureParamTypes.length != 0) {
-                        type = closureParamTypes[0];
-                    }
+                if (type == null && enclosingClosure != null && temporaryTypesForExpression == null) {
+                    type = getTypeFromClosureArguments(parameter, enclosingClosure);
                 }
                 if (type != null) {
-                    storeType((VariableExpression)exp, type);
+                    storeType(vexp, type);
                     return type;
                 }
                 return getType((Parameter) variable);
             }
+            return vexp.getOriginType();
         }
 
         if (exp instanceof ListExpression) {
             return inferListExpressionType((ListExpression) exp);
-        } else if (exp instanceof MapExpression) {
+        }
+        if (exp instanceof MapExpression) {
             return inferMapExpressionType((MapExpression) exp);
         }
         if (exp instanceof ConstructorCallExpression) {
@@ -4275,15 +4283,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             ClassNode ret = getInferredReturnType(exp);
             return ret != null ? ret : ((MethodNode) exp).getReturnType();
         }
-        if (exp instanceof ClosureExpression) {
-            ClassNode irt = getInferredReturnType(exp);
-            if (irt != null) {
-                irt = wrapTypeIfNecessary(irt);
-                ClassNode result = CLOSURE_TYPE.getPlainNodeReference();
-                result.setGenericsTypes(new GenericsType[]{new GenericsType(irt)});
-                return result;
-            }
-        }
         if (exp instanceof RangeExpression) {
             ClassNode plain = ClassHelper.RANGE_TYPE.getPlainNodeReference();
             RangeExpression re = (RangeExpression) exp;
@@ -4309,12 +4308,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         if (exp instanceof BitwiseNegationExpression) {
             return getType(((BitwiseNegationExpression) exp).getExpression());
         }
-        if (exp instanceof MethodCall) {
-            MethodNode target = (MethodNode) exp.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
-            if (target!=null) {
-                return getType(target);
-            }
-        }
         if (exp instanceof Parameter) {
             return ((Parameter) exp).getOriginType();
         }
@@ -4326,7 +4319,41 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             PropertyNode pn = (PropertyNode) exp;
             return getGenericsResolvedTypeOfFieldOrProperty(pn, pn.getOriginType());
         }
-        return exp instanceof VariableExpression ? ((VariableExpression) exp).getOriginType() : ((Expression) exp).getType();
+        if (exp instanceof ClosureExpression) {
+            ClassNode irt = getInferredReturnType(exp);
+            if (irt != null) {
+                irt = wrapTypeIfNecessary(irt);
+                ClassNode result = CLOSURE_TYPE.getPlainNodeReference();
+                result.setGenericsTypes(new GenericsType[]{new GenericsType(irt)});
+                return result;
+            }
+        } else if (exp instanceof MethodCall) {
+            MethodNode target = (MethodNode) exp.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
+            if (target != null) {
+                return getType(target);
+            }
+        }
+        return ((Expression) exp).getType();
+    }
+
+    private ClassNode getTypeFromClosureArguments(Parameter parameter, TypeCheckingContext.EnclosingClosure enclosingClosure) {
+        ClosureExpression closureExpression = enclosingClosure.getClosureExpression();
+        ClassNode[] closureParamTypes = (ClassNode[]) closureExpression.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS);
+        if (closureParamTypes == null) return null;
+        final Parameter[] parameters = closureExpression.getParameters();
+        String name = parameter.getName();
+
+        if (parameters.length == 0) {
+            return "it".equals(name) && closureParamTypes.length != 0 ? closureParamTypes[0] : null;
+        }
+
+        for (int index = 0; index < parameters.length; index++) {
+            if (name.equals(parameters[index].getName())) {
+                return closureParamTypes.length > index ? closureParamTypes[index] : null;
+            }
+        }
+
+        return null;
     }
 
     /**
@@ -4896,7 +4923,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         if (isClassClassNodeWrappingConcreteType(receiver)) {
             receiver = receiver.getGenericsTypes()[0].getType();
         }
-        addStaticTypeError("Cannot find matching method " + receiver.getText() + "#" + toMethodParametersString(name, args) + ". Please check if the declared type is right and if the method exists.", call);
+        addStaticTypeError("Cannot find matching method " + receiver.getText() + "#" + toMethodParametersString(name, args) + ". Please check if the declared type is correct and if the method exists.", call);
     }
 
     protected void addAmbiguousErrorMessage(final List<MethodNode> foundMethods, final String name, final ClassNode[] args, final Expression expr) {

http://git-wip-us.apache.org/repos/asf/groovy/blob/714fb105/src/spec/test/typing/TypeCheckingTest.groovy
----------------------------------------------------------------------
diff --git a/src/spec/test/typing/TypeCheckingTest.groovy b/src/spec/test/typing/TypeCheckingTest.groovy
index d22cce5..f32ca3f 100644
--- a/src/spec/test/typing/TypeCheckingTest.groovy
+++ b/src/spec/test/typing/TypeCheckingTest.groovy
@@ -300,7 +300,7 @@ class TypeCheckingTest extends StaticTypeCheckingTestCase {
             // tag::stc_argparam_array_fail[]
             format([1,2] as int[])              // fails
             // end::stc_argparam_array_fail[]
-        ''', '#format(int[]). Please check if the declared type is right and if the method exists.'
+        ''', '#format(int[]). Please check if the declared type is correct and if the method exists.'
 
 
         assertScript '''
@@ -319,7 +319,7 @@ class TypeCheckingTest extends StaticTypeCheckingTestCase {
             }
             format(new ArrayList())              // fails
             // end::stc_argparam_superclass_fail[]
-        ''', '#format(java.util.ArrayList). Please check if the declared type is right and if the method exists.'
+        ''', '#format(java.util.ArrayList). Please check if the declared type is correct and if the method exists.'
 
         assertScript '''
             // tag::stc_argparam_interface[]
@@ -337,7 +337,7 @@ class TypeCheckingTest extends StaticTypeCheckingTestCase {
             }
             format(new LinkedList())                 // fails
             // end::stc_argparam_interface_fail[]
-        ''', '#format(java.util.LinkedList). Please check if the declared type is right and if the method exists.'
+        ''', '#format(java.util.LinkedList). Please check if the declared type is correct and if the method exists.'
 
         assertScript '''
             // tag::stc_argparam_prim[]

http://git-wip-us.apache.org/repos/asf/groovy/blob/714fb105/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
index d7c6573..15c85cc 100644
--- a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
@@ -364,6 +364,29 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {
             '''
     }
 
+    void testShouldNotFailThanksToInstanceOfChecksAndWithoutExplicitCasts2() {
+        assertScript '''
+                static String foo(String s) {
+                    'String'
+                }
+                static String foo(Integer s) {
+                    'Integer'
+                }
+                static String foo(Boolean s) {
+                    'Boolean'
+                }
+                ['foo',123,true].each { argument ->
+                    if (argument instanceof String) {
+                        foo(argument)
+                    } else if (argument instanceof Boolean) {
+                        foo(argument)
+                    } else if (argument instanceof Integer) {
+                        foo(argument)
+                    }
+                }
+            '''
+    }
+
     void testShouldFailWithMultiplePossibleMethods() {
         shouldFailWithMessages '''
                 static String foo(String s) {
@@ -383,6 +406,94 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {
             ''', 'Reference to method is ambiguous'
     }
 
+    void testShouldFailWithMultiplePossibleMethods2() {
+        shouldFailWithMessages '''
+                static String foo(String s) {
+                    'String'
+                }
+                static String foo(Integer s) {
+                    'Integer'
+                }
+                static String foo(Boolean s) {
+                    'Boolean'
+                }
+                ['foo',123,true].each { argument ->
+                    if (argument instanceof String || argument instanceof Boolean || argument instanceof Integer) {
+                        foo(argument)
+                    }
+                }
+            ''', 'Reference to method is ambiguous'
+    }
+
+    void testInstanceOfOnExplicitParameter() {
+        assertScript '''
+                1.with { obj ->
+                    if (obj instanceof String) {
+                        obj.toUpperCase()
+                    }
+                }
+            '''
+    }
+
+    void testSAMWithExplicitParameter() {
+        assertScript '''
+            public interface SAM {
+                boolean run(String var1, Thread th);
+            }
+            
+            static boolean foo(SAM sam) {
+               sam.run("foo",  new Thread())
+            }
+            
+            static def callSAM() {
+                foo { str, th ->
+                    str.toUpperCase().equals(th.getName())
+                }
+            }
+            '''
+    }
+
+    void testGroovy8241() {
+        assertScript '''
+            import java.util.function.Predicate
+            
+            static boolean foo(Predicate<? super String> p) {
+                p.test("foo")
+            }
+            
+            static def testPredicate() {
+                foo { it ->
+                    it.toUpperCase()
+                    true
+                }
+            }
+            '''
+    }
+
+    void testGroovy7061() {
+        assertScript '''
+            void doIt() {
+                List<Integer> nums = [1, 2, 3, -2, -5, 6]
+                Collections.sort(nums, { a, b -> a.abs() <=> b.abs() })
+            }
+            '''
+    }
+
+    void testGroovy7061ex2() {
+        assertScript '''
+            def doIt(List<String> strings) {
+                return strings.
+                    stream().
+                    filter { s -> s.length() < 10 }.
+                    toArray()
+            }
+            
+            final words = ["orange", "sit", "test", "flabbergasted", "honorific"]
+            
+            println doIt(words)
+            '''
+    }
+
     void testShouldFailBecauseVariableIsReassigned() {
         shouldFailWithMessages '''
                 static String foo(String s) {