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/04/07 16:40:14 UTC

[groovy] branch GROOVY_3_0_X updated: GROOVY-9033: STC: resolve "def list = []" to List not List
This is an automated email from the ASF dual-hosted git repository.

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


The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
     new 0e976a58ad GROOVY-9033: STC: resolve "def list = []" to List<Object> not List<E>
0e976a58ad is described below

commit 0e976a58ad1780578697c8e32b82d305c147cbcf
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Apr 16 16:01:20 2021 -0500

    GROOVY-9033: STC: resolve "def list = []" to List<Object> not List<E>
    
    GROOVY-10089, GROOVY-10324, GROOVY-10367
---
 .../transform/stc/StaticTypeCheckingSupport.java   |  49 ++++----
 .../transform/stc/StaticTypeCheckingVisitor.java   |  87 +++++++-------
 .../groovy/transform/stc/GenericsSTCTest.groovy    |   8 +-
 .../transform/stc/TypeInferenceSTCTest.groovy      | 129 ++++++++++++++++-----
 .../classgen/asm/sc/BugsStaticCompileTest.groovy   |   4 +-
 .../asm/sc/TypeInferenceStaticCompileTest.groovy   |  68 +----------
 6 files changed, 179 insertions(+), 166 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 367b8cdb7d..873f228a85 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1296,31 +1296,32 @@ public abstract class StaticTypeCheckingSupport {
     }
 
     protected static ClassNode fullyResolveType(final ClassNode type, final Map<GenericsTypeName, GenericsType> placeholders) {
-        if (type.isUsingGenerics() && !type.isGenericsPlaceHolder()) {
-            GenericsType[] gts = type.getGenericsTypes();
-            if (gts != null) {
-                GenericsType[] copy = new GenericsType[gts.length];
-                for (int i = 0, n = gts.length; i < n; i += 1) {
-                    GenericsType genericsType = gts[i];
-                    if (genericsType.isPlaceholder() && placeholders.containsKey(new GenericsTypeName(genericsType.getName()))) {
-                        copy[i] = placeholders.get(new GenericsTypeName(genericsType.getName()));
-                    } else {
-                        copy[i] = fullyResolve(genericsType, placeholders);
-                    }
+        if (type.isArray()) {
+            return fullyResolveType(type.getComponentType(), placeholders).makeArray();
+        }
+        if (type.isUsingGenerics()) {
+            if (type.isGenericsPlaceHolder()) {
+                GenericsType gt = placeholders.get(new GenericsTypeName(type.getUnresolvedName()));
+                if (gt != null) {
+                    return gt.getType();
                 }
-                gts = copy;
-            }
-            ClassNode result = type.getPlainNodeReference();
-            result.setGenericsTypes(gts);
-            return result;
-        } else if (type.isUsingGenerics() && OBJECT_TYPE.equals(type) && type.getGenericsTypes() != null) {
-            // Object<T>
-            GenericsType genericsType = placeholders.get(new GenericsTypeName(type.getGenericsTypes()[0].getName()));
-            if (genericsType != null) {
-                return genericsType.getType();
+                ClassNode cn = type.redirect();
+                return cn != type ? cn : OBJECT_TYPE;
+            } else {
+                GenericsType[] gts = type.getGenericsTypes();
+                if (gts != null) {
+                    gts = Arrays.stream(gts).map(gt -> {
+                        if (gt.isPlaceholder()) {
+                            GenericsTypeName gtn = new GenericsTypeName(gt.getName());
+                            return placeholders.getOrDefault(gtn, extractType(gt).asGenericsType());
+                        }
+                        return fullyResolve(gt, placeholders);
+                    }).toArray(GenericsType[]::new);
+                }
+                ClassNode cn = type.getPlainNodeReference();
+                cn.setGenericsTypes(gts);
+                return cn;
             }
-        } else if (type.isArray()) {
-            return fullyResolveType(type.getComponentType(), placeholders).makeArray();
         }
         return type;
     }
@@ -1717,7 +1718,7 @@ public abstract class StaticTypeCheckingSupport {
     }
 
     public static ClassNode getCorrectedClassNode(final ClassNode type, final ClassNode superClass, final boolean handlingGenerics) {
-        if (handlingGenerics && missesGenericsTypes(type)) return superClass.getPlainNodeReference();
+        if (handlingGenerics && GenericsUtils.hasUnresolvedGenerics(type)) return superClass.getPlainNodeReference();
         return GenericsUtils.correctToGenericsSpecRecurse(GenericsUtils.createGenericsSpec(type), superClass);
     }
 
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 fcfc80f29a..fe75e83e78 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -198,7 +198,6 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.localVarX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.thisPropX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
-import static org.codehaus.groovy.ast.tools.GenericsUtils.toGenericTypesString;
 import static org.codehaus.groovy.ast.tools.WideningCategories.isBigDecCategory;
 import static org.codehaus.groovy.ast.tools.WideningCategories.isBigIntCategory;
 import static org.codehaus.groovy.ast.tools.WideningCategories.isDouble;
@@ -804,24 +803,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 typeCheckingContext.secondPassExpressions.add(new SecondPassExpression(expression));
             }
 
-            boolean isAssignment = isAssignment(expression.getOperation().getType());
-            if (isAssignment && rightExpression instanceof ConstructorCallExpression) {
-                inferDiamondType((ConstructorCallExpression) rightExpression, lType);
-            }
-            if (isAssignment && lType.isUsingGenerics() && missesGenericsTypes(resultType)) {
-                // unchecked assignment
-                // examples:
-                // List<A> list = []
-                // List<A> list = new LinkedList()
-                // Iterable<A> list = new LinkedList()
-
-                // in that case, the inferred type of the binary expression is the type of the RHS
-                // "completed" with generics type information available in the LHS
-                ClassNode completedType = GenericsUtils.parameterizeType(lType, resultType.getPlainNodeReference());
-
-                resultType = completedType;
-            }
-
             if (isArrayOp(op)
                     && !lType.isArray()
                     && enclosingBinaryExpression != null
@@ -842,16 +823,40 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             }
 
             boolean isEmptyDeclaration = (expression instanceof DeclarationExpression && rightExpression instanceof EmptyExpression);
-            if (isAssignment && !isEmptyDeclaration) {
+            if (!isEmptyDeclaration && isAssignment(op)) {
+                if (rightExpression instanceof ConstructorCallExpression)
+                    inferDiamondType((ConstructorCallExpression) rightExpression, lType);
+
+                if (lType.isUsingGenerics() && missesGenericsTypes(resultType)) {
+                    // unchecked assignment
+                    // List<Type> list = new LinkedList()
+                    // Iterable<Type> iter = new LinkedList()
+                    // Collection<Type> coll = Collections.emptyList()
+                    // Collection<Type> view = ConcurrentHashMap.newKeySet()
+
+                    // the inferred type of the binary expression is the type of the RHS
+                    // "completed" with generics type information available from the LHS
+                    if (lType.equals(resultType)) {
+                        if (!lType.isGenericsPlaceHolder()) resultType = lType;
+                    } else if (!resultType.isGenericsPlaceHolder()) { // GROOVY-10235, GROOVY-10324, et al.
+                        Map<GenericsTypeName, GenericsType> gt = new HashMap<>();
+                        extractGenericsConnections(gt, resultType, resultType.redirect());
+                        ClassNode sc = resultType;
+                        do { sc = getNextSuperClass(sc, lType);
+                        } while (sc != null && !sc.equals(lType));
+                        extractGenericsConnections(gt, lType, sc);
+
+                        resultType = applyGenericsContext(gt, resultType.redirect());
+                    }
+                }
+
                 ClassNode originType = getOriginalDeclarationType(leftExpression);
                 typeCheckAssignment(expression, leftExpression, originType, rightExpression, resultType);
-                // if assignment succeeds but result type is not a subtype of original type, then we are in a special cast handling
-                // and we must update the result type
-                if (!implementsInterfaceOrIsSubclassOf(getWrapper(resultType), getWrapper(originType))) {
+                // check for implicit conversion like "String a = 123", "int[] b = [1,2,3]", "List c = [].stream()", etc.
+                if (!implementsInterfaceOrIsSubclassOf(wrapTypeIfNecessary(resultType), wrapTypeIfNecessary(originType))) {
                     resultType = originType;
-                } else if (lType.isUsingGenerics() && !lType.isEnum() && hasRHSIncompleteGenericTypeInfo(resultType)) {
-                    // for example, LHS is List<ConcreteClass> and RHS is List<T> where T is a placeholder
-                    resultType = lType;
+                } else if (isPrimitiveType(originType) && resultType.equals(getWrapper(originType))) {
+                    resultType = originType; // retain primitive semantics
                 } else {
                     // GROOVY-7549: RHS type may not be accessible to enclosing class
                     int modifiers = resultType.getModifiers();
@@ -860,14 +865,12 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                             && !getOutermost(enclosingType).equals(getOutermost(resultType))
                             && (Modifier.isPrivate(modifiers) || !Objects.equals(enclosingType.getPackageName(), resultType.getPackageName()))) {
                         resultType = originType; // TODO: Find accesible type in hierarchy of resultType?
+                    } else if (GenericsUtils.hasUnresolvedGenerics(resultType)) { // GROOVY-9033, GROOVY-10089, et al.
+                        Map<GenericsTypeName, GenericsType> enclosing = extractGenericsParameterMapOfThis(typeCheckingContext);
+                        resultType = fullyResolveType(resultType, Optional.ofNullable(enclosing).orElseGet(Collections::emptyMap));
                     }
                 }
 
-                // make sure we keep primitive types
-                if (isPrimitiveType(originType) && resultType.equals(getWrapper(originType))) {
-                    resultType = originType;
-                }
-
                 // track conditional assignment
                 if (!isNullConstant(rightExpression)
                         && leftExpression instanceof VariableExpression
@@ -1261,9 +1264,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     private void checkTypeGenerics(final ClassNode leftExpressionType, final ClassNode wrappedRHS, final Expression rightExpression) {
         // last, check generic type information to ensure that inferred types are compatible
         if (!leftExpressionType.isUsingGenerics()) return;
-        // List<Foo> l = new List() is an example for incomplete generics type info
-        // we assume arity related errors are already handled here.
-        if (hasRHSIncompleteGenericTypeInfo(wrappedRHS)) return;
+        // example of incomplete type info: "List<Type> list = new LinkedList()"
+        // we assume arity related errors are already handled here
+        if (missesGenericsTypes(wrappedRHS)) return;
 
         GenericsType gt = GenericsUtils.buildWildcardType(leftExpressionType);
         if (UNKNOWN_PARAMETER_TYPE.equals(wrappedRHS) ||
@@ -1342,6 +1345,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         typeCheckingContext.popEnclosingBinaryExpression();
     }
 
+    @Deprecated
     protected static boolean hasRHSIncompleteGenericTypeInfo(final ClassNode inferredRightExpressionType) {
         boolean replaceType = false;
         GenericsType[] genericsTypes = inferredRightExpressionType.getGenericsTypes();
@@ -5673,29 +5677,26 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
     protected boolean typeCheckMethodsWithGenericsOrFail(final ClassNode receiver, final ClassNode[] arguments, final MethodNode candidateMethod, final Expression location) {
         if (!typeCheckMethodsWithGenerics(receiver, arguments, candidateMethod)) {
-            Map<GenericsTypeName, GenericsType> classGTs = GenericsUtils.extractPlaceholders(receiver);
+            Map<GenericsTypeName, GenericsType> generics = GenericsUtils.extractPlaceholders(receiver);
+            applyGenericsConnections(extractGenericsParameterMapOfThis(typeCheckingContext), generics);
+            addMethodLevelDeclaredGenerics(candidateMethod, generics);
             Parameter[] parameters = candidateMethod.getParameters();
             ClassNode[] paramTypes = new ClassNode[parameters.length];
             for (int i = 0, n = parameters.length; i < n; i += 1) {
-                paramTypes[i] = fullyResolveType(parameters[i].getType(), classGTs);
+                paramTypes[i] = fullyResolveType(parameters[i].getType(), generics);
                 // GROOVY-10010: check for List<String> parameter and ["foo","$bar"] argument
                 if (i < arguments.length && hasGStringStringError(paramTypes[i], arguments[i], location)) {
                     return false;
                 }
             }
-            addStaticTypeError("Cannot call " + toMethodGenericTypesString(candidateMethod) + receiver.toString(false) + "#" +
+            GenericsType[] mgt = candidateMethod.getGenericsTypes();
+            addStaticTypeError("Cannot call " + (mgt == null ? "" : GenericsUtils.toGenericTypesString(mgt)) + receiver.toString(false) + "#" +
                     toMethodParametersString(candidateMethod.getName(), paramTypes) + " with arguments " + formatArgumentList(arguments), location);
             return false;
         }
         return true;
     }
 
-    private static String toMethodGenericTypesString(final MethodNode node) {
-        GenericsType[] genericsTypes = node.getGenericsTypes();
-        if (genericsTypes == null) return "";
-        return toGenericTypesString(genericsTypes);
-    }
-
     protected static String formatArgumentList(final ClassNode[] nodes) {
         if (nodes == null || nodes.length == 0) return "[]";
 
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 0ad84dde39..7057a06c46 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -208,7 +208,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         assertScript '''
             @ASTTest(phase=INSTRUCTION_SELECTION, value={
                 def type = node.getNodeMetaData(INFERRED_TYPE)
-                assert type.toString(false) == 'java.util.List <T extends java.lang.Object>'
+                assert type.toString(false) == 'java.util.List <java.lang.Object>'
             })
             def list = Arrays.asList()
             assert list.size() == 0
@@ -268,7 +268,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    @NotYetImplemented // GROOVY-9033
+    // GROOVY-9033
     void testReturnTypeInferenceWithMethodGenerics8() {
         shouldFailWithMessages '''
             List<String> test() {
@@ -1123,7 +1123,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    @NotYetImplemented // GROOVY-10324
+    // GROOVY-10324
     void testDiamondInferrenceFromConstructor20() {
         assertScript '''
             class C<T> {
@@ -1214,7 +1214,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         }
     }
 
-    @NotYetImplemented // GROOVY-10367
+    // GROOVY-10367
     void testDiamondInferrenceFromConstructor26() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index ec9119ec41..97f09ecaf3 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -560,7 +560,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testShouldNotFailWithWithAndExplicitTypedIt() {
+    void testShouldFailWithWithAndWrongExplicitIt() {
         shouldFailWithMessages '''
             class A {
                 int x
@@ -569,7 +569,8 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
             a.with { String it ->
                 it.x = 2 // should be recognized as a.x at compile time
             }
-        ''', 'Expected parameter of type A but got java.lang.String'
+        ''',
+        'Expected parameter of type A but got java.lang.String'
     }
 
     void testShouldNotFailWithInheritanceAndWith() {
@@ -600,7 +601,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-   void testCallMethodInWithContextAndShadowing() {
+    void testCallMethodInWithContextAndShadowing() {
        // make sure that the method which is found in 'with' is actually the one from class A
        // which returns a String
        assertScript '''
@@ -727,11 +728,9 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
     }
 
     void testFlowTypingWithStringVariable() {
-        // as anything can be assigned to a string, flow typing engine
-        // could "erase" the type of the original variable although is must not
         assertScript '''
-            String str = new Object() // type checker will not complain, anything assignable to a String
-            str.toUpperCase() // should not complain
+            String s = new Object() // anything assignable to String
+            s.toUpperCase()
         '''
     }
 
@@ -740,7 +739,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
             def o
             o = 1L
             o = 2
-            @ASTTest(phase=INSTRUCTION_SELECTION, value= {
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
                 assert node.rightExpression.accessedVariable.getNodeMetaData(DECLARATION_INFERRED_TYPE) == long_TYPE
             })
             def z = o
@@ -811,10 +810,10 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
                         returnValue = 1;
                         break;
                 }
-                @ASTTest(phase=INSTRUCTION_SELECTION,value={
-                    def ift = node.getNodeMetaData(INFERRED_TYPE)
-                    assert ift instanceof LUB
-                    assert ift.name == 'java.io.Serializable'
+                @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                    def type = node.getNodeMetaData(INFERRED_TYPE)
+                    assert type instanceof LUB
+                    assert type.name == 'java.io.Serializable'
                 })
                 def val = returnValue
 
@@ -823,7 +822,8 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testGroovy6215() {
+    // GROOVY-6215
+    void testSwitchCaseAnalysis2() {
         assertScript '''
             def processNumber(int x) {
                 def value = getValueForNumber(x)
@@ -866,8 +866,8 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
             assertScript """
             $orig b = 65 as $orig
             @ASTTest(phase=INSTRUCTION_SELECTION, value={
-                def rit = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
-                assert rit == make($dest)
+                def type = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
+                assert type == make($dest)
             })
             def pp = ++b
             println '++${orig} -> ' + pp.class + ' ' + pp
@@ -890,8 +890,8 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
             assertScript """
             $orig b = 65 as $orig
             @ASTTest(phase=INSTRUCTION_SELECTION, value={
-                def rit = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
-                assert rit == make($dest)
+                def type = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
+                assert type == make($dest)
             })
             def pp = b++
             println '${orig}++ -> ' + pp.class + ' ' + pp
@@ -912,11 +912,11 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
                     callable.call()
                 }
 
-                @ASTTest(phase=INSTRUCTION_SELECTION,value={
+                @ASTTest(phase=INSTRUCTION_SELECTION, value={
                     lookup('test').each {
                         def call = it.expression
-                        def irt = call.getNodeMetaData(INFERRED_TYPE)
-                        assert irt == LIST_TYPE
+                        def type = call.getNodeMetaData(INFERRED_TYPE)
+                        assert type == LIST_TYPE
                     }
                 })
                 static void run() {
@@ -935,7 +935,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
             public <T> T[] intArray(ArrayFactory<T> f) {
                 f.array()
             }
-            @ASTTest(phase=INSTRUCTION_SELECTION,value={
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
                 assert node.getNodeMetaData(INFERRED_TYPE) == Integer_TYPE.makeArray()
             })
             def array = intArray { new Integer[8] }
@@ -951,10 +951,10 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
                 f.list()
             }
 
-            @ASTTest(phase=INSTRUCTION_SELECTION,value={
-                def irt = node.getNodeMetaData(INFERRED_TYPE)
-                assert irt == LIST_TYPE
-                assert irt.genericsTypes[0].type == Integer_TYPE
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.getNodeMetaData(INFERRED_TYPE)
+                assert type == LIST_TYPE
+                assert type.genericsTypes[0].type == Integer_TYPE
             })
             def res = list { new LinkedList<Integer>() }
             assert res.size() == 0
@@ -995,7 +995,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
     void testShouldInferPrimitiveBoolean() {
         assertScript '''
             def foo(Boolean o) {
-                @ASTTest(phase=INSTRUCTION_SELECTION,value={
+                @ASTTest(phase=INSTRUCTION_SELECTION, value={
                     assert node.getNodeMetaData(INFERRED_TYPE) == boolean_TYPE
                 })
                 boolean b = o
@@ -1062,6 +1062,60 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         }
     }
 
+    // GROOVY-5655
+    void testByteArrayInference() {
+        assertScript '''
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                assert node.getNodeMetaData(INFERRED_TYPE) == byte_TYPE.makeArray()
+            })
+            def b = "foo".bytes
+            new String(b)
+        '''
+    }
+
+    // GROOVY-
+    void testGetAnnotationFails() {
+        assertScript '''
+            import groovy.transform.*
+            import java.lang.annotation.*
+
+            @Retention(RetentionPolicy.RUNTIME)
+            @Target([ElementType.FIELD])
+            @interface Ann1 {}
+
+            @Retention(RetentionPolicy.RUNTIME)
+            @Target([ElementType.FIELD])
+            @interface Ann2 {}
+
+            class A {
+                @Ann2
+                String field
+            }
+
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                lookup('second').each {
+                    assert it.expression.getNodeMetaData(INFERRED_TYPE).name == 'Ann2'
+                }
+            })
+            def doit(obj, String propName) {
+                def field = obj.getClass().getDeclaredField(propName)
+                if (field) {
+                    @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                        assert node.getNodeMetaData(INFERRED_TYPE).name == 'Ann1'
+                    })
+                    def annotation = field.getAnnotation Ann1
+                    if(true) {
+                        second: annotation = field.getAnnotation Ann2
+                    }
+                    return annotation
+                }
+                return null
+            }
+
+            assert Ann2.isAssignableFrom(doit(new A(), "field").class)
+        '''
+    }
+
     // GROOVY-9077
     void testInferredTypeForPropertyThatResolvesToMethod() {
         assertScript '''
@@ -1094,4 +1148,27 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
             meth()
         '''
     }
+
+    // GROOVY-10089
+    void testInferredTypeForMapOfList() {
+        assertScript '''
+            void test(... attributes) {
+                List one = [
+                    [id:'x', options:[count:1]]
+                ]
+                List two = attributes.collect {
+                    def node = Collections.singletonMap('children', one)
+                    if (node) {
+                        node = node.get('children').find { child -> child['id'] == 'x' }
+                    }
+                    // inferred type of node must be something like Map<String,List<...>>
+
+                    [id: it['id'], name: node['name'], count: node['options']['count']]
+                    //                                        ^^^^^^^^^^^^^^^ GroovyCastException (map ctor for Collection)
+                }
+            }
+
+            test( [id:'x'] )
+        '''
+    }
 }
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
index e5e3948c28..32a6202527 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
@@ -1159,7 +1159,7 @@ assert it.next() == 1G
                 def ift = node.getNodeMetaData(INFERRED_TYPE)
                 assert ift == make(Set)
                 assert ift.isUsingGenerics()
-                assert ift.genericsTypes[0].type==STRING_TYPE
+                assert ift.genericsTypes[0].name == 'java.lang.String'
             })
             def set = map.keySet()
             def key = set[0]
@@ -1171,7 +1171,7 @@ assert it.next() == 1G
                 def ift = node.getNodeMetaData(INFERRED_TYPE)
                 assert ift == make(Set)
                 assert ift.isUsingGenerics()
-                assert ift.genericsTypes[0].name=='K'
+                assert ift.genericsTypes[0].name == 'java.lang.Object'
             })
             def set = map.keySet()
             def key = set[0]
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/TypeInferenceStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/TypeInferenceStaticCompileTest.groovy
index 40fc4e7184..afe168980f 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/TypeInferenceStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/TypeInferenceStaticCompileTest.groovy
@@ -21,73 +21,7 @@ package org.codehaus.groovy.classgen.asm.sc
 import groovy.transform.stc.TypeInferenceSTCTest
 
 /**
- * Unit tests for static type checking : type inference.
+ * Unit tests for static compilation : type inference.
  */
 class TypeInferenceStaticCompileTest extends TypeInferenceSTCTest implements StaticCompilationTestSupport {
-
-    // GROOVY-5655
-    void testByteArrayInference() {
-        assertScript '''
-                @ASTTest(phase=INSTRUCTION_SELECTION, value={
-                    assert node.getNodeMetaData(INFERRED_TYPE) == byte_TYPE.makeArray()
-                })
-                def b = "foo".bytes
-                new String(b)
-            '''
-    }
-
-    @Override
-    void testShouldNotThrowIncompatibleArgToFunVerifyError() {
-        try {
-            super.testShouldNotThrowIncompatibleArgToFunVerifyError()
-        } finally {
-//            println astTrees
-        }
-    }
-
-    // GROOVY-
-    void testGetAnnotationFail() {
-            assertScript '''import groovy.transform.*
-    import java.lang.annotation.ElementType;
-    import java.lang.annotation.Retention;
-    import java.lang.annotation.RetentionPolicy;
-    import java.lang.annotation.Target;
-
-            @Retention(RetentionPolicy.RUNTIME)
-            @Target([ElementType.FIELD])
-            @interface Ann1 {}
-            @Retention(RetentionPolicy.RUNTIME)
-            @Target([ElementType.FIELD])
-            @interface Ann2 {}
-
-            class A {
-                @Ann2
-                String field
-            }
-
-                @ASTTest(phase=INSTRUCTION_SELECTION,value={
-                    lookup('second').each {
-                      assert it.expression.getNodeMetaData(INFERRED_TYPE).name == 'Ann2'
-                    }
-                })
-                def doit(obj, String propName) {
-                def field = obj.getClass().getDeclaredField propName
-                println field
-                if(field) {
-                    @ASTTest(phase=INSTRUCTION_SELECTION,value={
-                        assert node.getNodeMetaData(INFERRED_TYPE).name == 'Ann1'
-                    })
-                    def annotation = field.getAnnotation Ann1
-                    if(true) {
-                        second: annotation = field.getAnnotation Ann2
-                    }
-                    return annotation
-                }
-                return null
-            }
-
-            assert Ann2.isAssignableFrom (doit(new A(), "field").class)
-            '''
-    }
 }
-