Skip to content

Wrong async return semantics #44395

Open
Open
@eernstg

Description

@eernstg

[Edit: This issue is blocked on dart-lang/language#870; see this comment for details.]

Consider the following program:

Future<void> f() async {
  throw 'f';
}

Future<void> g() async {
  try {
    return f();
  } catch (e) {
    print('Caught "$e"');
  }
}

void main() async {
  await g(); // Should print 'Caught "f"'.
}

Execution of this program with dart (from 74be667, and 2.12.0-96.0.dev) gives rise to the following output:

Unhandled exception:
f
#0      f (file:///usr/local/google/home/eernst/lang/dart/scratch/202012/n011.dart:2:3)
dart-lang/sdk#57147      g (file:///usr/local/google/home/eernst/lang/dart/scratch/202012/n011.dart:7:12)
dart-lang/sdk#57148      main (file:///usr/local/google/home/eernst/lang/dart/scratch/202012/n011.dart:14:9)
dart-lang/sdk#57149      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:283:19)
dart-lang/sdk#57150      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)

However, the semantics of return f() should have been as follows:

When $f$ is an asynchronous non-generator with future value type $T_v$
(\ref{functions}), evaluation proceeds as follows:

($f$ is the function whose body contains the return statement)

The expression $e$ is evaluated to an object $o$.

(In this case, $o$ is an instance of a subtype of Future whose type argument at Future is void.)

If the run-time type of $o$ is a subtype of \code{Future<$T_v$>},

($T_v$ is the future value type of $f$, that is, void. And the subtype relation does hold.)

let \code{v} be a fresh variable bound to $o$ and
evaluate \code{\AWAIT{} v} to an object $r$;
otherwise let $r$ be $o$.
...

The evaluation of said await v will throw, and hence we should proceed to execute the print statement and return from g by completing the body normally (and implicitly completing the returned future with the null object).

The actual behavior indicates that no such evaluation of await v occurs, and the returned future is completed with the thrown exception, so await g() in main throws.

In legacy code the await occurs at the same point, with similar spec language, since commit 5af9844 of Sep 17, 2018.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P4area-metaCross-cutting, high-level issues (for tracking many other implementation issues, ...).status-blockedBlocked from making progress by another (referenced) issuetype-bugIncorrect behavior (everything from a crash to more subtle misbehavior)vm-technical-debtThis label tries to capture all the technical debt that we have accumulated in the Dart VMweb-technical-debt

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions