Skip to content

Await on async work within await for loop causing unwanted stream event #37933

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

Open
tvolkert opened this issue Aug 21, 2019 · 1 comment
Open
Labels
area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)

Comments

@tvolkert
Copy link
Contributor

Consider the following code:

Future<void> main() async {
  await for (int i in foo()) {
    print('received $i');
    if (i > 1) {
      break;
    }
  }
}

Stream<int> foo() async* {
  for (int i = 0; true; i++) {
    print('yielding $i');
    yield i;
  }
}

This produces the following output:

yielding 0
received 0
yielding 1
received 1
yielding 2
received 2
yielding 3

Now, if we change the code to insert an async task in the await for loop, like so:

Future<void> main() async {
  await for (int i in foo()) {
    print('received $i');
    await bar();
    if (i > 1) {
      break;
    }
  }
}

Stream<int> foo() async* {
  for (int i = 0; true; i++) {
    print('yielding $i');
    yield i;
  }
}

Future<void> bar() async {}

It instead produces the following output:

yielding 0
received 0
yielding 1
received 1
yielding 2
received 2
yielding 3
yielding 4

For some reason, the introduction of an extra await on async work within the await for loop caused us to yield an extra value.

@lrhn
Copy link
Member

lrhn commented Aug 21, 2019

This is a bug in the implementation of async* methods.

In Dart 1, the specfication was not precise about what should happen at a yield.
The Dart 2 specification now states that it must deliver the event and then check for pauses (and be ready to handle a cancel while paused), and an await for should receive the event and then pause its subscription if it does any await. Together those should prevent the behavior you see here.

The implementations have not moved to the specified behavior yet, though. That's #34775.

@lrhn lrhn added area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. type-bug Incorrect behavior (everything from a crash to more subtle misbehavior) labels Aug 21, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)
Projects
None yet
Development

No branches or pull requests

2 participants