| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import org.checkerframework.framework.testchecker.h1h2checker.quals.*; |
| |
| public class InferTypeArgsPolyChecker<OUTER_SCOPE_TV> { |
| // ---------------------------------------------------------- |
| // Test Case - A |
| <A> A methodA(@H2Top A a1, @H2Top A a2) { |
| return null; |
| } |
| |
| void contextA(@H1S1 @H2Bot String str, @H1Bot @H2Bot List<@H1S2 String> s) { |
| @H2Bot Object a = methodA(str, s); |
| @H1Top @H2Bot Object aTester = a; |
| } |
| |
| // ---------------------------------------------------------- |
| // Test Case - B |
| <B> B methodB(List<@H2S2 B> b1, List<@H1S2 B> b2) { |
| return null; |
| } |
| |
| void contextB(List<@H1S1 @H2S2 String> l1, List<@H1S2 @H2S1 String> l2) { |
| @H1S1 @H2S1 String str = methodB(l1, l2); |
| } |
| |
| // ---------------------------------------------------------- |
| // Test Case - C |
| <C extends List<? extends Object>> C methodC(C c1, C c2) { |
| return null; |
| } |
| |
| void contextC(List<@H1S1 @H2S2 ? extends @H1S1 @H2S2 String> l1, List<@H1S1 @H2S2 String> l2) { |
| List<@H1S1 @H2S2 ?> str = methodC(l1, l2); |
| } |
| |
| // ---------------------------------------------------------- |
| // Test Case - D |
| |
| <D extends OUTER_SCOPE_TV, DD> D methodD(D d1, D d2, DD dd) { |
| return null; |
| } |
| |
| <D extends OUTER_SCOPE_TV, DD> DD methodD2(D d1, D d2, DD dd) { |
| return null; |
| } |
| |
| void contextD(OUTER_SCOPE_TV os1, @H1S1 @H2S1 OUTER_SCOPE_TV os2) { |
| OUTER_SCOPE_TV osNaked1 = methodD(os1, os1, os2); |
| |
| // So for the next failure we correctly infer that for methodD to take both os1 and os2 as |
| // arguments D must be @H1Top @H2Top OUTER_SCOPE_TV. However, the UPPER_BOUND of D is |
| // <@H1Bottom @H2Bottom OUTER_SCOPE_TV extends @H1Top @H2Top Object> notice that our |
| // inferred type for D is above this bound. |
| // |
| // A similar, more useful example in the Nullness type system would be: |
| /* |
| class Gen<OUTER> { |
| public List<OUTER> listo; |
| |
| <T extends OUTER> void addToListo(T t1, T T2) { |
| listo.add(t1); |
| listo.add(t2); |
| } |
| |
| void launder(@NonNull OUTER arg1, @Nullable OUTER arg2) { |
| addToListo(arg1, arg2); // T is inferred to be <@Nullable OUTER> |
| // if we did not mark this as type.argument |
| // then we would have no idea that in the last |
| // line of this example we are putting a null value into |
| // a List of @NonNull Strings |
| } |
| |
| } |
| |
| Gen<@NonNull String> g = ...; |
| g.listo = new ArrayList<@NonNull String>(); |
| g.launder("", null); // during this method call null would be added to g.listo |
| */ |
| // :: error: (type.argument) |
| OUTER_SCOPE_TV osNaked2 = methodD(os1, os2, ""); |
| |
| // :: error: (type.argument) |
| OUTER_SCOPE_TV osAnnoed = methodD(os2, os2, ""); |
| |
| // :: error: (type.argument) |
| String str = methodD2(os2, os1, ""); |
| OUTER_SCOPE_TV osNaked3 = methodD2(os1, os1, os2); |
| } |
| |
| // ---------------------------------------------------------- |
| // Test Case - E |
| <E> E methodE(E e1, E[] aos2) { |
| return null; |
| } // pass an array to one of these to cover A2FReducer.visitArray_Typevar |
| |
| void contextE(String[] strArr, String[][] strArrArr, OUTER_SCOPE_TV os, OUTER_SCOPE_TV[] aos) { |
| String[] strArrLocal = methodE(strArr, strArrArr); |
| OUTER_SCOPE_TV osLocal = methodE(os, aos); |
| } |
| |
| // ---------------------------------------------------------- |
| // Test Case - C |
| <F> List<? super F> methodF(List<? extends F> lExtF, List<? super F> lSupF) { |
| return null; |
| } |
| |
| void contextF( |
| List<@H1Bot @H2Bot ? extends @H1Top @H2S1 String> l1, |
| List<? super @H1S1 @H2S2 String> l2, |
| List<@H1S1 @H2S2 ? extends @H1Top @H2Top String> l3) { |
| |
| // :: error: (argument) |
| List<? super @H1Bot @H2Bot String> lstr1 = methodF(l1, l2); |
| |
| // :: error: (argument) |
| List<? super @H1Top @H2S2 String> lstr2 = methodF(l3, l2); |
| } |
| |
| <G extends List<H>, H extends List<G>> List<H> methodG(G g1, G G2) { |
| return null; |
| } |
| |
| class NodeList extends ArrayList<@H1Top @H2Top NodeList> {} |
| |
| void contextG(NodeList l1, NodeList l2) { |
| List<@H1Top @H2Top NodeList> a = methodG(l1, l2); |
| } |
| |
| // add test case for Array<String> vs. String[] |
| // add test case of E extends F, F extends G, H extends List<? super E> and other craziness |
| |
| <M, N extends M> Map<M, N> method() { |
| return null; |
| } |
| |
| void contextMN() { |
| |
| // so I am not exactly sure how to create a meaningful test for this case |
| // what occurs is the SubtypeSolver.propagateGlbs forces N to be a subtype of M |
| // and it works (at least while I was debugging) but I don't know how to create |
| // a check that fails or succeeds because of this |
| Map<? super @H1S1 @H2S2 CharSequence, @H1Top @H2Top ? super String> mnl = method(); |
| } |
| |
| // class Pair<PONE,PTWO> { |
| // PONE _1; |
| // PTWO _2; |
| // } |
| |
| <O extends P, P> @H1Top @H2Top P methodOP(@H1Top @H2Top P p, O o) { |
| return null; |
| } |
| |
| void contextOP(@H1S1 @H2S1 String s1, @H1Bot @H2Bot String s2) { |
| // This test is actually here to test that the constraint P :> O is implied on p |
| // :: error: (assignment) |
| @H1Bot @H2Bot String loc = methodOP(s1, s2); |
| } |
| |
| // class Triplet<L,M,N> { |
| // L l; |
| // M m; |
| // N n; |
| // } |
| // |
| // <X extends Y, Y extends Z, Z> Triplet<X,Y,Z> methodXYZ() { |
| // return null; |
| // } |
| // |
| // void contextXYZ() { |
| // Triplet<@H1S> |
| // } |
| } |