| // Copyright (c) 2017, 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. | |
| // This test verifies that for an async method, the following three | |
| // types are all appropriately matched: | |
| // - The static return type | |
| // - The return type of reified runtime type of a tearoff of the function or | |
| // method | |
| // - The reified type of the future returned by the function or method | |
| // | |
| // Specific attention is paid to the following conditions: | |
| // - The static return type is determined by type inference | |
| // - The static return type is `dynamic` | |
| // - The function or method immediately returns a value or future with a | |
| // different type (possibly using `=>` syntax) | |
| import 'dart:async'; | |
| import 'package:expect/expect.dart'; | |
| class A {} | |
| class B extends A {} | |
| Future quick() async {} | |
| Future<B> futureB() => new Future<B>.value(new B()); | |
| abstract class I { | |
| dynamic f_inferred_dynamic(); | |
| Future<A> f_inferred_A(); | |
| } | |
| class C implements I { | |
| f_inferred_dynamic() async { | |
| await quick(); | |
| return new B(); | |
| } | |
| f_inferred_A() async { | |
| await quick(); | |
| return new B(); | |
| } | |
| dynamic f_dynamic() async { | |
| await quick(); | |
| return new B(); | |
| } | |
| Future<A> f_A() async { | |
| await quick(); | |
| return new B(); | |
| } | |
| Future<A> f_immediateReturn_B() async { | |
| return new B(); | |
| } | |
| Future<A> f_immediateReturn_FutureB() async { | |
| return futureB(); | |
| } | |
| Future<A> f_expressionSyntax_B() async => new B(); | |
| Future<A> f_expressionSyntax_FutureB() async => futureB(); | |
| } | |
| // Not executed | |
| void checkStaticTypes(C c) { | |
| // Check that f_inferred_dynamic's static return type is `dynamic`, by | |
| // verifying that no error occurs if we try to call `foo` on its return value. | |
| c.f_inferred_dynamic().foo(); | |
| // Check that f_inferred_A's static return type is `Future<A>`, by verifying | |
| // that its return value can be assigned to `Future<A>` but not | |
| // `Future<B>`. | |
| Future<A> v1 = c.f_inferred_A(); | |
| Future<B> v2 = c.f_inferred_A(); | |
| // ^^^^^^^^^^^^^^^^ | |
| // [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT | |
| // ^ | |
| // [cfe] A value of type 'Future<A>' can't be assigned to a variable of type 'Future<B>'. | |
| } | |
| void checkDynamic(dynamic tearoff) { | |
| Expect.isTrue(tearoff is dynamic Function()); | |
| Expect.isFalse(tearoff is Future<dynamic> Function()); | |
| dynamic f = tearoff(); | |
| Expect.isTrue(f is Future<dynamic>); | |
| Expect.isFalse(f is Future<A>); | |
| } | |
| void checkFutureA(dynamic tearoff) { | |
| Expect.isTrue(tearoff is Future<A> Function()); | |
| Expect.isFalse(tearoff is Future<B> Function()); | |
| dynamic f = tearoff(); | |
| Expect.isTrue(f is Future<A>); | |
| Expect.isFalse(f is Future<B>); | |
| } | |
| void test(C c) { | |
| checkDynamic(c.f_inferred_dynamic); | |
| checkFutureA(c.f_inferred_A); | |
| checkDynamic(c.f_dynamic); | |
| checkFutureA(c.f_A); | |
| checkFutureA(c.f_immediateReturn_B); | |
| checkFutureA(c.f_immediateReturn_FutureB); | |
| checkFutureA(c.f_expressionSyntax_B); | |
| checkFutureA(c.f_expressionSyntax_FutureB); | |
| } | |
| main() { | |
| test(new C()); | |
| } |