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 2021/03/28 19:49:44 UTC

[groovy] branch GROOVY-9844 created (now ce9e475)

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

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


      at ce9e475  GROOVY-7106, GROOVY-7274, GROOVY-8909, GROOVY-9844: [] and [:] call args

This branch includes the following new commits:

     new ce9e475  GROOVY-7106, GROOVY-7274, GROOVY-8909, GROOVY-9844: [] and [:] call args

The 1 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.


[groovy] 01/01: GROOVY-7106, GROOVY-7274, GROOVY-8909, GROOVY-9844: [] and [:] call args

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit ce9e47579f30601b74b6f92d4219a79522daa8ac
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun Mar 28 14:06:00 2021 -0500

    GROOVY-7106, GROOVY-7274, GROOVY-8909, GROOVY-9844: [] and [:] call args
---
 .../transform/stc/StaticTypeCheckingSupport.java   | 13 ++--
 .../transform/stc/StaticTypeCheckingVisitor.java   | 81 ++++++++++++++--------
 .../stc/ArraysAndCollectionsSTCTest.groovy         | 15 ++++
 .../groovy/transform/stc/GenericsSTCTest.groovy    |  6 +-
 .../groovy/transform/stc/MethodCallsSTCTest.groovy | 41 +++++++++--
 .../transform/stc/STCExtensionMethodsTest.groovy   | 77 ++++++++++----------
 .../groovy/transform/BuilderTransformTest.groovy   |  4 +-
 7 files changed, 157 insertions(+), 80 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 2286ed6..c54f23c 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -57,6 +57,7 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -162,6 +163,7 @@ public abstract class StaticTypeCheckingSupport {
     protected static final ClassNode ArrayList_TYPE = makeWithoutCaching(ArrayList.class);
     protected static final ClassNode Collection_TYPE = makeWithoutCaching(Collection.class);
     protected static final ClassNode Deprecated_TYPE = makeWithoutCaching(Deprecated.class);
+    protected static final ClassNode LinkedHashMap_TYPE = makeWithoutCaching(LinkedHashMap.class);
     protected static final ClassNode LinkedHashSet_TYPE = makeWithoutCaching(LinkedHashSet.class);
 
     protected static final Map<ClassNode, Integer> NUMBER_TYPES = Maps.of(
@@ -1451,15 +1453,12 @@ public abstract class StaticTypeCheckingSupport {
         Set<GenericsTypeName> fixedGenericsPlaceHolders = extractResolvedPlaceHolders(resolvedMethodGenerics);
 
         for (int i = 0, n = argumentTypes.length; i < n; i += 1) {
-            int pindex = min(i, parameters.length - 1);
-            ClassNode wrappedArgument = argumentTypes[i];
-            ClassNode type = parameters[pindex].getOriginType();
+            ClassNode argumentType = argumentTypes[i], parameterType = parameters[min(i, parameters.length - 1)].getOriginType();
+            failure |= inferenceCheck(fixedGenericsPlaceHolders, resolvedMethodGenerics, parameterType, argumentType, i >= parameters.length - 1);
 
-            failure = failure || inferenceCheck(fixedGenericsPlaceHolders, resolvedMethodGenerics, type, wrappedArgument, i >= parameters.length - 1);
-
-            // set real fixed generics for extension methods
-            if (isExtensionMethod && i == 0)
+            if (i == 0 && isExtensionMethod) { // set real fixed generics for extension methods
                 fixedGenericsPlaceHolders = extractResolvedPlaceHolders(resolvedMethodGenerics);
+            }
         }
         return !failure;
     }
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 7b6bc43..0b57a55 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -133,7 +133,9 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiPredicate;
 import java.util.function.Supplier;
+import java.util.stream.IntStream;
 
 import static org.apache.groovy.util.BeanUtils.capitalize;
 import static org.apache.groovy.util.BeanUtils.decapitalize;
@@ -228,6 +230,7 @@ import static org.codehaus.groovy.syntax.Types.MOD_EQUAL;
 import static org.codehaus.groovy.syntax.Types.PLUS_PLUS;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.ArrayList_TYPE;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.Collection_TYPE;
+import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.LinkedHashMap_TYPE;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.LinkedHashSet_TYPE;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.Matcher_TYPE;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.NUMBER_OPS;
@@ -319,9 +322,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     protected static final MethodNode GET_THISOBJECT = CLOSURE_TYPE.getGetterMethod("getThisObject");
     protected static final ClassNode DELEGATES_TO = ClassHelper.make(DelegatesTo.class);
     protected static final ClassNode DELEGATES_TO_TARGET = ClassHelper.make(DelegatesTo.Target.class);
-    protected static final ClassNode LINKEDHASHMAP_CLASSNODE = ClassHelper.make(LinkedHashMap.class);
     protected static final ClassNode CLOSUREPARAMS_CLASSNODE = ClassHelper.make(ClosureParams.class);
     protected static final ClassNode NAMED_PARAMS_CLASSNODE = ClassHelper.make(NamedParams.class);
+    @Deprecated protected static final ClassNode LINKEDHASHMAP_CLASSNODE = LinkedHashMap_TYPE;
     protected static final ClassNode ENUMERATION_TYPE = ClassHelper.make(Enumeration.class);
     protected static final ClassNode MAP_ENTRY_TYPE = ClassHelper.make(Map.Entry.class);
     protected static final ClassNode ITERABLE_TYPE = ClassHelper.ITERABLE_TYPE;
@@ -1390,9 +1393,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
         List<MethodNode> constructorList = findMethod(node, "<init>", arguments);
         if (constructorList.isEmpty()) {
-            if (isBeingCompiled(node) && arguments.length == 1 && LINKEDHASHMAP_CLASSNODE.equals(arguments[0])) {
+            if (isBeingCompiled(node) && arguments.length == 1 && LinkedHashMap_TYPE.equals(arguments[0])) {
                 // there will be a default hash map constructor added later
-                ConstructorNode cn = new ConstructorNode(Opcodes.ACC_PUBLIC, new Parameter[]{new Parameter(LINKEDHASHMAP_CLASSNODE, "args")}, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
+                ConstructorNode cn = new ConstructorNode(Opcodes.ACC_PUBLIC, new Parameter[]{new Parameter(LinkedHashMap_TYPE, "args")}, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
                 return cn;
             } else {
                 addStaticTypeError("No matching constructor found: " + node + toMethodParametersString("<init>", arguments), source);
@@ -2646,7 +2649,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 mn = findMethod(currentReceiver.getType(), name, args);
                 if (!mn.isEmpty()) {
                     if (mn.size() == 1) {
-                        // GROOVY-8961, GROOVY-9734, GROOVY-9915
+                        // GROOVY-8909, GROOVY-8961, GROOVY-9734, GROOVY-9844, GROOVY-9915, etc.
                         resolvePlaceholdersFromImplicitTypeHints(args, argumentList, mn.get(0));
                         typeCheckMethodsWithGenericsOrFail(currentReceiver.getType(), args, mn.get(0), call);
                     }
@@ -3527,7 +3530,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                                 returnType = typeCheckingContext.getEnclosingClassNode();
                             }
                         }
-                        // GROOVY-8961, GROOVY-9734
+                        // GROOVY-7106, GROOVY-7274, GROOVY-8909, GROOVY-8961, GROOVY-9734, GROOVY-9844, et al.
                         resolvePlaceholdersFromImplicitTypeHints(args, argumentList, directMethodCallCandidate);
                         if (typeCheckMethodsWithGenericsOrFail(chosenReceiver.getType(), args, directMethodCallCandidate, call)) {
                             returnType = adjustWithTraits(directMethodCallCandidate, chosenReceiver.getType(), args, returnType);
@@ -4363,16 +4366,24 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 }
             }
 
-            if (rightExpression instanceof ListExpression && !leftRedirect.equals(OBJECT_TYPE)) {
-                if (LIST_TYPE.equals(leftRedirect)
-                        || ITERABLE_TYPE.equals(leftRedirect)
-                        || Collection_TYPE.equals(leftRedirect)
-                        || ArrayList_TYPE.isDerivedFrom(leftRedirect)) { // GROOVY-6912
-                    return getLiteralResultType(left, right, ArrayList_TYPE); // GROOVY-7128
+            if (!leftRedirect.equals(OBJECT_TYPE)) {
+                if (rightExpression instanceof ListExpression) {
+                    if (LIST_TYPE.equals(leftRedirect)
+                            || ITERABLE_TYPE.equals(leftRedirect)
+                            || Collection_TYPE.equals(leftRedirect)
+                            || ArrayList_TYPE.isDerivedFrom(leftRedirect)) { // GROOVY-6912
+                        return getLiteralResultType(left, right, ArrayList_TYPE); // GROOVY-7128
+                    }
+                    if (SET_TYPE.equals(leftRedirect)
+                            || LinkedHashSet_TYPE.isDerivedFrom(leftRedirect)) { // GROOVY-6912
+                        return getLiteralResultType(left, right, LinkedHashSet_TYPE); // GROOVY-7128
+                    }
                 }
-                if (SET_TYPE.equals(leftRedirect)
-                        || LinkedHashSet_TYPE.isDerivedFrom(leftRedirect)) { // GROOVY-6912
-                    return getLiteralResultType(left, right, LinkedHashSet_TYPE); // GROOVY-7128
+                if (rightExpression instanceof MapExpression) {
+                    if (MAP_TYPE.equals(leftRedirect)
+                            || LinkedHashMap_TYPE.isDerivedFrom(leftRedirect)) {
+                        return getLiteralResultType(left, right, LinkedHashMap_TYPE); // GROOVY-7128, GROOVY-9844
+                    }
                 }
             }
 
@@ -4430,15 +4441,24 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
      * the literal may be composed of sub-types of {@code Type}. In these cases,
      * {@code ArrayList<Type>} is an appropriate result type for the expression.
      */
-    private ClassNode getLiteralResultType(final ClassNode targetType, final ClassNode sourceType, final ClassNode baseType) {
+    private static ClassNode getLiteralResultType(final ClassNode targetType, final ClassNode sourceType, final ClassNode baseType) {
         ClassNode resultType = sourceType.equals(baseType) ? sourceType
                 : GenericsUtils.parameterizeType(sourceType, baseType.getPlainNodeReference());
 
         if (targetType.getGenericsTypes() != null
                 && !GenericsUtils.buildWildcardType(targetType).isCompatibleWith(resultType)) {
+            BiPredicate<GenericsType, GenericsType> isEqualOrSuper = (target, source) -> {
+                if (target.isCompatibleWith(source.getType())) {
+                    return true;
+                }
+                if (!target.isPlaceholder() && !target.isWildcard()) {
+                    return GenericsUtils.buildWildcardType(getCombinedBoundType(target)).isCompatibleWith(source.getType());
+                }
+                return false;
+            };
+
             GenericsType[] lgt = targetType.getGenericsTypes(), rgt = resultType.getGenericsTypes();
-            if (!lgt[0].isPlaceholder() && !lgt[0].isWildcard() && GenericsUtils.buildWildcardType(
-                    getCombinedBoundType(lgt[0])).isCompatibleWith(getCombinedBoundType(rgt[0]))) {
+            if (IntStream.range(0, lgt.length).allMatch(i -> isEqualOrSuper.test(lgt[i], rgt[i]))) {
                 resultType = GenericsUtils.parameterizeType(targetType, baseType.getPlainNodeReference());
             }
         }
@@ -4446,7 +4466,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         return resultType;
     }
 
-    private ClassNode getMathResultType(final int op, final ClassNode leftRedirect, final ClassNode rightRedirect, final String operationName) {
+    private static ClassNode getMathResultType(final int op, final ClassNode leftRedirect, final ClassNode rightRedirect, final String operationName) {
         if (isNumberType(leftRedirect) && isNumberType(rightRedirect)) {
             if (isOperationInGroup(op)) {
                 if (isIntCategory(leftRedirect) && isIntCategory(rightRedirect)) return int_TYPE;
@@ -5145,7 +5165,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     }
 
     protected ClassNode inferMapExpressionType(final MapExpression map) {
-        ClassNode mapType = LINKEDHASHMAP_CLASSNODE.getPlainNodeReference();
+        ClassNode mapType = LinkedHashMap_TYPE.getPlainNodeReference();
         List<MapEntryExpression> entryExpressions = map.getMapEntryExpressions();
         int nExpressions = entryExpressions.size();
         if (nExpressions == 0) return mapType;
@@ -5293,24 +5313,29 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
      * method target of "m", {@code T} could be resolved.
      */
     private static void resolvePlaceholdersFromImplicitTypeHints(final ClassNode[] actuals, final ArgumentListExpression argumentList, final MethodNode inferredMethod) {
-        for (int i = 0, n = actuals.length; i < n; i += 1) {
-            // check for method call with known target
+        int np = inferredMethod.getParameters().length;
+        for (int i = 0, n = actuals.length; np > 0 && i < n; i += 1) {
             Expression a = argumentList.getExpression(i);
+            Parameter p = inferredMethod.getParameters()[Math.min(i, np - 1)];
+
+            ClassNode at = actuals[i], pt = p.getOriginType();
+            if (i >= (np - 1) && pt.isArray() && !at.isArray()) pt = pt.getComponentType();
+
+            if (a instanceof ListExpression) {
+                actuals[i] = getLiteralResultType(pt, at, ArrayList_TYPE);
+            } else if (a instanceof MapExpression) {
+                actuals[i] = getLiteralResultType(pt, at, LinkedHashMap_TYPE);
+            }
+
+            // check for method call with known target
             if (!(a instanceof MethodCallExpression)) continue;
             if (((MethodCallExpression) a).isUsingGenerics()) continue;
             MethodNode aNode = a.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
             if (aNode == null || aNode.getGenericsTypes() == null) continue;
 
             // and unknown generics
-            ClassNode at = actuals[i];
             if (!GenericsUtils.hasUnresolvedGenerics(at)) continue;
 
-            int np = inferredMethod.getParameters().length;
-            Parameter p = inferredMethod.getParameters()[Math.min(i, np - 1)];
-
-            ClassNode pt = p.getOriginType();
-            if (i >= (np - 1) && pt.isArray() && !at.isArray()) pt = pt.getComponentType();
-
             // try to resolve placeholder(s) in argument type using parameter type
 
             Map<GenericsTypeName, GenericsType> linked = new HashMap<>();
diff --git a/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy b/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
index fa96651..35ac761 100644
--- a/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
@@ -741,4 +741,19 @@ class ArraysAndCollectionsSTCTest extends StaticTypeCheckingTestCase {
             assert set.last() == 3
         '''
     }
+
+    void testMapWithTypeArgumentsInitializedByMapLiteral() {
+        ['CharSequence,Integer', 'String,Number', 'CharSequence,Number'].each { spec ->
+            assertScript """
+                Map<$spec> map = [a:1,b:2,c:3]
+                assert map.size() == 3
+                assert map['c'] == 3
+                assert 'x' !in map
+            """
+        }
+
+        shouldFailWithMessages '''
+            Map<String,Integer> map = [1:2]
+        ''', 'Cannot assign java.util.LinkedHashMap <java.lang.Integer, java.lang.Integer> to: java.util.Map <String, Integer>'
+    }
 }
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 83f141f..638d14c 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -1586,7 +1586,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
                 println arg1 == arg2
             }
             printEqual(1, ['foo'])
-        ''', '#printEqual(T, java.util.List <T>) with arguments [int, java.util.List <java.lang.String>]'
+        ''', '#printEqual(T, java.util.List <T>) with arguments [int, java.util.ArrayList <java.lang.String>]'
     }
 
     // GROOVY-9902
@@ -1854,7 +1854,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
                 static <T extends List<? extends CharSequence>> void bar(T a) {}
             }
             Foo.bar([new Object()])
-        ''', 'Cannot call <T extends java.util.List<? extends java.lang.CharSequence>> Foo#bar(T) with arguments [java.util.List <java.lang.Object>]'
+        ''', 'Cannot call <T extends java.util.List<? extends java.lang.CharSequence>> Foo#bar(T) with arguments [java.util.ArrayList <java.lang.Object>]'
     }
 
     void testOutOfBoundsBySuperGenericParameterType() {
@@ -1863,7 +1863,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
                 static <T extends List<? super CharSequence>> void bar(T a) {}
             }
             Foo.bar(['abc'])
-        ''', 'Cannot call <T extends java.util.List<? super java.lang.CharSequence>> Foo#bar(T) with arguments [java.util.List <java.lang.String>]'
+        ''', 'Cannot call <T extends java.util.List<? super java.lang.CharSequence>> Foo#bar(T) with arguments [java.util.ArrayList <java.lang.String>]'
     }
 
     void testOutOfBoundsByExtendsPlaceholderParameterType() {
diff --git a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
index c1bd7f0..f077def 100644
--- a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
@@ -20,7 +20,6 @@ package groovy.transform.stc
 
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
 import org.codehaus.groovy.control.customizers.ImportCustomizer
-import groovy.test.NotYetImplemented
 
 /**
  * Unit tests for static type checking : method calls.
@@ -207,11 +206,45 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {
         ''', 'Cannot call groovy.transform.stc.MethodCallsSTCTest$MyMethodCallTestClass2#identity(java.lang.Integer[]) with arguments [java.lang.String[]]'
     }
 
-    @NotYetImplemented // GROOVY-8909
+    // GROOVY-8909
     void testGenericMethodCall4() {
         assertScript '''
-            def m(List<Object> list) { }
-            m([1, 2, 3]) // List<Integer>
+            void m(List<Object> list) {
+                assert list.size() == 3
+            }
+            m([1,2,3])
+        '''
+        // no coercion like assignment
+        shouldFailWithMessages '''
+            void m(Set<Integer> set) {
+            }
+            m([1,2,3,3])
+        ''', 'm(java.util.List <java.lang.Integer>). Please check if the declared type is correct and if the method exists.'
+    }
+
+    // GROOVY-7106, GROOVY-7274, GROOVY-9844
+    void testGenericMethodCall5() {
+        assertScript '''
+            void m(Map<CharSequence,Number> map) {
+                assert map.size() == 3
+                assert map['a'] == 1
+                assert 'z' !in map
+            }
+            m([a:1,b:2,c:3])
+        '''
+
+        assertScript '''
+            void m(Map<String,Object> map) {
+            }
+            m([d:new Date(), i:1, s:""])
+        '''
+
+        assertScript '''
+            void m(Map<String,Object> map) {
+            }
+            ['x'].each {
+                m([(it): it.toLowerCase()])
+            }
         '''
     }
 
diff --git a/src/test/groovy/transform/stc/STCExtensionMethodsTest.groovy b/src/test/groovy/transform/stc/STCExtensionMethodsTest.groovy
index 169ab1c..fa538aa 100644
--- a/src/test/groovy/transform/stc/STCExtensionMethodsTest.groovy
+++ b/src/test/groovy/transform/stc/STCExtensionMethodsTest.groovy
@@ -18,60 +18,65 @@
  */
 package groovy.transform.stc
 
-import org.codehaus.groovy.runtime.m12n.ExtensionModuleHelperForTests
+import static org.codehaus.groovy.runtime.m12n.ExtensionModuleHelperForTests.doInFork
 
 /**
  * Unit tests for static type checking : extension methods.
  */
 class STCExtensionMethodsTest extends StaticTypeCheckingTestCase {
 
-    void testShouldFindExtensionMethod() {
+    void testStaticExtensionMethod() {
         assertScript '''
-            // reverseToUpperCase is an extension method specific to unit tests
-            def str = 'This is a string'
-            assert str.reverseToUpperCase() == str.toUpperCase().reverse()
             assert String.answer() == 42
         '''
     }
 
-    void testShouldFindExtensionMethodWithGrab() {
-        ExtensionModuleHelperForTests.doInFork('groovy.transform.stc.StaticTypeCheckingTestCase', '''
-        def impl = new MetaClassImpl(String)
-        impl.initialize()
-        String.metaClass = impl
-        ExtensionModuleRegistry registry = GroovySystem.metaClassRegistry.moduleRegistry
-        // ensure that the module isn't loaded
-        assert !registry.modules.any { it.name == 'Test module for Grab' && it.version == '1.3' }
-
-        // find jar resource
-        def jarURL = this.class.getResource("/jars")
-        assert jarURL
-
-        def resolver = "@GrabResolver(name='local',root='$jarURL')"
-
-        assertScript resolver + """
-        @Grab('module-test:module-test:1.4')
-        import org.codehaus.groovy.runtime.m12n.*
+    void testNonStaticExtensionMethod() {
+        assertScript '''
+            def str = 'This is a string'
+            // reverseToUpperCase is a usnit test extension method
+            assert str.reverseToUpperCase() == str.toUpperCase().reverse()
+        '''
+    }
 
-        // the following methods are added by the Grab test module
-        def str = 'This is a string'
-        assert str.reverseToUpperCase2() == str.toUpperCase().reverse()
-        // a static method added to String thanks to a @Grab extension
-        assert String.answer2() == 42
-        """
-        ''')
+    // GROOVY-7953
+    void testExtensionPropertyWithPrimitiveReceiver() {
+        assertScript '''
+            assert 4.even
+        '''
     }
 
     void testExtensionMethodWithGenericsAndPrimitiveReceiver() {
         assertScript '''
             assert 2d.groovy6496(2d) == 2d
-    '''
+        '''
     }
 
-    //GROOVY-7953
-    void testExtensionPropertyWithPrimitiveReceiver() {
-        assertScript '''
-            assert 4.even
+    void testShouldFindExtensionMethodWithGrab() {
+        doInFork 'groovy.transform.stc.StaticTypeCheckingTestCase', '''
+            def impl = new MetaClassImpl(String)
+            impl.initialize()
+            String.metaClass = impl
+            ExtensionModuleRegistry registry = GroovySystem.metaClassRegistry.moduleRegistry
+            // ensure that the module isn't loaded
+            assert !registry.modules.any { it.name == 'Test module for Grab' && it.version == '1.3' }
+
+            // find jar resource
+            def jarURL = this.class.getResource('/jars')
+            assert jarURL
+
+            def resolver = "@GrabResolver(name='local',root='$jarURL')"
+
+            assertScript resolver + """
+                @Grab('module-test:module-test:1.4')
+                import org.codehaus.groovy.runtime.m12n.*
+
+                // the following methods are added by the Grab test module
+                def str = 'This is a string'
+                assert str.reverseToUpperCase2() == str.toUpperCase().reverse()
+                // a static method added to String thanks to a @Grab extension
+                assert String.answer2() == 42
+            """
         '''
     }
-}
\ No newline at end of file
+}
diff --git a/src/test/org/codehaus/groovy/transform/BuilderTransformTest.groovy b/src/test/org/codehaus/groovy/transform/BuilderTransformTest.groovy
index a200ff6..461fd45 100644
--- a/src/test/org/codehaus/groovy/transform/BuilderTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/BuilderTransformTest.groovy
@@ -232,7 +232,7 @@ class BuilderTransformTest extends CompilableTestSupport {
                 CookBook.builder().recipes([35, 42]).build()
             }
         '''
-        assert message =~ /.*Cannot call.*recipes.*java.util.List\s?<java.lang.String>.*with arguments.*java.util.List\s?<java.lang.Integer>.*/
+        assert message =~ /.*Cannot call.*recipes.*java.util.List\s?<java.lang.String>.*with arguments.*java.util.(Array)?List\s?<java.lang.Integer>.*/
     }
 
     void testInitializerGenerics() {
@@ -261,7 +261,7 @@ class BuilderTransformTest extends CompilableTestSupport {
                 new CookBook(CookBook.createInitializer().recipes([35, 42]))
             }
         '''
-        assert message =~ /.*Cannot call.*recipes.*java.util.List\s?<java.lang.String>.*with arguments.*java.util.List\s?<java.lang.Integer>.*/
+        assert message =~ /.*Cannot call.*recipes.*java.util.List\s?<java.lang.String>.*with arguments.*java.util.(Array)?List\s?<java.lang.Integer>.*/
     }
 
     void testDefaultBuilderCustomNames() {