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 2020/09/28 02:19:07 UTC

[groovy] branch master updated (939cbb3 -> 3cae41e)

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

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


    from 939cbb3  some it's -> its typo fixes
     new 6a38568  reuse object expression knowledge
     new 3cae41e  repair and reuse TypeCheckingExtension#buildListType

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:
 .../transform/stc/StaticTypeCheckingVisitor.java   | 154 +++++++++------------
 .../transform/stc/TypeCheckingExtension.java       |  25 ++--
 2 files changed, 76 insertions(+), 103 deletions(-)


[groovy] 02/02: repair and reuse TypeCheckingExtension#buildListType

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

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

commit 3cae41ea52e9cd62fce21b50c2c84e4a159da5cc
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun Sep 27 21:11:04 2020 -0500

    repair and reuse TypeCheckingExtension#buildListType
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 25 ++++++----------------
 .../transform/stc/TypeCheckingExtension.java       | 25 ++++++++++++----------
 2 files changed, 20 insertions(+), 30 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 0cdb70b..8b068bd 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1142,15 +1142,12 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         return null;
     }
 
-    private static ClassNode adjustTypeForSpreading(final ClassNode inferredRightExpressionType, final Expression leftExpression) {
+    private ClassNode adjustTypeForSpreading(final ClassNode inferredRightExpressionType, final Expression leftExpression) {
         // imagine we have: list*.foo = 100
         // then the assignment must be checked against [100], not 100
         ClassNode wrappedRHS = inferredRightExpressionType;
         if (leftExpression instanceof PropertyExpression && ((PropertyExpression) leftExpression).isSpreadSafe()) {
-            wrappedRHS = LIST_TYPE.getPlainNodeReference();
-            wrappedRHS.setGenericsTypes(new GenericsType[]{
-                    new GenericsType(getWrapper(inferredRightExpressionType))
-            });
+            wrappedRHS = extension.buildListType(inferredRightExpressionType);
         }
         return wrappedRHS;
     }
@@ -1679,9 +1676,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         PropertyExpression subExp = new PropertyExpression(varX("{}", contentType), pexp.getPropertyAsString());
         AtomicReference<ClassNode> result = new AtomicReference<>();
         if (existsProperty(subExp, true, new PropertyLookupVisitor(result))) {
-            ClassNode intf = LIST_TYPE.getPlainNodeReference();
-            intf.setGenericsTypes(new GenericsType[]{new GenericsType(getWrapper(result.get()))});
-            return intf;
+            return extension.buildListType(result.get());
         }
         return null;
     }
@@ -1695,10 +1690,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         PropertyExpression subExp = new PropertyExpression(varX("{}", types[0].getType()), pexp.getPropertyAsString());
         AtomicReference<ClassNode> result = new AtomicReference<>();
         if (existsProperty(subExp, true, new PropertyLookupVisitor(result))) {
-            intf = LIST_TYPE.getPlainNodeReference();
-            ClassNode itemType = result.get();
-            intf.setGenericsTypes(new GenericsType[]{new GenericsType(wrapTypeIfNecessary(itemType))});
-            return intf;
+            return extension.buildListType(result.get());
         }
         return null;
     }
@@ -1805,9 +1797,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
     protected void storeInferredTypeForPropertyExpression(final PropertyExpression pexp, final ClassNode flatInferredType) {
         if (pexp.isSpreadSafe()) {
-            ClassNode list = LIST_TYPE.getPlainNodeReference();
-            list.setGenericsTypes(new GenericsType[]{new GenericsType(flatInferredType)});
-            storeType(pexp, list);
+            storeType(pexp, extension.buildListType(flatInferredType));
         } else {
             storeType(pexp, flatInferredType);
         }
@@ -3303,10 +3293,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 subcall.setImplicitThis(call.isImplicitThis());
                 visitMethodCallExpression(subcall);
                 // the inferred type here should be a list of what the subcall returns
-                ClassNode subcallReturnType = getType(subcall);
-                ClassNode listType = LIST_TYPE.getPlainNodeReference();
-                listType.setGenericsTypes(new GenericsType[]{new GenericsType(wrapTypeIfNecessary(subcallReturnType))});
-                storeType(call, listType);
+                storeType(call, extension.buildListType(getType(subcall)));
                 storeTargetMethod(call, subcall.getNodeMetaData(DIRECT_METHOD_CALL_TARGET));
             }
             typeCheckingContext.popEnclosingMethodCall();
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/TypeCheckingExtension.java b/src/main/java/org/codehaus/groovy/transform/stc/TypeCheckingExtension.java
index d28d652..e0758dd 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/TypeCheckingExtension.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/TypeCheckingExtension.java
@@ -36,6 +36,7 @@ import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.ast.stmt.ReturnStatement;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -324,19 +325,21 @@ public class TypeCheckingExtension {
         return null;
     }
 
-    public ClassNode parameterizedType(ClassNode baseType, ClassNode... genericsTypeArguments) {
+    public ClassNode parameterizedType(final ClassNode baseType, final ClassNode... genericsTypeArguments) {
+        if (baseType.isArray()) {
+            return parameterizedType(baseType.getComponentType(), genericsTypeArguments).makeArray();
+        }
         ClassNode result = baseType.getPlainNodeReference();
-        if (result.isUsingGenerics()) {
-            GenericsType[] gts = new GenericsType[genericsTypeArguments.length];
-            int expectedLength = result.getGenericsTypes().length;
-            if (expectedLength!=genericsTypeArguments.length) {
-                throw new GroovyBugError("Expected number of generic type arguments for "+baseType.toString(false)+" is "+expectedLength
-                + " but you gave "+genericsTypeArguments.length);
-            }
-            for (int i = 0; i < gts.length; i++) {
-                gts[i] = new GenericsType(genericsTypeArguments[i]);
+        GenericsType[] generics = baseType.redirect().getGenericsTypes();
+        if (generics != null) {
+            int expectedLength = generics.length;
+            if (expectedLength != genericsTypeArguments.length) {
+                throw new GroovyBugError("Expected number of generic type arguments for " + baseType.toString(false) + " is " + expectedLength + " but you gave " + genericsTypeArguments.length);
             }
-            result.setGenericsTypes(gts);
+            result.setGenericsTypes(Arrays.stream(genericsTypeArguments)
+                    .map(StaticTypeCheckingVisitor::wrapTypeIfNecessary)
+                    .map(GenericsType::new).toArray(GenericsType[]::new)
+            );
         }
         return result;
     }


[groovy] 01/02: reuse object expression knowledge

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

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

commit 6a38568b2af9a10c96295061e2ea2774c5553b67
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun Sep 27 20:46:06 2020 -0500

    reuse object expression knowledge
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 135 +++++++++------------
 1 file changed, 59 insertions(+), 76 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 2dd8b3e..0cdb70b 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -2404,11 +2404,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 }
             }
 
-            int candidateCnt = candidates.size();
-            if (0 == candidateCnt) {
+            if (candidates.isEmpty()) {
                 candidates = extension.handleMissingMethod(
                     getType(expression.getExpression()), nameText, null, null, null);
-            } else if (candidateCnt > 1) {
+            } else if (candidates.size() > 1) {
                 candidates = extension.handleAmbiguousMethods(candidates, expression);
             }
 
@@ -3291,60 +3290,67 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         objectExpression.visit(this);
         call.getMethod().visit(this);
 
-        // if the call expression is a spread operator call, then we must make sure that
-        // the call is made on a collection type
+        ClassNode receiver = getType(objectExpression);
+        // if it's a spread operator call, then make sure receiver is array or collection
         if (call.isSpreadSafe()) {
-            // TODO: check if this should not be change to iterator based call logic
-            ClassNode expressionType = getType(objectExpression);
-            if (!implementsInterfaceOrIsSubclassOf(expressionType, Collection_TYPE) && !expressionType.isArray()) {
+            if (!receiver.isArray() && !implementsInterfaceOrIsSubclassOf(receiver, Collection_TYPE)) {
                 addStaticTypeError("Spread operator can only be used on collection types", objectExpression);
-                return;
             } else {
                 // type check call as if it was made on component type
-                ClassNode componentType = inferComponentType(expressionType, int_TYPE);
+                ClassNode componentType = inferComponentType(receiver, int_TYPE);
                 MethodCallExpression subcall = callX(castX(componentType, EmptyExpression.INSTANCE), name, call.getArguments());
-                subcall.setLineNumber(call.getLineNumber());
-                subcall.setColumnNumber(call.getColumnNumber());
+                subcall.setLineNumber(call.getLineNumber()); subcall.setColumnNumber(call.getColumnNumber());
                 subcall.setImplicitThis(call.isImplicitThis());
                 visitMethodCallExpression(subcall);
                 // the inferred type here should be a list of what the subcall returns
                 ClassNode subcallReturnType = getType(subcall);
-                ClassNode listNode = LIST_TYPE.getPlainNodeReference();
-                listNode.setGenericsTypes(new GenericsType[]{new GenericsType(wrapTypeIfNecessary(subcallReturnType))});
-                storeType(call, listNode);
-                // store target method
+                ClassNode listType = LIST_TYPE.getPlainNodeReference();
+                listType.setGenericsTypes(new GenericsType[]{new GenericsType(wrapTypeIfNecessary(subcallReturnType))});
+                storeType(call, listType);
                 storeTargetMethod(call, subcall.getNodeMetaData(DIRECT_METHOD_CALL_TARGET));
-                typeCheckingContext.popEnclosingMethodCall();
-                return;
             }
+            typeCheckingContext.popEnclosingMethodCall();
+            return;
         }
 
         Expression callArguments = call.getArguments();
         ArgumentListExpression argumentList = InvocationWriter.makeArgumentList(callArguments);
 
         checkForbiddenSpreadArgument(argumentList);
-
-        // for arguments, we need to visit closures *after* the method has been chosen
-
-        ClassNode receiver = getType(objectExpression);
+        // visit closures *after* the method has been chosen
         visitMethodCallArguments(receiver, argumentList, false, null);
 
-        ClassNode[] args = getArgumentTypes(argumentList);
-        boolean isCallOnClosure = isClosureCall(name, objectExpression, callArguments);
+        boolean isThisObjectExpression = isThisExpression(objectExpression);
+        boolean isCallOnClosure = false;
+        FieldNode fieldNode = null;
+        switch (name) {
+            case "call":
+            case "doCall":
+                if (!isThisObjectExpression) {
+                    isCallOnClosure = receiver.equals(CLOSURE_TYPE);
+                    break;
+                }
+            default:
+                if (isThisObjectExpression) {
+                    ClassNode enclosingType = typeCheckingContext.getEnclosingClassNode();
+                    fieldNode = enclosingType.getDeclaredField(name);
+                    if (fieldNode != null && getType(fieldNode).equals(CLOSURE_TYPE)
+                            && !enclosingType.hasPossibleMethod(name, callArguments)) {
+                        isCallOnClosure = true;
+                    }
+                }
+        }
 
         try {
+            ClassNode[] args = getArgumentTypes(argumentList);
             boolean callArgsVisited = false;
             if (isCallOnClosure) {
-                // this is a closure.call() call
-                if (isThisExpression(objectExpression)) {
-                    // isClosureCall() check verified earlier that a field exists
-                    FieldNode field = typeCheckingContext.getEnclosingClassNode().getDeclaredField(name);
-                    GenericsType[] genericsTypes = field.getType().getGenericsTypes();
+                if (fieldNode != null) {
+                    GenericsType[] genericsTypes = getType(fieldNode).getGenericsTypes();
                     if (genericsTypes != null) {
                         ClassNode closureReturnType = genericsTypes[0].getType();
-                        Object data = field.getNodeMetaData(CLOSURE_ARGUMENTS);
-                        if (data != null) {
-                            Parameter[] parameters = (Parameter[]) data;
+                        Parameter[] parameters = fieldNode.getNodeMetaData(CLOSURE_ARGUMENTS);
+                        if (parameters != null) {
                             typeCheckClosureCall(callArguments, args, parameters);
                         }
                         storeType(call, closureReturnType);
@@ -3352,19 +3358,16 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 } else if (objectExpression instanceof VariableExpression) {
                     Variable variable = findTargetVariable((VariableExpression) objectExpression);
                     if (variable instanceof ASTNode) {
-                        Object data = ((ASTNode) variable).getNodeMetaData(CLOSURE_ARGUMENTS);
-                        if (data != null) {
-                            Parameter[] parameters = (Parameter[]) data;
+                        Parameter[] parameters = ((ASTNode) variable).getNodeMetaData(CLOSURE_ARGUMENTS);
+                        if (parameters != null) {
                             typeCheckClosureCall(callArguments, args, parameters);
                         }
                         ClassNode type = getType(((ASTNode) variable));
-                        if (type != null && type.equals(CLOSURE_TYPE)) {
+                        if (CLOSURE_TYPE.equals(type)) {
                             GenericsType[] genericsTypes = type.getGenericsTypes();
                             type = OBJECT_TYPE;
-                            if (genericsTypes != null) {
-                                if (!genericsTypes[0].isPlaceholder()) {
-                                    type = genericsTypes[0].getType();
-                                }
+                            if (genericsTypes != null && !genericsTypes[0].isPlaceholder()) {
+                                type = genericsTypes[0].getType();
                             }
                         }
                         if (type != null) {
@@ -3375,24 +3378,17 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     // we can get actual parameters directly
                     Parameter[] parameters = ((ClosureExpression) objectExpression).getParameters();
                     typeCheckClosureCall(callArguments, args, parameters);
-                    ClassNode data = getInferredReturnType(objectExpression);
-                    if (data != null) {
-                        storeType(call, data);
+                    ClassNode type = getInferredReturnType(objectExpression);
+                    if (type != null) {
+                        storeType(call, type);
                     }
                 }
 
-                int nbOfArgs;
+                int nArgs = 0;
                 if (callArguments instanceof ArgumentListExpression) {
-                    ArgumentListExpression list = (ArgumentListExpression) callArguments;
-                    nbOfArgs = list.getExpressions().size();
-                } else {
-                    // todo : other cases
-                    nbOfArgs = 0;
+                    nArgs = ((ArgumentListExpression) callArguments).getExpressions().size();
                 }
-                storeTargetMethod(call,
-                        nbOfArgs == 0 ? CLOSURE_CALL_NO_ARG :
-                                nbOfArgs == 1 ? CLOSURE_CALL_ONE_ARG :
-                                        CLOSURE_CALL_VARGS);
+                storeTargetMethod(call, nArgs == 0 ? CLOSURE_CALL_NO_ARG : nArgs == 1 ? CLOSURE_CALL_ONE_ARG : CLOSURE_CALL_VARGS);
             } else {
                 // method call receivers are :
                 //   - possible "with" receivers
@@ -3413,7 +3409,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     // if we are not in a static context but the current receiver is a static class, we must
                     // ensure that all methods are either static or declared by the current receiver or a superclass
                     if (!mn.isEmpty()
-                            && (call.isImplicitThis() || isThisExpression(objectExpression))
+                            && (isThisObjectExpression || call.isImplicitThis())
                             && (typeCheckingContext.isInStaticContext || (receiverType.getModifiers() & Opcodes.ACC_STATIC) != 0)) {
                         // we create separate method lists just to be able to print out
                         // a nice error message to the user
@@ -3422,8 +3418,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                         List<MethodNode> accessibleMethods = new LinkedList<>();
                         List<MethodNode> inaccessibleMethods = new LinkedList<>();
                         for (final MethodNode node : mn) {
-                            if (node.isStatic()
-                                    || (!typeCheckingContext.isInStaticContext && implementsInterfaceOrIsSubclassOf(receiverType, node.getDeclaringClass()))) {
+                            if (node.isStatic() || (!typeCheckingContext.isInStaticContext
+                                    && implementsInterfaceOrIsSubclassOf(receiverType, node.getDeclaringClass()))) {
                                 accessibleMethods.add(node);
                             } else {
                                 inaccessibleMethods.add(node);
@@ -3443,7 +3439,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                         break;
                     }
                 }
-                if (mn.isEmpty() && call.isImplicitThis() && isThisExpression(objectExpression) && typeCheckingContext.getEnclosingClosure() != null) {
+                if (mn.isEmpty() && isThisObjectExpression && call.isImplicitThis() && typeCheckingContext.getEnclosingClosure() != null) {
                     mn = CLOSURE_TYPE.getDeclaredMethods(name);
                     if (!mn.isEmpty()) {
                         chosenReceiver = Receiver.make(CLOSURE_TYPE);
@@ -3463,14 +3459,15 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
                     if (mn.size() == 1) {
                         MethodNode directMethodCallCandidate = mn.get(0);
+                        ClassNode declaringClass = directMethodCallCandidate.getDeclaringClass();
                         if (call.getNodeMetaData(DYNAMIC_RESOLUTION) == null
-                                && !directMethodCallCandidate.isStatic() && objectExpression instanceof ClassExpression
-                                && !"java.lang.Class".equals(directMethodCallCandidate.getDeclaringClass().getName())) {
-                            ClassNode owner = directMethodCallCandidate.getDeclaringClass();
-                            addStaticTypeError("Non static method " + owner.getName() + "#" + directMethodCallCandidate.getName() + " cannot be called from static context", call);
+                                && objectExpression instanceof ClassExpression
+                                && !directMethodCallCandidate.isStatic()
+                                && !declaringClass.equals(CLASS_Type)) {
+                            addStaticTypeError("Non static method " + declaringClass.getName() + "#" + directMethodCallCandidate.getName() + " cannot be called from static context", call);
                         }
                         if (chosenReceiver == null) {
-                            chosenReceiver = Receiver.make(directMethodCallCandidate.getDeclaringClass());
+                            chosenReceiver = Receiver.make(declaringClass);
                         }
 
                         ClassNode returnType = getType(directMethodCallCandidate);
@@ -3831,20 +3828,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
     }
 
-    protected boolean isClosureCall(final String name, final Expression objectExpression, final Expression arguments) {
-        if (objectExpression instanceof ClosureExpression && ("call".equals(name) || "doCall".equals(name))) return true;
-        if (isThisExpression(objectExpression)) {
-            FieldNode fieldNode = typeCheckingContext.getEnclosingClassNode().getDeclaredField(name);
-            if (fieldNode != null && CLOSURE_TYPE.equals(fieldNode.getType())
-                    && !typeCheckingContext.getEnclosingClassNode().hasPossibleMethod(name, arguments)) {
-                return true;
-            }
-        } else if (!"call".equals(name) && !"doCall".equals(name)) {
-            return false;
-        }
-        return getType(objectExpression).equals(CLOSURE_TYPE);
-    }
-
     protected void typeCheckClosureCall(final Expression callArguments, final ClassNode[] args, final Parameter[] parameters) {
         if (allParametersAndArgumentsMatch(parameters, args) < 0 &&
                 lastArgMatchesVarg(parameters, args) < 0) {