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 fe69d2c06a63d6b12e18d59185599404670c55fd..55c1fb1431b1cb8c60f28c6c13c51854fa102bc4 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/dart/element/element.dart'; |
import 'package:analyzer/dart/element/type.dart'; |
import 'package:analyzer/src/dart/element/element.dart'; |
import 'package:analyzer/src/dart/element/type.dart'; |
+import 'package:analyzer/src/generated/engine.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'; |
@@ -17,6 +18,7 @@ import 'package:unittest/unittest.dart'; |
import '../reflective_tests.dart'; |
import '../utils.dart'; |
+import 'analysis_context_factory.dart'; |
main() { |
initializeTestEnvironment(); |
@@ -24,6 +26,8 @@ main() { |
runReflectiveTests(StrongSubtypingTest); |
runReflectiveTests(StrongGenericFunctionInferenceTest); |
runReflectiveTests(LeastUpperBoundTest); |
+ runReflectiveTests(StrongLeastUpperBoundTest); |
+ runReflectiveTests(StrongGreatestLowerBoundTest); |
} |
@reflectiveTest |
@@ -924,8 +928,10 @@ class TypeBuilder { |
ElementFactory.typeParameterWithType(name, bound).type; |
} |
-@reflectiveTest |
-class LeastUpperBoundTest { |
+/** |
+ * Base class for testing LUB and GLB in spec and strong mode. |
+ */ |
+abstract class BoundTestBase { |
TypeProvider typeProvider; |
TypeSystem typeSystem; |
FunctionType simpleFunctionType; |
@@ -941,9 +947,12 @@ class LeastUpperBoundTest { |
InterfaceType get stringType => typeProvider.stringType; |
DartType get voidType => VoidTypeImpl.instance; |
+ StrongTypeSystemImpl get strongTypeSystem => |
+ typeSystem as StrongTypeSystemImpl; |
+ |
void setUp() { |
- typeProvider = new TestTypeProvider(); |
- typeSystem = new TypeSystemImpl(); |
+ InternalAnalysisContext context = AnalysisContextFactory.contextWithCore(); |
+ typeProvider = context.typeProvider; |
FunctionTypeAliasElementImpl typeAlias = |
ElementFactory.functionTypeAliasElement('A'); |
typeAlias.parameters = []; |
@@ -951,6 +960,43 @@ class LeastUpperBoundTest { |
simpleFunctionType = typeAlias.type; |
} |
+ /** |
+ * Creates a function type with the given parameter and return types. |
+ * |
+ * The return type defaults to `void` if omitted. |
+ */ |
+ FunctionType _functionType(List<DartType> required, |
Leaf
2016/03/22 00:02:20
There's another version of this code in the TypeBu
|
+ {List<DartType> optional, |
+ Map<String, DartType> named, |
+ DartType returns}) { |
+ if (returns == null) { |
+ returns = voidType; |
+ } |
+ |
+ return ElementFactory |
+ .functionElement8(required, returns, optional: optional, named: named) |
+ .type; |
+ } |
+ |
+ void _checkLeastUpperBound( |
+ DartType type1, DartType type2, DartType expectedResult) { |
+ expect(typeSystem.getLeastUpperBound(typeProvider, type1, type2), |
+ expectedResult); |
+ } |
+ |
+ void _checkGreatestLowerBound( |
+ DartType type1, DartType type2, DartType expectedResult) { |
+ expect(strongTypeSystem.getGreatestLowerBound(typeProvider, type1, type2), |
+ expectedResult); |
+ } |
+} |
+ |
+/** |
+ * Base class for testing LUB in spec and strong mode. |
+ * Defines helper functions and tests. Tests here are ones whose behavior is |
+ * the same in strong and spec mode. |
+ */ |
+abstract class LeastUpperBoundTestBase extends BoundTestBase { |
void test_bottom_function() { |
_checkLeastUpperBound(bottomType, simpleFunctionType, simpleFunctionType); |
} |
@@ -966,11 +1012,9 @@ class LeastUpperBoundTest { |
} |
void test_directInterfaceCase() { |
- // |
// class A |
// class B implements A |
// class C implements B |
- // |
ClassElementImpl classA = ElementFactory.classElement2("A"); |
ClassElementImpl classB = ElementFactory.classElement2("B"); |
ClassElementImpl classC = ElementFactory.classElement2("C"); |
@@ -983,11 +1027,9 @@ class LeastUpperBoundTest { |
} |
void test_directSubclassCase() { |
- // |
// class A |
// class B extends A |
// class C extends B |
- // |
ClassElementImpl classA = ElementFactory.classElement2("A"); |
ClassElementImpl classB = ElementFactory.classElement("B", classA.type); |
ClassElementImpl classC = ElementFactory.classElement("C", classB.type); |
@@ -1024,12 +1066,10 @@ class LeastUpperBoundTest { |
} |
void test_mixinCase() { |
- // |
// class A |
// class B extends A |
// class C extends A |
// class D extends B with M, N, O, P |
- // |
ClassElement classA = ElementFactory.classElement2("A"); |
ClassElement classB = ElementFactory.classElement("B", classA.type); |
ClassElement classC = ElementFactory.classElement("C", classA.type); |
@@ -1220,10 +1260,8 @@ class LeastUpperBoundTest { |
} |
void test_typeParameters_different() { |
- // |
// class List<int> |
// class List<double> |
- // |
InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]); |
InterfaceType listOfDoubleType = |
listType.instantiate(<DartType>[doubleType]); |
@@ -1231,15 +1269,10 @@ class LeastUpperBoundTest { |
} |
void test_typeParameters_same() { |
- // |
// List<int> |
// List<int> |
- // |
InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]); |
- expect( |
- typeSystem.getLeastUpperBound( |
- typeProvider, listOfIntType, listOfIntType), |
- listOfIntType); |
+ _checkLeastUpperBound(listOfIntType, listOfIntType, listOfIntType); |
} |
void test_void_bottom() { |
@@ -1276,6 +1309,56 @@ class LeastUpperBoundTest { |
_checkLeastUpperBound(type1, type2, functionType); |
} |
+ void test_functionsIgnoreExtraPositionalParams() { |
+ FunctionType type1 = |
+ _functionType([], optional: [intType, intType, stringType]); |
+ FunctionType type2 = _functionType([], optional: [intType]); |
+ FunctionType expected = _functionType([], optional: [intType]); |
+ _checkLeastUpperBound(type1, type2, expected); |
+ } |
+ |
+ void test_functionsIgnoreExtraNamedParams() { |
+ FunctionType type1 = _functionType([], named: {'a': intType, 'b': intType}); |
+ FunctionType type2 = _functionType([], named: {'a': intType, 'c': intType}); |
+ FunctionType expected = _functionType([], named: {'a': intType}); |
+ _checkLeastUpperBound(type1, type2, expected); |
+ } |
+ |
+ void test_functionsLubReturnType() { |
+ FunctionType type1 = _functionType([], returns: intType); |
+ FunctionType type2 = _functionType([], returns: doubleType); |
+ FunctionType expected = _functionType([], returns: numType); |
+ _checkLeastUpperBound(type1, type2, expected); |
+ } |
+ |
+ void test_nestedFunctionsLubInnerParamTypes() { |
+ FunctionType type1 = _functionType([ |
+ _functionType([stringType, intType, intType]) |
+ ]); |
+ FunctionType type2 = _functionType([ |
+ _functionType([intType, doubleType, numType]) |
+ ]); |
+ FunctionType expected = _functionType([ |
+ _functionType([objectType, numType, numType]) |
+ ]); |
+ _checkLeastUpperBound(type1, type2, expected); |
+ } |
+} |
+ |
+/** |
+ * Tests LUB in spec mode. |
+ * |
+ * Tests defined in this class are ones whose behavior is spec mode-specific. |
+ * In particular, function parameters are compared using LUB in spec mode, but |
+ * GLB in strong mode. |
+ */ |
+@reflectiveTest |
+class LeastUpperBoundTest extends LeastUpperBoundTestBase { |
+ void setUp() { |
+ typeSystem = new TypeSystemImpl(); |
+ super.setUp(); |
+ } |
+ |
void test_functionsLubRequiredParams() { |
FunctionType type1 = _functionType([stringType, intType, intType]); |
FunctionType type2 = _functionType([intType, doubleType, numType]); |
@@ -1285,66 +1368,348 @@ class LeastUpperBoundTest { |
void test_functionsLubPositionalParams() { |
FunctionType type1 = _functionType([], optional: [stringType, intType]); |
- FunctionType type2 = _functionType([], optional: [intType, doubleType]); |
+ FunctionType type2 = _functionType([], optional: [intType, numType]); |
FunctionType expected = _functionType([], optional: [objectType, numType]); |
_checkLeastUpperBound(type1, type2, expected); |
} |
- void test_functionsIgnoreExtraPositionalParams() { |
+ void test_functionsLubNamedParams() { |
FunctionType type1 = |
- _functionType([], optional: [intType, intType, stringType]); |
- FunctionType type2 = _functionType([], optional: [doubleType]); |
- FunctionType expected = _functionType([], optional: [numType]); |
+ _functionType([], named: {'a': stringType, 'b': intType}); |
+ FunctionType type2 = _functionType([], named: {'a': intType, 'b': numType}); |
+ FunctionType expected = |
+ _functionType([], named: {'a': objectType, 'b': numType}); |
_checkLeastUpperBound(type1, type2, expected); |
} |
- void test_functionsLubNamedParams() { |
+ void test_nestedNestedFunctionsLubInnermostParamTypes() { |
+ FunctionType type1 = _functionType([ |
+ _functionType([ |
+ _functionType([stringType, intType, intType]) |
+ ]) |
+ ]); |
+ FunctionType type2 = _functionType([ |
+ _functionType([ |
+ _functionType([intType, doubleType, numType]) |
+ ]) |
+ ]); |
+ FunctionType expected = _functionType([ |
+ _functionType([ |
+ _functionType([objectType, numType, numType]) |
+ ]) |
+ ]); |
+ _checkLeastUpperBound(type1, type2, expected); |
+ } |
+} |
+ |
+/** |
+ * Tests LUB in strong mode. |
+ * |
+ * Tests defined in this class are ones whose behavior is spec mode-specific. |
Leaf
2016/03/22 00:02:20
s/spec/strong/
|
+ * In particular, function parameters are compared using LUB in spec mode, but |
+ * GLB in strong mode. |
+ */ |
+@reflectiveTest |
+class StrongLeastUpperBoundTest extends LeastUpperBoundTestBase { |
+ void setUp() { |
Leaf
2016/03/22 00:02:20
Can you add tests to both of these checking LUB an
|
+ typeSystem = new StrongTypeSystemImpl(); |
+ super.setUp(); |
+ } |
+ |
+ void test_functionsGlbRequiredParams() { |
+ FunctionType type1 = _functionType([stringType, intType, intType]); |
+ FunctionType type2 = _functionType([intType, doubleType, numType]); |
+ FunctionType expected = _functionType([bottomType, bottomType, intType]); |
+ _checkLeastUpperBound(type1, type2, expected); |
+ } |
+ |
+ void test_functionsGlbPositionalParams() { |
+ FunctionType type1 = _functionType([], optional: [stringType, intType]); |
+ FunctionType type2 = _functionType([], optional: [intType, numType]); |
+ FunctionType expected = _functionType([], optional: [bottomType, intType]); |
+ _checkLeastUpperBound(type1, type2, expected); |
+ } |
+ |
+ void test_functionsGlbNamedParams() { |
FunctionType type1 = |
_functionType([], named: {'a': stringType, 'b': intType}); |
- FunctionType type2 = |
- _functionType([], named: {'a': intType, 'b': doubleType}); |
+ FunctionType type2 = _functionType([], named: {'a': intType, 'b': numType}); |
FunctionType expected = |
- _functionType([], named: {'a': objectType, 'b': numType}); |
+ _functionType([], named: {'a': bottomType, 'b': intType}); |
_checkLeastUpperBound(type1, type2, expected); |
} |
- void test_functionsIgnoreExtraNamedParams() { |
- FunctionType type1 = _functionType([], named: {'a': intType, 'b': intType}); |
- FunctionType type2 = |
- _functionType([], named: {'a': doubleType, 'c': doubleType}); |
- FunctionType expected = _functionType([], named: {'a': numType}); |
+ void test_nestedNestedFunctionsGlbInnermostParamTypes() { |
+ FunctionType type1 = _functionType([ |
+ _functionType([ |
+ _functionType([stringType, intType, intType]) |
+ ]) |
+ ]); |
+ FunctionType type2 = _functionType([ |
+ _functionType([ |
+ _functionType([intType, doubleType, numType]) |
+ ]) |
+ ]); |
+ FunctionType expected = _functionType([ |
+ _functionType([ |
+ _functionType([bottomType, bottomType, intType]) |
+ ]) |
+ ]); |
_checkLeastUpperBound(type1, type2, expected); |
} |
+} |
- void test_functionsLubReturnType() { |
- FunctionType type1 = _functionType([], returns: intType); |
- FunctionType type2 = _functionType([], returns: doubleType); |
+/** |
+ * Tests GLB, which only exists in strong mode. |
+ */ |
+@reflectiveTest |
+class StrongGreatestLowerBoundTest extends BoundTestBase { |
+ void setUp() { |
+ typeSystem = new StrongTypeSystemImpl(); |
+ super.setUp(); |
+ } |
- FunctionType expected = _functionType([], returns: numType); |
- _checkLeastUpperBound(type1, type2, expected); |
+ void test_bottom_function() { |
+ _checkGreatestLowerBound(bottomType, simpleFunctionType, bottomType); |
} |
- /** |
- * Creates a function type with the given parameter and return types. |
- * |
- * The return type defaults to `void` if omitted. |
- */ |
- FunctionType _functionType(List<DartType> required, |
- {List<DartType> optional, |
- Map<String, DartType> named, |
- DartType returns}) { |
- if (returns == null) { |
- returns = voidType; |
+ void test_bottom_interface() { |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ _checkGreatestLowerBound(bottomType, interfaceType, bottomType); |
+ } |
+ |
+ void test_bottom_typeParam() { |
+ DartType typeParam = ElementFactory.typeParameterElement('T').type; |
+ _checkGreatestLowerBound(bottomType, typeParam, bottomType); |
+ } |
+ |
+ void test_classAndSuperinterface() { |
+ // class A |
+ // class B implements A |
+ // class C implements B |
+ ClassElementImpl classA = ElementFactory.classElement2("A"); |
+ ClassElementImpl classB = ElementFactory.classElement2("B"); |
+ ClassElementImpl classC = ElementFactory.classElement2("C"); |
+ classB.interfaces = <InterfaceType>[classA.type]; |
+ classC.interfaces = <InterfaceType>[classB.type]; |
+ _checkGreatestLowerBound(classA.type, classC.type, classC.type); |
+ } |
+ |
+ void test_classAndSuperclass() { |
+ // class A |
+ // class B extends A |
+ // class C extends B |
+ ClassElementImpl classA = ElementFactory.classElement2("A"); |
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type); |
+ ClassElementImpl classC = ElementFactory.classElement("C", classB.type); |
+ _checkGreatestLowerBound(classA.type, classC.type, classC.type); |
+ } |
+ |
+ void test_mixin() { |
+ // class A |
+ // class B |
+ // class C |
+ // class D extends A with B, C |
+ ClassElement classA = ElementFactory.classElement2("A"); |
+ ClassElement classB = ElementFactory.classElement2("B"); |
+ ClassElement classC = ElementFactory.classElement2("C"); |
+ ClassElementImpl classD = ElementFactory.classElement("D", classA.type); |
+ classD.mixins = <InterfaceType>[classB.type, classC.type]; |
+ _checkGreatestLowerBound(classA.type, classD.type, classD.type); |
+ _checkGreatestLowerBound(classB.type, classD.type, classD.type); |
+ _checkGreatestLowerBound(classC.type, classD.type, classD.type); |
+ } |
+ |
+ void test_dynamic_bottom() { |
+ _checkGreatestLowerBound(dynamicType, bottomType, bottomType); |
+ } |
+ |
+ void test_dynamic_function() { |
+ _checkGreatestLowerBound( |
+ dynamicType, simpleFunctionType, simpleFunctionType); |
+ } |
+ |
+ void test_dynamic_interface() { |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ _checkGreatestLowerBound(dynamicType, interfaceType, interfaceType); |
+ } |
+ |
+ void test_dynamic_typeParam() { |
+ DartType typeParam = ElementFactory.typeParameterElement('T').type; |
+ _checkGreatestLowerBound(dynamicType, typeParam, typeParam); |
+ } |
+ |
+ void test_dynamic_void() { |
+ _checkGreatestLowerBound(dynamicType, voidType, voidType); |
+ } |
+ |
+ void test_interface_function() { |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ _checkGreatestLowerBound(interfaceType, simpleFunctionType, bottomType); |
+ } |
+ |
+ void test_unrelatedClasses() { |
+ // class A |
+ // class B |
+ // class C |
+ ClassElementImpl classA = ElementFactory.classElement2("A"); |
+ ClassElementImpl classB = ElementFactory.classElement2("B"); |
+ _checkGreatestLowerBound(classA.type, classB.type, bottomType); |
+ } |
+ |
+ void test_self() { |
+ DartType typeParam = ElementFactory.typeParameterElement('T').type; |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ |
+ List<DartType> types = [ |
+ dynamicType, |
+ voidType, |
+ bottomType, |
+ typeParam, |
+ interfaceType, |
+ simpleFunctionType |
+ ]; |
+ |
+ for (DartType type in types) { |
+ _checkGreatestLowerBound(type, type, type); |
} |
+ } |
- return ElementFactory |
- .functionElement8(required, returns, optional: optional, named: named) |
- .type; |
+ void test_typeParam_function_noBound() { |
+ DartType typeParam = ElementFactory.typeParameterElement('T').type; |
+ _checkGreatestLowerBound(typeParam, simpleFunctionType, simpleFunctionType); |
Leaf
2016/03/22 00:02:20
This should be bottom.
|
} |
- void _checkLeastUpperBound( |
- DartType type1, DartType type2, DartType expectedResult) { |
- expect(typeSystem.getLeastUpperBound(typeProvider, type1, type2), |
- expectedResult); |
+ void test_typeParam_interface_bounded() { |
+ DartType typeA = ElementFactory.classElement2('A', []).type; |
+ DartType typeB = ElementFactory.classElement('B', typeA).type; |
+ DartType typeC = ElementFactory.classElement('C', typeB).type; |
+ TypeParameterElementImpl typeParam = |
+ ElementFactory.typeParameterElement('T'); |
+ typeParam.bound = typeB; |
+ _checkGreatestLowerBound(typeParam.type, typeC, typeC); |
+ } |
+ |
+ void test_typeParam_interface_noBound() { |
+ // GLB(T, A) = A |
+ DartType typeParam = ElementFactory.typeParameterElement('T').type; |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ _checkGreatestLowerBound(typeParam, interfaceType, interfaceType); |
Leaf
2016/03/22 00:02:20
Should be bottom.
|
+ } |
+ |
+ void test_typeParameters_different() { |
+ // GLB(List<int>, List<double>) = ⊥ |
+ InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]); |
+ InterfaceType listOfDoubleType = |
+ listType.instantiate(<DartType>[doubleType]); |
+ // TODO(rnystrom): Can we do something better here? |
+ _checkGreatestLowerBound(listOfIntType, listOfDoubleType, bottomType); |
+ } |
+ |
+ void test_typeParameters_same() { |
+ // GLB(List<int>, List<int>) = List<int> |
+ InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]); |
+ _checkGreatestLowerBound(listOfIntType, listOfIntType, listOfIntType); |
+ } |
+ |
+ void test_void_bottom() { |
+ _checkGreatestLowerBound(voidType, bottomType, bottomType); |
+ } |
+ |
+ void test_void_function() { |
+ _checkGreatestLowerBound(voidType, simpleFunctionType, voidType); |
+ } |
+ |
+ void test_void_interface() { |
+ DartType interfaceType = ElementFactory.classElement2('A', []).type; |
+ _checkGreatestLowerBound(voidType, interfaceType, voidType); |
+ } |
+ |
+ void test_void_typeParam() { |
+ DartType typeParam = ElementFactory.typeParameterElement('T').type; |
+ _checkGreatestLowerBound(voidType, typeParam, voidType); |
+ } |
+ |
+ void test_functionsSameType() { |
+ FunctionType type1 = _functionType([stringType, intType, numType], |
+ optional: [doubleType], named: {'n': numType}, returns: intType); |
+ FunctionType type2 = _functionType([stringType, intType, numType], |
+ optional: [doubleType], named: {'n': numType}, returns: intType); |
+ FunctionType expected = _functionType([stringType, intType, numType], |
+ optional: [doubleType], named: {'n': numType}, returns: intType); |
+ _checkGreatestLowerBound(type1, type2, expected); |
+ } |
+ |
+ void test_functionsLubRequiredParams() { |
+ FunctionType type1 = _functionType([stringType, intType, intType]); |
+ FunctionType type2 = _functionType([intType, doubleType, numType]); |
+ FunctionType expected = _functionType([objectType, numType, numType]); |
+ _checkGreatestLowerBound(type1, type2, expected); |
+ } |
+ |
+ void test_functionsLubPositionalParams() { |
+ FunctionType type1 = _functionType([], optional: [stringType, intType]); |
+ FunctionType type2 = _functionType([], optional: [intType, numType]); |
+ FunctionType expected = _functionType([], optional: [objectType, numType]); |
+ _checkGreatestLowerBound(type1, type2, expected); |
+ } |
+ |
+ void test_functionsLubNamedParams() { |
+ FunctionType type1 = |
+ _functionType([], named: {'a': stringType, 'b': intType}); |
+ FunctionType type2 = _functionType([], named: {'a': intType, 'b': numType}); |
+ FunctionType expected = |
+ _functionType([], named: {'a': objectType, 'b': numType}); |
+ _checkGreatestLowerBound(type1, type2, expected); |
+ } |
+ |
+ void test_functionsGlbReturnType() { |
+ FunctionType type1 = _functionType([], returns: intType); |
+ FunctionType type2 = _functionType([], returns: numType); |
+ FunctionType expected = _functionType([], returns: intType); |
+ _checkGreatestLowerBound(type1, type2, expected); |
+ } |
+ |
+ void test_functionsDifferentRequiredArityBecomeOptional() { |
+ FunctionType type1 = _functionType([intType]); |
+ FunctionType type2 = _functionType([intType, intType, intType]); |
+ FunctionType expected = |
+ _functionType([intType], optional: [intType, intType]); |
+ _checkGreatestLowerBound(type1, type2, expected); |
+ } |
+ |
+ void test_functionsDifferentOptionalArityTakeMax() { |
+ FunctionType type1 = _functionType([], optional: [intType]); |
+ FunctionType type2 = |
+ _functionType([], optional: [doubleType, stringType, objectType]); |
+ FunctionType expected = |
+ _functionType([], optional: [numType, stringType, objectType]); |
+ _checkGreatestLowerBound(type1, type2, expected); |
+ } |
+ |
+ void test_functionsMixedOptionalAndRequiredBecomeOptional() { |
+ FunctionType type1 = _functionType([intType, intType], |
+ optional: [intType, intType, intType]); |
+ FunctionType type2 = _functionType([intType], optional: [intType, intType]); |
+ FunctionType expected = _functionType([intType], |
+ optional: [intType, intType, intType, intType]); |
+ _checkGreatestLowerBound(type1, type2, expected); |
+ } |
+ |
+ void test_functionsDifferentNamedTakeUnion() { |
+ FunctionType type1 = _functionType([], named: {'a': intType, 'b': intType}); |
+ FunctionType type2 = |
+ _functionType([], named: {'b': doubleType, 'c': stringType}); |
+ FunctionType expected = |
+ _functionType([], named: {'a': intType, 'b': numType, 'c': stringType}); |
+ _checkGreatestLowerBound(type1, type2, expected); |
+ } |
+ |
+ void test_functionsReturnBottomIfMixOptionalAndNamed() { |
+ // Dart doesn't allow a function to have both optional and named parameters, |
+ // so if we would have synthethized that, pick bottom instead. |
+ FunctionType type1 = _functionType([intType], named: {'a': intType}); |
+ FunctionType type2 = _functionType([], named: {'a': intType}); |
+ _checkGreatestLowerBound(type1, type2, bottomType); |
} |
} |