Chromium Code Reviews| 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 c24297f2860b05a1763d94921daa9076a28485f4..6700c6858af39924daae6cf95ff8b076be5ea117 100644 |
| --- a/pkg/analyzer/test/generated/type_system_test.dart |
| +++ b/pkg/analyzer/test/generated/type_system_test.dart |
| @@ -10,6 +10,7 @@ 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:analyzer/src/generated/utilities_dart.dart'; |
| import 'package:unittest/unittest.dart'; |
| import '../reflective_tests.dart'; |
| @@ -18,6 +19,8 @@ import '../utils.dart'; |
| main() { |
| initializeTestEnvironment(); |
| runReflectiveTests(TypeSystemTest); |
| + runReflectiveTests(StrongSubtypingTest); |
| + runReflectiveTests(StrongAssignabilityTest); |
| } |
| @reflectiveTest |
| @@ -39,7 +42,7 @@ class TypeSystemTest { |
| void setUp() { |
| typeProvider = new TestTypeProvider(); |
| - typeSystem = new TypeSystemImpl(typeProvider); |
| + typeSystem = new TypeSystemImpl(); |
| FunctionTypeAliasElementImpl typeAlias = |
| ElementFactory.functionTypeAliasElement('A'); |
| typeAlias.parameters = []; |
| @@ -160,14 +163,21 @@ class TypeSystemTest { |
| DartType typeParam = ElementFactory.typeParameterElement('T').type; |
| DartType interfaceType = ElementFactory.classElement2('A', []).type; |
| expect( |
| - typeSystem.getLeastUpperBound(dynamicType, dynamicType), dynamicType); |
| - expect(typeSystem.getLeastUpperBound(voidType, voidType), voidType); |
| - expect(typeSystem.getLeastUpperBound(bottomType, bottomType), bottomType); |
| - expect(typeSystem.getLeastUpperBound(typeParam, typeParam), typeParam); |
| - expect(typeSystem.getLeastUpperBound(interfaceType, interfaceType), |
| + 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(simpleFunctionType, simpleFunctionType), |
| + typeSystem.getLeastUpperBound( |
| + typeProvider, simpleFunctionType, simpleFunctionType), |
| simpleFunctionType); |
| } |
| @@ -329,7 +339,9 @@ class TypeSystemTest { |
| // List<int> |
| // |
| InterfaceType listOfIntType = listType.substitute4(<DartType>[intType]); |
| - expect(typeSystem.getLeastUpperBound(listOfIntType, listOfIntType), |
| + expect( |
| + typeSystem.getLeastUpperBound( |
| + typeProvider, listOfIntType, listOfIntType), |
| listOfIntType); |
| } |
| @@ -353,6 +365,592 @@ class TypeSystemTest { |
| void _checkLeastUpperBound( |
| DartType type1, DartType type2, DartType expectedResult) { |
| - expect(typeSystem.getLeastUpperBound(type1, type2), expectedResult); |
| + expect(typeSystem.getLeastUpperBound(typeProvider, type1, type2), |
| + expectedResult); |
| + } |
| +} |
| + |
| +class TypeBuilder { |
| + static FunctionType functionType( |
|
Brian Wilkerson
2015/09/16 14:00:45
nit: Seems like something that could go in Element
Leaf
2015/09/16 21:07:55
Done.
|
| + List<DartType> parameters, DartType returnType, |
| + {List<DartType> optional, Map<String, DartType> named}) { |
| + List<ParameterElement> parameterElements = new List<ParameterElement>(); |
| + for (int i = 0; i < parameters.length; i++) { |
| + ParameterElementImpl parameterElement = |
| + new ParameterElementImpl("a$i", i); |
| + parameterElement.type = parameters[i]; |
| + parameterElement.parameterKind = ParameterKind.REQUIRED; |
| + parameterElements.add(parameterElement); |
| + } |
| + if (optional != null) { |
| + int j = parameters.length; |
| + for (int i = 0; i < optional.length; i++) { |
| + ParameterElementImpl parameterElement = |
| + new ParameterElementImpl("o$i", j); |
| + parameterElement.type = optional[i]; |
| + parameterElement.parameterKind = ParameterKind.POSITIONAL; |
| + parameterElements.add(parameterElement); |
| + j++; |
| + } |
| + } else if (named != null) { |
| + int j = parameters.length; |
| + for (String s in named.keys) { |
| + ParameterElementImpl parameterElement = new ParameterElementImpl(s, j); |
| + parameterElement.type = named[s]; |
| + parameterElement.parameterKind = ParameterKind.NAMED; |
| + parameterElements.add(parameterElement); |
| + } |
| + } |
| + |
| + FunctionElementImpl element = ElementFactory.functionElementWithParameters( |
| + "f", returnType, parameterElements); |
| + return element.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); |
| } |
| } |