"Fossies" - the Fresh Open Source Software Archive

Member "groovy-3.0.9/src/test/groovy/transform/stc/GenericsSTCTest.groovy" (3 Sep 2021, 87827 Bytes) of package /linux/misc/apache-groovy-src-3.0.9.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Java source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "GenericsSTCTest.groovy": 3.0.9_vs_4.0.0-rc-1.

    1 /*
    2  *  Licensed to the Apache Software Foundation (ASF) under one
    3  *  or more contributor license agreements.  See the NOTICE file
    4  *  distributed with this work for additional information
    5  *  regarding copyright ownership.  The ASF licenses this file
    6  *  to you under the Apache License, Version 2.0 (the
    7  *  "License"); you may not use this file except in compliance
    8  *  with the License.  You may obtain a copy of the License at
    9  *
   10  *    http://www.apache.org/licenses/LICENSE-2.0
   11  *
   12  *  Unless required by applicable law or agreed to in writing,
   13  *  software distributed under the License is distributed on an
   14  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   15  *  KIND, either express or implied.  See the License for the
   16  *  specific language governing permissions and limitations
   17  *  under the License.
   18  */
   19 package groovy.transform.stc
   20 
   21 import groovy.test.NotYetImplemented
   22 import org.codehaus.groovy.antlr.AntlrParserPluginFactory
   23 import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit
   24 
   25 /**
   26  * Unit tests for static type checking : generics.
   27  */
   28 class GenericsSTCTest extends StaticTypeCheckingTestCase {
   29 
   30     void testDeclaration() {
   31         assertScript '''
   32             List test = new LinkedList<String>()
   33         '''
   34     }
   35 
   36     void testDeclaration5() {
   37         assertScript '''
   38             Map<String,Integer> obj = new HashMap<String,Integer>()
   39         '''
   40     }
   41 
   42     void testDeclaration6() {
   43         shouldFailWithMessages '''
   44             Map<String,String> obj = new HashMap<String,Integer>()
   45         ''', 'Incompatible generic argument types. Cannot assign java.util.HashMap <String, Integer> to: java.util.Map <String, String>'
   46     }
   47 
   48     void testDeclaration4() {
   49         // no generics checked after first wildcard
   50         shouldFailWithMessages '''
   51             Map<? extends CharSequence,String> obj = new HashMap<String,Integer>()
   52         ''', 'Incompatible generic argument types. Cannot assign java.util.HashMap <String, Integer> to: java.util.Map <? extends java.lang.CharSequence, String>'
   53     }
   54 
   55     void testAddOnList() {
   56         shouldFailWithMessages '''
   57             List<String> list = []
   58             list.add(1)
   59         ''', "[Static type checking] - Cannot find matching method java.util.List#add(int)"
   60     }
   61 
   62     void testAddOnList2() {
   63         assertScript '''
   64             List<String> list = []
   65             list.add 'Hello'
   66         '''
   67 
   68         assertScript '''
   69             List<Integer> list = []
   70             list.add 1
   71         '''
   72     }
   73 
   74     void testAddOnListWithDiamond() {
   75         assertScript '''
   76             List<String> list = new LinkedList<>()
   77             list.add 'Hello'
   78         '''
   79     }
   80 
   81     void testAddOnListUsingLeftShift() {
   82         shouldFailWithMessages '''
   83             List<String> list = []
   84             list << 1
   85         ''', '[Static type checking] - Cannot call <T> java.util.List <String>#leftShift(T) with arguments [int] '
   86     }
   87 
   88     void testAddOnList2UsingLeftShift() {
   89         assertScript '''
   90             List<String> list = []
   91             list << 'Hello'
   92         '''
   93 
   94         assertScript '''
   95             List<Integer> list = []
   96             list << 1
   97         '''
   98     }
   99 
  100     void testAddOnListWithParameterizedTypeLeftShift() {
  101         assertScript '''
  102             class Trie<T> {}
  103             List<Trie<String>> list = []
  104             list << new Trie<String>()
  105         '''
  106     }
  107 
  108     void testAddOnListWithDiamondUsingLeftShift() {
  109         assertScript '''
  110             List<String> list = new LinkedList<>()
  111             list << 'Hello'
  112         '''
  113     }
  114 
  115     void testListInferrenceWithNullElems() {
  116         assertScript '''
  117             List<String> strings = ['a', null]
  118             assert strings == ['a',null]
  119         '''
  120     }
  121 
  122     void testListInferrenceWithAllNullElems() {
  123         assertScript '''
  124             List<String> strings = [null, null]
  125             assert strings == [null,null]
  126         '''
  127     }
  128 
  129     void testAddOnListWithDiamondAndWrongType() {
  130         shouldFailWithMessages '''
  131             List<Integer> list = new LinkedList<>()
  132             list.add 'Hello'
  133         ''', '[Static type checking] - Cannot find matching method java.util.LinkedList#add(java.lang.String). Please check if the declared type is correct and if the method exists.'
  134     }
  135 
  136     void testAddOnListWithDiamondAndWrongTypeUsingLeftShift() {
  137         shouldFailWithMessages '''
  138             List<Integer> list = new LinkedList<>()
  139             list << 'Hello'
  140         ''', '[Static type checking] - Cannot call <T> java.util.LinkedList <java.lang.Integer>#leftShift(T) with arguments [java.lang.String]'
  141     }
  142 
  143     void testAddOnListWithDiamondAndNullUsingLeftShift() {
  144         assertScript '''
  145             List<Integer> list = new LinkedList<>()
  146             list << null
  147         '''
  148     }
  149 
  150     void testReturnTypeInference() {
  151         assertScript '''
  152             class Foo<U> {
  153                 U method() { }
  154             }
  155             Foo<Integer> foo = new Foo<Integer>()
  156             Integer result = foo.method()
  157         '''
  158     }
  159 
  160     void testReturnTypeInferenceWithDiamond() {
  161         assertScript '''
  162             class Foo<U> {
  163                 U method() { }
  164             }
  165             Foo<Integer> foo = new Foo<>()
  166             Integer result = foo.method()
  167         '''
  168     }
  169 
  170     // GROOVY-9064
  171     void testReturnTypeInferenceWithGenerics() {
  172         assertScript '''
  173             List getSomeRows() { [new String[]{'x'}] }
  174             List<String[]> rows = getSomeRows()
  175             rows.each { row ->
  176                 def col = row[0].toUpperCase()
  177                 assert col == 'X'
  178             }
  179         '''
  180     }
  181 
  182     void testReturnTypeInferenceWithMethodGenerics() {
  183         assertScript '''
  184             List<Long> list = Arrays.asList([0L,0L] as Long[])
  185         '''
  186     }
  187 
  188     void testReturnTypeInferenceWithMethodGenericsAndVarArg() {
  189         assertScript '''
  190             List<Long> list = Arrays.asList(0L,0L)
  191         '''
  192     }
  193 
  194     // GROOVY-8638
  195     void testReturnTypeInferenceWithMethodGenerics17() {
  196         assertScript '''
  197             @Grab('com.google.guava:guava:30.1.1-jre')
  198             import com.google.common.collect.*
  199 
  200             ListMultimap<String, Integer> mmap = ArrayListMultimap.create()
  201 
  202             Map<String, Collection<Integer>> map = mmap.asMap()
  203             Set<Map.Entry<String, Collection<Integer>>> set = map.entrySet()
  204             Iterator<Map.Entry<String, Collection<Integer>>> it = set.iterator()
  205             while (it.hasNext()) { Map.Entry<String, Collection<Integer>> entry = it.next()
  206                 Collection<Integer> values = entry.value
  207             }
  208         '''
  209     }
  210 
  211     // GROOVY-10098
  212     void testReturnTypeInferenceWithMethodGenerics16() {
  213         assertScript '''
  214             @groovy.transform.TupleConstructor(defaults=false)
  215             class C<T extends Number> {
  216               T p
  217               T m() {
  218                 Closure<T> x = { -> p }
  219                 x() // Cannot return value of type Object on method returning type T
  220               }
  221             }
  222             assert new C<>(42).m() == 42
  223         '''
  224     }
  225 
  226     void testDiamondInferrenceFromConstructor1() {
  227         assertScript '''
  228             Set< Long > s2 = new HashSet<>()
  229         '''
  230     }
  231 
  232     void testDiamondInferrenceFromConstructor2() {
  233         assertScript '''
  234             new HashSet<>(Arrays.asList(0L,0L));
  235         '''
  236     }
  237 
  238     void testDiamondInferrenceFromConstructor3() {
  239         shouldFailWithMessages '''
  240             Set< Number > s3 = new HashSet<>(Arrays.asList(0L,0L));
  241         ''', 'Cannot assign java.util.HashSet <java.lang.Long> to: java.util.Set <Number>'
  242     }
  243 
  244     void testDiamondInferrenceFromConstructor4() {
  245         assertScript '''
  246             Set<Number> s4 = new HashSet<Number>(Arrays.asList(0L,0L))
  247         '''
  248     }
  249     // GROOVY-9984
  250     void testDiamondInferrenceFromConstructor5() {
  251         assertScript '''
  252             @groovy.transform.TupleConstructor(defaults=false)
  253             class C<T> {
  254                 T p
  255             }
  256 
  257             C<Integer> c = new C<>(null)
  258             assert c.p === null
  259         '''
  260     }
  261 
  262     // GROOVY-9996
  263     void testDiamondInferrenceFromConstructor6() {
  264         assertScript '''
  265             @groovy.transform.TupleConstructor(defaults=false)
  266             class C<T> {
  267                 T p
  268             }
  269             interface I { }
  270             class D implements I { }
  271             void test(C<I> c) { assert c.p instanceof D }
  272 
  273             I i = new D() // infers D for "i"
  274             def ci = new C<>(i) // infers C<D> for "ci"
  275             test(ci)
  276         '''
  277     }
  278 
  279     // GROOVY-10011
  280     void testDiamondInferrenceFromConstructor7() {
  281         assertScript '''
  282             @groovy.transform.TupleConstructor(defaults=false)
  283             class C<T> {
  284                 T p
  285             }
  286             interface I { }
  287             class D implements I { }
  288 
  289             void test(I i) {
  290                 if (i instanceof D) {
  291                     C<D> cd = new C<>(i)
  292                 }
  293             }
  294             test(new D())
  295         '''
  296     }
  297 
  298     void testLinkedListWithListArgument() {
  299         assertScript '''
  300             List<String> list = new LinkedList<String>(['1','2','3'])
  301         '''
  302     }
  303 
  304     void testLinkedListWithListArgumentAndWrongElementTypes() {
  305         shouldFailWithMessages '''
  306             List<String> list = new LinkedList<String>([1,2,3])
  307         ''', 'Cannot call java.util.LinkedList <String>#<init>(java.util.Collection <? extends java.lang.String>) with arguments [java.util.List <java.lang.Integer>]'
  308     }
  309 
  310     void testCompatibleGenericAssignmentWithInference() {
  311         shouldFailWithMessages '''
  312             List<String> elements = ['a','b', 1]
  313         ''', 'Incompatible generic argument types. Cannot assign java.util.List <java.io.Serializable> to: java.util.List <String>'
  314     }
  315 
  316     void testGenericAssignmentWithSubClass() {
  317         assertScript '''
  318             List<String> list = new groovy.transform.stc.GenericsSTCTest.MyList()
  319         '''
  320     }
  321 
  322     void testGenericAssignmentWithSubClassAndWrongGenericType() {
  323         shouldFailWithMessages '''
  324             List<Integer> list = new groovy.transform.stc.GenericsSTCTest.MyList()
  325         ''', 'Incompatible generic argument types'
  326     }
  327 
  328     void testAddShouldBeAllowedOnUncheckedGenerics() {
  329         assertScript '''
  330             List list = []
  331             list.add 'Hello'
  332             list.add 2
  333             list.add 'the'
  334             list.add 'world'
  335         '''
  336     }
  337 
  338     void testAssignmentShouldFailBecauseOfLowerBound() {
  339         shouldFailWithMessages '''
  340             List<? super Number> list = ['string']
  341         ''', 'Number'
  342     }
  343 
  344     // GROOVY-9914, GROOVY-10036
  345     void testAssignmentShouldWorkForParameterizedMap() {
  346         assertScript '''
  347             Map test(Map<String,String> one) {
  348                 Map<String,Integer> two = one.collectEntries { k,v ->
  349                     [(k): v.hashCode()]
  350                 }
  351             }
  352             assert test(foo:'bar').containsKey('foo')
  353         '''
  354 
  355         assertScript '''
  356             def list = ['foo','bar','baz']
  357             @ASTTest(phase=INSTRUCTION_SELECTION, value={
  358                 def type = node.getNodeMetaData(INFERRED_TYPE)
  359                 assert type.toString(false) == 'java.util.Map <String, Object>'
  360             })
  361             def map = list.<String,Object,String>collectEntries {
  362                 [(it): it.hashCode()]
  363             }
  364         '''
  365     }
  366 
  367     void testGroovy5154() {
  368         assertScript '''
  369             class Foo {
  370                 def say() {
  371                     FooWithGenerics f
  372                     FooBound fb
  373                     f.say(fb)
  374                 }
  375             }
  376 
  377             class FooWithGenerics {
  378                 def <T extends FooBound> void say(T p) {
  379                 }
  380             }
  381             class FooBound {
  382             }
  383             new Foo()
  384         '''
  385     }
  386 
  387     void testGroovy5154WithSubclass() {
  388         assertScript '''
  389             class Foo {
  390                 def say() {
  391                     FooWithGenerics f
  392                     FooBound2 fb
  393                     f.say(fb)
  394                 }
  395             }
  396 
  397             class FooWithGenerics {
  398                 def <T extends FooBound> void say(T p) {
  399                 }
  400             }
  401             class FooBound {
  402             }
  403             class FooBound2 extends FooBound {}
  404             new Foo()
  405         '''
  406     }
  407 
  408     void testGroovy5154WithIncorrectType() {
  409         shouldFailWithMessages '''
  410             class Foo {
  411                 def say() {
  412                     FooWithGenerics f
  413                     Object fb
  414                     f.say(fb)
  415                 }
  416             }
  417 
  418             class FooWithGenerics {
  419                 def <T extends FooBound> void say(T p) {
  420                 }
  421             }
  422             class FooBound {
  423             }
  424             new Foo()
  425         ''', 'Cannot find matching method FooWithGenerics#say(java.lang.Object)'
  426     }
  427 
  428     void testVoidReturnTypeInferrence() {
  429         assertScript '''
  430         Object m() {
  431           def s = '1234'
  432           println 'Hello'
  433         }
  434         '''
  435     }
  436 
  437     // GROOVY-5237
  438     void testGenericTypeArgumentAsField() {
  439         assertScript '''
  440             class Container<T> {
  441                 private T initialValue
  442                 Container(T initialValue) { this.initialValue = initialValue }
  443                 T get() { initialValue }
  444             }
  445             Container<Date> c = new Container<Date>(new Date())
  446             long time = c.get().time
  447         '''
  448     }
  449 
  450     // GROOVY-9860
  451     void testGenericTypeArgumentInCtorCall() {
  452         assertScript '''
  453             def <T> void test() {
  454                 def bind = { T a, T b ->
  455                     new Tuple2<T, T>(a, b)
  456                 }
  457                 assert bind('foo', 'bar').toString() == '[foo, bar]'
  458             }
  459             test()
  460         '''
  461     }
  462 
  463     void testReturnAnntationClass() {
  464         assertScript '''
  465             import java.lang.annotation.Documented
  466             Documented annotation = Deprecated.getAnnotation(Documented)
  467         '''
  468     }
  469 
  470     void testReturnListOfParameterizedType() {
  471         assertScript '''
  472             class A {}
  473             class B extends A { void bar() {} }
  474             public <T extends A> List<T> foo() { [] }
  475 
  476             List<B> list = foo()
  477             list.add(new B())
  478         '''
  479     }
  480 
  481     // GROOVY-6126
  482     void testChoosesCorrectMethodOfParameterizedReturnType() {
  483         assertScript '''
  484             class Loader {
  485                 public <T> T load(Class<T> entityClass, Serializable id) {entityClass.newInstance()}
  486                 public void load(final Object entity, final Serializable id) {}
  487             }
  488 
  489             class MyClass<D> {
  490                 Class<D> persistentClass
  491                 Loader hibernateTemplate = new Loader()
  492                 MyClass(Class<D> c) {
  493                     this.persistentClass = c
  494                 }
  495 
  496                 D load(Serializable id) {
  497                     id = convertIdentifier(id)
  498                     if (id != null) {
  499                         return hibernateTemplate.load(persistentClass, id)
  500                     }
  501                 }
  502 
  503                 Serializable convertIdentifier(Serializable s) {"1"}
  504             }
  505             class Foo{}
  506 
  507             MyClass<Foo> mc = new MyClass(Foo)
  508             Foo foo = mc.load("2")'''
  509     }
  510 
  511     void testMethodCallWithClassParameterUsingClassLiteralArg() {
  512         assertScript '''
  513             class A {}
  514             class B extends A {}
  515             class Foo {
  516                 void m(Class<? extends A> clazz) {}
  517             }
  518             new Foo().m(B)
  519         '''
  520     }
  521 
  522     void testMethodCallWithClassParameterUsingClassLiteralArgWithoutWrappingClass() {
  523         assertScript '''
  524             class A {}
  525             class B extends A {}
  526             void m(Class<? extends A> clazz) {}
  527             m(B)
  528         '''
  529     }
  530 
  531     // GROOVY-7945
  532     void testSpecialCtorCallWithClassLiteral() {
  533         shouldFailWithMessages '''
  534             abstract class A<X, Y> {
  535                 private final Class<X> x
  536                 private final Class<Y> y
  537 
  538                 A(Class<X> x, Class<Y> y) {
  539                     this.x = x
  540                     this.y = y
  541                 }
  542 
  543                 void test() {
  544                     println("{$x} and {$y}")
  545                 }
  546             }
  547 
  548             class B extends A<String, Integer> {
  549                 B() {
  550                     super(Integer, String)
  551                 }
  552             }
  553 
  554             A<String, Integer> a = new B()
  555             a.test()
  556         ''', 'Cannot call A <String, Integer>#<init>(java.lang.Class <String>, java.lang.Class <Integer>) with arguments [java.lang.Class <java.lang.Integer>, java.lang.Class <java.lang.String>]'
  557     }
  558 
  559     // GROOVY-9460
  560     void testMethodCallWithClassParameterUnbounded() {
  561         assertScript '''
  562             class Bar {
  563                 static void baz(Class<?> target) {
  564                 }
  565             }
  566             class Foo<D> { // cannot be "T" because that matches type parameter in Class
  567                 void test(Class<D> param) {
  568                     Bar.baz(param) // Cannot call Bar#baz(java.lang.Class<?>) with arguments [java.lang.Class<D>]
  569                 }
  570             }
  571             new Foo<String>().test(String.class)
  572         '''
  573     }
  574 
  575     void testConstructorCallWithClassParameterUsingClassLiteralArg() {
  576         assertScript '''
  577             class A {}
  578             class B extends A {}
  579             class C extends B {}
  580             class Foo {
  581                 Foo(Class<? extends A> clazz) {}
  582             }
  583             new Foo(B)
  584             new Foo(C)
  585         '''
  586     }
  587 
  588     void testConstructorCallWithClassParameterUsingClassLiteralArgAndInterface() {
  589         assertScript '''
  590             interface A {}
  591             class B implements A {}
  592             class C extends B {}
  593             class Foo {
  594                 Foo(Class<? extends A> clazz) {}
  595             }
  596             new Foo(B)
  597             new Foo(C)
  598         '''
  599     }
  600 
  601     void testPutMethodWithPrimitiveValue1() {
  602         assertScript '''
  603             def map = new HashMap<String, Integer>()
  604             map.put('hello', 1)
  605         '''
  606     }
  607 
  608     void testPutMethodWithPrimitiveValue2() {
  609         assertScript '''
  610             def map = new HashMap<String, Integer>()
  611             map['hello'] = 1
  612         '''
  613     }
  614 
  615     void testPutMethodWithWrongValueType() {
  616         shouldFailWithMessages '''
  617             def map = new HashMap<String, Integer>()
  618             map.put('hello', new Object())
  619         ''', '[Static type checking] - Cannot find matching method java.util.HashMap#put(java.lang.String, java.lang.Object). Please check if the declared type is correct and if the method exists.'
  620     }
  621 
  622     void testShouldComplainAboutToInteger() {
  623         String code = '''
  624             class Test {
  625                 static test2() {
  626                     if (new Random().nextBoolean()) {
  627                         def a = new ArrayList<String>()
  628                         a << "a" << "b" << "c"
  629                         return a
  630                     } else {
  631                         def b = new LinkedList<Number>()
  632                         b << 1 << 2 << 3
  633                         return b
  634                     }
  635                 }
  636 
  637                 static test() {
  638                     def result = test2()
  639                     result[0].toInteger()
  640                     //result[0].toString()
  641                 }
  642             }
  643             new Test()
  644         '''
  645 
  646         if (config.pluginFactory instanceof AntlrParserPluginFactory) {
  647             shouldFailWithMessages code, 'Cannot find matching method java.lang.Object#getAt(int)'
  648         } else {
  649             shouldFailWithMessages code,
  650                     'Cannot find matching method java.lang.Object#getAt(int)',
  651                     'Cannot find matching method java.lang.Object#toInteger()'
  652         }
  653     }
  654 
  655     void testAssignmentOfNewInstance() {
  656         assertScript '''
  657             class Foo {
  658                 static Class clazz = Date
  659                 public static void main(String... args) {
  660                     @ASTTest(phase=INSTRUCTION_SELECTION, value={
  661                         assert node.getNodeMetaData(INFERRED_TYPE) == OBJECT_TYPE
  662                     })
  663                     def obj = clazz.newInstance()
  664                 }
  665             }
  666         '''
  667     }
  668 
  669     // GROOVY-5415
  670     void testShouldUseMethodGenericType1() {
  671         assertScript '''import groovy.transform.stc.GenericsSTCTest.ClassA
  672         class ClassB {
  673             void bar() {
  674                 def ClassA<Long> a = new ClassA<Long>();
  675                 a.foo(this.getClass());
  676             }
  677         }
  678         new ClassB()
  679         '''
  680     }
  681 
  682     // GROOVY-5415
  683     void testShouldUseMethodGenericType2() {
  684         shouldFailWithMessages '''import groovy.transform.stc.GenericsSTCTest.ClassA
  685         class ClassB {
  686             void bar() {
  687                 def ClassA<Long> a = new ClassA<Long>();
  688                 a.bar(this.getClass());
  689             }
  690         }
  691         new ClassB()
  692         ''', 'Cannot call <X> groovy.transform.stc.GenericsSTCTest$ClassA <Long>#bar(java.lang.Class <Long>) with arguments [java.lang.Class <? extends java.lang.Object>]'
  693     }
  694 
  695     // GROOVY-8961, GROOVY-9915
  696     void testShouldUseMethodGenericType3() {
  697         ['', 'static'].each { mods ->
  698             assertScript """
  699                 $mods void setM(List<String> strings) {
  700                 }
  701                 void test() {
  702                   m = Collections.emptyList() // Cannot assign value of type List<T> to variable of List<String>
  703                 }
  704                 test()
  705             """
  706             assertScript """
  707                 $mods void setM(Collection<String> strings) {
  708                 }
  709                 void test() {
  710                   m = Collections.emptyList()
  711                 }
  712                 test()
  713             """
  714             assertScript """
  715                 $mods void setM(Iterable<String> strings) {
  716                 }
  717                 void test() {
  718                   m = Collections.emptyList()
  719                 }
  720                 test()
  721             """
  722 
  723             shouldFailWithMessages """
  724                 $mods void setM(List<String> strings) {
  725                 }
  726                 void test() {
  727                   m = Collections.<Integer>emptyList()
  728                 }
  729             """, '[Static type checking] - Cannot assign value of type java.util.List <Integer> to variable of type java.util.List <String>'
  730         }
  731     }
  732 
  733     // GROOVY-9734, GROOVY-9915
  734     void testShouldUseMethodGenericType4() {
  735         ['', 'static'].each { mods ->
  736             assertScript """
  737                 $mods void m(List<String> strings) {
  738                 }
  739                 void test() {
  740                   m(Collections.emptyList()) // Cannot call m(List<String>) with arguments [List<T>]
  741                 }
  742                 test()
  743             """
  744             assertScript """
  745                 $mods void m(Collection<String> strings) {
  746                 }
  747                 void test() {
  748                   m(Collections.emptyList())
  749                 }
  750                 test()
  751             """
  752             assertScript """
  753                 $mods void m(Iterable<String> strings) {
  754                 }
  755                 void test() {
  756                   m(Collections.emptyList())
  757                 }
  758                 test()
  759             """
  760         }
  761     }
  762 
  763     // GROOVY-9751
  764     void testShouldUseMethodGenericType5() {
  765         assertScript '''
  766             interface Service {
  767                 Number transform(String s)
  768             }
  769             void test(Service service) {
  770                 Set<Number> numbers = []
  771                 List<String> strings = ['1','2','3']
  772                 numbers.addAll(strings.collect(service.&transform))
  773             }
  774             test({ String s -> Integer.valueOf(s) } as Service)
  775         '''
  776     }
  777 
  778     void testShouldUseMethodGenericType6() {
  779         assertScript '''
  780             @ASTTest(phase=INSTRUCTION_SELECTION, value={
  781                 def type = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
  782                 assert type.equals(CLOSURE_TYPE)
  783                 assert type.getGenericsTypes()[0].getType().equals(STRING_TYPE)
  784             })
  785             def ptr = "".&toString
  786         '''
  787         assertScript '''
  788             @ASTTest(phase=INSTRUCTION_SELECTION, value={
  789                 def type = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
  790                 assert type.equals(CLOSURE_TYPE)
  791                 assert type.getGenericsTypes()[0].getType().equals(Double_TYPE)
  792             })
  793             def ptr = Math.&abs
  794         '''
  795     }
  796 
  797     // GROOVY-9762
  798     void testShouldUseMethodGenericType7() {
  799         for (toList in ['{ list(it) }', 'o -> list(o)', 'this.&list', 'this::list']) {
  800             assertScript """
  801                 def <T> List<T> list(T item) {
  802                     return [item]
  803                 }
  804                 def test() {
  805                     Optional<Integer> opt = Optional.ofNullable(1)
  806                     List<Integer> ret = opt.map($toList).get()
  807                     return ret
  808                 }
  809                 assert test() == [1]
  810             """
  811         }
  812     }
  813 
  814     // GROOVY-9803
  815     void testShouldUseMethodGenericType8() {
  816         assertScript '''
  817             def opt = Optional.of(42)
  818                 .map(Collections::singleton)
  819                 .map(x -> x.first().intValue()) // Cannot find matching method java.lang.Object#intValue()
  820             assert opt.get() == 42
  821         '''
  822         // same as above but with separate type parameter name for each location
  823         assertScript '''
  824             abstract class A<I,O> {
  825                 abstract O apply(I input)
  826             }
  827             class C<T> {
  828                 static <U> C<U> of(U item) {
  829                     new C<U>()
  830                 }
  831                 def <V> C<V> map(A<? super T, ? super V> func) {
  832                     new C<V>()
  833                 }
  834             }
  835             class D {
  836                 static <W> Set<W> wrap(W o) {
  837                 }
  838             }
  839 
  840             void test() {
  841                 def c = C.of(42)
  842                 def d = c.map(D.&wrap)
  843                 def e = d.map(x -> x.first().intValue())
  844             }
  845 
  846             test()
  847         '''
  848     }
  849 
  850     // GROOVY-9945
  851     void testShouldUseMethodGenericType9() {
  852         assertScript '''
  853             interface I<T> {
  854             }
  855             class A<T> implements I<String> {
  856                 def m(T t) { 'works' }
  857             }
  858             class B<T> extends A<T> {
  859             }
  860 
  861             def bee = new B<Float>()
  862             def obj = bee.m(3.14f)
  863             assert obj == 'works'
  864         '''
  865     }
  866 
  867     // GROOVY-5516
  868     void testAddAllWithCollectionShouldBeAllowed() {
  869         assertScript '''import org.codehaus.groovy.transform.stc.ExtensionMethodNode
  870             List<String> list = ['a','b','c']
  871             Collection<String> e = list.findAll { it }
  872             @ASTTest(phase=INSTRUCTION_SELECTION, value={
  873                 def dmt = node.rightExpression.getNodeMetaData(DIRECT_METHOD_CALL_TARGET)
  874                 assert dmt instanceof ExtensionMethodNode == false
  875                 assert dmt.name == 'addAll'
  876                 assert dmt.declaringClass == make(List)
  877             })
  878             boolean r = list.addAll(e)
  879         '''
  880     }
  881 
  882     void testAddAllWithCollectionShouldNotBeAllowed() {
  883         shouldFailWithMessages '''
  884             List<String> list = ['a','b','c']
  885             Collection<Integer> e = (Collection<Integer>) [1,2,3]
  886             boolean r = list.addAll(e)
  887         ''', 'Cannot call java.util.List <java.lang.String>#addAll(java.util.Collection <? extends java.lang.String>) with arguments [java.util.Collection <Integer>]'
  888     }
  889 
  890     // GROOVY-5528
  891     void testAssignmentToInterfaceFromUserClassWithGenerics() {
  892         assertScript '''class UserList<T> extends LinkedList<T> {}
  893         List<String> list = new UserList<String>()
  894         '''
  895     }
  896 
  897     // GROOVY-5559, GROOVY-10010
  898     void testGStringInListShouldNotBeConsideredAsAString() {
  899         String base = '''import org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode as LUB
  900             def bar = 1
  901         '''
  902 
  903         assertScript base + '''
  904             @ASTTest(phase=INSTRUCTION_SELECTION, value={
  905                 assert node.getNodeMetaData(INFERRED_TYPE) == LIST_TYPE
  906                 assert node.getNodeMetaData(INFERRED_TYPE).genericsTypes[0].type instanceof LUB
  907             })
  908             def list = ["foo", "$bar"]
  909         '''
  910 
  911         shouldFailWithMessages base + '''
  912             @ASTTest(phase=INSTRUCTION_SELECTION, value={
  913                 assert node.getNodeMetaData(INFERRED_TYPE) == LIST_TYPE
  914                 assert node.getNodeMetaData(INFERRED_TYPE).genericsTypes[0].type instanceof LUB
  915             })
  916             List<String> list = ["foo", "$bar"]
  917         ''', 'You are trying to use a GString in place of a String'
  918 
  919         shouldFailWithMessages base + '''
  920             @ASTTest(phase=INSTRUCTION_SELECTION, value={
  921                 assert node.getNodeMetaData(INFERRED_TYPE) == LIST_TYPE
  922                 assert node.getNodeMetaData(INFERRED_TYPE).genericsTypes[0].type == GSTRING_TYPE // single element means no LUB
  923             })
  924             List<String> list = ["$bar"]
  925         ''', 'You are trying to use a GString in place of a String'
  926 
  927         shouldFailWithMessages base + '''
  928             void m(List<String> list) {}
  929             m(["foo", "$bar"])
  930         ''', 'You are trying to use a GString in place of a String'
  931     }
  932 
  933     // GROOVY-5559, GROOVY-10010
  934     void testGStringInMapShouldNotBeConsideredAsAString() {
  935         String base = 'def bar = 123'
  936 
  937         shouldFailWithMessages base + '''
  938             Map<String,String> map = [x:"foo", y:"$bar"]
  939         ''', 'You are trying to use a GString in place of a String'
  940 
  941         shouldFailWithMessages base + '''
  942             void m(Map<?,String> map) {}
  943             m([x:"foo", y:"$bar"])
  944         ''', 'You are trying to use a GString in place of a String'
  945 
  946         shouldFailWithMessages base + '''
  947             void m(Map<?,String> map) {}
  948             m(x:"foo", y:"$bar")
  949         ''', 'You are trying to use a GString in place of a String'
  950     }
  951 
  952     // GROOVY-5559: related behaviour
  953     void testGStringString() {
  954         assertScript '''
  955             int i = 1
  956             @ASTTest(phase=INSTRUCTION_SELECTION, value={
  957                 assert node.getNodeMetaData(INFERRED_TYPE) == GSTRING_TYPE
  958             })
  959             def str = "foo$i"
  960             assert str == 'foo1'
  961         '''
  962     }
  963 
  964     // GROOVY-5594
  965     void testMapEntryUsingPropertyNotation() {
  966         assertScript '''
  967         Map.Entry<Date, Integer> entry = null
  968 
  969         @ASTTest(phase=INSTRUCTION_SELECTION, value={
  970             assert node.getNodeMetaData(INFERRED_TYPE) == make(Date)
  971         })
  972         def k = entry?.key
  973 
  974         @ASTTest(phase=INSTRUCTION_SELECTION, value={
  975             assert node.getNodeMetaData(INFERRED_TYPE) == Integer_TYPE
  976         })
  977         def v = entry?.value
  978         '''
  979     }
  980 
  981     void testInferenceFromMap() {
  982         assertScript '''
  983         Map<Date, Integer> map = [:]
  984 
  985         @ASTTest(phase=INSTRUCTION_SELECTION, value={
  986             def infType = node.getNodeMetaData(INFERRED_TYPE)
  987             assert infType == make(Set)
  988             def entryInfType = infType.genericsTypes[0].type
  989             assert entryInfType == make(Map.Entry)
  990             assert entryInfType.genericsTypes[0].type == make(Date)
  991             assert entryInfType.genericsTypes[1].type == Integer_TYPE
  992         })
  993         def entries = map?.entrySet()
  994         '''
  995     }
  996 
  997     void testInferenceFromListOfMaps() {
  998         assertScript '''
  999         List<Map<Date, Integer>> maps = []
 1000 
 1001         @ASTTest(phase=INSTRUCTION_SELECTION, value={
 1002             def listType = node.getNodeMetaData(INFERRED_TYPE)
 1003             assert listType == Iterator_TYPE
 1004             def infType = listType.genericsTypes[0].type
 1005             assert infType == make(Map)
 1006             assert infType.genericsTypes[0].type == make(Date)
 1007             assert infType.genericsTypes[1].type == Integer_TYPE
 1008         })
 1009         def iter = maps?.iterator()
 1010         '''
 1011     }
 1012 
 1013     void testAssignNullMapWithGenerics() {
 1014         assertScript '''
 1015             Map<String, Integer> foo = null
 1016             Integer result = foo?.get('a')
 1017             assert result == null
 1018         '''
 1019     }
 1020 
 1021     void testAssignNullListWithGenerics() {
 1022         assertScript '''
 1023             List<Integer> foo = null
 1024             Integer result = foo?.get(0)
 1025             assert result == null
 1026         '''
 1027     }
 1028 
 1029     void testAssignNullListWithGenericsWithSequence() {
 1030         assertScript '''
 1031             List<Integer> foo = [1]
 1032             foo = null
 1033             Integer result = foo?.get(0)
 1034             assert result == null
 1035         '''
 1036     }
 1037 
 1038     // GROOVY-10107
 1039     void testAssignNullTypeParameterWithUpperBounds() {
 1040         assertScript '''
 1041             class C<T extends Number> {
 1042                 void m() {
 1043                     T n = null
 1044                 }
 1045             }
 1046             new C<Long>().m()
 1047         '''
 1048     }
 1049 
 1050     void testMethodCallWithArgumentUsingNestedGenerics() {
 1051         assertScript '''
 1052            ThreadLocal<Map<Integer, String>> cachedConfigs = new ThreadLocal<Map<Integer, String>>()
 1053            def configs = new HashMap<Integer, String>()
 1054            cachedConfigs.set configs
 1055         '''
 1056     }
 1057 
 1058     void testInferDiamondUsingAIC() {
 1059         shouldFailWithMessages '''
 1060             Map<String,Date> map = new HashMap<>() {}
 1061         ''', 'Cannot use diamond <> with anonymous inner classes'
 1062     }
 1063 
 1064     // GROOVY-5614
 1065     void testInferDiamondForFields() {
 1066         assertScript '''
 1067             class Rules {
 1068                 @ASTTest(phase=INSTRUCTION_SELECTION, value={
 1069                     def type = node.initialExpression.getNodeMetaData(INFERRED_TYPE)
 1070                     assert type == make(HashMap)
 1071                     assert type.genericsTypes.length == 2
 1072                     assert type.genericsTypes[0].type == Integer_TYPE
 1073                     assert type.genericsTypes[1].type == make(Date)
 1074                 })
 1075 
 1076                 final Map<Integer, Date> bindings1  = new HashMap<>();
 1077                 @ASTTest(phase=INSTRUCTION_SELECTION, value={
 1078                     def type = node.initialExpression.getNodeMetaData(INFERRED_TYPE)
 1079                     assert type == make(HashMap)
 1080                     assert type.genericsTypes.length == 2
 1081                     assert type.genericsTypes[0].type == STRING_TYPE
 1082                     assert type.genericsTypes[1].type == STRING_TYPE
 1083                 })
 1084                 final Map<String, String> bindings2 = new HashMap<>();
 1085             }
 1086             def r = new Rules()
 1087 
 1088             r.bindings1[3] = new Date()
 1089             assert r.bindings1.containsKey(3)
 1090 
 1091             r.bindings2['a'] = 'A'
 1092             r.bindings2.put('b', 'B')
 1093 
 1094         '''
 1095     }
 1096     void testInferDiamondForAssignment() {
 1097         assertScript '''
 1098             @ASTTest(phase=INSTRUCTION_SELECTION, value={
 1099                 def type = node.getNodeMetaData(INFERRED_TYPE)
 1100                 assert type == make(HashMap)
 1101                 assert type.genericsTypes.length == 2
 1102                 assert type.genericsTypes[0].type == STRING_TYPE
 1103                 assert type.genericsTypes[1].type == STRING_TYPE
 1104                 type = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
 1105                 assert type == make(HashMap)
 1106                 assert type.genericsTypes.length == 2
 1107                 assert type.genericsTypes[0].type == STRING_TYPE
 1108                 assert type.genericsTypes[1].type == STRING_TYPE
 1109             })
 1110             Map<String, String> map = new HashMap<>()
 1111         '''
 1112     }
 1113     void testInferDiamondForAssignmentWithDates() {
 1114         assertScript '''
 1115             @ASTTest(phase=INSTRUCTION_SELECTION, value={
 1116                 def DATE = make(Date)
 1117                 def type = node.getNodeMetaData(INFERRED_TYPE)
 1118                 assert type == make(HashMap)
 1119                 assert type.genericsTypes.length == 2
 1120                 assert type.genericsTypes[0].type == DATE
 1121                 assert type.genericsTypes[1].type == DATE
 1122                 type = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
 1123                 assert type == make(HashMap)
 1124                 assert type.genericsTypes.length == 2
 1125                 assert type.genericsTypes[0].type == DATE
 1126                 assert type.genericsTypes[1].type == DATE
 1127             })
 1128             Map<Date, Date> map = new HashMap<>()
 1129         '''
 1130     }
 1131     void testInferDiamondForAssignmentWithDatesAndIllegalKeyUsingPut() {
 1132         shouldFailWithMessages '''
 1133             @ASTTest(phase=INSTRUCTION_SELECTION, value={
 1134                 def DATE = make(Date)
 1135                 def type = node.getNodeMetaData(INFERRED_TYPE)
 1136                 assert type == make(HashMap)
 1137                 assert type.genericsTypes.length == 2
 1138                 assert type.genericsTypes[0].type == DATE
 1139                 assert type.genericsTypes[1].type == DATE
 1140                 type = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
 1141                 assert type == make(HashMap)
 1142                 assert type.genericsTypes.length == 2
 1143                 assert type.genericsTypes[0].type == DATE
 1144                 assert type.genericsTypes[1].type == DATE
 1145             })
 1146             Map<Date, Date> map = new HashMap<>()
 1147             map.put('foo', new Date())
 1148         ''', '[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.'
 1149     }
 1150     void testInferDiamondForAssignmentWithDatesAndIllegalKeyUsingSquareBracket() {
 1151         shouldFailWithMessages '''
 1152             @ASTTest(phase=INSTRUCTION_SELECTION, value={
 1153                 def DATE = make(Date)
 1154                 def type = node.getNodeMetaData(INFERRED_TYPE)
 1155                 assert type == make(HashMap)
 1156                 assert type.genericsTypes.length == 2
 1157                 assert type.genericsTypes[0].type == DATE
 1158                 assert type.genericsTypes[1].type == DATE
 1159                 type = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
 1160                 assert type == make(HashMap)
 1161                 assert type.genericsTypes.length == 2
 1162                 assert type.genericsTypes[0].type == DATE
 1163                 assert type.genericsTypes[1].type == DATE
 1164             })
 1165             Map<Date, Date> map = new HashMap<>()
 1166             map['foo'] = new Date()
 1167         ''', 'Cannot call <K,V> java.util.HashMap <java.util.Date, java.util.Date>#putAt(java.util.Date, java.util.Date) with arguments [java.lang.String, java.util.Date]'
 1168     }
 1169     void testInferDiamondForAssignmentWithDatesAndIllegalValueUsingPut() {
 1170         shouldFailWithMessages '''
 1171             @ASTTest(phase=INSTRUCTION_SELECTION, value={
 1172                 def DATE = make(Date)
 1173                 def type = node.getNodeMetaData(INFERRED_TYPE)
 1174                 assert type == make(HashMap)
 1175                 assert type.genericsTypes.length == 2
 1176                 assert type.genericsTypes[0].type == DATE
 1177                 assert type.genericsTypes[1].type == DATE
 1178                 type = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
 1179                 assert type == make(HashMap)
 1180                 assert type.genericsTypes.length == 2
 1181                 assert type.genericsTypes[0].type == DATE
 1182                 assert type.genericsTypes[1].type == DATE
 1183             })
 1184             Map<Date, Date> map = new HashMap<>()
 1185             map.put(new Date(), 'foo')
 1186         ''', '[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.'
 1187     }
 1188     void testInferDiamondForAssignmentWithDatesAndIllegalValueUsingSquareBracket() {
 1189         shouldFailWithMessages '''
 1190             @ASTTest(phase=INSTRUCTION_SELECTION, value={
 1191                 def DATE = make(Date)
 1192                 def type = node.getNodeMetaData(INFERRED_TYPE)
 1193                 assert type == make(HashMap)
 1194                 assert type.genericsTypes.length == 2
 1195                 assert type.genericsTypes[0].type == DATE
 1196                 assert type.genericsTypes[1].type == DATE
 1197                 type = node.rightExpression.getNodeMetaData(INFERRED_TYPE)
 1198                 assert type == make(HashMap)
 1199                 assert type.genericsTypes.length == 2
 1200                 assert type.genericsTypes[0].type == DATE
 1201                 assert type.genericsTypes[1].type == DATE
 1202             })
 1203             Map<Date, Date> map = new HashMap<>()
 1204             map[new Date()] = 'foo'
 1205         ''', 'Cannot call <K,V> java.util.HashMap <java.util.Date, java.util.Date>#putAt(java.util.Date, java.util.Date) with arguments [java.util.Date, java.lang.String]'
 1206     }
 1207 
 1208     void testCallMethodWithParameterizedArrayList() {
 1209         assertScript '''
 1210         class MyUtility {
 1211             def methodOne() {
 1212                 def someFiles = new ArrayList<File>()
 1213                 def someString = ''
 1214                 methodTwo someString, someFiles
 1215             }
 1216 
 1217             def methodTwo(String s, List<File> files) {}
 1218         }
 1219         new MyUtility()
 1220         '''
 1221     }
 1222 
 1223     void testGenericTypeArrayOfDGMMethod() {
 1224         assertScript '''
 1225             int[] arr = [0,1,2,3]
 1226             assert arr.findAll() == [1,2,3]
 1227         '''
 1228     }
 1229 
 1230     // GROOVY-5617
 1231     void testIntermediateListAssignmentOfGStrings() {
 1232         assertScript '''
 1233         def test() {
 1234             @ASTTest(phase=INSTRUCTION_SELECTION, value={
 1235                 def type = node.getNodeMetaData(INFERRED_TYPE)
 1236                 assert type == make(List)
 1237                 assert type.genericsTypes.length==1
 1238                 assert type.genericsTypes[0].type == GSTRING_TYPE
 1239             })
 1240             List<GString> dates = ["${new Date()-1}", "${new Date()}", "${new Date()+1}"]
 1241             dates*.toUpperCase()
 1242             @ASTTest(phase=INSTRUCTION_SELECTION, value={
 1243                 def type = node.getNodeMetaData(INFERRED_TYPE)
 1244                 assert type == make(List)
 1245                 assert type.genericsTypes.length==1
 1246                 assert type.genericsTypes[0].type == GSTRING_TYPE
 1247             })
 1248             List<GString> copied = []
 1249             copied.addAll(dates)
 1250             List<String> upper = copied*.toUpperCase()
 1251         }
 1252         test()
 1253         '''
 1254     }
 1255 
 1256     // GROOVY-5650
 1257     void testRegressionInGenericsTypeInference() {
 1258         assertScript '''import groovy.transform.stc.GenericsSTCTest.JavaClassSupport as JavaClass
 1259         List<JavaClass.StringContainer> containers = new ArrayList<>();
 1260         containers.add(new JavaClass.StringContainer());
 1261         List<String> strings = JavaClass.unwrap(containers);
 1262         '''
 1263     }
 1264 
 1265     // In Groovy, we do not throw warnings (in general) and in that situation, not for unchecked
 1266     // assignments like in Java
 1267     // In the following test, the LHS of the assignment uses generics, while the RHS does not.
 1268     // As we have the concept of flow typing too, we are facing a problem: what inferred type is the RHS?
 1269     void testUncheckedAssignment() {
 1270         assertScript '''
 1271             @ASTTest(phase=INSTRUCTION_SELECTION, value={
 1272                 def ift = node.getNodeMetaData(INFERRED_TYPE)
 1273                 assert ift == make(List)
 1274                 assert ift.isUsingGenerics()
 1275                 def gts = ift.genericsTypes
 1276                 assert gts.length==1
 1277                 assert gts[0].type == STRING_TYPE
 1278             })
 1279             List<String> list = (List) null
 1280         '''
 1281     }
 1282 
 1283     void testUncheckedAssignmentWithSuperInterface() {
 1284         assertScript '''
 1285             @ASTTest(phase=INSTRUCTION_SELECTION, value={
 1286                 def ift = node.getNodeMetaData(INFERRED_TYPE)
 1287                 assert ift == make(List)
 1288                 assert ift.isUsingGenerics()
 1289                 def gts = ift.genericsTypes
 1290                 assert gts.length==1
 1291                 assert gts[0].type == STRING_TYPE
 1292             })
 1293             Iterable<String> list = (List) null
 1294         '''
 1295     }
 1296 
 1297     void testIncompatibleGenericsForTwoArguments() {
 1298         shouldFailWithMessages '''
 1299             public <T> void printEqual(T arg1, T arg2) {
 1300                 println arg1 == arg2
 1301             }
 1302             printEqual(1, 'foo')
 1303         ''', '#printEqual(T, T) with arguments [int, java.lang.String]'
 1304     }
 1305     void testIncompatibleGenericsForTwoArgumentsUsingEmbeddedPlaceholder() {
 1306         shouldFailWithMessages '''
 1307             public <T> void printEqual(T arg1, List<T> arg2) {
 1308                 println arg1 == arg2
 1309             }
 1310             printEqual(1, ['foo'])
 1311         ''', '#printEqual(T, java.util.List <T>) with arguments [int, java.util.List <java.lang.String>]'
 1312     }
 1313 
 1314     // GROOVY-9902
 1315     void testIncompatibleArgumentsForGenericArgument_IncludingDelegation() {
 1316         shouldFailWithMessages '''
 1317             class Holder<Unknown> {
 1318                 TypedProperty<Number, Unknown> numberProperty = prop(Number)
 1319                 TypedProperty<String, Unknown> stringProperty = prop(String)
 1320 
 1321                 def <T> TypedProperty<T, Unknown> prop(Class<T> clazz) {
 1322                     return new TypedProperty<T, Unknown>(clazz: clazz)
 1323                 }
 1324 
 1325                 // Note: type argument of Holder cannot be supplied to value attribute of @DelegatesTo
 1326                 def <T> T of(@DelegatesTo(value=Holder, strategy=Closure.DELEGATE_FIRST) Closure<T> c) {
 1327                     this.with(c)
 1328                 }
 1329             }
 1330 
 1331             class TypedProperty<X, Y> {
 1332                 Class<X> clazz
 1333 
 1334                 void eq(X x) {
 1335                     assert x.class == clazz : "x.class is ${x.class} not ${clazz}"
 1336                 }
 1337             }
 1338 
 1339             void test(Holder<Object> h) {
 1340                 h.stringProperty.eq("${0}") // STC error
 1341                 h.of { // <-- 2nd type parameter discarded
 1342                     stringProperty.eq(1234) // expect STC error
 1343                     numberProperty.eq("xx") // expect STC error
 1344                 }
 1345             }
 1346 
 1347             test(new Holder<Object>())
 1348         ''',
 1349         'Cannot call TypedProperty <String, Object>#eq(java.lang.String) with arguments [groovy.lang.GString]',
 1350         'Cannot call TypedProperty <String, Unknown>#eq(java.lang.String) with arguments [int]',
 1351         'Cannot call TypedProperty <Number, Unknown>#eq(java.lang.Number) with arguments [java.lang.String]'
 1352     }
 1353 
 1354     void testGroovy5748() {
 1355         assertScript '''
 1356             interface IStack<T> {
 1357                 INonEmptyStack<T, ? extends IStack<T>> push(T x)
 1358             }
 1359 
 1360             interface IEmptyStack<T> extends IStack<T> {
 1361                 INonEmptyStack<T, IEmptyStack<T>> push(T x)
 1362             }
 1363 
 1364             interface INonEmptyStack<T, TStackBeneath extends IStack<T>> extends IStack<T> {
 1365                 T getTop()
 1366 
 1367                 TStackBeneath pop()
 1368 
 1369                 INonEmptyStack<T, INonEmptyStack<T, TStackBeneath>> push(T x)
 1370             }
 1371 
 1372             class EmptyStack<T> implements IEmptyStack<T> {
 1373                 INonEmptyStack<T, IEmptyStack<T>> push(T x) {
 1374                     new NonEmptyStack<T, IEmptyStack<T>>(x, this)
 1375                 }
 1376             }
 1377 
 1378             class NonEmptyStack<T, TStackBeneath extends IStack<T>>
 1379                     implements INonEmptyStack<T, TStackBeneath> {
 1380                 private final TStackBeneath stackBeneathTop;
 1381                 private final T top
 1382 
 1383                 NonEmptyStack(T top, TStackBeneath stackBeneathTop) {
 1384                     this.top = top
 1385                     this.stackBeneathTop = stackBeneathTop
 1386                 }
 1387 
 1388                 T getTop() {
 1389                     top
 1390                 }
 1391 
 1392                 TStackBeneath pop() {
 1393                     stackBeneathTop
 1394                 }
 1395 
 1396                 INonEmptyStack<T, INonEmptyStack<T, TStackBeneath>> push(T x) {
 1397                     new NonEmptyStack<T, INonEmptyStack<T, TStackBeneath>>(x, this)
 1398                 }
 1399             }
 1400 
 1401             final IStack<Integer> stack = new EmptyStack<Integer>()
 1402 
 1403             def oneInteger = stack.push(1)
 1404             assert oneInteger.getTop() == 1
 1405 
 1406             def twoIntegers = stack.push(1).push(2)
 1407             assert twoIntegers.getTop() == 2
 1408 
 1409             def oneIntegerAgain = stack.push(1).push(2).pop()
 1410             assert oneIntegerAgain.getTop() == 1 // BOOM!!!!
 1411         '''
 1412     }
 1413 
 1414     // GROOVY-5758
 1415     void testShouldNotForbidAssignmentToString() {
 1416         assertScript '''
 1417             class A {
 1418                 public String foo
 1419             }
 1420             new A().foo = new ArrayList()
 1421         '''
 1422     }
 1423 
 1424     // GROOVY-5735
 1425     void testCorrespondingParameterType() {
 1426         assertScript '''
 1427         public <T> void someMethod (java.lang.Class<T> clazz, T object) {}
 1428 
 1429         void method() {
 1430             List<String> list = null
 1431             someMethod(java.util.List.class, list)
 1432         }
 1433 
 1434         method()
 1435         '''
 1436     }
 1437 
 1438     void testCorrectlyBoundedByWildcardGenericParameterType() {
 1439         assertScript '''
 1440             class Foo {
 1441                 static <T extends List<?>> void bar(T a) {}
 1442             }
 1443             Foo.bar(['abc'])
 1444         '''
 1445     }
 1446 
 1447     void testCorrectlyBoundedByExtendsGenericParameterType1() {
 1448         assertScript '''
 1449             class Foo {
 1450                 static <T extends List<? extends CharSequence>> void bar(T a) {}
 1451             }
 1452             Foo.bar(['abc'])
 1453         '''
 1454     }
 1455 
 1456     // GROOVY-8960
 1457     void testCorrectlyBoundedByExtendsGenericParameterType2() {
 1458         File parentDir = File.createTempDir()
 1459         config.with {
 1460             targetDirectory = File.createTempDir()
 1461             jointCompilationOptions = [stubDir: File.createTempDir()]
 1462         }
 1463         try {
 1464             def a = new File(parentDir, 'aJavaClass.java')
 1465             a.write '''
 1466                 import java.io.Serializable;
 1467                 public class aJavaClass<A extends Serializable>  {
 1468                     public static <A extends Serializable> aJavaClass<A> create(A a) {
 1469                         return new aJavaClass<>(a);
 1470                     }
 1471                     private aJavaClass(A a) {
 1472                     }
 1473                     public enum anEnum {
 1474                         entry1;
 1475                     }
 1476                 }
 1477             '''
 1478             def b = new File(parentDir, 'aGroovyClass.groovy')
 1479             b.write '''
 1480                 import aJavaClass
 1481                 class aGroovyClass {
 1482                     static main(args) {
 1483                         def out = aJavaClass.create(aJavaClass.anEnum.entry1)
 1484                         assert out != null
 1485                     }
 1486                 }
 1487             '''
 1488 
 1489             def loader = new GroovyClassLoader(this.class.classLoader)
 1490             def cu = new JavaAwareCompilationUnit(config, loader)
 1491             cu.addSources(a, b)
 1492             cu.compile()
 1493 
 1494             loader.loadClass('aGroovyClass').main()
 1495         } finally {
 1496             parentDir.deleteDir()
 1497             config.targetDirectory.deleteDir()
 1498             config.jointCompilationOptions.stubDir.deleteDir()
 1499         }
 1500     }
 1501 
 1502     void testCorrectlyBoundedBySuperGenericParameterType() {
 1503         assertScript '''
 1504             class Foo {
 1505                 static <T extends List<? super CharSequence>> void bar(T a) {}
 1506             }
 1507             Foo.bar([new Object()])
 1508         '''
 1509     }
 1510 
 1511     void testCorrectlyBoundedByExtendsPlaceholderParameterType() {
 1512         assertScript '''
 1513             class Foo {
 1514                 static <T extends List<? extends CharSequence>> void bar(T a) {}
 1515             }
 1516             class Baz {
 1517                 static <T extends List<? extends String>> void qux(T a) {
 1518                     Foo.bar(a)
 1519                 }
 1520             }
 1521             Baz.qux(['abc'])
 1522         '''
 1523     }
 1524 
 1525     void testCorrectlyBoundedBySuperPlaceholderParameterType() {
 1526         assertScript '''
 1527             class Foo {
 1528                 static <T extends List<? super CharSequence>> void bar(T a) {}
 1529             }
 1530             class Baz {
 1531                 static <T extends List<? super Object>> void qux(T a) {
 1532                     Foo.bar(a)
 1533                 }
 1534             }
 1535             Baz.qux([new Object()])
 1536         '''
 1537     }
 1538 
 1539     void testCorrectlyBoundedSubtypeGenericParameterType() {
 1540         assertScript '''
 1541             class Foo {
 1542                 static <T extends Collection<? extends CharSequence>> void bar(T a) {}
 1543             }
 1544             Foo.bar(['abc'])
 1545         '''
 1546     }
 1547 
 1548     void testOutOfBoundsByExtendsGenericParameterType() {
 1549         shouldFailWithMessages '''
 1550             class Foo {
 1551                 static <T extends List<? extends CharSequence>> void bar(T a) {}
 1552             }
 1553             Foo.bar([new Object()])
 1554         ''', 'Cannot call <T extends java.util.List<? extends java.lang.CharSequence>> Foo#bar(T) with arguments [java.util.List <java.lang.Object>]'
 1555     }
 1556 
 1557     void testOutOfBoundsBySuperGenericParameterType() {
 1558         shouldFailWithMessages '''
 1559             class Foo {
 1560                 static <T extends List<? super CharSequence>> void bar(T a) {}
 1561             }
 1562             Foo.bar(['abc'])
 1563         ''', 'Cannot call <T extends java.util.List<? super java.lang.CharSequence>> Foo#bar(T) with arguments [java.util.List <java.lang.String>]'
 1564     }
 1565 
 1566     void testOutOfBoundsByExtendsPlaceholderParameterType() {
 1567         shouldFailWithMessages '''
 1568             class Foo {
 1569                 static <T extends List<? extends CharSequence>> void bar(T a) {}
 1570             }
 1571             class Baz {
 1572                 static <T extends List<Object>> void qux(T a) {
 1573                     Foo.bar(a)
 1574                 }
 1575             }
 1576             Baz.qux([new Object()])
 1577         ''', 'Cannot call <T extends java.util.List<? extends java.lang.CharSequence>> Foo#bar(T) with arguments [java.util.List <Object>]'
 1578     }
 1579 
 1580     void testOutOfBoundsBySuperPlaceholderParameterType() {
 1581         shouldFailWithMessages '''
 1582             class Foo {
 1583                 static <T extends List<? super CharSequence>> void bar(T a) {}
 1584             }
 1585             class Baz {
 1586                 static <T extends List<String>> void qux(T a) {
 1587                     Foo.bar(a)
 1588                 }
 1589             }
 1590             Baz.qux(['abc'])
 1591         ''', 'Cannot call <T extends java.util.List<? super java.lang.CharSequence>> Foo#bar(T) with arguments [java.util.List <String>] '
 1592     }
 1593 
 1594     // GROOVY-5721
 1595     void testExtractComponentTypeFromSubclass() {
 1596         assertScript '''
 1597         class MyList extends ArrayList<Double> {}
 1598 
 1599         List<Double> list1 = new ArrayList<Double>()
 1600         list1 << 0.0d
 1601 
 1602         // OK
 1603         Double d1 = list1.get(0)
 1604 
 1605         //---------------------------
 1606 
 1607         List<Double> list2 = new MyList()
 1608         list2 << 0.0d
 1609 
 1610         //Groovyc: [Static type checking] - Cannot assign value of type java.lang.Object to variable of type java.lang.Double
 1611         Double d2 = list2.get(0)
 1612 
 1613         //---------------------------
 1614 
 1615         MyList list3 = new MyList()
 1616         list3 << 0.0d
 1617 
 1618         //Groovyc: [Static type checking] - Cannot assign value of type java.lang.Object to variable of type java.lang.Double
 1619         Double d3 = list3.get(0)
 1620         '''
 1621 
 1622     }
 1623 
 1624     // GROOVY-5724
 1625     void testJUnitHamcrest() {
 1626         assertScript '''
 1627             public class Matcher<T> {}
 1628             public <T> void assertThat(T obj, Matcher<T> matcher) {}
 1629             public <T> Matcher<T> notNullValue() {}
 1630             String result = '12345'.substring(2)
 1631             // assert
 1632             assertThat(result, notNullValue())
 1633         '''
 1634     }
 1635 
 1636     // GROOVY-8103
 1637     void testJUnitFestAssert() {
 1638         assertScript '''
 1639             import static Fluent.*
 1640             import Util.Ours
 1641 
 1642             class Fluent {
 1643                 static FluentAPI  fluent(String s) { return new FluentAPI() }
 1644                 static <T extends FluentExtension> T fluent(T t) { return t }
 1645             }
 1646 
 1647             class FluentAPI {
 1648                 FluentAPI isEqualTo(String s) { return this }
 1649             }
 1650 
 1651             interface FluentExtension {
 1652             }
 1653 
 1654             class Util {
 1655                 static class Ours implements FluentExtension {
 1656                     Ours isSimilarTo(String json) { return this }
 1657                 }
 1658                 static Ours factory(String json) { new Ours() }
 1659             }
 1660 
 1661             void test() {
 1662                 fluent('string').isEqualTo('x') // fine
 1663                 fluent(new Ours()).isSimilarTo('') // fine
 1664                 fluent(Util.factory('{}')).isSimilarTo('{"key":"val"}') // STC error
 1665             }
 1666 
 1667             test()
 1668         '''
 1669     }
 1670 
 1671     // GROOVY-5836
 1672     void testShouldFindMethodEvenIfUsingGenerics() {
 1673         assertScript '''
 1674             class Test<T> {
 1675                 void transform(boolean passThroughNulls, Closure<T> mapper) {}
 1676                 void transformAll(boolean passThroughNulls, Closure<T>... mappers) {
 1677                     for (m in mappers) {
 1678                         transform passThroughNulls, m
 1679                     }
 1680                 }
 1681             }
 1682             new Test()
 1683         '''
 1684     }
 1685 
 1686     // GROOVY-10196
 1687     void testShouldFindMethodEvenWithRepeatNames() {
 1688         assertScript '''
 1689             interface M<K,V> {
 1690             }
 1691             interface MM<K,V> extends M<K,List<V>> {
 1692                 void add(K key, V val)
 1693             }
 1694             class MMA<K,V> implements MM<K,V> {
 1695                 @Override
 1696                 void add(K key, V val) {
 1697                 }
 1698             }
 1699             class LMM<K,V> extends MMA<K,V> {
 1700             }
 1701 
 1702             MM<String,String> map = new LMM<>()
 1703             map.add('foo','bar')
 1704         '''
 1705     }
 1706 
 1707     // GROOVY-5893
 1708     @NotYetImplemented
 1709     void testPlusInClosure() {
 1710         assertScript '''
 1711         def list = [1, 2, 3]
 1712 
 1713         @ASTTest(phase=INSTRUCTION_SELECTION,value={
 1714             assert node.getNodeMetaData(INFERRED_TYPE) == int_TYPE
 1715         })
 1716         def sum = 0
 1717         list.each { int i -> sum = sum+i }
 1718         assert sum == 6
 1719 
 1720         sum = 0
 1721         list.each { int i -> sum += i }
 1722         assert sum == 6
 1723 
 1724         @ASTTest(phase=INSTRUCTION_SELECTION, value={
 1725             assert node.getNodeMetaData(INFERRED_TYPE) == Integer_TYPE
 1726         })
 1727         def sumWithInject = list.inject(0, { int x, int y -> x + y })
 1728         sum = sumWithInject
 1729         assert sum == 6
 1730         '''
 1731     }
 1732 
 1733     void testShouldNotCreateStackOverflow() {
 1734         assertScript '''
 1735             class Element {
 1736               Iterator<List<Element>> multi() {
 1737                 [ [ ] ].iterator()
 1738               }
 1739             }
 1740             new Element()
 1741         '''
 1742 
 1743         // GROOVY-9822
 1744         config.with {
 1745             targetDirectory = File.createTempDir()
 1746             jointCompilationOptions = [memStub: true]
 1747         }
 1748         File parentDir = File.createTempDir()
 1749         try {
 1750             def a = new File(parentDir, 'Types.java')
 1751             a.write '''
 1752                 import java.io.*;
 1753                 import java.util.*;
 1754 
 1755                 // from org.apache.tinkerpop:gremlin-core:3.4.8
 1756 
 1757                 interface TraversalStrategy<S extends TraversalStrategy> extends Serializable, Comparable<Class<? extends TraversalStrategy>> {
 1758                     interface VerificationStrategy extends TraversalStrategy<VerificationStrategy> {
 1759                     }
 1760                 }
 1761                 abstract class AbstractTraversalStrategy<S extends TraversalStrategy> implements TraversalStrategy<S> {
 1762                 }
 1763                 abstract // don't want to implement Comparable
 1764                 class ReadOnlyStrategy extends AbstractTraversalStrategy<TraversalStrategy.VerificationStrategy>
 1765                         implements TraversalStrategy.VerificationStrategy {
 1766                     static ReadOnlyStrategy instance() { return null; }
 1767                 }
 1768 
 1769                 interface TraversalSource extends Cloneable, AutoCloseable {
 1770                     default TraversalSource withStrategies(TraversalStrategy... strategies) {
 1771                         return null;
 1772                     }
 1773                 }
 1774                 abstract // don't want to implement AutoCloseable
 1775                 class GraphTraversalSource implements TraversalSource {
 1776                     @Override
 1777                     public GraphTraversalSource withStrategies(TraversalStrategy... strategies) {
 1778                         return (GraphTraversalSource) TraversalSource.super.withStrategies(strategies);
 1779                     }
 1780                 }
 1781                 class Graph {
 1782                     public <C extends TraversalSource> C traversal(Class<C> c) {
 1783                         return null;
 1784                     }
 1785                     public GraphTraversalSource traversal() {
 1786                         return null;
 1787                     }
 1788                 }
 1789             '''
 1790             def b = new File(parentDir, 'Script.groovy')
 1791             b.write '''
 1792                 GraphTraversalSource test(Graph graph) {
 1793                     def strategy = ReadOnlyStrategy.instance()
 1794                     graph.traversal().withStrategies(strategy)
 1795                 }
 1796             '''
 1797 
 1798             def loader = new GroovyClassLoader(this.class.classLoader)
 1799             def cu = new JavaAwareCompilationUnit(config, loader)
 1800             cu.addSources(a, b)
 1801             cu.compile()
 1802         } finally {
 1803             parentDir.deleteDir()
 1804             config.targetDirectory.deleteDir()
 1805         }
 1806     }
 1807 
 1808     void testRegressionInConstructorCheck() {
 1809         assertScript '''
 1810             new ArrayList(['a','b','c'].collect { String it -> it.toUpperCase()})
 1811         '''
 1812     }
 1813 
 1814     void testReturnTypeInferenceWithMethodUsingWildcard() {
 1815         assertScript '''
 1816             public Object createInstance(Class<?> projectComponentClass, String foo) { projectComponentClass.newInstance() }
 1817             createInstance(LinkedList, 'a')
 1818         '''
 1819     }
 1820 
 1821     // GROOVY-6051
 1822     void testGenericsReturnTypeInferenceShouldNotThrowNPE() {
 1823         assertScript '''
 1824         class Bar {
 1825           public static List<Date> bar(List<Date> dummy) {}
 1826         }
 1827         class Foo extends Bar {
 1828             static public Date genericItem() {
 1829                 @ASTTest(phase=INSTRUCTION_SELECTION, value={
 1830                     def inft = node.getNodeMetaData(INFERRED_TYPE)
 1831                     assert inft == make(List)
 1832                     assert inft.genericsTypes[0].type == make(Date)
 1833                 })
 1834                 def res = bar(null)
 1835 
 1836                 res[0]
 1837             }
 1838         }
 1839         new Foo()
 1840         '''
 1841     }
 1842 
 1843     // GROOVY-6035
 1844     void testReturnTypeInferenceWithClosure() {
 1845         assertScript '''import org.codehaus.groovy.ast.expr.ClosureExpression
 1846         class CTypeTest {
 1847 
 1848           public static void test1(String[] args) {
 1849 
 1850             // Cannot assign value of type java.lang.Object to variable of type CTypeTest
 1851             @ASTTest(phase=INSTRUCTION_SELECTION,value={
 1852                 def cl = node.rightExpression.arguments[0]
 1853                 assert cl instanceof ClosureExpression
 1854                 def type = cl.getNodeMetaData(INFERRED_TYPE)
 1855                 assert type == make(Closure)
 1856                 assert type.isUsingGenerics()
 1857                 assert type.genericsTypes
 1858                 assert type.genericsTypes[0].type.name == 'CTypeTest'
 1859 
 1860                 type = node.getNodeMetaData(INFERRED_TYPE)
 1861                 assert type.name == 'CTypeTest'
 1862             })
 1863             def s1 = cache  {
 1864               return new CTypeTest();
 1865             }
 1866 
 1867             CTypeTest s2 = cache {
 1868                 new CTypeTest()
 1869             }
 1870 
 1871           }
 1872 
 1873 
 1874           static <T> T cache(Closure<T> closure) {
 1875             return closure.call();
 1876           }
 1877 
 1878         }
 1879         1
 1880         '''
 1881     }
 1882 
 1883     // GROOVY-6129
 1884     void testShouldNotThrowNPE() {
 1885         assertScript '''
 1886             def map = new HashMap<>()
 1887             map.put(1, 'foo')
 1888             map.put('bar', new Date())
 1889         '''
 1890     }
 1891 
 1892     // GROOVY-6232
 1893     void testDiamond() {
 1894         assertScript '''
 1895             class Foo<T>{  Foo(T a, T b){} }
 1896             def bar() {
 1897                 Foo<Object> f = new Foo<>("a",new Object())
 1898             }
 1899             bar()
 1900         '''
 1901     }
 1902 
 1903     // GROOVY-6233
 1904     void testConstructorArgumentsAgainstGenerics() {
 1905         shouldFailWithMessages '''
 1906             class Foo<T>{  Foo(T a, T b){} }
 1907             def bar() {
 1908                 Foo<Map> f = new Foo<Map>("a",1)
 1909             }
 1910             bar()
 1911         ''', '[Static type checking] - Cannot find matching method Foo#<init>(java.lang.String, int)'
 1912     }
 1913 
 1914     // GROOVY-5742
 1915     void testNestedGenerics() {
 1916         assertScript '''
 1917             import static Next.*
 1918 
 1919             abstract class Base<A extends Base<A>> {}
 1920             class Done extends Base<Done> { }
 1921             class Next<H, T extends Base<T>> extends Base<Next<H, T>> {
 1922                 H head; T tail
 1923                 static <H, T extends Base<T>> Next<H, T> next(H h, T t) { new Next<H, T>(head:h, tail:t) }
 1924                 String toString() { "Next($head, ${tail.toString()})" }
 1925             }
 1926 
 1927             Next<Integer, Next<String, Done>> x = next(3, next("foo", new Done()))
 1928         '''
 1929     }
 1930 
 1931     // GROOVY-7848
 1932     void testNestedGenerics2() {
 1933         assertScript '''
 1934             List<Integer> test() {
 1935               def listOfLists = [[1,2], [3,4]]
 1936               listOfLists.collect { pair -> pair[0] + pair[1] }
 1937             }
 1938             def result = test()
 1939             assert result == [3,7]
 1940         '''
 1941     }
 1942 
 1943     void testMethodLevelGenericsFromInterface() {
 1944         assertScript '''
 1945             interface A {
 1946                 public <T> T getBean(Class<T> c)
 1947             }
 1948             interface B extends A {}
 1949             interface C extends B {}
 1950 
 1951             void foo(C c) {
 1952                 String s = c?.getBean("".class)
 1953             }
 1954             foo(null)
 1955             true
 1956         '''
 1957     }
 1958 
 1959     // GROOVY-5610
 1960     void testMethodWithDefaultArgument() {
 1961         assertScript '''
 1962             class A{}
 1963             class B extends A{}
 1964             def foo(List<? extends A> arg, String value='default'){1}
 1965 
 1966             List<B> b = new ArrayList<>()
 1967             assert foo(b) == 1
 1968             List<A> a = new ArrayList<>()
 1969             assert foo(a) == 1
 1970         '''
 1971 
 1972         shouldFailWithMessages '''
 1973             class A{}
 1974             class B extends A{}
 1975             def foo(List<? extends A> arg, String value='default'){1}
 1976 
 1977             List<Object> l = new ArrayList<>()
 1978             assert foo(l) == 1
 1979         ''',
 1980         '#foo(java.util.List <? extends A>) with arguments [java.util.ArrayList <java.lang.Object>]'
 1981     }
 1982 
 1983     void testMethodLevelGenericsForMethodCall() {
 1984         // Groovy-5891
 1985         assertScript '''
 1986             public <T extends List<Integer>> T foo(Class<T> type, def x) {
 1987                 return type.cast(x)
 1988             }
 1989             def l = [1,2,3]
 1990             assert foo(l.class, l) == l
 1991         '''
 1992         assertScript '''
 1993             public <T extends Runnable> T foo(Class<T> type, def x) {
 1994                 return type.cast(x)
 1995             }
 1996             def cl = {1}
 1997             assert foo(cl.class, cl) == cl
 1998          '''
 1999          assertScript '''
 2000             public <T extends Runnable> T foo(Class<T> type, def x) {
 2001                 return type.cast(x) as T
 2002             }
 2003             def cl = {1}
 2004             assert foo(cl.class, cl) == cl
 2005          '''
 2006          // GROOVY-5885
 2007          assertScript '''
 2008             class Test {
 2009                 public <X extends Test> X castToMe(Class<X> type, Object o) {
 2010                     return type.cast(o);
 2011                 }
 2012             }
 2013             def t = new Test()
 2014             assert t.castToMe(Test, t)  == t
 2015          '''
 2016     }
 2017 
 2018     // GROOVY-5839
 2019     void testMethodShadowGenerics() {
 2020         shouldFailWithMessages '''
 2021             public class GoodCodeRed<T> {
 2022                 Collection<GoodCodeRed<T>> attached = []
 2023                 public <T> void attach(GoodCodeRed<T> toAttach) {
 2024                     attached.add(toAttach)
 2025                 }
 2026                 static void foo() {
 2027                     def g1 = new GoodCodeRed<Long>()
 2028                     def g2 = new GoodCodeRed<Integer>()
 2029                     g1.attach(g2);
 2030                 }
 2031             }
 2032             GoodCodeRed.foo()
 2033         ''',
 2034         "Cannot call <T> GoodCodeRed <Long>#attach(GoodCodeRed <Long>) with arguments [GoodCodeRed <Integer>]"
 2035     }
 2036 
 2037     void testHiddenGenerics() {
 2038         // Groovy-6237
 2039         assertScript '''
 2040             class MyList extends LinkedList<Object> {}
 2041             List<Object> o = new MyList()
 2042         '''
 2043 
 2044         shouldFailWithMessages '''
 2045             class Blah {}
 2046             class MyList extends LinkedList<Object> {}
 2047             List<Blah> o = new MyList()
 2048         ''','Incompatible generic argument types. Cannot assign MyList to: java.util.List <Blah>'
 2049 
 2050         // Groovy-5873
 2051         assertScript """
 2052             abstract class Parent<T> {
 2053                 public T value
 2054             }
 2055             class Impl extends Parent<Integer> {}
 2056             Impl impl = new Impl()
 2057             Integer i = impl.value
 2058         """
 2059 
 2060         // GROOVY-5920
 2061         assertScript """
 2062             class Data<T> {
 2063               T value
 2064             }
 2065 
 2066             class StringDataIterator implements Iterator<Data<String>> {
 2067               boolean hasNext() { true }
 2068               void    remove()  {}
 2069               Data<String> next() {
 2070                 new Data<String>( value: 'tim' )
 2071               }
 2072             }
 2073 
 2074             class Runner {
 2075               static main( args ) {
 2076                 Data<String> elem = new StringDataIterator().next()
 2077                 assert elem.value.length() == 3
 2078               }
 2079             }
 2080             Runner.main(null);
 2081         """
 2082     }
 2083 
 2084     void testReturnTypeInferenceRemovalWithGenerics() {
 2085         assertScript '''
 2086             class SynchronousPromise<T> {
 2087                 Closure<T> callable
 2088                 Object value
 2089 
 2090                 SynchronousPromise(Closure<T> callable) {
 2091                     this.callable = callable
 2092                 }
 2093 
 2094                 T get() throws Throwable {
 2095                     @ASTTest(phase=INSTRUCTION_SELECTION,value={
 2096                         assert node.getNodeMetaData(INFERRED_TYPE) == OBJECT_TYPE
 2097                     })
 2098                     value=callable.call()
 2099                     return value
 2100                 }
 2101             }
 2102 
 2103             def promise = new SynchronousPromise({ "Hello" })
 2104             promise.get()
 2105         '''
 2106     }
 2107 
 2108     // GROOVY-6455
 2109     void testDelegateWithGenerics() {
 2110         assertScript '''
 2111             class IntList {
 2112                 @Delegate List<Integer> delegate = new ArrayList<Integer>()
 2113             }
 2114             def l = new IntList()
 2115             assert l == []
 2116         '''
 2117     }
 2118 
 2119     // GROOVY-6504
 2120     void testInjectMethodWithInitialValueChoosesTheCollectionVersion() {
 2121         assertScript '''import org.codehaus.groovy.transform.stc.ExtensionMethodNode
 2122             @ASTTest(phase=INSTRUCTION_SELECTION, value={
 2123                 def method = node.rightExpression.getNodeMetaData(DIRECT_METHOD_CALL_TARGET)
 2124                 assert method.name == 'inject'
 2125                 assert method instanceof ExtensionMethodNode
 2126                 method = method.extensionMethodNode
 2127                 assert method.parameters[0].type == make(Collection)
 2128             })
 2129             def result = ['a','bb','ccc'].inject(0) { int acc, String str -> acc += str.length(); acc }
 2130             assert  result == 6
 2131         '''
 2132     }
 2133 
 2134     // GROOVY-6504
 2135     void testInjectMethodWithInitialValueChoosesTheCollectionVersionUsingDGM() {
 2136         assertScript '''import org.codehaus.groovy.runtime.DefaultGroovyMethods
 2137             @ASTTest(phase=INSTRUCTION_SELECTION, value={
 2138                 def method = node.rightExpression.getNodeMetaData(DIRECT_METHOD_CALL_TARGET)
 2139                 assert method.name == 'inject'
 2140                 assert method.parameters[0].type == make(Collection)
 2141             })
 2142             def result = DefaultGroovyMethods.inject(['a','bb','ccc'],0, { int acc, String str -> acc += str.length(); acc })
 2143             assert  result == 6
 2144         '''
 2145     }
 2146 
 2147     // GROOVY-6760
 2148     void testGenericsAtMethodLevelWithGenericsInTypeOfGenericType() {
 2149         assertScript '''
 2150             @Grab('com.netflix.rxjava:rxjava-core:0.18.1')
 2151             import rx.Observable
 2152             import java.util.concurrent.Callable
 2153 
 2154             static <T> Observable<T> observe(Callable<Iterable<T>> callable) {
 2155                 Observable.from(callable.call())
 2156             }
 2157             observe({ ["foo"] }) map {
 2158                 it.toUpperCase() // <- compiler doesn't know 'it' is a string
 2159             } subscribe {
 2160                 assert it == "FOO"
 2161             }
 2162         '''
 2163     }
 2164 
 2165     // GROOVY-6135
 2166     void testGenericField() {
 2167         assertScript '''
 2168             class MyClass {
 2169                 static void main(args) {
 2170                     Holder<Integer> holder = new Holder<Integer>()
 2171                     holder.value = 5
 2172                     assert holder.value > 4
 2173                 }
 2174                 private static class Holder<T> {
 2175                     T value
 2176                 }
 2177             }
 2178         '''
 2179     }
 2180 
 2181     //GROOVY-6723, GROOVY-6415
 2182     void testIndirectMethodLevelGenerics() {
 2183         assertScript '''
 2184             class C1<A> {
 2185                 def void m1(A a) {C1.m2(a)}
 2186                 static <B> void m2(B b) {}
 2187             }
 2188             new C1().m1(null) // the call does not really matter
 2189         '''
 2190         assertScript '''
 2191             class Test1 {
 2192                 static <A, B> void pair1(A a, B b) {}
 2193                 static <A, B> void pair2(A a, B b) {pair1(a, a)}
 2194                 static <A> List<A> list1(A a) {[a]}
 2195                 static <B> List<B> list2(B b) {list1(b)}
 2196                 static <A> List<A> list3(A a) {list1(a)}
 2197             }
 2198             Test1.pair2(1,2) // the call does not really matter
 2199         '''
 2200 
 2201         assertScript '''
 2202             class Foo {
 2203                 String method() {
 2204                     return callT('abc')
 2205                 }
 2206 
 2207                 private <T> T callT(T t) {
 2208                     return callV(t)
 2209                 }
 2210 
 2211                 private <V> V callV(V v) {
 2212                     return v
 2213                 }
 2214             }
 2215 
 2216             println new Foo().method()
 2217         '''
 2218     }
 2219 
 2220     // GROOVY-6358
 2221     void testGenericsReturnedFromStaticMethodWithInnerClosureAndAsType() {
 2222         assertScript '''
 2223             import java.lang.reflect.Method
 2224 
 2225             interface Ifc {
 2226                void method()
 2227             }
 2228             class Generator {
 2229                 static <T> T create (Class<T> clazz ){
 2230                     return clazz.methods.collectEntries { Method method ->
 2231                             [ (method.name) : { println "${method.name} called"} ]
 2232                         }.asType(clazz)
 2233                 }
 2234             }
 2235             class User {
 2236                 static void main() {
 2237                     Ifc ifc = Generator.create(Ifc)
 2238                     ifc.method()
 2239                 }
 2240             }
 2241 
 2242             User.main()
 2243         '''
 2244     }
 2245 
 2246     void testConcreteTypeInsteadOfGenerifiedInterface() {
 2247         assertScript '''
 2248             import groovy.transform.ASTTest
 2249             import static org.codehaus.groovy.transform.stc.StaticTypesMarker.*
 2250             import static org.codehaus.groovy.ast.ClassHelper.*
 2251 
 2252             interface Converter<F, T> {
 2253             T convertC(F from)
 2254             }
 2255             class Holder<T> {
 2256                T thing
 2257                Holder(T thing) {
 2258                 this.thing = thing
 2259                }
 2260                def <R> Holder<R> convertH(Converter<? super T, ? extends R> func1) {
 2261                   new Holder(func1.convertC(thing))
 2262                }
 2263             }
 2264             class IntToFloatConverter implements Converter<Integer,Float> {
 2265                 public Float convertC(Integer from) { from.floatValue() }
 2266             }
 2267             void foo() {
 2268                 @ASTTest(phase=INSTRUCTION_SELECTION,value={
 2269                     def holderType = node.getNodeMetaData(INFERRED_TYPE)
 2270                     assert holderType.genericsTypes[0].type == Float_TYPE
 2271                 })
 2272                 def h1 = new Holder<Integer>(2).convertH(new IntToFloatConverter())
 2273             }
 2274             foo()
 2275         '''
 2276     }
 2277 
 2278     // GROOVY-6748
 2279     void testCleanGenerics() {
 2280         assertScript '''
 2281             class Class1 {
 2282                 static <A, B> void method1(A a, B b) {
 2283                     method2(a, b)
 2284                 }
 2285                 static <A, B> void method2(A a, B b) {}
 2286                 static <A, B> void method3(List<A> list1, List<B> list2) {
 2287                     method1(list1.get(0), list2.get(0))
 2288                 }
 2289             }
 2290             new Class1().method3(["a"],["b"])
 2291         '''
 2292     }
 2293 
 2294     // GROOVY-6761
 2295     void testInVariantAndContraVariantGenerics() {
 2296         assertScript '''
 2297             class Thing {
 2298               public <O> void contravariant(Class<? super O> type, O object) {}
 2299               public <O> void invariant(Class<O> type, O object) {}
 2300               void m() {
 2301                 invariant(String, "foo")
 2302                 contravariant(String, "foo") // fails, can't find method
 2303               }
 2304             }
 2305             new Thing().m()
 2306         '''
 2307     }
 2308 
 2309     // GROOVY-6731
 2310     void testContravariantMethodResolution() {
 2311         assertScript '''
 2312             interface Function<T, R> {
 2313                 R apply(T t)
 2314             }
 2315 
 2316             public <I, O> void transform(Function<? super I, ? extends O> function) {
 2317                 function.apply('')
 2318             }
 2319 
 2320             String result = null
 2321             transform(new Function<String, String>() {
 2322                 String apply(String input) {
 2323                     result = "ok"
 2324                 }
 2325             })
 2326 
 2327             assert result == 'ok'
 2328         '''
 2329     }
 2330 
 2331     void testContravariantMethodResolutionWithImplicitCoercion() {
 2332         assertScript '''
 2333             interface Function<T, R> {
 2334                 R apply(T t)
 2335             }
 2336 
 2337             public <I, O> void transform(Function<? super I, ? extends O> function) {
 2338                 function.apply('')
 2339             }
 2340 
 2341             String result = null
 2342             transform {
 2343                 result = 'ok'
 2344             }
 2345             assert result == 'ok'
 2346         '''
 2347     }
 2348 
 2349     void testGROOVY5981() {
 2350         assertScript '''
 2351             import javax.swing.*
 2352             import java.awt.*
 2353 
 2354             class ComponentFixture<T extends Component> {}
 2355             class JButtonFixture extends ComponentFixture<JButton> {}
 2356             class ContainerFixture<T extends Container> extends ComponentFixture<T> {}
 2357             abstract class ComponentAdapter<Fixture extends ComponentFixture> {
 2358                 Fixture getFixture() {
 2359                     return fixture
 2360                 }
 2361             }
 2362             abstract class ContainerAdapter<Fixture extends ContainerFixture> extends ComponentAdapter<Fixture> {}
 2363 
 2364             class ButtonComponent extends ComponentAdapter<JButtonFixture> {
 2365                 void setFixtureResolver(final ContainerAdapter<? extends ContainerFixture> containerAdapter) {
 2366                     final ContainerFixture containerFixture = containerAdapter.getFixture()
 2367                 }
 2368             }
 2369 
 2370             new ButtonComponent()
 2371         '''
 2372     }
 2373 
 2374     // GROOVY-6856
 2375     void testReturnTypeFitsInferredTypeWithBound() {
 2376         assertScript '''
 2377             class Wrapper {}
 2378 
 2379             class Foo<W extends Wrapper> {
 2380                 W doIt (List<W> l) {
 2381                     l.iterator().next()
 2382                 }
 2383             }
 2384             Wrapper w = new Wrapper()
 2385             assert new Foo<Wrapper>().doIt([w]) == w
 2386         '''
 2387     }
 2388 
 2389     // GROOVY-7691
 2390     void testCovariantReturnTypeInferredFromField() {
 2391         assertScript '''
 2392             import groovy.transform.*
 2393 
 2394             @TupleConstructor(includeFields=true)
 2395             abstract class A<N extends Number> {
 2396                 protected final N number
 2397             }
 2398 
 2399             class C<L extends Long> extends A<L> { // further restriction of type parameter
 2400                 C(L longNumber) {
 2401                     super(longNumber)
 2402                 }
 2403 
 2404                 L getValue() {
 2405                     return number
 2406                 }
 2407             }
 2408 
 2409             assert new C<Long>(42L).value == 42L
 2410         '''
 2411     }
 2412 
 2413     // GROOVY-7691
 2414     void testCovariantReturnTypeInferredFromProperty() {
 2415         assertScript '''
 2416             import groovy.transform.*
 2417 
 2418             @TupleConstructor
 2419             abstract class A<N extends Number> {
 2420                 final N number
 2421             }
 2422 
 2423             class C<L extends Long> extends A<L> {
 2424                 C(L longNumber) {
 2425                     super(longNumber)
 2426                 }
 2427 
 2428                 L getValue() {
 2429                     return number
 2430                 }
 2431             }
 2432 
 2433             assert new C<Long>(42L).value == 42L
 2434         '''
 2435     }
 2436 
 2437     void testCovariantReturnTypeInferredFromMethod1() {
 2438         assertScript '''
 2439             import groovy.transform.*
 2440 
 2441             @TupleConstructor(includeFields=true)
 2442             abstract class A<N extends Number> {
 2443                 protected final N number
 2444 
 2445                 protected N getNumber() {
 2446                     return number
 2447                 }
 2448             }
 2449 
 2450             class C<L extends Long> extends A<L> {
 2451                 C(L longNumber) {
 2452                     super(longNumber)
 2453                 }
 2454 
 2455                 L getValue() {
 2456                     return getNumber()
 2457                 }
 2458             }
 2459 
 2460             assert new C<Long>(42L).value == 42L
 2461         '''
 2462     }
 2463 
 2464     // GROOVY-9580
 2465     void testCovariantReturnTypeInferredFromMethod2() {
 2466         assertScript '''
 2467             import groovy.transform.*
 2468 
 2469             @TupleConstructor(includeFields=true)
 2470             abstract class A<N extends Number> {
 2471                 final N number
 2472             }
 2473 
 2474             class C<L extends Long> extends A<L> {
 2475                 C(L longNumber) {
 2476                     super(longNumber)
 2477                 }
 2478 
 2479                 L getValue() {
 2480                     return getNumber() // property method stubbed by StaticTypeCheckingVisitor
 2481                 }
 2482             }
 2483 
 2484             assert new C<Long>(42L).value == 42L
 2485         '''
 2486     }
 2487 
 2488     // GROOVY-9635
 2489     void testCovariantReturnTypeInferredFromMethod3() {
 2490         assertScript '''
 2491             import java.util.function.Function
 2492 
 2493             class C<R extends Number> {
 2494                 def <V> V m(Function<C, V> f) { // R from C is confused with R->V from Function
 2495                     V result = f.apply(this)
 2496                     return result
 2497                 }
 2498             }
 2499 
 2500             def ret = new C().m(new Function<C, String>() {
 2501                 @Override
 2502                 String apply(C that) {
 2503                     return 'foo'
 2504                 }
 2505             })
 2506 
 2507             assert ret == 'foo'
 2508         '''
 2509     }
 2510 
 2511     void testReturnTypeChecking() {
 2512         shouldFailWithMessages '''
 2513             class Foo {
 2514                 List<String> run() {
 2515                     [11, 12]
 2516                 }
 2517             }
 2518         ''', 'Incompatible generic argument types. Cannot assign java.util.List <java.lang.Integer> to: java.util.List <String>'
 2519     }
 2520 
 2521     void testBoundedReturnTypeChecking() {
 2522         assertScript '''
 2523             class Foo {
 2524                 List<? extends Serializable> run() {
 2525                     [1, 'a']
 2526                 }
 2527             }
 2528             null
 2529         '''
 2530 
 2531         // GROOVY-9821
 2532         ['.', '?.', '*.'].each { op ->
 2533             config.with {
 2534                 targetDirectory = File.createTempDir()
 2535                 jointCompilationOptions = [memStub: true]
 2536             }
 2537             File parentDir = File.createTempDir()
 2538             try {
 2539                 def a = new File(parentDir, 'Types.java')
 2540                 a.write '''
 2541                     interface A {
 2542                         java.util.List<? extends B> getBees();
 2543                     }
 2544                     interface B {
 2545                         Object getC();
 2546                     }
 2547                 '''
 2548                 def b = new File(parentDir, 'Script.groovy')
 2549                 b.write """
 2550                     def test(A a) {
 2551                         a.bees${op}c
 2552                     }
 2553                 """
 2554 
 2555                 def loader = new GroovyClassLoader(this.class.classLoader)
 2556                 def cu = new JavaAwareCompilationUnit(config, loader)
 2557                 cu.addSources(a, b)
 2558                 cu.compile()
 2559             } finally {
 2560                 parentDir.deleteDir()
 2561                 config.targetDirectory.deleteDir()
 2562             }
 2563         }
 2564     }
 2565 
 2566     // GROOVY-9934
 2567     void testBoundedReturnTypeChecking2() {
 2568         assertScript '''
 2569             class Bar {
 2570             }
 2571             class Foo<T extends Bar> {
 2572                 T method(T t) {
 2573                     def c = { -> t }
 2574                     return c() // Cannot return value of type Object on method returning type T
 2575                 }
 2576             }
 2577             def bar = new Bar()
 2578             assert bar.is(new Foo<Bar>().method(bar))
 2579         '''
 2580     }
 2581 
 2582     // GROOVY-9981
 2583     void testBoundedReturnTypeChecking3() {
 2584         assertScript '''
 2585             class Pogo {
 2586                 Map<String, ? extends Number> map
 2587             }
 2588             def test(Pogo p) {
 2589                 Collection<? extends Number> c = p.map.values()
 2590                 Iterable<? extends Number> i = p.map.values()
 2591                 i.iterator().next()
 2592             }
 2593             def n = test(new Pogo(map:[x:1,y:2.3]))
 2594             assert n == 1
 2595         '''
 2596 
 2597         //
 2598 
 2599         config.with {
 2600             targetDirectory = File.createTempDir()
 2601             jointCompilationOptions = [memStub: true]
 2602         }
 2603         File parentDir = File.createTempDir()
 2604         try {
 2605             def a = new File(parentDir, 'Pojo.java')
 2606             a.write '''
 2607                 import java.util.Map;
 2608                 class Pojo {
 2609                     Map<String, ? extends Number> getMap() {
 2610                         return map;
 2611                     }
 2612                     void setMap(Map<String, ? extends Number> map) {
 2613                         this.map = map;
 2614                     }
 2615                     private Map<String, ? extends Number> map = null;
 2616                 }
 2617             '''
 2618             def b = new File(parentDir, 'Script.groovy')
 2619             b.write '''
 2620                 void test(Pojo p) {
 2621                     Collection<? extends Number> c = p.map.values()
 2622                     Iterable<? extends Number> i = p.map.values()
 2623                 }
 2624             '''
 2625 
 2626             def loader = new GroovyClassLoader(this.class.classLoader)
 2627             def cu = new JavaAwareCompilationUnit(config, loader)
 2628             cu.addSources(a, b)
 2629             cu.compile()
 2630         } finally {
 2631             parentDir.deleteDir()
 2632             config.targetDirectory.deleteDir()
 2633         }
 2634     }
 2635 
 2636     // GROOVY-7804
 2637     void testParameterlessClosureToGenericSAMTypeArgumentCoercion() {
 2638         assertScript '''
 2639             interface Supplier<T> {
 2640                 public <T> T get()
 2641             }
 2642 
 2643             static <T> T doGet(Supplier<T> supplier) { supplier.get() }
 2644 
 2645             assert doGet { -> 'foo' } == 'foo'
 2646         '''
 2647     }
 2648 
 2649     // GROOVY-7713
 2650     void testClosureReturnNull() {
 2651         assertScript '''
 2652             Closure<String> cl = {
 2653                 if (hashCode() > 0) {
 2654                     return null
 2655                 }
 2656                 'foo'
 2657             }
 2658         '''
 2659     }
 2660 
 2661     static class MyList extends LinkedList<String> {}
 2662 
 2663     public static class ClassA<T> {
 2664         public <X> Class<X> foo(Class<X> classType) {
 2665             return classType;
 2666         }
 2667 
 2668         public <X> Class<X> bar(Class<T> classType) {
 2669             return null;
 2670         }
 2671     }
 2672 
 2673     public static class JavaClassSupport {
 2674         public static class Container<T> {
 2675         }
 2676 
 2677         public static class StringContainer extends Container<String> {
 2678         }
 2679 
 2680         public static <T> List<T> unwrap(Collection<? extends Container<T>> list) {
 2681         }
 2682     }
 2683 }