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 18:02:39 UTC

[groovy] branch GROOVY_2_5_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_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 316ea3e1ac GROOVY-9033: STC: resolve "def list = []" to List<Object> not List<E>
316ea3e1ac is described below

commit 316ea3e1ac1c38cf247047eff6c6898861f4cd65
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Apr 6 15:36:08 2022 -0500

    GROOVY-9033: STC: resolve "def list = []" to List<Object> not List<E>
    
    GROOVY-10089, GROOVY-10235, GROOVY-10324, GROOVY-10367
    
    2_5_X backport
---
 .../transform/stc/StaticTypeCheckingSupport.java   |  54 ++--
 .../transform/stc/StaticTypeCheckingVisitor.java   |  95 +++----
 src/test/groovy/bugs/Groovy8609Bug.groovy          | 176 ++++++------
 .../groovy/transform/stc/GenericsSTCTest.groovy    |  84 +++++-
 .../transform/stc/TypeInferenceSTCTest.groovy      | 313 +++++++++++++--------
 .../classgen/asm/sc/BugsStaticCompileTest.groovy   |   4 +-
 .../asm/sc/TypeInferenceStaticCompileTest.groovy   |  68 +----
 7 files changed, 431 insertions(+), 363 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 95af881c87..67980dc670 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1346,7 +1346,7 @@ public abstract class StaticTypeCheckingSupport {
      * Given a generics type representing SomeClass&lt;T,V&gt; and a resolved placeholder map, returns a new generics type
      * for which placeholders are resolved recursively.
      */
-    protected static GenericsType fullyResolve(GenericsType gt, Map<GenericsTypeName, GenericsType> placeholders) {
+    protected static GenericsType fullyResolve(GenericsType gt, final Map<GenericsTypeName, GenericsType> placeholders) {
         GenericsType fromMap = placeholders.get(new GenericsTypeName(gt.getName()));
         if (gt.isPlaceholder() && fromMap != null) {
             gt = fromMap;
@@ -1370,31 +1370,37 @@ 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; i < gts.length; i++) {
-                    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();
+                }
+                ClassNode cn = type.redirect();
+                return cn != type ? cn : OBJECT_TYPE;
+            } else {
+                GenericsType[] gts = type.getGenericsTypes();
+                if (gts != null) {  final int n = gts.length;
+                    GenericsType[] copy = new GenericsType[n];
+                    for (int i = 0; i < n; i += 1) {
+                        GenericsType gt = gts[i];
+                        if (gt.isPlaceholder()) {
+                            GenericsTypeName gtn = new GenericsTypeName(gt.getName());
+                            copy[i] = placeholders.containsKey(gtn)
+                                ? placeholders.get(gtn) : extractType(gt).asGenericsType();
+                        } else {
+                            copy[i] = fullyResolve(gt, placeholders);
+                        }
                     }
+                    gts = copy;
                 }
-                gts = copy;
+                ClassNode cn = type.getPlainNodeReference();
+                cn.setGenericsTypes(gts);
+                return cn;
             }
-            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();
-            }
-        } else if (type.isArray()) {
-            return fullyResolveType(type.getComponentType(), placeholders).makeArray();
         }
         return type;
     }
@@ -1804,7 +1810,7 @@ public abstract class StaticTypeCheckingSupport {
 
     public static ClassNode getCorrectedClassNode(ClassNode type, ClassNode superClass, boolean handlingGenerics) {
         ClassNode corrected;
-        if (handlingGenerics && missesGenericsTypes(type)) {
+        if (handlingGenerics && GenericsUtils.hasUnresolvedGenerics(type)) {
             corrected = superClass.getPlainNodeReference();
         } else {
             corrected = 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 6a8a4ee826..37445a392f 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -185,7 +185,6 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.isOrImplements;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.localVarX;
 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;
@@ -836,20 +835,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 }
             }
 
-            if (lType.isUsingGenerics() && missesGenericsTypes(resultType) && isAssignment(op)) {
-                // 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
@@ -868,21 +853,42 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     addNoMatchingMethodError(lType, "putAt", arguments, enclosingBinaryExpression);
                 }
             }
-            boolean isEmptyDeclaration = expression instanceof DeclarationExpression && rightExpression instanceof EmptyExpression;
+
+            boolean isEmptyDeclaration = (expression instanceof DeclarationExpression && rightExpression instanceof EmptyExpression);
             if (!isEmptyDeclaration && isAssignment(op)) {
-                if (rightExpression instanceof ConstructorCallExpression) {
+                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();
@@ -891,14 +897,13 @@ 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);
+                        if (enclosing == null) enclosing = Collections.emptyMap();
+                        resultType = fullyResolveType(resultType, enclosing);
                     }
                 }
 
-                // make sure we keep primitive types
-                if (isPrimitiveType(originType) && resultType.equals(getWrapper(originType))) {
-                    resultType = originType;
-                }
-
                 // track conditional assignment
                 if (!isNullConstant(rightExpression)
                         && leftExpression instanceof VariableExpression
@@ -930,8 +935,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                         }
                     }
                 }
-
-
             } else if (op == KEYWORD_INSTANCEOF) {
                 pushInstanceOfTypeInfo(leftExpression, rightExpression);
             }
@@ -1249,9 +1252,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     private void checkTypeGenerics(ClassNode leftExpressionType, ClassNode wrappedRHS, 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) ||
@@ -1335,6 +1338,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         typeCheckingContext.popEnclosingBinaryExpression();
     }
 
+    @Deprecated
     protected static boolean hasRHSIncompleteGenericTypeInfo(final ClassNode inferredRightExpressionType) {
         boolean replaceType = false;
         GenericsType[] genericsTypes = inferredRightExpressionType.getGenericsTypes();
@@ -5403,7 +5407,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         return declaringClass;
     }
 
-    private Map<GenericsTypeName, GenericsType> resolvePlaceHoldersFromDeclaration(ClassNode receiver, ClassNode declaration, MethodNode method, boolean isStaticTarget) {
+    private static Map<GenericsTypeName, GenericsType> resolvePlaceHoldersFromDeclaration(ClassNode receiver, ClassNode declaration, MethodNode method, boolean isStaticTarget) {
         Map<GenericsTypeName, GenericsType> resolvedPlaceholders;
         if (isStaticTarget && CLASS_Type.equals(receiver) &&
                 receiver.isUsingGenerics() &&
@@ -5488,35 +5492,28 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         return resolvedPlaceholders;
     }
 
-    protected boolean typeCheckMethodsWithGenericsOrFail(ClassNode receiver, ClassNode[] arguments, MethodNode candidateMethod, Expression location) {
+    protected boolean typeCheckMethodsWithGenericsOrFail(final ClassNode receiver, final ClassNode[] arguments, final MethodNode candidateMethod, final Expression location) {
         if (!typeCheckMethodsWithGenerics(receiver, arguments, candidateMethod)) {
-            Map<GenericsTypeName, GenericsType> spec = 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(), spec);
+                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) + "#" +
-                    toMethodParametersString(candidateMethod.getName(), paramTypes) +
-                    " with arguments " + formatArgumentList(arguments), location);
+            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(MethodNode node) {
-        GenericsType[] genericsTypes = node.getGenericsTypes();
-
-        if (genericsTypes == null)
-            return "";
-
-        return toGenericTypesString(genericsTypes);
-    }
-
     protected static String formatArgumentList(ClassNode[] nodes) {
         if (nodes == null || nodes.length == 0) return "[] ";
         StringBuilder sb = new StringBuilder(24 * nodes.length);
diff --git a/src/test/groovy/bugs/Groovy8609Bug.groovy b/src/test/groovy/bugs/Groovy8609Bug.groovy
index bfc021fe85..593d6d9c36 100644
--- a/src/test/groovy/bugs/Groovy8609Bug.groovy
+++ b/src/test/groovy/bugs/Groovy8609Bug.groovy
@@ -18,128 +18,122 @@
  */
 package groovy.bugs
 
-import gls.CompilableTestSupport
+final class Groovy8609Bug extends GroovyTestCase {
 
-class Groovy8609Bug extends CompilableTestSupport {
     void testUpperBoundWithGenerics() {
         assertScript '''
-        @groovy.transform.CompileStatic
-        public class A<T extends List<E>, E extends Map<String, Integer>> {
-            E getFirstRecord(T recordList) {
-                return recordList.get(0)
-            }
-            
-            static void main(args) {
-                def list = new ArrayList<HashMap<String, Integer>>()
-                def record = new HashMap<String, Integer>()
-                list.add(record)
-                def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>()
-                assert record.is(a.getFirstRecord(list))
+            @groovy.transform.CompileStatic
+            public class A<T extends List<E>, E extends Map<String, Integer>> {
+                E getFirstRecord(T recordList) {
+                    return recordList.get(0)
+                }
+
+                static void main(args) {
+                    def list = new ArrayList<HashMap<String, Integer>>()
+                    def record = new HashMap<String, Integer>()
+                    list.add(record)
+                    def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>()
+                    assert record.is(a.getFirstRecord(list))
+                }
             }
-        }
         '''
     }
 
     void testUpperBoundWithoutGenerics() {
         assertScript '''
-        @groovy.transform.CompileStatic
-        public class A<T extends List<E>, E extends Map> {
-            E getFirstRecord(T recordList) {
-                return recordList.get(0);
-            }
-            
-            static void main(args) {
-                def list = new ArrayList<HashMap<String, Integer>>()
-                def record = new HashMap<String, Integer>()
-                list.add(record)
-                def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>()
-                assert record.is(a.getFirstRecord(list))
+            @groovy.transform.CompileStatic
+            public class A<T extends List<E>, E extends Map> {
+                E getFirstRecord(T recordList) {
+                    return recordList.get(0);
+                }
+
+                static void main(args) {
+                    def list = new ArrayList<HashMap<String, Integer>>()
+                    def record = new HashMap<String, Integer>()
+                    list.add(record)
+                    def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>()
+                    assert record.is(a.getFirstRecord(list))
+                }
             }
-        }
         '''
     }
 
     void testNoUpperBound() {
         assertScript '''
-        @groovy.transform.CompileStatic
-        public class A<T extends List<E>, E> {
-            E getFirstRecord(T recordList) {
-                return recordList.get(0);
-            }
-            
-            static void main(args) {
-                def list = new ArrayList<HashMap<String, Integer>>()
-                def record = new HashMap<String, Integer>()
-                list.add(record)
-                def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>()
-                assert record.is(a.getFirstRecord(list))
+            @groovy.transform.CompileStatic
+            public class A<T extends List<E>, E> {
+                E getFirstRecord(T recordList) {
+                    return recordList.get(0);
+                }
+
+                static void main(args) {
+                    def list = new ArrayList<HashMap<String, Integer>>()
+                    def record = new HashMap<String, Integer>()
+                    list.add(record)
+                    def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>()
+                    assert record.is(a.getFirstRecord(list))
+                }
             }
-        }
         '''
     }
 
     void testUpperBoundWithGenericsThroughWrongType() {
-        def errMsg = shouldFail '''
-        @groovy.transform.CompileStatic
-        public class A<T extends List<E>, E extends Map<String, Integer>> {
-            E getFirstRecord(T recordList) {
-                return recordList.get(0)
-            }
-            
-            static void main(args) {
-                def list = new ArrayList<TreeMap<String, Integer>>()
-                def record = new TreeMap<String, Integer>()
-                list.add(record)
-                def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>()
-                assert record.is(a.getFirstRecord(list))
+        def err = shouldFail '''
+            @groovy.transform.CompileStatic
+            public class A<T extends List<E>, E extends Map<String, Integer>> {
+                E getFirstRecord(T recordList) {
+                    return recordList.get(0)
+                }
+
+                static void main(args) {
+                    def list = new ArrayList<TreeMap<String, Integer>>()
+                    def record = new TreeMap<String, Integer>()
+                    list.add(record)
+                    def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>()
+                    assert record.is(a.getFirstRecord(list))
+                }
             }
-        }
         '''
-
-        assert errMsg.contains('[Static type checking] - Cannot call A <ArrayList, HashMap>#getFirstRecord(T) with arguments [java.util.ArrayList <TreeMap>]')
+        assert err.contains('#getFirstRecord(java.util.ArrayList <HashMap>)')
     }
 
     void testUpperBoundWithGenericsThroughWrongType2() {
-        def errMsg = shouldFail '''
-        @groovy.transform.CompileStatic
-        public class A<T extends List<E>, E extends Map<String, Integer>> {
-            E getFirstRecord(T recordList) {
-                return recordList.get(0)
-            }
-            
-            static void main(args) {
-                def list = new ArrayList<HashMap<String, Long>>()
-                def record = new HashMap<String, Long>()
-                list.add(record)
-                def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>()
-                assert record.is(a.getFirstRecord(list))
+        def err = shouldFail '''
+            @groovy.transform.CompileStatic
+            public class A<T extends List<E>, E extends Map<String, Integer>> {
+                E getFirstRecord(T recordList) {
+                    return recordList.get(0)
+                }
+
+                static void main(args) {
+                    def list = new ArrayList<HashMap<String, Long>>()
+                    def record = new HashMap<String, Long>()
+                    list.add(record)
+                    def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>()
+                    assert record.is(a.getFirstRecord(list))
+                }
             }
-        }
         '''
-
-        // TODO we should print generics details, e.g. [Static type checking] - Cannot call A <ArrayList, HashMap<String, Integer>>#getFirstRecord(T) with arguments [java.util.ArrayList <HashMap<String, Long>>]
-        assert errMsg.contains('[Static type checking] - Cannot call A <ArrayList, HashMap>#getFirstRecord(T) with arguments [java.util.ArrayList <HashMap>]')
+        assert err.contains('#getFirstRecord(java.util.ArrayList <HashMap>)')
     }
 
     void testUpperBoundWithGenericsThroughWrongType3() {
-        def errMsg = shouldFail '''
-        @groovy.transform.CompileStatic
-        public class A<T extends List<E>, E extends Map<String, Integer>> {
-            E getFirstRecord(T recordList) {
-                return recordList.get(0)
-            }
-            
-            static void main(args) {
-                def list = new ArrayList<HashMap<StringBuffer, Integer>>()
-                def record = new HashMap<StringBuffer, Integer>()
-                list.add(record)
-                def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>()
-                assert record.is(a.getFirstRecord(list))
+        def err = shouldFail '''
+            @groovy.transform.CompileStatic
+            public class A<T extends List<E>, E extends Map<String, Integer>> {
+                E getFirstRecord(T recordList) {
+                    return recordList.get(0)
+                }
+
+                static void main(args) {
+                    def list = new ArrayList<HashMap<StringBuffer, Integer>>()
+                    def record = new HashMap<StringBuffer, Integer>()
+                    list.add(record)
+                    def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>()
+                    assert record.is(a.getFirstRecord(list))
+                }
             }
-        }
         '''
-
-        // TODO we should print generics details, e.g. [Static type checking] - Cannot call A <ArrayList, HashMap<String, Integer>>#getFirstRecord(T) with arguments [java.util.ArrayList <HashMap<StringBuffer, Integer>>]
-        assert errMsg.contains('[Static type checking] - Cannot call A <ArrayList, HashMap>#getFirstRecord(T) with arguments [java.util.ArrayList <HashMap>]')
+        assert err.contains('#getFirstRecord(java.util.ArrayList <HashMap>)')
     }
 }
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 6516ecb130..b8e6237387 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -198,16 +198,16 @@ 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) {
-                }
+            interface Handle {
+                Result getResult()
             }
             class HandleContainer<H extends Handle> {
                 H handle
             }
-            interface Handle {
-                Result getResult()
+            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 Result {
                 int itemCount
@@ -230,6 +230,53 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
             assert getStrings(null,[]).isEmpty()
         '''
+
+        assertScript '''
+            interface Handle {
+                int getCount()
+            }
+            class HandleContainer<H extends Handle> {
+                H handle
+            }
+            interface Input {
+                HandleContainer<? extends Handle> getResult(key)
+            }
+            interface State {
+                def <X extends Handle> HandleContainer<X> getResult(key)
+            }
+
+            void test(Input input, State state) {
+                def container = state.getResult('k') ?: input.getResult('k')
+                Handle handle = container.handle
+                Integer count = handle.count
+                assert count == 1
+            }
+
+            Handle h = {->1}
+            def c = new HandleContainer(handle: h)
+            test({k->c} as Input, {k->c} as State)
+        '''
+    }
+
+    // GROOVY-9033
+    void testReturnTypeInferenceWithMethodGenerics8() {
+        shouldFailWithMessages '''
+            List<String> test() {
+              def x = [].each { }
+              x.add(new Object())
+              return x // List<E>
+            }
+        ''',
+        'Incompatible generic argument types.' // Cannot assign java.util.List<java.lang.Object> to: java.util.List<java.lang.String>
+
+        assertScript '''
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.getNodeMetaData(INFERRED_TYPE)
+                assert type.genericsTypes[0].toString() == 'java.lang.String'
+                assert type.genericsTypes[1].toString() == 'java.util.List<java.lang.Object>' // not List<E>
+            })
+            def map = [ key: [] ]
+        '''
     }
 
     void testDiamondInferrenceFromConstructor1() {
@@ -256,6 +303,31 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-10324
+    void testDiamondInferrenceFromConstructor20() {
+        assertScript '''
+            class C<T> {
+            }
+            def <X> X m(C<X> c) {
+            }
+            List<String> x = m(new C<>())
+        '''
+    }
+
+    // GROOVY-10367
+    void testDiamondInferrenceFromConstructor26() {
+        assertScript '''
+            @groovy.transform.TupleConstructor(defaults=false)
+            class C<X, Y extends X> { // works without Y
+              X x
+            }
+            def <Z extends Number> void test(Z z) {
+              z = new C<>(z).x // Cannot assign value of type Object to variable of type Z
+            }
+            test(null)
+        '''
+    }
+
     // GROOVY-10280
     void testTypeArgumentPropagation() {
         assertScript '''
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index 8fe23b8a1f..ac10b0501c 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -35,10 +35,10 @@ import org.codehaus.groovy.transform.stc.StaticTypesMarker
 class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
 
     void testStringToInteger() {
-        assertScript """
-        def name = "123" // we want type inference
-        name.toInteger() // toInteger() is defined by DGM
-        """
+        assertScript '''
+            def name = "123" // we want type inference
+            name.toInteger() // toInteger() is defined by DGM
+        '''
     }
 
     // GROOVY-9935
@@ -62,76 +62,72 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testAnnotationOnSingleMethod() {
-        GroovyShell shell = new GroovyShell()
-        shell.evaluate '''
-            // calling a method which has got some dynamic stuff in it
-
-            import groovy.transform.TypeChecked
-            import groovy.xml.MarkupBuilder
+    void testDynamicMethodWithinTypeCheckedClass() {
+        assertScript '''
+            import groovy.transform.*
 
-            class Greeter {
-                @TypeChecked
-                String greeting(String name) {
-                    generateMarkup(name.toUpperCase())
+            class C {
+                String m(String s) {
+                    generateMarkup(s.toUpperCase())
                 }
 
-                // MarkupBuilder is dynamic so we won't do typechecking here
-                String generateMarkup(String name) {
+                // MarkupBuilder is dynamic so skip type-checking
+                @TypeChecked(TypeCheckingMode.SKIP)
+                String generateMarkup(String s) {
                     def sw = new StringWriter()
-                    def mkp = new MarkupBuilder()
-                    mkp.html {
+                    def mb = new groovy.xml.MarkupBuilder(sw)
+                    mb.html {
                         body {
-                            div name
+                            div s
                         }
                     }
-                    sw
+                    sw.toString()
                 }
             }
 
-            def g = new Greeter()
-            g.greeting("Guillaume")
-
+            def c = new C()
+            def xml = c.m('x')
+            // TODO: check XML
         '''
     }
 
     void testInstanceOf() {
-        assertScript """
-        Object o
-        if (o instanceof String) o.toUpperCase()
-        """
+        assertScript '''
+            Object o
+            if (o instanceof String) o.toUpperCase()
+        '''
     }
 
     void testEmbeddedInstanceOf() {
-        assertScript """
-        Object o
-        if (o instanceof Object) {
-            if (o instanceof String) {
-                o.toUpperCase()
+        assertScript '''
+            Object o
+            if (o instanceof Object) {
+                if (o instanceof String) {
+                    o.toUpperCase()
+                }
             }
-        }
-        """
+        '''
     }
 
     void testEmbeddedInstanceOf2() {
-        assertScript """
-        Object o
-        if (o instanceof String) {
-            if (true) {
-                o.toUpperCase()
+        assertScript '''
+            Object o
+            if (o instanceof String) {
+                if (true) {
+                    o.toUpperCase()
+                }
             }
-        }
-        """
+        '''
     }
 
     void testEmbeddedInstanceOf3() {
         shouldFailWithMessages '''
-        Object o
-        if (o instanceof String) {
-            if (o instanceof Object) { // causes the inferred type of 'o' to be overwritten
-                o.toUpperCase()
+            Object o
+            if (o instanceof String) {
+                if (o instanceof Object) { // causes the inferred type of 'o' to be overwritten
+                    o.toUpperCase()
+                }
             }
-        }
         ''', 'Cannot find matching method java.lang.Object#toUpperCase()'
     }
 
@@ -151,7 +147,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
             if (o instanceof String) {
                o.toUpperCase()
             } else {
-                o.toUpperCase() // ensure that type information is lost in else()
+                o.toUpperCase() // ensure that type information is lost in else
             }
         ''', 'Cannot find matching method java.lang.Object#toUpperCase()'
     }
@@ -166,6 +162,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
             }
             class Task<R extends Face> implements java.util.concurrent.Callable<String> {
                 R request
+
                 @Override
                 String call() {
                     if (request instanceof Impl) {
@@ -193,7 +190,6 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
                void foo2() { println 'ok 2' }
             }
 
-
             def o = new A()
 
             if (o instanceof A) {
@@ -207,7 +203,6 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
             if (o instanceof A || o instanceof B) {
               o.foo()
             }
-
         '''
     }
 
@@ -216,16 +211,11 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
             class A {
                int foo() { 1 }
             }
-
             class B {
                int foo2() { 2 }
             }
-
-
             def o = new A()
-
             int result = o instanceof A?o.foo():(o instanceof B?o.foo2():3)
-
         '''
     }
 
@@ -516,7 +506,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testShouldNotFailWithWithAndExplicitTypedIt() {
+    void testShouldFailWithWithAndWrongExplicitIt() {
         shouldFailWithMessages '''
             class A {
                 int x
@@ -556,8 +546,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 '''
@@ -572,6 +561,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
                 method().toUpperCase()
             }
         '''
+
        // check that if we switch signatures, it fails
        shouldFailWithMessages '''
             class A {
@@ -636,8 +626,6 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
             }
         '''
         assert method.code.statements[0].expression.leftExpression.getNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE) == ClassHelper.make(HashSet)
-
-
     }
 
     void testChooseMethodWithTypeInference() {
@@ -685,11 +673,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()
         '''
     }
 
@@ -698,7 +684,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
@@ -756,7 +742,8 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
     }
 
     void testSwitchCaseAnalysis() {
-        assertScript '''import org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode as LUB
+        assertScript '''
+            import org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode as LUB
 
             def method(int x) {
                 def returnValue= new Date()
@@ -768,10 +755,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
 
@@ -780,32 +767,33 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testGroovy6215() {
+    // GROOVY-6215
+    void testSwitchCaseAnalysis2() {
         assertScript '''
-                def processNumber(int x) {
-                    def value = getValueForNumber(x)
-                    value
-                }
+            def processNumber(int x) {
+                def value = getValueForNumber(x)
+                value
+            }
 
-                def getValueForNumber(int x) {
-                    def valueToReturn
-                    switch(x) {
-                        case 1:
-                            valueToReturn = 'One'
-                            break
-                        case 2:
-                            valueToReturn = []
-                            valueToReturn << 'Two'
-                            break
-                    }
-                    valueToReturn
+            def getValueForNumber(int x) {
+                def valueToReturn
+                switch(x) {
+                    case 1:
+                        valueToReturn = 'One'
+                        break
+                    case 2:
+                        valueToReturn = []
+                        valueToReturn << 'Two'
+                        break
                 }
-                def v1 = getValueForNumber(1)
-                def v2 = getValueForNumber(2)
-                def v3 = getValueForNumber(3)
-                assert v1 == 'One'
-                assert v2 == ['Two']
-                assert v3 == null
+                valueToReturn
+            }
+            def v1 = getValueForNumber(1)
+            def v2 = getValueForNumber(2)
+            def v3 = getValueForNumber(3)
+            assert v1 == 'One'
+            assert v2 == ['Two']
+            assert v3 == null
         '''
     }
 
@@ -823,8 +811,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
@@ -847,8 +835,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
@@ -860,29 +848,29 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
     // GROOVY-6522
     void testInferenceWithImplicitClosureCoercion() {
         assertScript '''
-interface CustomCallable<T> {
-    T call()
-}
+            interface CustomCallable<T> {
+                T call()
+            }
 
-class Thing {
-    static <T> T customType(CustomCallable<T> callable) {
-        callable.call()
-    }
+            class Thing {
+                static <T> T customType(CustomCallable<T> callable) {
+                    callable.call()
+                }
 
-    @ASTTest(phase=INSTRUCTION_SELECTION,value={
-        lookup('test').each {
-            def call = it.expression
-            def irt = call.getNodeMetaData(INFERRED_TYPE)
-            assert irt == LIST_TYPE
-        }
-    })
-    static void run() {
-        test: customType { [] } // return type is not inferred - fails compile
-    }
-}
+                @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                    lookup('test').each {
+                        def call = it.expression
+                        def type = call.getNodeMetaData(INFERRED_TYPE)
+                        assert type == LIST_TYPE
+                    }
+                })
+                static void run() {
+                    test: customType { [] } // return type is not inferred - fails compile
+                }
+            }
 
-Thing.run()
-'''
+            Thing.run()
+        '''
     }
 
     void testInferenceWithImplicitClosureCoercionAndArrayReturn() {
@@ -892,7 +880,7 @@ Thing.run()
             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] }
@@ -908,10 +896,10 @@ Thing.run()
                 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
@@ -952,7 +940,7 @@ Thing.run()
     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
@@ -1019,6 +1007,60 @@ Thing.run()
         }
     }
 
+    // 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-9847
     void testShouldKeepInferredTypeWhenPrivateInnerClass() {
         assertScript '''
@@ -1082,6 +1124,29 @@ Thing.run()
             }
 
             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 bb63f47165..69765c6999 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
@@ -1202,7 +1202,7 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati
                 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]
@@ -1214,7 +1214,7 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati
                 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)
-            '''
-    }
 }
-