// 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 futureNum() async => null; FutureOr futureOrNum() async => null; Future futureInt() async => null; FutureOr futureOrInt() async => null; Future> futureListNum() async => null; FutureOr> futureOrListNum() async => null; Future> futureFutureNum() async => null; FutureOr> futureOrFutureOrNum() async => null; Future futureNull() async => null; FutureOr futureOrNull() async => null; void returnVoid() {} class C { Future futureT() async => null; FutureOr 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'); FutureOrType futureOrNum = getReturnType('futureOrNum', 'FutureOr'); DartType num_ = futureOrNum.typeArgument; DartType futureInt = getReturnType('futureInt', 'Future'); FutureOrType futureOrInt = getReturnType('futureOrInt', 'FutureOr'); DartType int_ = futureOrInt.typeArgument; DartType futureListNum = getReturnType('futureListNum', 'Future>'); FutureOrType futureOrListNum = getReturnType('futureOrListNum', 'FutureOr>'); DartType ListNum = futureOrListNum.typeArgument; DartType futureFutureNum = getReturnType('futureFutureNum', 'Future>'); FutureOrType futureOrFutureOrNum = getReturnType('futureOrFutureOrNum', 'FutureOr>'); DartType futureNull = getReturnType('futureNull', 'Future'); InterfaceType futureOrNull = getReturnType('futureOrNull', 'Future'); DartType Null_ = futureOrNull.typeArguments.single; ClassEntity C = env.getClass('C'); DartType futureT = getReturnType('futureT', 'Future', C); FutureOrType futureOrT = getReturnType('futureOrT', 'FutureOr', 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? Function()'); List all = [ Object_, num_, int_, Null_, ListNum, T, futureNum, futureOrNum, futureInt, futureNull, futureListNum, futureT, futureOrInt, futureOrNull, futureOrListNum, futureFutureNum, futureOrFutureOrNum, futureOrT, returnVoid, returnFutureNull, ]; Map> 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 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."); } } }); }