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 c46a124e6b GROOVY-11816: SC: set variable scope on spread-dot
generated for loop
c46a124e6b is described below
commit c46a124e6bfd64ff511f85411c1a7dd751a6fd22
Author: Eric Milles <[email protected]>
AuthorDate: Sun Dec 14 17:31:37 2025 -0600
GROOVY-11816: SC: set variable scope on spread-dot generated for loop
---
.../classgen/asm/sc/StaticInvocationWriter.java | 17 +++--
src/test/groovy/groovy/SpreadDotTest.groovy | 84 +++++++++++-----------
.../stc/ArraysAndCollectionsSTCTest.groovy | 11 +++
3 files changed, 64 insertions(+), 48 deletions(-)
diff --git
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
index f1486ffe7e..816df9717a 100644
---
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
+++
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
@@ -27,6 +27,7 @@ import org.codehaus.groovy.ast.GroovyCodeVisitor;
import org.codehaus.groovy.ast.InnerClassNode;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.VariableScope;
import org.codehaus.groovy.ast.decompiled.DecompiledClassNode;
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
import org.codehaus.groovy.ast.expr.ArrayExpression;
@@ -520,6 +521,11 @@ public class StaticInvocationWriter extends
InvocationWriter {
ClassNode elementType =
StaticTypeCheckingVisitor.inferLoopElementType(controller.getTypeChooser().resolveType(receiver,
controller.getClassNode()));
Parameter element = new Parameter(elementType, "for$it$" +
labelCounter.incrementAndGet());
+ VariableScope varScope = new
VariableScope(controller.getCompileStack().getScope());
+
varScope.setInStaticContext(varScope.getParent().isInStaticContext());
+ element
.setInStaticContext(varScope.getParent().isInStaticContext());
+ varScope.putDeclaredVariable(element);
+
Expression nextValue;
if (origin instanceof MethodCallExpression) {
MethodCallExpression oldMCE = (MethodCallExpression) origin;
@@ -550,13 +556,10 @@ public class StaticInvocationWriter extends
InvocationWriter {
addNextValue.setImplicitThis(false);
addNextValue.setMethodTarget(StaticCompilationVisitor.ARRAYLIST_ADD_METHOD);
- // for (element in receiver)
result.add(element?.method(arguments));
- var stmt = new ForStatement(
- element,
- tmpReceiver,
- stmt(produceResultList ? addNextValue : nextValue)
- );
- stmt.visit(controller.getAcg());
+ // for (element in receiver) result.add(element?.method(arguments))
+ var loop = new ForStatement(element, tmpReceiver,
stmt(produceResultList ? addNextValue : nextValue));
+ loop.setVariableScope(varScope); // GROOVY-11816
+ loop.visit(controller.getAcg());
if (produceResultList) {
result.remove(controller);
}
diff --git a/src/test/groovy/groovy/SpreadDotTest.groovy
b/src/test/groovy/groovy/SpreadDotTest.groovy
index 164cb34b24..ac9a3d78da 100644
--- a/src/test/groovy/groovy/SpreadDotTest.groovy
+++ b/src/test/groovy/groovy/SpreadDotTest.groovy
@@ -18,68 +18,75 @@
*/
package groovy
-import org.junit.Test
+import org.junit.jupiter.api.Test
-import static org.junit.Assert.assertEquals
+import static org.junit.jupiter.api.Assertions.assertEquals
/**
- * Tests for the spread dot operator "*.".
- *
- * For an example,
- * list*.property
- * means
- * list.collect { it?.property }
+ * Tests for the spread dot operator. For example, {@code list*.name} works
+ * like: <pre>
+ * list.collect { it?.name }
+ * </pre>
*/
final class SpreadDotTest {
@Test
- void testSpreadDot() {
- def m1 = ["a": 1, "b": 2]
- def m2 = ["a": 11, "b": 22]
- def m3 = ["a": 111, "b": 222]
+ void testSpreadDot1() {
+ def map = [A: 'one', B: 'two', C: 'three']
+
+ assert map*.key == ['A', 'B', 'C']
+ assert map*.value*.size() == [3, 3, 5]
+ assert map.collect { entry -> entry.value.size() } == [3, 3, 5]
+ }
+
+ @Test
+ void testSpreadDot2() {
+ def m1 = [a: 1, b: 2]
+ def m2 = [a: 11, b: 22]
+ def m3 = [a: 111, b: 222]
+
def x = [m1, m2, m3]
- assert x*.a == [1, 11, 111]
- assert x*."a" == [1, 11, 111]
assert x == [m1, m2, m3]
+ assert x*.a == [1, 11, 111]
+ assert x*.'a' == [1, 11, 111]
- def m4 = null
- x << m4
- assert x*.a == [1, 11, 111, null]
- assert x*."a" == [1, 11, 111, null]
+ x << null
assert x == [m1, m2, m3, null]
+ assert x*.a == [1, 11, 111, null]
+ assert x*.'a' == [1, 11, 111, null]
Date checkDate = new Date()
def d = new SpreadDotDemo()
x << d
- assert x*."a"[4] >= checkDate
+ assert x*.'a'[4] >= checkDate
assert x == [m1, m2, m3, null, d]
def y = new SpreadDotDemo2()
- assert y."a" == 'Attribute Get a'
assert y.a == 'Attribute Get a'
+ assert y.'a' == 'Attribute Get a'
x << y
- assert x*."a"[5] == 'Attribute Get a'
assert x == [m1, m2, m3, null, d, y]
+ assert x*.'a'[5] == 'Attribute Get a'
}
@Test
- void testSpreadDot2() {
+ void testSpreadDot3() {
def a = new SpreadDotDemo()
def b = new SpreadDotDemo2()
def x = [a, b]
- assert x*.fnB("1") == [a.fnB("1"), b.fnB("1")]
+ assert x*.fnB('1') == [a.fnB('1'), b.fnB('1')]
assert [a, b]*.fnB() == [a.fnB(), b.fnB()]
}
@Test
- void testSpreadDotArrays() {
+ void testSpreadDotArrays1() {
def a = new SpreadDotDemo()
def b = new SpreadDotDemo2()
Object[] x = [a, b]
- assert x*.fnB("1") == [a.fnB("1"), b.fnB("1")]
+ assert x*.fnB('1') == [a.fnB('1'), b.fnB('1')]
assert [a, b]*.fnB() == [a.fnB(), b.fnB()]
int[] nums = [3, 4, 5]
@@ -98,9 +105,9 @@ final class SpreadDotTest {
books*.metaClass*.foo = { "Hello,
${delegate.class.simpleName}".toString() }
- assertEquals("Hello, Book1", new Book1().foo())
- assertEquals("Hello, Book2", new Book2().foo())
- assertEquals("Hello, Book3", new Book3().foo())
+ assertEquals('Hello, Book1', new Book1().foo())
+ assertEquals('Hello, Book2', new Book2().foo())
+ assertEquals('Hello, Book3', new Book3().foo())
}
@Test
@@ -116,14 +123,6 @@ final class SpreadDotTest {
assertEquals(['Large'], new Shirt()*.size())
}
- @Test
- void testSpreadDotMap() {
- def map = [A: "one", B: "two", C: "three"]
- assert map.collect { child -> child.value.size() } == [3, 3, 5]
- assert map*.value*.size() == [3, 3, 5]
- assert map*.getKey() == ['A', 'B', 'C']
- }
-
@Test
void testSpreadDotAttribute() {
def s = new Singlet()
@@ -160,7 +159,7 @@ final class SpreadDotTest {
}
String fnB() {
- return "bb"
+ return 'bb'
}
String fnB(String m) {
@@ -178,7 +177,7 @@ final class SpreadDotTest {
}
String fnB() {
- return "cc"
+ return 'cc'
}
String fnB(String m) {
@@ -186,11 +185,14 @@ final class SpreadDotTest {
}
}
- static class Book1 {}
+ static class Book1 {
+ }
- static class Book2 {}
+ static class Book2 {
+ }
- static class Book3 {}
+ static class Book3 {
+ }
static class Shirt {
def size() { 'Large' }
diff --git
a/src/test/groovy/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
b/src/test/groovy/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
index 3bc268d00c..4ece87fab2 100644
--- a/src/test/groovy/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
+++ b/src/test/groovy/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
@@ -339,6 +339,17 @@ class ArraysAndCollectionsSTCTest extends
StaticTypeCheckingTestCase {
def listClass = list.class
assert listClass == ArrayList
'''
+
+ // GROOVY-11816
+ assertScript '''
+ class C {
+ List<Class> classes
+ void test() {
+ def names = classes*.simpleName
+ }
+ }
+ new C().test()
+ '''
}
void testListStarMethod() {