blob: 4c069d9c4a777ac9c2fc2e7f92556f78d11c8643 [file] [log] [blame]
// 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.
// @dart = 2.9
// This test verifies that for an unnamed async closure, 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 {}
class B2 extends A {}
Future quick() async {}
Future<A> futureA() => new Future<A>.value(new A());
Future<B> futureB() => new Future<B>.value(new B());
void checkFutureObject(dynamic tearoff) {
Expect.isTrue(tearoff is Future<Object> Function());
Expect.isFalse(tearoff is Future<A> Function());
dynamic f = tearoff();
Expect.isTrue(f is Future<Object>);
Expect.isFalse(f is Future<A>);
}
void checkFutureDynamic(dynamic tearoff) {
Expect.isTrue(tearoff is Future<dynamic> Function());
Expect.isFalse(tearoff is Future<A> 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>);
}
main() {
var f_inferred_futureObject = () async {
await quick();
if (false) {
return 0;
} else {
return new A();
}
};
var f_inferred_A = () async {
await quick();
if (false) {
return new A();
} else {
return new B();
}
};
Future<dynamic> Function() f_futureDynamic = () async {
await quick();
if (false) {
return 0;
} else {
return new B();
}
};
Future<A> Function() f_A = () async {
await quick();
if (false) {
return new A();
} else {
return new B();
}
};
Future<A> Function() f_immediateReturn_B = () async {
if (false) {
return new A();
} else {
return new B();
}
};
Future<A> Function() f_immediateReturn_FutureB = () async {
if (false) {
return new A();
} else {
return futureB();
}
};
Future<A> Function() f_expressionSyntax_B =
() async => false ? new A() : new B();
Future<A> Function() f_expressionSyntax_FutureB =
() async => false ? futureA() : futureB();
// Not executed
void checkStaticTypes() {
// Check that f_inferred_futureObject's static return type is
// `Future<Object>`, by verifying that its return value can be assigned to
// `Future<int>` but not `int`.
Future<int> v1 = f_inferred_futureObject();
int v2 = f_inferred_futureObject();
// ^^^^^^^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe] A value of type 'Future<Object>' can't be assigned to a variable of type 'int'.
// Check that f_inferred_A's static return type is `Future<A>`, by verifying
// that its return value can be assigned to `Future<B2>` but not
// `Future<int>`.
Future<B2> v3 = f_inferred_A();
Future<int> v4 = 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<int>'.
}
checkFutureObject(f_inferred_futureObject);
checkFutureA(f_inferred_A);
checkFutureDynamic(f_futureDynamic);
checkFutureA(f_A);
checkFutureA(f_immediateReturn_B);
checkFutureA(f_immediateReturn_FutureB);
checkFutureA(f_expressionSyntax_B);
checkFutureA(f_expressionSyntax_FutureB);
}