[
https://issues.apache.org/jira/browse/GROOVY-11022?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18076828#comment-18076828
]
ASF GitHub Bot commented on GROOVY-11022:
-----------------------------------------
Copilot commented on code in PR #2497:
URL: https://github.com/apache/groovy/pull/2497#discussion_r3154041200
##########
src/test/groovy/groovy/transform/stc/GenericsSTCTest.groovy:
##########
@@ -4616,6 +4616,40 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase
{
}
}
+ // GROOVY-11022
+ @Test
+ void testNoStackOverflow3() {
+ // F-bounded type parameter with self-reference inside a `? super`
wildcard
+ assertScript '''
+ class C<K, V> {
+ public static <K extends Comparable<? super K>, V> C<K, V> m(K
k, V v) {
+ new C<K, V>()
+ }
+ }
+ class Main {
+ @groovy.transform.TypeChecked
+ static test() {
+ C.<Object, Integer>m(null, 1)
Review Comment:
In this `@TypeChecked` script, the explicit type argument `Object` does not
satisfy the method bound `K extends Comparable<? super K>` (since Object is not
Comparable). This risks the test failing with a bounds/type-checking error (or
masking the intended regression) depending on how generic bounds are validated.
Consider using a type that satisfies the bound (e.g., `Integer`/`String`) while
still exercising the recursive wildcard structure.
```suggestion
C.<String, Integer>m(null, 1)
```
##########
src/test/groovy/groovy/transform/stc/GenericsSTCTest.groovy:
##########
@@ -4616,6 +4616,40 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase
{
}
}
+ // GROOVY-11022
+ @Test
+ void testNoStackOverflow3() {
+ // F-bounded type parameter with self-reference inside a `? super`
wildcard
+ assertScript '''
+ class C<K, V> {
+ public static <K extends Comparable<? super K>, V> C<K, V> m(K
k, V v) {
+ new C<K, V>()
+ }
+ }
+ class Main {
+ @groovy.transform.TypeChecked
+ static test() {
+ C.<Object, Integer>m(null, 1)
+ }
+ }
+ Main.test()
+ '''
+
+ // self-reference inside a `? extends` wildcard
+ assertScript '''
+ class C<K> {
+ public static <K extends Iterable<? extends K>> C<K> m(K k) {
+ new C<K>()
+ }
+ }
+ @groovy.transform.TypeChecked
+ void test() {
+ C.<List<Object>>m(null)
Review Comment:
The explicit type argument `List<Object>` does not appear to satisfy the
bound `K extends Iterable<? extends K>` (a `List<Object>` is
`Iterable<Object>`, not `Iterable<? extends List<Object>>`). To keep this
regression focused on the StackOverflowError and avoid potential
bounds-checking failures, consider introducing a small self-referential type
(e.g., a class implementing `Iterable<Self>`) and using that as `K`.
```suggestion
class Self implements Iterable<Self> {
@Override
Iterator<Self> iterator() {
Collections.<Self>emptyList().iterator()
}
}
@groovy.transform.TypeChecked
void test() {
C.<Self>m(null)
```
##########
src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java:
##########
@@ -1841,26 +1882,38 @@ private static boolean hasNonTrivialBounds(final
GenericsType gt) {
}
static ClassNode[] applyGenericsContext(final Map<GenericsTypeName,
GenericsType> spec, final ClassNode[] types) {
+ if (types == null) return null;
+ return applyGenericsContext(new BoundExpansionContext(), spec, types);
+ }
+
+ private static ClassNode[] applyGenericsContext(final
BoundExpansionContext ctx, final Map<GenericsTypeName, GenericsType> spec,
final ClassNode[] types) {
if (types == null) return null;
final int nTypes = types.length;
ClassNode[] newTypes = new ClassNode[nTypes];
for (int i = 0; i < nTypes; i += 1) {
- newTypes[i] = applyGenericsContext(spec, types[i]);
+ newTypes[i] = applyGenericsContext(ctx, spec, types[i]);
}
return newTypes;
}
static ClassNode applyGenericsContext(final Map<GenericsTypeName,
GenericsType> spec, final ClassNode type) {
+ if (type == null || !isUsingGenericsOrIsArrayUsingGenerics(type)) {
+ return type;
+ }
+ return applyGenericsContext(new BoundExpansionContext(), spec, type);
+ }
Review Comment:
`applyGenericsContext(spec, type)` now allocates a new
`BoundExpansionContext` unconditionally for any generic-using type, even when
`spec` is null/empty (in which case the context is never used). Since this
method is on a hot path during STC, consider creating/passing the context only
when `asBoolean(spec)` is true and you are about to expand generics
placeholders/bounds, to avoid per-call allocation overhead in the common "no
substitutions" case.
> StackOverflowError when having parameterized function with recursive bounds
> ---------------------------------------------------------------------------
>
> Key: GROOVY-11022
> URL: https://issues.apache.org/jira/browse/GROOVY-11022
> Project: Groovy
> Issue Type: Bug
> Components: Static Type Checker
> Reporter: Thodoris Sotiropoulos
> Assignee: Eric Milles
> Priority: Critical
> Labels: StackOverflowError, bounded-polymorphism
>
> I have the following program
> {code}
> class Test<K, V> {
> public static <K extends Comparable<? super K>, V> Test<K, V> m(K k1, V
> v1) {
> return new Test<K, V>()
> }
> }
> class Main {
> @groovy.transform.TypeChecked test() {
> Test.<Object, Integer>m(null, 1)
> }
> }
> {code}
> h3. Actual behavior
> {code}
> >>> a serious error occurred: null
> >>> stacktrace:
> java.lang.StackOverflowError
> at org.codehaus.groovy.ast.ClassNode.getText(ClassNode.java:1606)
> at org.codehaus.groovy.ast.ClassNode.equals(ClassNode.java:729)
> at
> org.codehaus.groovy.ast.ClassHelper.isObjectType(ClassHelper.java:525)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.hasNonTrivialBounds(StaticTypeCheckingSupport.java:1880)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1833)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1821)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1905)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1843)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1821)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1905)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1890)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1834)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1821)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1905)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1843)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1821)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1905)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1890)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1834)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1821)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1905)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1843)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1821)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1905)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1890)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1834)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1821)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1905)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1843)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1821)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1905)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1890)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1834)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1821)
> at
> org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext(StaticTypeCheckingSupport.java:1905)
> ...
> {code}
> h3. Expected behavior
> Reject with type error
> Tested against master (commit: bbbff15b867157d8ed9f05207265a5ea80357ba6)
--
This message was sent by Atlassian Jira
(v8.20.10#820010)