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/03/01 20:02:33 UTC

[groovy] branch GROOVY_2_5_X updated (9dda58e -> 25b48f5)

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

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


    from 9dda58e  GROOVY-7945: resolve type of "super" ctor call including type arguments
     new a621d8b  GROOVY-9945: wildcard bounds checks
     new aeb8141  GROOVY-10075: STC: always re-check extension method receiver/argument(s)
     new 3b27dda  GROOVY-10051: STC: fully resolve "T extends Number" to Number not Object
     new 25b48f5  GROOVY-10052: no re-visit for closure without changed/shared variable(s)

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../java/org/codehaus/groovy/ast/GenericsType.java | 21 +++---
 .../transform/stc/StaticTypeCheckingSupport.java   | 37 +++++-----
 .../transform/stc/StaticTypeCheckingVisitor.java   | 41 +++++++----
 .../groovy/transform/stc/ClosuresSTCTest.groovy    | 65 ++++++++++++++---
 .../stc/DefaultGroovyMethodsSTCTest.groovy         | 84 +++++++++++++++-------
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 55 ++++++++++++++
 .../groovy/runtime/m12n/TestStringExtension.java   | 12 +++-
 7 files changed, 237 insertions(+), 78 deletions(-)

[groovy] 04/04: GROOVY-10052: no re-visit for closure without changed/shared variable(s)

Posted by em...@apache.org.
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

commit 25b48f561897032dfcd2ee06734c71845ab5e6ba
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Apr 23 13:31:39 2021 -0500

    GROOVY-10052: no re-visit for closure without changed/shared variable(s)
    
    Conflicts:
    	src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
---
 .../transform/stc/StaticTypeCheckingSupport.java   |  8 ++-
 .../transform/stc/StaticTypeCheckingVisitor.java   | 36 +++++++-----
 .../groovy/transform/stc/ClosuresSTCTest.groovy    | 65 +++++++++++++++++++---
 3 files changed, 84 insertions(+), 25 deletions(-)

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 b929881..1feb1b7 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1779,8 +1779,12 @@ public abstract class StaticTypeCheckingSupport {
             extractGenericsConnections(connections, type.getComponentType(), target.getComponentType());
 
         } else if (type.equals(CLOSURE_TYPE) && (sam = findSAM(target)) != null) { // GROOVY-9974
-            ClassNode returnType = StaticTypeCheckingVisitor.wrapTypeIfNecessary(sam.getReturnType());
-            extractGenericsConnections(connections, type.getGenericsTypes(), new GenericsType[] {new GenericsType(returnType)});
+            ClassNode returnType = sam.getReturnType();
+            if (returnType.isGenericsPlaceHolder()) { // GROOVY-10052
+                returnType = GenericsUtils.findActualTypeByGenericsPlaceholderName(returnType.getUnresolvedName(),
+                    GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(sam.getDeclaringClass(), target));
+            }
+            extractGenericsConnections(connections, type.getGenericsTypes(), new GenericsType[] {new GenericsType(StaticTypeCheckingVisitor.wrapTypeIfNecessary(returnType))});
 
         } else if (type.equals(target) || !implementsInterfaceOrIsSubclassOf(type, target)) {
             extractGenericsConnections(connections, type.getGenericsTypes(), target.getGenericsTypes());
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 47e733e..9d21672 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1946,8 +1946,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 typeCheckingContext.controlStructureVariables.remove(forLoop.getVariable());
             }
         }
-        boolean typeChanged = isSecondPassNeededForControlStructure(varOrigType, oldTracker);
-        if (typeChanged) visitForLoop(forLoop);
+        if (isSecondPassNeededForControlStructure(varOrigType, oldTracker)) {
+            visitForLoop(forLoop);
+        }
     }
 
     /**
@@ -2397,10 +2398,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         boolean oldStaticContext = typeCheckingContext.isInStaticContext;
         typeCheckingContext.isInStaticContext = false;
 
-        // collect every variable expression used in the loop body
-        final Map<VariableExpression, ClassNode> varOrigType = new HashMap<VariableExpression, ClassNode>();
-        Statement code = expression.getCode();
-        code.visit(new VariableExpressionTypeMemoizer(varOrigType));
+        // collect every variable expression used in the closure body
+        Map<VariableExpression, ClassNode> varTypes = new HashMap<>();
+        expression.getCode().visit(new VariableExpressionTypeMemoizer(varTypes, true));
         Map<VariableExpression, List<ClassNode>> oldTracker = pushAssignmentTracking();
 
         // first, collect closure shared variables and reinitialize types
@@ -2429,8 +2429,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
         super.visitClosureExpression(expression);
         typeCheckingContext.delegationMetadata = typeCheckingContext.delegationMetadata.getParent();
-        MethodNode node = new MethodNode("dummy", 0, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, code);
-        returnAdder.visitMethod(node);
+        returnAdder.visitMethod(new MethodNode("dummy", 0, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, expression.getCode()));
 
         TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
         if (!enclosingClosure.getReturnTypes().isEmpty()) {
@@ -2441,9 +2440,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
 
         typeCheckingContext.popEnclosingClosure();
-
-        boolean typeChanged = isSecondPassNeededForControlStructure(varOrigType, oldTracker);
-        if (typeChanged) visitClosureExpression(expression);
+        // check types of closure shared variables for change
+        if (isSecondPassNeededForControlStructure(varTypes, oldTracker)) {
+            visitClosureExpression(expression);
+        }
 
         // restore original metadata
         restoreVariableExpressionMetadata(typesBeforeVisit);
@@ -5644,10 +5644,16 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
 
     protected class VariableExpressionTypeMemoizer extends ClassCodeVisitorSupport {
+        private final boolean onlySharedVariables;
         private final Map<VariableExpression, ClassNode> varOrigType;
 
         public VariableExpressionTypeMemoizer(final Map<VariableExpression, ClassNode> varOrigType) {
+            this(varOrigType, false);
+        }
+
+        public VariableExpressionTypeMemoizer(final Map<VariableExpression, ClassNode> varOrigType, final boolean onlySharedVariables) {
             this.varOrigType = varOrigType;
+            this.onlySharedVariables = onlySharedVariables;
         }
 
         @Override
@@ -5657,12 +5663,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
         @Override
         public void visitVariableExpression(final VariableExpression expression) {
-            super.visitVariableExpression(expression);
             Variable var = findTargetVariable(expression);
-            if (var instanceof VariableExpression) {
+            if ((!onlySharedVariables || var.isClosureSharedVariable()) && var instanceof VariableExpression) {
                 VariableExpression ve = (VariableExpression) var;
-                varOrigType.put(ve, (ClassNode) ve.getNodeMetaData(INFERRED_TYPE));
+                ClassNode cn = ve.getNodeMetaData(INFERRED_TYPE);
+                if (cn == null) cn = ve.getOriginType();
+                varOrigType.put(ve, cn);
             }
+            super.visitVariableExpression(expression);
         }
     }
 
diff --git a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
index e6c60e2..ef61a3d 100644
--- a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
@@ -18,6 +18,8 @@
  */
 package groovy.transform.stc
 
+import groovy.transform.NotYetImplemented
+
 /**
  * Unit tests for static type checking : closures.
  */
@@ -77,7 +79,7 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
         '''
 
         shouldFailWithMessages '''
-            def c = { int a, int b -> print a + b }
+            def c = { int a, int b -> a + b }
             c('5', '7')
         ''',
         'Cannot call closure that accepts [int, int] with [java.lang.String, java.lang.String]'
@@ -103,7 +105,7 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testClosureReturnTypeInferrence() {
+    void testClosureReturnTypeInference1() {
         assertScript '''
             def c = { int a, int b -> return a + b }
             int total = c(2, 3)
@@ -131,10 +133,17 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
         'Possible loss of precision from long to byte'
     }
 
-    // GROOVY-9907
+    @NotYetImplemented // GROOVY-9907
     void testClosureReturnTypeInference4() {
         assertScript '''
-            { -> println 'Hello' }()
+            Integer foo(x) {
+                if (x instanceof Integer) {
+                    def bar = { -> return x }
+                    return bar.call()
+                }
+                return 0
+            }
+            assert foo(1) == 1
         '''
     }
 
@@ -164,7 +173,7 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
     // GROOVY-8427
     void testClosureReturnTypeInference6() {
         assertScript '''
-            class Main {
+            class C {
                 static <T> void m(T t, Consumer<T> c) {
                     c.accept(t)
                 }
@@ -300,15 +309,15 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testClosureShouldNotChangeInferredType() {
+    void testClosureSharedVariable1() {
         assertScript '''
             def x = '123';
             { -> x = new StringBuffer() }
-            x.charAt(0)
+            x.charAt(0) // available in String and StringBuffer
         '''
     }
 
-    void testClosureSharedVariableWithIncompatibleType() {
+    void testClosureSharedVariable2() {
         shouldFailWithMessages '''
             def x = '123';
             { -> x = 123 }
@@ -334,6 +343,43 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
         'Cannot find matching method A#m()'
     }
 
+    // GROOVY-10052
+    void testClosureSharedVariable4() {
+        assertScript '''
+            String x
+            def f = { ->
+                x = Optional.of('x').orElseThrow{ new Exception() }
+            }
+            assert f() == 'x'
+            assert x == 'x'
+        '''
+    }
+
+    // GROOVY-10052
+    void testClosureSharedVariable5() {
+        assertScript '''
+            def x
+            def f = { ->
+                x = Optional.of('x').orElseThrow{ new Exception() }
+            }
+            assert f() == 'x'
+            assert x == 'x'
+        '''
+    }
+
+    // GROOVY-10052
+    void testNotClosureSharedVariable() {
+        assertScript '''
+            String x = Optional.of('x').orElseThrow{ new Exception() }
+            def f = { ->
+                String y = Optional.of('y').orElseThrow{ new Exception() }
+            }
+
+            assert x == 'x'
+            assert f() == 'y'
+        '''
+    }
+
     // GROOVY-9607
     void testClosureSharedVariableInferredType1() {
         assertScript '''
@@ -459,6 +505,7 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
         }
         '''
     }
+
     // a case in Grails
     void testShouldNotThrowClosureSharedVariableError2() {
         assertScript '''
@@ -535,7 +582,7 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-6189
-    void testSAMsInMethodSelection(){
+    void testSAMsInMethodSelection() {
         // simple direct case
         assertScript """
             interface MySAM {

[groovy] 03/04: GROOVY-10051: STC: fully resolve "T extends Number" to Number not Object

Posted by em...@apache.org.
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

commit 3b27dda4b84b1cb06e6e2f3d942ecaf6fa85d1eb
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Apr 22 14:44:48 2021 -0500

    GROOVY-10051: STC: fully resolve "T extends Number" to Number not Object
    
    Conflicts:
    	src/test/groovy/transform/stc/GenericsSTCTest.groovy
---
 .../transform/stc/StaticTypeCheckingSupport.java   |  2 +-
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 38 ++++++++++++++++++++++
 2 files changed, 39 insertions(+), 1 deletion(-)

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 de5ada0..b929881 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1699,7 +1699,7 @@ public abstract class StaticTypeCheckingSupport {
         }
         // For a placeholder, a type based on the generics type is used for the compatibility check, to match on
         // the actual bounds and not the name of the placeholder.
-        ClassNode replacementType = OBJECT_TYPE;
+        ClassNode replacementType = gt.getType().redirect();
         if (gt.getType().getGenericsTypes() != null) {
             GenericsType realGt = gt.getType().getGenericsTypes()[0];
             if (realGt.getLowerBound() != null) {
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 0af04e3..1228166 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -195,6 +195,44 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+
+    // GROOVY-10051
+    void testReturnTypeInferenceWithMethodGenericsAndBounds() {
+        assertScript '''
+            abstract class State<H extends Handle> {
+                // Why not return HandleContainer<H>? I can't really say.
+                def <T extends Handle> HandleContainer<T> getHandleContainer(key) {
+                }
+            }
+            class HandleContainer<H extends Handle> {
+                H handle
+            }
+            interface Handle {
+                Result getResult()
+            }
+            class Result {
+                int itemCount
+                String[] items
+            }
+
+            List<String> getStrings(State state, List keys) {
+                keys.collectMany { key ->
+                    List<String> strings = Collections.emptyList()
+                    def container = state.getHandleContainer(key) // returns HandleContainer<Object> not HandleContainer<SearchHandle>
+                    if (container != null) {
+                        def result = container.handle.result
+                        if (result != null && result.itemCount > 0) {
+                            strings = Arrays.asList(result.items)
+                        }
+                    }
+                    strings
+                }
+            }
+
+            assert getStrings(null,[]).isEmpty()
+        '''
+    }
+
     void testDiamondInferrenceFromConstructor1() {
         assertScript '''
             Set< Long > s2 = new HashSet<>()

[groovy] 01/04: GROOVY-9945: wildcard bounds checks

Posted by em...@apache.org.
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

commit a621d8b679fbb7459cf0ee9c271ba0312315a228
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Mar 1 12:07:37 2022 -0600

    GROOVY-9945: wildcard bounds checks
    
    2_5_X backport
---
 .../java/org/codehaus/groovy/ast/GenericsType.java  | 21 ++++++++++++---------
 .../groovy/transform/stc/GenericsSTCTest.groovy     | 17 +++++++++++++++++
 2 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/GenericsType.java b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
index 6f40ec0..4356ca3 100644
--- a/src/main/java/org/codehaus/groovy/ast/GenericsType.java
+++ b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
@@ -244,17 +244,20 @@ public class GenericsType extends ASTNode {
                 // if the classnode we compare to is a generics placeholder (like <E>) then we
                 // only need to check that the names are equal
                 if (genericsTypes==null) return true;
-                if (isWildcard()) {
-                    if (lowerBound!=null) return genericsTypes[0].getName().equals(lowerBound.getUnresolvedName());
-                    if (upperBounds!=null) {
-                        for (ClassNode upperBound : upperBounds) {
-                            String name = upperBound.getGenericsTypes()[0].getName();
-                            if (genericsTypes[0].getName().equals(name)) return true;
-                        }
-                        return false;
+                String name0 = genericsTypes[0].getName();
+                if (!isWildcard()) {
+                    return name0.equals(getName());
+                }
+                if (getLowerBound() != null) {
+                    if (name0.equals(getLowerBound().getUnresolvedName())) {
+                        return true;
+                    }
+                } else if (getUpperBounds() != null) {
+                    if (name0.equals(getUpperBounds()[0].getUnresolvedName())) {
+                        return true;
                     }
                 }
-                return genericsTypes[0].getName().equals(name);
+                return checkGenerics(classNode);
             }
             if (wildcard || placeholder) {
                 // if the current generics spec is a wildcard spec or a placeholder spec
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index da05e44..0af04e3 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -669,6 +669,23 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-9945
+    void testShouldUseMethodGenericType7() {
+        assertScript '''
+            interface I<T> {
+            }
+            class A<T> implements I<String> {
+                def m(T t) { 'works' }
+            }
+            class B<T> extends A<T> {
+            }
+
+            def bee = new B<Float>()
+            def obj = bee.m(3.14f)
+            assert obj == 'works'
+        '''
+    }
+
     // GROOVY-5516
     void testAddAllWithCollectionShouldBeAllowed() {
         assertScript '''import org.codehaus.groovy.transform.stc.ExtensionMethodNode

[groovy] 02/04: GROOVY-10075: STC: always re-check extension method receiver/argument(s)

Posted by em...@apache.org.
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

commit aeb81411e82a77426cfac957e157e1c45e604957
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri May 7 15:22:53 2021 -0500

    GROOVY-10075: STC: always re-check extension method receiver/argument(s)
    
    Conflicts:
    	src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
---
 .../transform/stc/StaticTypeCheckingSupport.java   | 27 +++----
 .../transform/stc/StaticTypeCheckingVisitor.java   |  5 ++
 .../stc/DefaultGroovyMethodsSTCTest.groovy         | 84 +++++++++++++++-------
 .../groovy/runtime/m12n/TestStringExtension.java   | 12 +++-
 4 files changed, 85 insertions(+), 43 deletions(-)

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 d7b7f72..de5ada0 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -20,7 +20,6 @@
 package org.codehaus.groovy.transform.stc;
 
 import org.codehaus.groovy.GroovyBugError;
-import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.GenericsType;
 import org.codehaus.groovy.ast.GenericsType.GenericsTypeName;
@@ -1449,25 +1448,21 @@ public abstract class StaticTypeCheckingSupport {
     }
 
     protected static boolean typeCheckMethodsWithGenerics(ClassNode receiver, ClassNode[] arguments, MethodNode candidateMethod) {
-        boolean isExtensionMethod = candidateMethod instanceof ExtensionMethodNode;
-        if (!isExtensionMethod
-                && receiver.isUsingGenerics()
+        if (candidateMethod instanceof ExtensionMethodNode) {
+            ClassNode[] realTypes = new ClassNode[arguments.length + 1];
+            realTypes[0] = receiver; // object expression is first argument
+            System.arraycopy(arguments, 0, realTypes, 1, arguments.length);
+            MethodNode realMethod = ((ExtensionMethodNode) candidateMethod).getExtensionMethodNode();
+            return typeCheckMethodsWithGenerics(realMethod.getDeclaringClass(), realTypes, realMethod, true);
+        }
+
+        if (receiver.isUsingGenerics()
                 && receiver.equals(CLASS_Type)
                 && !candidateMethod.getDeclaringClass().equals(CLASS_Type)) {
             return typeCheckMethodsWithGenerics(receiver.getGenericsTypes()[0].getType(), arguments, candidateMethod);
         }
-        // both candidate method and receiver have generic information so a check is possible
-        GenericsType[] genericsTypes = candidateMethod.getGenericsTypes();
-        boolean methodUsesGenerics = (genericsTypes != null && genericsTypes.length > 0);
-        if (isExtensionMethod && methodUsesGenerics) {
-            ClassNode[] dgmArgs = new ClassNode[arguments.length + 1];
-            dgmArgs[0] = receiver;
-            System.arraycopy(arguments, 0, dgmArgs, 1, arguments.length);
-            MethodNode extensionMethodNode = ((ExtensionMethodNode) candidateMethod).getExtensionMethodNode();
-            return typeCheckMethodsWithGenerics(extensionMethodNode.getDeclaringClass(), dgmArgs, extensionMethodNode, true);
-        } else {
-            return typeCheckMethodsWithGenerics(receiver, arguments, candidateMethod, false);
-        }
+
+        return typeCheckMethodsWithGenerics(receiver, arguments, candidateMethod, false);
     }
 
     private static boolean typeCheckMethodsWithGenerics(ClassNode receiver, ClassNode[] arguments, MethodNode candidateMethod, boolean isExtensionMethod) {
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 d66f72a..47e733e 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1581,6 +1581,11 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 for (MethodNode m : findDGMMethodsByNameAndArguments(getSourceUnit().getClassLoader(), dgmReceiver, "is" + capName, ClassNode.EMPTY_ARRAY)) {
                     if (Boolean_TYPE.equals(getWrapper(m.getReturnType()))) methods.add(m);
                 }
+                if (isUsingGenericsOrIsArrayUsingGenerics(dgmReceiver)) { // GROOVY-10075: "List<Integer>" vs "List<String>"
+                    for (Iterator<MethodNode> it = methods.iterator(); it.hasNext(); ) { MethodNode method = it.next();
+                        if (!typeCheckMethodsWithGenerics(dgmReceiver, ClassNode.EMPTY_ARRAY, method)) it.remove();
+                    }
+                }
                 if (!methods.isEmpty()) {
                     List<MethodNode> methodNodes = chooseBestMethod(dgmReceiver, methods, ClassNode.EMPTY_ARRAY);
                     if (methodNodes.size() == 1) {
diff --git a/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy b/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
index 11caeb0..3e271b0 100644
--- a/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
@@ -24,37 +24,37 @@ package groovy.transform.stc
 class DefaultGroovyMethodsSTCTest extends StaticTypeCheckingTestCase {
 
     void testEach() {
-        assertScript """
+        assertScript '''
             ['a','b'].each { // DGM#each(Object, Closure)
                 println it // DGM#println(Object,Object)
             }
-        """
+        '''
 
-        assertScript """
+        assertScript '''
             ['a','b'].eachWithIndex { it, i ->// DGM#eachWithIndex(Object, Closure)
                 println it // DGM#println(Object,Object)
             }
-        """
+        '''
     }
 
     void testStringToInteger() {
-        assertScript """
-        String name = "123"
-        name.toInteger() // toInteger() is defined by DGM
-        """
+        assertScript '''
+            String name = "123"
+            name.toInteger() // toInteger() is defined by DGM
+        '''
     }
 
     void testVariousAssignmentsThenToInteger() {
-        assertScript """
-         class A {
-          void foo() {}
-         }
-        def name = new A()
-        name.foo()
-        name = 1
-        name = '123'
-        name.toInteger() // toInteger() is defined by DGM
-        """
+        assertScript '''
+            class A {
+                void foo() {}
+            }
+            def name = new A()
+            name.foo()
+            name = 1
+            name = '123'
+            name.toInteger() // toInteger() is defined by DGM
+        '''
     }
 
     void testMethodsOnPrimitiveTypes() {
@@ -66,7 +66,7 @@ class DefaultGroovyMethodsSTCTest extends StaticTypeCheckingTestCase {
             true.equals { it }
         '''
     }
-  
+
     void testShouldAcceptMethodFromDefaultDateMethods() {
       assertScript '''
         def s = new Date()
@@ -76,16 +76,50 @@ class DefaultGroovyMethodsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-5568
-    void testDGMMethodAsProperty() {
+    void testPropertySemantics1() {
         assertScript '''
-            String foo(InputStream input) {
-                input.text
+            String test(InputStream input) {
+                input.text // IOGroovyMethods#getText(InputStream)
             }
-            def text = new ByteArrayInputStream('foo'.getBytes())
-            assert foo(text) == 'foo'
+            assert test(new ByteArrayInputStream('foo'.bytes)) == 'foo'
+        '''
+
+        assertScript '''
+            def chars = new StringBuilder('foo').chars // StringGroovyMethods#getChars(CharSequence)
+            assert chars == 'foo'.toCharArray()
+        '''
+
+        assertScript '''
+            def a = Character.valueOf((char) 'a')
+            assert a.letter // DefaultGroovyMethods#isLetter(Character)
         '''
     }
 
+    // GROOVY-10075
+    void testPropertySemantics2() {
+        // see org.codehaus.groovy.runtime.m12n.TestStringExtension
+
+        assertScript '''
+            List<String> strings = ['x','y','z']
+            assert strings.getSequence() == 'x'
+            assert strings.getString() == 'x'
+          //assert strings.sequence == 'x'
+          //assert strings.string == 'x'
+        '''
+
+        shouldFailWithMessages '''
+            List<Number> numbers = [(Number)1, 2, 3]
+            numbers.getSequence()
+            numbers.getString()
+            numbers.sequence
+            numbers.string
+        ''',
+        'Cannot call <CS extends java.lang.CharSequence> java.util.List <java.lang.Number>#getSequence() with arguments []',
+        'Cannot call java.util.List <java.lang.Number>#getString() with arguments []',
+        'No such property: sequence for class: java.util.List <java.lang.Number>',
+        'No such property: string for class: java.util.List <java.lang.Number>'
+    }
+
     // GROOVY-5584
     void testEachOnMap() {
         assertScript '''import org.codehaus.groovy.transform.stc.ExtensionMethodNode
@@ -195,7 +229,7 @@ class DefaultGroovyMethodsSTCTest extends StaticTypeCheckingTestCase {
                 def results = [:]
                 Functions.values().eachWithIndex { val, idx -> results[idx] = val.name() }
                 results
-            } 
+            }
             assert m() == ['A', 'B', 'C']
             assert m2() == [0: 'A', 1: 'B', 2: 'C']
         '''
diff --git a/src/test/org/codehaus/groovy/runtime/m12n/TestStringExtension.java b/src/test/org/codehaus/groovy/runtime/m12n/TestStringExtension.java
index fdd5e9f..fbbe8c2 100644
--- a/src/test/org/codehaus/groovy/runtime/m12n/TestStringExtension.java
+++ b/src/test/org/codehaus/groovy/runtime/m12n/TestStringExtension.java
@@ -19,8 +19,16 @@
 package org.codehaus.groovy.runtime.m12n;
 
 public class TestStringExtension {
+
     public static String reverseToUpperCase(String self) {
-        StringBuilder sb = new StringBuilder(self.toUpperCase());
-        return sb.reverse().toString();
+        return new StringBuilder(self.toUpperCase()).reverse().toString();
+    }
+
+    public static String getString(java.util.List<String> self) {
+        return self.get(0);
+    }
+
+    public static <CS extends CharSequence> CharSequence getSequence(java.util.List<CS> self) {
+        return self.get(0);
     }
 }