Skip to content

For generic method inference, use refined type of locals #1287

@msridhar

Description

@msridhar

Consider:

public void firstOrDefaultLocalVarParam() {
makeHelper()
.addSourceLines(
"Test.java",
"import org.jspecify.annotations.*;",
"@NullMarked",
"class Test {",
" public interface List<E extends @Nullable Object> { boolean isEmpty(); E get(int index); }",
" public static class Collections {",
" public static <T extends @Nullable Object> List<T> singletonList(T element) {",
" throw new UnsupportedOperationException();",
" }",
" }",
" public static <U extends @Nullable Object> U firstOrDefault(List<U> list, U defaultValue) {",
" return list.isEmpty() ? defaultValue : list.get(0);",
" }",
" static void use() {",
" String x = null;",
" // should infer T -> @Nullable String",
" String result = firstOrDefault(Collections.singletonList(x), \"hello\");",
" // BUG: Diagnostic contains: dereferenced expression result is @Nullable",
" result.hashCode();",
" }",
"}")
.doTest();
}

Our generic method inference currently does not work correctly for this case, as it incorrectly assumes x is @NonNull based on its declaration. Instead, inference should get nullability of local variables based on what is computed by our flow-sensitive type refinement, which in this case would be @Nullable for x.

This is a subtle change, since dataflow analysis also needs to invoke inference (see #1262), and so we have a cyclic dependence; will have to manage this carefully.

Metadata

Metadata

Assignees

No one assigned

    Labels

    jspecifyRelated to support for jspecify standard (see jspecify.dev)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions