Change in dart/sdk[master]: Add `unawaited` function and `ignore` extensions member.

82 views
Skip to first unread message

Lasse R.H. Nielsen (Gerrit)

unread,
Jun 17, 2021, 7:03:23 AM6/17/21
to rev...@dartlang.org

Attention is currently required from: Jacob Richman.

Lasse R.H. Nielsen uploaded patch set #6 to this change.

View Change

Add `unawaited` function and `ignore` extensions member.

The `unawaited` function in `dart:async` is intended for use with the `unawaited_futures` lint which is hopefully going to be part of the Dart recommended set of lints.

The `ignore` extension method is there to provide an alternative if you even want to ignore errors from a future. By having both, it makes the distinction clearer and makes it easier to not think one can be used for everything.

Change-Id: Ib96ed5ff64ead4b228721e5210efa82f76119c9f
---
M CHANGELOG.md
M sdk/lib/async/future.dart
M sdk/lib/async/future_impl.dart
M tests/language/static_type_helper.dart
A tests/language_2/static_type_helper.dart
A tests/lib/async/future_extension_test.dart
A tests/lib/async/unawaited_error_test.dart
A tests/lib/async/unawaited_test.dart
A tests/lib_2/async/future_extension_test.dart
A tests/lib_2/async/unawaited_error_test.dart
A tests/lib_2/async/unawaited_test.dart
11 files changed, 454 insertions(+), 25 deletions(-)

To view, visit change 200428. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: master
Gerrit-Change-Id: Ib96ed5ff64ead4b228721e5210efa82f76119c9f
Gerrit-Change-Number: 200428
Gerrit-PatchSet: 6
Gerrit-Owner: Lasse R.H. Nielsen <l...@google.com>
Gerrit-Reviewer: Lasse R.H. Nielsen <l...@google.com>
Gerrit-Reviewer: Nate Bosch <nbo...@google.com>
Gerrit-CC: Jacob Richman <jac...@google.com>
Gerrit-Attention: Jacob Richman <jac...@google.com>
Gerrit-MessageType: newpatchset

Dart CI (Gerrit)

unread,
Jun 21, 2021, 7:11:20 AM6/21/21
to Lasse R.H. Nielsen, rev...@dartlang.org, Nate Bosch, Jacob Richman, commi...@chromium.org

Attention is currently required from: Jacob Richman.

go/dart-cbuild result: SUCCESS

Details: https://goto.google.com/dart-cbuild/find/b09cfbf466af6e5645803ce0d2e6c567934586cf

View Change

    To view, visit change 200428. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Ib96ed5ff64ead4b228721e5210efa82f76119c9f
    Gerrit-Change-Number: 200428
    Gerrit-PatchSet: 8
    Gerrit-Owner: Lasse R.H. Nielsen <l...@google.com>
    Gerrit-Reviewer: Lasse R.H. Nielsen <l...@google.com>
    Gerrit-Reviewer: Nate Bosch <nbo...@google.com>
    Gerrit-CC: Jacob Richman <jac...@google.com>
    Gerrit-Attention: Jacob Richman <jac...@google.com>
    Gerrit-Comment-Date: Mon, 21 Jun 2021 11:11:16 +0000
    Gerrit-HasComments: No
    Gerrit-Has-Labels: No
    Gerrit-MessageType: comment

    Dart CI (Gerrit)

    unread,
    Jun 21, 2021, 7:27:26 AM6/21/21
    to Lasse R.H. Nielsen, rev...@dartlang.org, Nate Bosch, Jacob Richman, commi...@chromium.org

    Attention is currently required from: Jacob Richman.

    go/dart-cbuild result: SUCCESS

    Details: https://goto.google.com/dart-cbuild/find/09ebde8e9d831060fa640650ba13550e127fa787

    View Change

      To view, visit change 200428. To unsubscribe, or for help writing mail filters, visit settings.

      Gerrit-Project: sdk
      Gerrit-Branch: master
      Gerrit-Change-Id: Ib96ed5ff64ead4b228721e5210efa82f76119c9f
      Gerrit-Change-Number: 200428
      Gerrit-PatchSet: 8
      Gerrit-Owner: Lasse R.H. Nielsen <l...@google.com>
      Gerrit-Reviewer: Lasse R.H. Nielsen <l...@google.com>
      Gerrit-Reviewer: Nate Bosch <nbo...@google.com>
      Gerrit-CC: Jacob Richman <jac...@google.com>
      Gerrit-Attention: Jacob Richman <jac...@google.com>
      Gerrit-Comment-Date: Mon, 21 Jun 2021 11:27:23 +0000

      Dart CI (Gerrit)

      unread,
      Jun 21, 2021, 9:03:05 AM6/21/21
      to Lasse R.H. Nielsen, rev...@dartlang.org, Nate Bosch, Jacob Richman, commi...@chromium.org

      Attention is currently required from: Jacob Richman.

      go/dart-cbuild result: SUCCESS

      Details: https://goto.google.com/dart-cbuild/find/f99ce00d6ab51dfa74ffc21943d8df33ec70d2cd

      View Change

        To view, visit change 200428. To unsubscribe, or for help writing mail filters, visit settings.

        Gerrit-Project: sdk
        Gerrit-Branch: master
        Gerrit-Change-Id: Ib96ed5ff64ead4b228721e5210efa82f76119c9f
        Gerrit-Change-Number: 200428
        Gerrit-PatchSet: 9
        Gerrit-Owner: Lasse R.H. Nielsen <l...@google.com>
        Gerrit-Reviewer: Lasse R.H. Nielsen <l...@google.com>
        Gerrit-Reviewer: Nate Bosch <nbo...@google.com>
        Gerrit-CC: Jacob Richman <jac...@google.com>
        Gerrit-Attention: Jacob Richman <jac...@google.com>
        Gerrit-Comment-Date: Mon, 21 Jun 2021 13:03:02 +0000

        Jacob Richman (Gerrit)

        unread,
        Jun 21, 2021, 2:01:20 PM6/21/21
        to Lasse R.H. Nielsen, rev...@dartlang.org, Nate Bosch, Dart CI, commi...@chromium.org

        Attention is currently required from: Lasse R.H. Nielsen.

        Patch set 9:Code-Review +1

        View Change

          To view, visit change 200428. To unsubscribe, or for help writing mail filters, visit settings.

          Gerrit-Project: sdk
          Gerrit-Branch: master
          Gerrit-Change-Id: Ib96ed5ff64ead4b228721e5210efa82f76119c9f
          Gerrit-Change-Number: 200428
          Gerrit-PatchSet: 9
          Gerrit-Owner: Lasse R.H. Nielsen <l...@google.com>
          Gerrit-Reviewer: Jacob Richman <jac...@google.com>
          Gerrit-Reviewer: Lasse R.H. Nielsen <l...@google.com>
          Gerrit-Reviewer: Nate Bosch <nbo...@google.com>
          Gerrit-Attention: Lasse R.H. Nielsen <l...@google.com>
          Gerrit-Comment-Date: Mon, 21 Jun 2021 18:01:12 +0000
          Gerrit-HasComments: No
          Gerrit-Has-Labels: Yes
          Gerrit-MessageType: comment

          Lasse R.H. Nielsen (Gerrit)

          unread,
          Jun 21, 2021, 2:02:27 PM6/21/21
          to rev...@dartlang.org, Jacob Richman, Nate Bosch, Dart CI, commi...@chromium.org

          View Change

          1 comment:

          • Patchset:

            • Patch Set #9:

              PTAL @nbosch too.

              Has changed `unawaited` to a top-level function in `dart:async`. It's not exported from `dart:core`.

          To view, visit change 200428. To unsubscribe, or for help writing mail filters, visit settings.

          Gerrit-Project: sdk
          Gerrit-Branch: master
          Gerrit-Change-Id: Ib96ed5ff64ead4b228721e5210efa82f76119c9f
          Gerrit-Change-Number: 200428
          Gerrit-PatchSet: 9
          Gerrit-Owner: Lasse R.H. Nielsen <l...@google.com>
          Gerrit-Reviewer: Jacob Richman <jac...@google.com>
          Gerrit-Reviewer: Lasse R.H. Nielsen <l...@google.com>
          Gerrit-Reviewer: Nate Bosch <nbo...@google.com>
          Gerrit-Comment-Date: Mon, 21 Jun 2021 18:02:23 +0000
          Gerrit-HasComments: Yes
          Gerrit-Has-Labels: No
          Gerrit-MessageType: comment

          Lasse R.H. Nielsen (Gerrit)

          unread,
          Jun 22, 2021, 3:02:24 PM6/22/21
          to rev...@dartlang.org, Jacob Richman, Nate Bosch, Dart CI, commi...@chromium.org

          Patch set 9:Commit-Queue +2

          View Change

            To view, visit change 200428. To unsubscribe, or for help writing mail filters, visit settings.

            Gerrit-Project: sdk
            Gerrit-Branch: master
            Gerrit-Change-Id: Ib96ed5ff64ead4b228721e5210efa82f76119c9f
            Gerrit-Change-Number: 200428
            Gerrit-PatchSet: 9
            Gerrit-Owner: Lasse R.H. Nielsen <l...@google.com>
            Gerrit-Reviewer: Jacob Richman <jac...@google.com>
            Gerrit-Reviewer: Lasse R.H. Nielsen <l...@google.com>
            Gerrit-Reviewer: Nate Bosch <nbo...@google.com>
            Gerrit-Comment-Date: Tue, 22 Jun 2021 19:02:20 +0000

            Nate Bosch (Gerrit)

            unread,
            Jun 22, 2021, 3:07:54 PM6/22/21
            to Lasse R.H. Nielsen, rev...@dartlang.org, Jacob Richman, Dart CI, commi...@chromium.org

            Attention is currently required from: Lasse R.H. Nielsen.

            Patch set 9:Code-Review +1

            View Change

              To view, visit change 200428. To unsubscribe, or for help writing mail filters, visit settings.

              Gerrit-Project: sdk
              Gerrit-Branch: master
              Gerrit-Change-Id: Ib96ed5ff64ead4b228721e5210efa82f76119c9f
              Gerrit-Change-Number: 200428
              Gerrit-PatchSet: 9
              Gerrit-Owner: Lasse R.H. Nielsen <l...@google.com>
              Gerrit-Reviewer: Jacob Richman <jac...@google.com>
              Gerrit-Reviewer: Lasse R.H. Nielsen <l...@google.com>
              Gerrit-Reviewer: Nate Bosch <nbo...@google.com>
              Gerrit-Attention: Lasse R.H. Nielsen <l...@google.com>
              Gerrit-Comment-Date: Tue, 22 Jun 2021 19:07:50 +0000

              commit-bot@chromium.org (Gerrit)

              unread,
              Jun 22, 2021, 4:03:19 PM6/22/21
              to Lasse R.H. Nielsen, rev...@dartlang.org, Jacob Richman, Nate Bosch, Dart CI

              commi...@chromium.org submitted this change.

              View Change

              Approvals: Jacob Richman: Looks good to me, approved Nate Bosch: Looks good to me, approved Lasse R.H. Nielsen: Commit
              Add `unawaited` function and `ignore` extensions member.

              The `unawaited` function in `dart:async` is intended for use with the `unawaited_futures` lint which is hopefully going to be part of the Dart recommended set of lints.

              The `ignore` extension method is there to provide an alternative if you even want to ignore errors from a future. By having both, it makes the distinction clearer and makes it easier to not think one can be used for everything.

              Change-Id: Ib96ed5ff64ead4b228721e5210efa82f76119c9f
              Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/200428
              Reviewed-by: Jacob Richman <jac...@google.com>
              Reviewed-by: Nate Bosch <nbo...@google.com>
              Commit-Queue: Lasse R.H. Nielsen <l...@google.com>

              ---
              M CHANGELOG.md
              M sdk/lib/async/future.dart
              M sdk/lib/async/future_impl.dart
              M tests/language/static_type_helper.dart
              A tests/language_2/static_type_helper.dart
              A tests/lib/async/future_extension_test.dart
              A tests/lib/async/unawaited_error_test.dart
              A tests/lib/async/unawaited_test.dart
              A tests/lib_2/async/future_extension_test.dart
              A tests/lib_2/async/unawaited_error_test.dart
              A tests/lib_2/async/unawaited_test.dart
              11 files changed, 457 insertions(+), 25 deletions(-)

              diff --git a/CHANGELOG.md b/CHANGELOG.md
              index 4b4cef9..7d5d4ba3 100644
              --- a/CHANGELOG.md
              +++ b/CHANGELOG.md
              @@ -12,9 +12,14 @@

              #### `dart:async`

              -* The uncaught error handlers of `Zone`s are now run in the parent zone
              - of the zone where they were declared. This prevents a throwing handler
              - from causing an infinite loop by repeatedly triggering itself.
              +* The uncaught error handlers of `Zone`s are now run in the parent zone
              + of the zone where they were declared. This prevents a throwing handler
              + from causing an infinite loop by repeatedly triggering itself.
              +
              +* Added `ignore()` as extension member on futures.
              +
              +* Added `void unawaited(Future)` top-level function to deal with
              + the `unawaited_futures` lint.

              #### `dart:core`

              diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
              index 4d98a53..edc6264 100644
              --- a/sdk/lib/async/future.dart
              +++ b/sdk/lib/async/future.dart
              @@ -698,6 +698,30 @@
              Future<T> timeout(Duration timeLimit, {FutureOr<T> onTimeout()?});
              }

              +/// Explicitly ignores a future.
              +///
              +/// Not all futures need to be awaited.
              +/// The Dart linter has an optional ["unawaited futures" lint](https://dart-lang.github.io/linter/lints/unawaited_futures.html)
              +/// which enforces that futures (expressions with a static type of [Future])
              +/// in asynchronous functions are handled *somehow*.
              +/// If a particular future value doesn't need to be awaited,
              +/// you can call `unawaited(...)` with it, which will avoid the lint,
              +/// simply because the expression no longer has type [Future].
              +/// Using `unawaited` has no other effect.
              +/// You should use `unawaited` to convey the *intention* of
              +/// deliberately not waiting for the future.
              +///
              +/// If the future completes with an error,
              +/// it was likely a mistake to not await it.
              +/// That error will still occur and will be considered unhandled
              +/// unless the same future is awaited (or otherwise handled) elsewhere too.
              +/// Because of that, `unawaited` should only be used for futures that
              +/// are *expected* to complete with a value.
              +/// You can use [FutureExtension.ignore] if you also don't want to know
              +/// about errors from this future.
              +@Since("2.15")
              +void unawaited(Future<void> future) {}
              +
              /// Convenience methods on futures.
              ///
              /// Adds functionality to futures which makes it easier to
              @@ -770,6 +794,32 @@
              handleError(error as E, stackTrace),
              test: (Object error) => error is E && (test == null || test(error)));
              }
              +
              + /// Completely ignores this future and its result.
              + ///
              + /// Not all futures are important, not even if they contain errors,
              + /// for example if a request was made, but the response is no longer needed.
              + /// Simply ignoring a future can result in uncaught asynchronous errors.
              + /// This method instead handles (and ignores) any values or errors
              + /// coming from this future, making it safe to otherwise ignore
              + /// the future.
              + ///
              + /// Use `ignore` to signal that the result of the future is
              + /// no longer important to the program, not even if it's an error.
              + /// If you merely want to silence the ["unawaited futures" lint](https://dart-lang.github.io/linter/lints/unawaited_futures.html),
              + /// use the [unawaited] function instead.
              + /// That will ensure that an unexpected error is still reported.
              + @Since("2.15")
              + void ignore() {
              + var self = this;
              + if (self is _Future<T>) {
              + self._ignore();
              + } else {
              + self.then<void>(_ignore, onError: _ignore);
              + }
              + }
              +
              + static void _ignore(Object? _, [Object? __]) {}
              }

              /// Thrown when a scheduled timeout happens while waiting for an async result.
              diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart
              index e73300f..c89d345 100644
              --- a/sdk/lib/async/future_impl.dart
              +++ b/sdk/lib/async/future_impl.dart
              @@ -69,9 +69,14 @@
              static const int maskTestError = 4;
              static const int maskWhenComplete = 8;
              static const int stateChain = 0;
              + // Handles values, passes errors on.
              static const int stateThen = maskValue;
              + // Handles values and errors.
              static const int stateThenOnerror = maskValue | maskError;
              + // Handles errors, has errorCallback.
              static const int stateCatchError = maskError;
              + // Ignores both values and errors. Has no callback or errorCallback.
              + // The [result] future is ignored, its always the same as the source.
              static const int stateCatchErrorTest = maskError | maskTestError;
              static const int stateWhenComplete = maskWhenComplete;
              static const int maskType =
              @@ -191,21 +196,40 @@
              /// [_FutureListener] listeners.
              static const int _stateIncomplete = 0;

              + /// Flag set when an error need not be handled.
              + ///
              + /// Set by the [FutureExtensions.ignore] method to avoid
              + /// having to introduce an unnecessary listener.
              + /// Only relevant until the future is completed.
              + static const int _stateIgnoreError = 1;
              +
              /// Pending completion. Set when completed using [_asyncComplete] or
              /// [_asyncCompleteError]. It is an error to try to complete it again.
              /// [_resultOrListeners] holds listeners.
              - static const int _statePendingComplete = 1;
              + static const int _statePendingComplete = 2;

              - /// The future has been chained to another future. The result of that
              - /// other future becomes the result of this future as well.
              + /// The future has been chained to another "source" [_Future].
              + ///
              + /// The result of that other future becomes the result of this future
              + /// as well, when the other future completes.
              + /// This future cannot be completed again.
              /// [_resultOrListeners] contains the source future.
              - static const int _stateChained = 2;
              + /// Listeners have been moved to the chained future.
              + static const int _stateChained = 4;

              /// The future has been completed with a value result.
              - static const int _stateValue = 4;
              + ///
              + /// [_resultOrListeners] contains the value.
              + static const int _stateValue = 8;

              /// The future has been completed with an error result.
              - static const int _stateError = 8;
              + ///
              + /// [_resultOrListeners] contains an [AsyncEror]
              + /// holding the error and stack trace.
              + static const int _stateError = 16;
              +
              + /// Mask for the states above except [_stateIgnoreError].
              + static const int _completionStateMask = 30;

              /// Whether the future is complete, and as what.
              int _state = _stateIncomplete;
              @@ -227,8 +251,8 @@
              /// and it is not chained to another future.
              ///
              /// The future is another future that this future is chained to. This future
              - /// is waiting for the other future to complete, and when it does, this future
              - /// will complete with the same result.
              + /// is waiting for the other future to complete, and when it does,
              + /// this future will complete with the same result.
              /// All listeners are forwarded to the other future.
              @pragma("vm:entry-point")
              var _resultOrListeners;
              @@ -253,12 +277,14 @@
              /// Creates a future that is already completed with the value.
              _Future.value(T value) : this.zoneValue(value, Zone._current);

              - bool get _mayComplete => _state == _stateIncomplete;
              - bool get _isPendingComplete => _state == _statePendingComplete;
              - bool get _mayAddListener => _state <= _statePendingComplete;
              - bool get _isChained => _state == _stateChained;
              - bool get _isComplete => _state >= _stateValue;
              - bool get _hasError => _state == _stateError;
              + bool get _mayComplete => (_state & _completionStateMask) == _stateIncomplete;
              + bool get _isPendingComplete => (_state & _statePendingComplete) != 0;
              + bool get _mayAddListener =>
              + _state <= (_statePendingComplete | _stateIgnoreError);
              + bool get _isChained => (_state & _stateChained) != 0;
              + bool get _isComplete => (_state & (_stateValue | _stateError)) != 0;
              + bool get _hasError => (_state & _stateError) != 0;
              + bool get _ignoreError => (_state & _stateIgnoreError) != 0;

              static List<Function>? _continuationFunctions(_Future<Object> future) {
              List<Function>? result = null;
              @@ -283,7 +309,7 @@

              void _setChained(_Future source) {
              assert(_mayAddListener);
              - _state = _stateChained;
              + _state = _stateChained | (_state & _stateIgnoreError);
              _resultOrListeners = source;
              }

              @@ -315,6 +341,10 @@
              return result;
              }

              + void _ignore() {
              + _state |= _stateIgnoreError;
              + }
              +
              Future<T> catchError(Function onError, {bool test(Object error)?}) {
              _Future<T> result = new _Future<T>();
              if (!identical(result._zone, _rootZone)) {
              @@ -337,13 +367,13 @@
              Stream<T> asStream() => new Stream<T>.fromFuture(this);

              void _setPendingComplete() {
              - assert(_mayComplete);
              - _state = _statePendingComplete;
              + assert(_mayComplete); // Aka _statIncomplete
              + _state ^= _stateIncomplete ^ _statePendingComplete;
              }

              void _clearPendingComplete() {
              assert(_isPendingComplete);
              - _state = _stateIncomplete;
              + _state ^= _statePendingComplete ^ _stateIncomplete;
              }

              AsyncError get _error {
              @@ -365,7 +395,7 @@

              void _setErrorObject(AsyncError error) {
              assert(!_isComplete); // But may have a completion pending.
              - _state = _stateError;
              + _state = _stateError | (_state & _stateIgnoreError);
              _resultOrListeners = error;
              }

              @@ -379,7 +409,8 @@
              void _cloneResult(_Future source) {
              assert(!_isComplete);
              assert(source._isComplete);
              - _state = source._state;
              + _state =
              + (source._state & _completionStateMask) | (_state & _stateIgnoreError);
              _resultOrListeners = source._resultOrListeners;
              }

              @@ -615,7 +646,7 @@
              assert(source._isComplete);
              bool hasError = source._hasError;
              if (listeners == null) {
              - if (hasError) {
              + if (hasError && !source._ignoreError) {
              AsyncError asyncError = source._error;
              source._zone
              .handleUncaughtError(asyncError.error, asyncError.stackTrace);
              diff --git a/tests/language/static_type_helper.dart b/tests/language/static_type_helper.dart
              index 9484387..4a7809a 100644
              --- a/tests/language/static_type_helper.dart
              +++ b/tests/language/static_type_helper.dart
              @@ -2,7 +2,10 @@
              // for details. All rights reserved. Use of this source code is governed by a
              // BSD-style license that can be found in the LICENSE file.

              -// Ensures a context type of [T] for the operand.
              +/// Helper to create [Type] values.
              +Type typeOf<T>() => T;
              +
              +/// Ensures a context type of [T] for the operand.
              void context<T>(T x) {}

              /// Captures the context type of the call and returns the same type.
              @@ -34,6 +37,23 @@
              T expectStaticType<R extends Exactly<T>>() {
              return this;
              }
              +
              + /// Invokes [callback] with the static type of `this`.
              + ///
              + /// Allows any operation on the type.
              + T captureStaticType(void Function<X>() callback) {
              + callback<T>();
              + return this;
              + }
              +}
              +
              +/// Invokes [callback] with the static type of [value].
              +///
              +/// Similar to [StaticType.captureStaticType], but works
              +/// for types like `void` and `dynamic` which do not allow
              +/// extension methods.
              +void captureStaticType<T>(T value, void Function<X>(X value) callback) {
              + callback<T>(value);
              }

              /// Use with [StaticType.expectStaticType] to expect precisely the type [T].
              diff --git a/tests/language_2/static_type_helper.dart b/tests/language_2/static_type_helper.dart
              new file mode 100644
              index 0000000..4a7809a
              --- /dev/null
              +++ b/tests/language_2/static_type_helper.dart
              @@ -0,0 +1,90 @@
              +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
              +// for details. All rights reserved. Use of this source code is governed by a
              +// BSD-style license that can be found in the LICENSE file.
              +
              +/// Helper to create [Type] values.
              +Type typeOf<T>() => T;
              +
              +/// Ensures a context type of [T] for the operand.
              +void context<T>(T x) {}
              +
              +/// Captures the context type of the call and returns the same type.
              +///
              +/// Can be used to check the context type as:
              +/// ```dart
              +/// int x = contextType(1 /* valid value */)..expectStaticType<Exactly<int>>;
              +/// ```
              +T contextType<T>(Object result) => result as T;
              +
              +extension StaticType<T> on T {
              + /// Check the static type.
              + ///
              + /// Use as follows (assuming `e` has static type `num`):
              + /// ```dart
              + /// e.expectStaticType<Exactly<num>>() // No context type.
              + /// e.expectStaticType<SubtypeOf<Object>>() // No context type.
              + /// e.expectStaticType<SupertypeOf<int>>() // No context type.
              + /// ```
              + /// or
              + /// ```dart
              + /// e..expectStaticType<Exactly<num>>() // Preserve context type.
              + /// e..expectStaticType<SubtypeOf<Object>>() // Preserve context type.
              + /// e..expectStaticType<SupertypeOf<int>>() // Preserve context type.
              + /// ```
              + /// This will be a *compile-time error* if the static type is not
              + /// as required by the constraints type (the one passed to [Exactly],
              + /// [SubtypeOf] or [SupertypeOf].)
              + T expectStaticType<R extends Exactly<T>>() {
              + return this;
              + }
              +
              + /// Invokes [callback] with the static type of `this`.
              + ///
              + /// Allows any operation on the type.
              + T captureStaticType(void Function<X>() callback) {
              + callback<T>();
              + return this;
              + }
              +}
              +
              +/// Invokes [callback] with the static type of [value].
              +///
              +/// Similar to [StaticType.captureStaticType], but works
              +/// for types like `void` and `dynamic` which do not allow
              +/// extension methods.
              +void captureStaticType<T>(T value, void Function<X>(X value) callback) {
              + callback<T>(value);
              +}
              +
              +/// Use with [StaticType.expectStaticType] to expect precisely the type [T].
              +///
              +/// Example use:
              +/// ```dart
              +/// "abc".expectStaticType<Exactly<String>>();
              +/// ```
              +typedef Exactly<T> = T Function(T);
              +
              +/// Use with [StaticType.expectStaticType] to expect a subtype of [T].
              +///
              +/// Example use:
              +/// ```dart
              +/// num x = 1;
              +/// x.expectStaticType<SubtypeOf<Object>>();
              +/// ```
              +typedef SubtypeOf<T> = Never Function(T);
              +
              +/// Use with [StaticType.expectStaticType] to expect a supertype of [T].
              +///
              +/// Example use:
              +/// ```dart
              +/// num x = 1;
              +/// x.expectStaticType<SupertypeOf<int>>();
              +/// ```
              +typedef SupertypeOf<T> = T Function(Object?);
              +
              +/// Checks that an expression is assignable to [T1], [T2] and [Object].
              +///
              +/// This ensures that the static type of the expression is either dynamic,
              +/// Never, or a type assignable to both [T1] and [T2], and if those are
              +/// unrelated, it must be an intersection type.
              +void checkIntersectionType<T1, T2>(T1 v1, T2 v2, Object v3) {}
              diff --git a/tests/lib/async/future_extension_test.dart b/tests/lib/async/future_extension_test.dart
              new file mode 100644
              index 0000000..cd28986
              --- /dev/null
              +++ b/tests/lib/async/future_extension_test.dart
              @@ -0,0 +1,54 @@
              +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
              +// for details. All rights reserved. Use of this source code is governed by a
              +// BSD-style license that can be found in the LICENSE file.
              +
              +import 'package:async_helper/async_helper.dart';
              +import "package:expect/expect.dart";
              +import 'dart:async' show Completer, runZonedGuarded;
              +import '../../language/static_type_helper.dart';
              +
              +void main() {
              + testIgnore();
              +}
              +
              +void testIgnore() {
              + var future = Future<int>.value(42);
              + captureStaticType(future.ignore(), <T>(T value) {
              + Expect.equals(typeOf<void>(), T);
              + });
              +
              + asyncStart();
              + // Ignored futures can still be listend to.
              + {
              + var c = Completer<int>.sync();
              + var f = c.future;
              + f.ignore();
              + asyncStart();
              + f.catchError((e) {
              + Expect.equals("ERROR1", e);
              + asyncEnd();
              + return 0;
              + });
              + c.completeError("ERROR1");
              + }
              +
              + // Ignored futures are not uncaught errors.
              + {
              + asyncStart();
              + bool threw = false;
              + runZonedGuarded(() {
              + var c = Completer<int>.sync();
              + var f = c.future;
              + f.ignore();
              + c.completeError("ERROR2");
              + }, (e, s) {
              + threw = true;
              + Expect.fail("Should not happen: $e");
              + });
              + Future.delayed(Duration.zero, () {
              + if (threw) Expect.fail("Future not ignored.");
              + asyncEnd();
              + });
              + }
              + asyncEnd();
              +}
              diff --git a/tests/lib/async/unawaited_error_test.dart b/tests/lib/async/unawaited_error_test.dart
              new file mode 100644
              index 0000000..597a9f8
              --- /dev/null
              +++ b/tests/lib/async/unawaited_error_test.dart
              @@ -0,0 +1,11 @@
              +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
              +// for details. All rights reserved. Use of this source code is governed by a
              +// BSD-style license that can be found in the LICENSE file.
              +
              +void main() {
              + // The `unawaited` function is not exposed by dart:core.
              + unawaited;
              + // [error line 7, column 3, length 9]
              + // [cfe] Getter not found: 'unawaited'.
              + // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER
              +}
              diff --git a/tests/lib/async/unawaited_test.dart b/tests/lib/async/unawaited_test.dart
              new file mode 100644
              index 0000000..dc095cc
              --- /dev/null
              +++ b/tests/lib/async/unawaited_test.dart
              @@ -0,0 +1,52 @@
              +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
              +// for details. All rights reserved. Use of this source code is governed by a
              +// BSD-style license that can be found in the LICENSE file.
              +
              +import 'package:async_helper/async_helper.dart';
              +import "package:expect/expect.dart";
              +import 'dart:async' show Completer, runZonedGuarded, unawaited;
              +import 'dart:async' as prefix;
              +import '../../language/static_type_helper.dart';
              +
              +void main() {
              + testUnawaited();
              +}
              +
              +void testUnawaited() {
              + // Exists where expected.
              + prefix.unawaited.expectStaticType<Exactly<void Function(Future<Object?>)>>();
              +
              + var future = Future<int>.value(42);
              + captureStaticType(unawaited(future), <T>(value) {
              + Expect.equals(typeOf<void>(), T);
              + });
              +
              + asyncStart();
              + // Unawaited futures still throw.
              + {
              + var c = Completer<int>();
              + var f = c.future;
              + unawaited(f);
              + asyncStart();
              + f.catchError((e) {
              + Expect.equals("ERROR1", e);
              + asyncEnd();
              + return 0;
              + });
              + c.completeError("ERROR1");
              + }
              + // Unawaited futures are still uncaught errors.
              + {
              + asyncStart();
              + runZonedGuarded(() {
              + var c = Completer<int>();
              + var f = c.future;
              + unawaited(f);
              + c.completeError("ERROR2");
              + }, (e, s) {
              + Expect.equals("ERROR2", e);
              + asyncEnd();
              + });
              + }
              + asyncEnd();
              +}
              diff --git a/tests/lib_2/async/future_extension_test.dart b/tests/lib_2/async/future_extension_test.dart
              new file mode 100644
              index 0000000..cd28986
              --- /dev/null
              +++ b/tests/lib_2/async/future_extension_test.dart
              @@ -0,0 +1,54 @@
              +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
              +// for details. All rights reserved. Use of this source code is governed by a
              +// BSD-style license that can be found in the LICENSE file.
              +
              +import 'package:async_helper/async_helper.dart';
              +import "package:expect/expect.dart";
              +import 'dart:async' show Completer, runZonedGuarded;
              +import '../../language/static_type_helper.dart';
              +
              +void main() {
              + testIgnore();
              +}
              +
              +void testIgnore() {
              + var future = Future<int>.value(42);
              + captureStaticType(future.ignore(), <T>(T value) {
              + Expect.equals(typeOf<void>(), T);
              + });
              +
              + asyncStart();
              + // Ignored futures can still be listend to.
              + {
              + var c = Completer<int>.sync();
              + var f = c.future;
              + f.ignore();
              + asyncStart();
              + f.catchError((e) {
              + Expect.equals("ERROR1", e);
              + asyncEnd();
              + return 0;
              + });
              + c.completeError("ERROR1");
              + }
              +
              + // Ignored futures are not uncaught errors.
              + {
              + asyncStart();
              + bool threw = false;
              + runZonedGuarded(() {
              + var c = Completer<int>.sync();
              + var f = c.future;
              + f.ignore();
              + c.completeError("ERROR2");
              + }, (e, s) {
              + threw = true;
              + Expect.fail("Should not happen: $e");
              + });
              + Future.delayed(Duration.zero, () {
              + if (threw) Expect.fail("Future not ignored.");
              + asyncEnd();
              + });
              + }
              + asyncEnd();
              +}
              diff --git a/tests/lib_2/async/unawaited_error_test.dart b/tests/lib_2/async/unawaited_error_test.dart
              new file mode 100644
              index 0000000..597a9f8
              --- /dev/null
              +++ b/tests/lib_2/async/unawaited_error_test.dart
              @@ -0,0 +1,11 @@
              +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
              +// for details. All rights reserved. Use of this source code is governed by a
              +// BSD-style license that can be found in the LICENSE file.
              +
              +void main() {
              + // The `unawaited` function is not exposed by dart:core.
              + unawaited;
              + // [error line 7, column 3, length 9]
              + // [cfe] Getter not found: 'unawaited'.
              + // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER
              +}
              diff --git a/tests/lib_2/async/unawaited_test.dart b/tests/lib_2/async/unawaited_test.dart
              new file mode 100644
              index 0000000..16bd285
              --- /dev/null
              +++ b/tests/lib_2/async/unawaited_test.dart
              @@ -0,0 +1,54 @@
              +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
              +// for details. All rights reserved. Use of this source code is governed by a
              +// BSD-style license that can be found in the LICENSE file.
              +
              +// @dart = 2.9
              +
              +import 'package:async_helper/async_helper.dart';
              +import "package:expect/expect.dart";
              +import 'dart:async' show Completer, runZonedGuarded, unawaited;
              +import 'dart:async' as prefix;
              +import '../../language/static_type_helper.dart';
              +
              +void main() {
              + testUnawaited();
              +}
              +
              +void testUnawaited() {
              + // Exists where expected.
              + prefix.unawaited.expectStaticType<Exactly<void Function(Future<Object>)>>();
              +
              + var future = Future<int>.value(42);
              + captureStaticType(unawaited(future), <T>(value) {
              + Expect.equals(typeOf<void>(), T);
              + });
              +
              + asyncStart();
              + // Unawaited futures still throw.
              + {
              + var c = Completer<int>();
              + var f = c.future;
              + unawaited(f);
              + asyncStart();
              + f.catchError((e) {
              + Expect.equals("ERROR1", e);
              + asyncEnd();
              + return 0;
              + });
              + c.completeError("ERROR1");
              + }
              + // Unawaited futures are still uncaught errors.
              + {
              + asyncStart();
              + runZonedGuarded(() {
              + var c = Completer<int>();
              + var f = c.future;
              + unawaited(f);
              + c.completeError("ERROR2");
              + }, (e, s) {
              + Expect.equals("ERROR2", e);
              + asyncEnd();
              + });
              + }
              + asyncEnd();
              +}

              To view, visit change 200428. To unsubscribe, or for help writing mail filters, visit settings.

              Gerrit-Project: sdk
              Gerrit-Branch: master
              Gerrit-Change-Id: Ib96ed5ff64ead4b228721e5210efa82f76119c9f
              Gerrit-Change-Number: 200428
              Gerrit-PatchSet: 10
              Gerrit-Owner: Lasse R.H. Nielsen <l...@google.com>
              Gerrit-Reviewer: Jacob Richman <jac...@google.com>
              Gerrit-Reviewer: Lasse R.H. Nielsen <l...@google.com>
              Gerrit-Reviewer: Nate Bosch <nbo...@google.com>
              Gerrit-MessageType: merged

              Dart CI (Gerrit)

              unread,
              Jun 22, 2021, 6:18:17 PM6/22/21
              to commi...@chromium.org, Lasse R.H. Nielsen, rev...@dartlang.org, Jacob Richman, Nate Bosch

              go/dart-cbuild result: FAILURE (NO REGRESSIONS DETECTED)

              Details: https://goto.google.com/dart-cbuild/find/902f149e2c25926310b463a92891169f75024706

              View Change

                To view, visit change 200428. To unsubscribe, or for help writing mail filters, visit settings.

                Gerrit-Project: sdk
                Gerrit-Branch: master
                Gerrit-Change-Id: Ib96ed5ff64ead4b228721e5210efa82f76119c9f
                Gerrit-Change-Number: 200428
                Gerrit-PatchSet: 10
                Gerrit-Owner: Lasse R.H. Nielsen <l...@google.com>
                Gerrit-Reviewer: Jacob Richman <jac...@google.com>
                Gerrit-Reviewer: Lasse R.H. Nielsen <l...@google.com>
                Gerrit-Reviewer: Nate Bosch <nbo...@google.com>
                Gerrit-Comment-Date: Tue, 22 Jun 2021 22:18:13 +0000
                Reply all
                Reply to author
                Forward
                0 new messages