You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2016/06/24 21:47:26 UTC
groovy git commit: GROOVY-7865: Better error message in the presence
of Generics arity errors (closes #353)
Repository: groovy
Updated Branches:
refs/heads/master 8bcca9ef2 -> d1308e20b
GROOVY-7865: Better error message in the presence of Generics arity errors (closes #353)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/d1308e20
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/d1308e20
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/d1308e20
Branch: refs/heads/master
Commit: d1308e20b09776b18e67ce99faab4054058b6824
Parents: 8bcca9e
Author: paulk <pa...@asert.com.au>
Authored: Fri Jun 17 18:38:25 2016 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Thu Jun 23 20:38:08 2016 +1000
----------------------------------------------------------------------
.../groovy/control/CompilationUnit.java | 15 +-
.../groovy/control/GenericsVisitor.java | 138 ++++++++++++-------
.../stc/StaticTypeCheckingVisitor.java | 11 +-
src/test/gls/generics/GenericsTest.groovy | 123 +++++++++++------
4 files changed, 184 insertions(+), 103 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/d1308e20/src/main/org/codehaus/groovy/control/CompilationUnit.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/control/CompilationUnit.java b/src/main/org/codehaus/groovy/control/CompilationUnit.java
index de53c5b..0c5726f 100644
--- a/src/main/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/org/codehaus/groovy/control/CompilationUnit.java
@@ -186,6 +186,16 @@ public class CompilationUnit extends ProcessingUnit {
}
}, Phases.SEMANTIC_ANALYSIS);
addPhaseOperation(new PrimaryClassNodeOperation() {
+ @Override
+ public void call(SourceUnit source, GeneratorContext context,
+ ClassNode classNode) throws CompilationFailedException {
+ if (!classNode.isSynthetic()) {
+ GenericsVisitor genericsVisitor = new GenericsVisitor(source);
+ genericsVisitor.visitClass(classNode);
+ }
+ }
+ }, Phases.SEMANTIC_ANALYSIS);
+ addPhaseOperation(new PrimaryClassNodeOperation() {
public void call(SourceUnit source, GeneratorContext context,
ClassNode classNode) throws CompilationFailedException {
TraitComposer.doExtendTraits(classNode, source, CompilationUnit.this);
@@ -764,11 +774,6 @@ public class CompilationUnit extends ProcessingUnit {
optimizer.visitClass(classNode, source); // GROOVY-4272: repositioned it here from staticImport
- if(!classNode.isSynthetic()) {
- GenericsVisitor genericsVisitor = new GenericsVisitor(source);
- genericsVisitor.visitClass(classNode);
- }
-
//
// Run the Verifier on the outer class
//
http://git-wip-us.apache.org/repos/asf/groovy/blob/d1308e20/src/main/org/codehaus/groovy/control/GenericsVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/control/GenericsVisitor.java b/src/main/org/codehaus/groovy/control/GenericsVisitor.java
index 7cdf9fd..d95bf24 100644
--- a/src/main/org/codehaus/groovy/control/GenericsVisitor.java
+++ b/src/main/org/codehaus/groovy/control/GenericsVisitor.java
@@ -22,41 +22,56 @@ import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.InnerClassNode;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
/**
- * class used to verify correct usage of generics in
- * class header (class and superclass declaration)
+ * class used to verify correct usage of generics in
+ * class header (class and superclass declaration)
+ *
* @author Jochen Theodorou
*/
public class GenericsVisitor extends ClassCodeVisitorSupport {
private SourceUnit source;
-
+
public GenericsVisitor(SourceUnit source) {
this.source = source;
}
-
+
protected SourceUnit getSourceUnit() {
return source;
}
-
+
+ @Override
public void visitClass(ClassNode node) {
- boolean error=checkWildcard(node);
+ boolean error = checkWildcard(node);
if (error) return;
- checkGenericsUsage(node.getUnresolvedSuperClass(false), node.getSuperClass());
+ boolean isAnon = node instanceof InnerClassNode && ((InnerClassNode)node).isAnonymous();
+ checkGenericsUsage(node.getUnresolvedSuperClass(false), node.getSuperClass(), isAnon ? true : null);
ClassNode[] interfaces = node.getInterfaces();
- for (int i = 0; i < interfaces.length; i++) {
- checkGenericsUsage(interfaces[i], interfaces[i].redirect());
+ for (ClassNode anInterface : interfaces) {
+ checkGenericsUsage(anInterface, anInterface.redirect());
}
node.visitContents(this);
}
-
+
+ @Override
public void visitField(FieldNode node) {
ClassNode type = node.getType();
checkGenericsUsage(type, type.redirect());
+ super.visitField(node);
}
-
+
+ @Override
+ public void visitConstructorCallExpression(ConstructorCallExpression call) {
+ ClassNode type = call.getType();
+ boolean isAnon = type instanceof InnerClassNode && ((InnerClassNode)type).isAnonymous();
+ checkGenericsUsage(type, type.redirect(), isAnon);
+ }
+
+ @Override
public void visitMethod(MethodNode node) {
Parameter[] parameters = node.getParameters();
for (Parameter param : parameters) {
@@ -65,17 +80,18 @@ public class GenericsVisitor extends ClassCodeVisitorSupport {
}
ClassNode returnType = node.getReturnType();
checkGenericsUsage(returnType, returnType.redirect());
+ super.visitMethod(node);
}
-
+
private boolean checkWildcard(ClassNode cn) {
ClassNode sn = cn.getUnresolvedSuperClass(false);
- if (sn==null) return false;
+ if (sn == null) return false;
GenericsType[] generics = sn.getGenericsTypes();
- if (generics==null) return false;
- boolean error=false;
- for (int i = 0; i < generics.length; i++) {
- if(generics[i].isWildcard()) {
- addError("A supertype may not specify a wildcard type",sn);
+ if (generics == null) return false;
+ boolean error = false;
+ for (GenericsType generic : generics) {
+ if (generic.isWildcard()) {
+ addError("A supertype may not specify a wildcard type", sn);
error = true;
}
}
@@ -83,65 +99,89 @@ public class GenericsVisitor extends ClassCodeVisitorSupport {
}
private void checkGenericsUsage(ClassNode n, ClassNode cn) {
- if(n.isGenericsPlaceHolder()) return;
+ checkGenericsUsage(n, cn, null);
+ }
+
+ private void checkGenericsUsage(ClassNode n, ClassNode cn, Boolean isAnonInnerClass) {
+ if (n.isGenericsPlaceHolder()) return;
GenericsType[] nTypes = n.getGenericsTypes();
GenericsType[] cnTypes = cn.getGenericsTypes();
// raw type usage is always allowed
- if (nTypes==null) return;
- // parameterize a type by using all of the parameters only
- if (cnTypes==null) {
- addError( "The class "+n.getName()+" refers to the class "+
- cn.getName()+" and uses "+nTypes.length+
- " parameters, but the referred class takes no parameters", n);
+ if (nTypes == null) return;
+ // you can't parameterize a non-generified type
+ if (cnTypes == null) {
+ String message = "The class " + getPrintName(n) + " (supplied with " + plural("type parameter", nTypes.length) +
+ ") refers to the class " + getPrintName(cn) + " which takes no parameters";
+ if (nTypes.length == 0) {
+ message += " (invalid Diamond <> usage?)";
+ }
+ addError(message, n);
return;
}
- if (nTypes.length!=cnTypes.length) {
- addError( "The class "+n.getName()+" refers to the class "+
- cn.getName()+" and uses "+nTypes.length+
- " parameters, but the referred class needs "+
- cnTypes.length, n);
+ // parameterize a type by using all of the parameters only
+ if (nTypes.length != cnTypes.length) {
+ if (Boolean.FALSE.equals(isAnonInnerClass) && nTypes.length == 0) {
+ return; // allow Diamond for non-AIC cases from CCE
+ }
+ String message;
+ if (Boolean.TRUE.equals(isAnonInnerClass) && nTypes.length == 0) {
+ message = "Cannot use diamond <> with anonymous inner classes";
+ } else {
+ message = "The class " + getPrintName(n) + " (supplied with " + plural("type parameter", nTypes.length) +
+ ") refers to the class " + getPrintName(cn) +
+ " which takes " + plural("parameter", cnTypes.length);
+ if (nTypes.length == 0) {
+ message += " (invalid Diamond <> usage?)";
+ }
+ }
+ addError(message, n);
return;
}
// check bounds
- for (int i=0; i<nTypes.length; i++) {
+ for (int i = 0; i < nTypes.length; i++) {
ClassNode nType = nTypes[i].getType();
ClassNode cnType = cnTypes[i].getType();
if (!nType.isDerivedFrom(cnType)) {
if (cnType.isInterface() && nType.implementsInterface(cnType)) continue;
- addError("The type "+nTypes[i].getName()+
- " is not a valid substitute for the bounded parameter <"+
- getPrintName(cnTypes[i])+">",n);
+ addError("The type " + nTypes[i].getName() +
+ " is not a valid substitute for the bounded parameter <" +
+ getPrintName(cnTypes[i]) + ">", n);
}
}
}
-
+
+ private String plural(String orig, int count) {
+ return "" + count + " " + (count == 1 ? orig : orig + "s");
+ }
+
private static String getPrintName(GenericsType gt) {
String ret = gt.getName();
ClassNode[] upperBounds = gt.getUpperBounds();
ClassNode lowerBound = gt.getLowerBound();
- if (upperBounds!=null) {
- ret += " extends ";
- for (int i = 0; i < upperBounds.length; i++) {
- ret += getPrintName(upperBounds[i]);
- if (i+1<upperBounds.length) ret += " & ";
+ if (upperBounds != null) {
+ if (upperBounds.length != 1 || !"java.lang.Object".equals(getPrintName(upperBounds[0]))) {
+ ret += " extends ";
+ for (int i = 0; i < upperBounds.length; i++) {
+ ret += getPrintName(upperBounds[i]);
+ if (i + 1 < upperBounds.length) ret += " & ";
+ }
}
- } else if (lowerBound!=null) {
- ret += " super "+getPrintName(lowerBound);
+ } else if (lowerBound != null) {
+ ret += " super " + getPrintName(lowerBound);
}
return ret;
-
}
-
+
private static String getPrintName(ClassNode cn) {
String ret = cn.getName();
GenericsType[] gts = cn.getGenericsTypes();
- if (gts!=null) {
+ if (gts != null) {
ret += "<";
for (int i = 0; i < gts.length; i++) {
- if (i!=0) ret+=",";
- ret+=getPrintName(gts[i]);
- }
- ret+=">";
+ if (i != 0) ret += ",";
+ ret += getPrintName(gts[i]);
+ }
+ ret += ">";
}
return ret;
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/d1308e20/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index e3cc081..bf53f52 100644
--- a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -771,16 +771,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
protected void inferDiamondType(final ConstructorCallExpression cce, final ClassNode lType) {
// check if constructor call expression makes use of the diamond operator
ClassNode node = cce.getType();
- if (node.isUsingGenerics() && node instanceof InnerClassNode && ((InnerClassNode) node).isAnonymous()) {
- ClassNode[] interfaces = node.getInterfaces();
- node = interfaces != null && interfaces.length == 1 ? interfaces[0] : node.getUnresolvedSuperClass(false);
- if ((node.getGenericsTypes() == null || node.getGenericsTypes().length == 0) && lType.isUsingGenerics()) {
- // InterfaceA<Foo> obj = new InterfaceA<>() { ... }
- // InterfaceA<Foo> obj = new ClassA<>() { ... }
- // ClassA<Foo> obj = new ClassA<>() { ... }
- addStaticTypeError("Cannot use diamond <> with anonymous inner classes", cce);
- }
- } else if (node.isUsingGenerics() && node.getGenericsTypes() != null && node.getGenericsTypes().length == 0) {
+ if (node.isUsingGenerics() && node.getGenericsTypes() != null && node.getGenericsTypes().length == 0) {
ArgumentListExpression argumentListExpression = InvocationWriter.makeArgumentList(cce.getArguments());
if (argumentListExpression.getExpressions().isEmpty()) {
GenericsType[] genericsTypes = lType.getGenericsTypes();
http://git-wip-us.apache.org/repos/asf/groovy/blob/d1308e20/src/test/gls/generics/GenericsTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/gls/generics/GenericsTest.groovy b/src/test/gls/generics/GenericsTest.groovy
index b2779c9..02a76ce 100644
--- a/src/test/gls/generics/GenericsTest.groovy
+++ b/src/test/gls/generics/GenericsTest.groovy
@@ -22,7 +22,7 @@ import org.codehaus.groovy.control.MultipleCompilationErrorsException
class GenericsTest extends GenericsTestBase {
- public void testClassWithoutParameterExtendsClassWithFixedParameter() {
+ void testClassWithoutParameterExtendsClassWithFixedParameter() {
createClassInfo """
class B extends ArrayList<Long> {}
"""
@@ -31,56 +31,56 @@ class GenericsTest extends GenericsTestBase {
]
}
- public void testMultipleImplementsWithParameter() {
+ void testMultipleImplementsWithParameter() {
createClassInfo """
abstract class B<T> implements Runnable,List<T> {}
"""
assert signatures == ["class": "<T:Ljava/lang/Object;>Ljava/lang/Object;Ljava/lang/Runnable;Ljava/util/List<TT;>;Lgroovy/lang/GroovyObject;"]
}
- public void testImplementsWithParameter() {
+ void testImplementsWithParameter() {
createClassInfo """
abstract class B<T> implements List<T> {}
"""
assert signatures == ["class": "<T:Ljava/lang/Object;>Ljava/lang/Object;Ljava/util/List<TT;>;Lgroovy/lang/GroovyObject;"]
}
- public void testExtendsWithParameter() {
+ void testExtendsWithParameter() {
createClassInfo """
class B<T> extends ArrayList<T> {}
"""
assert signatures == ["class": "<T:Ljava/lang/Object;>Ljava/util/ArrayList<TT;>;Lgroovy/lang/GroovyObject;"]
}
- public void testNestedExtendsWithParameter() {
+ void testNestedExtendsWithParameter() {
createClassInfo """
class B<T> extends HashMap<T,List<T>> {}
"""
assert signatures == ["class": "<T:Ljava/lang/Object;>Ljava/util/HashMap<TT;Ljava/util/List<TT;>;>;Lgroovy/lang/GroovyObject;"]
}
- public void testBoundInterface() {
+ void testBoundInterface() {
createClassInfo """
class B<T extends List> {}
"""
assert signatures == ["class": "<T::Ljava/util/List;>Ljava/lang/Object;Lgroovy/lang/GroovyObject;"]
}
- public void testNestedReuseOfParameter() {
+ void testNestedReuseOfParameter() {
createClassInfo """
class B<Y,T extends Map<String,Map<Y,Integer>>> {}
"""
assert signatures == ["class": "<Y:Ljava/lang/Object;T::Ljava/util/Map<Ljava/lang/String;Ljava/util/Map<TY;Ljava/lang/Integer;>;>;>Ljava/lang/Object;Lgroovy/lang/GroovyObject;"]
}
- public void testFieldWithParameter() {
+ void testFieldWithParameter() {
createClassInfo """
class B { public Collection<Integer> books }
"""
assert signatures == [books: "Ljava/util/Collection<Ljava/lang/Integer;>;"]
}
- public void testFieldReusedParameter() {
+ void testFieldReusedParameter() {
createClassInfo """
class B<T> { public Collection<T> collection }
"""
@@ -88,7 +88,7 @@ class GenericsTest extends GenericsTestBase {
collection: "Ljava/util/Collection<TT;>;"]
}
- public void testParameterAsReturnType() {
+ void testParameterAsReturnType() {
createClassInfo """
class B {
static <T> T foo() {return null}
@@ -97,7 +97,7 @@ class GenericsTest extends GenericsTestBase {
assert signatures == ["foo()Ljava/lang/Object;": "<T:Ljava/lang/Object;>()TT;"]
}
- public void testParameterAsReturnTypeAndParameter() {
+ void testParameterAsReturnTypeAndParameter() {
createClassInfo """
class B {
static <T> T foo(T t) {return null}
@@ -106,7 +106,7 @@ class GenericsTest extends GenericsTestBase {
assert signatures == ["foo(Ljava/lang/Object;)Ljava/lang/Object;": "<T:Ljava/lang/Object;>(TT;)TT;"]
}
- public void testParameterAsMethodParameter() {
+ void testParameterAsMethodParameter() {
createClassInfo """
class B<T> {
void foo(T t){}
@@ -116,7 +116,7 @@ class GenericsTest extends GenericsTestBase {
"foo(Ljava/lang/Object;)V": "(TT;)V"]
}
- public void testParameterAsNestedMethodParameter() {
+ void testParameterAsNestedMethodParameter() {
createClassInfo """
class B<T> {
void foo(List<T> t){}
@@ -126,7 +126,7 @@ class GenericsTest extends GenericsTestBase {
"foo(Ljava/util/List;)V": "(Ljava/util/List<TT;>;)V"]
}
- public void testParameterAsNestedMethodParameterReturningInterface() {
+ void testParameterAsNestedMethodParameterReturningInterface() {
createClassInfo """
class B<T> {
Cloneable foo(List<T> t){}
@@ -136,7 +136,7 @@ class GenericsTest extends GenericsTestBase {
"foo(Ljava/util/List;)Ljava/lang/Cloneable;": "(Ljava/util/List<TT;>;)Ljava/lang/Cloneable;"]
}
- public void testArray() {
+ void testArray() {
createClassInfo """
class B<T> {
T[] get(T[] arr) {return null}
@@ -146,7 +146,7 @@ class GenericsTest extends GenericsTestBase {
"get([Ljava/lang/Object;)[Ljava/lang/Object;": "([TT;)[TT;"]
}
- public void testMultipleBounds() {
+ void testMultipleBounds() {
createClassInfo """
class Pair< A extends Comparable<A> & Cloneable ,
B extends Cloneable & Comparable<B> >
@@ -161,7 +161,7 @@ class GenericsTest extends GenericsTestBase {
"bar()Ljava/lang/Cloneable;": "()TB;"]
}
- public void testWildCard() {
+ void testWildCard() {
createClassInfo """
class B {
private Collection<?> f1
@@ -192,7 +192,7 @@ class GenericsTest extends GenericsTestBase {
]
}
- public void testParameterAsParameterForReturnTypeAndFieldClass() {
+ void testParameterAsParameterForReturnTypeAndFieldClass() {
createClassInfo """
public class B<T> {
private T owner;
@@ -207,7 +207,7 @@ class GenericsTest extends GenericsTestBase {
]
}
- public void testInterfaceWithParameter() {
+ void testInterfaceWithParameter() {
createClassInfo """
interface B<T> {}
"""
@@ -215,7 +215,7 @@ class GenericsTest extends GenericsTestBase {
}
- public void testTypeParamAsBound() {
+ void testTypeParamAsBound() {
createClassInfo """
class Box<A> {
public <V extends A> void foo(V v) {
@@ -226,7 +226,7 @@ class GenericsTest extends GenericsTestBase {
assert signatures == ["foo(Ljava/lang/Object;)V": "<V:TA;>(TV;)V", "class": "<A:Ljava/lang/Object;>Ljava/lang/Object;Lgroovy/lang/GroovyObject;"]
}
- public void testInvalidParameterUsage() {
+ void testInvalidParameterUsage() {
shouldNotCompile """
abstract class B<T> implements Map<T>{}
"""
@@ -323,9 +323,9 @@ class GenericsTest extends GenericsTestBase {
}
void testGenericsDiamondShortcutIllegalPosition() {
- assertScriptAndVerifyCompilationError """
+ shouldFailCompilationWithMessage '''
List<> list4 = []
- """, 'unexpected token: <'
+ ''', 'unexpected token: <'
}
void testGenericsInAsType() {
@@ -356,55 +356,61 @@ import java.util.concurrent.atomic.AtomicInteger
}
void testCompilationWithMissingClosingBracketsInGenerics() {
- assertScriptAndVerifyCompilationError """
+ shouldFailCompilationWithExpectedMessage """
def list1 = new ArrayList<Integer()
"""
- assertScriptAndVerifyCompilationError """
+ shouldFailCompilationWithExpectedMessage """
List<Integer list2 = new ArrayList<Integer>()
"""
- assertScriptAndVerifyCompilationError """
+ shouldFailCompilationWithExpectedMessage """
def c = []
for (Iterator<String i = c.iterator(); i.hasNext(); ) { }
"""
- assertScriptAndVerifyCompilationError """
+ shouldFailCompilationWithExpectedMessage """
def m(Class<Integer someParam) {}
"""
- assertScriptAndVerifyCompilationError """
+ shouldFailCompilationWithExpectedMessage """
abstract class ArrayList1<E extends AbstractList<E> implements List<E> {}
"""
- assertScriptAndVerifyCompilationError """
+ shouldFailCompilationWithExpectedMessage """
abstract class ArrayList2<E> extends AbstractList<E implements List<E> {}
"""
- assertScriptAndVerifyCompilationError """
+ shouldFailCompilationWithExpectedMessage """
abstract class ArrayList3<E> extends AbstractList<E> implements List<E {}
"""
- assertScriptAndVerifyCompilationError """
+ shouldFailCompilationWithExpectedMessage """
def List<List<Integer> history = new ArrayList<List<Integer>>()
"""
- assertScriptAndVerifyCompilationError """
+ shouldFailCompilationWithExpectedMessage """
def List<List<Integer>> history = new ArrayList<List<Integer>()
"""
}
- private void assertScriptAndVerifyCompilationError(scriptText) {
- assertScriptAndVerifyCompilationError(scriptText, "Missing closing bracket '>' for generics types")
+ private void shouldFailCompilationWithExpectedMessage(scriptText) {
+ shouldFailCompilationWithMessage scriptText, "Missing closing bracket '>' for generics types"
}
- private void assertScriptAndVerifyCompilationError(scriptText, errorMessage) {
+ private void shouldFailCompilationWithMessage(scriptText, String errorMessage) {
+ shouldFailCompilationWithMessages(scriptText, [errorMessage])
+ }
+
+ private void shouldFailCompilationWithMessages(scriptText, List<String> errorMessages) {
try {
assertScript scriptText
- fail("The script compilation should have failed as it contains mis-matching generic brackets")
+ fail("The script compilation should have failed as it contains generics errors, e.g. mis-matching generic brackets")
} catch (MultipleCompilationErrorsException mcee) {
- def text = mcee.toString();
- assert text.contains(errorMessage)
+ def text = mcee.toString()
+ errorMessages.each {
+ assert text.contains(it)
+ }
}
}
@@ -440,11 +446,50 @@ import java.util.concurrent.atomic.AtomicInteger
'''
}
- public void "test method with generic return type defined at class level"() {
+ void "test method with generic return type defined at class level"() {
// class Bar should compile successfully
// the classes it references should be available as class files to check for ASM resolving
// so they're defined in compiled GenericsTestData and not loaded from text in the test
createClassInfo 'class Bar extends gls.generics.GenericsTestData.Abstract<String> {}'
}
+
+ void testFriendlyErrorMessageForGenericsArityErrorsGroovy7865() {
+ shouldFailCompilationWithMessages '''
+ class MyList extends ArrayList<String, String> {}
+ ''', ['(supplied with 2 type parameters)', 'which takes 1 parameter']
+ shouldFailCompilationWithMessages '''
+ class MyList extends ArrayList<> {}
+ ''', ['(supplied with 0 type parameters)', 'which takes 1 parameter', 'invalid Diamond <> usage?']
+ shouldFailCompilationWithMessages '''
+ class MyMap extends HashMap<String> {}
+ ''', ['(supplied with 1 type parameter)', 'which takes 2 parameters']
+ shouldFailCompilationWithMessages '''
+ class MyList implements List<String, String> {}
+ ''', ['(supplied with 2 type parameters)', 'which takes 1 parameter']
+ shouldFailCompilationWithMessages '''
+ class MyList implements Map<> {}
+ ''', ['(supplied with 0 type parameters)', 'which takes 2 parameters', 'invalid Diamond <> usage?']
+ shouldFailCompilationWithMessages '''
+ class MyMap implements Map<String> {}
+ ''', ['(supplied with 1 type parameter)', 'which takes 2 parameters']
+ shouldFailCompilationWithMessages '''
+ List<String> ss = new LinkedList<Integer, String>()
+ ''', ['(supplied with 2 type parameters)', 'which takes 1 parameter']
+ shouldFailCompilationWithMessage '''
+ List<String> ss = new LinkedList<>(){}
+ ''', 'Cannot use diamond <> with anonymous inner classes'
+ shouldFailCompilationWithMessages '''
+ List<String> ss = new LinkedList<String, String>(){}
+ ''', ['(supplied with 2 type parameters)', 'which takes 1 parameter']
+ shouldFailCompilationWithMessages '''
+ List<String> ss = new LinkedList<String, String>()
+ ''', ['supplied with 2 type parameters', 'which takes 1 parameter']
+ shouldFailCompilationWithMessages '''
+ def now = new Date<Calendar>()
+ ''', ['supplied with 1 type parameter', 'which takes no parameters']
+ assertScript '''
+ List<String> ss = new LinkedList<>()
+ '''
+ }
}