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

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


The following commit(s) were added to refs/heads/GROOVY_5_0_X by this push:
     new c05a538d01 GROOVY-11856: STC: save inferred type of list and map 
expressions
c05a538d01 is described below

commit c05a538d01062265f2eaa610a644a1e34296652c
Author: Eric Milles <[email protected]>
AuthorDate: Sat Feb 7 19:13:26 2026 -0600

    GROOVY-11856: STC: save inferred type of list and map expressions
---
 .../codehaus/groovy/classgen/asm/OperandStack.java | 46 +++++++++++-----------
 .../transform/stc/StaticTypeCheckingVisitor.java   |  8 +++-
 src/test/groovy/bugs/Groovy10034.groovy            | 12 ++++--
 src/test/groovy/bugs/Groovy9126.groovy             |  4 +-
 4 files changed, 41 insertions(+), 29 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/OperandStack.java 
b/src/main/java/org/codehaus/groovy/classgen/asm/OperandStack.java
index 4ff4538551..bac046633e 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/OperandStack.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/OperandStack.java
@@ -22,8 +22,6 @@ import org.apache.groovy.ast.tools.ClassNodeUtils;
 import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.ConstructorNode;
-import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Variable;
 import org.codehaus.groovy.ast.expr.CastExpression;
 import org.codehaus.groovy.ast.expr.ConstantExpression;
@@ -313,36 +311,40 @@ public class OperandStack {
         doConvertAndCast(targetType,true);
     }
 
-    private void throwExceptionForNoStackElement(final int size, final 
ClassNode targetType, final boolean coerce) {
-        if (size > 0) return;
-        StringBuilder sb = new StringBuilder();
-        sb.append("Internal compiler error while compiling 
").append(controller.getSourceUnit().getName()).append("\n");
-        MethodNode methodNode = controller.getMethodNode();
-        if (methodNode!=null) {
-            sb.append("Method: ");
-            sb.append(methodNode);
-            sb.append("\n");
-        }
-        ConstructorNode constructorNode = controller.getConstructorNode();
-        if (constructorNode!=null) {
+    private String missingOperand(final ClassNode targetType, final boolean 
coerce) {
+        var sb = new StringBuilder("Internal compiler error while compiling ");
+        sb.append(controller.getSourceUnit().getName());
+        sb.append("\n");
+        var constructorNode = controller.getConstructorNode();
+        if (constructorNode != null) {
             sb.append("Constructor: ");
-            sb.append(methodNode);
+            sb.append(constructorNode);
             sb.append("\n");
+        } else {
+            var methodNode = controller.getMethodNode();
+            if (methodNode != null) {
+                sb.append("Method: ");
+                sb.append(methodNode);
+                sb.append("\n");
+            }
         }
-        sb.append("Line ").append(controller.getLineNumber()).append(",");
-        sb.append(" expecting ").append(coerce ? "coercion" : 
"casting").append(" to ").append(targetType.toString(false));
+        sb.append("Line ").append(controller.getLineNumber()).append(", 
expecting ").append(coerce ? "coercion" : "casting");
+        sb.append(" to ").append(ClassNodeUtils.formatTypeName(targetType));
         sb.append(" but operand stack is empty");
-        throw new ArrayIndexOutOfBoundsException(sb.toString());
+        return sb.toString();
     }
 
     private void doConvertAndCast(ClassNode targetType, final boolean coerce) {
         int size = stack.size();
-        throwExceptionForNoStackElement(size, targetType, coerce);
+        if (size == 0) {
+            throw new 
ArrayIndexOutOfBoundsException(missingOperand(targetType, coerce));
+        }
 
         ClassNode top = stack.get(size - 1);
-        targetType = targetType.redirect();
-        if (top == targetType /* for better performance */
-                || ClassNodeUtils.isCompatibleWith(top, targetType)) return;
+        if (top == (targetType = targetType.redirect()) // quick check
+                || ClassNodeUtils.isCompatibleWith(top, targetType)) {
+            return;
+        }
 
         if (coerce) {
             controller.getInvocationWriter().coerce(top, targetType);
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 a1ef0d5107..7e39318a68 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -5271,11 +5271,15 @@ trying: for (ClassNode[] signature : signatures) {
         }
 
         if (node instanceof ListExpression) {
-            return inferListExpressionType((ListExpression) node);
+            type = inferListExpressionType((ListExpression) node);
+            node.putNodeMetaData(INFERRED_TYPE, type);
+            return type;
         }
 
         if (node instanceof MapExpression) {
-            return inferMapExpressionType((MapExpression) node);
+            type = inferMapExpressionType((MapExpression) node);
+            node.putNodeMetaData(INFERRED_TYPE, type);
+            return type;
         }
 
         if (node instanceof RangeExpression) {
diff --git a/src/test/groovy/bugs/Groovy10034.groovy 
b/src/test/groovy/bugs/Groovy10034.groovy
index bed617b7a7..7dc6baefa5 100644
--- a/src/test/groovy/bugs/Groovy10034.groovy
+++ b/src/test/groovy/bugs/Groovy10034.groovy
@@ -31,8 +31,14 @@ final class Groovy10034 extends AbstractBytecodeTestCase {
                 ["x"].toArray(new String[0])
             }
         '''
-        int offset = result.indexOf('ANEWARRAY java/lang/String', 
result.indexOf('--BEGIN--'))
-        assert result.hasStrictSequence(['ANEWARRAY 
java/lang/String','INVOKEVIRTUAL java/util/ArrayList.toArray'], offset)
-        // there should be no 'INVOKEDYNAMIC cast' instruction here: ^
+        int offset = result.indexOf('INVOKESTATIC', 
result.indexOf('--BEGIN--'))
+        assert result.hasStrictSequence([
+            'INVOKESTATIC 
org/codehaus/groovy/runtime/ScriptBytecodeAdapter.createList',
+            'CHECKCAST java/util/ArrayList', // not 'INVOKEDYNAMIC cast'
+            'ICONST_0',
+            'ANEWARRAY java/lang/String',
+            // no 'INVOKEDYNAMIC cast' to Object[]
+            'INVOKEVIRTUAL java/util/ArrayList.toArray'
+        ], offset)
     }
 }
diff --git a/src/test/groovy/bugs/Groovy9126.groovy 
b/src/test/groovy/bugs/Groovy9126.groovy
index baadd5dc72..b2f804a26b 100644
--- a/src/test/groovy/bugs/Groovy9126.groovy
+++ b/src/test/groovy/bugs/Groovy9126.groovy
@@ -19,12 +19,12 @@
 package bugs
 
 import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase
-import org.junit.Test
+import org.junit.jupiter.api.Test
 
 final class Groovy9126 extends AbstractBytecodeTestCase {
 
     @Test
-    void testUnreachableBytecode() {
+    void testUnreachableBytecode1() {
         assert compile(method:'nonVoidMethod', 
'''@groovy.transform.CompileStatic
             int nonVoidMethod() {
                 1 * 1

Reply via email to