| // Copyright (c) 2022, 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. |
| |
| // Verifies that 'await' should check if the awaited value has a correct |
| // Future<T> type before awaiting it. A Future of incompatible type |
| // should not be awaited. |
| // |
| // Regression test for https://github.com/dart-lang/sdk/issues/49396. |
| |
| // Requirements=nnbd-strong |
| |
| import 'dart:async'; |
| import 'package:expect/expect.dart'; |
| import '../static_type_helper.dart'; |
| |
| class A {} |
| |
| abstract class B<X> extends A implements Future<X> { |
| Future<X> get fut; |
| asStream() => fut.asStream(); |
| catchError(error, {test}) => fut.catchError(error, test: test); |
| then<R>(onValue, {onError}) => fut.then(onValue, onError: onError); |
| timeout(timeLimit, {onTimeout}) => |
| fut.timeout(timeLimit, onTimeout: onTimeout); |
| whenComplete(action) => fut.whenComplete(action); |
| } |
| |
| class C extends B<Object?> { |
| final Future<Object?> fut = Future.value(CompletelyUnrelated()); |
| } |
| |
| class CompletelyUnrelated {} |
| |
| class C1 extends A {} |
| |
| class C2 extends B<C1> { |
| final Future<C1> fut = Future.value(C1()); |
| } |
| |
| void main() async { |
| final Object o = Future<Object?>.value(); |
| var o2 = await o; // Remains a future. |
| o2.expectStaticType<Exactly<Object>>(); |
| Expect.isTrue(o2 is Future<Object?>); |
| Expect.identical(o2, o); |
| |
| final FutureOr<Object> x = Future<Object?>.value(); |
| var x2 = await x; // Remains a future. |
| x2.expectStaticType<Exactly<Object>>(); |
| Expect.isTrue(x2 is Future<Object?>); |
| Expect.identical(x2, x); |
| |
| final FutureOr<Future<int>> y = Future<int>.value(1); |
| var y2 = await y; // Remains a `Future<int>`. |
| y2.expectStaticType<Exactly<Future<int>>>(); |
| Expect.isTrue(y2 is Future<int>); |
| Expect.identical(y2, y); |
| |
| A a = C(); |
| var a2 = await a; // Remains an `A`. |
| a2.expectStaticType<Exactly<A>>(); |
| Expect.isTrue(a2 is A); |
| Expect.identical(a2, a); |
| |
| Future<void> f<X extends Object>(X x) async { |
| var x2 = await x; // Remains a `Future<Object?>`. |
| Expect.isTrue(x2 is Future<Object?>); |
| Expect.identical(x2, x); |
| } |
| |
| await f(Future<Object?>.value(null)); |
| |
| Future<void> g<X extends A>(X x) async { |
| var x2 = await x; // The future is awaited. |
| Expect.isTrue(x2 is C1); |
| Expect.notIdentical(x2, x); |
| } |
| |
| await g<A>(C2()); |
| } |