You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2017/12/13 03:27:21 UTC

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

Repository: groovy
Updated Branches:
  refs/heads/master 22e45ebe2 -> bd5191d9a


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


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

Branch: refs/heads/master
Commit: bd5191d9a8858945a4d83df58e261eb56bec0ab7
Parents: 22e45eb
Author: alexey.afanasiev <Al...@jetbrains.com>
Authored: Mon Dec 11 16:01:02 2017 +0300
Committer: sunlan <su...@apache.org>
Committed: Wed Dec 13 11:22:51 2017 +0800

----------------------------------------------------------------------
 .../stc/StaticTypeCheckingVisitor.java          |  37 +++++--
 .../transform/stc/MethodCallsSTCTest.groovy     | 111 +++++++++++++++++++
 2 files changed, 141 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/bd5191d9/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 cee30e4..a372284 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++) {
@@ -4271,12 +4278,8 @@ 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(vexp, type);
@@ -4356,6 +4359,26 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         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;
+    }
+
     /**
      * resolves a Field or Property node generics by using the current class and
      * the declaring class to extract the right meaning of the generics symbols

http://git-wip-us.apache.org/repos/asf/groovy/blob/bd5191d9/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 12e9cd2..74c2095 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) {