This is an automated email from the ASF dual-hosted git repository. jonnybot pushed a commit to branch GROOVY-9526-regression-semantic-analysis-exception in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 24ab6a3a4b9e8b862f5bc3c46dd962ef6aaf97a1 Author: Jonny Carter <jcar...@adaptavist.com> AuthorDate: Mon Jul 21 15:29:25 2025 -0500 Fix generics handling error Under the hood, the root cause seemed to be this: Caused by: java.lang.UnsupportedOperationException at java.base/java.util.AbstractMap.put(AbstractMap.java:209) at org.codehaus.groovy.control.ResolveVisitor.resolveGenericsHeader(ResolveVisitor.java:1452) at org.codehaus.groovy.control.ResolveVisitor.resolveGenericsHeader(ResolveVisitor.java:1409) Based on a look in the debugger, without this change, the genericParameterNames field will be a Collections$EmptyMap, which is immutable and therefore doesn't support PUT operations. --- .../codehaus/groovy/control/ResolveVisitor.java | 2 +- .../util/GroovyScriptEngineReloadingTest.groovy | 33 ++++++++++++++++++++++ 2 files changed, 34 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 383c0bffa7..33ec9c51e6 100644 --- a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java +++ b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java @@ -1279,7 +1279,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer { if (!Modifier.isStatic(node.getModifiers())) genericParameterNames.putAll(outerNames); // outer names visible } else { - genericParameterNames.clear(); // outer class: new generic namespace + genericParameterNames = new HashMap<>(); // outer class: new generic namespace } resolveGenericsHeader(node.getGenericsTypes()); switch (phase) { // GROOVY-9866, GROOVY-10466 diff --git a/src/test/groovy/groovy/util/GroovyScriptEngineReloadingTest.groovy b/src/test/groovy/groovy/util/GroovyScriptEngineReloadingTest.groovy index 660f4ddcf0..935d99abc8 100644 --- a/src/test/groovy/groovy/util/GroovyScriptEngineReloadingTest.groovy +++ b/src/test/groovy/groovy/util/GroovyScriptEngineReloadingTest.groovy @@ -182,6 +182,39 @@ final class GroovyScriptEngineReloadingTest { } + @Test + void testRecompilingWithGenericsAndConstants() { + MapFileSystem.instance.modFile('BaseClass.groovy', 'class BaseClass<T> {}', gse.@time) + + def tertiaryClassText = ''' + class NotGeneric { + /** + * Not typed on purpose - if typed as String then NotGeneric is no longer a dependency of + * ParameterisedClass for some reason... + */ + public static final Object CONSTANT = "not generic" + } + ''' + MapFileSystem.instance.modFile('NotGeneric.groovy', tertiaryClassText, gse.@time) + + def subClassText = ''' + class SubClass extends BaseClass<String> { + public static final String CONSTANT = NotGeneric.CONSTANT + } + ''' + MapFileSystem.instance.modFile('SubClass.groovy', subClassText, gse.@time) + + MapFileSystem.instance.modFile('scriptUsingGeneric.groovy', 'SubClass.CONSTANT', gse.@time) + + + gse.loadScriptByName('scriptUsingGeneric.groovy') + sleep 1000 + + // make a change to the sub-class so that it gets recompiled + MapFileSystem.instance.modFile('SubClass.groovy', subClassText + '\n', gse.@time) + gse.loadScriptByName('scriptUsingGeneric.groovy') + } + @Test void testDeleteDependent() { sleep 10000