blob: 416e97e7a928657c24109b2d00ad26ab02a2a9f6 [file] [log] [blame]
// Copyright (c) 2024, 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.
// Verify that if an `await` expression appears in a syntactic postion that
// doesn't impose a context on it, it supplies a context of `FutureOr<_>` to its
// operand, rather than `_` (which was the behavior prior to fixing
// https://github.com/dart-lang/language/issues/3648).
// Contexts of `FutureOr<_>` and `_` are difficult to distinguish. This test
// distinguishes them by awaiting the expression `((null as Future<B>?) ??
// (Future.value(C())..expectStaticType<Exactly<Future<C>>>()))`, where `C` is a
// class that extends `B`.
//
// This works because, if it is analyzed in context `Future<_>`, then:
// - The RHS of `??` is analyzed in context `Future<_>`.
// - Therefore downwards inference doesn't impose any constraint on the type
// parameter of `Future.value(C())`.
// - Therefore `Future.value(C())` gets its type parameter from upwards
// inference.
// - So it receives a type parameter of `C`.
// - So the static type of `Future.value(C())` is `Future<C>`.
//
// Whereas if it is analyzed in context `_`, then:
// - The static type of the LHS of `??` is used as the context for the RHS.
// That is, the RHS is analyzed in context `Future<B>?`.
// - Therefore downwards inference constraints the type parameter of
// `Future.value(C())` to `B`.
// - So the static type of `Future.value(C())` is `Future<B>`.
import '../static_type_helper.dart';
class B {
var prop;
void method() {}
}
class C extends B {}
main() async {
// Initializer part of a C-style for loop
for (await ((null as Future<B>?) ??
(Future.value(C())..expectStaticType<Exactly<Future<C>>>()));
false;) {}
// Updater part of a C-style for loop
for (var i = 0;
i < 1;
i++,
await ((null as Future<B>?) ??
(Future.value(C())..expectStaticType<Exactly<Future<C>>>()))) {}
// Target of a property set
(await ((null as Future<B>?) ??
(Future.value(C())..expectStaticType<Exactly<Future<C>>>())))
.prop = 0;
// Target of a property get
(await ((null as Future<B>?) ??
(Future.value(C())..expectStaticType<Exactly<Future<C>>>())))
.prop;
// Assert statement message
try {
assert(
false,
await ((null as Future<B>?) ??
(Future.value(C())..expectStaticType<Exactly<Future<C>>>())));
} on AssertionError {}
// Expression statement
await ((null as Future<B>?) ??
(Future.value(C())..expectStaticType<Exactly<Future<C>>>()));
// Interpolation expression
"${await ((null as Future<B>?) ?? (Future.value(C())..expectStaticType<Exactly<Future<C>>>()))}";
// Target of a method invocation
(await ((null as Future<B>?) ??
(Future.value(C())..expectStaticType<Exactly<Future<C>>>())))
.method();
// Target of a throw expression
try {
throw await ((null as Future<B>?) ??
(Future.value(C())..expectStaticType<Exactly<Future<C>>>()));
} on C {}
}