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 5baa8c8 GROOVY-10322: STC: remove hidden generics when checking
method arguments
5baa8c8 is described below
commit 5baa8c8e17fb414d6fbad37835da87a93ede2900
Author: Eric Milles <[email protected]>
AuthorDate: Wed Nov 3 19:35:36 2021 -0500
GROOVY-10322: STC: remove hidden generics when checking method arguments
---
.../transform/stc/StaticTypeCheckingSupport.java | 88 ++---
.../transform/stc/StaticTypeCheckingVisitor.java | 145 ++++----
.../stc/ArraysAndCollectionsSTCTest.groovy | 6 +-
.../stc/DefaultGroovyMethodsSTCTest.groovy | 4 +-
.../groovy/transform/stc/GenericsSTCTest.groovy | 410 +++++++++++----------
5 files changed, 338 insertions(+), 315 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 19e961b..7095e54 100644
---
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -59,6 +59,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
@@ -1060,14 +1061,28 @@ public abstract class StaticTypeCheckingSupport {
Person p = foo(b)
*/
- ClassNode declaringClassForDistance =
candidate.getDeclaringClass();
- ClassNode actualReceiverForDistance = receiver != null ? receiver
: declaringClassForDistance;
- Map<GenericsType, GenericsType> declaringAndActualGenericsTypeMap
=
GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(declaringClassForDistance,
actualReceiverForDistance);
+ ClassNode declaringClass = candidate.getDeclaringClass();
+ ClassNode actualReceiver = receiver != null ? receiver :
declaringClass;
- Parameter[] params = makeRawTypes(safeNode.getParameters(),
declaringAndActualGenericsTypeMap);
+ Map<GenericsType, GenericsType> spec;
+ if (candidate.isStatic()) {
+ spec = Collections.emptyMap(); // none visible
+ } else {
+ spec =
GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(declaringClass,
actualReceiver);
+ GenericsType[] methodGenerics = candidate.getGenericsTypes();
+ if (methodGenerics != null) { // GROOVY-10322: remove hidden
type parameters
+ for (int i = 0, n = methodGenerics.length; i < n &&
!spec.isEmpty(); i += 1) {
+ for (Iterator<GenericsType> it =
spec.keySet().iterator(); it.hasNext(); ) {
+ if
(it.next().getName().equals(methodGenerics[i].getName())) it.remove();
+ }
+ }
+ }
+ }
+
+ Parameter[] params = makeRawTypes(safeNode.getParameters(), spec);
int dist = measureParametersAndArgumentsDistance(params, safeArgs);
if (dist >= 0) {
- dist += getClassDistance(declaringClassForDistance,
actualReceiverForDistance);
+ dist += getClassDistance(declaringClass, actualReceiver);
dist += getExtensionDistance(isExtensionMethod);
if (dist < bestDist) {
bestDist = dist;
@@ -1387,16 +1402,6 @@ public abstract class StaticTypeCheckingSupport {
return true;
}
- static void addMethodLevelDeclaredGenerics(final MethodNode method, final
Map<GenericsTypeName, GenericsType> placeholders) {
- GenericsType[] generics = method.getGenericsTypes();
- if (!method.isStatic() && !placeholders.isEmpty()) {
- // GROOVY-8034: non-static method may use class generics
- generics = applyGenericsContext(placeholders, generics);
- }
- ClassNode dummy = GenericsUtils.makeClassSafe0(OBJECT_TYPE, generics);
- GenericsUtils.extractPlaceholders(dummy, placeholders);
- }
-
protected static boolean typeCheckMethodsWithGenerics(final ClassNode
receiver, final ClassNode[] argumentTypes, final MethodNode candidateMethod) {
if (candidateMethod instanceof ExtensionMethodNode) {
ClassNode[] realTypes = new ClassNode[argumentTypes.length + 1];
@@ -1417,46 +1422,46 @@ public abstract class StaticTypeCheckingSupport {
private static boolean typeCheckMethodsWithGenerics(final ClassNode
receiver, final ClassNode[] argumentTypes, final MethodNode candidateMethod,
final boolean isExtensionMethod) {
Parameter[] parameters = candidateMethod.getParameters();
- if (parameters.length > argumentTypes.length || parameters.length ==
0) {
- // this is a limitation that must be removed in a future version
- // we cannot check generic type arguments if there are default
parameters!
+ if (parameters.length == 0 || parameters.length >
argumentTypes.length) {
+ // this is a limitation that must be removed in a future version;
we
+ // cannot check generic type arguments if there is default
argument!
return true;
}
boolean failure = false;
Set<GenericsTypeName> fixedPlaceHolders = Collections.emptySet();
- Map<GenericsTypeName, GenericsType> resolvedMethodGenerics = new
HashMap<>();
+ Map<GenericsTypeName, GenericsType> candidateGenerics = new
HashMap<>();
// correct receiver for inner class
// we assume the receiver is an instance of the declaring class of the
- // candidate method, but findMethod returns also outer class methods
- // for that receiver. For now we skip receiver based checks in that
case
- // TODO: correct generics for when receiver is to be skipped
+ // candidate method, but findMethod() returns also outer class methods
+ // for that receiver; for now we skip receiver-based checks in that
case
boolean skipBecauseOfInnerClassNotReceiver =
!implementsInterfaceOrIsSubclassOf(receiver,
candidateMethod.getDeclaringClass());
if (!skipBecauseOfInnerClassNotReceiver) {
if (candidateMethod instanceof ConstructorNode) {
- resolvedMethodGenerics =
GenericsUtils.extractPlaceholders(receiver);
- fixedPlaceHolders = new
HashSet<>(resolvedMethodGenerics.keySet());
+ candidateGenerics =
GenericsUtils.extractPlaceholders(receiver);
+ fixedPlaceHolders = new HashSet<>(candidateGenerics.keySet());
} else {
- // we have here different generics contexts we have to deal
with.
- // There is firstly the context given through the class, and
the method.
- // The method context may hide generics given through the
class, but use
- // the non-hidden ones.
- addMethodLevelDeclaredGenerics(candidateMethod,
resolvedMethodGenerics);
- if (!resolvedMethodGenerics.isEmpty()) {
- // first remove hidden generics
- Map<GenericsTypeName, GenericsType> receiverGenerics =
GenericsUtils.extractPlaceholders(receiver);
-
receiverGenerics.keySet().removeAll(resolvedMethodGenerics.keySet());
- // then use the remaining information to refine the method
generics
- applyGenericsConnections(receiverGenerics,
resolvedMethodGenerics);
+ failure = inferenceCheck(fixedPlaceHolders, candidateGenerics,
candidateMethod.getDeclaringClass(), receiver, false);
+
+ GenericsType[] gts = candidateMethod.getGenericsTypes();
+ if (candidateMethod.isStatic()) {
+ candidateGenerics.clear(); // not in scope
+ } else if (gts != null) {
+ // first remove hidden params
+ for (GenericsType gt : gts) {
+ candidateGenerics.remove(new
GenericsTypeName(gt.getName()));
+ }
+ // GROOVY-8034: non-static method may use class generics
+ gts = applyGenericsContext(candidateGenerics, gts);
}
- // and then start our checks with the receiver
- failure = inferenceCheck(fixedPlaceHolders,
resolvedMethodGenerics, candidateMethod.getDeclaringClass(), receiver, false);
+ GenericsUtils.extractPlaceholders(makeClassSafe0(OBJECT_TYPE,
gts), candidateGenerics);
+
// the outside context parts till now define placeholder we
are not allowed to
// generalize, thus we save that for later use...
// extension methods are special, since they set the receiver
as
// first parameter. While we normally allow generalization for
the first
// parameter, in case of an extension method we must not.
- fixedPlaceHolders =
extractResolvedPlaceHolders(resolvedMethodGenerics);
+ fixedPlaceHolders =
extractResolvedPlaceHolders(candidateGenerics);
}
}
@@ -1464,11 +1469,10 @@ public abstract class StaticTypeCheckingSupport {
for (int i = 0, n = argumentTypes.length; i < n; i += 1) {
ClassNode parameterType = parameters[Math.min(i,
lastParamIndex)].getOriginType();
ClassNode argumentType =
StaticTypeCheckingVisitor.wrapTypeIfNecessary(argumentTypes[i]);
- failure |= inferenceCheck(fixedPlaceHolders,
resolvedMethodGenerics, parameterType, argumentType, i >= lastParamIndex);
+ failure |= inferenceCheck(fixedPlaceHolders, candidateGenerics,
parameterType, argumentType, i >= lastParamIndex);
- if (i == 0 && isExtensionMethod) {
- // set real fixed type parameters for extension method
- fixedPlaceHolders =
extractResolvedPlaceHolders(resolvedMethodGenerics);
+ if (i == 0 && isExtensionMethod) { // re-load fixed names for
extension
+ fixedPlaceHolders =
extractResolvedPlaceHolders(candidateGenerics);
}
}
return !failure;
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 a2db17e..35c696b 100644
---
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -260,7 +260,6 @@ import static
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.Linked
import static
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.Matcher_TYPE;
import static
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.NUMBER_OPS;
import static
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.UNKNOWN_PARAMETER_TYPE;
-import static
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.addMethodLevelDeclaredGenerics;
import static
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.allParametersAndArgumentsMatchWithDefaultParams;
import static
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsConnections;
import static
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.applyGenericsContext;
@@ -1008,8 +1007,7 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
Function<MethodNode, ClassNode> setterType = setter -> {
ClassNode type = setter.getParameters()[0].getOriginType();
if (!setter.isStatic() && !(setter instanceof ExtensionMethodNode)
&& GenericsUtils.hasUnresolvedGenerics(type)) {
- Map<GenericsTypeName, GenericsType> spec =
extractPlaceHolders(null, setterInfo.receiverType, setter.getDeclaringClass());
- type = applyGenericsContext(spec, type);
+ type =
applyGenericsContext(extractPlaceHolders(setterInfo.receiverType,
setter.getDeclaringClass()), type);
}
return type;
};
@@ -1867,8 +1865,8 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
}
private void storeWithResolve(ClassNode type, final ClassNode receiver,
final ClassNode declaringClass, final boolean isStatic, final Expression
expressionToStoreOn) {
- if (GenericsUtils.hasUnresolvedGenerics(type)) {
- type =
resolveGenericsWithContext(resolvePlaceHoldersFromDeclaration(receiver,
declaringClass, null, isStatic), type);
+ if (!isStatic && GenericsUtils.hasUnresolvedGenerics(type)) {
+ type = resolveGenericsWithContext(extractPlaceHolders(receiver,
declaringClass), type);
}
if (expressionToStoreOn instanceof PropertyExpression) {
storeInferredTypeForPropertyExpression((PropertyExpression)
expressionToStoreOn, type);
@@ -2906,7 +2904,7 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
}
}
} else if (isSAMType(target.getOriginType())) { // SAM-type coercion
- Map<GenericsTypeName, GenericsType> context = method.isStatic() ?
new HashMap<>() : extractPlaceHolders(null, receiver, getDeclaringClass(method,
arguments));
+ Map<GenericsTypeName, GenericsType> context =
extractPlaceHoldersVisibleToDeclaration(receiver, method, arguments);
GenericsType[] typeParameters = method instanceof ConstructorNode
? method.getDeclaringClass().getGenericsTypes() : applyGenericsContext(context,
method.getGenericsTypes());
if (typeParameters != null) {
@@ -3516,8 +3514,8 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
// GROOVY-7106, GROOVY-7274, GROOVY-8909, GROOVY-8961,
GROOVY-9734, GROOVY-9844, GROOVY-9915, et al.
Parameter[] parameters =
directMethodCallCandidate.getParameters();
if (chosenReceiver.getType().getGenericsTypes() !=
null && !directMethodCallCandidate.isStatic() && !(directMethodCallCandidate
instanceof ExtensionMethodNode)) {
- Map<GenericsTypeName, GenericsType> context =
extractPlaceHolders(null, chosenReceiver.getType(),
getDeclaringClass(directMethodCallCandidate, argumentList));
- parameters = Arrays.stream(parameters).map(param
-> new Parameter(applyGenericsContext(context, param.getType()),
param.getName())).toArray(Parameter[]::new);
+ Map<GenericsTypeName, GenericsType> context =
extractPlaceHoldersVisibleToDeclaration(chosenReceiver.getType(),
directMethodCallCandidate, argumentList);
+ parameters = Arrays.stream(parameters).map(p ->
new Parameter(applyGenericsContext(context, p.getType()),
p.getName())).toArray(Parameter[]::new);
}
resolvePlaceholdersFromImplicitTypeHints(args,
argumentList, parameters);
@@ -4986,13 +4984,11 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
if (vexp.isSuperExpression()) return makeSuper();
Variable variable = vexp.getAccessedVariable();
if (variable instanceof FieldNode) {
- ClassNode fieldType = variable.getOriginType();
- if (isUsingGenericsOrIsArrayUsingGenerics(fieldType)) {
- boolean isStatic = (variable.getModifiers() &
Opcodes.ACC_STATIC) != 0;
- ClassNode thisType =
typeCheckingContext.getEnclosingClassNode(), declType = ((FieldNode)
variable).getDeclaringClass();
- Map<GenericsTypeName, GenericsType> placeholders =
resolvePlaceHoldersFromDeclaration(thisType, declType, null, isStatic);
-
- fieldType = resolveGenericsWithContext(placeholders,
fieldType);
+ FieldNode fieldNode = (FieldNode) variable;
+ ClassNode fieldType = fieldNode.getOriginType();
+ if (!fieldNode.isStatic() &&
GenericsUtils.hasUnresolvedGenerics(fieldType)) {
+ ClassNode declType = fieldNode.getDeclaringClass(),
thisType = typeCheckingContext.getEnclosingClassNode();
+ fieldType =
resolveGenericsWithContext(extractPlaceHolders(thisType, declType), fieldType);
}
return fieldType;
}
@@ -5278,9 +5274,8 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
return inferReturnTypeGenerics(receiver, extension, args,
explicitTypeHints);
}
- // TODO: remove name conflicts from context before applying to method
generics or parameters
Map<GenericsTypeName, GenericsType> context = method.isStatic() ||
method instanceof ConstructorNode
- ? null : extractPlaceHolders(null,
receiver, getDeclaringClass(method, arguments));
+ ? null :
extractPlaceHoldersVisibleToDeclaration(receiver, method, arguments);
GenericsType[] methodGenericTypes = method instanceof ConstructorNode
? method.getDeclaringClass().getGenericsTypes() : applyGenericsContext(context,
method.getGenericsTypes());
// 1) resolve type parameters of method
@@ -5590,21 +5585,6 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
return getInferredTypeFromTempInfo(expression, declaredOrInferred);
}
- private static ClassNode getDeclaringClass(final MethodNode method, final
Expression arguments) {
- ClassNode declaringClass = method.getDeclaringClass();
-
- // correcting declaring class for extension methods:
- if (arguments instanceof ArgumentListExpression) {
- ArgumentListExpression al = (ArgumentListExpression) arguments;
- List<Expression> list = al.getExpressions();
- if (list.isEmpty()) return declaringClass;
- Expression exp = list.get(0);
- ClassNode cn =
exp.getNodeMetaData(ExtensionMethodDeclaringClass.class);
- if (cn != null) return cn;
- }
- return declaringClass;
- }
-
private static class ExtensionMethodDeclaringClass {
}
@@ -5629,64 +5609,45 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
return cn.isGenericsPlaceHolder();
}
- private static Map<GenericsTypeName, GenericsType>
resolvePlaceHoldersFromDeclaration(final ClassNode receiver, final ClassNode
declaration, final MethodNode method, final boolean isStaticTarget) {
- Map<GenericsTypeName, GenericsType> resolvedPlaceholders;
- if (isStaticTarget
- && isClassType(receiver)
- && receiver.getGenericsTypes() != null
- && receiver.getGenericsTypes().length > 0
- && !isObjectType(receiver.getGenericsTypes()[0].getType())) {
- return
resolvePlaceHoldersFromDeclaration(receiver.getGenericsTypes()[0].getType(),
declaration, method, isStaticTarget);
- } else {
- resolvedPlaceholders = extractPlaceHolders(method, receiver,
declaration);
- }
- return resolvedPlaceholders;
- }
-
- private static Map<GenericsTypeName, GenericsType>
extractPlaceHolders(final MethodNode method, ClassNode receiver, final
ClassNode declaringClass) {
- Map<GenericsTypeName, GenericsType> resolvedPlaceHolders = null;
- if (isPrimitiveType(receiver) && !isPrimitiveType(declaringClass)) {
- receiver = getWrapper(receiver);
- }
+ private static Map<GenericsTypeName, GenericsType>
extractPlaceHolders(final ClassNode receiver, final ClassNode declaringClass) {
+ Map<GenericsTypeName, GenericsType> result = null;
ClassNode[] todo;
if (receiver instanceof UnionTypeClassNode) {
todo = ((UnionTypeClassNode) receiver).getDelegates();
} else {
- todo = new ClassNode[] {receiver};
+ todo = new ClassNode[] {!isPrimitiveType(declaringClass) ?
wrapTypeIfNecessary(receiver) : receiver};
}
for (ClassNode type : todo) {
ClassNode current = type;
while (current != null) {
- Map<GenericsTypeName, GenericsType> currentPlaceHolders = new
HashMap<>();
+ Map<GenericsTypeName, GenericsType> placeHolders = new
HashMap<>();
// GROOVY-10055: handle diamond or raw
if (current.getGenericsTypes() != null
? current.getGenericsTypes().length == 0
: current.redirect().getGenericsTypes() != null) {
for (GenericsType gt :
current.redirect().getGenericsTypes()) {
ClassNode cn = gt.getUpperBounds() != null ?
gt.getUpperBounds()[0] : gt.getType().redirect();
- currentPlaceHolders.put(new
GenericsTypeName(gt.getName()), cn.getPlainNodeReference().asGenericsType());
+ placeHolders.put(new GenericsTypeName(gt.getName()),
cn.getPlainNodeReference().asGenericsType());
}
}
boolean currentIsDeclaring = current.equals(declaringClass) ||
isGenericsPlaceHolderOrArrayOf(declaringClass);
if (currentIsDeclaring) {
- extractGenericsConnections(currentPlaceHolders, current,
declaringClass);
- if (method != null)
- addMethodLevelDeclaredGenerics(method,
currentPlaceHolders);
+ extractGenericsConnections(placeHolders, current,
declaringClass);
} else {
- GenericsUtils.extractPlaceholders(current,
currentPlaceHolders);
+ GenericsUtils.extractPlaceholders(current, placeHolders);
}
- if (resolvedPlaceHolders != null) { // merge maps
- for (Map.Entry<GenericsTypeName, GenericsType> entry :
currentPlaceHolders.entrySet()) {
+ if (result != null) { // merge maps
+ for (Map.Entry<GenericsTypeName, GenericsType> entry :
placeHolders.entrySet()) {
GenericsType gt = entry.getValue();
if (!gt.isPlaceholder()) continue;
- GenericsType referenced = resolvedPlaceHolders.get(new
GenericsTypeName(gt.getName()));
+ GenericsType referenced = result.get(new
GenericsTypeName(gt.getName()));
if (referenced == null) continue;
entry.setValue(referenced);
}
}
- resolvedPlaceHolders = currentPlaceHolders;
+ result = placeHolders;
// we are done if we are now in the declaring class
if (currentIsDeclaring) break;
@@ -5697,42 +5658,68 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
// the actual receiver is Foo and declaringClass is Class
current = declaringClass;
} else {
- current = applyGenericsContext(currentPlaceHolders,
current);
+ current = applyGenericsContext(placeHolders, current);
}
}
}
- if (resolvedPlaceHolders == null) {
- throw new GroovyBugError("Declaring class for method call to '" +
(method != null ? method.getTypeDescriptor() : "<>") +
- "' declared in " + declaringClass.getName() + " was not
matched with found receiver " + receiver.getName() + ". This should not have
happened!");
+ if (result == null) {
+ throw new GroovyBugError("Declaring class " +
prettyPrintTypeName(declaringClass) + " was not matched with receiver " +
prettyPrintTypeName(receiver) + ". This should not have happened!");
}
- return resolvedPlaceHolders;
+ return result;
+ }
+
+ private static Map<GenericsTypeName, GenericsType>
extractPlaceHoldersVisibleToDeclaration(final ClassNode receiver, final
MethodNode method, final Expression argument) {
+ Map<GenericsTypeName, GenericsType> result;
+ if (method.isStatic()) {
+ result = new HashMap<>();
+ } else {
+ ClassNode declaring = method.getDeclaringClass();
+ if (argument instanceof ArgumentListExpression) { // resolve
extension method class
+ List<Expression> arguments = ((ArgumentListExpression)
argument).getExpressions();
+ if (!arguments.isEmpty()) {
+ ClassNode cn =
arguments.get(0).getNodeMetaData(ExtensionMethodDeclaringClass.class);
+ if (cn != null)
+ declaring = cn;
+ }
+ }
+ result = extractPlaceHolders(receiver, declaring);
+ if (!result.isEmpty())
Optional.ofNullable(method.getGenericsTypes()).ifPresent(methodGenerics ->
+ Arrays.stream(methodGenerics).map(gt -> new
GenericsTypeName(gt.getName())).forEach(result::remove)); // GROOVY-10322
+ }
+ return result;
}
protected boolean typeCheckMethodsWithGenericsOrFail(final ClassNode
receiver, final ClassNode[] arguments, final MethodNode candidateMethod, final
Expression location) {
if (!typeCheckMethodsWithGenerics(receiver, arguments,
candidateMethod)) {
- Map<GenericsTypeName, GenericsType> generics =
GenericsUtils.extractPlaceholders(receiver);
-
applyGenericsConnections(extractGenericsParameterMapOfThis(typeCheckingContext),
generics);
- addMethodLevelDeclaredGenerics(candidateMethod, generics);
- Parameter[] parameters = candidateMethod.getParameters();
+ ClassNode r = receiver, at[] = arguments; MethodNode m =
candidateMethod;
+ if (candidateMethod instanceof ExtensionMethodNode) {
+ m = ((ExtensionMethodNode)
candidateMethod).getExtensionMethodNode();
+ r = m.getDeclaringClass();
+ at = new ClassNode[arguments.length + 1];
+ at[0] = receiver; // object expression is first argument
+ System.arraycopy(arguments, 0, at, 1, arguments.length);
+ }
+ Map<GenericsTypeName, GenericsType> spec =
extractPlaceHoldersVisibleToDeclaration(r, m, null);
+ GenericsType[] gt = applyGenericsContext(spec,
m.getGenericsTypes()); // class params in bounds
+ GenericsUtils.extractPlaceholders(makeClassSafe0(OBJECT_TYPE, gt),
spec);
+
+ Parameter[] parameters = m.getParameters();
ClassNode[] paramTypes = new ClassNode[parameters.length];
for (int i = 0, n = parameters.length; i < n; i += 1) {
- paramTypes[i] = fullyResolveType(parameters[i].getType(),
generics);
+ paramTypes[i] = fullyResolveType(parameters[i].getType(),
spec);
// GROOVY-10010: check for List<String> parameter and
["foo","$bar"] argument
- if (i < arguments.length &&
hasGStringStringError(paramTypes[i], arguments[i], location)) {
+ if (i < at.length && hasGStringStringError(paramTypes[i],
at[i], location)) {
return false;
}
}
- addStaticTypeError("Cannot call " +
toMethodGenericTypesString(candidateMethod) + prettyPrintTypeName(receiver) +
"#" +
- toMethodParametersString(candidateMethod.getName(),
paramTypes) + " with arguments " + formatArgumentList(arguments), location);
+
+ addStaticTypeError("Cannot call " +
Optional.ofNullable(gt).map(GenericsUtils::toGenericTypesString).orElse("") +
+ prettyPrintTypeName(r) + "#" +
toMethodParametersString(m.getName(), paramTypes) + " with arguments " +
formatArgumentList(at), location);
return false;
}
return true;
}
- private static String toMethodGenericTypesString(final MethodNode node) {
- return
Optional.ofNullable(node.getGenericsTypes()).map(GenericsUtils::toGenericTypesString).orElse("");
- }
-
protected static String formatArgumentList(final ClassNode[] nodes) {
if (nodes == null || nodes.length == 0) return "[]";
diff --git a/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
b/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
index f375092..8de032e 100644
--- a/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
@@ -583,7 +583,8 @@ class ArraysAndCollectionsSTCTest extends
StaticTypeCheckingTestCase {
shouldFailWithMessages '''
String[] arr = ['abc']
arr.putAt(0, new Object())
- ''', 'Cannot call <T,U extends T> java.lang.String[]#putAt(int, U)
with arguments [int, java.lang.Object]'
+ ''',
+ '#putAt(T[], int, U) with arguments [java.lang.String[], int,
java.lang.Object]'
}
void testStringArrayPutWithSubType() {
@@ -604,7 +605,8 @@ class ArraysAndCollectionsSTCTest extends
StaticTypeCheckingTestCase {
shouldFailWithMessages '''
Serializable[] arr = ['abc']
arr.putAt(0, new groovy.xml.XmlSlurper())
- ''', 'Cannot call <T,U extends T> java.io.Serializable[]#putAt(int, U)
with arguments [int, groovy.xml.XmlSlurper]'
+ ''',
+ '#putAt(T[], int, U) with arguments [java.io.Serializable[], int,
groovy.xml.XmlSlurper]'
}
void testArrayGetOnPrimitiveArray() {
diff --git a/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
b/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
index 6192bba..5b2a702 100644
--- a/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
@@ -114,8 +114,8 @@ class DefaultGroovyMethodsSTCTest extends
StaticTypeCheckingTestCase {
numbers.sequence
numbers.string
''',
- 'Cannot call <CS extends java.lang.CharSequence>
java.util.ArrayList#getSequence() with arguments []',
- 'Cannot call java.util.ArrayList#getString() with arguments []',
+ '#getSequence(java.util.List<CS extends java.lang.CharSequence>) with
arguments [java.util.ArrayList<java.lang.Number>]',
+ '#getString(java.util.List<java.lang.String>) with arguments
[java.util.ArrayList<java.lang.Number>]',
'No such property: sequence for class: java.util.ArrayList',
'No such property: string for class: java.util.ArrayList'
}
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 0669a23..1a8d7fd 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -41,21 +41,24 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
void testDeclaration3() {
shouldFailWithMessages '''
Map<String,String> obj = new HashMap<String,Integer>()
- ''', 'Incompatible generic argument types. Cannot assign
java.util.HashMap<java.lang.String, java.lang.Integer> to:
java.util.Map<java.lang.String, java.lang.String>'
+ ''',
+ 'Incompatible generic argument types. Cannot assign
java.util.HashMap<java.lang.String, java.lang.Integer> to:
java.util.Map<java.lang.String, java.lang.String>'
}
void testDeclaration4() {
// no generics checked after first wildcard
shouldFailWithMessages '''
Map<? extends CharSequence,String> obj = new
HashMap<String,Integer>()
- ''', 'Incompatible generic argument types. Cannot assign
java.util.HashMap<java.lang.String, java.lang.Integer> to: java.util.Map<?
extends java.lang.CharSequence, java.lang.String>'
+ ''',
+ 'Incompatible generic argument types. Cannot assign
java.util.HashMap<java.lang.String, java.lang.Integer> to: java.util.Map<?
extends java.lang.CharSequence, java.lang.String>'
}
void testAddOnList() {
shouldFailWithMessages '''
List<String> list = []
list.add(1)
- ''', "[Static type checking] - Cannot find matching method
java.util.ArrayList#add(int)"
+ ''',
+ 'Cannot find matching method java.util.ArrayList#add(int)'
}
void testAddOnList2() {
@@ -81,7 +84,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
List<String> list = []
list << 1
- ''', 'Cannot call <T> java.util.ArrayList#leftShift(T) with arguments
[int]'
+ ''',
+ 'Cannot call <T>
org.codehaus.groovy.runtime.DefaultGroovyMethods#leftShift(java.util.List<T>,
T) with arguments [java.util.ArrayList<java.lang.String>, int]'
}
void testAddOnList2UsingLeftShift() {
@@ -129,14 +133,16 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
List<Integer> list = new LinkedList<>()
list.add 'Hello'
- ''', 'Cannot find matching method
java.util.LinkedList#add(java.lang.String). Please check if the declared type
is correct and if the method exists.'
+ ''',
+ 'Cannot find matching method
java.util.LinkedList#add(java.lang.String). Please check if the declared type
is correct and if the method exists.'
}
void testAddOnListWithDiamondAndWrongTypeUsingLeftShift() {
shouldFailWithMessages '''
List<Integer> list = new LinkedList<>()
list << 'Hello'
- ''', 'Cannot call <T> java.util.LinkedList#leftShift(T) with arguments
[java.lang.String]'
+ ''',
+ 'Cannot call <T>
org.codehaus.groovy.runtime.DefaultGroovyMethods#leftShift(java.util.List<T>,
T) with arguments [java.util.LinkedList<java.lang.Integer>, java.lang.String]'
}
void testAddOnListWithDiamondAndNullUsingLeftShift() {
@@ -234,7 +240,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
Number number = Optional.of(42).orElse(Double.NaN)
assert number.intValue() == 42
- ''', '[Static type checking] - Cannot find matching method
java.util.Optional#orElse(double).'
+ ''',
+ 'Cannot find matching method java.util.Optional#orElse(double).'
}
void testReturnTypeInferenceWithMethodGenerics5() {
@@ -249,7 +256,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
Number number = Optional.ofNullable((Integer) null).orElse(42d)
assert number.intValue() == 42
- ''', '[Static type checking] - Cannot find matching method
java.util.Optional#orElse(double).'
+ ''',
+ 'Cannot find matching method java.util.Optional#orElse(double).'
}
void testReturnTypeInferenceWithMethodGenerics7() {
@@ -267,7 +275,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
x.add(new Object())
return x // List<E>
}
- ''', 'Incompatible generic argument types.' // Cannot assign
java.util.List<java.lang.Object> to: java.util.List<java.lang.String>
+ ''',
+ 'Incompatible generic argument types.' // Cannot assign
java.util.List<java.lang.Object> to: java.util.List<java.lang.String>
assertScript '''
@ASTTest(phase=INSTRUCTION_SELECTION, value={
@@ -738,11 +747,13 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
class D implements I { }
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<java.lang.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<java.lang.Number>> to:
java.util.Set<java.util.List<java.lang.String>>'
}
// GROOVY-9972
@@ -831,7 +842,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
def foo = { flag, C<D> cd = (flag ? new C<>(new D()) : new C<>(new
Object())) ->
cd.p.f.toLowerCase()
}
- ''', 'Incompatible generic argument types. Cannot assign C<? extends
java.lang.Object> to: C<D>'
+ ''',
+ 'Incompatible generic argument types. Cannot assign C<? extends
java.lang.Object> to: C<D>'
}
// GROOVY-9963
@@ -1102,7 +1114,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
void testLinkedListWithListArgumentAndWrongElementTypes() {
shouldFailWithMessages '''
List<String> list = new LinkedList<String>([1,2,3])
- ''', 'Cannot call java.util.LinkedList#<init>(java.util.Collection<?
extends java.lang.String>) with arguments [java.util.List<java.lang.Integer>]'
+ ''',
+ 'Cannot call java.util.LinkedList#<init>(java.util.Collection<?
extends java.lang.String>) with arguments [java.util.List<java.lang.Integer>]'
}
void testGenericAssignmentWithSubClass() {
@@ -1114,7 +1127,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
void testGenericAssignmentWithSubClassAndWrongGenericType() {
shouldFailWithMessages '''
List<Integer> list = new
groovy.transform.stc.GenericsSTCTest.MyList()
- ''', 'Incompatible generic argument types'
+ ''',
+ 'Incompatible generic argument types'
}
void testAddShouldBeAllowedOnUncheckedGenerics() {
@@ -1130,7 +1144,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
void testAssignmentShouldFailBecauseOfLowerBound() {
shouldFailWithMessages '''
List<? super Number> list = ['string']
- ''', 'Number'
+ ''',
+ 'Cannot assign java.util.ArrayList<java.lang.String> to:
java.util.List<? super java.lang.Number>'
}
// GROOVY-9914, GROOVY-10036
@@ -1292,7 +1307,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
class FooBound {
}
new Foo()
- ''', 'Cannot find matching method
FooWithGenerics#say(java.lang.Object)'
+ ''',
+ 'Cannot find matching method FooWithGenerics#say(java.lang.Object)'
}
// GROOVY-5237
@@ -1414,7 +1430,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
A<String, Integer> a = new B()
a.test()
- ''', 'Cannot call A#<init>(java.lang.Class<java.lang.String>,
java.lang.Class<java.lang.Integer>) with arguments
[java.lang.Class<java.lang.Integer>, java.lang.Class<java.lang.String>]'
+ ''',
+ 'Cannot call A#<init>(java.lang.Class<java.lang.String>,
java.lang.Class<java.lang.Integer>) with arguments
[java.lang.Class<java.lang.Integer>, java.lang.Class<java.lang.String>]'
}
// GROOVY-9460
@@ -1486,7 +1503,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
def map = new HashMap<String, Integer>()
map['hello'] = new Object()
''',
- 'Cannot call <K,V> java.util.HashMap#putAt(java.lang.String,
java.lang.Integer) with arguments [java.lang.String, java.lang.Object]'
+ 'Cannot call <K,V>
org.codehaus.groovy.runtime.DefaultGroovyMethods#putAt(java.util.Map<K, V>, K,
V) with arguments [java.util.HashMap<java.lang.String, java.lang.Integer>,
java.lang.String, java.lang.Object]'
}
// GROOVY-9069
@@ -1496,15 +1513,14 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
}
void test(Map<String, Map<String, List<String>>> maps) {
maps.each { String key, Map<String, List<String>> map ->
- Map<String, List<ConfigAttribute>> value = [:] // Why
"List<ConfigAttribute>"?
- // populate value
- maps[key] = value
+ Map<String, List<ConfigAttribute>> value = [:]
maps.put(key, value)
+ maps[key] = value
}
}
''',
- 'Cannot call <K,V> java.util.Map#putAt(java.lang.String,
java.util.Map<java.lang.String, java.util.List<java.lang.String>>) with
arguments [java.lang.String, java.util.LinkedHashMap<java.lang.String,
java.util.List<ConfigAttribute>>]',
- 'Cannot find matching method java.util.Map#put(java.lang.String,
java.util.LinkedHashMap<java.lang.String, java.util.List<ConfigAttribute>>).
Please check if the declared type is correct and if the method exists.'
+ 'Cannot find matching method java.util.Map#put(java.lang.String,
java.util.LinkedHashMap<java.lang.String, java.util.List<ConfigAttribute>>).
Please check if the declared type is correct and if the method exists.',
+ 'Cannot call <K,V>
org.codehaus.groovy.runtime.DefaultGroovyMethods#putAt(java.util.Map<K, V>, K,
V) with arguments [java.util.Map<java.lang.String,
java.util.Map<java.lang.String, java.util.List<java.lang.String>>>,
java.lang.String, java.util.LinkedHashMap<java.lang.String,
java.util.List<ConfigAttribute>>]'
}
void testPutAtMethodWithWrongValueType3() {
@@ -1521,7 +1537,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
void testShouldComplainAboutToInteger() {
- String code = '''
+ shouldFailWithMessages '''
class Test {
static test2() {
if (new Random().nextBoolean()) {
@@ -1542,11 +1558,9 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase
{
}
}
new Test()
- '''
-
- shouldFailWithMessages code,
- 'Cannot find matching method java.lang.Object#getAt(int)',
- 'Cannot find matching method java.lang.Object#toInteger()'
+ ''',
+ 'Cannot find matching method java.lang.Object#getAt(int)',
+ 'Cannot find matching method java.lang.Object#toInteger()'
}
void testAssignmentOfNewInstance() {
@@ -1586,7 +1600,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
}
new ClassB()
- ''', 'Cannot call <X>
groovy.transform.stc.GenericsSTCTest$ClassA#bar(java.lang.Class<java.lang.Long>)
with arguments [java.lang.Class<? extends java.lang.Object>]'
+ ''',
+ 'Cannot call <X>
groovy.transform.stc.GenericsSTCTest$ClassA#bar(java.lang.Class<java.lang.Long>)
with arguments [java.lang.Class<? extends java.lang.Object>]'
}
// GROOVY-8961, GROOVY-9915
@@ -1623,7 +1638,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
void test() {
x = Collections.<Integer>emptyList()
}
- """, 'Incompatible generic argument types. Cannot assign
java.util.List<java.lang.Integer> to: java.util.List<java.lang.String>'
+ """,
+ 'Incompatible generic argument types. Cannot assign
java.util.List<java.lang.Integer> to: java.util.List<java.lang.String>'
}
}
@@ -1893,7 +1909,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
List<String> list = ['a','b','c']
Collection<Integer> numbers = (Collection<Integer>) [1,2,3]
boolean r = list.addAll(numbers)
- ''', 'Cannot call java.util.ArrayList#addAll(java.util.Collection<?
extends java.lang.String>) with arguments
[java.util.Collection<java.lang.Integer>]'
+ ''',
+ 'Cannot call java.util.ArrayList#addAll(java.util.Collection<? extends
java.lang.String>) with arguments [java.util.Collection<java.lang.Integer>]'
}
// GROOVY-5528
@@ -1924,7 +1941,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
assert
node.getNodeMetaData(INFERRED_TYPE).genericsTypes[0].type instanceof LUB
})
List<String> list = ["foo", "$bar"]
- ''', 'You are trying to use a GString in place of a String'
+ ''',
+ 'You are trying to use a GString in place of a String'
shouldFailWithMessages base + '''
@ASTTest(phase=INSTRUCTION_SELECTION, value={
@@ -1932,12 +1950,14 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
assert
node.getNodeMetaData(INFERRED_TYPE).genericsTypes[0].type == GSTRING_TYPE //
single element means no LUB
})
List<String> list = ["$bar"]
- ''', 'You are trying to use a GString in place of a String'
+ ''',
+ 'You are trying to use a GString in place of a String'
shouldFailWithMessages base + '''
void m(List<String> list) {}
m(["foo", "$bar"])
- ''', 'You are trying to use a GString in place of a String'
+ ''',
+ 'You are trying to use a GString in place of a String'
}
// GROOVY-5559, GROOVY-10010
@@ -1946,17 +1966,20 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
shouldFailWithMessages base + '''
Map<String,String> map = [x:"foo", y:"$bar"]
- ''', 'You are trying to use a GString in place of a String'
+ ''',
+ 'You are trying to use a GString in place of a String'
shouldFailWithMessages base + '''
void m(Map<?,String> map) {}
m([x:"foo", y:"$bar"])
- ''', 'You are trying to use a GString in place of a String'
+ ''',
+ 'You are trying to use a GString in place of a String'
shouldFailWithMessages base + '''
void m(Map<?,String> map) {}
m(x:"foo", y:"$bar")
- ''', 'You are trying to use a GString in place of a String'
+ ''',
+ 'You are trying to use a GString in place of a String'
}
// GROOVY-5559: related behaviour
@@ -2068,7 +2091,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
void testInferDiamondUsingAIC() {
shouldFailWithMessages '''
Map<String,Date> map = new HashMap<>() {}
- ''', 'Cannot use diamond <> with anonymous inner classes'
+ ''',
+ 'Cannot use diamond <> with anonymous inner classes'
}
// GROOVY-5614
@@ -2155,7 +2179,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
})
Map<Date, Date> map = new HashMap<>()
map.put('foo', new Date())
- ''', '[Static type checking] - Cannot find matching method
java.util.HashMap#put(java.lang.String, java.util.Date). Please check if the
declared type is correct and if the method exists.'
+ ''',
+ 'Cannot find matching method java.util.HashMap#put(java.lang.String,
java.util.Date). Please check if the declared type is correct and if the method
exists.'
}
void
testInferDiamondForAssignmentWithDatesAndIllegalKeyUsingSquareBracket() {
shouldFailWithMessages '''
@@ -2174,7 +2199,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
})
Map<Date, Date> map = new HashMap<>()
map['foo'] = new Date()
- ''', 'Cannot call <K,V> java.util.HashMap#putAt(java.util.Date,
java.util.Date) with arguments [java.lang.String, java.util.Date]'
+ ''',
+ 'Cannot call <K,V>
org.codehaus.groovy.runtime.DefaultGroovyMethods#putAt(java.util.Map<K, V>, K,
V) with arguments [java.util.HashMap<java.util.Date, java.util.Date>,
java.lang.String, java.util.Date]'
}
void testInferDiamondForAssignmentWithDatesAndIllegalValueUsingPut() {
shouldFailWithMessages '''
@@ -2193,7 +2219,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
})
Map<Date, Date> map = new HashMap<>()
map.put(new Date(), 'foo')
- ''', '[Static type checking] - Cannot find matching method
java.util.HashMap#put(java.util.Date, java.lang.String). Please check if the
declared type is correct and if the method exists.'
+ ''',
+ 'Cannot find matching method java.util.HashMap#put(java.util.Date,
java.lang.String). Please check if the declared type is correct and if the
method exists.'
}
void
testInferDiamondForAssignmentWithDatesAndIllegalValueUsingSquareBracket() {
shouldFailWithMessages '''
@@ -2212,21 +2239,22 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
})
Map<Date, Date> map = new HashMap<>()
map[new Date()] = 'foo'
- ''', 'Cannot call <K,V> java.util.HashMap#putAt(java.util.Date,
java.util.Date) with arguments [java.util.Date, java.lang.String]'
+ ''',
+ 'Cannot call <K,V>
org.codehaus.groovy.runtime.DefaultGroovyMethods#putAt(java.util.Map<K, V>, K,
V) with arguments [java.util.HashMap<java.util.Date, java.util.Date>,
java.util.Date, java.lang.String]'
}
void testCallMethodWithParameterizedArrayList() {
assertScript '''
- class MyUtility {
- def methodOne() {
- def someFiles = new ArrayList<File>()
- def someString = ''
- methodTwo someString, someFiles
- }
+ class MyUtility {
+ def methodOne() {
+ def someFiles = new ArrayList<File>()
+ def someString = ''
+ methodTwo someString, someFiles
+ }
- def methodTwo(String s, List<File> files) {}
- }
- new MyUtility()
+ def methodTwo(String s, List<File> files) {}
+ }
+ new MyUtility()
'''
}
@@ -2240,35 +2268,35 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
// GROOVY-5617
void testIntermediateListAssignmentOfGStrings() {
assertScript '''
- def test() {
- @ASTTest(phase=INSTRUCTION_SELECTION, value={
- def type = node.getNodeMetaData(INFERRED_TYPE)
- assert type.implementsInterface(LIST_TYPE)
- assert type.genericsTypes.length == 1
- assert type.genericsTypes[0].type == GSTRING_TYPE
- })
- List<GString> dates = ["${new Date()-1}", "${new Date()}", "${new
Date()+1}"]
- dates*.toUpperCase()
- @ASTTest(phase=INSTRUCTION_SELECTION, value={
- def type = node.getNodeMetaData(INFERRED_TYPE)
- assert type.implementsInterface(LIST_TYPE)
- assert type.genericsTypes.length == 1
- assert type.genericsTypes[0].type == GSTRING_TYPE
- })
- List<GString> copied = []
- copied.addAll(dates)
- List<String> upper = copied*.toUpperCase()
- }
- test()
+ def test() {
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type.implementsInterface(LIST_TYPE)
+ assert type.genericsTypes.length == 1
+ assert type.genericsTypes[0].type == GSTRING_TYPE
+ })
+ List<GString> dates = ["${new Date()-1}", "${new Date()}",
"${new Date()+1}"]
+ dates*.toUpperCase()
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type.implementsInterface(LIST_TYPE)
+ assert type.genericsTypes.length == 1
+ assert type.genericsTypes[0].type == GSTRING_TYPE
+ })
+ List<GString> copied = []
+ copied.addAll(dates)
+ List<String> upper = copied*.toUpperCase()
+ }
+ test()
'''
}
// GROOVY-5650
void testRegressionInGenericsTypeInference() {
assertScript '''import
groovy.transform.stc.GenericsSTCTest.JavaClassSupport as JavaClass
- List<JavaClass.StringContainer> containers = new ArrayList<>();
- containers.add(new JavaClass.StringContainer());
- List<String> strings = JavaClass.unwrap(containers);
+ List<JavaClass.StringContainer> containers = new ArrayList<>();
+ containers.add(new JavaClass.StringContainer());
+ List<String> strings = JavaClass.unwrap(containers);
'''
}
@@ -2544,14 +2572,14 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
// GROOVY-5735
void testCorrespondingParameterType() {
assertScript '''
- public <T> void someMethod (java.lang.Class<T> clazz, T object) {}
+ public <T> void someMethod (java.lang.Class<T> clazz, T object) {}
- void method() {
- List<String> list = null
- someMethod(java.util.List.class, list)
- }
+ void method() {
+ List<String> list = null
+ someMethod(java.util.List.class, list)
+ }
- method()
+ method()
'''
}
@@ -2696,7 +2724,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
static <T extends List<? extends CharSequence>> void bar(T a)
{}
}
Foo.bar([new Object()])
- ''', 'Cannot call <T extends java.util.List<? extends
java.lang.CharSequence>> Foo#bar(T) with arguments
[java.util.ArrayList<java.lang.Object>]'
+ ''',
+ 'Cannot call <T extends java.util.List<? extends
java.lang.CharSequence>> Foo#bar(T) with arguments
[java.util.ArrayList<java.lang.Object>]'
}
void testOutOfBoundsBySuperGenericParameterType() {
@@ -2705,7 +2734,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
static <T extends List<? super CharSequence>> void bar(T a) {}
}
Foo.bar(['abc'])
- ''', 'Cannot call <T extends java.util.List<? super
java.lang.CharSequence>> Foo#bar(T) with arguments
[java.util.ArrayList<java.lang.String>]'
+ ''',
+ 'Cannot call <T extends java.util.List<? super
java.lang.CharSequence>> Foo#bar(T) with arguments
[java.util.ArrayList<java.lang.String>]'
}
void testOutOfBoundsByExtendsPlaceholderParameterType() {
@@ -2716,7 +2746,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
def <U extends List<Object>> void baz(U list) {
Foo.bar(list)
}
- ''', 'Cannot call <T extends java.util.List<? extends
java.lang.CharSequence>> Foo#bar(T) with arguments [U]'
+ ''',
+ 'Cannot call <T extends java.util.List<? extends
java.lang.CharSequence>> Foo#bar(T) with arguments [U]'
}
void testOutOfBoundsBySuperPlaceholderParameterType() {
@@ -2727,37 +2758,37 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
def <U extends List<String>> void baz(U list) {
Foo.bar(list)
}
- ''', 'Cannot call <T extends java.util.List<? super
java.lang.CharSequence>> Foo#bar(T) with arguments [U]'
+ ''',
+ 'Cannot call <T extends java.util.List<? super
java.lang.CharSequence>> Foo#bar(T) with arguments [U]'
}
// GROOVY-5721
void testExtractComponentTypeFromSubclass() {
assertScript '''
- class MyList extends ArrayList<Double> {}
+ class MyList extends ArrayList<Double> {}
- List<Double> list1 = new ArrayList<Double>()
- list1 << 0.0d
+ List<Double> list1 = new ArrayList<Double>()
+ list1 << 0.0d
- // OK
- Double d1 = list1.get(0)
+ // OK
+ Double d1 = list1.get(0)
- //---------------------------
+ //---------------------------
- List<Double> list2 = new MyList()
- list2 << 0.0d
+ List<Double> list2 = new MyList()
+ list2 << 0.0d
- //Groovyc: [Static type checking] - Cannot assign value of type
java.lang.Object to variable of type java.lang.Double
- Double d2 = list2.get(0)
+ //Groovyc: [Static type checking] - Cannot assign value of type
java.lang.Object to variable of type java.lang.Double
+ Double d2 = list2.get(0)
- //---------------------------
+ //---------------------------
- MyList list3 = new MyList()
- list3 << 0.0d
+ MyList list3 = new MyList()
+ list3 << 0.0d
- //Groovyc: [Static type checking] - Cannot assign value of type
java.lang.Object to variable of type java.lang.Double
- Double d3 = list3.get(0)
+ //Groovyc: [Static type checking] - Cannot assign value of type
java.lang.Object to variable of type java.lang.Double
+ Double d3 = list3.get(0)
'''
-
}
// GROOVY-5724
@@ -2884,9 +2915,22 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase
{
'''
}
- // GROOVY-10337
+ // GROOVY-10322
void testShouldFindMethodEvenWithRepeatNames4() {
assertScript '''
+ class C<T> {
+ def <T> T m(T t) { // this T hides T from C<T>
+ return t
+ }
+ }
+ int x = new C<String>().m(1) // no error, param and return types
are `int` not `String`
+ assert x == 1
+ '''
+ }
+
+ // GROOVY-10337
+ void testShouldFindMethodEvenWithRepeatNames5() {
+ assertScript '''
class C<X,Y> {
C(C<Y,? extends Y> that) {
}
@@ -3041,62 +3085,55 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
// GROOVY-6051
void testGenericsReturnTypeInferenceShouldNotThrowNPE() {
assertScript '''
- class Bar {
- public static List<Date> bar(List<Date> dummy) {}
- }
- class Foo extends Bar {
- static public Date genericItem() {
- @ASTTest(phase=INSTRUCTION_SELECTION, value={
- def inft = node.getNodeMetaData(INFERRED_TYPE)
- assert inft == make(List)
- assert inft.genericsTypes[0].type == make(Date)
- })
- def res = bar(null)
+ class Bar {
+ public static List<Date> bar(List<Date> dummy) {}
+ }
+ class Foo extends Bar {
+ static public Date genericItem() {
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ def inft = node.getNodeMetaData(INFERRED_TYPE)
+ assert inft == make(List)
+ assert inft.genericsTypes[0].type == make(Date)
+ })
+ def res = bar(null)
- res[0]
+ res[0]
+ }
}
- }
- new Foo()
+ new Foo()
'''
}
// GROOVY-6035
void testReturnTypeInferenceWithClosure() {
assertScript '''import org.codehaus.groovy.ast.expr.ClosureExpression
- class CTypeTest {
-
- public static void test1(String[] args) {
-
- // Cannot assign value of type java.lang.Object to variable of
type CTypeTest
- @ASTTest(phase=INSTRUCTION_SELECTION,value={
- def cl = node.rightExpression.arguments[0]
- assert cl instanceof ClosureExpression
- def type = cl.getNodeMetaData(INFERRED_TYPE)
- assert type == make(Closure)
- assert type.isUsingGenerics()
- assert type.genericsTypes
- assert type.genericsTypes[0].type.name == 'CTypeTest'
-
- type = node.getNodeMetaData(INFERRED_TYPE)
- assert type.name == 'CTypeTest'
- })
- def s1 = cache {
- return new CTypeTest();
- }
-
- CTypeTest s2 = cache {
- new CTypeTest()
+ class CTypeTest {
+ public static void test1(String[] args) {
+ // Cannot assign value of type java.lang.Object to variable of
type CTypeTest
+ @ASTTest(phase=INSTRUCTION_SELECTION,value={
+ def cl = node.rightExpression.arguments[0]
+ assert cl instanceof ClosureExpression
+ def type = cl.getNodeMetaData(INFERRED_TYPE)
+ assert type == make(Closure)
+ assert type.isUsingGenerics()
+ assert type.genericsTypes
+ assert type.genericsTypes[0].type.name == 'CTypeTest'
+
+ type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type.name == 'CTypeTest'
+ })
+ def s1 = cache {
+ return new CTypeTest();
+ }
+ CTypeTest s2 = cache {
+ new CTypeTest()
+ }
+ }
+ static <T> T cache(Closure<T> closure) {
+ return closure.call();
+ }
}
-
- }
-
-
- static <T> T cache(Closure<T> closure) {
- return closure.call();
- }
-
- }
- 1
+ 1
'''
}
@@ -3117,7 +3154,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
Foo<Map> f = new Foo<Map>("a",1)
}
bar()
- ''', '[Static type checking] - Cannot find matching method
Foo#<init>(java.lang.String, int)'
+ ''',
+ 'Cannot find matching method Foo#<init>(java.lang.String, int)'
}
// GROOVY-5742
@@ -3318,67 +3356,56 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
// GROOVY-5839
void testMethodShadowGenerics() {
- shouldFailWithMessages '''
- public class GoodCodeRed<T> {
- Collection<GoodCodeRed<T>> attached = []
- public <T> void attach(GoodCodeRed<T> toAttach) {
- attached.add(toAttach)
- }
- static void foo() {
- def g1 = new GoodCodeRed<Long>()
- def g2 = new GoodCodeRed<Integer>()
- g1.attach(g2);
+ assertScript '''
+ class C<T> {
+ Collection<C<T>> attached = []
+ def <T> void attach(C<T> toAttach) {
+ attached.add(toAttach) // TODO: GROOVY-7719
}
}
- GoodCodeRed.foo()
- ''',
- 'Cannot call <T> GoodCodeRed#attach(GoodCodeRed<java.lang.Long>) with
arguments [GoodCodeRed<java.lang.Integer>]'
+ def c1 = new C<Short>()
+ def c2 = new C<Long>()
+ c1.attach(c2)
+ '''
}
- void testHiddenGenerics() {
+ void testSuperClassGenerics() {
// GROOVY-6237
assertScript '''
- class MyList extends LinkedList<Object> {}
+ class MyList extends LinkedList<Object> {
+ }
List<Object> o = new MyList()
'''
shouldFailWithMessages '''
- class Blah {}
- class MyList extends LinkedList<Object> {}
- List<Blah> o = new MyList()
- ''','Incompatible generic argument types. Cannot assign MyList to:
java.util.List<Blah>'
+ class MyList extends LinkedList<Object> {
+ }
+ List<String> o = new MyList()
+ ''',
+ 'Incompatible generic argument types. Cannot assign MyList to:
java.util.List<java.lang.String>'
// GROOVY-5873
assertScript '''
- abstract class Parent<T> {
+ abstract class A<T> {
public T value
}
- class Impl extends Parent<Integer> {}
- Impl impl = new Impl()
- Integer i = impl.value
+ class C extends A<Integer> {
+ }
+ C c = new C()
+ Integer i = c.value
'''
// GROOVY-5920
assertScript '''
class Data<T> {
- T value
+ T value
}
-
class StringDataIterator implements Iterator<Data<String>> {
- boolean hasNext() { true }
- void remove() {}
- Data<String> next() {
- new Data<String>( value: 'tim' )
- }
- }
-
- class Runner {
- static main( args ) {
- Data<String> elem = new StringDataIterator().next()
- assert elem.value.length() == 3
- }
+ boolean hasNext() { true }
+ Data<String> next() { new Data<String>(value: 'tim') }
}
- Runner.main(null);
+ Data<String> elem = new StringDataIterator().next()
+ assert elem.value.length() == 3
'''
}
@@ -3488,6 +3515,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
}
new C1().m1(null) // the call does not really matter
'''
+
assertScript '''
class Test1 {
static <A, B> void pair1(A a, B b) {}
@@ -3873,13 +3901,15 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
List<String> test() {
return [1,2,3]
}
- ''', 'Cannot assign java.util.ArrayList<java.lang.Integer> to:
java.util.List<java.lang.String>'
+ ''',
+ 'Cannot assign java.util.ArrayList<java.lang.Integer> to:
java.util.List<java.lang.String>'
shouldFailWithMessages '''
List<CharSequence> test() {
return [1,2,3]
}
- ''', 'Cannot assign java.util.ArrayList<java.lang.Integer> to:
java.util.List<java.lang.CharSequence>'
+ ''',
+ 'Cannot assign java.util.ArrayList<java.lang.Integer> to:
java.util.List<java.lang.CharSequence>'
}
// GROOVY-10295