Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for opt.map(type::method) pattern. #6370

Merged
merged 18 commits into from
Dec 15, 2023

Conversation

smillst
Copy link
Member

@smillst smillst commented Dec 13, 2023

Pass -AoptionalMapAssumeNonNull to use.

@@ -14,6 +15,7 @@
// @NonNull, make the return type have type @Present.
@RelevantJavaTypes(Optional.class)
@StubFiles({"javaparser.astub"})
@SupportedOptions("optionalMapAssumeNonNull")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a better name would be "assumeNullAnnotated" or the like. This isn't specific to Optional.map, and it's about the assumption that nullness annotations are available for method references.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code as implemented is specific to Optional.map. (And is specific to method references.)

@mernst mernst assigned smillst and unassigned mernst Dec 13, 2023
@smillst smillst assigned mernst and unassigned smillst Dec 14, 2023
Copy link
Member

@mernst mernst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a suggestion about clarifying code & documentation. Thanks!

@smillst smillst assigned smillst and unassigned mernst Dec 14, 2023
@mernst
Copy link
Member

mernst commented Dec 14, 2023

@smillst I added a failing test case.

* @param memberReferenceTree a member reference
* @return true if the return type of the function type of {@code memberReferenceTree} is non-null
*/
private boolean returnsNonNull(MemberReferenceTree memberReferenceTree) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find returnsNonNull (and the documentation above) a bit misleading. The given function can return null, but only if it is passed null. Another way to say this is that the function never introduces a new null value. Could you please adjust the method name and documentation accordingly? Thank you!

Copy link
Member Author

@smillst smillst Dec 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is only checking that the return type does not have an explicit nullable annotation. If the return type is annotated with @PolyNull, then it still may return null even if the argument is non-null. Here's an example method signature with that property.

  @PolyNull Integer convertPoly(List<@PolyNull String> s);

I renamed to the method to make it clear that it is only checking from the lack of a Nullable annotation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! That renaming is helpful.

There is an inconsistency between the documentation (which says "true if @Nullable") and the name (which says "true if not @Nullable"). I suspect this is just a typo, Could you make them consistent? My preference would be to avoid negation in method names (& specifications), because negation makes reasoning more difficult.

Regarding the semantics: is there a difference between "is not annotated as @Nullable" and "never introduces a new null value"? I think they are the same, assuming that the code is fully annotated. Noting this equivalence (or explicitly disclaiming it, if I am mistaken) would help to clarify the effect of the code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the semantics: is there a difference between "is not annotated as @nullable" and "never introduces a new null value"? I think they are the same, assuming that the code is fully annotated. Noting this equivalence (or explicitly disclaiming it, if I am mistaken) would help to clarify the effect of the code.

I don't know what "never introduces a new null value" means. (What's a new null value? How does a method reference introduce a null value?) I think you mean that the function only returns null if its argument is also null. That is not the same a method whose return type is not annotated with a nullable annotation. Here's an example of method that is not annotated with a nullable annotation and returns null when its argument in non-null:

  @PolyNull Integer convertPoly(List<@PolyNull String> s) {
    for (String ins : s) {
      if (ins == null) {
        return null;
      }
    }
    return 0;
  }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this example! It is helpful. I indeed meant that the function only returns null if its argument is also null. But, as you point out, @PolyNull might not be written on the formal parameter. I had overlooked that. That would need to be checked.

Could you add a note about this to the documentation? Thanks.

@smillst
Copy link
Member Author

smillst commented Dec 14, 2023

@smillst I added a failing test case.

The tests still pass, so I'm not sure what's failing.

@mernst
Copy link
Member

mernst commented Dec 14, 2023

@smillst I added a failing test case.

The tests still pass, so I'm not sure what's failing.

I was testing locally without the extra command-line argument. Sorry for the false alarm!

Copy link
Member

@mernst mernst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this feature!

@mernst mernst enabled auto-merge (squash) December 15, 2023 16:40
@mernst mernst merged commit 886d0b3 into typetools:master Dec 15, 2023
29 checks passed
@mernst mernst deleted the optional-map-nullable branch December 15, 2023 18:50
wmdietl pushed a commit to eisop/checker-framework that referenced this pull request Jan 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants