| // 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()); |
| } |