You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2021/03/24 03:50:15 UTC
[groovy] branch master updated: GROOVY-9998: STC: connect "? super
T" with "X" not as "T=X" but as "T=?"
This is an automated email from the ASF dual-hosted git repository.
emilles 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 e6ce56f GROOVY-9998: STC: connect "? super T" with "X" not as "T=X" but as "T=?"
e6ce56f is described below
commit e6ce56fc27e7640664946eb1a99bdee6fb63547e
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Mar 23 22:43:26 2021 -0500
GROOVY-9998: STC: connect "? super T" with "X" not as "T=X" but as "T=?"
---
.../transform/stc/StaticTypeCheckingSupport.java | 21 +++---
.../groovy/transform/stc/GenericsSTCTest.groovy | 21 ++++++
.../classgen/asm/sc/bugs/Groovy6564Bug.groovy | 82 +++++++++++-----------
3 files changed, 71 insertions(+), 53 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 875777a..6270dd0 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1579,7 +1579,7 @@ public abstract class StaticTypeCheckingSupport {
}
static void applyGenericsConnections(final Map<GenericsTypeName, GenericsType> connections, final Map<GenericsTypeName, GenericsType> resolvedPlaceholders) {
- if (connections == null) return;
+ if (connections == null || connections.isEmpty()) return;
int count = 0;
while (count++ < 10000) {
boolean checkForMorePlaceholders = false;
@@ -1598,7 +1598,7 @@ public abstract class StaticTypeCheckingSupport {
// the original bounds are lost, which can result in accepting an incompatible type as an argument.
ClassNode replacementType = extractType(newValue);
if (oldValue.isCompatibleWith(replacementType)) {
- entry.setValue(newValue);
+ entry.setValue(newValue.isWildcard() ? new GenericsType(replacementType) : newValue); // GROOVY-9998
if (newValue.isPlaceholder()) {
checkForMorePlaceholders = checkForMorePlaceholders || !equalIncludingGenerics(oldValue, newValue);
}
@@ -1736,8 +1736,7 @@ public abstract class StaticTypeCheckingSupport {
// both have generics
for (int i = 0, n = usage.length; i < n; i += 1) {
- GenericsType ui = usage[i];
- GenericsType di = declaration[i];
+ GenericsType ui = usage[i], di = declaration[i];
if (di.isPlaceholder()) {
connections.put(new GenericsTypeName(di.getName()), ui);
} else if (di.isWildcard()) {
@@ -1745,13 +1744,13 @@ public abstract class StaticTypeCheckingSupport {
extractGenericsConnections(connections, ui.getLowerBound(), di.getLowerBound());
extractGenericsConnections(connections, ui.getUpperBounds(), di.getUpperBounds());
} else {
- ClassNode cu = ui.getType();
- extractGenericsConnections(connections, cu, di.getLowerBound());
- ClassNode[] upperBounds = di.getUpperBounds();
- if (upperBounds != null) {
- for (ClassNode cn : upperBounds) {
- extractGenericsConnections(connections, cu, cn);
- }
+ ClassNode boundType = getCombinedBoundType(di);
+ if (boundType.isGenericsPlaceHolder()) { // GROOVY-9998
+ String placeholderName = boundType.getUnresolvedName();
+ ui = new GenericsType(ui.getType()); ui.setWildcard(true);
+ connections.put(new GenericsTypeName(placeholderName), ui);
+ } else { // di like "? super Collection<T>" and ui like "List<Type>"
+ extractGenericsConnections(connections, ui.getType(), boundType);
}
}
} else {
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 087eaab..dc1a4ae 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -2543,6 +2543,27 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-9998
+ void testContravariantMethodResolution2() {
+ assertScript '''
+ import groovy.transform.*
+ @TupleConstructor(defaults=false)
+ class A {
+ final int order
+ }
+ @InheritConstructors @ToString(includeSuperProperties=true)
+ class B extends A {
+ }
+
+ Comparator<A> comparator = { a1, a2 -> Integer.compare(a1.order, a2.order) }
+
+ def input = [new B(2), new B(3), new B(1), new B(0)]
+ // sorted(Comparator<? super B>) using Comparator<A>
+ def result = input.stream().sorted(comparator).toList()
+ assert result.toString().equals("[B(0), B(1), B(2), B(3)]")
+ '''
+ }
+
void testContravariantMethodResolutionWithImplicitCoercion() {
assertScript '''
interface Function<T, R> {
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6564Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6564Bug.groovy
index 0697069..b15a994 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6564Bug.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6564Bug.groovy
@@ -16,10 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-
-
-
-
package org.codehaus.groovy.classgen.asm.sc.bugs
import groovy.transform.stc.StaticTypeCheckingTestCase
@@ -28,46 +24,48 @@ import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
class Groovy6564Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
void testShouldNotRequireIntermediateVariableToPass() {
- assertScript '''class Stream<T> implements Iterable<T> {
- public static Stream<String> from(BufferedReader reader) { new Stream(data: ['a', 'b', 'c']) }
-
- List<T> data
-
- public Iterator<T> iterator() { data.iterator() }
-
- public <U> Stream<U> flatMap(Closure<? extends Collection<U>> closure) {
- new Stream(data: data.collect(closure).flatten() as List)
- }
-}
-
-Map<String, Integer> frequencies = [:].withDefault { 0 }
-BufferedReader r = null
-Stream.from(r)
- .flatMap { String it -> it.toList() }
- .each { String it -> frequencies[it.toUpperCase()]++ }
- assert frequencies == [A:1, B:1, C:1]
-'''
+ assertScript '''
+ class Stream<T> implements Iterable<T> {
+ public static Stream<String> from(BufferedReader reader) { new Stream(data: ['a', 'b', 'c']) }
+
+ List<T> data
+
+ public Iterator<T> iterator() { data.iterator() }
+
+ public <U> Stream<U> flatMap(Closure<? extends Collection<U>> closure) {
+ new Stream(data: data.collect(closure).flatten() as List)
+ }
+ }
+
+ Map<String, Integer> frequencies = [:].withDefault { 0 }
+ BufferedReader r = null
+ Stream.from(r)
+ .flatMap { String it -> it.toList() }
+ .each { String it -> frequencies[it.toUpperCase()]++ }
+ assert frequencies == [A:1, B:1, C:1]
+ '''
}
void testShouldNotRequireIntermediateVariableToPassWithEachParamInference() {
- assertScript '''class Stream<T> implements Iterable<T> {
- public static Stream<String> from(BufferedReader reader) { new Stream(data: ['a', 'b', 'c']) }
-
- List<T> data
-
- public Iterator<T> iterator() { data.iterator() }
-
- public <U> Stream<U> flatMap(Closure<? extends Collection<U>> closure) {
- new Stream(data: data.collect(closure).flatten() as List)
- }
-}
-
-Map<String, Integer> frequencies = [:].withDefault { 0 }
-BufferedReader r = null
-Stream.from(r)
- .flatMap { String it -> it.toList() }
- .each { println it; frequencies[it.toUpperCase()]++ }
- assert frequencies == [A:1, B:1, C:1]
-'''
+ assertScript '''
+ class Stream<T> implements Iterable<T> {
+ public static Stream<String> from(BufferedReader reader) { new Stream(data: ['a', 'b', 'c']) }
+
+ List<T> data
+
+ public Iterator<T> iterator() { data.iterator() }
+
+ public <U> Stream<U> flatMap(Closure<? extends Collection<U>> closure) {
+ new Stream(data: data.collect(closure).flatten() as List)
+ }
+ }
+
+ Map<String, Integer> frequencies = [:].withDefault { 0 }
+ BufferedReader r = null
+ Stream.from(r)
+ .flatMap { String it -> it.toList() }
+ .each { frequencies[it.toUpperCase()]++ }
+ assert frequencies == [A:1, B:1, C:1]
+ '''
}
}