Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
Use the new
TypeUseLocation
default locations #165Use the new
TypeUseLocation
default locations #165Changes from 29 commits
33817d8
324d817
1ef0817
e673ee8
209435e
d9e96d0
1362fa2
4a8bd5b
cb1c7b2
cbebcf2
a1a45fc
8eb4ab8
fad09d5
04b8d84
9ee2796
93b50dc
cf2aa1d
859669f
f73dfbf
41a4ce4
e073d35
77dc086
752ad09
88d9c88
a4d344b
acf4230
5c25a46
ac7487f
9ba1aa8
2588340
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
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.
I'm going to just not think about this part for now, given the chance that our substitution behavior will change in one or more ways (jspecify/jspecify#248 (comment), jspecify/jspecify#91 (comment)) and given my lack of deep understanding of the Checker Framework model :)
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.
The unexpected error for this test case is:
I think the defaults work correctly: the
IMPLICIT_WILDCARD_UPPER_BOUND_NO_SUPER
default is@Nullable
, which gets combined with the declared upper bound, resulting incapture of ? extends Object*
.However, that is not a subtype of
Object*
. @cpovirk does this look like some problem with the type hierarchy?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.
It is correct for the checker to produce an error here. The reason that it's showing up as
FAIL
is that the conformance-test framework doesn't supportjspecify_nullness_not_enough_information
yet, onlyjspecify_nullness_mismatch
.(
Object*
is not a subtype ofObject*
so as to indicate that, if you don't know what you have and you don't know what you need, we can't prove that it's safe. Our expectation is that few checkers (if any) will produce even a warning in this case—or even in a more-likely-to-be-unsafe case in which you have anObject?
and need anObject*
. Still, the tests label such cases accordingly. This labeling may help tools like the Checker Framework that make specific assumptions about unannotated code: If a line is labeled withjspecify_nullness_mismatch
, a tool like the Checker Framework can consider itself to "pass" whether it produces an error there or not. This is in contrast to cases in which it should always produce an error and cases in which it never should.)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.
Thanks, so I did remember correctly that that is how unspecified nullness is supposed to work.
I've opened jspecify/jspecify#487 to add the optional error.
(In your penultimate sentence:
If a line is labeled with jspecify_nullness_mismatch, a tool like the Checker Framework can consider itself to "pass" whether it produces an error there or not.
Here you meantjspecify_nullness_not_enough_information
, right?)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.
Oops, yes, sorry.
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.
The error here (which we add as expected in jspecify/jspecify#487) feels wrong to me.
The captured wildcard is for that type parameter of
Supplier
. So while in general, two unspecified nullness can't be subtypes, here, the type argument is a capture of that unspecified nullness, so it will always match.Even more fundamentally, when checking
Supplier<?>
the wildcard isn't captured at all - a capture only happens at a call/field access. So the found type is not what it should be.What do you think?
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.
I am still not sure where the code that makes the main branch avoid this error is :\
I thought maybe 89d9b72#diff-ce82a59b06d0d82bfc6d06835d1b06ac15619bc3a71617d32189d041f02ca9c0R270, but then I found that I'd removed that cocde in 8ba39b0
I thought maybe jspecify/checker-framework@00cc056, but then I found that I'd removed that code in jspecify/checker-framework@72c5c16.
Maybe 9348e76#diff-ce82a59b06d0d82bfc6d06835d1b06ac15619bc3a71617d32189d041f02ca9c0R894 is somehow related?
I also have open 74f564f, 7e662e3, and 824113a, but I'm not convinced that any of that is relevant.
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.
OK, I started just diffing
checker-framework
against upstream, and the code jumped right out to me. At least, I assume this is the right code:https://github.com/jspecify/checker-framework/blob/b84882d9b2f77c99081118cc7ad095dfcc3484f5/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeValidator.java#L562
(That code was a small part of the large merge commit jspecify/checker-framework@2e588e7.)
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.
Thanks a lot for tracking this down!
I'll look into fixing this in the reference checker or the framework.
Besides the error here, these incorrect captures are also the cause for #164.
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.
Ah, do you think that it's possible that #164 is related to https://github.com/jspecify/checker-framework/blob/b84882d9b2f77c99081118cc7ad095dfcc3484f5/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java#L5017 (jspecify/checker-framework#47)?
That is, could there be two issues here?
Object*
is not a subtype ofObject*
. My "fix" for that was to remove the possibly unnecessary check entirely. (cause of Capture ofObject*
is not compatible withObject*
. jspecify#487)?)x(Foo<? super T>)
cannot override identical signature #164?)The reason that it seems strange for #164 to be related to this issue is that #164 doesn't involve unspecified nullness.
But I guess that, if the tests of #164 start passing with this change, then it's a fix :) Still, maybe it's more that we're hiding the failure (by no longer checking the incorrect capture against anything) than fixing it (by making the results of capture correct)? I don't know :\
I should also write up something about type parameters in general that I've been thinking about recently. It might end up saving us some work... maybe....
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.
9ee2796 uses
hasEffectiveAnnotation
instead ofhasAnnotation
. #164 has? super T
and when the code asked whether the wildcard had a particular annotation in the lower bound, it got "none", because the type variableT
isn't annotated.hasEffectiveAnnotation
follows bounds to find the first declared type.I replaced all
hasAnnotation
withhasEffectiveAnnotation
in theNullSpecAnnotatedTypeFactory
. I should probably have that done more incrementally, as two more conformance tests fail now... let me see why that is. I should also look at uses ofhasAnnotation
in other files.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 line contains a
jspecify_nullness_not_enough_information
marker.I get as error:
The
Object?
seems wrong, as the wildcard bound should become unspecified.However, there is an error marker... should I change something about the test case?
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.
There appears to be a lot going on here.
First: I would have expected:
I think that's what you're saying, as well.
This seems familiar: I think that the reason that
NullUnmarkedUndoesNullMarkedForWildcards
exists is that I had wanted to define@NullMarked
as something like "nullnessOperatorUnspecified
for locationALL
." But that turns out not to work when the enclosing scope is@NullMarked
:@NullMarked
configuresunionNull
forUNBOUNDED_WILDCARD_UPPER_BOUND
, andUNBOUNDED_WILDCARD_UPPER_BOUND
is more specific thanALL
, even though it's on a wider scope. Or something like that? ThepopulateNewDefaults
method inNullSpecAnnotatedTypeFactory.java
discusses this. Perhaps you just need to do this TODO?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.
As for the fact that it's an error:
That much is expected. It's only the types that are wrong.
Our checker doesn't actually issue "warnings." It issues only errors. The cases that we would think of as "warnings" are cases where the checker issues an error in strict mode but no error in lenient mode. (That's in contrast to "real" errors, which are errors in both modes.)
This is what I was getting at in jspecify/jspecify#486 (comment).
As I note there, the conformance-test framework doesn't support
jspecify_nullness_not_enough_information
. Since IIRC the conformance-test framework current runs only in strict mode, it could be made to treatjspecify_nullness_not_enough_information
exactly likejspecify_nullness_mismatch
, since both of those comments indicate lines that should be errors in strict mode.If we were to make the conformance-test framework treat
jspecify_nullness_not_enough_information
in that way, then the test here would begin to pass. It would still be passing for the wrong reason (since it has the types wrong), but we wouldn't notice until we also run the conformance tests in lenient mode. Once we do, it would fail: It would appear there as an unexpected error in lenient mode. Or at least I'd hope so :) (We should be able to see it fail now if we run the old-style samples integration that you'd put into place.)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.
But things get more interesting from there....
The current head checker is likely also doing this wrong! I built it and ran
./demo -Astrict
on this test, and:That's true! Since the method is
@NullUnmarked
,supplier
has unspecified nullness, so the call toget()
itself is not provably safe, independent of what we do with the result!(Hmm, so
main-eisop
should probably be producing that error, too!)To make that accidental error go away, we should probably change the sample to:
(Or we could insert a null check in the body of the method.)
But... where's the error that we actually wanted, the one about converting from
Object*
toObject
in the return statement? It looks like that error is missing at head. I wonder if it ever worked or if we only ever had the null-dereference error, which was enough to satisfy the tests? (This is definitely one reason to like a testing approach that can be more specific about what kind of error it expects....)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.
Sorry, I was looking at
main-eisop
there and not this PR.... Here's where this PR does it. It looks right to me at first blush:jspecify-reference-checker/src/main/java/com/google/jspecify/nullness/NullSpecAnnotatedTypeFactory.java
Line 154 in 41a4ce4
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.
@cpovirk @netdpb Let's re-start the discussion from #165 (comment)
I've added tests for the three fixed issues and the override test from one of the last comments. I could either remove them before we merge this or maybe move them from
minimal
toissues
or some other sub-directory?We can then merge this and I'll work on #164 in a new PR.
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.
We discussed this today and settled on moving the tests. Done in 2588340
A future cleanup can move some of them to conformance tests and keep others.