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/09/02 13:13:33 UTC
[groovy] branch GROOVY_4_0_X updated: GROOVY-10744: STC: assignment of primitives to wrapper-type interfaces
This is an automated email from the ASF dual-hosted git repository.
emilles 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 c9462cb261 GROOVY-10744: STC: assignment of primitives to wrapper-type interfaces
c9462cb261 is described below
commit c9462cb2610f5ad92964ca92bdb2d18fdaa05ee6
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Sep 2 07:37:58 2022 -0500
GROOVY-10744: STC: assignment of primitives to wrapper-type interfaces
---
.../transform/stc/StaticTypeCheckingSupport.java | 5 +-
.../transform/stc/StaticTypeCheckingVisitor.java | 23 ++-
.../groovy/transform/stc/STCAssignmentTest.groovy | 201 +++++++++++++--------
3 files changed, 140 insertions(+), 89 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 b63fc940bb..d450822884 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -751,8 +751,9 @@ public abstract class StaticTypeCheckingSupport {
return true;
}
- // simple sub-type check
- if (!left.isInterface() ? right.isDerivedFrom(left) : GeneralUtils.isOrImplements(right, left)) return true;
+ if (implementsInterfaceOrSubclassOf(getWrapper(right), left)) {
+ return true;
+ }
if (right.isDerivedFrom(CLOSURE_TYPE) && isSAMType(left)) {
return true;
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 2712d4213e..f8ea757d47 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1270,13 +1270,13 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
checkGroovyConstructorMap(leftExpression, leftRedirect, mapExpression);
}
- private void checkTypeGenerics(final ClassNode leftExpressionType, final ClassNode wrappedRHS, final Expression rightExpression) {
+ private void checkTypeGenerics(final ClassNode leftExpressionType, final ClassNode rightExpressionType, final Expression rightExpression) {
if (leftExpressionType.isUsingGenerics()
- && !isNullConstant(rightExpression)
+ && !missesGenericsTypes(rightExpressionType)
&& !(rightExpression instanceof ClosureExpression) // GROOVY-10277
- && !UNKNOWN_PARAMETER_TYPE.equals(wrappedRHS) && !missesGenericsTypes(wrappedRHS)
- && !GenericsUtils.buildWildcardType(leftExpressionType).isCompatibleWith(wrappedRHS))
- addStaticTypeError("Incompatible generic argument types. Cannot assign " + prettyPrintType(wrappedRHS) + " to: " + prettyPrintType(leftExpressionType), rightExpression);
+ && !isNullConstant(rightExpression) && !UNKNOWN_PARAMETER_TYPE.equals(rightExpressionType)
+ && !GenericsUtils.buildWildcardType(leftExpressionType).isCompatibleWith(wrapTypeIfNecessary(rightExpressionType)))
+ addStaticTypeError("Incompatible generic argument types. Cannot assign " + prettyPrintType(rightExpressionType) + " to: " + prettyPrintType(leftExpressionType), rightExpression);
}
private boolean hasGStringStringError(final ClassNode leftExpressionType, final ClassNode wrappedRHS, final Expression rightExpression) {
@@ -1307,23 +1307,22 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
// TODO: need errors for write-only too!
if (addedReadOnlyPropertyError(leftExpression)) return;
- ClassNode rTypeWrapped = adjustTypeForSpreading(rightExpressionType, leftExpression);
+ ClassNode rType = adjustTypeForSpreading(rightExpressionType, leftExpression);
- if (!checkCompatibleAssignmentTypes(leftExpressionType, rTypeWrapped, rightExpression)) {
- if (!extension.handleIncompatibleAssignment(leftExpressionType, rightExpressionType, assignmentExpression)) {
+ if (!checkCompatibleAssignmentTypes(leftExpressionType, rType, rightExpression)) {
+ if (!extension.handleIncompatibleAssignment(leftExpressionType, rType, assignmentExpression)) {
addAssignmentError(leftExpressionType, rightExpressionType, rightExpression);
}
} else {
ClassNode lTypeRedirect = leftExpressionType.redirect();
- addPrecisionErrors(lTypeRedirect, leftExpressionType, rightExpressionType, rightExpression);
+ addPrecisionErrors(lTypeRedirect, leftExpressionType, rType, rightExpression);
if (rightExpression instanceof ListExpression) {
addListAssignmentConstructorErrors(lTypeRedirect, leftExpressionType, rightExpressionType, rightExpression, assignmentExpression);
} else if (rightExpression instanceof MapExpression) {
addMapAssignmentConstructorErrors(lTypeRedirect, leftExpression, rightExpression);
}
- if (!hasGStringStringError(leftExpressionType, rTypeWrapped, rightExpression)
- && !isConstructorAbbreviation(leftExpressionType, rightExpression)) {
- checkTypeGenerics(leftExpressionType, rTypeWrapped, rightExpression);
+ if (!hasGStringStringError(leftExpressionType, rType, rightExpression) && !isConstructorAbbreviation(leftExpressionType, rightExpression)) {
+ checkTypeGenerics(leftExpressionType, rType, rightExpression);
}
}
}
diff --git a/src/test/groovy/transform/stc/STCAssignmentTest.groovy b/src/test/groovy/transform/stc/STCAssignmentTest.groovy
index c573582bcc..38c7e21169 100644
--- a/src/test/groovy/transform/stc/STCAssignmentTest.groovy
+++ b/src/test/groovy/transform/stc/STCAssignmentTest.groovy
@@ -23,43 +23,49 @@ package groovy.transform.stc
*/
class STCAssignmentTest extends StaticTypeCheckingTestCase {
- void testAssignmentFailure() {
+ void testAssignmentFailure1() {
shouldFailWithMessages '''
int x = new Object()
- ''', 'Cannot assign value of type java.lang.Object to variable of type int'
+ ''',
+ 'Cannot assign value of type java.lang.Object to variable of type int'
}
void testAssignmentFailure2() {
shouldFailWithMessages '''
Set set = new Object()
- ''', 'Cannot assign value of type java.lang.Object to variable of type java.util.Set'
+ ''',
+ 'Cannot assign value of type java.lang.Object to variable of type java.util.Set'
}
void testAssignmentFailure3() {
shouldFailWithMessages '''
Set set = new Integer(2)
- ''', 'Cannot assign value of type java.lang.Integer to variable of type java.util.Set'
+ ''',
+ 'Cannot assign value of type java.lang.Integer to variable of type java.util.Set'
}
- void testIndirectAssignment() {
+ void testIndirectAssignment1() {
shouldFailWithMessages '''
def o = new Object()
int x = o
- ''', 'Cannot assign value of type java.lang.Object to variable of type int'
+ ''',
+ 'Cannot assign value of type java.lang.Object to variable of type int'
}
void testIndirectAssignment2() {
shouldFailWithMessages '''
def o = new Object()
Set set = o
- ''', 'Cannot assign value of type java.lang.Object to variable of type java.util.Set'
+ ''',
+ 'Cannot assign value of type java.lang.Object to variable of type java.util.Set'
}
void testIndirectAssignment3() {
shouldFailWithMessages '''
int x = 2
Set set = x
- ''', 'Cannot assign value of type int to variable of type java.util.Set'
+ ''',
+ 'Cannot assign value of type int to variable of type java.util.Set'
}
void testAssignmentToEnum() {
@@ -69,14 +75,18 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
e = 'a' // string to enum is implicit
e = "${'a'}" // gstring to enum is implicit too
'''
- }
-
- void testAssignmentToEnumFailure() {
shouldFailWithMessages '''
enum MyEnum { a, b, c }
MyEnum e = MyEnum.a
e = 1
- ''', 'Cannot assign value of type int to variable of type MyEnum'
+ ''',
+ 'Cannot assign value of type int to variable of type MyEnum'
+ }
+
+ void testAssignmentToClass() {
+ assertScript '''
+ Class test = 'java.lang.String'
+ '''
}
void testAssignmentToString() {
@@ -97,9 +107,23 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
'''
}
- void testAssignmentToClass() {
+ // GROOVY-10744
+ void testAssignmentToSerializable() {
+ // Number implements Serializable
assertScript '''
- Class test = 'java.lang.String'
+ Serializable x = 0
+ Serializable y = 1.2
+ Serializable z = Math.PI
+ assert x.class.name == 'java.lang.Integer'
+ assert y.class.name == 'java.math.BigDecimal'
+ assert z.class.name == 'java.lang.Double'
+ '''
+ // Boolean implements Serializable and Comparable<Boolean>
+ assertScript '''
+ Serializable x = true
+ Comparable<Boolean> y = false
+ assert x.class.name == 'java.lang.Boolean'
+ assert y.class.name == 'java.lang.Boolean'
'''
}
@@ -121,14 +145,16 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
int i = 0
i += new Object()
- ''', 'Cannot find matching method int#plus(java.lang.Object)'
+ ''',
+ 'Cannot find matching method int#plus(java.lang.Object)'
}
void testIntMinusEqualsObject() {
shouldFailWithMessages '''
int i = 0
i -= new Object()
- ''', 'Cannot find matching method int#minus(java.lang.Object)'
+ ''',
+ 'Cannot find matching method int#minus(java.lang.Object)'
}
void testStringPlusEqualsString() {
@@ -214,65 +240,69 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
'''
}
- void testPossibleLooseOfPrecision() {
+ void testPossibleLossOfPrecision1() {
shouldFailWithMessages '''
long a = Long.MAX_VALUE
int b = a
- ''', 'Possible loss of precision from long to int'
+ ''',
+ 'Possible loss of precision from long to int'
}
- void testPossibleLooseOfPrecision2() {
+ void testPossibleLossOfPrecision2() {
assertScript '''
int b = 0L
'''
}
- void testPossibleLooseOfPrecision3() {
+ void testPossibleLossOfPrecision3() {
assertScript '''
byte b = 127
'''
}
- void testPossibleLooseOfPrecision4() {
+ void testPossibleLossOfPrecision4() {
shouldFailWithMessages '''
byte b = 128 // will not fit in a byte
- ''', 'Possible loss of precision from int to byte'
+ ''',
+ 'Possible loss of precision from int to byte'
}
- void testPossibleLooseOfPrecision5() {
+ void testPossibleLossOfPrecision5() {
assertScript '''
short b = 128
'''
}
- void testPossibleLooseOfPrecision6() {
+ void testPossibleLossOfPrecision6() {
shouldFailWithMessages '''
short b = 32768 // will not fit in a short
- ''', 'Possible loss of precision from int to short'
+ ''',
+ 'Possible loss of precision from int to short'
}
- void testPossibleLooseOfPrecision7() {
+ void testPossibleLossOfPrecision7() {
assertScript '''
int b = 32768L // mark it as a long, but it fits into an int
'''
}
- void testPossibleLooseOfPrecision8() {
+ void testPossibleLossOfPrecision8() {
assertScript '''
int b = 32768.0f // mark it as a float, but it fits into an int
'''
}
- void testPossibleLooseOfPrecision9() {
+ void testPossibleLossOfPrecision9() {
assertScript '''
int b = 32768.0d // mark it as a double, but it fits into an int
'''
}
- void testPossibleLooseOfPrecision10() {
+ void testPossibleLossOfPrecision10() {
shouldFailWithMessages '''
int b = 32768.1d
- ''', 'Possible loss of precision from double to int'
+ ''',
+ 'Possible loss of precision from double to int'
}
void testCastIntToShort() {
@@ -289,8 +319,8 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
void testCompatibleTypeCast() {
assertScript '''
- String s = 'Hello'
- ((CharSequence) s)
+ String s = 'Hello'
+ ((CharSequence) s)
'''
}
@@ -298,7 +328,8 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
String s = 'Hello'
((Set) s)
- ''', 'Inconvertible types: cannot cast java.lang.String to java.util.Set'
+ ''',
+ 'Inconvertible types: cannot cast java.lang.String to java.util.Set'
}
void testIncompatibleTypeCastWithAsType() {
@@ -314,7 +345,8 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
def s = 'Hello'
s = 1
((Set) s)
- ''', 'Inconvertible types: cannot cast int to java.util.Set'
+ ''',
+ 'Inconvertible types: cannot cast int to java.util.Set'
}
void testArrayLength() {
@@ -347,7 +379,8 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
List x
List y
(x,y) = [1,2]
- ''', 'Cannot assign value of type int to variable of type java.util.List'
+ ''',
+ 'Cannot assign value of type int to variable of type java.util.List'
}
void testMultipleAssignmentWithoutEnoughArgs() {
@@ -355,7 +388,8 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
int x
int y
(x,y) = [1]
- ''', 'Incorrect number of values. Expected:2 Was:1'
+ ''',
+ 'Incorrect number of values. Expected:2 Was:1'
}
void testMultipleAssignmentTooManyArgs() {
@@ -372,7 +406,8 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
def list = [1,2,3]
def (x,y) = list
- ''', 'Multiple assignments without list or tuple on the right-hand side are unsupported in static type checking mode'
+ ''',
+ 'Multiple assignments without list or tuple on the right-hand side are unsupported in static type checking mode'
}
// GROOVY-8223, GROOVY-8887, GROOVY-10063
@@ -477,20 +512,20 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
void testAssignmentToInterface() {
assertScript '''
- Serializable ser = 'Hello'
+ Comparable<String> x = 'x'
+ CharSequence y = 'y'
'''
- }
-
- void testAssignmentToIncompatibleInterface() {
shouldFailWithMessages '''
- Collection ser = 'Hello'
- ''', 'Cannot assign value of type java.lang.String to variable of type java.util.Collection'
+ Collection z = 'z'
+ ''',
+ 'Cannot assign value of type java.lang.String to variable of type java.util.Collection'
}
void testTernaryOperatorAssignmentShouldFailBecauseOfIncompatibleGenericTypes() {
shouldFailWithMessages '''
List<Integer> foo = true?new LinkedList<String>():new LinkedList<Integer>();
- ''', 'Incompatible generic argument types. Cannot assign java.util.LinkedList<? extends java.io.Serializable<? extends java.io.Serializable<java.lang.String>>> to: java.util.List<java.lang.Integer>'
+ ''',
+ 'Incompatible generic argument types. Cannot assign java.util.LinkedList<? extends java.io.Serializable<? extends java.io.Serializable<java.lang.String>>> to: java.util.List<java.lang.Integer>'
}
void testCastStringToChar() {
@@ -502,13 +537,15 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
void testCastStringLongerThan1CharToChar() {
shouldFailWithMessages '''
char c = 'aa'
- ''','Cannot assign value of type java.lang.String to variable of type char'
+ ''',
+ 'Cannot assign value of type java.lang.String to variable of type char'
}
void testCastNullToChar() {
shouldFailWithMessages '''
char c = null
- ''', 'Cannot assign value of type java.lang.Object to variable of type char'
+ ''',
+ 'Cannot assign value of type java.lang.Object to variable of type char'
}
// GROOVY-6577
@@ -536,7 +573,8 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
void testCastStringLongerThan1CharToCharacter() {
shouldFailWithMessages '''
Character c = 'aa'
- ''','Cannot assign value of type java.lang.String to variable of type java.lang.Character'
+ ''',
+ 'Cannot assign value of type java.lang.String to variable of type java.lang.Character'
}
void testAssignNullToCharacter() {
@@ -570,13 +608,15 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
void testCastStringLongerThan1ToCharWithCast() {
shouldFailWithMessages '''
def c = (char) 'aa'
- ''', 'Inconvertible types: cannot cast java.lang.String to char'
+ ''',
+ 'Inconvertible types: cannot cast java.lang.String to char'
}
void testCastNullToCharWithCast() {
shouldFailWithMessages '''
def c = (char) null
- ''', 'Inconvertible types: cannot cast java.lang.Object to char'
+ ''',
+ 'Inconvertible types: cannot cast java.lang.Object to char'
}
void testCastStringToCharacterWithCast() {
@@ -588,7 +628,8 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
void testCastStringLongerThan1ToCharacterWithCast() {
shouldFailWithMessages '''
def c = (Character) 'aa'
- ''', 'Inconvertible types: cannot cast java.lang.String to java.lang.Character'
+ ''',
+ 'Inconvertible types: cannot cast java.lang.String to java.lang.Character'
}
void testCastNullToCharacterWithCast() {
@@ -600,10 +641,7 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
void testCastObjectToSubclass() {
assertScript '''
Object o = null
- try {
- ((Integer)o).intValue()
- } catch (NullPointerException e) {
- }
+ ((Integer) o)?.intValue()
'''
}
@@ -617,7 +655,8 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
x = '123'
}
x.toInteger()
- ''', 'Cannot find matching method java.io.Serializable#toInteger()'
+ ''',
+ 'Cannot find matching method java.io.Serializable#toInteger()'
}
void testIfElseBranchParameter() {
@@ -632,7 +671,8 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
x.toInteger()
}
foo('bar')
- ''', 'Cannot find matching method java.lang.Object#toInteger()'
+ ''',
+ 'Cannot find matching method java.lang.Object#toInteger()'
}
void testIfOnly() {
@@ -643,7 +683,8 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
x = new HashSet()
}
x.toInteger()
- ''', 'Cannot find matching method java.io.Serializable#toInteger()'
+ ''',
+ 'Cannot find matching method java.io.Serializable#toInteger()'
}
void testIfOnlyParameter() {
@@ -657,7 +698,8 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
x.toInteger()
}
foo('123')
- ''', 'Cannot find matching method java.lang.Object#toInteger()'
+ ''',
+ 'Cannot find matching method java.lang.Object#toInteger()'
}
void testIfWithCommonInterface() {
@@ -921,7 +963,8 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
BigInteger a = 333
double b = 2d
BigInteger c = a * b
- ''', 'Cannot assign value of type java.math.BigDecimal to variable of type java.math.BigInteger'
+ ''',
+ 'Cannot assign value of type java.math.BigDecimal to variable of type java.math.BigInteger'
}
void testBigIntegerMultInteger() {
@@ -988,18 +1031,21 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
void setInteger(Character c) { integer = (c as int) }
}
new Pogo().integer++
- ''', 'Cannot assign value of type java.lang.Integer to variable of type java.lang.Character'
+ ''',
+ 'Cannot assign value of type java.lang.Integer to variable of type java.lang.Character'
}
void testPostfixOnObject() {
shouldFailWithMessages '''
Object o = new Object()
o++
- ''', 'Cannot find matching method java.lang.Object#next()'
+ ''',
+ 'Cannot find matching method java.lang.Object#next()'
shouldFailWithMessages '''
Object o = new Object()
o--
- ''', 'Cannot find matching method java.lang.Object#previous()'
+ ''',
+ 'Cannot find matching method java.lang.Object#previous()'
}
void testPrefixOnInt() {
@@ -1028,11 +1074,13 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
Object o = new Object()
++o
- ''', 'Cannot find matching method java.lang.Object#next()'
+ ''',
+ 'Cannot find matching method java.lang.Object#next()'
shouldFailWithMessages '''
Object o = new Object()
--o
- ''', 'Cannot find matching method java.lang.Object#previous()'
+ ''',
+ 'Cannot find matching method java.lang.Object#previous()'
}
void testAssignArray() {
@@ -1053,13 +1101,15 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
String[] src = ['a','b','c']
(Set[]) src
- ''', 'Inconvertible types: cannot cast java.lang.String[] to java.util.Set[]'
+ ''',
+ 'Inconvertible types: cannot cast java.lang.String[] to java.util.Set[]'
}
void testIncompatibleToArray() {
shouldFailWithMessages '''
(Set[]) ['a','b','c'].toArray(new String[3])
- ''', 'Inconvertible types: cannot cast java.lang.String[] to java.util.Set[]'
+ ''',
+ 'Inconvertible types: cannot cast java.lang.String[] to java.util.Set[]'
}
// GROOVY-5535, GROOVY-10623
@@ -1135,7 +1185,8 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
Object o
int[] array = o
- ''', 'Cannot assign value of type java.lang.Object to variable of type int[]'
+ ''',
+ 'Cannot assign value of type java.lang.Object to variable of type int[]'
}
// GROOVY-7015
@@ -1175,19 +1226,19 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
void testIntegerArraySmartType() {
assertScript '''
- def m() {
- def a = 1
- Integer[] b = [a]
- }
+ def m() {
+ def a = 1
+ Integer[] b = [a]
+ }
'''
}
void testIntegerSecondDimArraySmartType() {
assertScript '''
- def m() {
- def a = new int[5]
- int[][] b = [a]
- }
+ def m() {
+ def a = new int[5]
+ int[][] b = [a]
+ }
'''
}