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 6d7810dc71 GROOVY-10687, GROOVY-11780: fix nest members for
multi-level closures
6d7810dc71 is described below
commit 6d7810dc7151012387a3a229138bb3d6fc8abf10
Author: Eric Milles <[email protected]>
AuthorDate: Fri Oct 10 22:27:13 2025 -0500
GROOVY-10687, GROOVY-11780: fix nest members for multi-level closures
---
.../groovy/classgen/AsmClassGenerator.java | 27 ++++++++++----
.../groovy/classgen/asm/NestHostTests.groovy | 43 ++++++++++++++++++++++
2 files changed, 62 insertions(+), 8 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
index 11f7db8c43..6786d3cd7f 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -131,6 +131,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.TreeMap;
import java.util.function.Consumer;
import static org.apache.groovy.ast.tools.ClassNodeUtils.getField;
@@ -472,15 +473,13 @@ public class AsmClassGenerator extends ClassGenerator {
int[] n = {this.context.getClosureClassIndex()};
for (ClassNode innerClass : getInnerClasses()) {
if (innerClass instanceof InterfaceHelperClassNode) continue;
- var doCall = innerClass.getMethods().get(0);
- doCall.getCode().visit(new CodeVisitorSupport() {
+ var toVisit = new TreeMap<String, ClosureExpression>(); //
GROOVY-11780
+ var visitor = new CodeVisitorSupport() {
private String name =
BytecodeHelper.getClassInternalName(innerClass);
private void visitNested(final String kind, final
ClosureExpression expr) {
- String save = name;
- name += "$_" + kind + n[0]++;
- classVisitor.visitNestMember(name);
- super.visitClosureExpression(expr);
- name = save;
+ String nest = name + "$_" + kind + n[0]++;
+ classVisitor.visitNestMember(nest);
+ toVisit.put(nest, expr);
}
@Override
public void visitClosureExpression(final ClosureExpression
expression) {
@@ -495,7 +494,19 @@ public class AsmClassGenerator extends ClassGenerator {
super.visitLambdaExpression(expression);
}
}
- });
+ };
+
+ MethodNode doCall = innerClass.getMethods().get(0);
+ doCall.getCode().visit(visitor);
+
+ while (!toVisit.isEmpty()) {
+ var iter = toVisit.entrySet().iterator(); // take first entry
+ var next = iter.next();
+ iter.remove();
+
+ visitor.name = next.getKey(); // traverse
+ next.getValue().getCode().visit(visitor);
+ }
}
}
diff --git
a/src/test/groovy/org/codehaus/groovy/classgen/asm/NestHostTests.groovy
b/src/test/groovy/org/codehaus/groovy/classgen/asm/NestHostTests.groovy
index 07ee8ea33f..797f6e950c 100644
--- a/src/test/groovy/org/codehaus/groovy/classgen/asm/NestHostTests.groovy
+++ b/src/test/groovy/org/codehaus/groovy/classgen/asm/NestHostTests.groovy
@@ -134,4 +134,47 @@ final class NestHostTests {
assert type.nestMembers*.name.sort() == ['C', 'C$_closure1',
'C$_closure1$_closure2', 'C$_closure1$_closure2$_lambda3']
}
}
+
+ // GROOVY-11780
+ @Test
+ void testNestHost7() {
+ def types = compileScript '''
+ class C {
+ def aaa() {
+ { ->
+ { ->
+ { ->
+ { ->
+ }
+ }
+ }
+ { ->
+ { ->
+ }
+ }
+ }
+ { ->
+ { ->
+ }
+ }
+ }
+ def bbb() {
+ { ->
+ { ->
+ }
+ }
+ }
+ }
+ '''
+
+ types.each { type ->
+ assert type.nestHost.name == 'C'
+ assert type.nestMembers*.name.sort() == ['C',
+ 'C$_aaa_closure1', 'C$_aaa_closure1$_closure4',
'C$_aaa_closure1$_closure4$_closure6',
'C$_aaa_closure1$_closure4$_closure6$_closure7',
+ 'C$_aaa_closure1$_closure5',
'C$_aaa_closure1$_closure5$_closure8',
+ 'C$_aaa_closure2', 'C$_aaa_closure2$_closure9',
+ 'C$_bbb_closure3', 'C$_bbb_closure3$_closure10'
+ ]
+ }
+ }
}