This is an automated email from the ASF dual-hosted git repository. sunlan 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 c7cc2a069a GROOVY-11711: restore outer class generics after inner class visit c7cc2a069a is described below commit c7cc2a069a7e41762b4c7c00bb7b1b676af7a5e6 Author: Eric Milles <eric.mil...@thomsonreuters.com> AuthorDate: Tue Jul 8 08:40:32 2025 -0500 GROOVY-11711: restore outer class generics after inner class visit --- .../org/codehaus/groovy/control/ResolveVisitor.java | 9 ++++++++- src/test/groovy/gls/innerClass/InnerClassTest.groovy | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java index d671816f9f..f8bbf25e17 100644 --- a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java +++ b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java @@ -1294,8 +1294,14 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer { if (phase < 2) node.putNodeMetaData(AnnotationNode[].class, new LinkedHashSet<>()); - if (!(node instanceof InnerClassNode) || Modifier.isStatic(node.getModifiers())) { + Map<GenericsTypeName, GenericsType> outerNames = null; + if (node instanceof InnerClassNode) { + outerNames = genericParameterNames; genericParameterNames = new HashMap<>(); + if (!Modifier.isStatic(node.getModifiers())) + genericParameterNames.putAll(outerNames); // outer names visible + } else { + genericParameterNames.clear(); // outer class: new generic namespace } resolveGenericsHeader(node.getGenericsTypes()); switch (phase) { // GROOVY-9866, GROOVY-10466 @@ -1342,6 +1348,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer { // GROOVY-10750, GROOVY-11179: resolve and inline headerAnnotations.forEach(this::visitAnnotation); } + if (outerNames != null) genericParameterNames = outerNames; currentClass = oldNode; } diff --git a/src/test/groovy/gls/innerClass/InnerClassTest.groovy b/src/test/groovy/gls/innerClass/InnerClassTest.groovy index d834cb11e3..ed3645535d 100644 --- a/src/test/groovy/gls/innerClass/InnerClassTest.groovy +++ b/src/test/groovy/gls/innerClass/InnerClassTest.groovy @@ -1381,6 +1381,25 @@ final class InnerClassTest { assert err =~ /No enclosing instance passed in constructor call of a non-static inner class/ } + // GROOVY-11711 + @Test + void testUsageOfOuterType6() { + assertScript ''' + class Foo<T> { + static class Bar { + } + /*non-static*/ class Baz + implements java.util.concurrent.Callable<T> { + T call() { + } + } + } + def foo = new Foo<Short>() + def baz = new Foo.Baz(foo) + assert baz.call() == null + ''' + } + @Test void testClassOutputOrdering() { // this does actually not do much, but before this