typetools / typetools/checker-framework

Optional checker: possible erroneous report of an incompatible method receiver for `Optional#get` in a `Stream#map`

Open
#6,210 5 comments 0 reactions 1 assignee View on GitHub

@smillst is already working on this.

Since Sep 29, 2023.

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

Description

Summary

Running the Optional checker on code that contains a call to Optional#get within a call to .map on a Java stream produces an error reporting to an incompatible method receiver.

Commands executed

Using the latest commit on the master branch of the Checker Framework, where javacheck is an alias for javac included in the Checker Framework's binary distribution.

javacheck -processor optional Main.java

Input

This is a minimal test case that should be able to trigger this issue

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class Main {

  public List<Integer> getOnlyPresentInts(List<Optional<Integer>> optInts) {
    return optInts.stream()
      .map(Optional::get)
      .collect(Collectors.toList());
  }
}

Actual output

Main.java:9: warning: [optional.as.element.type] Don't use Optional as the element type in a collection.
  public List<Integer> getOnlyPresentInts(List<Optional<Integer>> optInts) {
                                                                  ^
Main.java:11: error: [methodref.receiver] Incompatible receiver type
      .map(Optional::get)
           ^
  found   : @Present Optional<@MaybePresent Integer>
  required: @MaybePresent Optional<@MaybePresent Integer>
  Consequence: method in @MaybePresent Optional<@MaybePresent Integer>
    @MaybePresent Integer get(@Present Optional<@MaybePresent Integer> this)
  is not a valid method reference for method in @MaybePresent Function<@MaybePresent Optional<@MaybePresent Integer>, @MaybePresent Integer>
    @MaybePresent Integer apply(@MaybePresent Function<@MaybePresent Optional<@MaybePresent Integer>, @MaybePresent Integer> this, @MaybePresent Optional<@MaybePresent Integer> p0)
1 error
1 warning

Expected output

There should technically be no error about an incompatible method receiver, as calling .stream() on an object of type List<Optional<Integer>> should evaluate to an object of type Stream<Optional<Integer>>.

Additionally, the error line

Main.java:11: error: [methodref.receiver] Incompatible receiver type
      .map(Optional::get)
           ^
  found   : @Present Optional<@MaybePresent Integer>
  required: @MaybePresent Optional<@MaybePresent Integer>

Is confusing to me, shouldn't the found type be annotated with @MaybePresent? Since the manual states

@MaybePresent
The annotated Optional container may or may not contain a value. This is the default type, so programmers do not have to
write it.

However, this might be a misunderstanding of the Optional checker's type system on my part.

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.