typetools / typetools/checker-framework

Incorrect default for inner looping variable in a foreach loop.

Open
#2,172 2 comments 0 reactions 1 assignee View on GitHub

@wmdietl is already working on this.

Since Sep 27, 2018.

Dataflow
Dominant language
Java
Stars
1.1k
Forks
440
Avg merge
1d 12h
Merged PRs (30d)
134

Description

Normally, local variables (including loop index variables) default to the top type in the qualifier hierarchy and then get type refined to the type of the value they are assigned. The checker framework reveals an unusual behavior where the type of a loop variable doesn't get type refined correctly in the case of nested foreach loops.
Consider the following example to be checked with the nullness checker:

import org.checkerframework.checker.nullness.qual.*;
import java.lang.*;
public class Issue28Nullness {
    public static @PolyNull Integer @PolyNull [] makeArr(@PolyNull Integer n) {
        return new @PolyNull Integer @PolyNull [] {n};
    }

    public static void f(@NonNull Integer n) {
        for (Integer i : makeArr(n)) {
            for (Integer j : makeArr(i)) {
                @NonNull Integer m = j;
            }
        }
    }
}

The command javac -processor nullness Issue28Nullness.java produces the following unexpected error:

Issue28Nullness.java:13: error: [assignment.type.incompatible] incompatible types in assignment.
                @NonNull Integer m = j;
                                     ^
  found   : @Initialized @Nullable Integer
  required: @UnknownInitialization @NonNull Integer
1 error

Since n is @NonNull Integer, the type of makeArr(n) is @NonNull Integer @NonNull[]. As a result, i is of the type @NonNull Integer. Subsequently, the return type of makeArr(i) is also @NonNull Integer @NonNull[] and the type of j should also be @NonNull Integer. But the checker framework incorrectly treats j as @Nullable Integer.

Strangely, the error disappears if the inner loop variable is explicitly annotated as @NonNull Integer j.

The error also disappears if the foreach loops are changed to indexed for loops as follows:

import org.checkerframework.checker.nullness.qual.*;
import java.lang.*;
public class Issue28Nullness {
    public static @PolyNull Integer @PolyNull [] makeArr(@PolyNull Integer n) {
        return new @PolyNull Integer @PolyNull [] {n};
    }
    public static void fSimple(@NonNull Integer n) {
        @NonNull Integer @NonNull [] local = makeArr(n);
        for (Integer i = 0; i < local.length; i++) {
            @NonNull Integer @NonNull [] local1 = makeArr(i);
            for (Integer j = 0; j < local1.length; j++) {
                @NonNull Integer m = j;
            }
        }
    }
}

This shows that this problem pertains to inner loop variables of foreach loops.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.