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 2021/03/02 23:59:38 UTC
[groovy] branch master updated: GROOVY-6232,
GROOVY-9956: check LHS type witness for diamond constructor
This is an automated email from the ASF dual-hosted git repository.
sunlan 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 715c34e GROOVY-6232, GROOVY-9956: check LHS type witness for diamond constructor
715c34e is described below
commit 715c34edc82261544b8715bc2253b0b3f05bdbad
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Feb 27 15:29:44 2021 -0600
GROOVY-6232, GROOVY-9956: check LHS type witness for diamond constructor
---
.../transform/stc/StaticTypeCheckingVisitor.java | 15 ++++++
.../groovy/transform/stc/GenericsSTCTest.groovy | 57 +++++++++++-----------
2 files changed, 43 insertions(+), 29 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 0a77404..1ef88a0 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1028,6 +1028,20 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
ClassNode type = GenericsUtils.parameterizeType(cceType, cceType);
type = inferReturnTypeGenerics(type, constructor, argumentList);
if (type.isUsingGenerics()) {
+ // GROOVY-6232, GROOVY-9956: if cce not assignment compatible, process target as additional type witness
+ if (checkCompatibleAssignmentTypes(lType, type, cce) && !GenericsUtils.buildWildcardType(lType).isCompatibleWith(type)) {
+ // allow covariance of each type parameter, but maintain semantics for nested generics
+
+ ClassNode pType = GenericsUtils.parameterizeType(lType, type);
+ GenericsType[] lhs = pType.getGenericsTypes(), rhs = type.getGenericsTypes();
+ if (lhs == null || rhs == null || lhs.length != rhs.length) throw new GroovyBugError(
+ "Parameterization failed: " + prettyPrintType(pType) + " ~ " + prettyPrintType(type));
+
+ if (java.util.stream.IntStream.range(0, lhs.length).allMatch(i ->
+ GenericsUtils.buildWildcardType(getCombinedBoundType(lhs[i])).isCompatibleWith(getCombinedBoundType(rhs[i])))) {
+ type = pType; // lType proved to be a viable type witness
+ }
+ }
inferredType = type;
}
}
@@ -3100,6 +3114,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
* @return a class node usable as an inferred type
*/
private static ClassNode createUsableClassNodeFromGenericsType(final GenericsType genericsType) {
+ // TODO: Merge with StaticTypeCheckingSupport#getCombinedBoundType(GenericsType)?
ClassNode value = genericsType.getType();
if (genericsType.isPlaceholder()) {
value = OBJECT_TYPE;
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 12b5e70..4c28a82 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -223,9 +223,9 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
void testDiamondInferrenceFromConstructor3() {
- shouldFailWithMessages '''
+ assertScript '''
Set<Number> set = new HashSet<>(Arrays.asList(0L))
- ''', 'Cannot assign java.util.HashSet <java.lang.Long> to: java.util.Set <Number>'
+ '''
// not diamond inference, but tests compatible assignment
assertScript '''
@@ -241,16 +241,13 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-6232
void testDiamondInferrenceFromConstructor5() {
- [/*'"a",new Object()',*/ 'new Object(),"b"', /*'"a","b"'*/].each { args ->
+ ['"a",new Object()', 'new Object(),"b"', '"a","b"'].each { args ->
assertScript """
class C<T> {
C(T x, T y) {
}
}
- void test() {
- C<Object> c = new C<>($args)
- }
- test()
+ C<Object> c = new C<>($args)
"""
}
}
@@ -265,11 +262,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
}
- void test() {
- C<Integer> c = new C<>(1)
- assert c.p < 10
- }
- test()
+ C<Integer> c = new C<>(1)
+ assert c.p < 10
'''
}
@@ -281,15 +275,12 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
T p
}
- void test() {
- C<Integer> c = new C<>(1)
- assert c.p < 10
- }
- test()
+ C<Integer> c = new C<>(1)
+ assert c.p < 10
'''
}
- @NotYetImplemented // GROOVY-9956
+ // GROOVY-9956
void testDiamondInferrenceFromConstructor8() {
assertScript '''
@groovy.transform.TupleConstructor
@@ -299,16 +290,11 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
interface I { }
class D implements I { }
- void test() {
- C<I> ci;
- ci = new C<I>(new D())
- ci = new C<>(new D()) // infers C<D> on RHS
- }
- test()
+ C<I> ci = new C<I>(new D())
+ ci = new C<>(new D()) // infers C<D> on RHS
'''
}
- @NotYetImplemented
void testDiamondInferrenceFromConstructor9() {
assertScript '''
abstract class A<X> { }
@@ -319,11 +305,24 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
interface I { }
class D implements I { }
- void test() {
- A<I> ai = new C<>(new D())
- }
- test()
+ A<I> ai = new C<>(new D())
'''
+
+ shouldFailWithMessages '''
+ abstract class A<X> { }
+ @groovy.transform.TupleConstructor
+ class C<T> extends A<T> {
+ T p
+ }
+ interface I { }
+ class D implements I { }
+
+ A<String> ax = new C<>(new D())
+ ''', 'Incompatible generic argument types. Cannot assign C <D> to: A <String>'
+
+ shouldFailWithMessages '''
+ Set<List<String>> strings = new HashSet<>([new ArrayList<Number>()])
+ ''', 'Incompatible generic argument types. Cannot assign java.util.HashSet <java.util.ArrayList> to: java.util.Set <List>'
}
void testLinkedListWithListArgument() {