| // 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. |
| |
| // Requirements=nnbd-strong |
| |
| import 'dart:async'; |
| import 'package:expect/expect.dart'; |
| import '../static_type_helper.dart'; |
| |
| // Testing the behavior of flatten (cf. SDK issue #49396). |
| |
| 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.type<Future<Object?>>(o2); |
| Expect.identical(o, o2); |
| |
| final FutureOr<Object> x = Future<Object?>.value(); |
| var x2 = await x; // Remains a future. |
| x2.expectStaticType<Exactly<Object>>(); |
| Expect.type<Future<Object?>>(x2); |
| Expect.identical(x, x2); |
| |
| final FutureOr<Future<int>> y = Future<int>.value(1); |
| var y2 = await y; // Remains a `Future<int>`. |
| y2.expectStaticType<Exactly<Future<int>>>(); |
| Expect.type<Future<int>>(y2); |
| Expect.identical(y, y2); |
| |
| A a = C(); |
| var a2 = await a; // Remains a `C` and a `Future<Object?>`. |
| a2.expectStaticType<Exactly<A>>(); |
| Expect.type<C>(a2); |
| Expect.identical(a, a2); |
| |
| // Type variable; called with `X == Object`. |
| Future<void> f1<X extends Object>(X x) async { |
| var x2 = await x; // Remains a `Future<Object?>`. |
| x2.expectStaticType<Exactly<X>>(); |
| Expect.type<Future<Object?>>(x2); |
| Expect.identical(x, x2); |
| } |
| |
| await f1<Object>(Future<Object?>.value(null)); |
| |
| // Type variable; called with `X == A`. |
| Future<void> f2<X extends A>(X x) async { |
| var x2 = await x; // The future is awaited. |
| x2.expectStaticType<Exactly<X>>(); |
| Expect.type<C1>(x2); |
| Expect.notType<C2>(x2); |
| Expect.notIdentical(x, x2); |
| } |
| |
| await f2<A>(C2()); |
| |
| // Type variable; called with `X == C2`. |
| Future<void> f3<X extends A>(X x) async { |
| var x2 = await x; // Remains a `C2` and a `Future<C1>`. |
| x2.expectStaticType<Exactly<X>>(); |
| Expect.type<C2>(x2); |
| Expect.identical(x, x2); |
| } |
| |
| await f3<C2>(C2()); |
| |
| // Type variable; value of `X` makes no difference. |
| Future<void> f4<X extends Future<A>>(X x) async { |
| var x2 = await x; // The future is awaited. |
| x2.expectStaticType<Exactly<A>>(); |
| Expect.type<C1>(x2); |
| Expect.notType<C2>(x2); |
| Expect.notIdentical(x, x2); |
| } |
| |
| await f4<Future<A>>(C2()); |
| await f4<C2>(C2()); |
| |
| // Type variable; value of `X` makes no difference. |
| Future<void> f5<X extends FutureOr<A>>(X x) async { |
| var x2 = await x; // The future is awaited. |
| x2.expectStaticType<Exactly<A>>(); |
| Expect.type<C1>(x2); |
| Expect.notType<C2>(x2); |
| Expect.notIdentical(x, x2); |
| } |
| |
| await f5<A>(C2()); |
| await f5<Future<A>>(C2()); |
| await f5<Future<C1>>(C2()); |
| await f5<C2>(C2()); |
| |
| // Promoted type variable; called with `X == Object`. |
| Future<void> g1<X>(X x) async { |
| if (x is Object) { |
| var x2 = await x; // Remains a `Future<Object?>`. |
| x2.expectStaticType<Exactly<X>>(); |
| Expect.type<Future<Object?>>(x2); |
| Expect.identical(x, x2); |
| } |
| } |
| |
| await g1<Object>(Future<Object?>.value(null)); |
| |
| // Promoted type variable; called with `X == Object?`. |
| Future<void> g2<X>(X x) async { |
| if (x is Object) { |
| var x2 = await x; // The future is awaited. |
| x2.expectStaticType<Exactly<X>>(); |
| Expect.isNull(x2); |
| } |
| } |
| |
| await g2<Object?>(Future<Object?>.value(null)); |
| |
| // Promoted type variable; called with `X == A`. |
| Future<void> g3<X>(X x) async { |
| if (x is A) { |
| var x2 = await x; // The future is awaited. |
| x2.expectStaticType<Exactly<X>>(); |
| Expect.type<C1>(x2); |
| Expect.notType<C2>(x2); |
| Expect.notIdentical(x, x2); |
| } |
| } |
| |
| await g3<A>(C2()); |
| |
| // Promoted type variable; called with `X == C2`. |
| Future<void> g4<X>(X x) async { |
| if (x is A) { |
| var x2 = await x; // Remains a `C2` and a `Future<C1>`. |
| x2.expectStaticType<Exactly<X>>(); |
| Expect.type<C2>(x2); |
| Expect.identical(x, x2); |
| } |
| } |
| |
| await g4<C2>(C2()); |
| |
| // Promoted type variable; the value of `X` does not matter. |
| Future<void> g5<X>(X x) async { |
| if (x is Future<A>) { |
| var x2 = await x; // The future is awaited. |
| x2.expectStaticType<Exactly<A>>(); |
| Expect.type<C1>(x2); |
| Expect.notType<C2>(x2); |
| Expect.notIdentical(x, x2); |
| } |
| } |
| |
| await g5<A>(C2()); |
| await g5<C2>(C2()); |
| await g5<Future<A>>(C2()); |
| |
| // Promoted type variable; the value of `X` does not matter. |
| Future<void> g6<X>(X x) async { |
| if (x is FutureOr<A>) { |
| var x2 = await x; // The future is awaited. |
| x2.expectStaticType<Exactly<A>>(); |
| Expect.type<C1>(x2); |
| Expect.notType<C2>(x2); |
| Expect.notIdentical(x, x2); |
| } |
| } |
| |
| await g6<A>(C2()); |
| await g6<C2>(C2()); |
| await g6<Future<A>>(C2()); |
| await g6<Future<C1>>(C2()); |
| |
| // Promoted type variable; values of type variables makes no difference. |
| Future<void> g7<X, Y extends Future<int>>(X x) async { |
| if (x is Future<int> && x is Y) { |
| // The promoted type of `x` is `X & Y`. |
| var x2 = await x; // The future is awaited. |
| x2.expectStaticType<Exactly<int>>(); |
| Expect.equals(1, x2); |
| } |
| } |
| |
| await g7<Object?, Future<int>>(Future<int>.value(1)); |
| |
| // S? bounded type: called with `X == Null`. |
| Future<void> h1<X extends Future<A>?>(X x) async { |
| var x2 = await x; // Remains null. |
| x2.expectStaticType<Exactly<A?>>(); |
| Expect.identical(null, x2); |
| } |
| |
| await h1<Null>(null); |
| |
| // S? bounded type: called with `X == Future<A>`. |
| Future<void> h2<X extends Future<A>?>(X x) async { |
| var x2 = await x; // The future is awaited. |
| x2.expectStaticType<Exactly<A?>>(); |
| Expect.type<C1>(x2); |
| Expect.notType<C2>(x2); |
| Expect.notIdentical(x, x2); |
| } |
| |
| await h2<Future<A>>(C2()); |
| |
| // S? bounded type: called with `X == Null`. |
| Future<void> h3<X extends FutureOr<A>?>(X x) async { |
| var x2 = await x; // Remains null. |
| x2.expectStaticType<Exactly<A?>>(); |
| Expect.identical(null, x2); |
| } |
| |
| await h3<Null>(null); |
| |
| // S? bounded type: called with `X == FutureOr<A>`. |
| Future<void> h4<X extends FutureOr<A>?>(X x) async { |
| var x2 = await x; // The future is awaited. |
| x2.expectStaticType<Exactly<A?>>(); |
| Expect.type<C1>(x2); |
| Expect.notType<C2>(x2); |
| Expect.notIdentical(x, x2); |
| } |
| |
| await h4<FutureOr<A>>(C2()); |
| } |