Skip to content

Commit

Permalink
GROOVY-9948: infer type arguments for CCE diamond using argument type(s)
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles authored and daniellansun committed Feb 19, 2021
1 parent 9219777 commit 566c832
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1019,20 +1019,20 @@ protected ClassNode getOriginalDeclarationType(final Expression lhs) {
}

protected void inferDiamondType(final ConstructorCallExpression cce, final ClassNode lType) {
ClassNode cceType = cce.getType(), inferredType = lType;
// check if constructor call expression makes use of the diamond operator
ClassNode node = cce.getType();
if (node.isUsingGenerics() && node.getGenericsTypes() != null && node.getGenericsTypes().length == 0) {
ArgumentListExpression argumentListExpression = InvocationWriter.makeArgumentList(cce.getArguments());
if (argumentListExpression.getExpressions().isEmpty()) {
adjustGenerics(lType, node);
} else {
ClassNode type = getType(argumentListExpression.getExpression(0));
if (cceType.getGenericsTypes() != null && cceType.getGenericsTypes().length == 0) {
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 (type.isUsingGenerics()) {
adjustGenerics(type, node);
inferredType = type;
}
}
// store inferred type on CCE
storeType(cce, node);
adjustGenerics(inferredType, cceType);
storeType(cce, cceType);
}
}

Expand Down Expand Up @@ -5096,7 +5096,7 @@ protected ClassNode inferReturnTypeGenerics(final ClassNode receiver, final Meth
* @return parameterized, infered, class node
*/
protected ClassNode inferReturnTypeGenerics(final ClassNode receiver, final MethodNode method, final Expression arguments, final GenericsType[] explicitTypeHints) {
ClassNode returnType = method.getReturnType();
ClassNode returnType = method instanceof ConstructorNode ? method.getDeclaringClass() : method.getReturnType();
if (getGenericsWithoutArray(returnType) == null) {
return returnType;
}
Expand Down
82 changes: 63 additions & 19 deletions src/test/groovy/transform/stc/GenericsSTCTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -210,27 +210,82 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}

void testDiamondInferrenceFromConstructor() {
void testDiamondInferrenceFromConstructor1() {
assertScript '''
Set< Long > s2 = new HashSet<>()
Set<Long> set = new HashSet<>()
'''
}

void testDiamondInferrenceFromConstructorWithoutAssignment() {
void testDiamondInferrenceFromConstructor2() {
assertScript '''
new HashSet<>(Arrays.asList(0L,0L));
new HashSet<>(Arrays.asList(0L))
'''
}

void testDiamondInferrenceFromConstructor2() {
void testDiamondInferrenceFromConstructor3() {
shouldFailWithMessages '''
Set< Number > s3 = new HashSet<>(Arrays.asList(0L,0L));
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 '''
Set<Number> set = new HashSet<Number>(Arrays.asList(0L))
'''
}

void testDiamondInferrenceFromConstructor3() {
void testDiamondInferrenceFromConstructor4() {
assertScript '''
Set<? extends Number> set = new HashSet<>(Arrays.asList(0L))
'''
}

// GROOVY-6232
void testDiamondInferrenceFromConstructor5() {
[/*'"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()
"""
}
}

// GROOVY-9948
void testDiamondInferrenceFromConstructor6() {
assertScript '''
class C<T> {
T p
C(T p) {
this.p = p
}
}
void test() {
C<Integer> c = new C<>(1)
assert c.p < 10
}
test()
'''
}

// GROOVY-9948
void testDiamondInferrenceFromConstructor7() {
assertScript '''
Set<Number> s4 = new HashSet<Number>(Arrays.asList(0L,0L))
@groovy.transform.TupleConstructor
class C<T> {
T p
}
void test() {
C<Integer> c = new C<>(1)
assert c.p < 10
}
test()
'''
}

Expand Down Expand Up @@ -1777,17 +1832,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 '''
Expand Down

0 comments on commit 566c832

Please sign in to comment.