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

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

Issue 1807213005: Use GLB for function parameters when doing LUB in strong mode. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);
}
}

Powered by Google App Engine
This is Rietveld 408576698