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

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

commit 904e55989a661ec4aa0f8a3a257e2441d80bb079
Author: Eric Milles <[email protected]>
AuthorDate: Fri Oct 3 18:02:20 2025 -0500

    GROOVY-11375, GROOVY-11769: SC: lookup type of variable before target
    
    see also GROOVY-9344, GROOVY-9607
    
    4_0_X backport
---
 .../classgen/asm/sc/StaticTypesTypeChooser.java      | 15 +++++++++------
 .../groovy/transform/stc/STCAssignmentTest.groovy    | 15 +++++++++++++++
 .../transform/stc/STCnAryExpressionTest.groovy       | 20 ++++++++++++++++++++
 .../asm/sc/AssignmentsStaticCompileTest.groovy       |  8 ++++++++
 4 files changed, 52 insertions(+), 6 deletions(-)

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..5c00ceed4f 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);
+            ASTNode node = getTarget(exp); // GROOVY-9344, GROOVY-9607
+            inferredType = 
node.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/test/groovy/groovy/transform/stc/STCAssignmentTest.groovy 
b/src/test/groovy/groovy/transform/stc/STCAssignmentTest.groovy
index 91b14bd590..129501a9c3 100644
--- a/src/test/groovy/groovy/transform/stc/STCAssignmentTest.groovy
+++ b/src/test/groovy/groovy/transform/stc/STCAssignmentTest.groovy
@@ -645,6 +645,21 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase 
{
         '''
     }
 
+    void testCastObjectToInterface() {
+        assertScript '''
+            List<Object> m(object) {
+                if (object == null) return new ArrayList<>()
+                if (object instanceof Collection) return new 
ArrayList<Object>((Collection) object)
+                return [object]
+            }
+            def item = 0
+            def list = [1,2]
+            assert m(null).size() == 0
+            assert m(item).size() == 1
+            assert m(list).size() == 2
+        '''
+    }
+
     void testIfElseBranch() {
         shouldFailWithMessages '''
             def x
diff --git a/src/test/groovy/groovy/transform/stc/STCnAryExpressionTest.groovy 
b/src/test/groovy/groovy/transform/stc/STCnAryExpressionTest.groovy
index bff8c0a82a..7bb95c1ad6 100644
--- a/src/test/groovy/groovy/transform/stc/STCnAryExpressionTest.groovy
+++ b/src/test/groovy/groovy/transform/stc/STCnAryExpressionTest.groovy
@@ -132,6 +132,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 '''
diff --git 
a/src/test/groovy/org/codehaus/groovy/classgen/asm/sc/AssignmentsStaticCompileTest.groovy
 
b/src/test/groovy/org/codehaus/groovy/classgen/asm/sc/AssignmentsStaticCompileTest.groovy
index 538589f10d..7eead72ade 100644
--- 
a/src/test/groovy/org/codehaus/groovy/classgen/asm/sc/AssignmentsStaticCompileTest.groovy
+++ 
b/src/test/groovy/org/codehaus/groovy/classgen/asm/sc/AssignmentsStaticCompileTest.groovy
@@ -31,4 +31,12 @@ final class AssignmentsStaticCompileTest extends 
STCAssignmentTest implements St
         String bytecode = astTrees['C'][1]
         assert 
!bytecode.contains('ScriptBytecodeAdapter.setGroovyObjectProperty') : '"c.i += 
10" should use setter, not dynamic property'
     }
+
+    @Override // GROOVY-11769
+    void testCastObjectToInterface() {
+        super.testCastObjectToInterface()
+        String bytecode = astTrees.values()[0][1]
+        bytecode = 
bytecode.substring(bytecode.indexOf('m(Ljava/lang/Object;)'))
+        assert bytecode.count('CHECKCAST') == 1 // guarded typecast isn't 
groovy
+    }
 }

Reply via email to