Index: packages/analyzer/test/generated/type_system_test.dart |
diff --git a/packages/analyzer/test/generated/type_system_test.dart b/packages/analyzer/test/generated/type_system_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d49c75c117cd53c63f98d6c8a515c8bd6888b154 |
--- /dev/null |
+++ b/packages/analyzer/test/generated/type_system_test.dart |
@@ -0,0 +1,928 @@ |
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+// Tests related to the [TypeSystem] class. |
+ |
+library engine.type_system_test; |
+ |
+import 'package:analyzer/src/generated/element.dart'; |
+import 'package:analyzer/src/generated/resolver.dart'; |
+import 'package:analyzer/src/generated/testing/element_factory.dart'; |
+import 'package:analyzer/src/generated/testing/test_type_provider.dart'; |
+import 'package:unittest/unittest.dart'; |
+ |
+import '../reflective_tests.dart'; |
+import '../utils.dart'; |
+ |
+main() { |
+ initializeTestEnvironment(); |
+ runReflectiveTests(TypeSystemTest); |
+ runReflectiveTests(StrongSubtypingTest); |
+ runReflectiveTests(StrongAssignabilityTest); |
+} |
+ |
+@reflectiveTest |
+class TypeSystemTest { |
+ TypeProvider typeProvider; |
+ TypeSystem typeSystem; |
+ FunctionType simpleFunctionType; |
+ |
+ 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 TypeSystemImpl(); |
+ FunctionTypeAliasElementImpl typeAlias = |
+ ElementFactory.functionTypeAliasElement('A'); |
+ typeAlias.parameters = []; |
+ typeAlias.returnType = voidType; |
+ simpleFunctionType = typeAlias.type; |
+ } |
+ |
+ void test_getLeastUpperBound_bottom_function() { |
+ _checkLeastUpperBound(bottomType, simpleFunctionType, simpleFunctionType); |
+ } |
+ |
+ void test_getLeastUpperBound_bottom_interface() { |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ _checkLeastUpperBound(bottomType, interfaceType, interfaceType); |
+ } |
+ |
+ void test_getLeastUpperBound_bottom_typeParam() { |
+ DartType typeParam = ElementFactory.typeParameterElement('T').type; |
+ _checkLeastUpperBound(bottomType, typeParam, typeParam); |
+ } |
+ |
+ void test_getLeastUpperBound_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_getLeastUpperBound_directSubclassCase() { |
+ // |
+ // class A |
+ // class B extends A |
+ // class C extends B |
+ // |
+ ClassElementImpl classA = ElementFactory.classElement2("A"); |
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type); |
+ ClassElementImpl classC = ElementFactory.classElement("C", classB.type); |
+ InterfaceType typeB = classB.type; |
+ InterfaceType typeC = classC.type; |
+ _checkLeastUpperBound(typeB, typeC, typeB); |
+ } |
+ |
+ void test_getLeastUpperBound_dynamic_bottom() { |
+ _checkLeastUpperBound(dynamicType, bottomType, dynamicType); |
+ } |
+ |
+ void test_getLeastUpperBound_dynamic_function() { |
+ _checkLeastUpperBound(dynamicType, simpleFunctionType, dynamicType); |
+ } |
+ |
+ void test_getLeastUpperBound_dynamic_interface() { |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ _checkLeastUpperBound(dynamicType, interfaceType, dynamicType); |
+ } |
+ |
+ void test_getLeastUpperBound_dynamic_typeParam() { |
+ DartType typeParam = ElementFactory.typeParameterElement('T').type; |
+ _checkLeastUpperBound(dynamicType, typeParam, dynamicType); |
+ } |
+ |
+ void test_getLeastUpperBound_dynamic_void() { |
+ _checkLeastUpperBound(dynamicType, voidType, dynamicType); |
+ } |
+ |
+ void test_getLeastUpperBound_interface_function() { |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ _checkLeastUpperBound(interfaceType, simpleFunctionType, objectType); |
+ } |
+ |
+ void test_getLeastUpperBound_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_getLeastUpperBound_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_getLeastUpperBound_self() { |
+ DartType typeParam = ElementFactory.typeParameterElement('T').type; |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ expect( |
+ typeSystem.getLeastUpperBound(typeProvider, dynamicType, dynamicType), |
+ dynamicType); |
+ expect(typeSystem.getLeastUpperBound(typeProvider, voidType, voidType), |
+ voidType); |
+ expect(typeSystem.getLeastUpperBound(typeProvider, bottomType, bottomType), |
+ bottomType); |
+ expect(typeSystem.getLeastUpperBound(typeProvider, typeParam, typeParam), |
+ typeParam); |
+ expect( |
+ typeSystem.getLeastUpperBound( |
+ typeProvider, interfaceType, interfaceType), |
+ interfaceType); |
+ expect( |
+ typeSystem.getLeastUpperBound( |
+ typeProvider, simpleFunctionType, simpleFunctionType), |
+ simpleFunctionType); |
+ } |
+ |
+ void test_getLeastUpperBound_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_getLeastUpperBound_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_getLeastUpperBound_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_getLeastUpperBound_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_getLeastUpperBound_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_getLeastUpperBound_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_getLeastUpperBound_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_getLeastUpperBound_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_getLeastUpperBound_twoComparables() { |
+ _checkLeastUpperBound(stringType, numType, objectType); |
+ } |
+ |
+ void test_getLeastUpperBound_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_getLeastUpperBound_typeParam_function_noBound() { |
+ DartType typeParam = ElementFactory.typeParameterElement('T').type; |
+ _checkLeastUpperBound(typeParam, simpleFunctionType, objectType); |
+ } |
+ |
+ void test_getLeastUpperBound_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_getLeastUpperBound_typeParam_interface_noBound() { |
+ DartType typeParam = ElementFactory.typeParameterElement('T').type; |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ _checkLeastUpperBound(typeParam, interfaceType, objectType); |
+ } |
+ |
+ void test_getLeastUpperBound_typeParameters_different() { |
+ // |
+ // class List<int> |
+ // class List<double> |
+ // |
+ InterfaceType listOfIntType = listType.substitute4(<DartType>[intType]); |
+ InterfaceType listOfDoubleType = |
+ listType.substitute4(<DartType>[doubleType]); |
+ _checkLeastUpperBound(listOfIntType, listOfDoubleType, objectType); |
+ } |
+ |
+ void test_getLeastUpperBound_typeParameters_same() { |
+ // |
+ // List<int> |
+ // List<int> |
+ // |
+ InterfaceType listOfIntType = listType.substitute4(<DartType>[intType]); |
+ expect( |
+ typeSystem.getLeastUpperBound( |
+ typeProvider, listOfIntType, listOfIntType), |
+ listOfIntType); |
+ } |
+ |
+ void test_getLeastUpperBound_void_bottom() { |
+ _checkLeastUpperBound(voidType, bottomType, voidType); |
+ } |
+ |
+ void test_getLeastUpperBound_void_function() { |
+ _checkLeastUpperBound(voidType, simpleFunctionType, voidType); |
+ } |
+ |
+ void test_getLeastUpperBound_void_interface() { |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ _checkLeastUpperBound(voidType, interfaceType, voidType); |
+ } |
+ |
+ void test_getLeastUpperBound_void_typeParam() { |
+ DartType typeParam = ElementFactory.typeParameterElement('T').type; |
+ _checkLeastUpperBound(voidType, typeParam, voidType); |
+ } |
+ |
+ void _checkLeastUpperBound( |
+ DartType type1, DartType type2, DartType expectedResult) { |
+ expect(typeSystem.getLeastUpperBound(typeProvider, type1, type2), |
+ expectedResult); |
+ } |
+} |
+ |
+class TypeBuilder { |
+ static FunctionType functionType( |
+ List<DartType> parameters, DartType returnType, |
+ {List<DartType> optional, Map<String, DartType> named}) { |
+ return ElementFactory |
+ .functionElement8(parameters, returnType, |
+ optional: optional, named: named) |
+ .type; |
+ } |
+} |
+ |
+@reflectiveTest |
+class StrongSubtypingTest { |
+ TypeProvider typeProvider; |
+ TypeSystem typeSystem; |
+ |
+ DartType get bottomType => typeProvider.bottomType; |
+ InterfaceType get doubleType => typeProvider.doubleType; |
+ DartType get dynamicType => typeProvider.dynamicType; |
+ InterfaceType get functionType => typeProvider.functionType; |
+ InterfaceType get intType => typeProvider.intType; |
+ InterfaceType get listType => typeProvider.listType; |
+ InterfaceType get numType => typeProvider.numType; |
+ InterfaceType get objectType => typeProvider.objectType; |
+ InterfaceType get stringType => typeProvider.stringType; |
+ DartType get voidType => VoidTypeImpl.instance; |
+ |
+ void setUp() { |
+ typeProvider = new TestTypeProvider(); |
+ typeSystem = new StrongTypeSystemImpl(); |
+ } |
+ |
+ void test_isSubtypeOf_dynamic_isTop() { |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ List<DartType> equivalents = <DartType>[dynamicType, objectType]; |
+ List<DartType> subtypes = <DartType>[ |
+ intType, |
+ doubleType, |
+ numType, |
+ stringType, |
+ functionType, |
+ interfaceType, |
+ bottomType |
+ ]; |
+ _checkGroups(dynamicType, equivalents: equivalents, subtypes: subtypes); |
+ } |
+ |
+ void test_isSubtypeOf_bottom_isBottom() { |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ List<DartType> equivalents = <DartType>[bottomType]; |
+ List<DartType> supertypes = <DartType>[ |
+ dynamicType, |
+ objectType, |
+ intType, |
+ doubleType, |
+ numType, |
+ stringType, |
+ functionType, |
+ interfaceType |
+ ]; |
+ _checkGroups(bottomType, equivalents: equivalents, supertypes: supertypes); |
+ } |
+ |
+ void test_isSubtypeOf_int() { |
+ List<DartType> equivalents = <DartType>[intType]; |
+ List<DartType> supertypes = <DartType>[numType]; |
+ List<DartType> unrelated = <DartType>[doubleType]; |
+ _checkGroups(intType, |
+ equivalents: equivalents, supertypes: supertypes, unrelated: unrelated); |
+ } |
+ |
+ void test_isSubtypeOf_double() { |
+ List<DartType> equivalents = <DartType>[doubleType]; |
+ List<DartType> supertypes = <DartType>[numType]; |
+ List<DartType> unrelated = <DartType>[intType]; |
+ _checkGroups(doubleType, |
+ equivalents: equivalents, supertypes: supertypes, unrelated: unrelated); |
+ } |
+ |
+ void test_isSubtypeOf_num() { |
+ List<DartType> equivalents = <DartType>[numType]; |
+ List<DartType> supertypes = <DartType>[]; |
+ List<DartType> unrelated = <DartType>[stringType]; |
+ List<DartType> subtypes = <DartType>[intType, doubleType]; |
+ _checkGroups(numType, |
+ equivalents: equivalents, |
+ supertypes: supertypes, |
+ unrelated: unrelated, |
+ subtypes: subtypes); |
+ } |
+ |
+ void test_isSubtypeOf_classes() { |
+ ClassElement classTop = ElementFactory.classElement2("A"); |
+ ClassElement classLeft = ElementFactory.classElement("B", classTop.type); |
+ ClassElement classRight = ElementFactory.classElement("C", classTop.type); |
+ ClassElement classBottom = ElementFactory.classElement("D", classLeft.type) |
+ ..interfaces = <InterfaceType>[classRight.type]; |
+ InterfaceType top = classTop.type; |
+ InterfaceType left = classLeft.type; |
+ InterfaceType right = classRight.type; |
+ InterfaceType bottom = classBottom.type; |
+ |
+ _checkLattice(top, left, right, bottom); |
+ } |
+ |
+ void test_isSubtypeOf_simple_function() { |
+ FunctionType top = |
+ TypeBuilder.functionType(<DartType>[intType], objectType); |
+ FunctionType left = TypeBuilder.functionType(<DartType>[intType], intType); |
+ FunctionType right = |
+ TypeBuilder.functionType(<DartType>[objectType], objectType); |
+ FunctionType bottom = |
+ TypeBuilder.functionType(<DartType>[objectType], intType); |
+ |
+ _checkLattice(top, left, right, bottom); |
+ } |
+ |
+ void test_isSubtypeOf_call_method() { |
+ ClassElementImpl classBottom = ElementFactory.classElement2("Bottom"); |
+ MethodElement methodBottom = |
+ ElementFactory.methodElement("call", objectType, <DartType>[intType]); |
+ classBottom.methods = <MethodElement>[methodBottom]; |
+ |
+ DartType top = TypeBuilder.functionType(<DartType>[intType], objectType); |
+ InterfaceType bottom = classBottom.type; |
+ |
+ _checkIsStrictSubtypeOf(bottom, top); |
+ } |
+ |
+ void test_isSubtypeOf_fuzzy_arrows() { |
+ FunctionType top = |
+ TypeBuilder.functionType(<DartType>[dynamicType], objectType); |
+ FunctionType left = |
+ TypeBuilder.functionType(<DartType>[objectType], objectType); |
+ FunctionType right = |
+ TypeBuilder.functionType(<DartType>[dynamicType], bottomType); |
+ FunctionType bottom = |
+ TypeBuilder.functionType(<DartType>[objectType], bottomType); |
+ |
+ _checkLattice(top, left, right, bottom); |
+ } |
+ |
+ void test_isSubtypeOf_void_functions() { |
+ FunctionType top = TypeBuilder.functionType(<DartType>[intType], voidType); |
+ FunctionType bottom = |
+ TypeBuilder.functionType(<DartType>[objectType], intType); |
+ |
+ _checkIsStrictSubtypeOf(bottom, top); |
+ } |
+ |
+ void test_isSubtypeOf_named_optional() { |
+ DartType r = TypeBuilder.functionType(<DartType>[intType], intType); |
+ DartType o = TypeBuilder.functionType(<DartType>[], intType, |
+ optional: <DartType>[intType]); |
+ DartType n = TypeBuilder.functionType(<DartType>[], intType, |
+ named: <String, DartType>{'x': intType}); |
+ DartType rr = |
+ TypeBuilder.functionType(<DartType>[intType, intType], intType); |
+ DartType ro = TypeBuilder.functionType(<DartType>[intType], intType, |
+ optional: <DartType>[intType]); |
+ DartType rn = TypeBuilder.functionType(<DartType>[intType], intType, |
+ named: <String, DartType>{'x': intType}); |
+ DartType oo = TypeBuilder.functionType(<DartType>[], intType, |
+ optional: <DartType>[intType, intType]); |
+ DartType nn = TypeBuilder.functionType(<DartType>[], intType, |
+ named: <String, DartType>{'x': intType, 'y': intType}); |
+ DartType nnn = TypeBuilder.functionType(<DartType>[], intType, |
+ named: <String, DartType>{'x': intType, 'y': intType, 'z': intType}); |
+ |
+ _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_isSubtypeOf_generics() { |
+ ClassElementImpl LClass = ElementFactory.classElement2('L', ["T"]); |
+ InterfaceType LType = LClass.type; |
+ ClassElementImpl MClass = ElementFactory.classElement2('M', ["T"]); |
+ DartType typeParam = MClass.typeParameters[0].type; |
+ InterfaceType superType = LType.substitute4(<DartType>[typeParam]); |
+ MClass.interfaces = <InterfaceType>[superType]; |
+ InterfaceType MType = MClass.type; |
+ |
+ InterfaceType top = LType.substitute4(<DartType>[dynamicType]); |
+ InterfaceType left = MType.substitute4(<DartType>[dynamicType]); |
+ InterfaceType right = LType.substitute4(<DartType>[intType]); |
+ InterfaceType bottom = MType.substitute4(<DartType>[intType]); |
+ |
+ _checkLattice(top, left, right, bottom); |
+ } |
+ |
+ 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 _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 _checkUnrelated(DartType type1, DartType type2) { |
+ _checkIsNotSubtypeOf(type1, type2); |
+ _checkIsNotSubtypeOf(type2, type1); |
+ } |
+ |
+ void _checkEquivalent(DartType type1, DartType type2) { |
+ _checkIsSubtypeOf(type1, type2); |
+ _checkIsSubtypeOf(type2, type1); |
+ } |
+ |
+ void _checkIsStrictSubtypeOf(DartType type1, DartType type2) { |
+ _checkIsSubtypeOf(type1, type2); |
+ _checkIsNotSubtypeOf(type2, type1); |
+ } |
+ |
+ void _checkIsSubtypeOf(DartType type1, DartType type2) { |
+ expect(typeSystem.isSubtypeOf(type1, type2), true); |
+ } |
+ |
+ void _checkIsNotSubtypeOf(DartType type1, DartType type2) { |
+ expect(typeSystem.isSubtypeOf(type1, type2), false); |
+ } |
+} |
+ |
+@reflectiveTest |
+class StrongAssignabilityTest { |
+ TypeProvider typeProvider; |
+ TypeSystem typeSystem; |
+ |
+ DartType get bottomType => typeProvider.bottomType; |
+ InterfaceType get doubleType => typeProvider.doubleType; |
+ DartType get dynamicType => typeProvider.dynamicType; |
+ InterfaceType get functionType => typeProvider.functionType; |
+ InterfaceType get intType => typeProvider.intType; |
+ InterfaceType get listType => typeProvider.listType; |
+ InterfaceType get numType => typeProvider.numType; |
+ InterfaceType get objectType => typeProvider.objectType; |
+ InterfaceType get stringType => typeProvider.stringType; |
+ DartType get voidType => VoidTypeImpl.instance; |
+ |
+ void setUp() { |
+ typeProvider = new TestTypeProvider(); |
+ typeSystem = new StrongTypeSystemImpl(); |
+ } |
+ |
+ void test_isAssignableTo_dynamic_isTop() { |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ List<DartType> interassignable = <DartType>[ |
+ dynamicType, |
+ objectType, |
+ intType, |
+ doubleType, |
+ numType, |
+ stringType, |
+ interfaceType, |
+ bottomType |
+ ]; |
+ _checkGroups(dynamicType, interassignable: interassignable); |
+ } |
+ |
+ void test_isAssignableTo_bottom_isBottom() { |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ List<DartType> interassignable = <DartType>[ |
+ dynamicType, |
+ objectType, |
+ intType, |
+ doubleType, |
+ numType, |
+ stringType, |
+ interfaceType, |
+ bottomType |
+ ]; |
+ |
+ _checkGroups(bottomType, interassignable: interassignable); |
+ } |
+ |
+ void test_isAssignableTo_int() { |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ List<DartType> interassignable = <DartType>[ |
+ dynamicType, |
+ objectType, |
+ intType, |
+ numType, |
+ bottomType |
+ ]; |
+ List<DartType> unrelated = <DartType>[ |
+ doubleType, |
+ stringType, |
+ interfaceType, |
+ ]; |
+ |
+ _checkGroups(intType, |
+ interassignable: interassignable, unrelated: unrelated); |
+ } |
+ |
+ void test_isAssignableTo_double() { |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ List<DartType> interassignable = <DartType>[ |
+ dynamicType, |
+ objectType, |
+ doubleType, |
+ numType, |
+ bottomType |
+ ]; |
+ List<DartType> unrelated = <DartType>[intType, stringType, interfaceType,]; |
+ |
+ _checkGroups(doubleType, |
+ interassignable: interassignable, unrelated: unrelated); |
+ } |
+ |
+ void test_isAssignableTo_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_classes() { |
+ ClassElement classTop = ElementFactory.classElement2("A"); |
+ ClassElement classLeft = ElementFactory.classElement("B", classTop.type); |
+ ClassElement classRight = ElementFactory.classElement("C", classTop.type); |
+ ClassElement classBottom = ElementFactory.classElement("D", classLeft.type) |
+ ..interfaces = <InterfaceType>[classRight.type]; |
+ InterfaceType top = classTop.type; |
+ InterfaceType left = classLeft.type; |
+ InterfaceType right = classRight.type; |
+ InterfaceType bottom = classBottom.type; |
+ |
+ _checkLattice(top, left, right, bottom); |
+ } |
+ |
+ void test_isAssignableTo_simple_function() { |
+ FunctionType top = |
+ TypeBuilder.functionType(<DartType>[intType], objectType); |
+ FunctionType left = TypeBuilder.functionType(<DartType>[intType], intType); |
+ FunctionType right = |
+ TypeBuilder.functionType(<DartType>[objectType], objectType); |
+ FunctionType bottom = |
+ TypeBuilder.functionType(<DartType>[objectType], intType); |
+ |
+ _checkCrossLattice(top, left, right, bottom); |
+ } |
+ |
+ void test_isAssignableTo_call_method() { |
+ ClassElementImpl classBottom = ElementFactory.classElement2("B"); |
+ MethodElement methodBottom = |
+ ElementFactory.methodElement("call", objectType, <DartType>[intType]); |
+ classBottom.methods = <MethodElement>[methodBottom]; |
+ |
+ DartType top = TypeBuilder.functionType(<DartType>[intType], objectType); |
+ InterfaceType bottom = classBottom.type; |
+ |
+ _checkIsStrictAssignableTo(bottom, top); |
+ } |
+ |
+ void test_isAssignableTo_fuzzy_arrows() { |
+ FunctionType top = |
+ TypeBuilder.functionType(<DartType>[dynamicType], objectType); |
+ FunctionType left = |
+ TypeBuilder.functionType(<DartType>[objectType], objectType); |
+ FunctionType right = |
+ TypeBuilder.functionType(<DartType>[dynamicType], bottomType); |
+ FunctionType bottom = |
+ TypeBuilder.functionType(<DartType>[objectType], bottomType); |
+ |
+ _checkCrossLattice(top, left, right, bottom); |
+ } |
+ |
+ void test_isAssignableTo_void_functions() { |
+ FunctionType top = TypeBuilder.functionType(<DartType>[intType], voidType); |
+ FunctionType bottom = |
+ TypeBuilder.functionType(<DartType>[objectType], intType); |
+ |
+ _checkEquivalent(bottom, top); |
+ } |
+ |
+ void test_isAssignableTo_named_optional() { |
+ DartType r = TypeBuilder.functionType(<DartType>[intType], intType); |
+ DartType o = TypeBuilder.functionType(<DartType>[], intType, |
+ optional: <DartType>[intType]); |
+ DartType n = TypeBuilder.functionType(<DartType>[], intType, |
+ named: <String, DartType>{'x': intType}); |
+ DartType rr = |
+ TypeBuilder.functionType(<DartType>[intType, intType], intType); |
+ DartType ro = TypeBuilder.functionType(<DartType>[intType], intType, |
+ optional: <DartType>[intType]); |
+ DartType rn = TypeBuilder.functionType(<DartType>[intType], intType, |
+ named: <String, DartType>{'x': intType}); |
+ DartType oo = TypeBuilder.functionType(<DartType>[], intType, |
+ optional: <DartType>[intType, intType]); |
+ DartType nn = TypeBuilder.functionType(<DartType>[], intType, |
+ named: <String, DartType>{'x': intType, 'y': intType}); |
+ DartType nnn = TypeBuilder.functionType(<DartType>[], intType, |
+ named: <String, DartType>{'x': intType, 'y': intType, 'z': intType}); |
+ |
+ _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_generics() { |
+ ClassElementImpl LClass = ElementFactory.classElement2('L', ["T"]); |
+ InterfaceType LType = LClass.type; |
+ ClassElementImpl MClass = ElementFactory.classElement2('M', ["T"]); |
+ DartType typeParam = MClass.typeParameters[0].type; |
+ InterfaceType superType = LType.substitute4(<DartType>[typeParam]); |
+ MClass.interfaces = <InterfaceType>[superType]; |
+ InterfaceType MType = MClass.type; |
+ |
+ InterfaceType top = LType.substitute4(<DartType>[dynamicType]); |
+ InterfaceType left = MType.substitute4(<DartType>[dynamicType]); |
+ InterfaceType right = LType.substitute4(<DartType>[intType]); |
+ InterfaceType bottom = MType.substitute4(<DartType>[intType]); |
+ |
+ _checkCrossLattice(top, left, right, bottom); |
+ } |
+ |
+ void _checkCrossLattice( |
+ DartType top, DartType left, DartType right, DartType bottom) { |
+ _checkGroups(top, interassignable: <DartType>[top, left, right, bottom]); |
+ _checkGroups(left, interassignable: <DartType>[top, left, right, bottom]); |
+ _checkGroups(right, interassignable: <DartType>[top, left, right, bottom]); |
+ _checkGroups(bottom, interassignable: <DartType>[top, left, right, bottom]); |
+ } |
+ |
+ 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 _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 _checkUnrelated(DartType type1, DartType type2) { |
+ _checkIsNotAssignableTo(type1, type2); |
+ _checkIsNotAssignableTo(type2, type1); |
+ } |
+ |
+ void _checkEquivalent(DartType type1, DartType type2) { |
+ _checkIsAssignableTo(type1, type2); |
+ _checkIsAssignableTo(type2, type1); |
+ } |
+ |
+ void _checkIsStrictAssignableTo(DartType type1, DartType type2) { |
+ _checkIsAssignableTo(type1, type2); |
+ _checkIsNotAssignableTo(type2, type1); |
+ } |
+ |
+ void _checkIsAssignableTo(DartType type1, DartType type2) { |
+ expect(typeSystem.isAssignableTo(type1, type2), true); |
+ } |
+ |
+ void _checkIsNotAssignableTo(DartType type1, DartType type2) { |
+ expect(typeSystem.isAssignableTo(type1, type2), false); |
+ } |
+} |