Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Unified Diff: pkg/analyzer/test/generated/type_system_test.dart

Issue 1843473002: Sort analyzer sources (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Remove generated file and fix misplaced comments Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/analyzer/test/generated/static_warning_code_test.dart ('k') | pkg/analyzer/test/reflective_tests.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
}
« no previous file with comments | « pkg/analyzer/test/generated/static_warning_code_test.dart ('k') | pkg/analyzer/test/reflective_tests.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698