| // 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; |
| |
| _checkIsAssignableTo(top, bottom); |
| } |
| |
| 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); |
| } |
| } |