blob: 5221c58a7c52cc18b6202dd1a3fa7005c70858c2 [file] [log] [blame]
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>
// }
}