Skip to content

Nested generic calls lose qualifiers #7722

@lcahmu

Description

@lcahmu

I encountered this change while making the jump from 3.42.0 to 4.1.0, not certain if this was expected/intended from the inference changes in 3.43.0.

$ cat Test.java
public class Test {
    void test() {
        Object obj1 = new Object();
        Object obj2 = new Object();
        foo(obj1, bar(baz(obj2)));
    }

    interface Box<T> { }

    <T> void foo(T t, Box<? super T> b) { }

    <T> Box<T> bar(Box<T> b) {
        throw new UnsupportedOperationException();
    }

    <T> Box<T> baz(T t) {
        throw new UnsupportedOperationException();
    }
}
$ javac --version
javac 21.0.3

Succeeds with 3.42.0:

$ javac \
--release 21 \
-classpath checker-qual-3.42.0.jar \
-processorpath 'checker-3.42.0.jar;checker-qual-3.42.0.jar' \
-processor org.checkerframework.checker.nullness.NullnessChecker \
-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
Test.java

(no output)

Error with 4.1.0:

$ javac \
--release 21 \
-classpath checker-qual-4.1.0.jar \
-processorpath 'checker-4.1.0.jar;checker-qual-4.1.0.jar' \
-processor org.checkerframework.checker.nullness.NullnessChecker \
-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
Test.java
Test.java:5: error: [argument] incompatible argument for parameter b of Test.foo.
        foo(obj1, bar(baz(obj2)));
                     ^
  found   : @Initialized @NonNull Box<@UnknownInitialization @Nullable Object>
  required: @Initialized @NonNull Box<? extends @Initialized @Nullable Object super @Initialized @NonNull Object>
Test.java:5: error: [argument] incompatible argument for parameter b of Test.bar.
        foo(obj1, bar(baz(obj2)));
                         ^
  found   : @Initialized @NonNull Box<@UnknownInitialization @Nullable Object>
  required: @Initialized @NonNull Box<@Initialized @NonNull Object>
2 errors

Earliest failing version was 3.43.0:

$ javac \
--release 21 \
-classpath checker-qual-3.43.0.jar \
-processorpath 'checker-3.43.0.jar;checker-qual-3.43.0.jar' \
-processor org.checkerframework.checker.nullness.NullnessChecker \
-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
Test.java
Test.java:5: error: [argument] incompatible argument for parameter b of Test.foo.
        foo(obj1, bar(baz(obj2)));
                     ^
  found   : @Initialized @NonNull Box<@UnknownInitialization @Nullable Object>
  required: @Initialized @NonNull Box<? extends @Initialized @Nullable Object super @Initialized @NonNull Object>
Test.java:5: error: [argument] incompatible argument for parameter b of Test.bar.
        foo(obj1, bar(baz(obj2)));
                         ^
  found   : @Initialized @NonNull Box<@UnknownInitialization @Nullable Object>
  required: @Initialized @NonNull Box<@Initialized @NonNull Object>
2 errors

The type of obj2 is, I believe, @Initialized @NonNull Object, so I expected the result of baz(obj2) to be Box<@Initialized @NonNull Object>, but appears to be finding Box<@UnknownInitialization @Nullable Object> instead.


Double-checked with Java 25 just in case, but found no differences.

$ javac --version
javac 25.0.2

Succeeds with 3.42.0:

$ javac \
--release 25 \
-classpath checker-qual-3.42.0.jar \
-processorpath 'checker-3.42.0.jar;checker-qual-3.42.0.jar' \
-processor org.checkerframework.checker.nullness.NullnessChecker \
-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
Test.java

Error with 4.1.0:

$ javac \
--release 25 \
-classpath checker-qual-4.1.0.jar \
-processorpath 'checker-4.1.0.jar;checker-qual-4.1.0.jar' \
-processor org.checkerframework.checker.nullness.NullnessChecker \
-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
Test.java
Test.java:5: error: [argument] incompatible argument for parameter b of Test.foo.
        foo(obj1, bar(baz(obj2)));
                     ^
  found   : @Initialized @NonNull Box<@UnknownInitialization @Nullable Object>
  required: @Initialized @NonNull Box<? extends @Initialized @Nullable Object super @Initialized @NonNull Object>
Test.java:5: error: [argument] incompatible argument for parameter b of Test.bar.
        foo(obj1, bar(baz(obj2)));
                         ^
  found   : @Initialized @NonNull Box<@UnknownInitialization @Nullable Object>
  required: @Initialized @NonNull Box<@Initialized @NonNull Object>
2 errors

Earliest failing version was 3.43.0:

$ javac \
--release 25 \
-classpath checker-qual-3.43.0.jar \
-processorpath 'checker-3.43.0.jar;checker-qual-3.43.0.jar' \
-processor org.checkerframework.checker.nullness.NullnessChecker \
-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
Test.java
Test.java:5: error: [argument] incompatible argument for parameter b of Test.foo.
        foo(obj1, bar(baz(obj2)));
                     ^
  found   : @Initialized @NonNull Box<@UnknownInitialization @Nullable Object>
  required: @Initialized @NonNull Box<? extends @Initialized @Nullable Object super @Initialized @NonNull Object>
Test.java:5: error: [argument] incompatible argument for parameter b of Test.bar.
        foo(obj1, bar(baz(obj2)));
                         ^
  found   : @Initialized @NonNull Box<@UnknownInitialization @Nullable Object>
  required: @Initialized @NonNull Box<@Initialized @NonNull Object>
2 errors

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions