| Index: packages/analyzer/test/generated/type_system_test.dart
|
| diff --git a/packages/analyzer/test/generated/type_system_test.dart b/packages/analyzer/test/generated/type_system_test.dart
|
| index d49c75c117cd53c63f98d6c8a515c8bd6888b154..af08bb4d678584f5b353a8097e5dd59f815e4bee 100644
|
| --- a/packages/analyzer/test/generated/type_system_test.dart
|
| +++ b/packages/analyzer/test/generated/type_system_test.dart
|
| @@ -4,26 +4,36 @@
|
|
|
| // Tests related to the [TypeSystem] class.
|
|
|
| -library engine.type_system_test;
|
| +library analyzer.test.generated.type_system_test;
|
|
|
| -import 'package:analyzer/src/generated/element.dart';
|
| +import 'package:analyzer/dart/element/element.dart';
|
| +import 'package:analyzer/dart/element/type.dart';
|
| +import 'package:analyzer/src/dart/element/element.dart';
|
| +import 'package:analyzer/src/dart/element/type.dart';
|
| +import 'package:analyzer/src/generated/engine.dart';
|
| import 'package:analyzer/src/generated/resolver.dart';
|
| import 'package:analyzer/src/generated/testing/element_factory.dart';
|
| import 'package:analyzer/src/generated/testing/test_type_provider.dart';
|
| +import 'package:test_reflective_loader/test_reflective_loader.dart';
|
| import 'package:unittest/unittest.dart';
|
|
|
| -import '../reflective_tests.dart';
|
| import '../utils.dart';
|
| +import 'analysis_context_factory.dart';
|
|
|
| main() {
|
| initializeTestEnvironment();
|
| - runReflectiveTests(TypeSystemTest);
|
| - runReflectiveTests(StrongSubtypingTest);
|
| - runReflectiveTests(StrongAssignabilityTest);
|
| + defineReflectiveTests(StrongAssignabilityTest);
|
| + defineReflectiveTests(StrongSubtypingTest);
|
| + defineReflectiveTests(StrongGenericFunctionInferenceTest);
|
| + defineReflectiveTests(LeastUpperBoundTest);
|
| + defineReflectiveTests(StrongLeastUpperBoundTest);
|
| + defineReflectiveTests(StrongGreatestLowerBoundTest);
|
| }
|
|
|
| -@reflectiveTest
|
| -class TypeSystemTest {
|
| +/**
|
| + * Base class for testing LUB and GLB in spec and strong mode.
|
| + */
|
| +abstract class BoundTestBase {
|
| TypeProvider typeProvider;
|
| TypeSystem typeSystem;
|
| FunctionType simpleFunctionType;
|
| @@ -33,15 +43,19 @@ class TypeSystemTest {
|
| DartType get dynamicType => typeProvider.dynamicType;
|
| InterfaceType get functionType => typeProvider.functionType;
|
| InterfaceType get intType => typeProvider.intType;
|
| + InterfaceType get iterableType => typeProvider.iterableType;
|
| InterfaceType get listType => typeProvider.listType;
|
| InterfaceType get numType => typeProvider.numType;
|
| InterfaceType get objectType => typeProvider.objectType;
|
| InterfaceType get stringType => typeProvider.stringType;
|
| + StrongTypeSystemImpl get strongTypeSystem =>
|
| + typeSystem as StrongTypeSystemImpl;
|
| +
|
| DartType get voidType => VoidTypeImpl.instance;
|
|
|
| void setUp() {
|
| - typeProvider = new TestTypeProvider();
|
| - typeSystem = new TypeSystemImpl();
|
| + InternalAnalysisContext context = AnalysisContextFactory.contextWithCore();
|
| + typeProvider = context.typeProvider;
|
| FunctionTypeAliasElementImpl typeAlias =
|
| ElementFactory.functionTypeAliasElement('A');
|
| typeAlias.parameters = [];
|
| @@ -49,26 +63,173 @@ class TypeSystemTest {
|
| simpleFunctionType = typeAlias.type;
|
| }
|
|
|
| - void test_getLeastUpperBound_bottom_function() {
|
| + void _checkGreatestLowerBound(
|
| + DartType type1, DartType type2, DartType expectedResult) {
|
| + DartType glb =
|
| + strongTypeSystem.getGreatestLowerBound(typeProvider, type1, type2);
|
| + expect(glb, expectedResult);
|
| + // Check that the result is a lower bound.
|
| + expect(typeSystem.isSubtypeOf(glb, type1), true);
|
| + expect(typeSystem.isSubtypeOf(glb, type2), true);
|
| + // Check for symmetry while we're at it. Unfortunately,
|
| + // for function types, the current version of equality
|
| + // does not respect re-ordering of named parameters, so
|
| + // for function types we just check if they are mutual subtypes.
|
| + // https://github.com/dart-lang/sdk/issues/26126
|
| + // TODO(leafp): Fix this.
|
| + glb = strongTypeSystem.getGreatestLowerBound(typeProvider, type2, type1);
|
| + if (glb is FunctionTypeImpl) {
|
| + expect(typeSystem.isSubtypeOf(glb, expectedResult), true);
|
| + expect(typeSystem.isSubtypeOf(expectedResult, glb), true);
|
| + } else {
|
| + expect(glb, expectedResult);
|
| + }
|
| + }
|
| +
|
| + void _checkLeastUpperBound(
|
| + DartType type1, DartType type2, DartType expectedResult) {
|
| + DartType lub = typeSystem.getLeastUpperBound(typeProvider, type1, type2);
|
| + expect(lub, expectedResult);
|
| + // Check that the result is an upper bound.
|
| + expect(typeSystem.isSubtypeOf(type1, lub), true);
|
| + expect(typeSystem.isSubtypeOf(type2, lub), true);
|
| +
|
| + // Check for symmetry while we're at it. Unfortunately,
|
| + // for function types, the current version of equality
|
| + // does not respect re-ordering of named parameters, so
|
| + // for function types we just check if they are mutual subtypes.
|
| + // https://github.com/dart-lang/sdk/issues/26126
|
| + // TODO(leafp): Fix this.
|
| + lub = typeSystem.getLeastUpperBound(typeProvider, type2, type1);
|
| + if (lub is FunctionTypeImpl) {
|
| + expect(typeSystem.isSubtypeOf(lub, expectedResult), true);
|
| + expect(typeSystem.isSubtypeOf(expectedResult, lub), true);
|
| + } else {
|
| + expect(lub, expectedResult);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Creates a function type with the given parameter and return types.
|
| + *
|
| + * The return type defaults to `void` if omitted.
|
| + */
|
| + FunctionType _functionType(List<DartType> required,
|
| + {List<DartType> optional,
|
| + Map<String, DartType> named,
|
| + DartType returns}) {
|
| + if (returns == null) {
|
| + returns = voidType;
|
| + }
|
| +
|
| + return ElementFactory
|
| + .functionElement8(required, returns, optional: optional, named: named)
|
| + .type;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Tests LUB in spec mode.
|
| + *
|
| + * Tests defined in this class are ones whose behavior is spec mode-specific.
|
| + * In particular, function parameters are compared using LUB in spec mode, but
|
| + * GLB in strong mode.
|
| + */
|
| +@reflectiveTest
|
| +class LeastUpperBoundTest extends LeastUpperBoundTestBase {
|
| + void setUp() {
|
| + typeSystem = new TypeSystemImpl();
|
| + super.setUp();
|
| + }
|
| +
|
| + void test_functionsLubNamedParams() {
|
| + FunctionType type1 =
|
| + _functionType([], named: {'a': stringType, 'b': intType});
|
| + FunctionType type2 = _functionType([], named: {'a': intType, 'b': numType});
|
| + FunctionType expected =
|
| + _functionType([], named: {'a': objectType, 'b': numType});
|
| + _checkLeastUpperBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsLubPositionalParams() {
|
| + FunctionType type1 = _functionType([], optional: [stringType, intType]);
|
| + FunctionType type2 = _functionType([], optional: [intType, numType]);
|
| + FunctionType expected = _functionType([], optional: [objectType, numType]);
|
| + _checkLeastUpperBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsLubRequiredParams() {
|
| + FunctionType type1 = _functionType([stringType, intType, intType]);
|
| + FunctionType type2 = _functionType([intType, doubleType, numType]);
|
| + FunctionType expected = _functionType([objectType, numType, numType]);
|
| + _checkLeastUpperBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_nestedNestedFunctionsLubInnermostParamTypes() {
|
| + FunctionType type1 = _functionType([
|
| + _functionType([
|
| + _functionType([stringType, intType, intType])
|
| + ])
|
| + ]);
|
| + FunctionType type2 = _functionType([
|
| + _functionType([
|
| + _functionType([intType, doubleType, numType])
|
| + ])
|
| + ]);
|
| + FunctionType expected = _functionType([
|
| + _functionType([
|
| + _functionType([objectType, numType, numType])
|
| + ])
|
| + ]);
|
| + _checkLeastUpperBound(type1, type2, expected);
|
| + }
|
| +
|
| + /// Check least upper bound of the same class with different type parameters.
|
| + void test_typeParameters_different() {
|
| + // class List<int>
|
| + // class List<double>
|
| + InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
|
| + InterfaceType listOfDoubleType =
|
| + listType.instantiate(<DartType>[doubleType]);
|
| + _checkLeastUpperBound(listOfIntType, listOfDoubleType, objectType);
|
| + }
|
| +
|
| + /// Check least upper bound of two related classes with different
|
| + /// type parameters.
|
| + void test_typeParametersAndClass_different() {
|
| + // class List<int>
|
| + // class Iterable<double>
|
| + InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
|
| + InterfaceType iterableOfDoubleType =
|
| + iterableType.instantiate(<DartType>[doubleType]);
|
| + _checkLeastUpperBound(listOfIntType, iterableOfDoubleType, objectType);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Base class for testing LUB in spec and strong mode.
|
| + * Defines helper functions and tests. Tests here are ones whose behavior is
|
| + * the same in strong and spec mode.
|
| + */
|
| +abstract class LeastUpperBoundTestBase extends BoundTestBase {
|
| + void test_bottom_function() {
|
| _checkLeastUpperBound(bottomType, simpleFunctionType, simpleFunctionType);
|
| }
|
|
|
| - void test_getLeastUpperBound_bottom_interface() {
|
| + void test_bottom_interface() {
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| _checkLeastUpperBound(bottomType, interfaceType, interfaceType);
|
| }
|
|
|
| - void test_getLeastUpperBound_bottom_typeParam() {
|
| + void test_bottom_typeParam() {
|
| DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| _checkLeastUpperBound(bottomType, typeParam, typeParam);
|
| }
|
|
|
| - void test_getLeastUpperBound_directInterfaceCase() {
|
| - //
|
| + void test_directInterfaceCase() {
|
| // class A
|
| // class B implements A
|
| // class C implements B
|
| - //
|
| ClassElementImpl classA = ElementFactory.classElement2("A");
|
| ClassElementImpl classB = ElementFactory.classElement2("B");
|
| ClassElementImpl classC = ElementFactory.classElement2("C");
|
| @@ -80,12 +241,10 @@ class TypeSystemTest {
|
| _checkLeastUpperBound(typeB, typeC, typeB);
|
| }
|
|
|
| - void test_getLeastUpperBound_directSubclassCase() {
|
| - //
|
| + void test_directSubclassCase() {
|
| // class A
|
| // class B extends A
|
| // class C extends B
|
| - //
|
| ClassElementImpl classA = ElementFactory.classElement2("A");
|
| ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
|
| ClassElementImpl classC = ElementFactory.classElement("C", classB.type);
|
| @@ -94,40 +253,76 @@ class TypeSystemTest {
|
| _checkLeastUpperBound(typeB, typeC, typeB);
|
| }
|
|
|
| - void test_getLeastUpperBound_dynamic_bottom() {
|
| + void test_dynamic_bottom() {
|
| _checkLeastUpperBound(dynamicType, bottomType, dynamicType);
|
| }
|
|
|
| - void test_getLeastUpperBound_dynamic_function() {
|
| + void test_dynamic_function() {
|
| _checkLeastUpperBound(dynamicType, simpleFunctionType, dynamicType);
|
| }
|
|
|
| - void test_getLeastUpperBound_dynamic_interface() {
|
| + void test_dynamic_interface() {
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| _checkLeastUpperBound(dynamicType, interfaceType, dynamicType);
|
| }
|
|
|
| - void test_getLeastUpperBound_dynamic_typeParam() {
|
| + void test_dynamic_typeParam() {
|
| DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| _checkLeastUpperBound(dynamicType, typeParam, dynamicType);
|
| }
|
|
|
| - void test_getLeastUpperBound_dynamic_void() {
|
| + void test_dynamic_void() {
|
| _checkLeastUpperBound(dynamicType, voidType, dynamicType);
|
| }
|
|
|
| - void test_getLeastUpperBound_interface_function() {
|
| + void test_functionsDifferentRequiredArity() {
|
| + FunctionType type1 = _functionType([intType, intType]);
|
| + FunctionType type2 = _functionType([intType, intType, intType]);
|
| + _checkLeastUpperBound(type1, type2, functionType);
|
| + }
|
| +
|
| + void test_functionsIgnoreExtraNamedParams() {
|
| + FunctionType type1 = _functionType([], named: {'a': intType, 'b': intType});
|
| + FunctionType type2 = _functionType([], named: {'a': intType, 'c': intType});
|
| + FunctionType expected = _functionType([], named: {'a': intType});
|
| + _checkLeastUpperBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsIgnoreExtraPositionalParams() {
|
| + FunctionType type1 =
|
| + _functionType([], optional: [intType, intType, stringType]);
|
| + FunctionType type2 = _functionType([], optional: [intType]);
|
| + FunctionType expected = _functionType([], optional: [intType]);
|
| + _checkLeastUpperBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsLubReturnType() {
|
| + FunctionType type1 = _functionType([], returns: intType);
|
| + FunctionType type2 = _functionType([], returns: doubleType);
|
| + FunctionType expected = _functionType([], returns: numType);
|
| + _checkLeastUpperBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsSameType() {
|
| + FunctionType type1 = _functionType([stringType, intType, numType],
|
| + optional: [doubleType], named: {'n': numType}, returns: intType);
|
| + FunctionType type2 = _functionType([stringType, intType, numType],
|
| + optional: [doubleType], named: {'n': numType}, returns: intType);
|
| + FunctionType expected = _functionType([stringType, intType, numType],
|
| + optional: [doubleType], named: {'n': numType}, returns: intType);
|
| + _checkLeastUpperBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_interface_function() {
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| _checkLeastUpperBound(interfaceType, simpleFunctionType, objectType);
|
| }
|
|
|
| - void test_getLeastUpperBound_mixinCase() {
|
| - //
|
| + void test_mixinCase() {
|
| // class A
|
| // class B extends A
|
| // class C extends A
|
| // class D extends B with M, N, O, P
|
| - //
|
| ClassElement classA = ElementFactory.classElement2("A");
|
| ClassElement classB = ElementFactory.classElement("B", classA.type);
|
| ClassElement classC = ElementFactory.classElement("C", classA.type);
|
| @@ -144,7 +339,20 @@ class TypeSystemTest {
|
| _checkLeastUpperBound(typeD, typeC, typeA);
|
| }
|
|
|
| - void test_getLeastUpperBound_object() {
|
| + void test_nestedFunctionsLubInnerParamTypes() {
|
| + FunctionType type1 = _functionType([
|
| + _functionType([stringType, intType, intType])
|
| + ]);
|
| + FunctionType type2 = _functionType([
|
| + _functionType([intType, doubleType, numType])
|
| + ]);
|
| + FunctionType expected = _functionType([
|
| + _functionType([objectType, numType, numType])
|
| + ]);
|
| + _checkLeastUpperBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_object() {
|
| ClassElementImpl classA = ElementFactory.classElement2("A");
|
| ClassElementImpl classB = ElementFactory.classElement2("B");
|
| InterfaceType typeA = classA.type;
|
| @@ -158,29 +366,25 @@ class TypeSystemTest {
|
| _checkLeastUpperBound(typeA, typeB, typeObject);
|
| }
|
|
|
| - void test_getLeastUpperBound_self() {
|
| + void test_self() {
|
| DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - expect(
|
| - typeSystem.getLeastUpperBound(typeProvider, dynamicType, dynamicType),
|
| - dynamicType);
|
| - expect(typeSystem.getLeastUpperBound(typeProvider, voidType, voidType),
|
| - voidType);
|
| - expect(typeSystem.getLeastUpperBound(typeProvider, bottomType, bottomType),
|
| - bottomType);
|
| - expect(typeSystem.getLeastUpperBound(typeProvider, typeParam, typeParam),
|
| - typeParam);
|
| - expect(
|
| - typeSystem.getLeastUpperBound(
|
| - typeProvider, interfaceType, interfaceType),
|
| - interfaceType);
|
| - expect(
|
| - typeSystem.getLeastUpperBound(
|
| - typeProvider, simpleFunctionType, simpleFunctionType),
|
| - simpleFunctionType);
|
| +
|
| + List<DartType> types = [
|
| + dynamicType,
|
| + voidType,
|
| + bottomType,
|
| + typeParam,
|
| + interfaceType,
|
| + simpleFunctionType
|
| + ];
|
| +
|
| + for (DartType type in types) {
|
| + _checkLeastUpperBound(type, type, type);
|
| + }
|
| }
|
|
|
| - void test_getLeastUpperBound_sharedSuperclass1() {
|
| + void test_sharedSuperclass1() {
|
| ClassElementImpl classA = ElementFactory.classElement2("A");
|
| ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
|
| ClassElementImpl classC = ElementFactory.classElement("C", classA.type);
|
| @@ -190,7 +394,7 @@ class TypeSystemTest {
|
| _checkLeastUpperBound(typeB, typeC, typeA);
|
| }
|
|
|
| - void test_getLeastUpperBound_sharedSuperclass2() {
|
| + void test_sharedSuperclass2() {
|
| ClassElementImpl classA = ElementFactory.classElement2("A");
|
| ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
|
| ClassElementImpl classC = ElementFactory.classElement("C", classA.type);
|
| @@ -201,7 +405,7 @@ class TypeSystemTest {
|
| _checkLeastUpperBound(typeB, typeD, typeA);
|
| }
|
|
|
| - void test_getLeastUpperBound_sharedSuperclass3() {
|
| + void test_sharedSuperclass3() {
|
| ClassElementImpl classA = ElementFactory.classElement2("A");
|
| ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
|
| ClassElementImpl classC = ElementFactory.classElement("C", classB.type);
|
| @@ -212,7 +416,7 @@ class TypeSystemTest {
|
| _checkLeastUpperBound(typeC, typeD, typeB);
|
| }
|
|
|
| - void test_getLeastUpperBound_sharedSuperclass4() {
|
| + void test_sharedSuperclass4() {
|
| ClassElement classA = ElementFactory.classElement2("A");
|
| ClassElement classA2 = ElementFactory.classElement2("A2");
|
| ClassElement classA3 = ElementFactory.classElement2("A3");
|
| @@ -228,7 +432,7 @@ class TypeSystemTest {
|
| _checkLeastUpperBound(typeB, typeC, typeA);
|
| }
|
|
|
| - void test_getLeastUpperBound_sharedSuperinterface1() {
|
| + void test_sharedSuperinterface1() {
|
| ClassElementImpl classA = ElementFactory.classElement2("A");
|
| ClassElementImpl classB = ElementFactory.classElement2("B");
|
| ClassElementImpl classC = ElementFactory.classElement2("C");
|
| @@ -240,7 +444,7 @@ class TypeSystemTest {
|
| _checkLeastUpperBound(typeB, typeC, typeA);
|
| }
|
|
|
| - void test_getLeastUpperBound_sharedSuperinterface2() {
|
| + void test_sharedSuperinterface2() {
|
| ClassElementImpl classA = ElementFactory.classElement2("A");
|
| ClassElementImpl classB = ElementFactory.classElement2("B");
|
| ClassElementImpl classC = ElementFactory.classElement2("C");
|
| @@ -255,7 +459,7 @@ class TypeSystemTest {
|
| _checkLeastUpperBound(typeB, typeD, typeA);
|
| }
|
|
|
| - void test_getLeastUpperBound_sharedSuperinterface3() {
|
| + void test_sharedSuperinterface3() {
|
| ClassElementImpl classA = ElementFactory.classElement2("A");
|
| ClassElementImpl classB = ElementFactory.classElement2("B");
|
| ClassElementImpl classC = ElementFactory.classElement2("C");
|
| @@ -270,7 +474,7 @@ class TypeSystemTest {
|
| _checkLeastUpperBound(typeC, typeD, typeB);
|
| }
|
|
|
| - void test_getLeastUpperBound_sharedSuperinterface4() {
|
| + void test_sharedSuperinterface4() {
|
| ClassElement classA = ElementFactory.classElement2("A");
|
| ClassElement classA2 = ElementFactory.classElement2("A2");
|
| ClassElement classA3 = ElementFactory.classElement2("A3");
|
| @@ -286,11 +490,11 @@ class TypeSystemTest {
|
| _checkLeastUpperBound(typeB, typeC, typeA);
|
| }
|
|
|
| - void test_getLeastUpperBound_twoComparables() {
|
| + void test_twoComparables() {
|
| _checkLeastUpperBound(stringType, numType, objectType);
|
| }
|
|
|
| - void test_getLeastUpperBound_typeParam_function_bounded() {
|
| + void test_typeParam_function_bounded() {
|
| DartType typeA = ElementFactory.classElement('A', functionType).type;
|
| TypeParameterElementImpl typeParamElement =
|
| ElementFactory.typeParameterElement('T');
|
| @@ -299,12 +503,12 @@ class TypeSystemTest {
|
| _checkLeastUpperBound(typeParam, simpleFunctionType, functionType);
|
| }
|
|
|
| - void test_getLeastUpperBound_typeParam_function_noBound() {
|
| + void test_typeParam_function_noBound() {
|
| DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| _checkLeastUpperBound(typeParam, simpleFunctionType, objectType);
|
| }
|
|
|
| - void test_getLeastUpperBound_typeParam_interface_bounded() {
|
| + void test_typeParam_interface_bounded() {
|
| DartType typeA = ElementFactory.classElement2('A', []).type;
|
| DartType typeB = ElementFactory.classElement('B', typeA).type;
|
| DartType typeC = ElementFactory.classElement('C', typeA).type;
|
| @@ -315,73 +519,37 @@ class TypeSystemTest {
|
| _checkLeastUpperBound(typeParam, typeC, typeA);
|
| }
|
|
|
| - void test_getLeastUpperBound_typeParam_interface_noBound() {
|
| + void test_typeParam_interface_noBound() {
|
| DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| _checkLeastUpperBound(typeParam, interfaceType, objectType);
|
| }
|
|
|
| - void test_getLeastUpperBound_typeParameters_different() {
|
| - //
|
| - // class List<int>
|
| - // class List<double>
|
| - //
|
| - InterfaceType listOfIntType = listType.substitute4(<DartType>[intType]);
|
| - InterfaceType listOfDoubleType =
|
| - listType.substitute4(<DartType>[doubleType]);
|
| - _checkLeastUpperBound(listOfIntType, listOfDoubleType, objectType);
|
| - }
|
| -
|
| - void test_getLeastUpperBound_typeParameters_same() {
|
| - //
|
| + void test_typeParameters_same() {
|
| // List<int>
|
| // List<int>
|
| - //
|
| - InterfaceType listOfIntType = listType.substitute4(<DartType>[intType]);
|
| - expect(
|
| - typeSystem.getLeastUpperBound(
|
| - typeProvider, listOfIntType, listOfIntType),
|
| - listOfIntType);
|
| - }
|
| -
|
| - void test_getLeastUpperBound_void_bottom() {
|
| - _checkLeastUpperBound(voidType, bottomType, voidType);
|
| - }
|
| -
|
| - void test_getLeastUpperBound_void_function() {
|
| - _checkLeastUpperBound(voidType, simpleFunctionType, voidType);
|
| - }
|
| -
|
| - void test_getLeastUpperBound_void_interface() {
|
| - DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - _checkLeastUpperBound(voidType, interfaceType, voidType);
|
| - }
|
| -
|
| - void test_getLeastUpperBound_void_typeParam() {
|
| - DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| - _checkLeastUpperBound(voidType, typeParam, voidType);
|
| - }
|
| -
|
| - void _checkLeastUpperBound(
|
| - DartType type1, DartType type2, DartType expectedResult) {
|
| - expect(typeSystem.getLeastUpperBound(typeProvider, type1, type2),
|
| - expectedResult);
|
| + InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
|
| + _checkLeastUpperBound(listOfIntType, listOfIntType, listOfIntType);
|
| }
|
| -}
|
|
|
| -class TypeBuilder {
|
| - static FunctionType functionType(
|
| - List<DartType> parameters, DartType returnType,
|
| - {List<DartType> optional, Map<String, DartType> named}) {
|
| - return ElementFactory
|
| - .functionElement8(parameters, returnType,
|
| - optional: optional, named: named)
|
| - .type;
|
| + void test_void() {
|
| + List<DartType> types = [
|
| + bottomType,
|
| + simpleFunctionType,
|
| + ElementFactory.classElement2('A', []).type,
|
| + ElementFactory.typeParameterElement('T').type
|
| + ];
|
| + for (DartType type in types) {
|
| + _checkLeastUpperBound(
|
| + _functionType([], returns: voidType),
|
| + _functionType([], returns: type),
|
| + _functionType([], returns: voidType));
|
| + }
|
| }
|
| }
|
|
|
| @reflectiveTest
|
| -class StrongSubtypingTest {
|
| +class StrongAssignabilityTest {
|
| TypeProvider typeProvider;
|
| TypeSystem typeSystem;
|
|
|
| @@ -401,66 +569,36 @@ class StrongSubtypingTest {
|
| typeSystem = new StrongTypeSystemImpl();
|
| }
|
|
|
| - void test_isSubtypeOf_dynamic_isTop() {
|
| + void test_isAssignableTo_bottom_isBottom() {
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - List<DartType> equivalents = <DartType>[dynamicType, objectType];
|
| - List<DartType> subtypes = <DartType>[
|
| + List<DartType> interassignable = <DartType>[
|
| + dynamicType,
|
| + objectType,
|
| intType,
|
| doubleType,
|
| numType,
|
| stringType,
|
| - functionType,
|
| interfaceType,
|
| bottomType
|
| ];
|
| - _checkGroups(dynamicType, equivalents: equivalents, subtypes: subtypes);
|
| - }
|
|
|
| - void test_isSubtypeOf_bottom_isBottom() {
|
| - DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - List<DartType> equivalents = <DartType>[bottomType];
|
| - List<DartType> supertypes = <DartType>[
|
| - dynamicType,
|
| - objectType,
|
| - intType,
|
| - doubleType,
|
| - numType,
|
| - stringType,
|
| - functionType,
|
| - interfaceType
|
| - ];
|
| - _checkGroups(bottomType, equivalents: equivalents, supertypes: supertypes);
|
| + _checkGroups(bottomType, interassignable: interassignable);
|
| }
|
|
|
| - void test_isSubtypeOf_int() {
|
| - List<DartType> equivalents = <DartType>[intType];
|
| - List<DartType> supertypes = <DartType>[numType];
|
| - List<DartType> unrelated = <DartType>[doubleType];
|
| - _checkGroups(intType,
|
| - equivalents: equivalents, supertypes: supertypes, unrelated: unrelated);
|
| - }
|
| + void test_isAssignableTo_call_method() {
|
| + ClassElementImpl classBottom = ElementFactory.classElement2("B");
|
| + MethodElement methodBottom =
|
| + ElementFactory.methodElement("call", objectType, <DartType>[intType]);
|
| + classBottom.methods = <MethodElement>[methodBottom];
|
|
|
| - void test_isSubtypeOf_double() {
|
| - List<DartType> equivalents = <DartType>[doubleType];
|
| - List<DartType> supertypes = <DartType>[numType];
|
| - List<DartType> unrelated = <DartType>[intType];
|
| - _checkGroups(doubleType,
|
| - equivalents: equivalents, supertypes: supertypes, unrelated: unrelated);
|
| - }
|
| + DartType top =
|
| + TypeBuilder.function(required: <DartType>[intType], result: objectType);
|
| + InterfaceType bottom = classBottom.type;
|
|
|
| - void test_isSubtypeOf_num() {
|
| - List<DartType> equivalents = <DartType>[numType];
|
| - List<DartType> supertypes = <DartType>[];
|
| - List<DartType> unrelated = <DartType>[stringType];
|
| - List<DartType> subtypes = <DartType>[intType, doubleType];
|
| - _checkGroups(numType,
|
| - equivalents: equivalents,
|
| - supertypes: supertypes,
|
| - unrelated: unrelated,
|
| - subtypes: subtypes);
|
| + _checkIsStrictAssignableTo(bottom, top);
|
| }
|
|
|
| - void test_isSubtypeOf_classes() {
|
| + void test_isAssignableTo_classes() {
|
| ClassElement classTop = ElementFactory.classElement2("A");
|
| ClassElement classLeft = ElementFactory.classElement("B", classTop.type);
|
| ClassElement classRight = ElementFactory.classElement("C", classTop.type);
|
| @@ -474,142 +612,199 @@ class StrongSubtypingTest {
|
| _checkLattice(top, left, right, bottom);
|
| }
|
|
|
| - void test_isSubtypeOf_simple_function() {
|
| - FunctionType top =
|
| - TypeBuilder.functionType(<DartType>[intType], objectType);
|
| - FunctionType left = TypeBuilder.functionType(<DartType>[intType], intType);
|
| - FunctionType right =
|
| - TypeBuilder.functionType(<DartType>[objectType], objectType);
|
| - FunctionType bottom =
|
| - TypeBuilder.functionType(<DartType>[objectType], intType);
|
| + void test_isAssignableTo_double() {
|
| + DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| + List<DartType> interassignable = <DartType>[
|
| + dynamicType,
|
| + objectType,
|
| + doubleType,
|
| + numType,
|
| + bottomType
|
| + ];
|
| + List<DartType> unrelated = <DartType>[
|
| + intType,
|
| + stringType,
|
| + interfaceType,
|
| + ];
|
|
|
| - _checkLattice(top, left, right, bottom);
|
| + _checkGroups(doubleType,
|
| + interassignable: interassignable, unrelated: unrelated);
|
| }
|
|
|
| - void test_isSubtypeOf_call_method() {
|
| - ClassElementImpl classBottom = ElementFactory.classElement2("Bottom");
|
| - MethodElement methodBottom =
|
| - ElementFactory.methodElement("call", objectType, <DartType>[intType]);
|
| - classBottom.methods = <MethodElement>[methodBottom];
|
| + void test_isAssignableTo_dynamic_isTop() {
|
| + DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| + List<DartType> interassignable = <DartType>[
|
| + dynamicType,
|
| + objectType,
|
| + intType,
|
| + doubleType,
|
| + numType,
|
| + stringType,
|
| + interfaceType,
|
| + bottomType
|
| + ];
|
| + _checkGroups(dynamicType, interassignable: interassignable);
|
| + }
|
|
|
| - DartType top = TypeBuilder.functionType(<DartType>[intType], objectType);
|
| - InterfaceType bottom = classBottom.type;
|
| + void test_isAssignableTo_fuzzy_arrows() {
|
| + FunctionType top = TypeBuilder
|
| + .function(required: <DartType>[dynamicType], result: objectType);
|
| + FunctionType left = TypeBuilder
|
| + .function(required: <DartType>[objectType], result: objectType);
|
| + FunctionType right = TypeBuilder
|
| + .function(required: <DartType>[dynamicType], result: bottomType);
|
| + FunctionType bottom = TypeBuilder
|
| + .function(required: <DartType>[objectType], result: bottomType);
|
|
|
| - _checkIsStrictSubtypeOf(bottom, top);
|
| + _checkCrossLattice(top, left, right, bottom);
|
| }
|
|
|
| - void test_isSubtypeOf_fuzzy_arrows() {
|
| - FunctionType top =
|
| - TypeBuilder.functionType(<DartType>[dynamicType], objectType);
|
| - FunctionType left =
|
| - TypeBuilder.functionType(<DartType>[objectType], objectType);
|
| - FunctionType right =
|
| - TypeBuilder.functionType(<DartType>[dynamicType], bottomType);
|
| - FunctionType bottom =
|
| - TypeBuilder.functionType(<DartType>[objectType], bottomType);
|
| + void test_isAssignableTo_generics() {
|
| + ClassElementImpl LClass = ElementFactory.classElement2('L', ["T"]);
|
| + InterfaceType LType = LClass.type;
|
| + ClassElementImpl MClass = ElementFactory.classElement2('M', ["T"]);
|
| + DartType typeParam = MClass.typeParameters[0].type;
|
| + InterfaceType superType = LType.instantiate(<DartType>[typeParam]);
|
| + MClass.interfaces = <InterfaceType>[superType];
|
| + InterfaceType MType = MClass.type;
|
|
|
| - _checkLattice(top, left, right, bottom);
|
| + InterfaceType top = LType.instantiate(<DartType>[dynamicType]);
|
| + InterfaceType left = MType.instantiate(<DartType>[dynamicType]);
|
| + InterfaceType right = LType.instantiate(<DartType>[intType]);
|
| + InterfaceType bottom = MType.instantiate(<DartType>[intType]);
|
| +
|
| + _checkCrossLattice(top, left, right, bottom);
|
| }
|
|
|
| - void test_isSubtypeOf_void_functions() {
|
| - FunctionType top = TypeBuilder.functionType(<DartType>[intType], voidType);
|
| - FunctionType bottom =
|
| - TypeBuilder.functionType(<DartType>[objectType], intType);
|
| + void test_isAssignableTo_int() {
|
| + DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| + List<DartType> interassignable = <DartType>[
|
| + dynamicType,
|
| + objectType,
|
| + intType,
|
| + numType,
|
| + bottomType
|
| + ];
|
| + List<DartType> unrelated = <DartType>[
|
| + doubleType,
|
| + stringType,
|
| + interfaceType,
|
| + ];
|
|
|
| - _checkIsStrictSubtypeOf(bottom, top);
|
| + _checkGroups(intType,
|
| + interassignable: interassignable, unrelated: unrelated);
|
| }
|
|
|
| - void test_isSubtypeOf_named_optional() {
|
| - DartType r = TypeBuilder.functionType(<DartType>[intType], intType);
|
| - DartType o = TypeBuilder.functionType(<DartType>[], intType,
|
| - optional: <DartType>[intType]);
|
| - DartType n = TypeBuilder.functionType(<DartType>[], intType,
|
| - named: <String, DartType>{'x': intType});
|
| - DartType rr =
|
| - TypeBuilder.functionType(<DartType>[intType, intType], intType);
|
| - DartType ro = TypeBuilder.functionType(<DartType>[intType], intType,
|
| - optional: <DartType>[intType]);
|
| - DartType rn = TypeBuilder.functionType(<DartType>[intType], intType,
|
| - named: <String, DartType>{'x': intType});
|
| - DartType oo = TypeBuilder.functionType(<DartType>[], intType,
|
| - optional: <DartType>[intType, intType]);
|
| - DartType nn = TypeBuilder.functionType(<DartType>[], intType,
|
| - named: <String, DartType>{'x': intType, 'y': intType});
|
| - DartType nnn = TypeBuilder.functionType(<DartType>[], intType,
|
| - named: <String, DartType>{'x': intType, 'y': intType, 'z': intType});
|
| + void test_isAssignableTo_named_optional() {
|
| + DartType r =
|
| + TypeBuilder.function(required: <DartType>[intType], result: intType);
|
| + DartType o = TypeBuilder.function(
|
| + required: <DartType>[], optional: <DartType>[intType], result: intType);
|
| + DartType n = TypeBuilder.function(
|
| + required: <DartType>[],
|
| + named: <String, DartType>{'x': intType},
|
| + result: intType);
|
| + DartType rr = TypeBuilder
|
| + .function(required: <DartType>[intType, intType], result: intType);
|
| + DartType ro = TypeBuilder.function(
|
| + required: <DartType>[intType],
|
| + optional: <DartType>[intType],
|
| + result: intType);
|
| + DartType rn = TypeBuilder.function(
|
| + required: <DartType>[intType],
|
| + named: <String, DartType>{'x': intType},
|
| + result: intType);
|
| + DartType oo = TypeBuilder.function(
|
| + required: <DartType>[],
|
| + optional: <DartType>[intType, intType],
|
| + result: intType);
|
| + DartType nn = TypeBuilder.function(
|
| + required: <DartType>[],
|
| + named: <String, DartType>{'x': intType, 'y': intType},
|
| + result: intType);
|
| + DartType nnn = TypeBuilder.function(
|
| + required: <DartType>[],
|
| + named: <String, DartType>{'x': intType, 'y': intType, 'z': intType},
|
| + result: intType);
|
|
|
| _checkGroups(r,
|
| - equivalents: [r],
|
| - subtypes: [o, ro, rn, oo],
|
| - unrelated: [n, rr, nn, nnn]);
|
| + interassignable: [r, o, ro, rn, oo], unrelated: [n, rr, nn, nnn]);
|
| _checkGroups(o,
|
| - equivalents: [o], subtypes: [oo], unrelated: [n, rr, ro, rn, nn, nnn]);
|
| + interassignable: [o, oo], unrelated: [n, rr, ro, rn, nn, nnn]);
|
| _checkGroups(n,
|
| - equivalents: [n],
|
| - subtypes: [nn, nnn],
|
| - unrelated: [r, o, rr, ro, rn, oo]);
|
| + interassignable: [n, nn, nnn], unrelated: [r, o, rr, ro, rn, oo]);
|
| _checkGroups(rr,
|
| - equivalents: [rr],
|
| - subtypes: [ro, oo],
|
| - unrelated: [r, o, n, rn, nn, nnn]);
|
| - _checkGroups(ro,
|
| - equivalents: [ro], subtypes: [oo], unrelated: [o, n, rn, nn, nnn]);
|
| + interassignable: [rr, ro, oo], unrelated: [r, o, n, rn, nn, nnn]);
|
| + _checkGroups(ro, interassignable: [ro, oo], unrelated: [o, n, rn, nn, nnn]);
|
| _checkGroups(rn,
|
| - equivalents: [rn],
|
| - subtypes: [],
|
| - unrelated: [o, n, rr, ro, oo, nn, nnn]);
|
| - _checkGroups(oo,
|
| - equivalents: [oo], subtypes: [], unrelated: [n, rn, nn, nnn]);
|
| + interassignable: [rn], unrelated: [o, n, rr, ro, oo, nn, nnn]);
|
| + _checkGroups(oo, interassignable: [oo], unrelated: [n, rn, nn, nnn]);
|
| _checkGroups(nn,
|
| - equivalents: [nn], subtypes: [nnn], unrelated: [r, o, rr, ro, rn, oo]);
|
| + interassignable: [nn, nnn], unrelated: [r, o, rr, ro, rn, oo]);
|
| _checkGroups(nnn,
|
| - equivalents: [nnn], subtypes: [], unrelated: [r, o, rr, ro, rn, oo]);
|
| + interassignable: [nnn], unrelated: [r, o, rr, ro, rn, oo]);
|
| }
|
|
|
| - void test_isSubtypeOf_generics() {
|
| - ClassElementImpl LClass = ElementFactory.classElement2('L', ["T"]);
|
| - InterfaceType LType = LClass.type;
|
| - ClassElementImpl MClass = ElementFactory.classElement2('M', ["T"]);
|
| - DartType typeParam = MClass.typeParameters[0].type;
|
| - InterfaceType superType = LType.substitute4(<DartType>[typeParam]);
|
| - MClass.interfaces = <InterfaceType>[superType];
|
| - InterfaceType MType = MClass.type;
|
| + void test_isAssignableTo_num() {
|
| + DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| + List<DartType> interassignable = <DartType>[
|
| + dynamicType,
|
| + objectType,
|
| + numType,
|
| + intType,
|
| + doubleType,
|
| + bottomType
|
| + ];
|
| + List<DartType> unrelated = <DartType>[
|
| + stringType,
|
| + interfaceType,
|
| + ];
|
|
|
| - InterfaceType top = LType.substitute4(<DartType>[dynamicType]);
|
| - InterfaceType left = MType.substitute4(<DartType>[dynamicType]);
|
| - InterfaceType right = LType.substitute4(<DartType>[intType]);
|
| - InterfaceType bottom = MType.substitute4(<DartType>[intType]);
|
| + _checkGroups(numType,
|
| + interassignable: interassignable, unrelated: unrelated);
|
| + }
|
|
|
| - _checkLattice(top, left, right, bottom);
|
| + void test_isAssignableTo_simple_function() {
|
| + FunctionType top =
|
| + TypeBuilder.function(required: <DartType>[intType], result: objectType);
|
| + FunctionType left =
|
| + TypeBuilder.function(required: <DartType>[intType], result: intType);
|
| + FunctionType right = TypeBuilder
|
| + .function(required: <DartType>[objectType], result: objectType);
|
| + FunctionType bottom =
|
| + TypeBuilder.function(required: <DartType>[objectType], result: intType);
|
| +
|
| + _checkCrossLattice(top, left, right, bottom);
|
| }
|
|
|
| - void _checkLattice(
|
| + void test_isAssignableTo_void_functions() {
|
| + FunctionType top =
|
| + TypeBuilder.function(required: <DartType>[intType], result: voidType);
|
| + FunctionType bottom =
|
| + TypeBuilder.function(required: <DartType>[objectType], result: intType);
|
| +
|
| + _checkEquivalent(bottom, top);
|
| + }
|
| +
|
| + void _checkCrossLattice(
|
| DartType top, DartType left, DartType right, DartType bottom) {
|
| - _checkGroups(top,
|
| - equivalents: <DartType>[top],
|
| - subtypes: <DartType>[left, right, bottom]);
|
| + _checkGroups(top, interassignable: [top, left, right, bottom]);
|
| _checkGroups(left,
|
| - equivalents: <DartType>[left],
|
| - subtypes: <DartType>[bottom],
|
| - unrelated: <DartType>[right],
|
| - supertypes: <DartType>[top]);
|
| + interassignable: [top, left, bottom], unrelated: [right]);
|
| _checkGroups(right,
|
| - equivalents: <DartType>[right],
|
| - subtypes: <DartType>[bottom],
|
| - unrelated: <DartType>[left],
|
| - supertypes: <DartType>[top]);
|
| - _checkGroups(bottom,
|
| - equivalents: <DartType>[bottom],
|
| - supertypes: <DartType>[top, left, right]);
|
| + interassignable: [top, right, bottom], unrelated: [left]);
|
| + _checkGroups(bottom, interassignable: [top, left, right, bottom]);
|
| + }
|
| +
|
| + void _checkEquivalent(DartType type1, DartType type2) {
|
| + _checkIsAssignableTo(type1, type2);
|
| + _checkIsAssignableTo(type2, type1);
|
| }
|
|
|
| void _checkGroups(DartType t1,
|
| - {List<DartType> equivalents,
|
| - List<DartType> unrelated,
|
| - List<DartType> subtypes,
|
| - List<DartType> supertypes}) {
|
| - if (equivalents != null) {
|
| - for (DartType t2 in equivalents) {
|
| + {List<DartType> interassignable, List<DartType> unrelated}) {
|
| + if (interassignable != null) {
|
| + for (DartType t2 in interassignable) {
|
| _checkEquivalent(t1, t2);
|
| }
|
| }
|
| @@ -618,52 +813,50 @@ class StrongSubtypingTest {
|
| _checkUnrelated(t1, t2);
|
| }
|
| }
|
| - if (subtypes != null) {
|
| - for (DartType t2 in subtypes) {
|
| - _checkIsStrictSubtypeOf(t2, t1);
|
| - }
|
| - }
|
| - if (supertypes != null) {
|
| - for (DartType t2 in supertypes) {
|
| - _checkIsStrictSubtypeOf(t1, t2);
|
| - }
|
| - }
|
| }
|
|
|
| - void _checkUnrelated(DartType type1, DartType type2) {
|
| - _checkIsNotSubtypeOf(type1, type2);
|
| - _checkIsNotSubtypeOf(type2, type1);
|
| + void _checkIsAssignableTo(DartType type1, DartType type2) {
|
| + expect(typeSystem.isAssignableTo(type1, type2), true);
|
| }
|
|
|
| - void _checkEquivalent(DartType type1, DartType type2) {
|
| - _checkIsSubtypeOf(type1, type2);
|
| - _checkIsSubtypeOf(type2, type1);
|
| + void _checkIsNotAssignableTo(DartType type1, DartType type2) {
|
| + expect(typeSystem.isAssignableTo(type1, type2), false);
|
| }
|
|
|
| - void _checkIsStrictSubtypeOf(DartType type1, DartType type2) {
|
| - _checkIsSubtypeOf(type1, type2);
|
| - _checkIsNotSubtypeOf(type2, type1);
|
| + void _checkIsStrictAssignableTo(DartType type1, DartType type2) {
|
| + _checkIsAssignableTo(type1, type2);
|
| + _checkIsNotAssignableTo(type2, type1);
|
| }
|
|
|
| - void _checkIsSubtypeOf(DartType type1, DartType type2) {
|
| - expect(typeSystem.isSubtypeOf(type1, type2), true);
|
| + void _checkLattice(
|
| + DartType top, DartType left, DartType right, DartType bottom) {
|
| + _checkGroups(top, interassignable: <DartType>[top, left, right, bottom]);
|
| + _checkGroups(left,
|
| + interassignable: <DartType>[top, left, bottom],
|
| + unrelated: <DartType>[right]);
|
| + _checkGroups(right,
|
| + interassignable: <DartType>[top, right, bottom],
|
| + unrelated: <DartType>[left]);
|
| + _checkGroups(bottom, interassignable: <DartType>[top, left, right, bottom]);
|
| }
|
|
|
| - void _checkIsNotSubtypeOf(DartType type1, DartType type2) {
|
| - expect(typeSystem.isSubtypeOf(type1, type2), false);
|
| + void _checkUnrelated(DartType type1, DartType type2) {
|
| + _checkIsNotAssignableTo(type1, type2);
|
| + _checkIsNotAssignableTo(type2, type1);
|
| }
|
| }
|
|
|
| @reflectiveTest
|
| -class StrongAssignabilityTest {
|
| +class StrongGenericFunctionInferenceTest {
|
| TypeProvider typeProvider;
|
| - TypeSystem typeSystem;
|
| + StrongTypeSystemImpl typeSystem;
|
|
|
| DartType get bottomType => typeProvider.bottomType;
|
| InterfaceType get doubleType => typeProvider.doubleType;
|
| DartType get dynamicType => typeProvider.dynamicType;
|
| InterfaceType get functionType => typeProvider.functionType;
|
| InterfaceType get intType => typeProvider.intType;
|
| + InterfaceType get iterableType => typeProvider.iterableType;
|
| InterfaceType get listType => typeProvider.listType;
|
| InterfaceType get numType => typeProvider.numType;
|
| InterfaceType get objectType => typeProvider.objectType;
|
| @@ -675,88 +868,691 @@ class StrongAssignabilityTest {
|
| typeSystem = new StrongTypeSystemImpl();
|
| }
|
|
|
| - void test_isAssignableTo_dynamic_isTop() {
|
| - DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - List<DartType> interassignable = <DartType>[
|
| - dynamicType,
|
| - objectType,
|
| - intType,
|
| - doubleType,
|
| - numType,
|
| + void test_boundedByAnotherTypeParameter() {
|
| + // <TFrom, TTo extends Iterable<TFrom>>(TFrom) -> TTo
|
| + var tFrom = TypeBuilder.variable('TFrom');
|
| + var tTo =
|
| + TypeBuilder.variable('TTo', bound: iterableType.instantiate([tFrom]));
|
| + var cast = TypeBuilder
|
| + .function(types: [tFrom, tTo], required: [tFrom], result: tTo);
|
| + expect(_inferCall(cast, [stringType]), [
|
| stringType,
|
| - interfaceType,
|
| - bottomType
|
| - ];
|
| - _checkGroups(dynamicType, interassignable: interassignable);
|
| + iterableType.instantiate([stringType])
|
| + ]);
|
| + }
|
| +
|
| + void test_boundedByOuterClass() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/25740.
|
| +
|
| + // class A {}
|
| + var a = ElementFactory.classElement('A', objectType);
|
| +
|
| + // class B extends A {}
|
| + var b = ElementFactory.classElement('B', a.type);
|
| +
|
| + // class C<T extends A> {
|
| + var c = ElementFactory.classElement('C', objectType, ['T']);
|
| + (c.typeParameters[0] as TypeParameterElementImpl).bound = a.type;
|
| + // S m<S extends T>(S);
|
| + var s = TypeBuilder.variable('S');
|
| + (s.element as TypeParameterElementImpl).bound = c.typeParameters[0].type;
|
| + var m = ElementFactory.methodElement('m', s, [s]);
|
| + m.typeParameters = [s.element];
|
| + c.methods = [m];
|
| + // }
|
| +
|
| + // C<Object> cOfObject;
|
| + var cOfObject = c.type.instantiate([objectType]);
|
| + // C<A> cOfA;
|
| + var cOfA = c.type.instantiate([a.type]);
|
| + // C<B> cOfB;
|
| + var cOfB = c.type.instantiate([b.type]);
|
| + // B b;
|
| + // cOfB.m(b); // infer <B>
|
| + expect(_inferCall(cOfB.getMethod('m').type, [b.type]), [b.type, b.type]);
|
| + // cOfA.m(b); // infer <B>
|
| + expect(_inferCall(cOfA.getMethod('m').type, [b.type]), [a.type, b.type]);
|
| + // cOfObject.m(b); // infer <B>
|
| + expect(_inferCall(cOfObject.getMethod('m').type, [b.type]),
|
| + [objectType, b.type]);
|
| + }
|
| +
|
| + void test_boundedByOuterClassSubstituted() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/25740.
|
| +
|
| + // class A {}
|
| + var a = ElementFactory.classElement('A', objectType);
|
| +
|
| + // class B extends A {}
|
| + var b = ElementFactory.classElement('B', a.type);
|
| +
|
| + // class C<T extends A> {
|
| + var c = ElementFactory.classElement('C', objectType, ['T']);
|
| + (c.typeParameters[0] as TypeParameterElementImpl).bound = a.type;
|
| + // S m<S extends Iterable<T>>(S);
|
| + var s = TypeBuilder.variable('S');
|
| + var iterableOfT = iterableType.instantiate([c.typeParameters[0].type]);
|
| + (s.element as TypeParameterElementImpl).bound = iterableOfT;
|
| + var m = ElementFactory.methodElement('m', s, [s]);
|
| + m.typeParameters = [s.element];
|
| + c.methods = [m];
|
| + // }
|
| +
|
| + // C<Object> cOfObject;
|
| + var cOfObject = c.type.instantiate([objectType]);
|
| + // C<A> cOfA;
|
| + var cOfA = c.type.instantiate([a.type]);
|
| + // C<B> cOfB;
|
| + var cOfB = c.type.instantiate([b.type]);
|
| + // List<B> b;
|
| + var listOfB = listType.instantiate([b.type]);
|
| + // cOfB.m(b); // infer <B>
|
| + expect(_inferCall(cOfB.getMethod('m').type, [listOfB]), [b.type, listOfB]);
|
| + // cOfA.m(b); // infer <B>
|
| + expect(_inferCall(cOfA.getMethod('m').type, [listOfB]), [a.type, listOfB]);
|
| + // cOfObject.m(b); // infer <B>
|
| + expect(_inferCall(cOfObject.getMethod('m').type, [listOfB]),
|
| + [objectType, listOfB]);
|
| + }
|
| +
|
| + void test_boundedRecursively() {
|
| + // class Clonable<T extends Clonable<T>>
|
| + ClassElementImpl clonable =
|
| + ElementFactory.classElement('Clonable', objectType, ['T']);
|
| + (clonable.typeParameters[0] as TypeParameterElementImpl).bound =
|
| + clonable.type;
|
| + // class Foo extends Clonable<Foo>
|
| + ClassElementImpl foo = ElementFactory.classElement('Foo', null);
|
| + foo.supertype = clonable.type.instantiate([foo.type]);
|
| +
|
| + // <S extends Clonable<S>>
|
| + var s = TypeBuilder.variable('S');
|
| + (s.element as TypeParameterElementImpl).bound =
|
| + clonable.type.instantiate([s]);
|
| + // (S, S) -> S
|
| + var clone = TypeBuilder.function(types: [s], required: [s, s], result: s);
|
| + expect(_inferCall(clone, [foo.type, foo.type]), [foo.type]);
|
| +
|
| + // Something invalid...
|
| + expect(_inferCall(clone, [stringType, numType]), null);
|
| + }
|
| +
|
| + void test_genericCastFunction() {
|
| + // <TFrom, TTo>(TFrom) -> TTo
|
| + var tFrom = TypeBuilder.variable('TFrom');
|
| + var tTo = TypeBuilder.variable('TTo');
|
| + var cast = TypeBuilder
|
| + .function(types: [tFrom, tTo], required: [tFrom], result: tTo);
|
| + expect(_inferCall(cast, [intType]), [intType, dynamicType]);
|
| + }
|
| +
|
| + void test_genericCastFunctionWithUpperBound() {
|
| + // <TFrom, TTo extends TFrom>(TFrom) -> TTo
|
| + var tFrom = TypeBuilder.variable('TFrom');
|
| + var tTo = TypeBuilder.variable('TTo', bound: tFrom);
|
| + var cast = TypeBuilder
|
| + .function(types: [tFrom, tTo], required: [tFrom], result: tTo);
|
| + expect(_inferCall(cast, [intType]), [intType, intType]);
|
| + }
|
| +
|
| + void test_parametersToFunctionParam() {
|
| + // <T>(f(T t)) -> T
|
| + var t = TypeBuilder.variable('T');
|
| + var cast = TypeBuilder.function(types: [
|
| + t
|
| + ], required: [
|
| + TypeBuilder.function(required: [t], result: dynamicType)
|
| + ], result: t);
|
| + expect(
|
| + _inferCall(cast, [
|
| + TypeBuilder.function(required: [numType], result: dynamicType)
|
| + ]),
|
| + [numType]);
|
| + }
|
| +
|
| + void test_parametersUseLeastUpperBound() {
|
| + // <T>(T x, T y) -> T
|
| + var t = TypeBuilder.variable('T');
|
| + var cast = TypeBuilder.function(types: [t], required: [t, t], result: t);
|
| + expect(_inferCall(cast, [intType, doubleType]), [numType]);
|
| + }
|
| +
|
| + void test_parameterTypeUsesUpperBound() {
|
| + // <T extends num>(T) -> dynamic
|
| + var t = TypeBuilder.variable('T', bound: numType);
|
| + var f =
|
| + TypeBuilder.function(types: [t], required: [t], result: dynamicType);
|
| + expect(_inferCall(f, [intType]), [intType]);
|
| + }
|
| +
|
| + void test_returnFunctionWithGenericParameter() {
|
| + // <T>(T -> T) -> (T -> void)
|
| + var t = TypeBuilder.variable('T');
|
| + var f = TypeBuilder.function(types: [
|
| + t
|
| + ], required: [
|
| + TypeBuilder.function(required: [t], result: t)
|
| + ], result: TypeBuilder.function(required: [t], result: voidType));
|
| + expect(
|
| + _inferCall(f, [
|
| + TypeBuilder.function(required: [numType], result: intType)
|
| + ]),
|
| + [numType]);
|
| + }
|
| +
|
| + void test_returnFunctionWithGenericParameterAndReturn() {
|
| + // <T>(T -> T) -> (T -> T)
|
| + var t = TypeBuilder.variable('T');
|
| + var f = TypeBuilder.function(types: [
|
| + t
|
| + ], required: [
|
| + TypeBuilder.function(required: [t], result: t)
|
| + ], result: TypeBuilder.function(required: [t], result: t));
|
| + expect(
|
| + _inferCall(f, [
|
| + TypeBuilder.function(required: [numType], result: intType)
|
| + ]),
|
| + [numType]);
|
| + }
|
| +
|
| + void test_returnFunctionWithGenericReturn() {
|
| + // <T>(T -> T) -> (() -> T)
|
| + var t = TypeBuilder.variable('T');
|
| + var f = TypeBuilder.function(types: [
|
| + t
|
| + ], required: [
|
| + TypeBuilder.function(required: [t], result: t)
|
| + ], result: TypeBuilder.function(required: [], result: t));
|
| + expect(
|
| + _inferCall(f, [
|
| + TypeBuilder.function(required: [numType], result: intType)
|
| + ]),
|
| + [intType]);
|
| + }
|
| +
|
| + void test_returnTypeFromContext() {
|
| + // <T>() -> T
|
| + var t = TypeBuilder.variable('T');
|
| + var f = TypeBuilder.function(types: [t], required: [], result: t);
|
| + expect(_inferCall(f, [], stringType), [stringType]);
|
| + }
|
| +
|
| + void test_returnTypeWithBoundFromContext() {
|
| + // <T extends num>() -> T
|
| + var t = TypeBuilder.variable('T', bound: numType);
|
| + var f = TypeBuilder.function(types: [t], required: [], result: t);
|
| + expect(_inferCall(f, [], doubleType), [doubleType]);
|
| + }
|
| +
|
| + void test_returnTypeWithBoundFromInvalidContext() {
|
| + // <T extends num>() -> T
|
| + var t = TypeBuilder.variable('T', bound: numType);
|
| + var f = TypeBuilder.function(types: [t], required: [], result: t);
|
| + expect(_inferCall(f, [], stringType), null);
|
| + }
|
| +
|
| + void test_unifyParametersToFunctionParam() {
|
| + // <T>(f(T t), g(T t)) -> T
|
| + var t = TypeBuilder.variable('T');
|
| + var cast = TypeBuilder.function(types: [
|
| + t
|
| + ], required: [
|
| + TypeBuilder.function(required: [t], result: dynamicType),
|
| + TypeBuilder.function(required: [t], result: dynamicType)
|
| + ], result: t);
|
| + expect(
|
| + _inferCall(cast, [
|
| + TypeBuilder.function(required: [intType], result: dynamicType),
|
| + TypeBuilder.function(required: [doubleType], result: dynamicType)
|
| + ]),
|
| + null);
|
| + }
|
| +
|
| + void test_unusedReturnTypeIsDynamic() {
|
| + // <T>() -> T
|
| + var t = TypeBuilder.variable('T');
|
| + var f = TypeBuilder.function(types: [t], required: [], result: t);
|
| + expect(_inferCall(f, []), [dynamicType]);
|
| + }
|
| +
|
| + void test_unusedReturnTypeWithUpperBound() {
|
| + // <T extends num>() -> T
|
| + var t = TypeBuilder.variable('T', bound: numType);
|
| + var f = TypeBuilder.function(types: [t], required: [], result: t);
|
| + expect(_inferCall(f, []), [numType]);
|
| + }
|
| +
|
| + List<DartType> _inferCall(FunctionTypeImpl ft, List<DartType> arguments,
|
| + [DartType returnType]) {
|
| + FunctionType inferred = typeSystem.inferGenericFunctionCall(
|
| + typeProvider,
|
| + ft,
|
| + ft.parameters.map((p) => p.type).toList(),
|
| + arguments,
|
| + ft.returnType,
|
| + returnType);
|
| + return inferred?.typeArguments;
|
| }
|
| +}
|
|
|
| - void test_isAssignableTo_bottom_isBottom() {
|
| +/**
|
| + * Tests GLB, which only exists in strong mode.
|
| + */
|
| +@reflectiveTest
|
| +class StrongGreatestLowerBoundTest extends BoundTestBase {
|
| + void setUp() {
|
| + typeSystem = new StrongTypeSystemImpl();
|
| + super.setUp();
|
| + }
|
| +
|
| + void test_bottom_function() {
|
| + _checkGreatestLowerBound(bottomType, simpleFunctionType, bottomType);
|
| + }
|
| +
|
| + void test_bottom_interface() {
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - List<DartType> interassignable = <DartType>[
|
| - dynamicType,
|
| - objectType,
|
| - intType,
|
| - doubleType,
|
| - numType,
|
| - stringType,
|
| - interfaceType,
|
| - bottomType
|
| - ];
|
| + _checkGreatestLowerBound(bottomType, interfaceType, bottomType);
|
| + }
|
|
|
| - _checkGroups(bottomType, interassignable: interassignable);
|
| + void test_bottom_typeParam() {
|
| + DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| + _checkGreatestLowerBound(bottomType, typeParam, bottomType);
|
| }
|
|
|
| - void test_isAssignableTo_int() {
|
| + void test_classAndSuperclass() {
|
| + // class A
|
| + // class B extends A
|
| + // class C extends B
|
| + ClassElementImpl classA = ElementFactory.classElement2("A");
|
| + ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
|
| + ClassElementImpl classC = ElementFactory.classElement("C", classB.type);
|
| + _checkGreatestLowerBound(classA.type, classC.type, classC.type);
|
| + }
|
| +
|
| + void test_classAndSuperinterface() {
|
| + // class A
|
| + // class B implements A
|
| + // class C implements B
|
| + ClassElementImpl classA = ElementFactory.classElement2("A");
|
| + ClassElementImpl classB = ElementFactory.classElement2("B");
|
| + ClassElementImpl classC = ElementFactory.classElement2("C");
|
| + classB.interfaces = <InterfaceType>[classA.type];
|
| + classC.interfaces = <InterfaceType>[classB.type];
|
| + _checkGreatestLowerBound(classA.type, classC.type, classC.type);
|
| + }
|
| +
|
| + void test_dynamic_bottom() {
|
| + _checkGreatestLowerBound(dynamicType, bottomType, bottomType);
|
| + }
|
| +
|
| + void test_dynamic_function() {
|
| + _checkGreatestLowerBound(
|
| + dynamicType, simpleFunctionType, simpleFunctionType);
|
| + }
|
| +
|
| + void test_dynamic_interface() {
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - List<DartType> interassignable = <DartType>[
|
| + _checkGreatestLowerBound(dynamicType, interfaceType, interfaceType);
|
| + }
|
| +
|
| + void test_dynamic_typeParam() {
|
| + DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| + _checkGreatestLowerBound(dynamicType, typeParam, typeParam);
|
| + }
|
| +
|
| + void test_dynamic_void() {
|
| + _checkGreatestLowerBound(dynamicType, voidType, voidType);
|
| + }
|
| +
|
| + void test_functionsDifferentNamedTakeUnion() {
|
| + FunctionType type1 = _functionType([], named: {'a': intType, 'b': intType});
|
| + FunctionType type2 =
|
| + _functionType([], named: {'b': doubleType, 'c': stringType});
|
| + FunctionType expected =
|
| + _functionType([], named: {'a': intType, 'b': numType, 'c': stringType});
|
| + _checkGreatestLowerBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsDifferentOptionalArityTakeMax() {
|
| + FunctionType type1 = _functionType([], optional: [intType]);
|
| + FunctionType type2 =
|
| + _functionType([], optional: [doubleType, stringType, objectType]);
|
| + FunctionType expected =
|
| + _functionType([], optional: [numType, stringType, objectType]);
|
| + _checkGreatestLowerBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsDifferentRequiredArityBecomeOptional() {
|
| + FunctionType type1 = _functionType([intType]);
|
| + FunctionType type2 = _functionType([intType, intType, intType]);
|
| + FunctionType expected =
|
| + _functionType([intType], optional: [intType, intType]);
|
| + _checkGreatestLowerBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsFuzzyArrows() {
|
| + FunctionType type1 = _functionType([dynamicType]);
|
| + FunctionType type2 = _functionType([intType]);
|
| + FunctionType expected = _functionType([intType]);
|
| + _checkGreatestLowerBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsGlbReturnType() {
|
| + FunctionType type1 = _functionType([], returns: intType);
|
| + FunctionType type2 = _functionType([], returns: numType);
|
| + FunctionType expected = _functionType([], returns: intType);
|
| + _checkGreatestLowerBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsLubNamedParams() {
|
| + FunctionType type1 =
|
| + _functionType([], named: {'a': stringType, 'b': intType});
|
| + FunctionType type2 = _functionType([], named: {'a': intType, 'b': numType});
|
| + FunctionType expected =
|
| + _functionType([], named: {'a': objectType, 'b': numType});
|
| + _checkGreatestLowerBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsLubPositionalParams() {
|
| + FunctionType type1 = _functionType([], optional: [stringType, intType]);
|
| + FunctionType type2 = _functionType([], optional: [intType, numType]);
|
| + FunctionType expected = _functionType([], optional: [objectType, numType]);
|
| + _checkGreatestLowerBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsLubRequiredParams() {
|
| + FunctionType type1 = _functionType([stringType, intType, intType]);
|
| + FunctionType type2 = _functionType([intType, doubleType, numType]);
|
| + FunctionType expected = _functionType([objectType, numType, numType]);
|
| + _checkGreatestLowerBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsMixedOptionalAndRequiredBecomeOptional() {
|
| + FunctionType type1 = _functionType([intType, intType],
|
| + optional: [intType, intType, intType]);
|
| + FunctionType type2 = _functionType([intType], optional: [intType, intType]);
|
| + FunctionType expected = _functionType([intType],
|
| + optional: [intType, intType, intType, intType]);
|
| + _checkGreatestLowerBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsReturnBottomIfMixOptionalAndNamed() {
|
| + // Dart doesn't allow a function to have both optional and named parameters,
|
| + // so if we would have synthethized that, pick bottom instead.
|
| + FunctionType type1 = _functionType([intType], named: {'a': intType});
|
| + FunctionType type2 = _functionType([], named: {'a': intType});
|
| + _checkGreatestLowerBound(type1, type2, bottomType);
|
| + }
|
| +
|
| + void test_functionsSameType() {
|
| + FunctionType type1 = _functionType([stringType, intType, numType],
|
| + optional: [doubleType], named: {'n': numType}, returns: intType);
|
| + FunctionType type2 = _functionType([stringType, intType, numType],
|
| + optional: [doubleType], named: {'n': numType}, returns: intType);
|
| + FunctionType expected = _functionType([stringType, intType, numType],
|
| + optional: [doubleType], named: {'n': numType}, returns: intType);
|
| + _checkGreatestLowerBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_interface_function() {
|
| + DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| + _checkGreatestLowerBound(interfaceType, simpleFunctionType, bottomType);
|
| + }
|
| +
|
| + void test_mixin() {
|
| + // class A
|
| + // class B
|
| + // class C
|
| + // class D extends A with B, C
|
| + ClassElement classA = ElementFactory.classElement2("A");
|
| + ClassElement classB = ElementFactory.classElement2("B");
|
| + ClassElement classC = ElementFactory.classElement2("C");
|
| + ClassElementImpl classD = ElementFactory.classElement("D", classA.type);
|
| + classD.mixins = <InterfaceType>[classB.type, classC.type];
|
| + _checkGreatestLowerBound(classA.type, classD.type, classD.type);
|
| + _checkGreatestLowerBound(classB.type, classD.type, classD.type);
|
| + _checkGreatestLowerBound(classC.type, classD.type, classD.type);
|
| + }
|
| +
|
| + void test_self() {
|
| + DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| + DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| +
|
| + List<DartType> types = [
|
| dynamicType,
|
| - objectType,
|
| - intType,
|
| - numType,
|
| - bottomType
|
| - ];
|
| - List<DartType> unrelated = <DartType>[
|
| - doubleType,
|
| - stringType,
|
| + voidType,
|
| + bottomType,
|
| + typeParam,
|
| interfaceType,
|
| + simpleFunctionType
|
| ];
|
|
|
| - _checkGroups(intType,
|
| - interassignable: interassignable, unrelated: unrelated);
|
| + for (DartType type in types) {
|
| + _checkGreatestLowerBound(type, type, type);
|
| + }
|
| }
|
|
|
| - void test_isAssignableTo_double() {
|
| + void test_typeParam_function_noBound() {
|
| + DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| + _checkGreatestLowerBound(typeParam, simpleFunctionType, bottomType);
|
| + }
|
| +
|
| + void test_typeParam_interface_bounded() {
|
| + DartType typeA = ElementFactory.classElement2('A', []).type;
|
| + DartType typeB = ElementFactory.classElement('B', typeA).type;
|
| + DartType typeC = ElementFactory.classElement('C', typeB).type;
|
| + TypeParameterElementImpl typeParam =
|
| + ElementFactory.typeParameterElement('T');
|
| + typeParam.bound = typeB;
|
| + _checkGreatestLowerBound(typeParam.type, typeC, bottomType);
|
| + }
|
| +
|
| + void test_typeParam_interface_noBound() {
|
| + // GLB(T, A) = ⊥
|
| + DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - List<DartType> interassignable = <DartType>[
|
| - dynamicType,
|
| - objectType,
|
| - doubleType,
|
| - numType,
|
| - bottomType
|
| + _checkGreatestLowerBound(typeParam, interfaceType, bottomType);
|
| + }
|
| +
|
| + void test_typeParameters_different() {
|
| + // GLB(List<int>, List<double>) = ⊥
|
| + InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
|
| + InterfaceType listOfDoubleType =
|
| + listType.instantiate(<DartType>[doubleType]);
|
| + // TODO(rnystrom): Can we do something better here?
|
| + _checkGreatestLowerBound(listOfIntType, listOfDoubleType, bottomType);
|
| + }
|
| +
|
| + void test_typeParameters_same() {
|
| + // GLB(List<int>, List<int>) = List<int>
|
| + InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
|
| + _checkGreatestLowerBound(listOfIntType, listOfIntType, listOfIntType);
|
| + }
|
| +
|
| + void test_unrelatedClasses() {
|
| + // class A
|
| + // class B
|
| + // class C
|
| + ClassElementImpl classA = ElementFactory.classElement2("A");
|
| + ClassElementImpl classB = ElementFactory.classElement2("B");
|
| + _checkGreatestLowerBound(classA.type, classB.type, bottomType);
|
| + }
|
| +
|
| + void test_void() {
|
| + List<DartType> types = [
|
| + bottomType,
|
| + simpleFunctionType,
|
| + ElementFactory.classElement2('A', []).type,
|
| + ElementFactory.typeParameterElement('T').type
|
| ];
|
| - List<DartType> unrelated = <DartType>[intType, stringType, interfaceType,];
|
| + for (DartType type in types) {
|
| + _checkGreatestLowerBound(_functionType([], returns: voidType),
|
| + _functionType([], returns: type), _functionType([], returns: type));
|
| + }
|
| + }
|
| +}
|
|
|
| - _checkGroups(doubleType,
|
| - interassignable: interassignable, unrelated: unrelated);
|
| +/**
|
| + * Tests LUB in strong mode.
|
| + *
|
| + * Tests defined in this class are ones whose behavior is spec mode-specific.
|
| + * In particular, function parameters are compared using LUB in spec mode, but
|
| + * GLB in strong mode.
|
| + */
|
| +@reflectiveTest
|
| +class StrongLeastUpperBoundTest extends LeastUpperBoundTestBase {
|
| + void setUp() {
|
| + typeSystem = new StrongTypeSystemImpl();
|
| + super.setUp();
|
| + }
|
| +
|
| + void test_functionsFuzzyArrows() {
|
| + FunctionType type1 = _functionType([dynamicType]);
|
| + FunctionType type2 = _functionType([intType]);
|
| + FunctionType expected = _functionType([dynamicType]);
|
| + _checkLeastUpperBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsGlbNamedParams() {
|
| + FunctionType type1 =
|
| + _functionType([], named: {'a': stringType, 'b': intType});
|
| + FunctionType type2 = _functionType([], named: {'a': intType, 'b': numType});
|
| + FunctionType expected =
|
| + _functionType([], named: {'a': bottomType, 'b': intType});
|
| + _checkLeastUpperBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsGlbPositionalParams() {
|
| + FunctionType type1 = _functionType([], optional: [stringType, intType]);
|
| + FunctionType type2 = _functionType([], optional: [intType, numType]);
|
| + FunctionType expected = _functionType([], optional: [bottomType, intType]);
|
| + _checkLeastUpperBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_functionsGlbRequiredParams() {
|
| + FunctionType type1 = _functionType([stringType, intType, intType]);
|
| + FunctionType type2 = _functionType([intType, doubleType, numType]);
|
| + FunctionType expected = _functionType([bottomType, bottomType, intType]);
|
| + _checkLeastUpperBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_nestedNestedFunctionsGlbInnermostParamTypes() {
|
| + FunctionType type1 = _functionType([
|
| + _functionType([
|
| + _functionType([stringType, intType, intType])
|
| + ])
|
| + ]);
|
| + FunctionType type2 = _functionType([
|
| + _functionType([
|
| + _functionType([intType, doubleType, numType])
|
| + ])
|
| + ]);
|
| + FunctionType expected = _functionType([
|
| + _functionType([
|
| + _functionType([bottomType, bottomType, intType])
|
| + ])
|
| + ]);
|
| + _checkLeastUpperBound(type1, type2, expected);
|
| + }
|
| +
|
| + void test_typeParam_boundedByParam() {
|
| + TypeParameterElementImpl typeParamElementT =
|
| + ElementFactory.typeParameterElement('T');
|
| + TypeParameterElementImpl typeParamElementS =
|
| + ElementFactory.typeParameterElement('S');
|
| + DartType typeParamT = typeParamElementT.type;
|
| + DartType typeParamS = typeParamElementS.type;
|
| + typeParamElementT.bound = typeParamS;
|
| + _checkLeastUpperBound(typeParamT, typeParamS, typeParamS);
|
| }
|
|
|
| - void test_isAssignableTo_num() {
|
| + void test_typeParam_fBounded() {
|
| + ClassElementImpl AClass = ElementFactory.classElement2('A', ["Q"]);
|
| + InterfaceType AType = AClass.type;
|
| +
|
| + DartType s = TypeBuilder.variable("S");
|
| + (s.element as TypeParameterElementImpl).bound = AType.instantiate([s]);
|
| + DartType u = TypeBuilder.variable("U");
|
| + (u.element as TypeParameterElementImpl).bound = AType.instantiate([u]);
|
| +
|
| + _checkLeastUpperBound(s, u, AType.instantiate([objectType]));
|
| + }
|
| +
|
| + /// Check least upper bound of the same class with different type parameters.
|
| + void test_typeParameters_different() {
|
| + // class List<int>
|
| + // class List<double>
|
| + InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
|
| + InterfaceType listOfDoubleType =
|
| + listType.instantiate(<DartType>[doubleType]);
|
| + InterfaceType listOfNum = listType.instantiate(<DartType>[numType]);
|
| + _checkLeastUpperBound(listOfIntType, listOfDoubleType, listOfNum);
|
| + }
|
| +
|
| + /// Check least upper bound of two related classes with different
|
| + /// type parameters.
|
| + void test_typeParametersAndClass_different() {
|
| + // class List<int>
|
| + // class Iterable<double>
|
| + InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
|
| + InterfaceType iterableOfDoubleType =
|
| + iterableType.instantiate(<DartType>[doubleType]);
|
| + // TODO(leafp): this should be iterableOfNumType
|
| + _checkLeastUpperBound(listOfIntType, iterableOfDoubleType, objectType);
|
| + }
|
| +}
|
| +
|
| +@reflectiveTest
|
| +class StrongSubtypingTest {
|
| + TypeProvider typeProvider;
|
| + TypeSystem typeSystem;
|
| +
|
| + DartType get bottomType => typeProvider.bottomType;
|
| + InterfaceType get doubleType => typeProvider.doubleType;
|
| + DartType get dynamicType => typeProvider.dynamicType;
|
| + InterfaceType get functionType => typeProvider.functionType;
|
| + InterfaceType get intType => typeProvider.intType;
|
| + InterfaceType get listType => typeProvider.listType;
|
| + InterfaceType get numType => typeProvider.numType;
|
| + InterfaceType get objectType => typeProvider.objectType;
|
| + InterfaceType get stringType => typeProvider.stringType;
|
| + DartType get voidType => VoidTypeImpl.instance;
|
| +
|
| + void setUp() {
|
| + typeProvider = new TestTypeProvider();
|
| + typeSystem = new StrongTypeSystemImpl();
|
| + }
|
| +
|
| + void test_bottom_isBottom() {
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - List<DartType> interassignable = <DartType>[
|
| + List<DartType> equivalents = <DartType>[bottomType];
|
| + List<DartType> supertypes = <DartType>[
|
| dynamicType,
|
| objectType,
|
| - numType,
|
| intType,
|
| doubleType,
|
| - bottomType
|
| + numType,
|
| + stringType,
|
| + functionType,
|
| + interfaceType
|
| ];
|
| - List<DartType> unrelated = <DartType>[stringType, interfaceType,];
|
| + _checkGroups(bottomType, equivalents: equivalents, supertypes: supertypes);
|
| + }
|
|
|
| - _checkGroups(numType,
|
| - interassignable: interassignable, unrelated: unrelated);
|
| + void test_call_method() {
|
| + ClassElementImpl classBottom = ElementFactory.classElement2("Bottom");
|
| + MethodElement methodBottom =
|
| + ElementFactory.methodElement("call", objectType, <DartType>[intType]);
|
| + classBottom.methods = <MethodElement>[methodBottom];
|
| +
|
| + DartType top =
|
| + TypeBuilder.function(required: <DartType>[intType], result: objectType);
|
| + InterfaceType bottom = classBottom.type;
|
| +
|
| + _checkIsStrictSubtypeOf(bottom, top);
|
| }
|
|
|
| - void test_isAssignableTo_classes() {
|
| + void test_classes() {
|
| ClassElement classTop = ElementFactory.classElement2("A");
|
| ClassElement classLeft = ElementFactory.classElement("B", classTop.type);
|
| ClassElement classRight = ElementFactory.classElement("C", classTop.type);
|
| @@ -770,129 +1566,258 @@ class StrongAssignabilityTest {
|
| _checkLattice(top, left, right, bottom);
|
| }
|
|
|
| - void test_isAssignableTo_simple_function() {
|
| - FunctionType top =
|
| - TypeBuilder.functionType(<DartType>[intType], objectType);
|
| - FunctionType left = TypeBuilder.functionType(<DartType>[intType], intType);
|
| - FunctionType right =
|
| - TypeBuilder.functionType(<DartType>[objectType], objectType);
|
| - FunctionType bottom =
|
| - TypeBuilder.functionType(<DartType>[objectType], intType);
|
| + void test_double() {
|
| + List<DartType> equivalents = <DartType>[doubleType];
|
| + List<DartType> supertypes = <DartType>[numType];
|
| + List<DartType> unrelated = <DartType>[intType];
|
| + _checkGroups(doubleType,
|
| + equivalents: equivalents, supertypes: supertypes, unrelated: unrelated);
|
| + }
|
|
|
| - _checkCrossLattice(top, left, right, bottom);
|
| + void test_dynamic_isTop() {
|
| + DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| + List<DartType> equivalents = <DartType>[dynamicType, objectType];
|
| + List<DartType> subtypes = <DartType>[
|
| + intType,
|
| + doubleType,
|
| + numType,
|
| + stringType,
|
| + functionType,
|
| + interfaceType,
|
| + bottomType
|
| + ];
|
| + _checkGroups(dynamicType, equivalents: equivalents, subtypes: subtypes);
|
| }
|
|
|
| - void test_isAssignableTo_call_method() {
|
| - ClassElementImpl classBottom = ElementFactory.classElement2("B");
|
| - MethodElement methodBottom =
|
| - ElementFactory.methodElement("call", objectType, <DartType>[intType]);
|
| - classBottom.methods = <MethodElement>[methodBottom];
|
| + void test_fuzzy_arrows() {
|
| + FunctionType top = TypeBuilder
|
| + .function(required: <DartType>[dynamicType], result: objectType);
|
| + FunctionType left = TypeBuilder
|
| + .function(required: <DartType>[objectType], result: objectType);
|
| + FunctionType right = TypeBuilder
|
| + .function(required: <DartType>[dynamicType], result: bottomType);
|
| + FunctionType bottom = TypeBuilder
|
| + .function(required: <DartType>[objectType], result: bottomType);
|
|
|
| - DartType top = TypeBuilder.functionType(<DartType>[intType], objectType);
|
| - InterfaceType bottom = classBottom.type;
|
| + _checkLattice(top, left, right, bottom);
|
| + }
|
|
|
| - _checkIsStrictAssignableTo(bottom, top);
|
| + void test_genericFunction_generic_monomorphic() {
|
| + DartType s = TypeBuilder.variable("S");
|
| + DartType t = TypeBuilder.variable("T", bound: s);
|
| + DartType u = TypeBuilder.variable("U", bound: intType);
|
| + DartType v = TypeBuilder.variable("V", bound: u);
|
| +
|
| + _checkIsStrictSubtypeOf(
|
| + TypeBuilder.function(types: [s, t], required: [s], result: t),
|
| + TypeBuilder.function(required: [dynamicType], result: dynamicType));
|
| +
|
| + _checkIsNotSubtypeOf(
|
| + TypeBuilder.function(types: [u, v], required: [u], result: v),
|
| + TypeBuilder.function(required: [objectType], result: objectType));
|
| +
|
| + _checkIsStrictSubtypeOf(
|
| + TypeBuilder.function(types: [u, v], required: [u], result: v),
|
| + TypeBuilder.function(required: [intType], result: intType));
|
| }
|
|
|
| - void test_isAssignableTo_fuzzy_arrows() {
|
| - FunctionType top =
|
| - TypeBuilder.functionType(<DartType>[dynamicType], objectType);
|
| - FunctionType left =
|
| - TypeBuilder.functionType(<DartType>[objectType], objectType);
|
| - FunctionType right =
|
| - TypeBuilder.functionType(<DartType>[dynamicType], bottomType);
|
| - FunctionType bottom =
|
| - TypeBuilder.functionType(<DartType>[objectType], bottomType);
|
| + void test_genericFunction_simple() {
|
| + DartType s = TypeBuilder.variable("S");
|
| + DartType t = TypeBuilder.variable("T");
|
|
|
| - _checkCrossLattice(top, left, right, bottom);
|
| + _checkEquivalent(
|
| + TypeBuilder.function(types: [t]), TypeBuilder.function(types: [s]));
|
| +
|
| + _checkEquivalent(TypeBuilder.function(types: [t], required: [t], result: t),
|
| + TypeBuilder.function(types: [s], required: [s], result: s));
|
| }
|
|
|
| - void test_isAssignableTo_void_functions() {
|
| - FunctionType top = TypeBuilder.functionType(<DartType>[intType], voidType);
|
| - FunctionType bottom =
|
| - TypeBuilder.functionType(<DartType>[objectType], intType);
|
| + void test_genericFunction_simple_bounded() {
|
| + DartType s = TypeBuilder.variable("S");
|
| + DartType t = TypeBuilder.variable("T", bound: s);
|
| + DartType u = TypeBuilder.variable("U");
|
| + DartType v = TypeBuilder.variable("V", bound: u);
|
|
|
| - _checkEquivalent(bottom, top);
|
| + _checkEquivalent(TypeBuilder.function(types: [s, t]),
|
| + TypeBuilder.function(types: [u, v]));
|
| +
|
| + _checkEquivalent(
|
| + TypeBuilder.function(types: [s, t], required: [s], result: t),
|
| + TypeBuilder.function(types: [u, v], required: [u], result: v));
|
| +
|
| + {
|
| + DartType top =
|
| + TypeBuilder.function(types: [s, t], required: [t], result: s);
|
| + DartType left =
|
| + TypeBuilder.function(types: [u, v], required: [u], result: u);
|
| + DartType right =
|
| + TypeBuilder.function(types: [u, v], required: [v], result: v);
|
| + DartType bottom =
|
| + TypeBuilder.function(types: [s, t], required: [s], result: t);
|
| + _checkLattice(top, left, right, bottom);
|
| + }
|
| }
|
|
|
| - void test_isAssignableTo_named_optional() {
|
| - DartType r = TypeBuilder.functionType(<DartType>[intType], intType);
|
| - DartType o = TypeBuilder.functionType(<DartType>[], intType,
|
| - optional: <DartType>[intType]);
|
| - DartType n = TypeBuilder.functionType(<DartType>[], intType,
|
| - named: <String, DartType>{'x': intType});
|
| - DartType rr =
|
| - TypeBuilder.functionType(<DartType>[intType, intType], intType);
|
| - DartType ro = TypeBuilder.functionType(<DartType>[intType], intType,
|
| - optional: <DartType>[intType]);
|
| - DartType rn = TypeBuilder.functionType(<DartType>[intType], intType,
|
| - named: <String, DartType>{'x': intType});
|
| - DartType oo = TypeBuilder.functionType(<DartType>[], intType,
|
| - optional: <DartType>[intType, intType]);
|
| - DartType nn = TypeBuilder.functionType(<DartType>[], intType,
|
| - named: <String, DartType>{'x': intType, 'y': intType});
|
| - DartType nnn = TypeBuilder.functionType(<DartType>[], intType,
|
| - named: <String, DartType>{'x': intType, 'y': intType, 'z': intType});
|
| + void test_genericFunction_simple_fBounded() {
|
| + ClassElementImpl AClass = ElementFactory.classElement2('A', ["Q"]);
|
| + InterfaceType AType = AClass.type;
|
| + ClassElementImpl BClass = ElementFactory.classElement2('B', ["R"]);
|
| + BClass.supertype = AType.instantiate([BClass.typeParameters[0].type]);
|
| + InterfaceType BType = BClass.type;
|
| +
|
| + DartType s = TypeBuilder.variable("S");
|
| + (s.element as TypeParameterElementImpl).bound = AType.instantiate([s]);
|
| + DartType t = TypeBuilder.variable("T", bound: s);
|
| + DartType u = TypeBuilder.variable("U");
|
| + (u.element as TypeParameterElementImpl).bound = BType.instantiate([u]);
|
| + DartType v = TypeBuilder.variable("V", bound: u);
|
| +
|
| + _checkIsStrictSubtypeOf(
|
| + TypeBuilder.function(types: [s]), TypeBuilder.function(types: [u]));
|
| +
|
| + _checkIsStrictSubtypeOf(
|
| + TypeBuilder.function(types: [s, t], required: [s], result: t),
|
| + TypeBuilder.function(types: [u, v], required: [u], result: v));
|
| + }
|
| +
|
| + void test_generics() {
|
| + ClassElementImpl LClass = ElementFactory.classElement2('L', ["T"]);
|
| + InterfaceType LType = LClass.type;
|
| + ClassElementImpl MClass = ElementFactory.classElement2('M', ["T"]);
|
| + DartType typeParam = MClass.typeParameters[0].type;
|
| + InterfaceType superType = LType.instantiate(<DartType>[typeParam]);
|
| + MClass.interfaces = <InterfaceType>[superType];
|
| + InterfaceType MType = MClass.type;
|
| +
|
| + InterfaceType top = LType.instantiate(<DartType>[dynamicType]);
|
| + InterfaceType left = MType.instantiate(<DartType>[dynamicType]);
|
| + InterfaceType right = LType.instantiate(<DartType>[intType]);
|
| + InterfaceType bottom = MType.instantiate(<DartType>[intType]);
|
| +
|
| + _checkLattice(top, left, right, bottom);
|
| + }
|
| +
|
| + void test_int() {
|
| + List<DartType> equivalents = <DartType>[intType];
|
| + List<DartType> supertypes = <DartType>[numType];
|
| + List<DartType> unrelated = <DartType>[doubleType];
|
| + _checkGroups(intType,
|
| + equivalents: equivalents, supertypes: supertypes, unrelated: unrelated);
|
| + }
|
| +
|
| + void test_named_optional() {
|
| + DartType r =
|
| + TypeBuilder.function(required: <DartType>[intType], result: intType);
|
| + DartType o = TypeBuilder.function(
|
| + required: <DartType>[], optional: <DartType>[intType], result: intType);
|
| + DartType n = TypeBuilder.function(
|
| + required: <DartType>[],
|
| + named: <String, DartType>{'x': intType},
|
| + result: intType);
|
| + DartType rr = TypeBuilder
|
| + .function(required: <DartType>[intType, intType], result: intType);
|
| + DartType ro = TypeBuilder.function(
|
| + required: <DartType>[intType],
|
| + optional: <DartType>[intType],
|
| + result: intType);
|
| + DartType rn = TypeBuilder.function(
|
| + required: <DartType>[intType],
|
| + named: <String, DartType>{'x': intType},
|
| + result: intType);
|
| + DartType oo = TypeBuilder.function(
|
| + required: <DartType>[],
|
| + optional: <DartType>[intType, intType],
|
| + result: intType);
|
| + DartType nn = TypeBuilder.function(
|
| + required: <DartType>[],
|
| + named: <String, DartType>{'x': intType, 'y': intType},
|
| + result: intType);
|
| + DartType nnn = TypeBuilder.function(
|
| + required: <DartType>[],
|
| + named: <String, DartType>{'x': intType, 'y': intType, 'z': intType},
|
| + result: intType);
|
|
|
| _checkGroups(r,
|
| - interassignable: [r, o, ro, rn, oo], unrelated: [n, rr, nn, nnn]);
|
| + equivalents: [r],
|
| + subtypes: [o, ro, rn, oo],
|
| + unrelated: [n, rr, nn, nnn]);
|
| _checkGroups(o,
|
| - interassignable: [o, oo], unrelated: [n, rr, ro, rn, nn, nnn]);
|
| + equivalents: [o], subtypes: [oo], unrelated: [n, rr, ro, rn, nn, nnn]);
|
| _checkGroups(n,
|
| - interassignable: [n, nn, nnn], unrelated: [r, o, rr, ro, rn, oo]);
|
| + equivalents: [n],
|
| + subtypes: [nn, nnn],
|
| + unrelated: [r, o, rr, ro, rn, oo]);
|
| _checkGroups(rr,
|
| - interassignable: [rr, ro, oo], unrelated: [r, o, n, rn, nn, nnn]);
|
| - _checkGroups(ro, interassignable: [ro, oo], unrelated: [o, n, rn, nn, nnn]);
|
| + equivalents: [rr],
|
| + subtypes: [ro, oo],
|
| + unrelated: [r, o, n, rn, nn, nnn]);
|
| + _checkGroups(ro,
|
| + equivalents: [ro], subtypes: [oo], unrelated: [o, n, rn, nn, nnn]);
|
| _checkGroups(rn,
|
| - interassignable: [rn], unrelated: [o, n, rr, ro, oo, nn, nnn]);
|
| - _checkGroups(oo, interassignable: [oo], unrelated: [n, rn, nn, nnn]);
|
| + equivalents: [rn],
|
| + subtypes: [],
|
| + unrelated: [o, n, rr, ro, oo, nn, nnn]);
|
| + _checkGroups(oo,
|
| + equivalents: [oo], subtypes: [], unrelated: [n, rn, nn, nnn]);
|
| _checkGroups(nn,
|
| - interassignable: [nn, nnn], unrelated: [r, o, rr, ro, rn, oo]);
|
| + equivalents: [nn], subtypes: [nnn], unrelated: [r, o, rr, ro, rn, oo]);
|
| _checkGroups(nnn,
|
| - interassignable: [nnn], unrelated: [r, o, rr, ro, rn, oo]);
|
| + equivalents: [nnn], subtypes: [], unrelated: [r, o, rr, ro, rn, oo]);
|
| }
|
|
|
| - void test_isAssignableTo_generics() {
|
| - ClassElementImpl LClass = ElementFactory.classElement2('L', ["T"]);
|
| - InterfaceType LType = LClass.type;
|
| - ClassElementImpl MClass = ElementFactory.classElement2('M', ["T"]);
|
| - DartType typeParam = MClass.typeParameters[0].type;
|
| - InterfaceType superType = LType.substitute4(<DartType>[typeParam]);
|
| - MClass.interfaces = <InterfaceType>[superType];
|
| - InterfaceType MType = MClass.type;
|
| + void test_num() {
|
| + List<DartType> equivalents = <DartType>[numType];
|
| + List<DartType> supertypes = <DartType>[];
|
| + List<DartType> unrelated = <DartType>[stringType];
|
| + List<DartType> subtypes = <DartType>[intType, doubleType];
|
| + _checkGroups(numType,
|
| + equivalents: equivalents,
|
| + supertypes: supertypes,
|
| + unrelated: unrelated,
|
| + subtypes: subtypes);
|
| + }
|
|
|
| - InterfaceType top = LType.substitute4(<DartType>[dynamicType]);
|
| - InterfaceType left = MType.substitute4(<DartType>[dynamicType]);
|
| - InterfaceType right = LType.substitute4(<DartType>[intType]);
|
| - InterfaceType bottom = MType.substitute4(<DartType>[intType]);
|
| + void test_simple_function() {
|
| + FunctionType top =
|
| + TypeBuilder.function(required: <DartType>[intType], result: objectType);
|
| + FunctionType left =
|
| + TypeBuilder.function(required: <DartType>[intType], result: intType);
|
| + FunctionType right = TypeBuilder
|
| + .function(required: <DartType>[objectType], result: objectType);
|
| + FunctionType bottom =
|
| + TypeBuilder.function(required: <DartType>[objectType], result: intType);
|
|
|
| - _checkCrossLattice(top, left, right, bottom);
|
| + _checkLattice(top, left, right, bottom);
|
| }
|
|
|
| - void _checkCrossLattice(
|
| - DartType top, DartType left, DartType right, DartType bottom) {
|
| - _checkGroups(top, interassignable: <DartType>[top, left, right, bottom]);
|
| - _checkGroups(left, interassignable: <DartType>[top, left, right, bottom]);
|
| - _checkGroups(right, interassignable: <DartType>[top, left, right, bottom]);
|
| - _checkGroups(bottom, interassignable: <DartType>[top, left, right, bottom]);
|
| + /// Regression test for https://github.com/dart-lang/sdk/issues/25069
|
| + void test_simple_function_void() {
|
| + FunctionType functionType =
|
| + TypeBuilder.function(required: <DartType>[intType], result: objectType);
|
| + _checkIsNotSubtypeOf(voidType, functionType);
|
| }
|
|
|
| - void _checkLattice(
|
| - DartType top, DartType left, DartType right, DartType bottom) {
|
| - _checkGroups(top, interassignable: <DartType>[top, left, right, bottom]);
|
| - _checkGroups(left,
|
| - interassignable: <DartType>[top, left, bottom],
|
| - unrelated: <DartType>[right]);
|
| - _checkGroups(right,
|
| - interassignable: <DartType>[top, right, bottom],
|
| - unrelated: <DartType>[left]);
|
| - _checkGroups(bottom, interassignable: <DartType>[top, left, right, bottom]);
|
| + void test_void_functions() {
|
| + FunctionType top =
|
| + TypeBuilder.function(required: <DartType>[intType], result: voidType);
|
| + FunctionType bottom =
|
| + TypeBuilder.function(required: <DartType>[objectType], result: intType);
|
| +
|
| + _checkIsStrictSubtypeOf(bottom, top);
|
| + }
|
| +
|
| + void _checkEquivalent(DartType type1, DartType type2) {
|
| + _checkIsSubtypeOf(type1, type2);
|
| + _checkIsSubtypeOf(type2, type1);
|
| }
|
|
|
| void _checkGroups(DartType t1,
|
| - {List<DartType> interassignable, List<DartType> unrelated}) {
|
| - if (interassignable != null) {
|
| - for (DartType t2 in interassignable) {
|
| + {List<DartType> equivalents,
|
| + List<DartType> unrelated,
|
| + List<DartType> subtypes,
|
| + List<DartType> supertypes}) {
|
| + if (equivalents != null) {
|
| + for (DartType t2 in equivalents) {
|
| _checkEquivalent(t1, t2);
|
| }
|
| }
|
| @@ -901,28 +1826,75 @@ class StrongAssignabilityTest {
|
| _checkUnrelated(t1, t2);
|
| }
|
| }
|
| + if (subtypes != null) {
|
| + for (DartType t2 in subtypes) {
|
| + _checkIsStrictSubtypeOf(t2, t1);
|
| + }
|
| + }
|
| + if (supertypes != null) {
|
| + for (DartType t2 in supertypes) {
|
| + _checkIsStrictSubtypeOf(t1, t2);
|
| + }
|
| + }
|
| }
|
|
|
| - void _checkUnrelated(DartType type1, DartType type2) {
|
| - _checkIsNotAssignableTo(type1, type2);
|
| - _checkIsNotAssignableTo(type2, type1);
|
| + void _checkIsNotSubtypeOf(DartType type1, DartType type2) {
|
| + expect(typeSystem.isSubtypeOf(type1, type2), false);
|
| }
|
|
|
| - void _checkEquivalent(DartType type1, DartType type2) {
|
| - _checkIsAssignableTo(type1, type2);
|
| - _checkIsAssignableTo(type2, type1);
|
| + void _checkIsStrictSubtypeOf(DartType type1, DartType type2) {
|
| + _checkIsSubtypeOf(type1, type2);
|
| + _checkIsNotSubtypeOf(type2, type1);
|
| }
|
|
|
| - void _checkIsStrictAssignableTo(DartType type1, DartType type2) {
|
| - _checkIsAssignableTo(type1, type2);
|
| - _checkIsNotAssignableTo(type2, type1);
|
| + void _checkIsSubtypeOf(DartType type1, DartType type2) {
|
| + expect(typeSystem.isSubtypeOf(type1, type2), true);
|
| }
|
|
|
| - void _checkIsAssignableTo(DartType type1, DartType type2) {
|
| - expect(typeSystem.isAssignableTo(type1, type2), true);
|
| + void _checkLattice(
|
| + DartType top, DartType left, DartType right, DartType bottom) {
|
| + _checkGroups(top,
|
| + equivalents: <DartType>[top],
|
| + subtypes: <DartType>[left, right, bottom]);
|
| + _checkGroups(left,
|
| + equivalents: <DartType>[left],
|
| + subtypes: <DartType>[bottom],
|
| + unrelated: <DartType>[right],
|
| + supertypes: <DartType>[top]);
|
| + _checkGroups(right,
|
| + equivalents: <DartType>[right],
|
| + subtypes: <DartType>[bottom],
|
| + unrelated: <DartType>[left],
|
| + supertypes: <DartType>[top]);
|
| + _checkGroups(bottom,
|
| + equivalents: <DartType>[bottom],
|
| + supertypes: <DartType>[top, left, right]);
|
| }
|
|
|
| - void _checkIsNotAssignableTo(DartType type1, DartType type2) {
|
| - expect(typeSystem.isAssignableTo(type1, type2), false);
|
| + void _checkUnrelated(DartType type1, DartType type2) {
|
| + _checkIsNotSubtypeOf(type1, type2);
|
| + _checkIsNotSubtypeOf(type2, type1);
|
| }
|
| }
|
| +
|
| +class TypeBuilder {
|
| + static FunctionTypeImpl function(
|
| + {List<DartType> types,
|
| + List<DartType> required,
|
| + List<DartType> optional,
|
| + Map<String, DartType> named,
|
| + DartType result}) {
|
| + result = result ?? VoidTypeImpl.instance;
|
| + required = required ?? [];
|
| + FunctionElementImpl f = ElementFactory.functionElement8(required, result,
|
| + optional: optional, named: named);
|
| + if (types != null) {
|
| + f.typeParameters =
|
| + new List<TypeParameterElement>.from(types.map((t) => t.element));
|
| + }
|
| + return f.type = new FunctionTypeImpl(f);
|
| + }
|
| +
|
| + static TypeParameterType variable(String name, {DartType bound}) =>
|
| + ElementFactory.typeParameterWithType(name, bound).type;
|
| +}
|
|
|