-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Conversation
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.
@@ -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`. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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:
complete
, where it's called with aT
completeExceptionallyOrCancel
, where it's called with aCancelled
(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.
There was a problem hiding this 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!
Leverage the fact that `FutureCallback<T>.onSuccess` can only accept `null` when `T` is `null`, to remove the unchecked casts.
Leverage the fact that `FutureCallback<T>.onSuccess` can only accept `null` when `T` is `null`, to remove the unchecked casts.
Leverage the fact that `FutureCallback<T>.onSuccess` can only accept `null` when `T` is `null`, to remove the unchecked casts.
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 implementonSuccess(T)
instead of
onSuccess(T?)
. And with a future change to Guava, it willhave 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.