-
Notifications
You must be signed in to change notification settings - Fork 29
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
Handling of type-use annotations on type variables #91
Comments
That's a good point. Here are 2 more things that might help us feel better about making FIrst: One of the things I've said against making class ImmutableSupplier<T extends @Nullable Object> {
final @NonNull T value;
ImmutableSupplier(@NonNull T value) {
this.value = value;
}
@NonNull T get() {
return value;
}
} But! I think the main reason that we've seen this historically is that the Checker Framework treats Second: If we can encourage tools to follow my " [1] If we do indeed give it a non-null bound, it will be largely because Java has "forced" our hand by making [2] For fun, try an internal search like the following: |
(I just realized that this thread is possibly part of #13. I don't have much opinion about whether to discuss here or there.) @kevin1e100 mentioned earlier today that we haven't revisited early decisions about the specific case of We're talking especially about the following class... class Foo<T extends @Nullable Object> {
@NullnessUnspecified T bar();
} ...with the following instantiations...
The question is: What does I think that the current proposal says Note that the current proposal has different treatment for a similar (and much more common) case: [@DefaultNullnessUnspecified]
class Foo<T> {
T bar();
} For that case, the proposal gives I think we should apply that behavior to the first case, too: Our certainty about the nullness of the bound for This fits with the idea that
The result of " Such a rule might also help replace the special rule for "assumed parametric nullability" with a general rule (though that depends on other decisions). [*] This assumes that the file is |
Note that I split out the requirements question of whether non-nullable type projections are needed as #86. (I think we could use more clear separation between requirements and design questions.) |
I think the discussion here is less over whether it's needed -- I think @kevin1e100 and I, at least, agree that it's not -- as to what to do when a user inevitable writes |
Oh, sorry, you're saying that the other issue is for use cases for "projections to types other than nullable," not "projections to the type non-null." So you're pointing out that we can discuss whether there's a requirement to project to unspecified, doing so on that other issue. That sounds fair. Let me see how I can split this, hopefully on Monday. [edit: I've posted about projections to non-null and about projections to unspecified nullness.] |
Thanks for trying to shift what
Then the question becomes, what should that mean? Some basic observations:
The But to me at least it still seems much more natural to think that I've been trying to figure out what the issue is. I think in part at least it has to do with the type-use annotations directly corresponding to conceptual "qualifiers" (called "effective nullability specifiers" in the proposal doc) on each base type usage, especially given that "refinement type systems" were a big motivation behind introducing type-use annotations into Java in the first place, IIUC. It seems very natural, then, for type-use annotations to "override" any qualifier on a given type argument. None of this is supposed to contradict the observations made above and elsewhere that One issue that particularly worries me is the potential inconsistency with existing spellings of
That all seems to say we should figure out issue #86, that is, whether non-null (and nullness-unspecified) "projections" should even be a thing. I've been carrying these thoughts for a while though, so I wanted to dump them before I lose them, especially since they seem to say that even if projections aren't "needed", making |
I'm not sure this is the best issue for this discussion, but as there was a comparison to CF behavior earlier, I wanted to highlight the following: The Checker Frameworks makes the bound for j.l.Class <T> void foo(Class<T> type, T instance) Here the default CF behavior makes <T extends Object> void foo(Class<T> type, T instance) making the upper bound non-null. Maybe parameter I'm not sure all cases with a nullable bound and non-null type variable uses are instances of #78, but that would seem plausible. If we can continue to expand |
So here's a "trick" that might deserve its own issue: In the proposal doc there's "special consideration" for type arguments that was kind of inspired by wildcards, namely that any type argument is to be automatically "adjusted" to adhere to the corresponding type parameter's bound (similar to how Java intersects wildcard bounds with the wildcarded type parameter's bounds). The original motivation for that was Namely, the motivation was for Following this approach to the letter, the That seems to mean that this rule results in an implicit form of non-null "projection", now that I think about it, in the case where the type argument is itself a type variable. Something like that would happen in the example of an
Maybe that means this rule is problematic, if we don't believe projections should be a thing (#86). Or maybe it actually helps avoid awkward contortions in Again, the original motivation for this rule, |
A thought I had on the migration concern mentioned above: we could encourage tools to warn when they see |
@cpovirk could you perhaps see whether there's some current action/decision we need to salvage from this historical discussion, and file that if so, and close this either way? Note that we can assume there will be no |
This should be pretty well covered (incidentally, even including the groundwork for For our current annotations, you can basically view it as the "unioning" approach discussed above, or you can view it as "what Kotlin does." If we introduce |
In an ideal world, I'd find some time to think about #91 (comment) again: If I recall correctly, the "special consideration" for non-nullable type parameters (also previously discussed here):
On the other hand, I suspect that the "special consideration" catches some bugs. (I would like to have a more compelling example handy, but as an existence proof, it catches the bug in code that calls Now maybe there's a way to produce the same effect without hooking into substitution specifically. Like, maybe usages of One worry would be that, without this "special consideration," it would technically become useful to write the "redundant" " In practice, probably most of the danger here comes from cases in which the type argument is unspecified, rather than nullable or parametric (since nullable or parametric would have already produced an error at the site of (I do think that there may also have been an argument that it's nice to have the escape hatch of being able to write |
There are some similarities here to other cases in which we've argued that non-null types are "special":
But I'm not sure if any such arguments are exceptionally strong in this particular case: If an API is generic, then I don't have a feel for what Valhalla might be able to do in the future. But it's not obvious to me that parameters and return values could be "flattened" in the way that fields can, at least until the type is specialized. I still like the idea of catching bugs, like in the cases of (But I'd have to actually look more at our reference checker to see how large the complication is. It might be only #248 that really mucks things up.) |
Issue #45 brought up the idea of sometimes "ignoring" type-use annotations on type variables, or more precisely, union-ing them with other factors when parameterizing generic classes (which effectively means only
@Nullable
will be fully honored). This affects issues #45, #89, and #90, so trying to split this question out.The text was updated successfully, but these errors were encountered: