You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2019/12/21 10:16:12 UTC

[groovy] branch GROOVY_3_0_X updated (3d3dad8 -> a62f6ad)

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

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


    from 3d3dad8  Tweak javadoc
     new a3287b9  minor edits
     new a62f6ad  GROOVY-9347: extract super-interface generics information for SAM coerce

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


Summary of changes:
 .../codehaus/groovy/ast/tools/GenericsUtils.java   |   4 +-
 .../transform/stc/StaticTypeCheckingVisitor.java   | 162 ++++++++--------
 .../gls/generics/GenericsUsageOrderingTest.groovy  | 212 +++++++++++----------
 src/test/groovy/transform/stc/LambdaTest.groovy    |   3 +-
 4 files changed, 193 insertions(+), 188 deletions(-)


[groovy] 02/02: GROOVY-9347: extract super-interface generics information for SAM coerce

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

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

commit a62f6ad62a5631f908018107fe559bfe61aeb92f
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Dec 20 13:45:51 2019 -0600

    GROOVY-9347: extract super-interface generics information for SAM coerce
    
    ['x'].forEach(e -> e._) // forEach(Consumer<? super T>) from Iterable<T>
    List<X> redirects to List<E> extends Collection<E> extends Iterable<T>
    
    (cherry picked from commit 1a23abd68232d338cc1fc88ed12f04116e45dc50)
---
 .../codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java  | 8 +++++++-
 src/test/groovy/transform/stc/LambdaTest.groovy                   | 3 +--
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 81bb15d..fea37f6 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -248,6 +248,7 @@ import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findDG
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findSetters;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findTargetVariable;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.fullyResolveType;
+import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getCorrectedClassNode;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getGenericsWithoutArray;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getOperationName;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf;
@@ -2749,7 +2750,12 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     private void inferSAMType(final Parameter param, final ClassNode receiver, final MethodNode methodWithSAMParameter, final ArgumentListExpression originalMethodCallArguments, final ClosureExpression openBlock) {
         // first we try to get as much information about the declaration class through the receiver
         Map<GenericsTypeName, GenericsType> targetMethodConnections = new HashMap<>();
-        extractGenericsConnections(targetMethodConnections, receiver, receiver.redirect());
+        for (ClassNode face : receiver.getAllInterfaces()) {
+            extractGenericsConnections(targetMethodConnections, getCorrectedClassNode(receiver, face, true), face.redirect());
+        }
+        if (!receiver.isInterface()) {
+            extractGenericsConnections(targetMethodConnections, receiver, receiver.redirect());
+        }
 
         // then we use the method with the SAM-type parameter to get more information about the declaration
         Parameter[] parametersOfMethodContainingSAM = methodWithSAMParameter.getParameters();
diff --git a/src/test/groovy/transform/stc/LambdaTest.groovy b/src/test/groovy/transform/stc/LambdaTest.groovy
index 0f33f84..fd37f63 100644
--- a/src/test/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/transform/stc/LambdaTest.groovy
@@ -18,7 +18,6 @@
  */
 package groovy.transform.stc
 
-import groovy.test.NotYetImplemented
 import groovy.transform.CompileStatic
 import org.junit.Test
 
@@ -1081,7 +1080,7 @@ final class LambdaTest {
         '''
     }
 
-    @Test @NotYetImplemented // GROOVY-9347
+    @Test // GROOVY-9347
     void testStaticInitializeBlocks2() {
         assertScript '''
             @groovy.transform.CompileStatic


[groovy] 01/02: minor edits

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

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

commit a3287b9a7d6fdb2ab847cda340972bb149e7b38e
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Dec 20 13:13:50 2019 -0600

    minor edits
    
    (cherry picked from commit 1026764fcbda84c96098c94a734d75f2720fa870)
---
 .../codehaus/groovy/ast/tools/GenericsUtils.java   |   4 +-
 .../transform/stc/StaticTypeCheckingVisitor.java   | 156 +++++++--------
 .../gls/generics/GenericsUsageOrderingTest.groovy  | 212 +++++++++++----------
 3 files changed, 186 insertions(+), 186 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
index 07d0262..691a5c2 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -868,7 +868,7 @@ public class GenericsUtils {
     private static Map<GenericsType, GenericsType> connectGenericsTypes(Map<GenericsType, GenericsType> genericsTypeMap) {
         Map<GenericsType, GenericsType> result = new LinkedHashMap<>();
 
-        outter:
+        outer:
         for (Map.Entry<GenericsType, GenericsType> entry : genericsTypeMap.entrySet()) {
             GenericsType key = entry.getKey();
             GenericsType value = entry.getValue();
@@ -878,7 +878,7 @@ public class GenericsUtils {
                     GenericsType genericsTypeMapEntryValue = genericsTypeMapEntry.getValue();
                     if (!genericsTypeMapEntryValue.isPlaceholder() && (genericsTypeMapEntry.getKey().getName().equals(value.getName()))) {
                         result.put(key, genericsTypeMapEntryValue); // connected to actual type
-                        continue outter;
+                        continue outer;
                     }
                 }
             }
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 9fb0317..81bb15d 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -727,9 +727,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
         typeCheckingContext.pushEnclosingBinaryExpression(expression);
         try {
+            int op = expression.getOperation().getType();
             Expression leftExpression = expression.getLeftExpression();
             Expression rightExpression = expression.getRightExpression();
-            int op = expression.getOperation().getType();
+
             leftExpression.visit(this);
             SetterInfo setterInfo = removeSetterInfo(leftExpression);
             ClassNode lType = null;
@@ -739,21 +740,17 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 }
             } else {
                 lType = getType(leftExpression);
-
-                Expression constructedRightExpression = rightExpression;
-
-                boolean isMethodRefRHS = (rightExpression instanceof MethodReferenceExpression && isFunctionalInterface(lType));
-                if (isMethodRefRHS) {
-                    constructedRightExpression = constructLambdaExpressionForMethodReference(lType);
-                }
-
-                inferParameterAndReturnTypesOfClosureOnRHS(lType, constructedRightExpression, op);
-
-                if (isMethodRefRHS) {
-                    LambdaExpression lambdaExpression = (LambdaExpression) constructedRightExpression;
+                boolean isFunctionalInterface = isFunctionalInterface(lType);
+                if (isFunctionalInterface && rightExpression instanceof MethodReferenceExpression) {
+                    LambdaExpression lambdaExpression = constructLambdaExpressionForMethodReference(lType);
+                    if (op == ASSIGN) {
+                        inferParameterAndReturnTypesOfClosureOnRHS(lType, lambdaExpression);
+                    }
                     rightExpression.putNodeMetaData(CONSTRUCTED_LAMBDA_EXPRESSION, lambdaExpression);
-                    rightExpression.putNodeMetaData(CLOSURE_ARGUMENTS,
-                            Arrays.stream(lambdaExpression.getParameters()).map(Parameter::getType).toArray(ClassNode[]::new));
+                    rightExpression.putNodeMetaData(CLOSURE_ARGUMENTS, Arrays.stream(lambdaExpression.getParameters()).map(Parameter::getType).toArray(ClassNode[]::new));
+
+                } else if (op == ASSIGN && isFunctionalInterface && rightExpression instanceof ClosureExpression) {
+                    inferParameterAndReturnTypesOfClosureOnRHS(lType, (ClosureExpression) rightExpression);
                 }
 
                 rightExpression.visit(this);
@@ -913,29 +910,25 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
     }
 
-    private void inferParameterAndReturnTypesOfClosureOnRHS(final ClassNode lType, final Expression rightExpression, final int op) {
-        if (ASSIGN == op) {
-            if (rightExpression instanceof ClosureExpression && isFunctionalInterface(lType)) {
-                Tuple2<ClassNode[], ClassNode> typeInfo = GenericsUtils.parameterizeSAM(lType);
-                ClassNode[] paramTypes = typeInfo.getV1();
-                ClosureExpression closureExpression = ((ClosureExpression) rightExpression);
-                Parameter[] closureParameters = getParametersSafe(closureExpression);
+    private void inferParameterAndReturnTypesOfClosureOnRHS(final ClassNode lhsType, final ClosureExpression rhsExpression) {
+        Tuple2<ClassNode[], ClassNode> typeInfo = GenericsUtils.parameterizeSAM(lhsType);
+        Parameter[] closureParameters = getParametersSafe(rhsExpression);
+        ClassNode[] parameterTypes = typeInfo.getV1();
 
-                if (paramTypes.length == closureParameters.length) {
-                    for (int i = 0, n = closureParameters.length; i < n; i++) {
-                        Parameter parameter = closureParameters[i];
-                        if (parameter.isDynamicTyped()) {
-                            parameter.setType(paramTypes[i]);
-                            parameter.setOriginType(paramTypes[i]);
-                        }
-                    }
-                } else {
-                    addStaticTypeError("Wrong number of parameters: ", closureExpression);
+        int n = closureParameters.length;
+        if (n == parameterTypes.length) {
+            for (int i = 0; i < n; i += 1) {
+                Parameter parameter = closureParameters[i];
+                if (parameter.isDynamicTyped()) {
+                    parameter.setType(parameterTypes[i]);
+                    parameter.setOriginType(parameterTypes[i]);
                 }
-
-                storeInferredReturnType(rightExpression, typeInfo.getV2());
             }
+        } else {
+            addStaticTypeError("Wrong number of parameters: ", rhsExpression);
         }
+
+        storeInferredReturnType(rhsExpression, typeInfo.getV2());
     }
 
     /**
@@ -2743,84 +2736,82 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
     }
 
+    /**
+     * In a method call with SAM coercion the inference is to be understood as a
+     * two phase process.  We have the normal method call to the target method
+     * with the closure argument and we have the SAM method that will be called
+     * inside the normal target method.  To infer correctly we have to "simulate"
+     * this process. We know the call to the closure will be done through the SAM
+     * type, so the SAM type generics deliver information about the Closure.  At
+     * the same time the SAM class is used in the target method parameter,
+     * providing a connection from the SAM type and the target method's class.
+     */
     private void inferSAMType(final Parameter param, final ClassNode receiver, final MethodNode methodWithSAMParameter, final ArgumentListExpression originalMethodCallArguments, final ClosureExpression openBlock) {
-        // In a method call with SAM coercion the inference is to be
-        // understood as a two phase process. We have the normal method call
-        // to the target method with the closure argument and we have the
-        // SAM method that will be called inside the normal target method.
-        // To infer correctly we have to "simulate" this process. We know the
-        // call to the closure will be done through the SAM type, so the SAM
-        // type generics deliver information about the Closure. At the same
-        // time the SAM class is used in the target method parameter,
-        // providing a connection from the SAM type and the target method
-        // declaration class.
-
-        // First we try to get as much information about the declaration
-        // class through the receiver
-        Map<GenericsTypeName, GenericsType> targetMethodDeclarationClassConnections = new HashMap<>();
-        extractGenericsConnections(targetMethodDeclarationClassConnections, receiver, receiver.redirect());
-        // then we use the method with the SAM parameter to get more information about the declaration
+        // first we try to get as much information about the declaration class through the receiver
+        Map<GenericsTypeName, GenericsType> targetMethodConnections = new HashMap<>();
+        extractGenericsConnections(targetMethodConnections, receiver, receiver.redirect());
+
+        // then we use the method with the SAM-type parameter to get more information about the declaration
         Parameter[] parametersOfMethodContainingSAM = methodWithSAMParameter.getParameters();
-        for (int i = 0; i < parametersOfMethodContainingSAM.length; i++) {
+        for (int i = 0, n = parametersOfMethodContainingSAM.length; i < n; i += 1) {
+            ClassNode parameterType = parametersOfMethodContainingSAM[i].getType();
             // potentially skip empty varargs
-            if (i == parametersOfMethodContainingSAM.length - 1
-                    && i == originalMethodCallArguments.getExpressions().size()
-                    && parametersOfMethodContainingSAM[i].getType().isArray())
+            if (i == (n - 1) && i == originalMethodCallArguments.getExpressions().size() && parameterType.isArray()) {
                 continue;
+            }
             Expression callArg = originalMethodCallArguments.getExpression(i);
             // we look at the closure later in detail, so skip it here
-            if (callArg == openBlock) continue;
-            ClassNode parameterType = parametersOfMethodContainingSAM[i].getType();
-            extractGenericsConnections(targetMethodDeclarationClassConnections, getType(callArg), parameterType);
+            if (callArg == openBlock) {
+                continue;
+            }
+            extractGenericsConnections(targetMethodConnections, getType(callArg), parameterType);
         }
 
         // To make a connection to the SAM class we use that new information
         // to replace the generics in the SAM type parameter of the target
         // method and than that to make the connections to the SAM type generics
-        ClassNode paramTypeWithReceiverInformation = applyGenericsContext(targetMethodDeclarationClassConnections, param.getOriginType());
-        Map<GenericsTypeName, GenericsType> SAMTypeConnections = new HashMap<>();
-        ClassNode classForSAM = paramTypeWithReceiverInformation.redirect();
-        extractGenericsConnections(SAMTypeConnections, paramTypeWithReceiverInformation, classForSAM);
+        ClassNode paramTypeWithReceiverInformation = applyGenericsContext(targetMethodConnections, param.getOriginType());
+        Map<GenericsTypeName, GenericsType> samTypeConnections = new HashMap<>();
+        ClassNode samTypeRedirect = paramTypeWithReceiverInformation.redirect();
+        extractGenericsConnections(samTypeConnections, paramTypeWithReceiverInformation, samTypeRedirect);
 
         // should the open block provide final information we apply that
         // to the corresponding parameters of the SAM type method
-        MethodNode methodForSAM = findSAM(classForSAM);
-        ClassNode[] parameterTypesForSAM = extractTypesFromParameters(methodForSAM.getParameters());
-        ClassNode[] blockParameterTypes = openBlock.getNodeMetaData(CLOSURE_ARGUMENTS);
-        if (blockParameterTypes == null) {
+        MethodNode abstractMethod = findSAM(samTypeRedirect);
+        ClassNode[] abstractMethodParamTypes = extractTypesFromParameters(abstractMethod.getParameters());
+        ClassNode[] blockParamTypes = openBlock.getNodeMetaData(CLOSURE_ARGUMENTS);
+        if (blockParamTypes == null) {
             Parameter[] p = openBlock.getParameters();
             if (p == null) {
                 // zero parameter closure e.g. { -> println 'no args' }
-                blockParameterTypes = ClassNode.EMPTY_ARRAY;
-            } else if (p.length == 0 && parameterTypesForSAM.length != 0) {
+                blockParamTypes = ClassNode.EMPTY_ARRAY;
+            } else if (p.length == 0 && abstractMethodParamTypes.length != 0) {
                 // implicit it
-                blockParameterTypes = parameterTypesForSAM;
+                blockParamTypes = abstractMethodParamTypes;
             } else {
-                blockParameterTypes = new ClassNode[p.length];
-                for (int i = 0; i < p.length; i++) {
+                blockParamTypes = new ClassNode[p.length];
+                for (int i = 0, n = p.length; i < n; i += 1) {
                     if (p[i] != null && !p[i].isDynamicTyped()) {
-                        blockParameterTypes[i] = p[i].getType();
+                        blockParamTypes[i] = p[i].getType();
                     } else {
-                        blockParameterTypes[i] = typeOrNull(parameterTypesForSAM, i);
+                        blockParamTypes[i] = typeOrNull(abstractMethodParamTypes, i);
                     }
                 }
             }
         }
-        for (int i = 0; i < blockParameterTypes.length; i++) {
-            extractGenericsConnections(SAMTypeConnections, blockParameterTypes[i], typeOrNull(parameterTypesForSAM, i));
+        for (int i = 0, n = blockParamTypes.length; i < n; i += 1) {
+            extractGenericsConnections(samTypeConnections, blockParamTypes[i], typeOrNull(abstractMethodParamTypes, i));
         }
 
-        // and finally we apply the generics information to the parameters and
+        // finally apply the generics information to the parameters and
         // store the type of parameter and block type as meta information
-        for (int i = 0; i < blockParameterTypes.length; i++) {
-            ClassNode resolvedParameter =
-                    applyGenericsContext(SAMTypeConnections, typeOrNull(parameterTypesForSAM, i));
-            blockParameterTypes[i] = resolvedParameter;
+        for (int i = 0, n = blockParamTypes.length; i < n; i += 1) {
+            blockParamTypes[i] = applyGenericsContext(samTypeConnections, typeOrNull(abstractMethodParamTypes, i));
         }
 
-        tryToInferUnresolvedBlockParameterType(paramTypeWithReceiverInformation, methodForSAM, blockParameterTypes);
+        tryToInferUnresolvedBlockParameterType(paramTypeWithReceiverInformation, abstractMethod, blockParamTypes);
 
-        openBlock.putNodeMetaData(CLOSURE_ARGUMENTS, blockParameterTypes);
+        openBlock.putNodeMetaData(CLOSURE_ARGUMENTS, blockParamTypes);
     }
 
     private void tryToInferUnresolvedBlockParameterType(final ClassNode paramTypeWithReceiverInformation, final MethodNode methodForSAM, final ClassNode[] blockParameterTypes) {
@@ -3212,7 +3203,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         // if the call expression is a spread operator call, then we must make sure that
         // the call is made on a collection type
         if (call.isSpreadSafe()) {
-            //TODO check if this should not be change to iterator based call logic
+            // TODO: check if this should not be change to iterator based call logic
             ClassNode expressionType = getType(objectExpression);
             if (!implementsInterfaceOrIsSubclassOf(expressionType, Collection_TYPE) && !expressionType.isArray()) {
                 addStaticTypeError("Spread operator can only be used on collection types", objectExpression);
@@ -3244,7 +3235,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
         // for arguments, we need to visit closures *after* the method has been chosen
 
-
         ClassNode receiver = getType(objectExpression);
         visitMethodCallArguments(receiver, argumentList, false, null);
 
diff --git a/src/test/gls/generics/GenericsUsageOrderingTest.groovy b/src/test/gls/generics/GenericsUsageOrderingTest.groovy
index 3801d8d..0f58fbd 100644
--- a/src/test/gls/generics/GenericsUsageOrderingTest.groovy
+++ b/src/test/gls/generics/GenericsUsageOrderingTest.groovy
@@ -18,149 +18,159 @@
  */
 package gls.generics
 
-import gls.CompilableTestSupport
+import groovy.transform.CompileStatic
+import org.junit.Test
 
-// GROOVY-6167
-class GenericsUsageOrderingTest extends CompilableTestSupport {
+import static groovy.test.GroovyAssert.assertScript
+import static groovy.test.GroovyAssert.shouldFail
+
+@CompileStatic
+final class GenericsUsageOrderingTest {
+
+    @Test
     void testGroovy6167() {
-        shouldCompile '''
-        public class Foo<T extends List<X>, X extends Number> {}
+        assertScript '''
+            class Foo<T extends List<X>, X extends Number> {
+            }
+            assert true
         '''
     }
 
+    @Test
     void testIncompatibleType1() {
-        def errMsg = shouldFail '''
-        @groovy.transform.CompileStatic
-        public class Foo<T extends List<X>, X extends Number> {
-            static void main(String[] args) {
-                def f = new Foo<ArrayList<String>, String>()
+        def err = shouldFail '''
+            @groovy.transform.CompileStatic
+            class Foo<T extends List<X>, X extends Number> {
+                static main(args) {
+                    def f = new Foo<ArrayList<String>, String>()
+                }
             }
-        }
         '''
-
-        assert errMsg.contains('The type String is not a valid substitute for the bounded parameter <X extends java.lang.Number>')
+        assert err.message.contains('The type String is not a valid substitute for the bounded parameter <X extends java.lang.Number>')
     }
 
+    @Test
     void testIncompatibleType2() {
-        def errMsg = shouldFail '''
-        @groovy.transform.CompileStatic
-        public class Foo<T extends List<X>, X extends Number> {
-            static void main(String[] args) {
-                def f = new Foo<HashSet<Integer>, Integer>()
+        def err = shouldFail '''
+            @groovy.transform.CompileStatic
+            class Foo<T extends List<X>, X extends Number> {
+                static main(args) {
+                    def f = new Foo<HashSet<Integer>, Integer>()
+                }
             }
-        }
         '''
-
-        assert errMsg.contains('The type HashSet is not a valid substitute for the bounded parameter <T extends java.util.List<X>>')
+        assert err.message.contains('The type HashSet is not a valid substitute for the bounded parameter <T extends java.util.List<X>>')
     }
 
+    @Test
     void testParameter() {
         assertScript '''
-        @groovy.transform.CompileStatic
-        public class Foo<T extends List<X>, X extends Number> {
-            X getFirstElement(T t) {
-                X x = t.get(0)
-                return x
+            @groovy.transform.CompileStatic
+            class Foo<T extends List<X>, X extends Number> {
+                X getFirstElement(T t) {
+                    X x = t.get(0)
+                    return x
+                }
+
+                static main(args) {
+                    def f = new Foo<ArrayList<Integer>, Integer>()
+                    def list = new ArrayList<Integer>()
+                    list.add(123)
+                    assert f.getFirstElement(list) == 123
+                }
             }
-
-            static void main(String[] args) {
-                def f = new Foo<ArrayList<Integer>, Integer>()
-                def list = new ArrayList<Integer>()
-                list.add(123)
-                assert 123 == f.getFirstElement(list)
-            }
-        }
         '''
     }
 
+    @Test
     void testVariable() {
         assertScript '''
-        @groovy.transform.CompileStatic
-        public class Foo<T extends List<X>, X extends Number> {
-            X getFirstElement() {
-                def list = new ArrayList<Integer>()
-                list.add(123)
-                T t = list
-                X x = t.get(0)
-                return x
-            }
-
-            static void main(String[] args) {
-                def f = new Foo<ArrayList<Integer>, Integer>()
-                assert 123 == f.getFirstElement()
+            @groovy.transform.CompileStatic
+            class Foo<T extends List<X>, X extends Number> {
+                X getFirstElement() {
+                    def list = new ArrayList<Integer>()
+                    list.add(123)
+                    T t = list
+                    X x = t.get(0)
+                    return x
+                }
+
+                static main(args) {
+                    def f = new Foo<ArrayList<Integer>, Integer>()
+                    assert f.getFirstElement() == 123
+                }
             }
-        }
         '''
     }
 
+    @Test
     void testField() {
         assertScript '''
-        @groovy.transform.CompileStatic
-        public class Foo<T extends List<X>, X extends Number> {
-            T t
-
-            {
-                def list = new ArrayList<Integer>()
-                list.add(123)
-                t = list
-            }
-
-            X getFirstElement() {
-                X x = t.get(0)
-                return x
+            @groovy.transform.CompileStatic
+            class Foo<T extends List<X>, X extends Number> {
+                T t
+
+                {
+                    def list = new ArrayList<Integer>()
+                    list.add(123)
+                    t = list
+                }
+
+                X getFirstElement() {
+                    X x = t.get(0)
+                    return x
+                }
+
+                static main(args) {
+                    def f = new Foo<ArrayList<Integer>, Integer>()
+                    assert f.getFirstElement() == 123
+                }
             }
-
-            static void main(String[] args) {
-                def f = new Foo<ArrayList<Integer>, Integer>()
-                assert 123 == f.getFirstElement()
-            }
-        }
         '''
     }
 
+    @Test
     void testParameter2() {
         assertScript '''
-        @groovy.transform.CompileStatic
-        public class Foo<T extends List<X>, X extends Number> {
-            X getFirstElement(List<X> list) {
-                X x = list.get(0)
-
-                assert Number == x.getClass().getGenericSuperclass()
-
-                return x
-            }
-
-            Number getFirstNumber(T t) {
-                return getFirstElement(t)
+            @groovy.transform.CompileStatic
+            class Foo<T extends List<X>, X extends Number> {
+                X getFirstElement(List<X> list) {
+                    X x = list.get(0)
+                    assert Number == x.getClass().getGenericSuperclass()
+                    return x
+                }
+
+                Number getFirstNumber(T t) {
+                    return getFirstElement(t)
+                }
+
+                static main(args) {
+                    def f = new Foo<ArrayList<Integer>, Integer>()
+                    def list = new ArrayList<Integer>()
+                    list.add(123)
+                    assert f.getFirstNumber(list) == 123
+                }
             }
-
-            static void main(String[] args) {
-                def f = new Foo<ArrayList<Integer>, Integer>()
-                def list = new ArrayList<Integer>()
-                list.add(123)
-                assert 123 == f.getFirstNumber(list)
-            }
-        }
         '''
     }
 
+    @Test
     void testParameterAndVariable() {
         assertScript '''
-        @groovy.transform.CompileStatic
-        public class Foo<T extends List<X>, X extends Number> {
-            X getFirstElement(List<X> t) {
-                X x = t.get(0)
-                return x
+            @groovy.transform.CompileStatic
+            class Foo<T extends List<X>, X extends Number> {
+                X getFirstElement(List<X> t) {
+                    X x = t.get(0)
+                    return x
+                }
+
+                static main(args) {
+                    def f = new Foo<ArrayList<Integer>, Integer>()
+                    def list = new ArrayList<Integer>()
+                    list.add(123)
+                    assert f.getFirstElement(list) == 123
+                }
             }
-
-            static void main(String[] args) {
-                def f = new Foo<ArrayList<Integer>, Integer>()
-                def list = new ArrayList<Integer>()
-                list.add(123)
-                assert 123 == f.getFirstElement(list)
-            }
-        }
         '''
     }
-
 }