Skip to content

Update code to prepare for nullness annotations in Guava. #3026

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

Merged
merged 1 commit into from
Jan 18, 2022

Conversation

cpovirk
Copy link
Contributor

@cpovirk cpovirk commented Nov 16, 2021

Guava's current nullness annotations don't yet trigger Kotlin compile
errors. However, Guava did recently remove the misleading @Nullable
annotation from the parameter of FutureCallback.onSuccess:

Before:
https://github.com/google/guava/blob/v28.0/guava/src/com/google/common/util/concurrent/FutureCallback.java#L34

After:
https://github.com/google/guava/blob/v31.0.1/guava/src/com/google/common/util/concurrent/FutureCallback.java#L35

That means that a FutureCallback<T> can now implement onSuccess(T)
instead of onSuccess(T?). And with a future change to Guava, it will
have to.

(For background, see the section on "Nullness annotations" in
https://github.com/google/guava/releases/tag/v31.0)

In order to make that change, this commit updates from from Guava 28.0
to Guava 31.0.1.

When I performed that update, I found that that pulled in a newer
version of the Checker Framework nullness annotations. That version was
build with a newer version of Gradle, so it generates Gradle module
metadata:
https://docs.gradle.org/current/userguide/publishing_gradle_module_metadata.html

That metadata declares that the Checker Framework annotations require
Java 1.8. Even the old version had in fact required Java 1.8 -- and so
had even the old version of Guava -- just without having that encoded in
its metadata. So I fixed this by setting targetCompatibility and
sourceCompatibility to 1.8 for kotlinx-coroutines-guava, too.

Guava's current nullness annotations don't yet trigger Kotlin compile
errors. However, Guava did recently remove the misleading `@Nullable`
annotation from the parameter of `FutureCallback.onSuccess`:

Before:
https://github.com/google/guava/blob/v28.0/guava/src/com/google/common/util/concurrent/FutureCallback.java#L34

After:
https://github.com/google/guava/blob/v31.0.1/guava/src/com/google/common/util/concurrent/FutureCallback.java#L35

That means that a `FutureCallback<T>` can now implement `onSuccess(T)`
instead of `onSuccess(T?)`. And with a future change to Guava, it will
_have to_.

(For background, see the section on "Nullness annotations" in
https://github.com/google/guava/releases/tag/v31.0)

In order to make that change, this commit updates from from Guava 28.0
to Guava 31.0.1.

When I performed that update, I found that that pulled in a newer
version of the Checker Framework nullness annotations. That version was
build with a newer version of Gradle, so it generates Gradle module
metadata:
https://docs.gradle.org/current/userguide/publishing_gradle_module_metadata.html

That metadata declares that the Checker Framework annotations require
Java 1.8. Even the old version had in fact required Java 1.8 -- and so
had even the old version of Guava -- just without having that encoded in
its metadata. So I fixed this by setting targetCompatibility and
sourceCompatibility to 1.8 for kotlinx-coroutines-guava, too.
@cpovirk
Copy link
Contributor Author

cpovirk commented Nov 16, 2021

Split off from #3007 (and rebased onto develop) as requested.

(I still need to get back to #3007 itself. Thanks for your patience.)

@@ -436,7 +434,7 @@ private class JobListenableFuture<T>(private val jobToCancel: Job): ListenableFu
}

/** See [get()]. */
private fun getInternal(result: Any): T = if (result is Cancelled) {
private fun getInternal(result: Any?): T = if (result is Cancelled) {
throw CancellationException().initCause(result.exception)
} else {
// We know that `auxFuture` can contain either `T` or `Cancelled`.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can't the result here be null now? In which case, getInternal should also return a nullable value.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

auxFuture.set is called in 2 places:

(That appears to match this comment.)

It's true that T might be a nullable type in some cases, so the result might be null. But that's OK: The result can be null only if it came through complete(result: T). And that can happen only in the case that T is a nullable type.

Put another way, complete and getInternal combine to implement a system that accepts a T and produces a T. It just happens to store the T as an Any? in the meantime because it sometimes wants to store a Cancelled instead.

More broadly: This PR shouldn't change any runtime behavior. result: T could always be a null value. But once Guava is fully annotated for nullness (maybe in Guava 32.0?), the existing auxFuture.set(result) call will stop working: At that point, Kotlin will not only know that result: T could be a null value but also know that auxFuture.set should not be called with a null value because its parameter type is Any. This PR changes auxFuture so that auxFuture.set accepts an Any? and the code continues to compile. But it doesn't change the values that were already possible.

@dkhalanskyjb dkhalanskyjb self-requested a review January 18, 2022 13:07
Copy link
Collaborator

@dkhalanskyjb dkhalanskyjb left a comment

Choose a reason for hiding this comment

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

This makes sense, thanks!

@dkhalanskyjb dkhalanskyjb merged commit f442001 into Kotlin:develop Jan 18, 2022
@cpovirk cpovirk deleted the nullann-guava branch January 18, 2022 14:16
yorickhenning pushed a commit to yorickhenning/kotlinx.coroutines that referenced this pull request Jan 28, 2022
Leverage the fact that `FutureCallback<T>.onSuccess` can only accept
`null` when `T` is `null`, to remove the unchecked casts.
dee-tree pushed a commit to dee-tree/kotlinx.coroutines that referenced this pull request Jul 21, 2022
Leverage the fact that `FutureCallback<T>.onSuccess` can only accept
`null` when `T` is `null`, to remove the unchecked casts.
pablobaxter pushed a commit to pablobaxter/kotlinx.coroutines that referenced this pull request Sep 14, 2022
Leverage the fact that `FutureCallback<T>.onSuccess` can only accept
`null` when `T` is `null`, to remove the unchecked casts.
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