-
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
Possible false positive in discarded_futures
lint
#58889
Comments
It isn't entirely clear to me what It's certainly the case that the example code is not discarding a future; it ought to be fine to pass the future as an argument to another function. So if that's the purpose of the lint, then this is clearly a bug. But if the purpose is to ensure that future-returning functions are only invoked in If anyone has context on the purpose of the lint, I'd appreciate hearing more about it. |
CC @pq who implemented |
I've just added this lint to a fairly large code-base, and the only false-positive (after adding many The entire purpose of the |
As far as I can see,
It lints situations where a function returning a Object f() async => 1; // Returns a `Future`, but the return type doesn't show it.
void g() {
f(); // No lint.
} This means that the lint allows functions returning a future to be synchronous and still call some Future<int> f() async => 1;
// Returns a future.
Future<int> g() {
f(); // Calling an `async` function and discarding a future. No lint.
return new Future<int>.value(0);
}
// Returns a non-future.
void h() {
f(); // Lint!
} I think the lint is working in a manner that makes sense: It is basically nudging developers in the direction of keeping all asynchronous computations in It also makes sense that it isn't a core lint: There are lots of situations where it does make sense that a synchronous function body calls a function that returns a future and then, say, stores that future or passes it as an actual argument to some other function. In other words, false positives are no surprise, and special application domains or coding styles may generate many false positives. However, it should perhaps be renamed to something like Or perhaps the lint should try to detect whether or not a future is actually discarded? Do the analyzer and/or the linter have the appropriate APIs to detect any such situations? It's probably a lot of work to write it from scratch... |
Renaming won't match the actual operation. When you return the future as parameter it is actually not called! So |
I'm struggling with using this lint too - in theory it's so important it should be core. But in practice it doesn't seem to be handling the right thing. Flutter's FutureBuilder is a classic case - the Future is simply not being discarded, it's being handled very nicely. Synchronously taking a reference to a future in any code in a variable (sync or async) shoudn't be linted. Where the bugs occur is if the future is no longer referenced before it is considered completed via an await, precompleted, sync'd, or another mechanism like unawaited. e.g. this is fine Future<void> doAsyncFuture() async {
await Future<void>.delayed(const Duration(seconds: 1));
}
Future<void> nonAsyncFuture() {
return Future.value(null);
}
void main() {
final myFuture = doAsyncFuture();
unawaited(myFuture);
final useThisLater = nonAsyncFuture();
}
Whereas these are potential bugs, yet hugely common especially in Flutter callback handlers. Future<void> waitFor1sMaybe() async {
doAsyncFuture();
}
final widget = Thing(
onPressed: () async {
doAsyncFuture();
Navigator.pop(context);
},
); Discarding incomplete futures as they go out of scope is where the bugs happen. It can be considered separate from anything to do with async/await, except as await being one mechanism for ensuring a future is complete. With deeper analysis, method-side opt out shouldn't be needed in the majority of cases, as the linter should see the future is being passed elsewhere or returned and not being discarded. But I suppose it's one way of systemizing the non-core unawaited library call into the linter without taking a dependency. Probably more relevant for #46218 |
It would be great to fix this lint rule (or make a new lint rule) to better live up to the rule's name: spotting futures that have been discarded, with some reasonable rate of false positives. As is, the
One possible rule might be that if the future is (a) passed to some other method or (b) returned (or (c) is the argument to an To phrase it from the other direction, I believe that rule may be equivalent to saying — but I haven't tried to verify the equivalence, and could easily be missing some cases — that a future is "discarded" just if it's the top-level expression of an expression statement. I think that would also correctly handle all the examples I've seen, including both the "good" and "bad" examples in the handy comment at #58889 just above. |
Describe the issue
I believe that the
discarded_futures
lint is too aggressive. Read on.To Reproduce
Let's see the following simple Flutter code:
And let's enable
discarded_futures
lint inanalysis_options.yaml
:And let's run
dart analyze
:That's how it looks like in my VSCode:

Expected behavior
I'd expect no warnings.
FutureBuilder.future
expects a future, I'm giving it the future, we're happy, but there'sdiscarded_futures
yelling at us.Additional context
Also:
This might be another issue, but I often see code like this:
The
discarded_futures
lint also warns about that..init()
, but we never care about it. Implementing the lint that is talked about in this issue would solve this problem.The text was updated successfully, but these errors were encountered: