This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch GROOVY-9074 in repository https://gitbox.apache.org/repos/asf/groovy.git
commit de13eec22e6874afc42e477da367ef6dc5051726 Author: Eric Milles <eric.mil...@thomsonreuters.com> 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 ''' }