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 71490fbbc2 GROOVY-8084, GROOVY-9074, GROOVY-10588: STC: implement
wildcard capture
71490fbbc2 is described below
commit 71490fbbc2dc63cdaa70b2f61b77f7f5f94b82af
Author: Eric Milles <[email protected]>
AuthorDate: Mon Nov 11 15:44:23 2024 -0600
GROOVY-8084, GROOVY-9074, GROOVY-10588: STC: implement wildcard capture
---
.../transform/stc/StaticTypeCheckingSupport.java | 10 +-
src/spec/doc/core-semantics.adoc | 17 +-
src/spec/test/typing/TypeCheckingTest.groovy | 30 ++-
src/test/groovy/bugs/Groovy8084Bug.groovy | 39 ----
src/test/groovy/bugs/Groovy9074.groovy | 81 +------
src/test/groovy/transform/stc/BugsSTCTest.groovy | 8 -
.../groovy/transform/stc/GenericsSTCTest.groovy | 259 +++++++++++++++------
.../transform/stc/MethodReferenceTest.groovy | 6 +-
.../transform/stc/TypeInferenceSTCTest.groovy | 14 +-
9 files changed, 241 insertions(+), 223 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 bcf521910c..f79c62daac 100644
---
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1346,6 +1346,7 @@ public abstract class StaticTypeCheckingSupport {
if (type.isGenericsPlaceHolder()) {
GenericsType gt = placeholders.get(new
GenericsTypeName(type.getUnresolvedName()));
if (gt != null) {
+ if (gt.isWildcard()) return new ClassNode("capture-of " + gt,
0, getCombinedBoundType(gt));
return gt.getType();
}
ClassNode cn = extractType(type.asGenericsType()); // GROOVY-10756
@@ -1524,9 +1525,9 @@ public abstract class StaticTypeCheckingSupport {
resolvedMethodGenerics.put(entry.getKey(), candidate);
continue;
} else if (!candidate.isPlaceholder() &&
!candidate.isWildcard()) {
- // combine "T=Integer" and "T=String" to produce "T=?
extends Serializable & Comparable<...>"
+ // combine "T=Integer" and "T=String" to produce
"T=(Serializable & ... )"
ClassNode lub = lowestUpperBound(candidate.getType(),
resolved.getType());
- resolvedMethodGenerics.put(entry.getKey(),
lub.asGenericsType());
+ resolvedMethodGenerics.put(entry.getKey(), new
GenericsType(lub));
continue;
}
}
@@ -1559,6 +1560,11 @@ public abstract class StaticTypeCheckingSupport {
}
private static boolean compatibleConnection(final GenericsType resolved,
final GenericsType connection) {
+ if (resolved.isWildcard()
+ // TODO: figure out capture of super
+ && resolved.getLowerBound() == null) {
+ return false; // GROOVY-8084, GROOVY-9074, GROOVY-10588
+ }
if (resolved.isPlaceholder()
&& resolved.getUpperBounds() != null
&& resolved.getUpperBounds().length == 1
diff --git a/src/spec/doc/core-semantics.adoc b/src/spec/doc/core-semantics.adoc
index b217c9c445..8a74339de5 100644
--- a/src/spec/doc/core-semantics.adoc
+++ b/src/spec/doc/core-semantics.adoc
@@ -1777,8 +1777,8 @@ can assign to the variable:
----
include::../test/typing/TypeCheckingTest.groovy[tags=flowtyping_typeconstraints,indent=0]
----
-<1> `list` is declared as an unchecked `List` and assigned a list literal of
`String`s
-<2> this line passes compilation because of flow typing: the type checker
knows that `list` is at this point a `List<String>`
+<1> `list` is declared as an unchecked `List` and assigned a list literal of
strings
+<2> this line passes compilation because of flow typing: the type checker
knows that `list` is at this point an `ArrayList<String>`
<3> but you can't assign a `String` to a `List` so this is a type checking
error
You can also note that even if the variable is declared *without* generics
information, the type checker knows what is
@@ -1788,18 +1788,21 @@ the component type. Therefore, such code would fail
compilation:
----
include::../test/typing/TypeCheckingTest.groovy[tags=flowtyping_typeconstraints_failure,indent=0]
----
-<1> `list` is inferred as `List<String>`
-<2> so adding an `int` to a `List<String>` is a compile-time error
+<1> `list` is inferred as `ArrayList<String>`
+<2> so adding an `int` to a `ArrayList<String>` is a compile-time error
+<3> `list` is declared as `List<?>`
+<4> the inferred type of `list` here is `List<capture-of ?>`, so calling
`addAll` with a list of anything is a compile-time error
+<5> and calling `add` with an `int` is also a compile-time error for the same
reason; only `add(null)` is allowed
-Fixing this requires adding an explicit generic type to the declaration:
+Fixing this requires adding an explicit, non-wildcard type argument:
[source,groovy]
----
include::../test/typing/TypeCheckingTest.groovy[tags=flowtyping_typeconstraints_fixed,indent=0]
----
-<1> `list` declared as `List<? extends Serializable>` and initialized with an
empty list
+<1> `list` is declared as `List<Serializable>` and initialized with an empty
list
<2> elements added to the list conform to the declaration type of the list
-<3> so adding an `int` to a `List<? extends Serializable>` is allowed
+<3> and adding an integer is allowed
Flow typing has been introduced to reduce the difference in semantics between
classic and static Groovy. In particular,
consider the behavior of this code in Java:
diff --git a/src/spec/test/typing/TypeCheckingTest.groovy
b/src/spec/test/typing/TypeCheckingTest.groovy
index f4f4f16812..1b36511eb9 100644
--- a/src/spec/test/typing/TypeCheckingTest.groovy
+++ b/src/spec/test/typing/TypeCheckingTest.groovy
@@ -688,32 +688,40 @@ import static
org.codehaus.groovy.ast.tools.WideningCategories.lowestUpperBound
}
// end::flowtyping_typeconstraints[]
flowTypingWithExplicitType()
- ''', 'Cannot assign value of type java.lang.String to variable of type
java.util.List'
+ ''',
+ 'Cannot assign value of type java.lang.String to variable of type
java.util.List'
}
- void testFlowTypingTypeConstraintsFailure() {
+ void testFlowTypingTypeConstraints2() {
shouldFailWithMessages '''
// tag::flowtyping_typeconstraints_failure[]
@groovy.transform.TypeChecked
- void flowTypingWithExplicitType() {
- List list = ['a','b','c'] // <1>
+ void flowTypingTypeConstraints1() {
+ def list = ['a','b','c'] // <1>
list.add(1) // <2>
}
+ @groovy.transform.TypeChecked
+ void flowTypingTypeConstraints2() {
+ List<?> list = [] // <3>
+ list.addAll(['a','b','c']) // <4>
+ list.add(1) // <5>
+ }
// end::flowtyping_typeconstraints_failure[]
- flowTypingWithExplicitType()
''',
- 'Cannot call java.util.ArrayList#add(java.lang.String) with arguments
[int]'
+ 'Cannot call java.util.ArrayList#add(java.lang.String) with arguments
[int]',
+ 'Cannot call java.util.ArrayList#addAll(java.util.Collection<? extends
capture-of ?>) with arguments [java.util.ArrayList<java.lang.String>]',
+ 'Cannot call java.util.ArrayList#add(capture-of ?) with arguments
[int]'
assertScript '''
// tag::flowtyping_typeconstraints_fixed[]
@groovy.transform.TypeChecked
- void flowTypingWithExplicitType() {
- List<? extends Serializable> list = [] //
<1>
- list.addAll(['a','b','c']) //
<2>
- list.add(1) //
<3>
+ void flowTypingTypeConstraints3() {
+ List<Serializable> list = [] // <1>
+ list.addAll(['a','b','c']) // <2>
+ list.add(1) // <3>
}
// end::flowtyping_typeconstraints_fixed[]
- flowTypingWithExplicitType()
+ flowTypingTypeConstraints3()
'''
}
diff --git a/src/test/groovy/bugs/Groovy8084Bug.groovy
b/src/test/groovy/bugs/Groovy8084Bug.groovy
deleted file mode 100644
index a2c34d4e5f..0000000000
--- a/src/test/groovy/bugs/Groovy8084Bug.groovy
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.bugs
-
-import gls.CompilableTestSupport
-import groovy.test.NotYetImplemented
-
-class Groovy8084Bug extends CompilableTestSupport {
- // TODO REFINE ME
- void testGroovy8084Bug() {
- assertScript '''
- import groovy.transform.CompileStatic
-
- @CompileStatic
- static def method(List<? extends Serializable> captured) {
- captured.add('some string') // though the test passes now, but
I expect a STC error here because of adding an element to a producer, which is
not allowed in Java
- return captured
- }
-
- println method(new ArrayList<Integer>())
- '''
- }
-}
diff --git a/src/test/groovy/bugs/Groovy9074.groovy
b/src/test/groovy/bugs/Groovy9074.groovy
index f518ee5355..449a0dcdc7 100644
--- a/src/test/groovy/bugs/Groovy9074.groovy
+++ b/src/test/groovy/bugs/Groovy9074.groovy
@@ -18,84 +18,16 @@
*/
package groovy.bugs
-import groovy.test.GroovyTestCase
-import groovy.transform.CompileStatic
import org.codehaus.groovy.control.CompilationUnit
+import org.junit.Test
+import static groovy.test.GroovyAssert.shouldFail
import static org.codehaus.groovy.control.Phases.CLASS_GENERATION
-@CompileStatic
-final class Groovy9074 extends GroovyTestCase {
+final class Groovy9074 {
- void _FIXME_testWildcardCapture() {
- def err = shouldFail '''
- @groovy.transform.TypeChecked
- class Main {
- private static Collection<?> c = new ArrayList<String>()
- static main(args) {
- c.add(new Object())
- }
- }
- '''
-
- // TODO: This is just a sample message; Java produces this for the
equivalent code.
- assert err =~ / The method add\(capture#1-of \?\) in the type
Collection<capture#1-of \?> is not applicable for the arguments \(Object\)/
- }
-
- void _FIXME_testWildcardExtends() {
- def err = shouldFail '''
- import java.awt.Canvas
- abstract class Shape {
- abstract void draw(Canvas c)
- }
- class Circle extends Shape {
- private int x, y, radius
- @Override void draw(Canvas c) {}
- }
- class Rectangle extends Shape {
- private int x, y, width, height
- @Override void draw(Canvas c) {}
- }
-
- @groovy.transform.TypeChecked
- void addRectangle(List<? extends Shape> shapes) {
- shapes.add(0, new Rectangle()) // TODO: compile-time error!
- }
- '''
-
- // TODO: This is just a sample message; Java produces this for the
equivalent code.
- assert err =~ / The method add(capture#1-of \?) in the type
List<capture#1-of \?> is not applicable for the arguments \(Rectangle\)/
- }
-
- void testWildcardSuper() {
- assertScript '''
- import java.awt.Canvas
- abstract class Shape {
- abstract void draw(Canvas c)
- }
- class Circle extends Shape {
- private int x, y, radius
- @Override void draw(Canvas c) {}
- }
- class Rectangle extends Shape {
- private int x, y, width, height
- @Override void draw(Canvas c) {}
- }
-
- @groovy.transform.TypeChecked
- void addRectangle(List<? super Shape> shapes) {
- shapes.add(0, new Rectangle())
- }
-
- List<Shape> list = []
- addRectangle(list)
-
- assert list.size() == 1
- assert list.get(0) instanceof Rectangle
- '''
- }
-
- void testWildcardExtends2() {
+ @Test
+ void testWildcardExtends() {
new CompilationUnit().with {
addSource 'Main.groovy', '''
class Factory {
@@ -124,7 +56,8 @@ final class Groovy9074 extends GroovyTestCase {
}
}
- void testWildcardSuper2() {
+ @Test
+ void testWildcardSuper() {
new CompilationUnit().with {
addSource 'Main.groovy', '''
class Factory {
diff --git a/src/test/groovy/transform/stc/BugsSTCTest.groovy
b/src/test/groovy/transform/stc/BugsSTCTest.groovy
index d248cd4af0..020e7f7a58 100644
--- a/src/test/groovy/transform/stc/BugsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/BugsSTCTest.groovy
@@ -279,14 +279,6 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- void testGroovyObjectInGenerics() {
- assertScript '''
- class A {}
- List<? extends GroovyObject> list = new LinkedList<? extends
GroovyObject>()
- list.add(new A())
- '''
- }
-
// GROOVY-5656
void testShouldNotThrowAmbiguousMethodError() {
assertScript '''import groovy.transform.*
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 46c2b73b1c..f1dc0c97a9 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -53,45 +53,52 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'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)
- ''',
- 'Cannot call java.util.ArrayList#add(java.lang.String) with arguments
[int]'
- }
-
- void testAddOnList2() {
+ void testAddOnList1() {
assertScript '''
List<String> list = []
- list.add 'Hello'
+ list.add('string')
'''
assertScript '''
- List<Integer> list = []
- list.add 1
+ List<Number> list = []
+ list.add(1)
'''
}
- void testAddOnListWithDiamond() {
+ void testAddOnList2() {
assertScript '''
List<String> list = new LinkedList<>()
- list.add 'Hello'
+ list.add('string')
'''
}
- void testAddOnListUsingLeftShift() {
+ void testAddOnList3() {
shouldFailWithMessages '''
List<String> list = []
- list << 1
+ list.add(1)
''',
- 'Cannot call <T>
org.codehaus.groovy.runtime.DefaultGroovyMethods#leftShift(java.util.List<T>,
T) with arguments [java.util.ArrayList<java.lang.String>, int]'
+ 'Cannot call java.util.ArrayList#add(java.lang.String) with arguments
[int]'
}
- void testAddOnList2UsingLeftShift() {
+ // GROOVY-9074
+ void testAddOnList4() {
+ shouldFailWithMessages '''
+ List<?> list = []
+ list.add(1)
+ ''',
+ 'Cannot call java.util.ArrayList#add(capture-of ?) with arguments
[int]'
+
+ shouldFailWithMessages '''
+ List<? extends Number> list = []
+ list.add(1)
+ ''',
+ 'Cannot call java.util.ArrayList#add(capture-of ? extends
java.lang.Number) with arguments [int]'
+ }
+
+ void testAddOnListUsingLeftShift1() {
assertScript '''
List<String> list = []
- list << 'Hello'
+ list << 'string'
'''
assertScript '''
@@ -100,12 +107,20 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
- void testAddOnListWithParameterizedTypeLeftShift() {
- assertScript '''
- class Trie<T> {}
- List<Trie<String>> list = []
- list << new Trie<String>()
- '''
+ void testAddOnListUsingLeftShift2() {
+ shouldFailWithMessages '''
+ List<String> list = []
+ list << 1
+ ''',
+ 'Cannot call <T>
org.codehaus.groovy.runtime.DefaultGroovyMethods#leftShift(java.util.List<T>,
T) with arguments [java.util.ArrayList<java.lang.String>, int]'
+ }
+
+ void testAddOnListUsingLeftShift3() {
+ shouldFailWithMessages '''
+ def list = (List<? extends Number>) []
+ list << 1
+ ''',
+ 'Cannot call <T>
org.codehaus.groovy.runtime.DefaultGroovyMethods#leftShift(java.util.List<T>,
T) with arguments [java.util.List<? extends java.lang.Number>, int]'
}
void testAddOnListWithDiamondUsingLeftShift() {
@@ -115,6 +130,14 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ void testAddOnListWithParameterizedTypeLeftShift() {
+ assertScript '''
+ class Trie<T> {}
+ List<Trie<String>> list = []
+ list << new Trie<String>()
+ '''
+ }
+
void testListInferenceWithNullElems() {
assertScript '''
List<String> strings = ['a', null]
@@ -1923,6 +1946,20 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase
{
'Cannot assign java.util.ArrayList<java.lang.String> to:
java.util.List<? super java.lang.Number>'
}
+ // GROOVY-10371
+ void testAssignmentShouldFailBecauseOfUpperBound() {
+ shouldFailWithMessages '''
+ class A<X> {
+ }
+ class B<Y> extends A<Y> {
+ }
+
+ B<? extends Number> x = new B<Double>()
+ A<Number> y = x
+ ''',
+ 'Incompatible generic argument types. Cannot assign
B<java.lang.Double> to: A<java.lang.Number>'
+ }
+
// GROOVY-9914, GROOVY-10036
void testAssignmentShouldWorkForParameterizedMap() {
assertScript '''
@@ -2447,20 +2484,19 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
class Test {
static test2() {
if (new Random().nextBoolean()) {
- def a = new ArrayList<String>()
- a << "a" << "b" << "c"
- return a
+ def list = new ArrayList<String>()
+ list << "a" << "b" << "c"
+ return list
} else {
- def b = new LinkedList<Number>()
- b << 1 << 2 << 3
- return b
+ def list = new LinkedList<Integer>()
+ list << 1 << 2 << 3
+ return list
}
}
static test() {
def result = test2()
result[0].toInteger()
- //result[0].toString()
}
}
new Test()
@@ -2958,12 +2994,12 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
Map<Date, Integer> map = [:]
@ASTTest(phase=INSTRUCTION_SELECTION, value={
- def infType = node.getNodeMetaData(INFERRED_TYPE)
- assert infType == make(Set)
- def entryInfType = infType.genericsTypes[0].type
- assert entryInfType == make(Map.Entry)
- assert entryInfType.genericsTypes[0].type == make(Date)
- assert entryInfType.genericsTypes[1].type == Integer_TYPE
+ Object type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type == SET_TYPE
+ type = type.genericsTypes[0].type
+ assert type == make(Map.Entry)
+ assert type.genericsTypes[0].type == make(Date)
+ assert type.genericsTypes[1].type == Integer_TYPE
})
def entries = map?.entrySet()
'''
@@ -2974,12 +3010,12 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
List<Map<Date, Integer>> maps = []
@ASTTest(phase=INSTRUCTION_SELECTION, value={
- def listType = node.getNodeMetaData(INFERRED_TYPE)
- assert listType == Iterator_TYPE
- def infType = listType.genericsTypes[0].type
- assert infType == make(Map)
- assert infType.genericsTypes[0].type == make(Date)
- assert infType.genericsTypes[1].type == Integer_TYPE
+ Object type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type == Iterator_TYPE
+ type = type.genericsTypes[0].type
+ assert type == MAP_TYPE
+ assert type.genericsTypes[0].type == make(Date)
+ assert type.genericsTypes[1].type == Integer_TYPE
})
def iter = maps?.iterator()
'''
@@ -3304,12 +3340,12 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
void testUncheckedAssignment() {
assertScript '''
@ASTTest(phase=INSTRUCTION_SELECTION, value={
- def ift = node.getNodeMetaData(INFERRED_TYPE)
- assert ift == make(List)
- assert ift.isUsingGenerics()
- def gts = ift.genericsTypes
- assert gts.length==1
- assert gts[0].type == STRING_TYPE
+ Object type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type == LIST_TYPE
+ assert type.isUsingGenerics()
+ Object args = type.genericsTypes
+ assert args.length == 1
+ assert args[0].type == STRING_TYPE
})
List<String> list = (List) null
'''
@@ -3318,12 +3354,12 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
void testUncheckedAssignmentWithSuperInterface() {
assertScript '''
@ASTTest(phase=INSTRUCTION_SELECTION, value={
- def ift = node.getNodeMetaData(INFERRED_TYPE)
- assert ift == LIST_TYPE
- def gts = ift.genericsTypes
- assert gts != null
- assert gts.length == 1
- assert gts[0].type == STRING_TYPE
+ Object type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type == LIST_TYPE
+ Object args = type.genericsTypes
+ assert args != null
+ assert args.length == 1
+ assert args[0].type == STRING_TYPE
})
Iterable<String> list = (List) null
'''
@@ -3348,7 +3384,11 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase
{
// GROOVY-5692
void testCompatibleArgumentsForPlaceholders2() {
assertScript '''
- def <T> boolean test(T one, List<T> many) { }
+ def <T> void test(T one, List<T> many) { }
+ test(1,[2,3])
+ '''
+ assertScript '''
+ def <T> void test(T one, List<? extends T> many) { }
test(1,["II","III"])
'''
}
@@ -3852,7 +3892,18 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase
{
'''
}
- void testOutOfBoundsByExtendsGenericParameterType() {
+ // GROOVY-10588
+ void testOutOfBoundsByUnboundedGenericParameterType() {
+ shouldFailWithMessages '''
+ Map<String,?> one = [:]
+ Map<String,?> getTwo() { [:] }
+ def one_plus_two = one + two // <K,V> Map<K,V> plus(Map<K,V> left,
Map<K,V> right)
+ ''',
+ 'Cannot call <K,V>
org.codehaus.groovy.runtime.DefaultGroovyMethods#plus(java.util.Map<K, V>,
java.util.Map<K, V>)' +
+ ' with arguments [java.util.LinkedHashMap<java.lang.String, ?>,
java.util.Map<java.lang.String, ? extends java.lang.Object>]'
+ }
+
+ void testOutOfBoundsByExtendsGenericParameterType1() {
shouldFailWithMessages '''
class Foo {
static <T extends List<? extends CharSequence>> void bar(T a)
{}
@@ -3862,29 +3913,93 @@ class GenericsSTCTest extends
StaticTypeCheckingTestCase {
'Cannot call <T extends java.util.List<? extends
java.lang.CharSequence>> Foo#bar(T) with arguments
[java.util.ArrayList<java.lang.Object>]'
}
- void testOutOfBoundsBySuperGenericParameterType() {
+ void testOutOfBoundsByExtendsGenericParameterType2() {
shouldFailWithMessages '''
class Foo {
- static <T extends List<? super CharSequence>> void bar(T a) {}
+ static <T extends List<? extends CharSequence>> void bar(T
list) {}
+ }
+ def <U extends List<Object>> void baz(U list) {
+ Foo.bar(list)
}
- 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<? extends
java.lang.CharSequence>> Foo#bar(T) with arguments [U]'
}
- void testOutOfBoundsByExtendsPlaceholderParameterType() {
+ // GROOVY-8084
+ void testOutOfBoundsByExtendsGenericParameterType3() {
shouldFailWithMessages '''
class Foo {
- static <T extends List<? extends CharSequence>> void bar(T
list) {}
+ static m(List<? extends Serializable> list) {
+ list.add('string')
+ }
}
- def <U extends List<Object>> void baz(U list) {
- Foo.bar(list)
+ Foo.bar(new ArrayList<Integer>())
+ ''',
+ 'Cannot call java.util.List#add(capture-of ? extends
java.io.Serializable) with arguments [java.lang.String]',
+ 'Cannot find matching method
java.lang.Class#bar(java.util.ArrayList<java.lang.Integer>) or static method
Foo#bar(java.util.ArrayList<java.lang.Integer>)'
+ }
+
+ // GROOVY-9074
+ void testOutOfBoundsByExtendsGenericParameterType4() {
+ shouldFailWithMessages '''
+ import java.awt.Canvas
+ abstract class Shape {
+ abstract void draw(Canvas c)
+ }
+ class Circle extends Shape {
+ private int x, y, radius
+ @Override void draw(Canvas c) {}
+ }
+ class Rectangle extends Shape {
+ private int x, y, width, height
+ @Override void draw(Canvas c) {}
+ }
+
+ void addRectangle(List<? extends Shape> shapes) {
+ shapes.add(0, new Rectangle())
}
''',
- 'Cannot call <T extends java.util.List<? extends
java.lang.CharSequence>> Foo#bar(T) with arguments [U]'
+ 'Cannot call java.util.List#add(int, capture-of ? extends Shape) with
arguments [int, Rectangle]'
+ }
+
+ void testNotOutOfBoundsBySuperGenericParameterType() {
+ assertScript '''
+ import java.awt.Canvas
+ abstract class Shape {
+ abstract void draw(Canvas c)
+ }
+ class Circle extends Shape {
+ private int x, y, radius
+ @Override void draw(Canvas c) {}
+ }
+ class Rectangle extends Shape {
+ private int x, y, width, height
+ @Override void draw(Canvas c) {}
+ }
+
+ void addRectangle(List<? super Shape> shapes) {
+ shapes.add(0, new Rectangle())
+ }
+
+ List<Shape> list = []
+ addRectangle(list)
+
+ assert list.size() == 1
+ assert list.get(0) instanceof Rectangle
+ '''
+ }
+
+ void testOutOfBoundsBySuperGenericParameterType1() {
+ shouldFailWithMessages '''
+ class Foo {
+ 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>]'
}
- void testOutOfBoundsBySuperPlaceholderParameterType() {
+ void testOutOfBoundsBySuperGenericParameterType2() {
shouldFailWithMessages '''
class Foo {
static <T extends List<? super CharSequence>> void bar(T list)
{}
@@ -4238,9 +4353,9 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
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)
+ Object type = node.getNodeMetaData(INFERRED_TYPE)
+ assert type == LIST_TYPE
+ assert type.genericsTypes[0].type == make(Date)
})
def res = bar(null)
@@ -4261,7 +4376,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
def cl = node.rightExpression.arguments[0]
assert cl instanceof ClosureExpression
def type = cl.getNodeMetaData(INFERRED_TYPE)
- assert type == make(Closure)
+ assert type == CLOSURE_TYPE
assert type.isUsingGenerics()
assert type.genericsTypes
assert type.genericsTypes[0].type.name == 'CTypeTest'
diff --git a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
index a9353cbde5..921edf719a 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -1368,7 +1368,7 @@ final class MethodReferenceTest {
// GROOVY-10813, GROOVY-10858, GROOVY-11363
@Test
void testMethodSelection() {
- for (spec in ['', '<?>', '<Object>', '<? extends Object>', '<? super
String>']) {
+ for (spec in ['', '<Object>', '<? super String>']) {
assertScript shell, """
@CompileStatic
void test() {
@@ -1379,7 +1379,7 @@ final class MethodReferenceTest {
test()
"""
}
- for (spec in ['', '<?,?>', '<?,Object>', '<?,? extends Object>', '<?,?
super String>']) {
+ for (spec in ['', '<Object,Object>', '<Object,? super String>']) {
assertScript shell, """
@CompileStatic
void test() {
@@ -1393,7 +1393,7 @@ final class MethodReferenceTest {
assertScript shell, '''
@CompileStatic
void test() {
- BiConsumer<Script,?> c = Script::print
+ BiConsumer<Script,Object> c = Script::print
c.accept(this, 'hello world!')
}
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index 5d395506d9..e66b1d811c 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -1378,18 +1378,18 @@ class TypeInferenceSTCTest extends
StaticTypeCheckingTestCase {
// GROOVY-6835
void testFlowTypingWithInstanceofAndInterfaceTypes() {
assertScript '''
- class ShowUnionTypeBug {
- Map<String, Object> instanceMap = (Map<String,Object>)['a':
'Hello World']
+ class ShowFlowTypeBug {
+ Map<String,Object> instanceMap = (Map<String,Object>)[a:
'Hello World']
def findInstance(String key) {
- Set<? extends CharSequence> allInstances = [] as Set
- def instance = instanceMap.get(key)
+ Set<CharSequence> instanceSet = []
+ Object instance = instanceMap.get(key)
if(instance instanceof CharSequence) {
- allInstances.add(instance)
+ instanceSet.add(instance)
}
- allInstances
+ instanceSet
}
}
- assert new ShowUnionTypeBug().findInstance('a') == ['Hello World']
as Set
+ assert new ShowFlowTypeBug().findInstance('a') == ['Hello World']
as Set
'''
}