| Index: pkg/analyzer/test/generated/type_system_test.dart
|
| diff --git a/pkg/analyzer/test/generated/type_system_test.dart b/pkg/analyzer/test/generated/type_system_test.dart
|
| index 32cb5eaf8871062aca70e706dd4cb03209ef6f1d..f679517c84489850306b525d429790bcfcdacb30 100644
|
| --- a/pkg/analyzer/test/generated/type_system_test.dart
|
| +++ b/pkg/analyzer/test/generated/type_system_test.dart
|
| @@ -30,10 +30,13 @@ main() {
|
| runReflectiveTests(StrongGreatestLowerBoundTest);
|
| }
|
|
|
| -@reflectiveTest
|
| -class StrongAssignabilityTest {
|
| +/**
|
| + * Base class for testing LUB and GLB in spec and strong mode.
|
| + */
|
| +abstract class BoundTestBase {
|
| TypeProvider typeProvider;
|
| TypeSystem typeSystem;
|
| + FunctionType simpleFunctionType;
|
|
|
| DartType get bottomType => typeProvider.bottomType;
|
| InterfaceType get doubleType => typeProvider.doubleType;
|
| @@ -44,495 +47,465 @@ class StrongAssignabilityTest {
|
| 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 StrongTypeSystemImpl();
|
| + InternalAnalysisContext context = AnalysisContextFactory.contextWithCore();
|
| + typeProvider = context.typeProvider;
|
| + FunctionTypeAliasElementImpl typeAlias =
|
| + ElementFactory.functionTypeAliasElement('A');
|
| + typeAlias.parameters = [];
|
| + typeAlias.returnType = voidType;
|
| + simpleFunctionType = typeAlias.type;
|
| }
|
|
|
| - void test_isAssignableTo_bottom_isBottom() {
|
| - DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - List<DartType> interassignable = <DartType>[
|
| - dynamicType,
|
| - objectType,
|
| - intType,
|
| - doubleType,
|
| - numType,
|
| - stringType,
|
| - interfaceType,
|
| - bottomType
|
| - ];
|
| + void _checkGreatestLowerBound(
|
| + DartType type1, DartType type2, DartType expectedResult) {
|
| + expect(strongTypeSystem.getGreatestLowerBound(typeProvider, type1, type2),
|
| + expectedResult);
|
| + }
|
|
|
| - _checkGroups(bottomType, interassignable: interassignable);
|
| + void _checkLeastUpperBound(
|
| + DartType type1, DartType type2, DartType expectedResult) {
|
| + expect(typeSystem.getLeastUpperBound(typeProvider, type1, type2),
|
| + expectedResult);
|
| }
|
|
|
| - void test_isAssignableTo_call_method() {
|
| - ClassElementImpl classBottom = ElementFactory.classElement2("B");
|
| - MethodElement methodBottom =
|
| - ElementFactory.methodElement("call", objectType, <DartType>[intType]);
|
| - classBottom.methods = <MethodElement>[methodBottom];
|
| + /**
|
| + * 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;
|
| + }
|
|
|
| - DartType top =
|
| - TypeBuilder.function(required: <DartType>[intType], result: objectType);
|
| - InterfaceType bottom = classBottom.type;
|
| + return ElementFactory
|
| + .functionElement8(required, returns, optional: optional, named: named)
|
| + .type;
|
| + }
|
| +}
|
|
|
| - _checkIsStrictAssignableTo(bottom, top);
|
| +/**
|
| + * 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_isAssignableTo_classes() {
|
| - ClassElement classTop = ElementFactory.classElement2("A");
|
| - ClassElement classLeft = ElementFactory.classElement("B", classTop.type);
|
| - ClassElement classRight = ElementFactory.classElement("C", classTop.type);
|
| - ClassElement classBottom = ElementFactory.classElement("D", classLeft.type)
|
| - ..interfaces = <InterfaceType>[classRight.type];
|
| - InterfaceType top = classTop.type;
|
| - InterfaceType left = classLeft.type;
|
| - InterfaceType right = classRight.type;
|
| - InterfaceType bottom = classBottom.type;
|
| + 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);
|
| + }
|
|
|
| - _checkLattice(top, left, right, bottom);
|
| + 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_isAssignableTo_double() {
|
| - DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - List<DartType> interassignable = <DartType>[
|
| - dynamicType,
|
| - objectType,
|
| - doubleType,
|
| - numType,
|
| - bottomType
|
| - ];
|
| - List<DartType> unrelated = <DartType>[intType, stringType, interfaceType,];
|
| + 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);
|
| + }
|
|
|
| - _checkGroups(doubleType,
|
| - interassignable: interassignable, unrelated: unrelated);
|
| + 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);
|
| }
|
| +}
|
|
|
| - void test_isAssignableTo_dynamic_isTop() {
|
| +/**
|
| + * 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_bottom_interface() {
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - List<DartType> interassignable = <DartType>[
|
| - dynamicType,
|
| - objectType,
|
| - intType,
|
| - doubleType,
|
| - numType,
|
| - stringType,
|
| - interfaceType,
|
| - bottomType
|
| - ];
|
| - _checkGroups(dynamicType, interassignable: interassignable);
|
| + _checkLeastUpperBound(bottomType, interfaceType, interfaceType);
|
| }
|
|
|
| - 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);
|
| + void test_bottom_typeParam() {
|
| + DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| + _checkLeastUpperBound(bottomType, typeParam, typeParam);
|
| + }
|
|
|
| - _checkCrossLattice(top, left, right, bottom);
|
| + 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");
|
| + InterfaceType typeA = classA.type;
|
| + InterfaceType typeB = classB.type;
|
| + InterfaceType typeC = classC.type;
|
| + classB.interfaces = <InterfaceType>[typeA];
|
| + classC.interfaces = <InterfaceType>[typeB];
|
| + _checkLeastUpperBound(typeB, typeC, typeB);
|
| }
|
|
|
| - 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;
|
| + 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);
|
| + InterfaceType typeB = classB.type;
|
| + InterfaceType typeC = classC.type;
|
| + _checkLeastUpperBound(typeB, typeC, typeB);
|
| + }
|
|
|
| - InterfaceType top = LType.instantiate(<DartType>[dynamicType]);
|
| - InterfaceType left = MType.instantiate(<DartType>[dynamicType]);
|
| - InterfaceType right = LType.instantiate(<DartType>[intType]);
|
| - InterfaceType bottom = MType.instantiate(<DartType>[intType]);
|
| + void test_dynamic_bottom() {
|
| + _checkLeastUpperBound(dynamicType, bottomType, dynamicType);
|
| + }
|
|
|
| - _checkCrossLattice(top, left, right, bottom);
|
| + void test_dynamic_function() {
|
| + _checkLeastUpperBound(dynamicType, simpleFunctionType, dynamicType);
|
| }
|
|
|
| - void test_isAssignableTo_int() {
|
| + void test_dynamic_interface() {
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - List<DartType> interassignable = <DartType>[
|
| - dynamicType,
|
| - objectType,
|
| - intType,
|
| - numType,
|
| - bottomType
|
| - ];
|
| - List<DartType> unrelated = <DartType>[
|
| - doubleType,
|
| - stringType,
|
| - interfaceType,
|
| - ];
|
| + _checkLeastUpperBound(dynamicType, interfaceType, dynamicType);
|
| + }
|
|
|
| - _checkGroups(intType,
|
| - interassignable: interassignable, unrelated: unrelated);
|
| + void test_dynamic_typeParam() {
|
| + DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| + _checkLeastUpperBound(dynamicType, typeParam, dynamicType);
|
| }
|
|
|
| - 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,
|
| - interassignable: [r, o, ro, rn, oo], unrelated: [n, rr, nn, nnn]);
|
| - _checkGroups(o,
|
| - interassignable: [o, oo], unrelated: [n, rr, ro, rn, nn, nnn]);
|
| - _checkGroups(n,
|
| - interassignable: [n, 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]);
|
| - _checkGroups(rn,
|
| - interassignable: [rn], unrelated: [o, n, rr, ro, oo, nn, nnn]);
|
| - _checkGroups(oo, interassignable: [oo], unrelated: [n, rn, nn, nnn]);
|
| - _checkGroups(nn,
|
| - interassignable: [nn, nnn], unrelated: [r, o, rr, ro, rn, oo]);
|
| - _checkGroups(nnn,
|
| - interassignable: [nnn], unrelated: [r, o, rr, ro, rn, oo]);
|
| - }
|
| -
|
| - 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,];
|
| -
|
| - _checkGroups(numType,
|
| - interassignable: interassignable, unrelated: unrelated);
|
| - }
|
| -
|
| - 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 test_dynamic_void() {
|
| + _checkLeastUpperBound(dynamicType, voidType, dynamicType);
|
| }
|
|
|
| - 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 test_functionsDifferentRequiredArity() {
|
| + FunctionType type1 = _functionType([intType, intType]);
|
| + FunctionType type2 = _functionType([intType, intType, intType]);
|
| + _checkLeastUpperBound(type1, type2, functionType);
|
| }
|
|
|
| - 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]);
|
| + 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 _checkEquivalent(DartType type1, DartType type2) {
|
| - _checkIsAssignableTo(type1, type2);
|
| - _checkIsAssignableTo(type2, type1);
|
| + 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 _checkGroups(DartType t1,
|
| - {List<DartType> interassignable, List<DartType> unrelated}) {
|
| - if (interassignable != null) {
|
| - for (DartType t2 in interassignable) {
|
| - _checkEquivalent(t1, t2);
|
| - }
|
| - }
|
| - if (unrelated != null) {
|
| - for (DartType t2 in unrelated) {
|
| - _checkUnrelated(t1, t2);
|
| - }
|
| - }
|
| + void test_functionsLubReturnType() {
|
| + FunctionType type1 = _functionType([], returns: intType);
|
| + FunctionType type2 = _functionType([], returns: doubleType);
|
| + FunctionType expected = _functionType([], returns: numType);
|
| + _checkLeastUpperBound(type1, type2, expected);
|
| }
|
|
|
| - void _checkIsAssignableTo(DartType type1, DartType type2) {
|
| - expect(typeSystem.isAssignableTo(type1, type2), true);
|
| + 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 _checkIsNotAssignableTo(DartType type1, DartType type2) {
|
| - expect(typeSystem.isAssignableTo(type1, type2), false);
|
| + void test_interface_function() {
|
| + DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| + _checkLeastUpperBound(interfaceType, simpleFunctionType, objectType);
|
| }
|
|
|
| - void _checkIsStrictAssignableTo(DartType type1, DartType type2) {
|
| - _checkIsAssignableTo(type1, type2);
|
| - _checkIsNotAssignableTo(type2, type1);
|
| + 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);
|
| + ClassElementImpl classD = ElementFactory.classElement("D", classB.type);
|
| + InterfaceType typeA = classA.type;
|
| + InterfaceType typeC = classC.type;
|
| + InterfaceType typeD = classD.type;
|
| + classD.mixins = <InterfaceType>[
|
| + ElementFactory.classElement2("M").type,
|
| + ElementFactory.classElement2("N").type,
|
| + ElementFactory.classElement2("O").type,
|
| + ElementFactory.classElement2("P").type
|
| + ];
|
| + _checkLeastUpperBound(typeD, typeC, typeA);
|
| }
|
|
|
| - 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_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 _checkUnrelated(DartType type1, DartType type2) {
|
| - _checkIsNotAssignableTo(type1, type2);
|
| - _checkIsNotAssignableTo(type2, type1);
|
| + void test_object() {
|
| + ClassElementImpl classA = ElementFactory.classElement2("A");
|
| + ClassElementImpl classB = ElementFactory.classElement2("B");
|
| + InterfaceType typeA = classA.type;
|
| + InterfaceType typeB = classB.type;
|
| + DartType typeObject = typeA.element.supertype;
|
| + // assert that object does not have a super type
|
| + expect((typeObject.element as ClassElement).supertype, isNull);
|
| + // assert that both A and B have the same super type of Object
|
| + expect(typeB.element.supertype, typeObject);
|
| + // finally, assert that the only least upper bound of A and B is Object
|
| + _checkLeastUpperBound(typeA, typeB, typeObject);
|
| }
|
| -}
|
|
|
| -@reflectiveTest
|
| -class StrongGenericFunctionInferenceTest {
|
| - TypeProvider typeProvider;
|
| - StrongTypeSystemImpl typeSystem;
|
| + void test_self() {
|
| + DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| + DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
|
|
| - 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;
|
| - InterfaceType get stringType => typeProvider.stringType;
|
| - DartType get voidType => VoidTypeImpl.instance;
|
| + List<DartType> types = [
|
| + dynamicType,
|
| + voidType,
|
| + bottomType,
|
| + typeParam,
|
| + interfaceType,
|
| + simpleFunctionType
|
| + ];
|
|
|
| - void setUp() {
|
| - typeProvider = new TestTypeProvider();
|
| - typeSystem = new StrongTypeSystemImpl();
|
| + for (DartType type in types) {
|
| + _checkLeastUpperBound(type, type, type);
|
| + }
|
| }
|
|
|
| - 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,
|
| - iterableType.instantiate([stringType])
|
| - ]);
|
| + void test_sharedSuperclass1() {
|
| + ClassElementImpl classA = ElementFactory.classElement2("A");
|
| + ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
|
| + ClassElementImpl classC = ElementFactory.classElement("C", classA.type);
|
| + InterfaceType typeA = classA.type;
|
| + InterfaceType typeB = classB.type;
|
| + InterfaceType typeC = classC.type;
|
| + _checkLeastUpperBound(typeB, typeC, typeA);
|
| }
|
|
|
| - 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]);
|
| + void test_sharedSuperclass2() {
|
| + ClassElementImpl classA = ElementFactory.classElement2("A");
|
| + ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
|
| + ClassElementImpl classC = ElementFactory.classElement("C", classA.type);
|
| + ClassElementImpl classD = ElementFactory.classElement("D", classC.type);
|
| + InterfaceType typeA = classA.type;
|
| + InterfaceType typeB = classB.type;
|
| + InterfaceType typeD = classD.type;
|
| + _checkLeastUpperBound(typeB, typeD, typeA);
|
| + }
|
|
|
| - // <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]);
|
| + void test_sharedSuperclass3() {
|
| + ClassElementImpl classA = ElementFactory.classElement2("A");
|
| + ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
|
| + ClassElementImpl classC = ElementFactory.classElement("C", classB.type);
|
| + ClassElementImpl classD = ElementFactory.classElement("D", classB.type);
|
| + InterfaceType typeB = classB.type;
|
| + InterfaceType typeC = classC.type;
|
| + InterfaceType typeD = classD.type;
|
| + _checkLeastUpperBound(typeC, typeD, typeB);
|
| + }
|
|
|
| - // Something invalid...
|
| - expect(_inferCall(clone, [stringType, numType]), [
|
| - clonable.type.instantiate([dynamicType])
|
| - ]);
|
| + void test_sharedSuperclass4() {
|
| + ClassElement classA = ElementFactory.classElement2("A");
|
| + ClassElement classA2 = ElementFactory.classElement2("A2");
|
| + ClassElement classA3 = ElementFactory.classElement2("A3");
|
| + ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
|
| + ClassElementImpl classC = ElementFactory.classElement("C", classA.type);
|
| + InterfaceType typeA = classA.type;
|
| + InterfaceType typeA2 = classA2.type;
|
| + InterfaceType typeA3 = classA3.type;
|
| + InterfaceType typeB = classB.type;
|
| + InterfaceType typeC = classC.type;
|
| + classB.interfaces = <InterfaceType>[typeA2];
|
| + classC.interfaces = <InterfaceType>[typeA3];
|
| + _checkLeastUpperBound(typeB, typeC, typeA);
|
| }
|
|
|
| - 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_sharedSuperinterface1() {
|
| + ClassElementImpl classA = ElementFactory.classElement2("A");
|
| + ClassElementImpl classB = ElementFactory.classElement2("B");
|
| + ClassElementImpl classC = ElementFactory.classElement2("C");
|
| + InterfaceType typeA = classA.type;
|
| + InterfaceType typeB = classB.type;
|
| + InterfaceType typeC = classC.type;
|
| + classB.interfaces = <InterfaceType>[typeA];
|
| + classC.interfaces = <InterfaceType>[typeA];
|
| + _checkLeastUpperBound(typeB, typeC, typeA);
|
| }
|
|
|
| - 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_sharedSuperinterface2() {
|
| + ClassElementImpl classA = ElementFactory.classElement2("A");
|
| + ClassElementImpl classB = ElementFactory.classElement2("B");
|
| + ClassElementImpl classC = ElementFactory.classElement2("C");
|
| + ClassElementImpl classD = ElementFactory.classElement2("D");
|
| + InterfaceType typeA = classA.type;
|
| + InterfaceType typeB = classB.type;
|
| + InterfaceType typeC = classC.type;
|
| + InterfaceType typeD = classD.type;
|
| + classB.interfaces = <InterfaceType>[typeA];
|
| + classC.interfaces = <InterfaceType>[typeA];
|
| + classD.interfaces = <InterfaceType>[typeC];
|
| + _checkLeastUpperBound(typeB, typeD, typeA);
|
| }
|
|
|
| - 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_sharedSuperinterface3() {
|
| + ClassElementImpl classA = ElementFactory.classElement2("A");
|
| + ClassElementImpl classB = ElementFactory.classElement2("B");
|
| + ClassElementImpl classC = ElementFactory.classElement2("C");
|
| + ClassElementImpl classD = ElementFactory.classElement2("D");
|
| + InterfaceType typeA = classA.type;
|
| + InterfaceType typeB = classB.type;
|
| + InterfaceType typeC = classC.type;
|
| + InterfaceType typeD = classD.type;
|
| + classB.interfaces = <InterfaceType>[typeA];
|
| + classC.interfaces = <InterfaceType>[typeB];
|
| + classD.interfaces = <InterfaceType>[typeB];
|
| + _checkLeastUpperBound(typeC, typeD, typeB);
|
| }
|
|
|
| - 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_sharedSuperinterface4() {
|
| + ClassElement classA = ElementFactory.classElement2("A");
|
| + ClassElement classA2 = ElementFactory.classElement2("A2");
|
| + ClassElement classA3 = ElementFactory.classElement2("A3");
|
| + ClassElementImpl classB = ElementFactory.classElement2("B");
|
| + ClassElementImpl classC = ElementFactory.classElement2("C");
|
| + InterfaceType typeA = classA.type;
|
| + InterfaceType typeA2 = classA2.type;
|
| + InterfaceType typeA3 = classA3.type;
|
| + InterfaceType typeB = classB.type;
|
| + InterfaceType typeC = classC.type;
|
| + classB.interfaces = <InterfaceType>[typeA, typeA2];
|
| + classC.interfaces = <InterfaceType>[typeA, typeA3];
|
| + _checkLeastUpperBound(typeB, typeC, typeA);
|
| }
|
|
|
| - 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_twoComparables() {
|
| + _checkLeastUpperBound(stringType, numType, objectType);
|
| }
|
|
|
| - 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_typeParam_function_bounded() {
|
| + DartType typeA = ElementFactory.classElement('A', functionType).type;
|
| + TypeParameterElementImpl typeParamElement =
|
| + ElementFactory.typeParameterElement('T');
|
| + typeParamElement.bound = typeA;
|
| + DartType typeParam = typeParamElement.type;
|
| + _checkLeastUpperBound(typeParam, simpleFunctionType, functionType);
|
| }
|
|
|
| - 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_typeParam_function_noBound() {
|
| + DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| + _checkLeastUpperBound(typeParam, simpleFunctionType, objectType);
|
| }
|
|
|
| - 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_typeParam_interface_bounded() {
|
| + DartType typeA = ElementFactory.classElement2('A', []).type;
|
| + DartType typeB = ElementFactory.classElement('B', typeA).type;
|
| + DartType typeC = ElementFactory.classElement('C', typeA).type;
|
| + TypeParameterElementImpl typeParamElement =
|
| + ElementFactory.typeParameterElement('T');
|
| + typeParamElement.bound = typeB;
|
| + DartType typeParam = typeParamElement.type;
|
| + _checkLeastUpperBound(typeParam, typeC, typeA);
|
| }
|
|
|
| - 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_typeParam_interface_noBound() {
|
| + DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| + DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| + _checkLeastUpperBound(typeParam, interfaceType, objectType);
|
| }
|
|
|
| - 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_typeParameters_different() {
|
| + // class List<int>
|
| + // class List<double>
|
| + InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
|
| + InterfaceType listOfDoubleType =
|
| + listType.instantiate(<DartType>[doubleType]);
|
| + _checkLeastUpperBound(listOfIntType, listOfDoubleType, objectType);
|
| }
|
|
|
| - 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), [numType]);
|
| + void test_typeParameters_same() {
|
| + // List<int>
|
| + // List<int>
|
| + InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
|
| + _checkLeastUpperBound(listOfIntType, listOfIntType, listOfIntType);
|
| }
|
|
|
| - 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)
|
| - ]),
|
| - [dynamicType]);
|
| + void test_void_bottom() {
|
| + _checkLeastUpperBound(voidType, bottomType, voidType);
|
| }
|
|
|
| - 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_void_function() {
|
| + _checkLeastUpperBound(voidType, simpleFunctionType, voidType);
|
| }
|
|
|
| - 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]);
|
| + void test_void_interface() {
|
| + DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| + _checkLeastUpperBound(voidType, interfaceType, voidType);
|
| }
|
|
|
| - List<DartType> _inferCall(FunctionTypeImpl ft, List<DartType> arguments,
|
| - [DartType returnType]) {
|
| - FunctionType inferred = typeSystem.inferGenericFunctionCall(typeProvider,
|
| - ft, ft.parameters.map((p) => p.type).toList(), arguments, returnType);
|
| - return inferred.typeArguments;
|
| + void test_void_typeParam() {
|
| + DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| + _checkLeastUpperBound(voidType, typeParam, voidType);
|
| }
|
| }
|
|
|
| @reflectiveTest
|
| -class StrongSubtypingTest {
|
| +class StrongAssignabilityTest {
|
| TypeProvider typeProvider;
|
| TypeSystem typeSystem;
|
|
|
| @@ -552,24 +525,24 @@ class StrongSubtypingTest {
|
| typeSystem = new StrongTypeSystemImpl();
|
| }
|
|
|
| - void test_bottom_isBottom() {
|
| + void test_isAssignableTo_bottom_isBottom() {
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - List<DartType> equivalents = <DartType>[bottomType];
|
| - List<DartType> supertypes = <DartType>[
|
| + List<DartType> interassignable = <DartType>[
|
| dynamicType,
|
| objectType,
|
| intType,
|
| doubleType,
|
| numType,
|
| stringType,
|
| - functionType,
|
| - interfaceType
|
| + interfaceType,
|
| + bottomType
|
| ];
|
| - _checkGroups(bottomType, equivalents: equivalents, supertypes: supertypes);
|
| +
|
| + _checkGroups(bottomType, interassignable: interassignable);
|
| }
|
|
|
| - void test_call_method() {
|
| - ClassElementImpl classBottom = ElementFactory.classElement2("Bottom");
|
| + void test_isAssignableTo_call_method() {
|
| + ClassElementImpl classBottom = ElementFactory.classElement2("B");
|
| MethodElement methodBottom =
|
| ElementFactory.methodElement("call", objectType, <DartType>[intType]);
|
| classBottom.methods = <MethodElement>[methodBottom];
|
| @@ -578,10 +551,10 @@ class StrongSubtypingTest {
|
| TypeBuilder.function(required: <DartType>[intType], result: objectType);
|
| InterfaceType bottom = classBottom.type;
|
|
|
| - _checkIsStrictSubtypeOf(bottom, top);
|
| + _checkIsStrictAssignableTo(bottom, top);
|
| }
|
|
|
| - void test_classes() {
|
| + void test_isAssignableTo_classes() {
|
| ClassElement classTop = ElementFactory.classElement2("A");
|
| ClassElement classLeft = ElementFactory.classElement("B", classTop.type);
|
| ClassElement classRight = ElementFactory.classElement("C", classTop.type);
|
| @@ -595,30 +568,37 @@ class StrongSubtypingTest {
|
| _checkLattice(top, left, right, bottom);
|
| }
|
|
|
| - void test_double() {
|
| - List<DartType> equivalents = <DartType>[doubleType];
|
| - List<DartType> supertypes = <DartType>[numType];
|
| - List<DartType> unrelated = <DartType>[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,];
|
| +
|
| _checkGroups(doubleType,
|
| - equivalents: equivalents, supertypes: supertypes, unrelated: unrelated);
|
| + interassignable: interassignable, unrelated: unrelated);
|
| }
|
|
|
| - void test_dynamic_isTop() {
|
| + void test_isAssignableTo_dynamic_isTop() {
|
| 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);
|
| + _checkGroups(dynamicType, interassignable: interassignable);
|
| }
|
|
|
| - void test_fuzzy_arrows() {
|
| + void test_isAssignableTo_fuzzy_arrows() {
|
| FunctionType top = TypeBuilder
|
| .function(required: <DartType>[dynamicType], result: objectType);
|
| FunctionType left = TypeBuilder
|
| @@ -628,88 +608,10 @@ class StrongSubtypingTest {
|
| FunctionType bottom = TypeBuilder
|
| .function(required: <DartType>[objectType], result: bottomType);
|
|
|
| - _checkLattice(top, left, right, bottom);
|
| - }
|
| -
|
| - 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_genericFunction_simple() {
|
| - DartType s = TypeBuilder.variable("S");
|
| - DartType t = TypeBuilder.variable("T");
|
| -
|
| - _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_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(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_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));
|
| + _checkCrossLattice(top, left, right, bottom);
|
| }
|
|
|
| - void test_generics() {
|
| + void test_isAssignableTo_generics() {
|
| ClassElementImpl LClass = ElementFactory.classElement2('L', ["T"]);
|
| InterfaceType LType = LClass.type;
|
| ClassElementImpl MClass = ElementFactory.classElement2('M', ["T"]);
|
| @@ -723,18 +625,29 @@ class StrongSubtypingTest {
|
| InterfaceType right = LType.instantiate(<DartType>[intType]);
|
| InterfaceType bottom = MType.instantiate(<DartType>[intType]);
|
|
|
| - _checkLattice(top, left, right, bottom);
|
| + _checkCrossLattice(top, left, right, bottom);
|
| }
|
|
|
| - void test_int() {
|
| - List<DartType> equivalents = <DartType>[intType];
|
| - List<DartType> supertypes = <DartType>[numType];
|
| - List<DartType> unrelated = <DartType>[doubleType];
|
| + 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,
|
| + ];
|
| +
|
| _checkGroups(intType,
|
| - equivalents: equivalents, supertypes: supertypes, unrelated: unrelated);
|
| + interassignable: interassignable, unrelated: unrelated);
|
| }
|
|
|
| - void test_named_optional() {
|
| + void test_isAssignableTo_named_optional() {
|
| DartType r =
|
| TypeBuilder.function(required: <DartType>[intType], result: intType);
|
| DartType o = TypeBuilder.function(
|
| @@ -767,46 +680,40 @@ class StrongSubtypingTest {
|
| 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_num() {
|
| - List<DartType> equivalents = <DartType>[numType];
|
| - List<DartType> supertypes = <DartType>[];
|
| - List<DartType> unrelated = <DartType>[stringType];
|
| - List<DartType> subtypes = <DartType>[intType, doubleType];
|
| + 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,];
|
| +
|
| _checkGroups(numType,
|
| - equivalents: equivalents,
|
| - supertypes: supertypes,
|
| - unrelated: unrelated,
|
| - subtypes: subtypes);
|
| + interassignable: interassignable, unrelated: unrelated);
|
| }
|
|
|
| - void test_simple_function() {
|
| + void test_isAssignableTo_simple_function() {
|
| FunctionType top =
|
| TypeBuilder.function(required: <DartType>[intType], result: objectType);
|
| FunctionType left =
|
| @@ -816,37 +723,35 @@ class StrongSubtypingTest {
|
| FunctionType bottom =
|
| TypeBuilder.function(required: <DartType>[objectType], result: intType);
|
|
|
| - _checkLattice(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);
|
| + _checkCrossLattice(top, left, right, bottom);
|
| }
|
|
|
| - void test_void_functions() {
|
| + void test_isAssignableTo_void_functions() {
|
| FunctionType top =
|
| TypeBuilder.function(required: <DartType>[intType], result: voidType);
|
| FunctionType bottom =
|
| TypeBuilder.function(required: <DartType>[objectType], result: intType);
|
|
|
| - _checkIsStrictSubtypeOf(bottom, top);
|
| + _checkEquivalent(bottom, top);
|
| + }
|
| +
|
| + 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]);
|
| }
|
|
|
| void _checkEquivalent(DartType type1, DartType type2) {
|
| - _checkIsSubtypeOf(type1, type2);
|
| - _checkIsSubtypeOf(type2, type1);
|
| + _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);
|
| }
|
| }
|
| @@ -855,571 +760,526 @@ 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 _checkIsNotSubtypeOf(DartType type1, DartType type2) {
|
| - expect(typeSystem.isSubtypeOf(type1, type2), false);
|
| + void _checkIsAssignableTo(DartType type1, DartType type2) {
|
| + expect(typeSystem.isAssignableTo(type1, type2), true);
|
| }
|
|
|
| - void _checkIsStrictSubtypeOf(DartType type1, DartType type2) {
|
| - _checkIsSubtypeOf(type1, type2);
|
| - _checkIsNotSubtypeOf(type2, type1);
|
| + void _checkIsNotAssignableTo(DartType type1, DartType type2) {
|
| + expect(typeSystem.isAssignableTo(type1, type2), false);
|
| }
|
|
|
| - void _checkIsSubtypeOf(DartType type1, DartType type2) {
|
| - expect(typeSystem.isSubtypeOf(type1, type2), true);
|
| + void _checkIsStrictAssignableTo(DartType type1, DartType type2) {
|
| + _checkIsAssignableTo(type1, type2);
|
| + _checkIsNotAssignableTo(type2, type1);
|
| }
|
|
|
| void _checkLattice(
|
| DartType top, DartType left, DartType right, DartType bottom) {
|
| - _checkGroups(top,
|
| - equivalents: <DartType>[top],
|
| - subtypes: <DartType>[left, right, bottom]);
|
| + _checkGroups(top, interassignable: <DartType>[top, left, right, bottom]);
|
| _checkGroups(left,
|
| - equivalents: <DartType>[left],
|
| - subtypes: <DartType>[bottom],
|
| - unrelated: <DartType>[right],
|
| - supertypes: <DartType>[top]);
|
| + interassignable: <DartType>[top, left, bottom],
|
| + unrelated: <DartType>[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: <DartType>[top, right, bottom],
|
| + unrelated: <DartType>[left]);
|
| + _checkGroups(bottom, interassignable: <DartType>[top, left, right, bottom]);
|
| }
|
|
|
| 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);
|
| + _checkIsNotAssignableTo(type1, type2);
|
| + _checkIsNotAssignableTo(type2, type1);
|
| }
|
| -
|
| - static TypeParameterType variable(String name, {DartType bound}) =>
|
| - ElementFactory.typeParameterWithType(name, bound).type;
|
| }
|
|
|
| -/**
|
| - * Base class for testing LUB and GLB in spec and strong mode.
|
| - */
|
| -abstract class BoundTestBase {
|
| +@reflectiveTest
|
| +class StrongGenericFunctionInferenceTest {
|
| TypeProvider typeProvider;
|
| - TypeSystem typeSystem;
|
| - FunctionType simpleFunctionType;
|
| + 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;
|
| InterfaceType get stringType => typeProvider.stringType;
|
| DartType get voidType => VoidTypeImpl.instance;
|
|
|
| - StrongTypeSystemImpl get strongTypeSystem =>
|
| - typeSystem as StrongTypeSystemImpl;
|
| -
|
| void setUp() {
|
| - InternalAnalysisContext context = AnalysisContextFactory.contextWithCore();
|
| - typeProvider = context.typeProvider;
|
| - FunctionTypeAliasElementImpl typeAlias =
|
| - ElementFactory.functionTypeAliasElement('A');
|
| - typeAlias.parameters = [];
|
| - typeAlias.returnType = voidType;
|
| - simpleFunctionType = typeAlias.type;
|
| + typeProvider = new TestTypeProvider();
|
| + typeSystem = new StrongTypeSystemImpl();
|
| }
|
|
|
| - /**
|
| - * 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;
|
| - }
|
| + 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,
|
| + iterableType.instantiate([stringType])
|
| + ]);
|
| + }
|
| +
|
| + 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]), [
|
| + clonable.type.instantiate([dynamicType])
|
| + ]);
|
| + }
|
| +
|
| + 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), [numType]);
|
| + }
|
| +
|
| + 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)
|
| + ]),
|
| + [dynamicType]);
|
| + }
|
|
|
| - return ElementFactory
|
| - .functionElement8(required, returns, optional: optional, named: named)
|
| - .type;
|
| + void test_unusedReturnTypeIsDynamic() {
|
| + // <T>() -> T
|
| + var t = TypeBuilder.variable('T');
|
| + var f = TypeBuilder.function(types: [t], required: [], result: t);
|
| + expect(_inferCall(f, []), [dynamicType]);
|
| }
|
|
|
| - void _checkLeastUpperBound(
|
| - DartType type1, DartType type2, DartType expectedResult) {
|
| - expect(typeSystem.getLeastUpperBound(typeProvider, type1, type2),
|
| - expectedResult);
|
| + 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]);
|
| }
|
|
|
| - void _checkGreatestLowerBound(
|
| - DartType type1, DartType type2, DartType expectedResult) {
|
| - expect(strongTypeSystem.getGreatestLowerBound(typeProvider, type1, type2),
|
| - expectedResult);
|
| + List<DartType> _inferCall(FunctionTypeImpl ft, List<DartType> arguments,
|
| + [DartType returnType]) {
|
| + FunctionType inferred = typeSystem.inferGenericFunctionCall(typeProvider,
|
| + ft, ft.parameters.map((p) => p.type).toList(), arguments, returnType);
|
| + return inferred.typeArguments;
|
| }
|
| }
|
|
|
| /**
|
| - * 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.
|
| + * Tests GLB, which only exists in strong mode.
|
| */
|
| -abstract class LeastUpperBoundTestBase extends BoundTestBase {
|
| +@reflectiveTest
|
| +class StrongGreatestLowerBoundTest extends BoundTestBase {
|
| + void setUp() {
|
| + typeSystem = new StrongTypeSystemImpl();
|
| + super.setUp();
|
| + }
|
| +
|
| void test_bottom_function() {
|
| - _checkLeastUpperBound(bottomType, simpleFunctionType, simpleFunctionType);
|
| + _checkGreatestLowerBound(bottomType, simpleFunctionType, bottomType);
|
| }
|
|
|
| void test_bottom_interface() {
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - _checkLeastUpperBound(bottomType, interfaceType, interfaceType);
|
| + _checkGreatestLowerBound(bottomType, interfaceType, bottomType);
|
| }
|
|
|
| void test_bottom_typeParam() {
|
| DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| - _checkLeastUpperBound(bottomType, typeParam, typeParam);
|
| - }
|
| -
|
| - 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");
|
| - InterfaceType typeA = classA.type;
|
| - InterfaceType typeB = classB.type;
|
| - InterfaceType typeC = classC.type;
|
| - classB.interfaces = <InterfaceType>[typeA];
|
| - classC.interfaces = <InterfaceType>[typeB];
|
| - _checkLeastUpperBound(typeB, typeC, typeB);
|
| + _checkGreatestLowerBound(bottomType, typeParam, bottomType);
|
| }
|
|
|
| - void test_directSubclassCase() {
|
| + 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);
|
| - InterfaceType typeB = classB.type;
|
| - InterfaceType typeC = classC.type;
|
| - _checkLeastUpperBound(typeB, typeC, typeB);
|
| + _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() {
|
| - _checkLeastUpperBound(dynamicType, bottomType, dynamicType);
|
| + _checkGreatestLowerBound(dynamicType, bottomType, bottomType);
|
| }
|
|
|
| void test_dynamic_function() {
|
| - _checkLeastUpperBound(dynamicType, simpleFunctionType, dynamicType);
|
| + _checkGreatestLowerBound(
|
| + dynamicType, simpleFunctionType, simpleFunctionType);
|
| }
|
|
|
| void test_dynamic_interface() {
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - _checkLeastUpperBound(dynamicType, interfaceType, dynamicType);
|
| + _checkGreatestLowerBound(dynamicType, interfaceType, interfaceType);
|
| }
|
|
|
| void test_dynamic_typeParam() {
|
| DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| - _checkLeastUpperBound(dynamicType, typeParam, dynamicType);
|
| + _checkGreatestLowerBound(dynamicType, typeParam, typeParam);
|
| }
|
|
|
| void test_dynamic_void() {
|
| - _checkLeastUpperBound(dynamicType, voidType, dynamicType);
|
| - }
|
| -
|
| - void test_interface_function() {
|
| - DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - _checkLeastUpperBound(interfaceType, simpleFunctionType, objectType);
|
| + _checkGreatestLowerBound(dynamicType, voidType, voidType);
|
| }
|
|
|
| - 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);
|
| - ClassElementImpl classD = ElementFactory.classElement("D", classB.type);
|
| - InterfaceType typeA = classA.type;
|
| - InterfaceType typeC = classC.type;
|
| - InterfaceType typeD = classD.type;
|
| - classD.mixins = <InterfaceType>[
|
| - ElementFactory.classElement2("M").type,
|
| - ElementFactory.classElement2("N").type,
|
| - ElementFactory.classElement2("O").type,
|
| - ElementFactory.classElement2("P").type
|
| - ];
|
| - _checkLeastUpperBound(typeD, typeC, typeA);
|
| + 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_object() {
|
| - ClassElementImpl classA = ElementFactory.classElement2("A");
|
| - ClassElementImpl classB = ElementFactory.classElement2("B");
|
| - InterfaceType typeA = classA.type;
|
| - InterfaceType typeB = classB.type;
|
| - DartType typeObject = typeA.element.supertype;
|
| - // assert that object does not have a super type
|
| - expect((typeObject.element as ClassElement).supertype, isNull);
|
| - // assert that both A and B have the same super type of Object
|
| - expect(typeB.element.supertype, typeObject);
|
| - // finally, assert that the only least upper bound of A and B is Object
|
| - _checkLeastUpperBound(typeA, typeB, typeObject);
|
| + 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_self() {
|
| - DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| - DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| -
|
| - List<DartType> types = [
|
| - dynamicType,
|
| - voidType,
|
| - bottomType,
|
| - typeParam,
|
| - interfaceType,
|
| - simpleFunctionType
|
| - ];
|
| -
|
| - for (DartType type in types) {
|
| - _checkLeastUpperBound(type, type, type);
|
| - }
|
| + 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_sharedSuperclass1() {
|
| - ClassElementImpl classA = ElementFactory.classElement2("A");
|
| - ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
|
| - ClassElementImpl classC = ElementFactory.classElement("C", classA.type);
|
| - InterfaceType typeA = classA.type;
|
| - InterfaceType typeB = classB.type;
|
| - InterfaceType typeC = classC.type;
|
| - _checkLeastUpperBound(typeB, typeC, typeA);
|
| + void test_functionsGlbReturnType() {
|
| + FunctionType type1 = _functionType([], returns: intType);
|
| + FunctionType type2 = _functionType([], returns: numType);
|
| + FunctionType expected = _functionType([], returns: intType);
|
| + _checkGreatestLowerBound(type1, type2, expected);
|
| }
|
|
|
| - void test_sharedSuperclass2() {
|
| - ClassElementImpl classA = ElementFactory.classElement2("A");
|
| - ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
|
| - ClassElementImpl classC = ElementFactory.classElement("C", classA.type);
|
| - ClassElementImpl classD = ElementFactory.classElement("D", classC.type);
|
| - InterfaceType typeA = classA.type;
|
| - InterfaceType typeB = classB.type;
|
| - InterfaceType typeD = classD.type;
|
| - _checkLeastUpperBound(typeB, typeD, typeA);
|
| + 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_sharedSuperclass3() {
|
| - ClassElementImpl classA = ElementFactory.classElement2("A");
|
| - ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
|
| - ClassElementImpl classC = ElementFactory.classElement("C", classB.type);
|
| - ClassElementImpl classD = ElementFactory.classElement("D", classB.type);
|
| - InterfaceType typeB = classB.type;
|
| - InterfaceType typeC = classC.type;
|
| - InterfaceType typeD = classD.type;
|
| - _checkLeastUpperBound(typeC, typeD, typeB);
|
| + 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_sharedSuperclass4() {
|
| - ClassElement classA = ElementFactory.classElement2("A");
|
| - ClassElement classA2 = ElementFactory.classElement2("A2");
|
| - ClassElement classA3 = ElementFactory.classElement2("A3");
|
| - ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
|
| - ClassElementImpl classC = ElementFactory.classElement("C", classA.type);
|
| - InterfaceType typeA = classA.type;
|
| - InterfaceType typeA2 = classA2.type;
|
| - InterfaceType typeA3 = classA3.type;
|
| - InterfaceType typeB = classB.type;
|
| - InterfaceType typeC = classC.type;
|
| - classB.interfaces = <InterfaceType>[typeA2];
|
| - classC.interfaces = <InterfaceType>[typeA3];
|
| - _checkLeastUpperBound(typeB, typeC, typeA);
|
| + 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_sharedSuperinterface1() {
|
| - ClassElementImpl classA = ElementFactory.classElement2("A");
|
| - ClassElementImpl classB = ElementFactory.classElement2("B");
|
| - ClassElementImpl classC = ElementFactory.classElement2("C");
|
| - InterfaceType typeA = classA.type;
|
| - InterfaceType typeB = classB.type;
|
| - InterfaceType typeC = classC.type;
|
| - classB.interfaces = <InterfaceType>[typeA];
|
| - classC.interfaces = <InterfaceType>[typeA];
|
| - _checkLeastUpperBound(typeB, typeC, typeA);
|
| + 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_sharedSuperinterface2() {
|
| - ClassElementImpl classA = ElementFactory.classElement2("A");
|
| - ClassElementImpl classB = ElementFactory.classElement2("B");
|
| - ClassElementImpl classC = ElementFactory.classElement2("C");
|
| - ClassElementImpl classD = ElementFactory.classElement2("D");
|
| - InterfaceType typeA = classA.type;
|
| - InterfaceType typeB = classB.type;
|
| - InterfaceType typeC = classC.type;
|
| - InterfaceType typeD = classD.type;
|
| - classB.interfaces = <InterfaceType>[typeA];
|
| - classC.interfaces = <InterfaceType>[typeA];
|
| - classD.interfaces = <InterfaceType>[typeC];
|
| - _checkLeastUpperBound(typeB, typeD, typeA);
|
| + 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_sharedSuperinterface3() {
|
| - ClassElementImpl classA = ElementFactory.classElement2("A");
|
| - ClassElementImpl classB = ElementFactory.classElement2("B");
|
| - ClassElementImpl classC = ElementFactory.classElement2("C");
|
| - ClassElementImpl classD = ElementFactory.classElement2("D");
|
| - InterfaceType typeA = classA.type;
|
| - InterfaceType typeB = classB.type;
|
| - InterfaceType typeC = classC.type;
|
| - InterfaceType typeD = classD.type;
|
| - classB.interfaces = <InterfaceType>[typeA];
|
| - classC.interfaces = <InterfaceType>[typeB];
|
| - classD.interfaces = <InterfaceType>[typeB];
|
| - _checkLeastUpperBound(typeC, typeD, typeB);
|
| + 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_sharedSuperinterface4() {
|
| - ClassElement classA = ElementFactory.classElement2("A");
|
| - ClassElement classA2 = ElementFactory.classElement2("A2");
|
| - ClassElement classA3 = ElementFactory.classElement2("A3");
|
| - ClassElementImpl classB = ElementFactory.classElement2("B");
|
| - ClassElementImpl classC = ElementFactory.classElement2("C");
|
| - InterfaceType typeA = classA.type;
|
| - InterfaceType typeA2 = classA2.type;
|
| - InterfaceType typeA3 = classA3.type;
|
| - InterfaceType typeB = classB.type;
|
| - InterfaceType typeC = classC.type;
|
| - classB.interfaces = <InterfaceType>[typeA, typeA2];
|
| - classC.interfaces = <InterfaceType>[typeA, typeA3];
|
| - _checkLeastUpperBound(typeB, typeC, typeA);
|
| + void test_interface_function() {
|
| + DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| + _checkGreatestLowerBound(interfaceType, simpleFunctionType, bottomType);
|
| }
|
|
|
| - void test_twoComparables() {
|
| - _checkLeastUpperBound(stringType, numType, objectType);
|
| + 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_typeParam_function_bounded() {
|
| - DartType typeA = ElementFactory.classElement('A', functionType).type;
|
| - TypeParameterElementImpl typeParamElement =
|
| - ElementFactory.typeParameterElement('T');
|
| - typeParamElement.bound = typeA;
|
| - DartType typeParam = typeParamElement.type;
|
| - _checkLeastUpperBound(typeParam, simpleFunctionType, functionType);
|
| + void test_self() {
|
| + DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| + DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| +
|
| + List<DartType> types = [
|
| + dynamicType,
|
| + voidType,
|
| + bottomType,
|
| + typeParam,
|
| + interfaceType,
|
| + simpleFunctionType
|
| + ];
|
| +
|
| + for (DartType type in types) {
|
| + _checkGreatestLowerBound(type, type, type);
|
| + }
|
| }
|
|
|
| void test_typeParam_function_noBound() {
|
| DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| - _checkLeastUpperBound(typeParam, simpleFunctionType, objectType);
|
| + _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', typeA).type;
|
| - TypeParameterElementImpl typeParamElement =
|
| + DartType typeC = ElementFactory.classElement('C', typeB).type;
|
| + TypeParameterElementImpl typeParam =
|
| ElementFactory.typeParameterElement('T');
|
| - typeParamElement.bound = typeB;
|
| - DartType typeParam = typeParamElement.type;
|
| - _checkLeastUpperBound(typeParam, typeC, typeA);
|
| + 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;
|
| - _checkLeastUpperBound(typeParam, interfaceType, objectType);
|
| + _checkGreatestLowerBound(typeParam, interfaceType, bottomType);
|
| }
|
|
|
| void test_typeParameters_different() {
|
| - // class List<int>
|
| - // class List<double>
|
| + // GLB(List<int>, List<double>) = ⊥
|
| InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
|
| InterfaceType listOfDoubleType =
|
| listType.instantiate(<DartType>[doubleType]);
|
| - _checkLeastUpperBound(listOfIntType, listOfDoubleType, objectType);
|
| + // TODO(rnystrom): Can we do something better here?
|
| + _checkGreatestLowerBound(listOfIntType, listOfDoubleType, bottomType);
|
| }
|
|
|
| void test_typeParameters_same() {
|
| - // List<int>
|
| - // List<int>
|
| + // GLB(List<int>, List<int>) = List<int>
|
| InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
|
| - _checkLeastUpperBound(listOfIntType, listOfIntType, listOfIntType);
|
| + _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_bottom() {
|
| - _checkLeastUpperBound(voidType, bottomType, voidType);
|
| + _checkGreatestLowerBound(voidType, bottomType, bottomType);
|
| }
|
|
|
| void test_void_function() {
|
| - _checkLeastUpperBound(voidType, simpleFunctionType, voidType);
|
| + _checkGreatestLowerBound(voidType, simpleFunctionType, simpleFunctionType);
|
| }
|
|
|
| void test_void_interface() {
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - _checkLeastUpperBound(voidType, interfaceType, voidType);
|
| + _checkGreatestLowerBound(voidType, interfaceType, interfaceType);
|
| }
|
|
|
| void test_void_typeParam() {
|
| DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| - _checkLeastUpperBound(voidType, typeParam, voidType);
|
| - }
|
| -
|
| - 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_functionsDifferentRequiredArity() {
|
| - FunctionType type1 = _functionType([intType, intType]);
|
| - FunctionType type2 = _functionType([intType, intType, intType]);
|
| - _checkLeastUpperBound(type1, type2, functionType);
|
| - }
|
| -
|
| - 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_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_functionsLubReturnType() {
|
| - FunctionType type1 = _functionType([], returns: intType);
|
| - FunctionType type2 = _functionType([], returns: doubleType);
|
| - FunctionType expected = _functionType([], returns: numType);
|
| - _checkLeastUpperBound(type1, type2, expected);
|
| - }
|
| -
|
| - 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);
|
| + _checkGreatestLowerBound(voidType, typeParam, typeParam);
|
| }
|
| }
|
|
|
| /**
|
| - * Tests LUB in spec mode.
|
| + * 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 LeastUpperBoundTest extends LeastUpperBoundTestBase {
|
| +class StrongLeastUpperBoundTest extends LeastUpperBoundTestBase {
|
| void setUp() {
|
| - typeSystem = new TypeSystemImpl();
|
| + typeSystem = new StrongTypeSystemImpl();
|
| super.setUp();
|
| }
|
|
|
| - 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_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_functionsLubNamedParams() {
|
| + void test_functionsGlbNamedParams() {
|
| 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_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);
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * 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_functionsGlbRequiredParams() {
|
| - FunctionType type1 = _functionType([stringType, intType, intType]);
|
| - FunctionType type2 = _functionType([intType, doubleType, numType]);
|
| - FunctionType expected = _functionType([bottomType, bottomType, intType]);
|
| + _functionType([], named: {'a': bottomType, 'b': intType});
|
| _checkLeastUpperBound(type1, type2, expected);
|
| }
|
|
|
| @@ -1430,12 +1290,10 @@ class StrongLeastUpperBoundTest extends LeastUpperBoundTestBase {
|
| _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});
|
| + 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);
|
| }
|
|
|
| @@ -1459,257 +1317,399 @@ class StrongLeastUpperBoundTest extends LeastUpperBoundTestBase {
|
| }
|
| }
|
|
|
| -/**
|
| - * Tests GLB, which only exists in strong mode.
|
| - */
|
| -@reflectiveTest
|
| -class StrongGreatestLowerBoundTest extends BoundTestBase {
|
| +@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();
|
| - super.setUp();
|
| - }
|
| -
|
| - void test_bottom_function() {
|
| - _checkGreatestLowerBound(bottomType, simpleFunctionType, bottomType);
|
| }
|
|
|
| - void test_bottom_interface() {
|
| + void test_bottom_isBottom() {
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - _checkGreatestLowerBound(bottomType, interfaceType, bottomType);
|
| + List<DartType> equivalents = <DartType>[bottomType];
|
| + List<DartType> supertypes = <DartType>[
|
| + dynamicType,
|
| + objectType,
|
| + intType,
|
| + doubleType,
|
| + numType,
|
| + stringType,
|
| + functionType,
|
| + interfaceType
|
| + ];
|
| + _checkGroups(bottomType, equivalents: equivalents, supertypes: supertypes);
|
| }
|
|
|
| - void test_bottom_typeParam() {
|
| - DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| - _checkGreatestLowerBound(bottomType, typeParam, bottomType);
|
| - }
|
| + void test_call_method() {
|
| + ClassElementImpl classBottom = ElementFactory.classElement2("Bottom");
|
| + MethodElement methodBottom =
|
| + ElementFactory.methodElement("call", objectType, <DartType>[intType]);
|
| + classBottom.methods = <MethodElement>[methodBottom];
|
|
|
| - 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);
|
| - }
|
| + DartType top =
|
| + TypeBuilder.function(required: <DartType>[intType], result: objectType);
|
| + InterfaceType bottom = classBottom.type;
|
|
|
| - 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);
|
| + _checkIsStrictSubtypeOf(bottom, top);
|
| }
|
|
|
| - 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_classes() {
|
| + ClassElement classTop = ElementFactory.classElement2("A");
|
| + ClassElement classLeft = ElementFactory.classElement("B", classTop.type);
|
| + ClassElement classRight = ElementFactory.classElement("C", classTop.type);
|
| + ClassElement classBottom = ElementFactory.classElement("D", classLeft.type)
|
| + ..interfaces = <InterfaceType>[classRight.type];
|
| + InterfaceType top = classTop.type;
|
| + InterfaceType left = classLeft.type;
|
| + InterfaceType right = classRight.type;
|
| + InterfaceType bottom = classBottom.type;
|
|
|
| - void test_dynamic_bottom() {
|
| - _checkGreatestLowerBound(dynamicType, bottomType, bottomType);
|
| + _checkLattice(top, left, right, bottom);
|
| }
|
|
|
| - void test_dynamic_function() {
|
| - _checkGreatestLowerBound(
|
| - dynamicType, simpleFunctionType, simpleFunctionType);
|
| + 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);
|
| }
|
|
|
| - void test_dynamic_interface() {
|
| + void test_dynamic_isTop() {
|
| DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - _checkGreatestLowerBound(dynamicType, interfaceType, interfaceType);
|
| + 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_dynamic_typeParam() {
|
| - DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| - _checkGreatestLowerBound(dynamicType, typeParam, typeParam);
|
| - }
|
| + 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);
|
|
|
| - void test_dynamic_void() {
|
| - _checkGreatestLowerBound(dynamicType, voidType, voidType);
|
| + _checkLattice(top, left, right, bottom);
|
| }
|
|
|
| - void test_interface_function() {
|
| - DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - _checkGreatestLowerBound(interfaceType, simpleFunctionType, bottomType);
|
| + 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_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_genericFunction_simple() {
|
| + DartType s = TypeBuilder.variable("S");
|
| + DartType t = TypeBuilder.variable("T");
|
| +
|
| + _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_self() {
|
| - DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| - DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| + 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);
|
|
|
| - List<DartType> types = [
|
| - dynamicType,
|
| - voidType,
|
| - bottomType,
|
| - typeParam,
|
| - interfaceType,
|
| - simpleFunctionType
|
| - ];
|
| + _checkEquivalent(TypeBuilder.function(types: [s, t]),
|
| + TypeBuilder.function(types: [u, v]));
|
|
|
| - for (DartType type in types) {
|
| - _checkGreatestLowerBound(type, type, type);
|
| + _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_typeParam_function_noBound() {
|
| - DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| - _checkGreatestLowerBound(typeParam, simpleFunctionType, bottomType);
|
| + 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_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_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_typeParam_interface_noBound() {
|
| - // GLB(T, A) = ⊥
|
| - DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| - DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - _checkGreatestLowerBound(typeParam, interfaceType, bottomType);
|
| - }
|
| + 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);
|
|
|
| - 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);
|
| + _checkGroups(r,
|
| + equivalents: [r],
|
| + subtypes: [o, ro, rn, oo],
|
| + unrelated: [n, rr, nn, nnn]);
|
| + _checkGroups(o,
|
| + equivalents: [o], subtypes: [oo], unrelated: [n, rr, ro, rn, nn, nnn]);
|
| + _checkGroups(n,
|
| + equivalents: [n],
|
| + subtypes: [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]);
|
| + _checkGroups(rn,
|
| + equivalents: [rn],
|
| + subtypes: [],
|
| + unrelated: [o, n, rr, ro, oo, nn, nnn]);
|
| + _checkGroups(oo,
|
| + equivalents: [oo], subtypes: [], unrelated: [n, rn, nn, nnn]);
|
| + _checkGroups(nn,
|
| + equivalents: [nn], subtypes: [nnn], unrelated: [r, o, rr, ro, rn, oo]);
|
| + _checkGroups(nnn,
|
| + equivalents: [nnn], subtypes: [], unrelated: [r, o, rr, ro, rn, oo]);
|
| }
|
|
|
| - void test_typeParameters_same() {
|
| - // GLB(List<int>, List<int>) = List<int>
|
| - InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
|
| - _checkGreatestLowerBound(listOfIntType, listOfIntType, listOfIntType);
|
| + 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);
|
| }
|
|
|
| - void test_void_bottom() {
|
| - _checkGreatestLowerBound(voidType, bottomType, bottomType);
|
| - }
|
| + 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);
|
|
|
| - void test_void_function() {
|
| - _checkGreatestLowerBound(voidType, simpleFunctionType, simpleFunctionType);
|
| + _checkLattice(top, left, right, bottom);
|
| }
|
|
|
| - void test_void_interface() {
|
| - DartType interfaceType = ElementFactory.classElement2('A', []).type;
|
| - _checkGreatestLowerBound(voidType, interfaceType, interfaceType);
|
| + /// 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 test_void_typeParam() {
|
| - DartType typeParam = ElementFactory.typeParameterElement('T').type;
|
| - _checkGreatestLowerBound(voidType, typeParam, typeParam);
|
| - }
|
| + void test_void_functions() {
|
| + FunctionType top =
|
| + TypeBuilder.function(required: <DartType>[intType], result: voidType);
|
| + FunctionType bottom =
|
| + TypeBuilder.function(required: <DartType>[objectType], result: intType);
|
|
|
| - 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);
|
| + _checkIsStrictSubtypeOf(bottom, top);
|
| }
|
|
|
| - 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 _checkEquivalent(DartType type1, DartType type2) {
|
| + _checkIsSubtypeOf(type1, type2);
|
| + _checkIsSubtypeOf(type2, type1);
|
| }
|
|
|
| - 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 _checkGroups(DartType t1,
|
| + {List<DartType> equivalents,
|
| + List<DartType> unrelated,
|
| + List<DartType> subtypes,
|
| + List<DartType> supertypes}) {
|
| + if (equivalents != null) {
|
| + for (DartType t2 in equivalents) {
|
| + _checkEquivalent(t1, t2);
|
| + }
|
| + }
|
| + if (unrelated != null) {
|
| + for (DartType t2 in unrelated) {
|
| + _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 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 _checkIsNotSubtypeOf(DartType type1, DartType type2) {
|
| + expect(typeSystem.isSubtypeOf(type1, type2), false);
|
| }
|
|
|
| - void test_functionsGlbReturnType() {
|
| - FunctionType type1 = _functionType([], returns: intType);
|
| - FunctionType type2 = _functionType([], returns: numType);
|
| - FunctionType expected = _functionType([], returns: intType);
|
| - _checkGreatestLowerBound(type1, type2, expected);
|
| + void _checkIsStrictSubtypeOf(DartType type1, DartType type2) {
|
| + _checkIsSubtypeOf(type1, type2);
|
| + _checkIsNotSubtypeOf(type2, type1);
|
| }
|
|
|
| - 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 _checkIsSubtypeOf(DartType type1, DartType type2) {
|
| + expect(typeSystem.isSubtypeOf(type1, type2), true);
|
| }
|
|
|
| - 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 _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 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 _checkUnrelated(DartType type1, DartType type2) {
|
| + _checkIsNotSubtypeOf(type1, type2);
|
| + _checkIsNotSubtypeOf(type2, type1);
|
| }
|
| +}
|
|
|
| - 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);
|
| +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);
|
| }
|
|
|
| - 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);
|
| - }
|
| + static TypeParameterType variable(String name, {DartType bound}) =>
|
| + ElementFactory.typeParameterWithType(name, bound).type;
|
| }
|
|
|