-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Future.then inference does not work for classes that implement Future #27101
Comments
CC @nex3 @leafpetersen -- could y'all discuss and decide what to do here? I'll mark P1 in the meantime since this is blocking-ish |
I looked at the code briefly. It looked like it might not be too bad to extend this inference to classes which extend or implement Future, and which don't change the signature of .then. @jmesserly does that seem reasonable to you as well? @nex3 mentioned that there were similar patterns that currently sort of work because of Future flattening. Do you have concrete examples I can look at? Generally speaking, we can only take ad hoc inference so far, and extending it to other types that are unrelated to Future I think is too far. Future flattening sometimes does the right thing, but it is very confusing to users, and it's very problematic in the type system. I'd really prefer to move away from it. @jmesserly did you already rip it out, or is it still there for the time being? Until we get union types and/or overloading, APIs that both want to get good inference and provide overloading like functionality are probably going to have to do so via explicit overloads (that is, provide the equivalent of a |
yeah that sounds right to me.
well in general, any you have a type parameter |
This would force packages to make major breaking changes to their public APIs, to the detriment of users. |
@leafpetersen -- well maybe this is a terrible idea, but we could consider something like: whenever we see a that's probably way too crazy, so a less crazy idea is: we put |
Correct me if I'm wrong, but I think that Future.then is currently in a good place. Subclasses of Future.then can also be put into a good place, at some (but not too much) cost. The issue which @nex3 is concerned about is the set of other "Future.then like" methods that are out there for which we don't have ad hoc inference. I believe that these currently will still work as before because Future flattening is still in the type system (correct me if I'm wrong). So assuming we generalize the current inference to subclasses of Future, I think we're in an ok place for the short term. However, future flattening is a very expensive feature. It does quite a bit of violence to the static type system (which I could live with), and it also reaches into the dynamic type system. All of the implementations (VM, dart2js, DDC) will have to bake this into their reified type system. This isn't out of the question (DDC does it, though I have low confidence that it's 100% correct), but it's a big cost in complexity, and I think a likely source of soundness holes. I'd really like to avoid supporting this in the long term if at all possible. There are actually two parts of the Future.then ad hoc inference, I think. The main one is that inference essentially treats Future.then as having an overloaded signature: it tries to infer based on the type I believe that @nex3 is mostly concerned with the first part (since the second part didn't exist until just recently anyway). Assuming so, I wonder if we could address this by generalizing slightly to a notion of an "inference pattern" which generalizes the ad hoc "try this signature and then this other one". So the idea would be to use some sort of annotation or comment syntax to allow methods to be marked as essentially having an overloaded type strictly for the purpose of doing inference. This could potentially help with a fairly wide range of API surfaces: it might be enough to help address some of the other async functions we've discussed elsewhere. Thoughts? |
This would work for me, but would the other implementation teams go for it? |
@leafpetersen -- regarding your "Correct me if I'm wrong" ... all of those statements are correct :)
yeah I love that idea. +1 from me. RE: other implementations, I think type inference stuff only needs to be implemented once in the "shared front end" |
Some more context, this is causing test and build failures due to strong mode errors third_party/dart/async/lib/src/delegate/future.dart:30: [ERROR] Invalid override. The type of DelegatingFuture.then (<S>((T) → S, {onError: Function}) → Future<S>) is not a subtype of Future<T>.then (<S>((T) → dynamic, {onError: Function}) → Future<S>). [STRONG_MODE_INVALID_METHOD_OVERRIDE] third_party/dart/async/lib/src/typed/future.dart:17: [ERROR] Invalid override. The type of TypeSafeFuture.then (<S>((T) → S, {onError: Function}) → Future<S>) is not a subtype of Future<T>.then (<S>((T) → dynamic, {onError: Function}) → Future<S>). [STRONG_MODE_INVALID_METHOD_OVERRIDE] There are also other classes in internal code that implement And a cl - https://codereview.chromium.org/2250513003/ |
The original change improves inference dramatically. Lots of places where users currently have to write This change should be landed, and then we can see what the impact of the regression actually is. I will look into extending the ad hoc inference to subclasses of Future. If the regression is small, I suggest we live with the regression for now and land any extensions in the next roll. |
Now that Keerti's CL landed can we lower the priority to P1? |
This is a backwards incompatibility that affects real code. I'd like to be able to discuss it without the time pressure of an impending release, so I think we should roll back the breaking change for 1.19. |
I'm a little confused about context. @nex3 what is the backwards incompatible change that you're referring to? |
By the way, if Leaf doesn't beat me to it, I should be able to have a look at this bug tomorrow. In other words, the request for downwards inference on Future.then subtypes. (the change to match the new Future.then signature is still needed in subtypes) |
Changing the type of |
folding is still there, so that's good :) Future.then signature change was intentional. It's backwards-incompatible to strong mode, but we aren't done with strong mode, so breaking changes do happen from time to time. There are quite a few in the 1.19 release, as a consequence of adding many inference improvements. (and even making Future.then generic at all was a breaking change w.r.t. Dart 1, but we need to do these sort of things or folks would be passing explicit types everywhere) I know it's not fun to pass generic method types explicitly, especially with the annoying comment syntax, but what we gained on this one was a lot more than we lost. And I think we can fix this issue before 1.19 meaning the net loss will be zero :) |
@leafpetersen i'm assigning to you because I think you were working on it based on our conversation yesterday |
I'm mostly done with this - just triaging a couple of test cases to be sure I understand a couple of corner cases. |
@scheglov would you mind filing a new issue for that? I don't think it is related to this one. |
OK, I've opened a new issue. |
I'm not arguing for no breaking changes, just for being careful and working to mitigate the problems they cause. Ideally they'd be introduced early in the dev cycle for a new version, and we'd have a strong process in place for figuring out what concrete problems they cause and figuring out a way to ameliorate those problems. |
Definitely. In an ideal world we'd be able to develop against our internal repository and see the complete effect of inference changes. Unfortunately we aren't set up for that yet. But perhaps we will be soon. |
Fixes #27101 BUG= R=jmesserly@google.com Review URL: https://codereview.chromium.org/2260313002 .
Future.then now has really nice inference, in particular we understand that the "real" signature is one of:
We special case it in both downwards and upwards inference. However it does not work for a user-defined type that implements Future (often to simply forward).
original context https://codereview.chromium.org/2250513003/
The text was updated successfully, but these errors were encountered: