You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2022/06/25 04:39:21 UTC
[groovy] branch GROOVY_4_0_X updated: GROOVY-10633, GROOVY-10662: STC: do not mix generics contexts
This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
new a789e089b1 GROOVY-10633, GROOVY-10662: STC: do not mix generics contexts
a789e089b1 is described below
commit a789e089b18d051329db860fa173eafb9586c4d8
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Jun 21 09:39:09 2022 -0500
GROOVY-10633, GROOVY-10662: STC: do not mix generics contexts
(cherry picked from commit deeb858cc89fe8fee68bff00ef12eeb152720360)
---
.../transform/stc/StaticTypeCheckingSupport.java | 70 +++++++++-------------
.../groovy/transform/stc/GenericsSTCTest.groovy | 40 +++++++++++++
2 files changed, 68 insertions(+), 42 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
index a66471b9d8..3e1d2b3c25 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1603,53 +1603,39 @@ public abstract class StaticTypeCheckingSupport {
static void applyGenericsConnections(final Map<GenericsTypeName, GenericsType> connections, final Map<GenericsTypeName, GenericsType> resolvedPlaceholders) {
if (connections == null || connections.isEmpty()) return;
- int count = 0;
- while (count++ < 10000) {
- boolean checkForMorePlaceholders = false;
- for (Map.Entry<GenericsTypeName, GenericsType> entry : resolvedPlaceholders.entrySet()) {
- // entry could be T=T, T=T extends U, T=V, T=String, T=? extends String, etc.
- GenericsType oldValue = entry.getValue();
- if (oldValue.isPlaceholder()) { // T=T or V, not T=String or ? ...
- GenericsTypeName name = new GenericsTypeName(oldValue.getName());
- GenericsType newValue = connections.get(name); // find "V" in T=V
- if (newValue == oldValue) continue;
- if (newValue == null) {
- newValue = connections.get(entry.getKey());
- if (newValue != null) { // GROOVY-10315, GROOVY-10317
- newValue = getCombinedGenericsType(oldValue, newValue);
- }
+ for (Map.Entry<GenericsTypeName, GenericsType> entry : resolvedPlaceholders.entrySet()) {
+ // entry could be T=T, T=T extends U, T=V, T=String, T=? extends String, etc.
+ GenericsType oldValue = entry.getValue();
+ if (oldValue.isPlaceholder()) { // T=T or V, not T=String or ? ...
+ GenericsTypeName name = new GenericsTypeName(oldValue.getName());
+ GenericsType newValue = connections.get(name); // find "V" in T=V
+ if (newValue == oldValue) continue;
+ if (newValue == null) {
+ newValue = connections.get(entry.getKey());
+ if (newValue != null) { // GROOVY-10315, GROOVY-10317
+ newValue = getCombinedGenericsType(oldValue, newValue);
}
- if (newValue == null) {
- entry.setValue(newValue = applyGenericsContext(connections, oldValue));
- if (!checkForMorePlaceholders) {
- checkForMorePlaceholders = !equalIncludingGenerics(oldValue, newValue);
- }
- } else if (!newValue.isPlaceholder() || newValue != resolvedPlaceholders.get(name)) {
- // GROOVY-6787: Don't override the original if the replacement doesn't respect the bounds otherwise
- // the original bounds are lost, which can result in accepting an incompatible type as an argument!
- ClassNode replacementType = extractType(newValue);
- ClassNode suitabilityType = !replacementType.isGenericsPlaceHolder()
- ? replacementType : Optional.ofNullable(replacementType.getGenericsTypes())
- .map(gts -> extractType(gts[0])).orElse(replacementType.redirect());
-
- if (oldValue.isCompatibleWith(suitabilityType)) {
- if (newValue.isWildcard() && newValue.getLowerBound() == null && newValue.getUpperBounds() == null) {
- // GROOVY-9998: apply upper/lower bound for unknown
- entry.setValue(replacementType.asGenericsType());
- } else {
- entry.setValue(newValue);
- }
- if (!checkForMorePlaceholders && newValue.isPlaceholder()) {
- checkForMorePlaceholders = !equalIncludingGenerics(oldValue, newValue);
- }
+ }
+ if (newValue == null) {
+ entry.setValue(newValue = applyGenericsContext(connections, oldValue));
+ } else if (!newValue.isPlaceholder() || newValue != resolvedPlaceholders.get(name)) {
+ // GROOVY-6787: Don't override the original if the replacement doesn't respect the bounds otherwise
+ // the original bounds are lost, which can result in accepting an incompatible type as an argument!
+ ClassNode replacementType = extractType(newValue);
+ ClassNode suitabilityType = !replacementType.isGenericsPlaceHolder()
+ ? replacementType : Optional.ofNullable(replacementType.getGenericsTypes())
+ .map(gts -> extractType(gts[0])).orElse(replacementType.redirect());
+
+ if (oldValue.isCompatibleWith(suitabilityType)) {
+ if (newValue.isWildcard() && newValue.getLowerBound() == null && newValue.getUpperBounds() == null) {
+ // GROOVY-9998: apply upper/lower bound for unknown
+ entry.setValue(replacementType.asGenericsType());
+ } else {
+ entry.setValue(newValue);
}
}
}
}
- if (!checkForMorePlaceholders) break;
- }
- if (count >= 10000) {
- throw new GroovyBugError("unable to handle generics in " + resolvedPlaceholders + " with connections " + connections);
}
}
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 7776a15992..32c463ceb5 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -1354,6 +1354,46 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-10662
+ void testDiamondInferrenceFromConstructor31() {
+ assertScript '''
+ class A<X, T> {
+ A(T t, X x) {}
+ void m(X x) {}
+ }
+ class B<T extends Number> {
+ void test() {
+ T t = (T) null
+ Character c = 'c'
+ def a = new A<>(c, t)
+ a.m((T) null) // Cannot find matching method A#m(T)
+ }
+ }
+ new B<Integer>().test()
+ '''
+ }
+
+ // GROOVY-10633
+ void testDiamondInferrenceFromConstructor32() {
+ assertScript '''
+ class A<T, Y> {
+ public B<Y> f
+ A(B<Y> b_of_y, T t) {
+ this.f = b_of_y
+ }
+ }
+ class B<T> {
+ void m(T t) {
+ }
+ }
+ <T extends Number> void test() {
+ def x = new B<T>()
+ new A<>(x, '').f.m((T) null)
+ }
+ test()
+ '''
+ }
+
// GROOVY-10280
void testTypeArgumentPropagation() {
assertScript '''