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


The following commit(s) were added to refs/heads/master by this push:
     new fb954ba542 GROOVY-11375: STC: binary operator handling
fb954ba542 is described below

commit fb954ba5424facdd89ddfcb4ee08b733b019a1d8
Author: Eric Milles <eric.mil...@thomsonreuters.com>
AuthorDate: Wed Jun 26 20:41:47 2024 -0500

    GROOVY-11375: STC: binary operator handling
---
 .../classgen/asm/sc/StaticTypesCallSiteWriter.java | 120 +++++++++------------
 .../classgen/asm/sc/StaticTypesTypeChooser.java    |  15 +--
 .../transform/stc/StaticTypeCheckingVisitor.java   |  10 +-
 .../groovy/transform/stc/STCAssignmentTest.groovy  |   2 +-
 .../transform/stc/STCnAryExpressionTest.groovy     |  20 ++++
 5 files changed, 89 insertions(+), 78 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
index 9d4158e431..ee6949c80a 100644
--- 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
+++ 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
@@ -19,7 +19,6 @@
 package org.codehaus.groovy.classgen.asm.sc;
 
 import org.codehaus.groovy.GroovyBugError;
-import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.FieldNode;
@@ -41,7 +40,6 @@ import org.codehaus.groovy.classgen.asm.CallSiteWriter;
 import org.codehaus.groovy.classgen.asm.CompileStack;
 import org.codehaus.groovy.classgen.asm.MethodCallerMultiAdapter;
 import org.codehaus.groovy.classgen.asm.OperandStack;
-import org.codehaus.groovy.classgen.asm.TypeChooser;
 import org.codehaus.groovy.classgen.asm.VariableSlotLoader;
 import org.codehaus.groovy.runtime.InvokerHelper;
 import org.codehaus.groovy.syntax.SyntaxException;
@@ -568,79 +566,67 @@ public class StaticTypesCallSiteWriter extends 
CallSiteWriter {
     }
 
     @Override
-    public void makeSingleArgumentCall(final Expression receiver, final String 
message, final Expression arguments, final boolean safe) {
-        ClassNode classNode = controller.getClassNode();
-        TypeChooser typeChooser = controller.getTypeChooser();
-        ClassNode rType = typeChooser.resolveType(receiver, classNode);
-        ClassNode aType = typeChooser.resolveType(arguments, classNode);
-        if (trySubscript(receiver, message, arguments, rType, aType, safe)) {
-            return;
-        }
-        // now try with flow type instead of declaration type
-        rType = receiver.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
-        if (receiver instanceof VariableExpression && rType == null) {
-            // TODO: can STCV be made smarter to avoid this check?
-            ASTNode node = (ASTNode) ((VariableExpression) 
receiver).getAccessedVariable();
-            rType = node.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
-        }
-        if (rType!=null && trySubscript(receiver, message, arguments, rType, 
aType, safe)) {
+    public void makeSingleArgumentCall(final Expression receiver, final String 
message, final Expression argument, final boolean safe) {
+        ClassNode rType = controller.getTypeChooser().resolveType(receiver, 
controller.getClassNode());
+        ClassNode aType = controller.getTypeChooser().resolveType(argument, 
controller.getClassNode());
+        if (getWrapper(rType).isDerivedFrom(Number_TYPE) && 
getWrapper(aType).isDerivedFrom(Number_TYPE)) {
+            switch (message) {
+              case "plus":
+              case "minus":
+              case "multiply":
+              case "div"/*ide*/:
+                writeNumberNumberCall(receiver, message, argument);
+                return;
+              case "power":
+                writePowerCall(receiver, argument, rType, aType);
+                return;
+              case "and":
+              case  "or":
+              case "xor":
+              case "implies":
+              case "remainder":
+              case "leftShift":
+              case "rightShift":
+              case "rightShiftUnsigned":
+                writeOperatorCall(receiver, argument, message);
+                return;
+            }
+        } else if ("plus".equals(message) && isStringType(rType)) {
+            writeStringPlusCall(receiver, message, argument);
             return;
+        } else if ("getAt".equals(message)) {
+            if (rType.isArray() && 
getWrapper(aType).isDerivedFrom(Number_TYPE) && !safe) {
+                writeArrayGet(receiver, argument, rType, aType);
+                return;
+            }
+            MethodNode getAt = findGetAt(rType, aType);
+            if (getAt != null) {
+                MethodCallExpression call = callX(receiver, "getAt", argument);
+                call.setImplicitThis(false);
+                call.setMethodTarget(getAt);
+                call.setSafe(safe);
+                call.setSourcePosition(argument);
+                call.visit(controller.getAcg());
+                return;
+            }
+            if (isOrImplements(rType, MAP_TYPE)) { // Map#get accepts Object
+                MethodCallExpression call = callX(receiver, "get", argument);
+                call.setImplicitThis(false);
+                call.setMethodTarget(MAP_GET_METHOD);
+                call.setSafe(safe);
+                call.setSourcePosition(argument);
+                call.visit(controller.getAcg());
+                return;
+            }
         }
-        // TODO: more cases
+
         throw new GroovyBugError(
                 "at line " + receiver.getLineNumber() + " column " + 
receiver.getColumnNumber() + "\n" +
-                "On receiver: " + receiver.getText() + " with message: " + 
message + " and arguments: " + arguments.getText() + "\n" +
+                "On receiver: " + receiver.getText() + " with message: " + 
message + " and arguments: " + argument.getText() + "\n" +
                 "This method should not have been called. Please try to create 
a simple example reproducing " +
                 "this error and file a bug report at 
https://issues.apache.org/jira/browse/GROOVY";);
     }
 
-    private boolean trySubscript(final Expression receiver, final String 
message, final Expression arguments, final ClassNode rType, final ClassNode 
aType, final boolean safe) {
-        if (getWrapper(rType).isDerivedFrom(Number_TYPE)
-                && getWrapper(aType).isDerivedFrom(Number_TYPE)) {
-            if ("plus".equals(message) || "minus".equals(message) || 
"multiply".equals(message) || "div".equals(message)) {
-                writeNumberNumberCall(receiver, message, arguments);
-                return true;
-            } else if ("power".equals(message)) {
-                writePowerCall(receiver, arguments, rType, aType);
-                return true;
-            } else if ("remainder".equals(message) || 
"leftShift".equals(message)
-                    || "rightShift".equals(message) || 
"rightShiftUnsigned".equals(message)
-                    || "and".equals(message) || "or".equals(message) || 
"xor".equals(message) || "implies".equals(message)) {
-                writeOperatorCall(receiver, arguments, message);
-                return true;
-            }
-        } else if (isStringType(rType) && "plus".equals(message)) {
-            writeStringPlusCall(receiver, message, arguments);
-            return true;
-        } else if ("getAt".equals(message)) {
-            if (rType.isArray() && 
getWrapper(aType).isDerivedFrom(Number_TYPE) && !safe) {
-                writeArrayGet(receiver, arguments, rType, aType);
-                return true;
-            } else { // check the receiver for a getAt method
-                MethodNode getAtNode = findGetAt(rType, aType);
-                if (getAtNode != null) {
-                    MethodCallExpression call = callX(receiver, "getAt", 
arguments);
-                    call.setImplicitThis(false);
-                    call.setMethodTarget(getAtNode);
-                    call.setSafe(safe);
-                    call.setSourcePosition(arguments);
-                    call.visit(controller.getAcg());
-                    return true;
-                }
-                if (isOrImplements(rType, MAP_TYPE)) { // fallback to Map#get
-                    MethodCallExpression call = callX(receiver, "get", 
arguments);
-                    call.setImplicitThis(false);
-                    call.setMethodTarget(MAP_GET_METHOD);
-                    call.setSafe(safe);
-                    call.setSourcePosition(arguments);
-                    call.visit(controller.getAcg());
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     private MethodNode findGetAt(final ClassNode rType, final ClassNode aType) 
{
         // TODO: find "best" match or find all matches and deal with ambiguity
         // TODO: handle getAt with more than one parameter
diff --git 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java
index 5f7750575f..4918ca9012 100644
--- 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java
+++ 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java
@@ -32,20 +32,23 @@ import static 
org.codehaus.groovy.ast.ClassHelper.isPrimitiveVoid;
  * type information from node metadata generated by the static type checker.
  */
 public class StaticTypesTypeChooser extends StatementMetaTypeChooser {
+
     @Override
     public ClassNode resolveType(final Expression exp, final ClassNode 
current) {
-        ASTNode target = getTarget(exp); // see GROOVY-9344, GROOVY-9607
-
-        ClassNode inferredType = 
target.getNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE);
+        ClassNode inferredType = 
exp.getNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE);
+        if (inferredType == null) {
+            inferredType = 
exp.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
+        }
         if (inferredType == null) {
-            inferredType = 
target.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
+            var ast = getTarget(exp); // GROOVY-9344, GROOVY-9607, GROOVY-11375
+            inferredType = 
ast.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
         }
         if (inferredType != null && !isPrimitiveVoid(inferredType)) {
             return inferredType;
         }
 
-        // AsmClassGenerator may create "this" expressions that the type 
checker knows nothing about
-        if (target instanceof VariableExpression && ((VariableExpression) 
target).isThisExpression()) {
+        // AsmClassGenerator creates "this" expressions that the type checker 
knows nothing about
+        if (exp instanceof VariableExpression && ((VariableExpression) 
exp).isThisExpression()) {
             return current;
         }
 
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 49e9784380..59f97bd538 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -914,8 +914,6 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
                 // 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 (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();
@@ -4604,12 +4602,16 @@ trying: for (ClassNode[] signature : signatures) {
         if (op == EQUAL || op == ELVIS_EQUAL) {
             if (leftExpression instanceof VariableExpression) {
                 ClassNode initialType = 
getOriginalDeclarationType(leftExpression);
+                if (isDynamicTyped(initialType)) { // GROOVY-11375
+                    ClassNode inferredType = 
leftExpression.getNodeMetaData(INFERRED_TYPE);
+                    if (inferredType != null && 
!isPrimitiveType(inferredType)) initialType = OBJECT_TYPE;
+                }
 
-                if (isPrimitiveType(rightRedirect) && 
initialType.isDerivedFrom(Number_TYPE)) {
+                if (isPrimitiveType(rightRedirect) && 
(initialType.isDerivedFrom(Number_TYPE) || (isObjectType(initialType) && 
!isDynamicTyped(initialType)))) {
                     return getWrapper(right);
                 }
 
-                if (isPrimitiveType(initialType) && 
rightRedirect.isDerivedFrom(Number_TYPE)) {
+                if (isPrimitiveType(initialType) && 
(rightRedirect.isDerivedFrom(Number_TYPE) || rightRedirect == 
getWrapper(initialType))) { // GROOVY-6574
                     return getUnwrapper(right);
                 }
 
diff --git a/src/test/groovy/transform/stc/STCAssignmentTest.groovy 
b/src/test/groovy/transform/stc/STCAssignmentTest.groovy
index 9aeabcfa4a..bfa56abf3c 100644
--- a/src/test/groovy/transform/stc/STCAssignmentTest.groovy
+++ b/src/test/groovy/transform/stc/STCAssignmentTest.groovy
@@ -358,7 +358,7 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
             s = 1
             ((Set) s)
         ''',
-        'Inconvertible types: cannot cast int to java.util.Set'
+        'Inconvertible types: cannot cast java.lang.Integer to java.util.Set'
     }
 
     void testArrayLength() {
diff --git a/src/test/groovy/transform/stc/STCnAryExpressionTest.groovy 
b/src/test/groovy/transform/stc/STCnAryExpressionTest.groovy
index c7d40be540..c4903fcef6 100644
--- a/src/test/groovy/transform/stc/STCnAryExpressionTest.groovy
+++ b/src/test/groovy/transform/stc/STCnAryExpressionTest.groovy
@@ -141,6 +141,26 @@ class STCnAryExpressionTest extends 
StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-11375
+    void testShiftOnPrimitivesVariableFlowType() {
+        assertScript '''
+            def x = "--"
+            x = x.size()
+            def y = x << x
+            assert y === 8
+        '''
+    }
+
+    // GROOVY-11375
+    void testPowerOnPrimitivesVariableFlowType() {
+        assertScript '''
+            def x = "--"
+            x = x.size()
+            def y = x ** x
+            assert y === 4
+        '''
+    }
+
     // GROOVY-5644
     void testSpaceshipOperatorNoAmbiguousError() {
         assertScript '''

Reply via email to