|  | // 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 position 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 'package:expect/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(); | 
|  | } |