blob: f373be1f7e11393e420a15778fc4a330604b3a3c [file] [log] [blame]
// Copyright (c) 2018, 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.7
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/elements/entities.dart';
import 'package:compiler/src/elements/types.dart';
import 'package:expect/expect.dart';
import '../helpers/type_test_helper.dart';
main() {
asyncTest(() async {
var env = await TypeEnvironment.create("""
import 'dart:async';
Future<num> futureNum() async => null;
FutureOr<num> futureOrNum() async => null;
Future<int> futureInt() async => null;
FutureOr<int> futureOrInt() async => null;
Future<List<num>> futureListNum() async => null;
FutureOr<List<num>> futureOrListNum() async => null;
Future<Future<num>> futureFutureNum() async => null;
FutureOr<FutureOr<num>> futureOrFutureOrNum() async => null;
Future<Null> futureNull() async => null;
FutureOr<Null> futureOrNull() async => null;
void returnVoid() {}
class C<T> {
Future<T> futureT() async => null;
FutureOr<T> futureOrT() async => null;
}
main() {
futureNum();
futureOrNum();
futureInt();
futureOrInt();
futureListNum();
futureOrListNum();
futureFutureNum();
futureOrFutureOrNum();
futureNull();
futureOrNull();
new C().futureT();
new C().futureOrT();
}
""", options: [Flags.noSoundNullSafety]);
FunctionType getFunctionType(String name, String expectedType,
[ClassEntity cls]) {
FunctionType type = env.getMemberType(name, cls);
Expect.isNotNull(type,
"Member $name not found${cls != null ? ' in class $cls' : ''}.");
Expect.equals(
expectedType,
env.printType(type),
"Unexpected type for $name"
"${cls != null ? ' in class $cls' : ''}.");
return type;
}
DartType getReturnType(String name, String expectedType,
[ClassEntity cls]) {
FunctionType type = env.getMemberType(name, cls);
Expect.isNotNull(type,
"Member $name not found${cls != null ? ' in class $cls' : ''}.");
DartType returnType = type.returnType.withoutNullability;
Expect.equals(
expectedType,
env.printType(returnType),
"Unexpected return type for $name"
"${cls != null ? ' in class $cls' : ''}.");
return returnType;
}
DartType Object_ = env['Object'];
DartType futureNum = getReturnType('futureNum', 'Future<num>');
FutureOrType futureOrNum = getReturnType('futureOrNum', 'FutureOr<num>');
DartType num_ = futureOrNum.typeArgument;
DartType futureInt = getReturnType('futureInt', 'Future<int>');
FutureOrType futureOrInt = getReturnType('futureOrInt', 'FutureOr<int>');
DartType int_ = futureOrInt.typeArgument;
DartType futureListNum =
getReturnType('futureListNum', 'Future<List<num>>');
FutureOrType futureOrListNum =
getReturnType('futureOrListNum', 'FutureOr<List<num>>');
DartType ListNum = futureOrListNum.typeArgument;
DartType futureFutureNum =
getReturnType('futureFutureNum', 'Future<Future<num>>');
FutureOrType futureOrFutureOrNum =
getReturnType('futureOrFutureOrNum', 'FutureOr<FutureOr<num>>');
DartType futureNull = getReturnType('futureNull', 'Future<Null>');
InterfaceType futureOrNull = getReturnType('futureOrNull', 'Future<Null>');
DartType Null_ = futureOrNull.typeArguments.single;
ClassEntity C = env.getClass('C');
DartType futureT = getReturnType('futureT', 'Future<C.T>', C);
FutureOrType futureOrT = getReturnType('futureOrT', 'FutureOr<C.T>', C);
DartType T = futureOrT.typeArgument.withoutNullability;
Expect.isTrue(futureOrT.containsTypeVariables);
futureOrT.forEachTypeVariable((t) => Expect.equals(T, t));
DartType returnVoid = getFunctionType('returnVoid', 'void Function()');
DartType returnFutureNull =
getFunctionType('futureOrNull', 'Future<Null>? Function()');
List<DartType> all = [
Object_,
num_,
int_,
Null_,
ListNum,
T,
futureNum,
futureOrNum,
futureInt,
futureNull,
futureListNum,
futureT,
futureOrInt,
futureOrNull,
futureOrListNum,
futureFutureNum,
futureOrFutureOrNum,
futureOrT,
returnVoid,
returnFutureNull,
];
Map<DartType, List<DartType>> expectedSubtypesMap = {
num_: [futureOrNum, futureOrFutureOrNum],
int_: [num_, futureOrInt, futureOrNum, futureOrFutureOrNum],
ListNum: [futureOrListNum],
T: [futureOrT],
futureNum: [futureOrNum, futureOrFutureOrNum],
futureInt: [futureNum, futureOrNum, futureOrInt, futureOrFutureOrNum],
futureNull: [
futureOrNull,
futureNum,
futureOrNum,
futureInt,
futureOrInt,
futureListNum,
futureOrListNum,
futureFutureNum,
futureOrFutureOrNum,
futureT,
futureOrT,
],
futureListNum: [futureOrListNum],
futureT: [futureOrT],
futureFutureNum: [futureOrFutureOrNum],
futureOrNum: [futureOrFutureOrNum],
futureOrInt: [futureOrNum, futureOrFutureOrNum],
futureOrNull: [
futureNull,
futureNum,
futureOrNum,
futureInt,
futureOrInt,
futureListNum,
futureOrListNum,
futureFutureNum,
futureOrFutureOrNum,
futureT,
futureOrT,
],
returnFutureNull: [returnVoid],
};
for (DartType t in all) {
List<DartType> expectedSubtypes = expectedSubtypesMap[t] ?? [];
for (DartType s in all) {
bool expectedSubtype = t == s ||
expectedSubtypes.contains(s) ||
s == Object_ ||
t == Null_;
Expect.equals(
expectedSubtype,
env.isSubtype(t, s),
"$t${expectedSubtype ? '' : ' not'} "
"expected to be a subtype of $s.");
}
}
});
}