-
Notifications
You must be signed in to change notification settings - Fork 7
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
New errors (maybe related to ? super
) from eisop/checker-framework#746
#193
Comments
I tried minimizing a test case with
There is quite some unspecified nullness, but I think they are expected in
So the types themselves look correct. What is unclear is why the nullmarked signature is not allowed as override for the unspecified method. @cpovirk Do the types themselves look correct to you? |
I left some more comments on #178 (comment) before coming back here.... I might continue to postpone looking at this further until maybe Tuesday (when I'll be in a better position to attach a debugger), but I wonder if we need to expand our existing special case for Lines 662 to 669 in af9dfbc
On the need for the special case, I think I once concluded:
It looks like our Checker Framework fork had its own checking of parameters for overrides. I don't know if that sort of approach would help us here or not, but even if it did, it would be piling hacks upon hacks :) |
Actually, wait, my mistake: That JLS citation is just for method-level type parameters, not the class-level ones we're dealing with here. And there might actually be a place for capture conversion in override checking, though I still suspect it would happen at an earlier step (during computing the value of The JLS section about class-level type parameters is probably "as a member of the supertype of In theory, we could override I have no pressing need to import #178 into Google to use there (and eisop/checker-framework#746 alone produces much more limited fallout), so I'm not sure how hard I want to think about this. I still dream that someday we can rewrite override checking and more in a simpler way if we don't need to support the full generality of the Checker Framework.... |
If we do want to import this, another option might be to arrange for our compilations that currently see unannotated JDK APIs to see annotated JDK APIs instead. (That's actually what I did last time :)) That would probably mean annotating all the major collection interfaces. In particular, as we know from our experience with |
Removing the capture-conversion step I mentioned above helps more (apparently without creating other problems) but somehow still doesn't solve the problem fully :) I still have problems with (Certainly we're now at least at the point that I could easily go with suppressions and/or annotating a couple more JDK APIs.) I sat down intending to run a quick test, and obviously I ended up poking around a little more than that... :) But I'm going to try to stop here for now. |
I observe that no tests fail ( I think I've convinced myself that the [edit: That line dates from the implementation of capture conversion.] |
I have somehow still not gotten around to attaching a debugger, but I'll note some things here: I've been testing with a few combinations but now primarily with:
From what I'm seeing, I think that:
My assumption at this point is that |
Oh, I get the impression that I probably need to perform more testing than that to really see if it's working: I can change This slightly undercuts my claim above (though I do still have the significant Google testing to fall back on!) and definitely undercuts my attempt to figure out which of the "two distinct parameter checks" actually matters (at least without also testing on Google's codebase). |
DO NOT MERGE, probably. See discussion from about jspecify/jspecify-reference-checker#193 (comment) onward. This PR is a lazy way for me to run tests, since I don't trust myself to find the right way to run them all locally.
Nope! :) I see the same result if I change boolean success = typeHierarchy.isSubtype(overriddenParams.get(i), overriderParams.get(i)); ...i.e., without the Incidentally, if I keep only I'm still interested in whether the current Checker Framework override checking could be simplified. (Maybe some of it is a holdover from before the implementation of capture conversion, for example?) To that end, I've put together eisop/checker-framework#829 to test the approach that would work if my dreams came through. But I will try to actually do the debugger thing shortly... :) After the implosion of my latest theory, I now have no theory about what's happening. |
OK, I got the debugger hooked up. I've gotten as far as |
DO NOT MERGE, probably. See discussion from about jspecify/jspecify-reference-checker#193 (comment) onward. This PR is a lazy way for me to run tests, since I don't trust myself to find the right way to run them all locally.
( |
Probably:
(noting that I'm testing with the changes discussed above) Here's the code I'm referring to and the JDK 11 spec section it refers to. The specific spec items are:
The former shouldn't apply here at all, since at least one of the type arguments is a wildcard. So the mystery may be why capture-converting the type with In hindsight, I guess I could have seen that coming, given that I previously avoided a problem with plain |
OK, I backed out the As before, we end up in
Actually, regardless of what's going wrong there, I think the supertype should have My test code is: package com.google.foo;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
class Foo {
interface Predicate<E> {}
interface Super<E> {
void g(Predicate<? super E> p);
}
@NullMarked
interface Sub<E extends @Nullable Object> extends Super<E> {
@Override
void g(Predicate<? super E> p);
}
} |
Weird: The debugger shows that we have a previous result for But @wmdietl, is this something that you understand? I may be totally misunderstanding what the code is doing. |
...but the check fails even if I tell it to proceed if the history had a (The bit with |
The failing check is:
i.e.,
The Checker Framework It looks as if The weird
|
There's a call to We end up in The call is:
The parameters are:
Ah, and that calls into our So we don't actually want lenient mode for least-upper-bound computations, or at least we don't want it for this part of the computation. But I'm not sure how easily we can disable that. I guess the thing to try would be to always delegate |
--- a/src/main/java/com/google/jspecify/nullness/NullSpecAnnotatedTypeFactory.java 2024-08-07 16:00:04.000000000 -0400
+++ b/src/main/java/com/google/jspecify/nullness/NullSpecAnnotatedTypeFactory.java 2024-08-07 17:31:35.000000000 -0400
@@ -532,6 +532,14 @@
}
@Override
+ public AnnotatedTypeMirror applyCaptureConversion(
+ AnnotatedTypeMirror type, TypeMirror typeMirror) {
+ return this == withLeastConvenientWorld
+ ? super.applyCaptureConversion(type, typeMirror)
+ : withLeastConvenientWorld.applyCaptureConversion(type, typeMirror);
+ }
+
+ @Override
protected TypeHierarchy createTypeHierarchy() {
return new NullSpecTypeHierarchy(
checker, That seems to help. I then tried building the Google code that we use this checker on, but I discovered that I still need the wonkyness check, so I've restored that. (Having already restored the |
Yes, it works in Google, and it fixes 7 unexpected errors in
I'll create a PR to merge it into
Presumably those mixed results are a consequence of how the fix interacts with the eisop changes that revealed the problem. |
...by always performing capture conversion in _strict_ mode, where there is a better-defined hierarchy (non-null < unspecified < nullable, with no "but also unspecified < non-null if you want). Fixes jspecify#193
...by always performing capture conversion in _strict_ mode, where there is a better-defined hierarchy (non-null < unspecified < nullable, with no "but also unspecified < non-null if you want). Fixes #193
Ah, this must not have gotten automatically closed because it didn't get merged into |
Note that the |
Correction: Not all the problems I was seeing in Google's repo are fixed by #197. (I keep forgetting that I need to test the extra targets we have for special environments like J2CL....) And I assume that my promised fix to eisop defaulting isn't helpful for those, either. But it looks like the rest will be fixed once I also land the changes to update our handling of substitution with unspecified types (as discussed in jspecify/jspecify#248). That will require updates to the samples, and it will probably warrant new tests for the handling of I don't think that even the combination of those things will address the remainder of #200, but one thing at a time :) |
Or maybe I'm confused yet again? :) After kevinb9n's post tonight, I am questioning whether jspecify/jspecify#248 should actually be necessary to fix the problems I'm seeing in some of our implementations of We'll see when I get back to all this.... |
Using the command given here to test with
main-eisop
:E*
should be a valid substitute forE
in lenient mode.I'm not totally sure what's up with that one, nor even that these two errors are closely related.
Previous discussions (which also touched on the problem that
SequencedCollection
and friends are unannotated):NullSpecTypeValidator
to ensure unspecified type variables are ok #178 (comment)SequencedCollection
was added in Java 21 and needs to be handled #192I have promised to try to produce a smaller repro of this problem. For now, I'm filing this issue as a placeholder.
The text was updated successfully, but these errors were encountered: