TypeSystem tests code motion.
Drop `Strong` prefix, extract LeastUpperBoundFunctionsTest.
R=brianwilkerson@google.com, paulberry@google.com
Change-Id: I2ab28f23e28698f4c2063eb07362ae6df2938054
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105481
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/test/generated/type_system_test.dart b/pkg/analyzer/test/generated/type_system_test.dart
index 16599ec..964112f 100644
--- a/pkg/analyzer/test/generated/type_system_test.dart
+++ b/pkg/analyzer/test/generated/type_system_test.dart
@@ -30,13 +30,14 @@
main() {
defineReflectiveSuite(() {
+ defineReflectiveTests(AssignabilityTest);
defineReflectiveTests(ConstraintMatchingTest);
- defineReflectiveTests(StrongAssignabilityTest);
- defineReflectiveTests(StrongSubtypingTest);
+ defineReflectiveTests(GenericFunctionInferenceTest);
+ defineReflectiveTests(GreatestLowerBoundTest);
+ defineReflectiveTests(LeastUpperBoundFunctionsTest);
+ defineReflectiveTests(LeastUpperBoundTest);
defineReflectiveTests(NonNullableSubtypingTest);
- defineReflectiveTests(StrongGenericFunctionInferenceTest);
- defineReflectiveTests(StrongLeastUpperBoundTest);
- defineReflectiveTests(StrongGreatestLowerBoundTest);
+ defineReflectiveTests(SubtypingTest);
defineReflectiveTests(TypeSystemTest);
});
}
@@ -64,6 +65,272 @@
}
}
+@reflectiveTest
+class AssignabilityTest extends AbstractTypeSystemTest {
+ void test_isAssignableTo_bottom_isBottom() {
+ DartType interfaceType = ElementFactory.classElement2('A', []).type;
+ List<DartType> interassignable = <DartType>[
+ dynamicType,
+ objectType,
+ intType,
+ doubleType,
+ numType,
+ stringType,
+ interfaceType,
+ bottomType
+ ];
+
+ _checkGroups(bottomType, interassignable: interassignable);
+ }
+
+ void test_isAssignableTo_call_method() {
+ ClassElementImpl classBottom = ElementFactory.classElement2("B");
+ MethodElement methodBottom =
+ ElementFactory.methodElement("call", objectType, <DartType>[intType]);
+ classBottom.methods = <MethodElement>[methodBottom];
+
+ DartType top =
+ TypeBuilder.function(required: <DartType>[intType], result: objectType);
+ InterfaceType bottom = classBottom.type;
+
+ _checkIsStrictAssignableTo(bottom, top);
+ }
+
+ 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;
+
+ _checkLattice(top, left, right, bottom);
+ }
+
+ 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,
+ interassignable: interassignable, unrelated: unrelated);
+ }
+
+ void test_isAssignableTo_dynamic_isTop() {
+ DartType interfaceType = ElementFactory.classElement2('A', []).type;
+ List<DartType> interassignable = <DartType>[
+ dynamicType,
+ objectType,
+ intType,
+ doubleType,
+ numType,
+ stringType,
+ interfaceType,
+ bottomType
+ ];
+ _checkGroups(dynamicType, interassignable: interassignable);
+ }
+
+ 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;
+
+ InterfaceType top = LType.instantiate(<DartType>[dynamicType]);
+ InterfaceType left = MType.instantiate(<DartType>[dynamicType]);
+ InterfaceType right = LType.instantiate(<DartType>[intType]);
+ InterfaceType bottom = MType.instantiate(<DartType>[intType]);
+
+ _checkCrossLattice(top, left, right, bottom);
+ }
+
+ void test_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,
+ interassignable: interassignable, unrelated: unrelated);
+ }
+
+ 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_isAssignableTo_void_functions() {
+ FunctionType top =
+ TypeBuilder.function(required: <DartType>[intType], result: voidType);
+ FunctionType bottom =
+ TypeBuilder.function(required: <DartType>[objectType], result: intType);
+
+ _checkEquivalent(bottom, top);
+ }
+
+ void _checkCrossLattice(
+ DartType top, DartType left, DartType right, DartType bottom) {
+ _checkGroups(top, interassignable: [top, left, right, bottom]);
+ _checkGroups(left,
+ interassignable: [top, left, bottom], unrelated: [right]);
+ _checkGroups(right,
+ interassignable: [top, right, bottom], unrelated: [left]);
+ _checkGroups(bottom, interassignable: [top, left, right, bottom]);
+ }
+
+ void _checkEquivalent(DartType type1, DartType type2) {
+ _checkIsAssignableTo(type1, type2);
+ _checkIsAssignableTo(type2, type1);
+ }
+
+ void _checkGroups(DartType t1,
+ {List<DartType> 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 _checkIsAssignableTo(DartType type1, DartType type2) {
+ expect(typeSystem.isAssignableTo(type1, type2), true);
+ }
+
+ void _checkIsNotAssignableTo(DartType type1, DartType type2) {
+ expect(typeSystem.isAssignableTo(type1, type2), false);
+ }
+
+ void _checkIsStrictAssignableTo(DartType type1, DartType type2) {
+ _checkIsAssignableTo(type1, type2);
+ _checkIsNotAssignableTo(type2, type1);
+ }
+
+ 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 _checkUnrelated(DartType type1, DartType type2) {
+ _checkIsNotAssignableTo(type1, type2);
+ _checkIsNotAssignableTo(type2, type1);
+ }
+}
+
/**
* Base class for testing LUB and GLB in spec and strong mode.
*/
@@ -510,704 +777,8 @@
}
}
-/**
- * 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;
- _checkLeastUpperBound(bottomType, interfaceType, interfaceType);
- }
-
- 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);
- }
-
- 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);
- }
-
- void test_dynamic_bottom() {
- _checkLeastUpperBound(dynamicType, bottomType, dynamicType);
- }
-
- void test_dynamic_function() {
- _checkLeastUpperBound(dynamicType, simpleFunctionType, dynamicType);
- }
-
- void test_dynamic_interface() {
- DartType interfaceType = ElementFactory.classElement2('A', []).type;
- _checkLeastUpperBound(dynamicType, interfaceType, dynamicType);
- }
-
- void test_dynamic_typeParam() {
- DartType typeParam = ElementFactory.typeParameterElement('T').type;
- _checkLeastUpperBound(dynamicType, typeParam, dynamicType);
- }
-
- void test_dynamic_void() {
- // Note: _checkLeastUpperBound tests `LUB(x, y)` as well as `LUB(y, x)`
- _checkLeastUpperBound(dynamicType, voidType, voidType);
- }
-
- void test_functionsDifferentRequiredArity() {
- FunctionType type1 = _functionType([intType, intType]);
- FunctionType type2 = _functionType([intType, intType, intType]);
- _checkLeastUpperBound(type1, type2, functionType);
- }
-
- void test_functionsIgnoreExtraNamedParams() {
- FunctionType type1 = _functionType([], named: {'a': intType, 'b': intType});
- FunctionType type2 = _functionType([], named: {'a': intType, 'c': intType});
- FunctionType expected = _functionType([], named: {'a': intType});
- _checkLeastUpperBound(type1, type2, expected);
- }
-
- void test_functionsIgnoreExtraPositionalParams() {
- FunctionType type1 =
- _functionType([], optional: [intType, intType, stringType]);
- FunctionType type2 = _functionType([], optional: [intType]);
- FunctionType expected = _functionType([], optional: [intType]);
- _checkLeastUpperBound(type1, type2, expected);
- }
-
- void test_functionsLubReturnType() {
- FunctionType type1 = _functionType([], returns: intType);
- FunctionType type2 = _functionType([], returns: doubleType);
- FunctionType expected = _functionType([], returns: numType);
- _checkLeastUpperBound(type1, type2, expected);
- }
-
- void test_functionsSameType() {
- FunctionType type1 = _functionType([stringType, intType, numType],
- optional: [doubleType], named: {'n': numType}, returns: intType);
- FunctionType type2 = _functionType([stringType, intType, numType],
- optional: [doubleType], named: {'n': numType}, returns: intType);
- FunctionType expected = _functionType([stringType, intType, numType],
- optional: [doubleType], named: {'n': numType}, returns: intType);
- _checkLeastUpperBound(type1, type2, expected);
- }
-
- void test_interface_function() {
- DartType interfaceType = ElementFactory.classElement2('A', []).type;
- _checkLeastUpperBound(interfaceType, simpleFunctionType, objectType);
- }
-
- void test_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_nestedFunctionsLubInnerParamTypes() {
- FunctionType type1 = _functionType([
- _functionType([stringType, intType, intType])
- ]);
- FunctionType type2 = _functionType([
- _functionType([intType, doubleType, numType])
- ]);
- FunctionType expected = _functionType([
- _functionType([objectType, numType, numType])
- ]);
- _checkLeastUpperBound(type1, type2, expected);
- }
-
- void test_object() {
- ClassElementImpl classA = ElementFactory.classElement2("A");
- ClassElementImpl classB = ElementFactory.classElement2("B");
- InterfaceType typeA = classA.type;
- 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_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_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_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_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_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_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_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_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_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_twoComparables() {
- _checkLeastUpperBound(stringType, numType, objectType);
- }
-
- void test_typeParam_function_bounded() {
- TypeParameterElementImpl typeParamElement =
- ElementFactory.typeParameterElement('T');
- typeParamElement.bound = functionType;
- DartType typeParam = typeParamElement.type;
- _checkLeastUpperBound(typeParam, simpleFunctionType, functionType);
- }
-
- void test_typeParam_function_noBound() {
- DartType typeParam = ElementFactory.typeParameterElement('T').type;
- _checkLeastUpperBound(typeParam, simpleFunctionType, objectType);
- }
-
- 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_typeParam_interface_noBound() {
- DartType typeParam = ElementFactory.typeParameterElement('T').type;
- DartType interfaceType = ElementFactory.classElement2('A', []).type;
- _checkLeastUpperBound(typeParam, interfaceType, objectType);
- }
-
- void test_typeParameters_same() {
- // List<int>
- // List<int>
- InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
- _checkLeastUpperBound(listOfIntType, listOfIntType, listOfIntType);
- }
-
- void test_void() {
- List<DartType> types = [
- bottomType,
- simpleFunctionType,
- ElementFactory.classElement2('A', []).type,
- ElementFactory.typeParameterElement('T').type
- ];
- for (DartType type in types) {
- _checkLeastUpperBound(
- _functionType([], returns: voidType),
- _functionType([], returns: type),
- _functionType([], returns: voidType));
- }
- }
-}
-
@reflectiveTest
-class NonNullableSubtypingTest extends StrongSubtypingTestBase {
- @override
- void setUp() {
- typeProvider = AnalysisContextFactory.contextWithCoreAndOptions(
- new AnalysisOptionsImpl()
- ..contextFeatures = FeatureSet.forTesting(
- additionalFeatures: [Feature.non_nullable]),
- resourceProvider: new MemoryResourceProvider())
- .typeProvider;
-
- // TypeSystem should use the context type provider.
- typeSystem = new Dart2TypeSystem(typeProvider);
-
- LibraryElement coreLibrary = typeProvider.objectType.element.library;
- LibraryElement asyncLibrary = typeProvider.streamType.element.library;
-
- // Get a non-nullable type provider for convience during the test.
- typeProvider = new NonNullableTypeProvider(coreLibrary, asyncLibrary);
- }
-
- void test_int_nullableTypes() {
- List<DartType> equivalents = <DartType>[
- intType,
- _star(intType),
- ];
- List<DartType> supertypes = <DartType>[
- _question(intType),
- objectType,
- _question(objectType),
- ];
- List<DartType> unrelated = <DartType>[doubleType, nullType];
- _checkGroups(intType,
- equivalents: equivalents, supertypes: supertypes, unrelated: unrelated);
- }
-
- void test_intQuestion_nullableTypes() {
- List<DartType> equivalents = <DartType>[
- _question(intType),
- _star(intType),
- ];
- List<DartType> subtypes = <DartType>[
- intType,
- nullType,
- ];
- List<DartType> supertypes = <DartType>[
- _question(numType),
- _star(numType),
- _question(objectType),
- _star(objectType),
- ];
- List<DartType> unrelated = <DartType>[doubleType, numType, objectType];
- _checkGroups(_question(intType),
- equivalents: equivalents,
- supertypes: supertypes,
- unrelated: unrelated,
- subtypes: subtypes);
- }
-
- void test_intStar_nullableTypes() {
- List<DartType> equivalents = <DartType>[
- intType,
- _question(intType),
- _star(intType),
- ];
- List<DartType> subtypes = <DartType>[nullType];
- List<DartType> supertypes = <DartType>[
- numType,
- _question(numType),
- _star(numType),
- objectType,
- _question(objectType),
- ];
- List<DartType> unrelated = <DartType>[doubleType];
- _checkGroups(_star(intType),
- equivalents: equivalents,
- supertypes: supertypes,
- unrelated: unrelated,
- subtypes: subtypes);
- }
-
- DartType _question(DartType dartType) =>
- (dartType as TypeImpl).withNullability(NullabilitySuffix.question);
-
- DartType _star(DartType dartType) =>
- (dartType as TypeImpl).withNullability(NullabilitySuffix.star);
-}
-
-@reflectiveTest
-class StrongAssignabilityTest extends AbstractTypeSystemTest {
- void test_isAssignableTo_bottom_isBottom() {
- DartType interfaceType = ElementFactory.classElement2('A', []).type;
- List<DartType> interassignable = <DartType>[
- dynamicType,
- objectType,
- intType,
- doubleType,
- numType,
- stringType,
- interfaceType,
- bottomType
- ];
-
- _checkGroups(bottomType, interassignable: interassignable);
- }
-
- void test_isAssignableTo_call_method() {
- ClassElementImpl classBottom = ElementFactory.classElement2("B");
- MethodElement methodBottom =
- ElementFactory.methodElement("call", objectType, <DartType>[intType]);
- classBottom.methods = <MethodElement>[methodBottom];
-
- DartType top =
- TypeBuilder.function(required: <DartType>[intType], result: objectType);
- InterfaceType bottom = classBottom.type;
-
- _checkIsStrictAssignableTo(bottom, top);
- }
-
- 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;
-
- _checkLattice(top, left, right, bottom);
- }
-
- 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,
- interassignable: interassignable, unrelated: unrelated);
- }
-
- void test_isAssignableTo_dynamic_isTop() {
- DartType interfaceType = ElementFactory.classElement2('A', []).type;
- List<DartType> interassignable = <DartType>[
- dynamicType,
- objectType,
- intType,
- doubleType,
- numType,
- stringType,
- interfaceType,
- bottomType
- ];
- _checkGroups(dynamicType, interassignable: interassignable);
- }
-
- 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;
-
- InterfaceType top = LType.instantiate(<DartType>[dynamicType]);
- InterfaceType left = MType.instantiate(<DartType>[dynamicType]);
- InterfaceType right = LType.instantiate(<DartType>[intType]);
- InterfaceType bottom = MType.instantiate(<DartType>[intType]);
-
- _checkCrossLattice(top, left, right, bottom);
- }
-
- void test_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,
- interassignable: interassignable, unrelated: unrelated);
- }
-
- 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_isAssignableTo_void_functions() {
- FunctionType top =
- TypeBuilder.function(required: <DartType>[intType], result: voidType);
- FunctionType bottom =
- TypeBuilder.function(required: <DartType>[objectType], result: intType);
-
- _checkEquivalent(bottom, top);
- }
-
- void _checkCrossLattice(
- DartType top, DartType left, DartType right, DartType bottom) {
- _checkGroups(top, interassignable: [top, left, right, bottom]);
- _checkGroups(left,
- interassignable: [top, left, bottom], unrelated: [right]);
- _checkGroups(right,
- interassignable: [top, right, bottom], unrelated: [left]);
- _checkGroups(bottom, interassignable: [top, left, right, bottom]);
- }
-
- void _checkEquivalent(DartType type1, DartType type2) {
- _checkIsAssignableTo(type1, type2);
- _checkIsAssignableTo(type2, type1);
- }
-
- void _checkGroups(DartType t1,
- {List<DartType> 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 _checkIsAssignableTo(DartType type1, DartType type2) {
- expect(typeSystem.isAssignableTo(type1, type2), true);
- }
-
- void _checkIsNotAssignableTo(DartType type1, DartType type2) {
- expect(typeSystem.isAssignableTo(type1, type2), false);
- }
-
- void _checkIsStrictAssignableTo(DartType type1, DartType type2) {
- _checkIsAssignableTo(type1, type2);
- _checkIsNotAssignableTo(type2, type1);
- }
-
- 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 _checkUnrelated(DartType type1, DartType type2) {
- _checkIsNotAssignableTo(type1, type2);
- _checkIsNotAssignableTo(type2, type1);
- }
-}
-
-@reflectiveTest
-class StrongGenericFunctionInferenceTest extends AbstractTypeSystemTest {
+class GenericFunctionInferenceTest extends AbstractTypeSystemTest {
void test_boundedByAnotherTypeParameter() {
// <TFrom, TTo extends Iterable<TFrom>>(TFrom) -> TTo
var tFrom = TypeBuilder.variable('TFrom');
@@ -1503,11 +1074,8 @@
}
}
-/**
- * Tests GLB, which only exists in strong mode.
- */
@reflectiveTest
-class StrongGreatestLowerBoundTest extends BoundTestBase {
+class GreatestLowerBoundTest extends BoundTestBase {
void setUp() {
super.setUp();
typeSystem = new Dart2TypeSystem(typeProvider);
@@ -1823,20 +1391,19 @@
}
}
-/**
- * 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 {
+class LeastUpperBoundFunctionsTest extends BoundTestBase {
void setUp() {
super.setUp();
typeSystem = new Dart2TypeSystem(typeProvider);
}
+ void test_functionsDifferentRequiredArity() {
+ FunctionType type1 = _functionType([intType, intType]);
+ FunctionType type2 = _functionType([intType, intType, intType]);
+ _checkLeastUpperBound(type1, type2, functionType);
+ }
+
void test_functionsFuzzyArrows() {
FunctionType type1 = _functionType([dynamicType]);
FunctionType type2 = _functionType([intType]);
@@ -1867,6 +1434,149 @@
_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_functionsIgnoreExtraPositionalParams() {
+ FunctionType type1 =
+ _functionType([], optional: [intType, intType, stringType]);
+ FunctionType type2 = _functionType([], optional: [intType]);
+ FunctionType expected = _functionType([], optional: [intType]);
+ _checkLeastUpperBound(type1, type2, expected);
+ }
+
+ void test_functionsLubReturnType() {
+ FunctionType type1 = _functionType([], returns: intType);
+ FunctionType type2 = _functionType([], returns: doubleType);
+ FunctionType expected = _functionType([], returns: numType);
+ _checkLeastUpperBound(type1, type2, expected);
+ }
+
+ void test_functionsSameType() {
+ FunctionType type1 = _functionType([stringType, intType, numType],
+ optional: [doubleType], named: {'n': numType}, returns: intType);
+ FunctionType type2 = _functionType([stringType, intType, numType],
+ optional: [doubleType], named: {'n': numType}, returns: intType);
+ FunctionType expected = _functionType([stringType, intType, numType],
+ optional: [doubleType], named: {'n': numType}, returns: intType);
+ _checkLeastUpperBound(type1, type2, expected);
+ }
+}
+
+@reflectiveTest
+class LeastUpperBoundTest extends BoundTestBase {
+ void setUp() {
+ super.setUp();
+ typeSystem = new Dart2TypeSystem(typeProvider);
+ }
+
+ void test_bottom_function() {
+ _checkLeastUpperBound(bottomType, simpleFunctionType, simpleFunctionType);
+ }
+
+ void test_bottom_interface() {
+ DartType interfaceType = ElementFactory.classElement2('A', []).type;
+ _checkLeastUpperBound(bottomType, interfaceType, interfaceType);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ void test_dynamic_bottom() {
+ _checkLeastUpperBound(dynamicType, bottomType, dynamicType);
+ }
+
+ void test_dynamic_function() {
+ _checkLeastUpperBound(dynamicType, simpleFunctionType, dynamicType);
+ }
+
+ void test_dynamic_interface() {
+ DartType interfaceType = ElementFactory.classElement2('A', []).type;
+ _checkLeastUpperBound(dynamicType, interfaceType, dynamicType);
+ }
+
+ void test_dynamic_typeParam() {
+ DartType typeParam = ElementFactory.typeParameterElement('T').type;
+ _checkLeastUpperBound(dynamicType, typeParam, dynamicType);
+ }
+
+ void test_dynamic_void() {
+ // Note: _checkLeastUpperBound tests `LUB(x, y)` as well as `LUB(y, x)`
+ _checkLeastUpperBound(dynamicType, voidType, voidType);
+ }
+
+ void test_interface_function() {
+ DartType interfaceType = ElementFactory.classElement2('A', []).type;
+ _checkLeastUpperBound(interfaceType, simpleFunctionType, objectType);
+ }
+
+ 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_nestedFunctionsLubInnerParamTypes() {
+ FunctionType type1 = _functionType([
+ _functionType([stringType, intType, intType])
+ ]);
+ FunctionType type2 = _functionType([
+ _functionType([intType, doubleType, numType])
+ ]);
+ FunctionType expected = _functionType([
+ _functionType([objectType, numType, numType])
+ ]);
+ _checkLeastUpperBound(type1, type2, expected);
+ }
+
void test_nestedNestedFunctionsGlbInnermostParamTypes() {
FunctionType type1 = _functionType([
_functionType([
@@ -1886,6 +1596,148 @@
_checkLeastUpperBound(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_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_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_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_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_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_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_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_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_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_twoComparables() {
+ _checkLeastUpperBound(stringType, numType, objectType);
+ }
+
void test_typeParam_boundedByParam() {
TypeParameterElementImpl typeParamElementT =
ElementFactory.typeParameterElement('T');
@@ -1918,6 +1770,36 @@
_checkLeastUpperBound(s, u, AType.instantiate([objectType]));
}
+ void test_typeParam_function_bounded() {
+ TypeParameterElementImpl typeParamElement =
+ ElementFactory.typeParameterElement('T');
+ typeParamElement.bound = functionType;
+ DartType typeParam = typeParamElement.type;
+ _checkLeastUpperBound(typeParam, simpleFunctionType, functionType);
+ }
+
+ void test_typeParam_function_noBound() {
+ DartType typeParam = ElementFactory.typeParameterElement('T').type;
+ _checkLeastUpperBound(typeParam, simpleFunctionType, objectType);
+ }
+
+ 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_typeParam_interface_noBound() {
+ DartType typeParam = ElementFactory.typeParameterElement('T').type;
+ DartType interfaceType = ElementFactory.classElement2('A', []).type;
+ _checkLeastUpperBound(typeParam, interfaceType, objectType);
+ }
+
/// Check least upper bound of the same class with different type parameters.
void test_typeParameters_different() {
// class List<int>
@@ -1929,6 +1811,13 @@
_checkLeastUpperBound(listOfIntType, listOfDoubleType, listOfNum);
}
+ void test_typeParameters_same() {
+ // List<int>
+ // List<int>
+ InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
+ _checkLeastUpperBound(listOfIntType, listOfIntType, listOfIntType);
+ }
+
/// Check least upper bound of two related classes with different
/// type parameters.
void test_typeParametersAndClass_different() {
@@ -1940,10 +1829,113 @@
// TODO(leafp): this should be iterableOfNumType
_checkLeastUpperBound(listOfIntType, iterableOfDoubleType, objectType);
}
+
+ void test_void() {
+ List<DartType> types = [
+ bottomType,
+ simpleFunctionType,
+ ElementFactory.classElement2('A', []).type,
+ ElementFactory.typeParameterElement('T').type
+ ];
+ for (DartType type in types) {
+ _checkLeastUpperBound(
+ _functionType([], returns: voidType),
+ _functionType([], returns: type),
+ _functionType([], returns: voidType));
+ }
+ }
}
@reflectiveTest
-class StrongSubtypingTest extends StrongSubtypingTestBase {
+class NonNullableSubtypingTest extends SubtypingTestBase {
+ @override
+ void setUp() {
+ typeProvider = AnalysisContextFactory.contextWithCoreAndOptions(
+ new AnalysisOptionsImpl()
+ ..contextFeatures = FeatureSet.forTesting(
+ additionalFeatures: [Feature.non_nullable]),
+ resourceProvider: new MemoryResourceProvider())
+ .typeProvider;
+
+ // TypeSystem should use the context type provider.
+ typeSystem = new Dart2TypeSystem(typeProvider);
+
+ LibraryElement coreLibrary = typeProvider.objectType.element.library;
+ LibraryElement asyncLibrary = typeProvider.streamType.element.library;
+
+ // Get a non-nullable type provider for convience during the test.
+ typeProvider = new NonNullableTypeProvider(coreLibrary, asyncLibrary);
+ }
+
+ void test_int_nullableTypes() {
+ List<DartType> equivalents = <DartType>[
+ intType,
+ _star(intType),
+ ];
+ List<DartType> supertypes = <DartType>[
+ _question(intType),
+ objectType,
+ _question(objectType),
+ ];
+ List<DartType> unrelated = <DartType>[doubleType, nullType];
+ _checkGroups(intType,
+ equivalents: equivalents, supertypes: supertypes, unrelated: unrelated);
+ }
+
+ void test_intQuestion_nullableTypes() {
+ List<DartType> equivalents = <DartType>[
+ _question(intType),
+ _star(intType),
+ ];
+ List<DartType> subtypes = <DartType>[
+ intType,
+ nullType,
+ ];
+ List<DartType> supertypes = <DartType>[
+ _question(numType),
+ _star(numType),
+ _question(objectType),
+ _star(objectType),
+ ];
+ List<DartType> unrelated = <DartType>[doubleType, numType, objectType];
+ _checkGroups(_question(intType),
+ equivalents: equivalents,
+ supertypes: supertypes,
+ unrelated: unrelated,
+ subtypes: subtypes);
+ }
+
+ void test_intStar_nullableTypes() {
+ List<DartType> equivalents = <DartType>[
+ intType,
+ _question(intType),
+ _star(intType),
+ ];
+ List<DartType> subtypes = <DartType>[nullType];
+ List<DartType> supertypes = <DartType>[
+ numType,
+ _question(numType),
+ _star(numType),
+ objectType,
+ _question(objectType),
+ ];
+ List<DartType> unrelated = <DartType>[doubleType];
+ _checkGroups(_star(intType),
+ equivalents: equivalents,
+ supertypes: supertypes,
+ unrelated: unrelated,
+ subtypes: subtypes);
+ }
+
+ DartType _question(DartType dartType) =>
+ (dartType as TypeImpl).withNullability(NullabilitySuffix.question);
+
+ DartType _star(DartType dartType) =>
+ (dartType as TypeImpl).withNullability(NullabilitySuffix.star);
+}
+
+@reflectiveTest
+class SubtypingTest extends SubtypingTestBase {
void test_bottom_isBottom() {
DartType interfaceType = ElementFactory.classElement2('A', []).type;
List<DartType> equivalents = <DartType>[bottomType];
@@ -2255,7 +2247,7 @@
}
}
-class StrongSubtypingTestBase {
+class SubtypingTestBase {
TypeProvider typeProvider;
TypeSystem typeSystem;