Skip to content

Commit 5e82e1e

Browse files
committed
GROOVY-11711: restore outer class generics after inner class visit
3_0_X backport
1 parent 386177e commit 5e82e1e

2 files changed

Lines changed: 34 additions & 13 deletions

File tree

src/main/java/org/codehaus/groovy/control/ResolveVisitor.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1408,24 +1408,23 @@ private void checkAnnotationMemberValue(final Expression newValue) {
14081408

14091409
@Override
14101410
public void visitClass(final ClassNode node) {
1411-
ClassNode oldNode = currentClass;
1412-
1413-
currentClass = node;
1414-
1411+
ClassNode oldNode = currentClass; currentClass = node;
1412+
Map<GenericsTypeName, GenericsType> outerNames = null;
14151413
if (node instanceof InnerClassNode) {
1416-
if (Modifier.isStatic(node.getModifiers())) {
1417-
genericParameterNames = new HashMap<>();
1414+
outerNames = genericParameterNames;
1415+
genericParameterNames = new HashMap<>();
1416+
if (!Modifier.isStatic(node.getModifiers())) {
1417+
genericParameterNames.putAll(outerNames); // outer names visible
14181418
}
1419-
1420-
InnerClassNode innerClassNode = (InnerClassNode) node;
1421-
if (innerClassNode.isAnonymous()) {
1422-
MethodNode enclosingMethod = innerClassNode.getEnclosingMethod();
1423-
if (null != enclosingMethod) {
1419+
InnerClassNode innerClass = (InnerClassNode) node;
1420+
if (innerClass.isAnonymous()) {
1421+
MethodNode enclosingMethod = innerClass.getEnclosingMethod();
1422+
if (enclosingMethod != null) {
14241423
resolveGenericsHeader(enclosingMethod.getGenericsTypes());
14251424
}
14261425
}
14271426
} else {
1428-
genericParameterNames = new HashMap<>();
1427+
genericParameterNames.clear(); // outer class: new generic namespace
14291428
}
14301429

14311430
resolveGenericsHeader(node.getGenericsTypes());
@@ -1493,6 +1492,9 @@ public void visitClass(final ClassNode node) {
14931492

14941493
resolveOuterNestedClassFurther(node);
14951494

1495+
if (outerNames != null) // GROOVY-11711
1496+
genericParameterNames = outerNames;
1497+
14961498
currentClass = oldNode;
14971499
}
14981500

src/test/gls/innerClass/InnerClassTest.groovy

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1133,12 +1133,31 @@ final class InnerClassTest {
11331133
assert err =~ /No enclosing instance passed in constructor call of a non-static inner class/
11341134
}
11351135

1136+
// GROOVY-11711
1137+
@Test
1138+
void testUsageOfOuterType6() {
1139+
assertScript '''
1140+
class Foo<T> {
1141+
static class Bar {
1142+
}
1143+
/*non-static*/ class Baz
1144+
implements java.util.concurrent.Callable<T> {
1145+
T call() {
1146+
}
1147+
}
1148+
}
1149+
def foo = new Foo<Short>()
1150+
def baz = new Foo.Baz(foo)
1151+
assert baz.call() == null
1152+
'''
1153+
}
1154+
11361155
@Test
11371156
void testClassOutputOrdering() {
11381157
// this does actually not do much, but before this
11391158
// change the inner class was tried to be executed
11401159
// because a class ordering bug. The main method
1141-
// makes the Foo class executeable, but Foo$Bar is
1160+
// makes the Foo class executable, but Foo$Bar is
11421161
// not. So if Foo$Bar is returned, asserScript will
11431162
// fail. If Foo is returned, asserScript will not
11441163
// fail.

0 commit comments

Comments
 (0)