diff --git a/tests/language/async/await_flatten_test.dart b/tests/language/async/await_flatten_test.dart new file mode 100644 index 00000000000..5d2342f28f5 --- /dev/null +++ b/tests/language/async/await_flatten_test.dart @@ -0,0 +1,247 @@ +// 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. + +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 extends A implements Future { + Future get fut; + asStream() => fut.asStream(); + catchError(error, {test}) => fut.catchError(error, test: test); + then(onValue, {onError}) => fut.then(onValue, onError: onError); + timeout(timeLimit, {onTimeout}) => + fut.timeout(timeLimit, onTimeout: onTimeout); + whenComplete(action) => fut.whenComplete(action); +} + +class C extends B { + final Future fut = Future.value(CompletelyUnrelated()); +} + +class CompletelyUnrelated {} + +class C1 extends A {} + +class C2 extends B { + final Future fut = Future.value(C1()); +} + +void main() async { + final Object o = Future.value(); + var o2 = await o; // Remains a future. + o2.expectStaticType>(); + Expect.type>(o2); + Expect.identical(o, o2); + + final FutureOr x = Future.value(); + var x2 = await x; // Remains a future. + x2.expectStaticType>(); + Expect.type>(x2); + Expect.identical(x, x2); + + final FutureOr> y = Future.value(1); + var y2 = await y; // Remains a `Future`. + y2.expectStaticType>>(); + Expect.type>(y2); + Expect.identical(y, y2); + + A a = C(); + var a2 = await a; // Remains a `C` and a `Future`. + a2.expectStaticType>(); + Expect.type(a2); + Expect.identical(a, a2); + + // Type variable; called with `X == Object`. + Future f1(X x) async { + var x2 = await x; // Remains a `Future`. + x2.expectStaticType>(); + Expect.type>(x2); + Expect.identical(x, x2); + } + + await f1(Future.value(null)); + + // Type variable; called with `X == A`. + Future f2(X x) async { + var x2 = await x; // The future is awaited. + x2.expectStaticType>(); + Expect.type(x2); + Expect.notType(x2); + Expect.notIdentical(x, x2); + } + + await f2(C2()); + + // Type variable; called with `X == C2`. + Future f3(X x) async { + var x2 = await x; // Remains a `C2` and a `Future`. + x2.expectStaticType>(); + Expect.type(x2); + Expect.identical(x, x2); + } + + await f3(C2()); + + // Type variable; value of `X` makes no difference. + Future f4>(X x) async { + var x2 = await x; // The future is awaited. + x2.expectStaticType>(); + Expect.type(x2); + Expect.notType(x2); + Expect.notIdentical(x, x2); + } + + await f4>(C2()); + await f4(C2()); + + // Type variable; value of `X` makes no difference. + Future f5>(X x) async { + var x2 = await x; // The future is awaited. + x2.expectStaticType>(); + Expect.type(x2); + Expect.notType(x2); + Expect.notIdentical(x, x2); + } + + await f5(C2()); + await f5>(C2()); + await f5>(C2()); + await f5(C2()); + + // Promoted type variable; called with `X == Object`. + Future g1(X x) async { + if (x is Object) { + var x2 = await x; // Remains a `Future`. + x2.expectStaticType>(); + Expect.type>(x2); + Expect.identical(x, x2); + } + } + + await g1(Future.value(null)); + + // Promoted type variable; called with `X == Object?`. + Future g2(X x) async { + if (x is Object) { + var x2 = await x; // The future is awaited. + x2.expectStaticType>(); + Expect.isNull(x2); + } + } + + await g2(Future.value(null)); + + // Promoted type variable; called with `X == A`. + Future g3(X x) async { + if (x is A) { + var x2 = await x; // The future is awaited. + x2.expectStaticType>(); + Expect.type(x2); + Expect.notType(x2); + Expect.notIdentical(x, x2); + } + } + + await g3(C2()); + + // Promoted type variable; called with `X == C2`. + Future g4(X x) async { + if (x is A) { + var x2 = await x; // Remains a `C2` and a `Future`. + x2.expectStaticType>(); + Expect.type(x2); + Expect.identical(x, x2); + } + } + + await g4(C2()); + + // Promoted type variable; the value of `X` does not matter. + Future g5(X x) async { + if (x is Future) { + var x2 = await x; // The future is awaited. + x2.expectStaticType>(); + Expect.type(x2); + Expect.notType(x2); + Expect.notIdentical(x, x2); + } + } + + await g5(C2()); + await g5(C2()); + await g5>(C2()); + + // Promoted type variable; the value of `X` does not matter. + Future g6(X x) async { + if (X is FutureOr) { + var x2 = await x; // The future is awaited. + x2.expectStaticType>(); + Expect.type(x2); + Expect.notType(x2); + Expect.notIdentical(x, x2); + } + } + + await g6(C2()); + await g6(C2()); + await g6>(C2()); + await g6>(C2()); + + // Promoted type variable; values of type variables makes no difference. + Future g7>(X x) async { + if (x is Future && x is Y) { + // The promoted type of `x` is `X & Y`. + var x2 = await x; // The future is awaited. + x2.expectStaticType>(); + Expect.equals(1, x2); + } + } + + await g7(Future.value(1)); + + // S? bounded type: called with `X == Null`. + Future h1?>(X x) { + var x2 = await x; // Remains null. + x2.expectStaticType>(); + Expect.identical(null, x2); + } + + await h1(null); + + // S? bounded type: called with `X == Future`. + Future h2?>(X x) { + var x2 = await x; // The future is awaited. + x2.expectStaticType>(); + Expect.type(x2); + Expect.notType(x2); + Expect.notIdentical(x, x2); + } + + await h2>(C2()); + + // S? bounded type: called with `X == Null`. + Future h3?>(X x) { + var x2 = await x; // Remains null. + x2.expectStaticType>(); + Expect.identical(null, x2); + } + + await h3(null); + + // S? bounded type: called with `X == FutureOr`. + Future h4?>(X x) { + var x2 = await x; // The future is awaited. + x2.expectStaticType>(); + Expect.type(x2); + Expect.notType(x2); + Expect.notIdentical(x, x2); + } + + await h4>(C2()); +} diff --git a/tests/language/async/regression_49396_test.dart b/tests/language/async/regression_49396_test.dart deleted file mode 100644 index 625b2767a43..00000000000 --- a/tests/language/async/regression_49396_test.dart +++ /dev/null @@ -1,78 +0,0 @@ -// 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. - -import 'dart:async'; -import 'package:expect/expect.dart'; -import '../static_type_helper.dart'; - -// Regression test, exercising the behavior described in SDK issue 49396. - -class A {} - -abstract class B extends A implements Future { - Future get fut; - asStream() => fut.asStream(); - catchError(error, {test}) => fut.catchError(error, test: test); - then(onValue, {onError}) => fut.then(onValue, onError: onError); - timeout(timeLimit, {onTimeout}) => - fut.timeout(timeLimit, onTimeout: onTimeout); - whenComplete(action) => fut.whenComplete(action); -} - -class C extends B { - final Future fut = Future.value(CompletelyUnrelated()); -} - -class CompletelyUnrelated {} - -class C1 extends A {} - -class C2 extends B { - final Future fut = Future.value(C1()); -} - -void main() async { - final Object o = Future.value(); - var o2 = await o; // Remains a future. - o2.expectStaticType>(); - Expect.type>(o2); - Expect.identical(o, o2); - - final FutureOr x = Future.value(); - var x2 = await x; // Remains a future. - x2.expectStaticType>(); - Expect.type>(x2); - Expect.identical(x, x2); - - final FutureOr> y = Future.value(1); - var y2 = await y; // Remains a `Future`. - y2.expectStaticType>>(); - Expect.type>(y2); - Expect.identical(y, y2); - - A a = C(); - var a2 = await a; // Remains a `C` and a `Future`. - a2.expectStaticType>(); - Expect.type(a2); - Expect.identical(a, a2); - - Future f(X x) async { - var x2 = await x; // Remains an `A` and a `Future`. - x2.expectStaticType>(); - Expect.type>(x2); - Expect.identical(x, x2); - } - - await f(Future.value(null)); - - Future g(X x) async { - var x2 = await x; // The future is awaited. - x2.expectStaticType>(); - Expect.type(x2); - Expect.notType(x2); - Expect.notIdentical(x, x2); - } - - await g(C2()); -}