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/08/24 19:00:28 UTC

[groovy] branch GROOVY_2_5_X updated: GROOVY-9463: STC: error for unknown method pointer

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 898f8ca38c GROOVY-9463: STC: error for unknown method pointer
898f8ca38c is described below

commit 898f8ca38c62115e34ab7e0c9a828886f0740756
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Sep 21 14:11:32 2020 -0500

    GROOVY-9463: STC: error for unknown method pointer
---
 .../transform/stc/StaticTypeCheckingVisitor.java   |   4 +
 src/test/groovy/transform/stc/BugsSTCTest.groovy   | 235 ++++++++++++++-------
 2 files changed, 161 insertions(+), 78 deletions(-)

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 a4970762a7..f6f62dd6c8 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -2562,6 +2562,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 if (!returnType.equals(OBJECT_TYPE)) {
                     storeType(expression, wrapClosureType(returnType));
                 }
+            } else { // GROOVY-9463
+                ClassNode type = wrapTypeIfNecessary(getType(expression.getExpression()));
+                if (isClassClassNodeWrappingConcreteType(type)) type = type.getGenericsTypes()[0].getType();
+                addStaticTypeError("Cannot find matching method " + type.getText() + "#" + nameText + ". Please check if the declared type is correct and if the method exists.", nameExpr);
             }
         }
     }
diff --git a/src/test/groovy/transform/stc/BugsSTCTest.groovy b/src/test/groovy/transform/stc/BugsSTCTest.groovy
index 61d90da3ce..8535383800 100644
--- a/src/test/groovy/transform/stc/BugsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/BugsSTCTest.groovy
@@ -18,10 +18,13 @@
  */
 package groovy.transform.stc
 
+import groovy.transform.NotYetImplemented
+
 /**
  * Unit tests for static type checking : bug fixes.
  */
 class BugsSTCTest extends StaticTypeCheckingTestCase {
+
     // GROOVY-5456
     void testShouldNotAllowDivOnUntypedVariable() {
         shouldFailWithMessages '''
@@ -87,17 +90,50 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
     // GROOVY-7929
     void testShouldDetectInvalidMethodUseWithinTraitWithCompileStaticAndSelfType() {
         shouldFailWithMessages '''
-            class C1 {
-                def c1() { }
+            class C {
+                def m() { }
             }
             @groovy.transform.CompileStatic
-            @groovy.transform.SelfType(C1)
-            trait TT {
-                def foo() {
-                    c2()
+            @groovy.transform.SelfType(C)
+            trait T {
+                void test() {
+                    x()
                 }
             }
-        ''', 'Cannot find matching method <UnionType:C1+TT>#c2'
+        ''', 'Cannot find matching method <UnionType:C+T>#x'
+    }
+
+    @NotYetImplemented // GROOVY-10102
+    void testShouldDetectValidMethodUseWithinTraitWithCompileStaticAndSelfType() {
+        assertScript '''
+            import groovy.transform.*
+
+            trait A {
+                String foo = 'foo'
+                String m(String s, Closure x) {
+                    s + x()
+                }
+            }
+            @SelfType(A)
+            trait B {
+            }
+            @SelfType(B)
+            trait C {
+            }
+            @CompileStatic
+            @SelfType(C)
+            trait D {
+                def test() {
+                    String s = foo
+                    m(s) {
+                        s.toUpperCase()
+                    }
+                }
+            }
+
+            class E implements A, B, C, D { }
+            assert new E().test() == 'fooFOO'
+        '''
     }
 
     // GROOVY-10106
@@ -136,24 +172,24 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
 
     void testGroovy5444() {
         assertScript '''
-                def curr = { System.currentTimeMillis() }
-
-                5.times {
-                    @ASTTest(phase=INSTRUCTION_SELECTION, value= {
-                        assert node.getNodeMetaData(INFERRED_TYPE) == Long_TYPE
-                    })
-                    def t0 = curr()
-                    100000.times {
-                        "echo"
-                    }
-                    println (curr() - t0)
-                }'''
+            def millis = { System.currentTimeMillis() }
 
+            5.times {
+                @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                    assert node.getNodeMetaData(INFERRED_TYPE) == Long_TYPE
+                })
+                def t0 = millis()
+                1000.times {
+                    "echo"
+                }
+                def elapsed = millis() - t0
+            }
+        '''
     }
 
     void testGroovy5487ReturnNull() {
         assertScript '''
-        @ASTTest(phase=INSTRUCTION_SELECTION, value= {
+        @ASTTest(phase=INSTRUCTION_SELECTION, value={
             assert node.getNodeMetaData(INFERRED_RETURN_TYPE) == null // null since 2.1.9
         })
         List getList() {
@@ -164,7 +200,7 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
 
     void testGroovy5487ReturnNullWithExplicitReturn() {
         assertScript '''
-        @ASTTest(phase=INSTRUCTION_SELECTION, value= {
+        @ASTTest(phase=INSTRUCTION_SELECTION, value={
             assert node.getNodeMetaData(INFERRED_RETURN_TYPE) == null // null since 2.1.9
         })
         List getList() {
@@ -175,7 +211,7 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
 
     void testGroovy5487ReturnNullWithEmptyBody() {
         assertScript '''
-        @ASTTest(phase=INSTRUCTION_SELECTION, value= {
+        @ASTTest(phase=INSTRUCTION_SELECTION, value={
             assert node.getNodeMetaData(INFERRED_RETURN_TYPE) == null // null since 2.1.9
         })
         List getList() {
@@ -224,70 +260,87 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
         new StaticGroovy2()'''
     }
 
-    void testClosureDelegateThisOwner() {
+    void testClosureThisObjectDelegateOwnerProperty() {
         assertScript '''
-            class A {
-                A that = this
+            class C {
                 void m() {
-                    def cl = {
-                        @ASTTest(phase=INSTRUCTION_SELECTION, value= {
-                            assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'A'
+                    C that = this;
+
+                    { ->
+                        @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                            assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'C'
                         })
-                        def foo = this
-                        assert this == that
-                    }
-                    cl()
-                    cl = {
-                        @ASTTest(phase=INSTRUCTION_SELECTION, value= {
-                            assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'A'
+                        def ref = thisObject
+                        assert ref == that
+                    }();
+
+                    { ->
+                        @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                            assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'C'
                         })
-                        def foo = delegate
-                        assert delegate == that
-                    }
-                    cl()
-                    cl = {
-                        @ASTTest(phase=INSTRUCTION_SELECTION, value= {
-                            assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'A'
+                        def ref = delegate
+                        assert ref == that
+                    }();
+
+                    { ->
+                        @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                            assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'C'
                         })
-                        def foo = owner
-                        assert owner == that
-                    }
+                        def ref = owner
+                        assert ref == that
+                    }();
                 }
             }
-            new A().m()
+            new C().m()
         '''
     }
-    void testClosureDelegateThisOwnerUsingGetters() {
+
+    void testClosureThisObjectDelegateOwnerAccessor() {
         assertScript '''
-            class A {
-                A that = this
+            class C {
                 void m() {
-                    def cl = {
-                        @ASTTest(phase=INSTRUCTION_SELECTION, value= {
-                            assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'A'
+                    C that = this;
+
+                    { ->
+                        @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                            assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'C'
                         })
-                        def foo = getThisObject()
-                        assert getThisObject() == that
-                    }
-                    cl()
-                    cl = {
-                        @ASTTest(phase=INSTRUCTION_SELECTION, value= {
-                            assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'A'
+                        def ref = getThisObject()
+                        assert ref == that
+                    }();
+
+                    { ->
+                        @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                            assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'C'
                         })
-                        def foo = getDelegate()
-                        assert getDelegate() == that
-                    }
-                    cl()
-                    cl = {
-                        @ASTTest(phase=INSTRUCTION_SELECTION, value= {
-                            assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'A'
+                        def ref = getDelegate()
+                        assert ref == that
+                    }();
+
+                    { ->
+                        @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                            assert node.getNodeMetaData(INFERRED_TYPE)?.name == 'C'
                         })
-                        def foo = getOwner()
-                        assert getOwner() == that
-                    }
+                        def ref = getOwner()
+                        assert ref == that
+                    }();
+                }
+            }
+            new C().m()
+        '''
+    }
+
+    @NotYetImplemented // GROOVY-9604
+    void testClosureResolveStrategy() {
+        assertScript '''
+            class C {
+                def m() {
+                    return { ->
+                        resolveStrategy + getResolveStrategy()
+                    }();
                 }
             }
-            new A().m()
+            assert new C().m() == 0
         '''
     }
 
@@ -369,7 +422,7 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
         execute()'''
     }
 
-    // GROOVY-5874-part-1
+    // GROOVY-5874 (pt.1)
     void testClosureSharedVariableInBinExp() {
         shouldFailWithMessages '''
             def sum = 0
@@ -627,7 +680,7 @@ Printer
     }
 
     // GROOVY-6970
-    void testShouldBeAbleToChooseBetweenTwoEquivalentInterfaceMethods() {
+    void testShouldBeAbleToChooseBetweenTwoEquivalentInterfaceMethods1() {
         assertScript '''
             interface A { void m() }
             interface B { void m() }
@@ -645,7 +698,8 @@ Printer
             new D(new CImpl())
         '''
     }
-    void testShouldBeAbleToChooseBetweenTwoEquivalentInterfaceMethodsVariant() {
+
+    void testShouldBeAbleToChooseBetweenTwoEquivalentInterfaceMethods2() {
         assertScript '''
             interface A { void m() }
             interface B { void m() }
@@ -662,7 +716,7 @@ Printer
         '''
     }
 
-    void testShouldBeAbleToChooseBetweenTwoEquivalentInterfaceMethodsVariant2() {
+    void testShouldBeAbleToChooseBetweenTwoEquivalentInterfaceMethods3() {
         assertScript '''
             interface A { void m() }
             interface B { void m() }
@@ -680,7 +734,8 @@ Printer
         '''
     }
 
-    void testAmbiguousMethodResolutionGroovy6849() {
+    // GROOVY-6849
+    void testAmbiguousMethodResolution() {
         assertScript '''
             interface ObservableList<E> extends List<E> {
                 public boolean addAll(E... elements)
@@ -691,13 +746,15 @@ Printer
         '''
     }
 
-    void testAmbiguousMethodResolutionGroovy7710NoArgsOverloaded() {
+    // GROOVY-7710
+    void testAmbiguousMethodResolutionNoArgsOverload() {
         shouldFailWithMessages '''
             Arrays.sort()
         ''', 'Reference to method is ambiguous. Cannot choose between '
     }
 
-    void testAmbiguousMethodResolutionGroovy7711NoArgsCovariantOverride() {
+    // GROOVY-7711
+    void testAmbiguousMethodResolutionNoArgsCovariantOverride() {
         assertScript '''
             class A {}
             class B {
@@ -805,7 +862,7 @@ Printer
         '''
     }
 
-    // GROOVY-8255 and GROOVY-8382
+    // GROOVY-8255, GROOVY-8382
     void testTargetTypingEmptyCollectionLiterals() {
         assertScript '''
             class Foo {
@@ -865,6 +922,13 @@ Printer
         '''
     }
 
+    // GROOVY-9463
+    void testMethodPointerUnknownReference() {
+        shouldFailWithMessages '''
+            def ptr = String.&toLowerCaseX
+        ''', 'Cannot find matching method java.lang.String#toLowerCaseX.'
+    }
+
     // GROOVY-9938
     void testInnerClassImplementsInterfaceMethod() {
         assertScript '''
@@ -941,6 +1005,21 @@ Printer
         '''
     }
 
+    // GROOVY-9951
+    void testInnerImmutable() {
+        assertScript '''
+            class Outer {
+                @groovy.transform.Immutable
+                static class Inner {
+                    String proper
+                }
+            }
+
+            def obj = new Outer.Inner('value')
+            assert obj.proper == 'value'
+        '''
+    }
+
     // GROOVY-10424
     void testPrivateInnerClassOptimizedBooleanExpr1() {
         assertScript '''