File: UnexpectedRaw.java

package info (click to toggle)
checker-framework-java 3.2.0%2Bds-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 23,104 kB
  • sloc: java: 145,916; xml: 839; sh: 518; makefile: 404; perl: 26
file content (59 lines) | stat: -rw-r--r-- 2,509 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import org.checkerframework.checker.nullness.qual.*;

interface Consumer<A extends @Nullable Object> {
    public void consume(A object);
}

class Utils {

    public static <B extends @Nullable Object> Consumer<B> cast(
            final @Nullable Consumer<? super B> consumer) {
        throw new RuntimeException();
    }

    public static <C extends @Nullable Object> Consumer<C> getConsumer() {
        // null for simplicity, but could be anything
        Consumer<@Nullable Object> nullConsumer = null;

        // Previous reasoning for this to generate an (argument.type.incompatible) error was:
        // C could be @NonNull Object, so argument is incompatible?
        //
        // This is poor reasoning, however, because the type of the formal parameter should be:
        // @Nullable Consumer< ? [
        //                         super C[ extends @Nullable Object
        //                                  super @NonNull  Void
        //                                ]
        //                         extends @Nullable Object
        // ]
        // The primary annotations on nullConsumer and the formal parameter consumer are
        // identical, so it comes down to the annotations on the type arguments.

        // Let X stand in for the type argument of nullConsumer.  For it to be a valid
        // parameter, X must be contained by the type argument of the formal parameter,
        // ? super C.
        //
        // In other words, the following constraints must hold:
        //
        // C1: X <: upper bound of (? super C)
        // C2: lower bound of (? super C) <: X
        //
        // we can simplify these constraints by substituting out the lower and upper bound of
        // ? super C.
        // C1: X <: @Nullable Object
        // C2: C <: X
        //
        // we can simplify the constraints again by substituting X with the actual type argument to
        // nullConsumer and in C2, we can substitute C with its upper bound, since for the
        // constraint to hold X must be above C's upper bound.  This yields:
        //
        // C1: @Nullable Object <: @Nullable Object
        // C2: @Nullable Object <: @Nullable Object
        //
        // Since, for all type's T => T <: T, both C1 and C2 are upheld and the following statement
        // should NOT report an error
        Consumer<C> result = Utils.<C>cast(nullConsumer);

        // on a side note, I am not sure why this is called unexpected raw
        return result;
    }
}