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 2022/05/16 19:32:24 UTC
[groovy] 01/03: GROOVY-7419, GROOVY-9948, GROOVY-9956: STC: infer <> from argument types
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit e6016c634d0ab92f892216ef52be0a7f52457630
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Feb 17 15:05:15 2021 -0600
GROOVY-7419, GROOVY-9948, GROOVY-9956: STC: infer <> from argument types
---
.../transform/stc/StaticTypeCheckingVisitor.java | 32 +++++++++++++-----
.../groovy/transform/stc/GenericsSTCTest.groovy | 38 +++++-----------------
2 files changed, 32 insertions(+), 38 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 3631754ce6..35f6cd29d4 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1051,19 +1051,33 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
protected void inferDiamondType(final ConstructorCallExpression cce, final ClassNode lType) {
- ClassNode cceType = cce.getType();
+ ClassNode cceType = cce.getType(), inferredType = lType;
// check if constructor call expression makes use of the diamond operator
if (cceType.getGenericsTypes() != null && cceType.getGenericsTypes().length == 0) {
- ArgumentListExpression argumentListExpression = InvocationWriter.makeArgumentList(cce.getArguments());
- if (argumentListExpression.getExpressions().isEmpty()) {
- adjustGenerics(lType, cceType);
- } else {
- ClassNode type = getType(argumentListExpression.getExpression(0));
- if (type.isUsingGenerics()) {
- adjustGenerics(type, cceType);
+ ArgumentListExpression argumentList = InvocationWriter.makeArgumentList(cce.getArguments());
+ ConstructorNode constructor = cce.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
+ if (!argumentList.getExpressions().isEmpty() && constructor != null) {
+ ClassNode type = GenericsUtils.parameterizeType(cceType, cceType);
+ type = inferReturnTypeGenerics(type, constructor, argumentList);
+ if (lType.getGenericsTypes() != null // GROOVY-10367: nothing to inspect
+ // GROOVY-6232, GROOVY-9956: if cce not assignment compatible, process target as additional type witness
+ && 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(rhs[i].getType()))) {
+ type = pType; // lType proved to be a viable type witness
+ }
}
+ inferredType = type;
}
- // store inferred type on CCE
+
+ adjustGenerics(inferredType, cceType);
storeType(cce, cceType);
}
}
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 2582791dfa..461bcd0cae 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -494,7 +494,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-8638
void testReturnTypeInferenceWithMethodGenerics18() {
assertScript '''
- @Grab('com.google.guava:guava:30.1.1-jre')
+ @Grab('com.google.guava:guava:31.1-jre')
import com.google.common.collect.*
ListMultimap<String, Integer> mmap = ArrayListMultimap.create()
@@ -633,21 +633,13 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
new HashSet<>(Arrays.asList(0L))
'''
- // not diamond inference, but tests compatible assignment
assertScript '''
- Set<Number> set = new HashSet<Number>(Arrays.asList(0L))
- '''
-
- shouldFailWithMessages '''
Set<Number> set = new HashSet<>(Arrays.asList(0L))
- ''',
- 'Cannot assign java.util.HashSet <java.lang.Long> to: java.util.Set <Number>'
- }
+ '''
- @NotYetImplemented
- void testDiamondInferrenceFromConstructor3a() {
+ // not diamond inference, but tests compatible assignment
assertScript '''
- Set<Number> set = new HashSet<>(Arrays.asList(0L))
+ Set<Number> set = new HashSet<Number>(Arrays.asList(0L))
'''
assertScript '''
@@ -659,7 +651,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- @NotYetImplemented // GROOVY-7419
+ // GROOVY-7419
void testDiamondInferrenceFromConstructor4() {
assertScript '''
Map<Thread.State, Object> map = new EnumMap<>(Thread.State)
@@ -773,7 +765,6 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- @NotYetImplemented
void testDiamondInferrenceFromConstructor9() {
assertScript '''
abstract class A<X> { }
@@ -798,12 +789,12 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
A<String> ax = new C<>(new D())
''',
- 'Incompatible generic argument types. Cannot assign C<D> to: A<java.lang.String>'
+ '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<java.lang.Number>> to: java.util.Set<java.util.List<java.lang.String>>'
+ 'Incompatible generic argument types. Cannot assign java.util.HashSet <java.util.ArrayList> to: java.util.Set <List>'
}
// GROOVY-9972
@@ -832,7 +823,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
C<D> cd = b ? new C<>(new D()) : (b ? new C<>((D) null) : new C<>(new D()))
assert cd.p.f.toLowerCase() == 'd#f'
'''
-/*
+
assertScript '''
@groovy.transform.TupleConstructor(defaults=false)
class C<T> {
@@ -849,7 +840,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
assert cd.p.f.toLowerCase() == 'd#f'
'''
-*/
+
assertScript '''
@groovy.transform.TupleConstructor
class C {
@@ -3182,17 +3173,6 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- // GROOVY-6232
- void testDiamond() {
- assertScript '''
- class Foo<T>{ Foo(T a, T b){} }
- def bar() {
- Foo<Object> f = new Foo<>("a",new Object())
- }
- bar()
- '''
- }
-
// GROOVY-6233
void testConstructorArgumentsAgainstGenerics() {
shouldFailWithMessages '''