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/08/30 20:47:51 UTC

[groovy] branch GROOVY_2_5_X updated: GROOVY-10088: STC: apply receiver generics to setter parameter

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 d08345b5a4 GROOVY-10088: STC: apply receiver generics to setter parameter
d08345b5a4 is described below

commit d08345b5a4f6908dcf014d93aefdae236814097e
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Aug 30 15:47:38 2022 -0500

    GROOVY-10088: STC: apply receiver generics to setter parameter
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 31 +++++++++++++++++-----
 .../groovy/transform/stc/GenericsSTCTest.groovy    |  2 +-
 2 files changed, 26 insertions(+), 7 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 6e311a2d9b..ec271d106b 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -28,6 +28,7 @@ import groovy.transform.TypeCheckingMode;
 import groovy.transform.stc.ClosureParams;
 import groovy.transform.stc.ClosureSignatureConflictResolver;
 import groovy.transform.stc.ClosureSignatureHint;
+import org.apache.groovy.internal.util.Function;
 import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.AnnotatedNode;
@@ -388,6 +389,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             visitClass(innerClassNode);
         }
         typeCheckingContext.alreadyVisitedMethods = oldVisitedMethod;
+        typeCheckingContext.popEnclosingClassNode();
+        if (type != null) {
+            typeCheckingContext.popErrorCollector();
+        }
         node.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, node);
         // mark all methods as visited. We can't do this in visitMethod because the type checker
         // works in a two pass sequence and we don't want to skip the second pass
@@ -776,6 +781,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         try {
             final Expression leftExpression = expression.getLeftExpression();
             final Expression rightExpression = expression.getRightExpression();
+
             leftExpression.visit(this); final ClassNode lType, rType;
             SetterInfo setterInfo = removeSetterInfo(leftExpression);
             if (setterInfo != null) {
@@ -959,6 +965,19 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         // but we must check if the binary expression is an assignment
         // because we need to check if a setter uses @DelegatesTo
         VariableExpression ve = varX("%", setterInfo.receiverType);
+        ve.setType(setterInfo.receiverType); // same as origin type
+
+        Function<MethodNode, ClassNode> firstParamType = new Function<MethodNode, ClassNode>() {
+            @Override public ClassNode apply(final MethodNode method) {
+                ClassNode type = method.getParameters()[0].getOriginType();
+                if (!method.isStatic() && !(method instanceof ExtensionMethodNode) && GenericsUtils.hasUnresolvedGenerics(type)) {
+                    Map<GenericsTypeName, GenericsType> spec = extractPlaceHolders(null, setterInfo.receiverType, method.getDeclaringClass());
+                    type = applyGenericsContext(spec, type);
+                }
+                return type;
+            }
+        };
+
         // for compound assignment "x op= y" find type as if it was "x = (x op y)"
         final Expression newRightExpression = isCompoundAssignment(expression)
                 ? binX(leftExpression, getOpWithoutEqual(expression), rightExpression)
@@ -971,7 +990,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             // this may happen if there's a setter of type boolean/String/Class, and that we are using the property
             // notation AND that the RHS is not a boolean/String/Class
             for (MethodNode setter : setterInfo.setters) {
-                ClassNode type = getWrapper(setter.getParameters()[0].getOriginType());
+                ClassNode type = getWrapper(firstParamType.apply(setter));
                 if (Boolean_TYPE.equals(type) || STRING_TYPE.equals(type) || CLASS_Type.equals(type)) {
                     call = callX(ve, setterInfo.name, castX(type, newRightExpression));
                     call.setImplicitThis(false);
@@ -988,13 +1007,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 if (setter == directSetterCandidate) {
                     leftExpression.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, directSetterCandidate);
                     leftExpression.removeNodeMetaData(StaticTypesMarker.INFERRED_TYPE); // clear assumption
-                    storeType(leftExpression, getType(newRightExpression));
+                    ClassNode setterType = firstParamType.apply(setter);
+                    storeType(leftExpression, setterType);
                     break;
                 }
             }
             return false;
         } else {
-            ClassNode firstSetterType = setterInfo.setters.get(0).getParameters()[0].getOriginType();
+            ClassNode firstSetterType = firstParamType.apply(setterInfo.setters.get(0));
             addAssignmentError(firstSetterType, getType(newRightExpression), expression);
             return true;
         }
@@ -2522,7 +2542,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
                 candidates = findMethodsWithGenerated(receiverType, nameText);
                 if (isBeingCompiled(receiverType)) candidates.addAll(GROOVY_OBJECT_TYPE.getMethods(nameText));
-                candidates.addAll(findDGMMethodsForClassNode(getTransformLoader(), receiverType, nameText));
+                candidates.addAll(findDGMMethodsForClassNode(getSourceUnit().getClassLoader(), receiverType, nameText));
                 candidates = filterMethodsByVisibility(candidates);
                 if (!candidates.isEmpty()) {
                     break;
@@ -3382,7 +3402,6 @@ 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
             ClassNode expressionType = getType(objectExpression);
             if (!implementsInterfaceOrIsSubclassOf(expressionType, Collection_TYPE) && !expressionType.isArray()) {
                 addStaticTypeError("Spread operator can only be used on collection types", objectExpression);
@@ -5141,7 +5160,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             ArgumentListExpression args = new ArgumentListExpression();
             VariableExpression vexp = varX("$self", receiver);
             args.addExpression(vexp);
-            if (arguments instanceof TupleExpression) {
+            if (arguments instanceof TupleExpression) { // NO_ARGUMENTS
                 for (Expression argument : (TupleExpression) arguments) {
                     args.addExpression(argument);
                 }
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 5d41a83230..565bc441ce 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -1269,7 +1269,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
             new D<Number>().p = 'x'
         ''',
-        'Cannot assign value of type java.lang.String to variable of type T'
+        'Cannot assign value of type java.lang.String to variable of type java.lang.Number'
     }
 
     // GROOVY-10225