Index: pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart |
diff --git a/pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart b/pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c48d397c94ffc3c78a3e93011620f1bfcdaea631 |
--- /dev/null |
+++ b/pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart |
@@ -0,0 +1,487 @@ |
+// Copyright (c) 2017, 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. |
+ |
+import 'package:front_end/src/fasta/type_inference/type_schema.dart'; |
+import 'package:front_end/src/fasta/type_inference/type_schema_environment.dart'; |
+import 'package:kernel/ast.dart'; |
+import 'package:kernel/class_hierarchy.dart'; |
+import 'package:kernel/core_types.dart'; |
+import 'package:kernel/testing/mock_sdk_program.dart'; |
+import 'package:test/test.dart'; |
+import 'package:test_reflective_loader/test_reflective_loader.dart'; |
ahe
2017/05/02 18:32:56
Why do we need to use this for new tests?
Paul Berry
2017/05/03 17:31:25
test_reflective_loader has two big advantages over
|
+ |
+main() { |
+ defineReflectiveSuite(() { |
+ defineReflectiveTests(TypeSchemaEnvironmentTest); |
+ }); |
+} |
+ |
+@reflectiveTest |
+class TypeSchemaEnvironmentTest { |
+ static const UnknownType unknownType = const UnknownType(); |
+ |
+ static const DynamicType dynamicType = const DynamicType(); |
+ |
+ static const VoidType voidType = const VoidType(); |
+ |
+ static const BottomType bottomType = const BottomType(); |
+ |
+ final testLib = new Library(Uri.parse('file:///test.dart')); |
ahe
2017/05/02 18:32:56
Dummy URL, for example, org-dartlang:///test.dart.
Paul Berry
2017/05/03 17:31:25
Done.
|
+ |
+ Program program; |
+ |
+ CoreTypes coreTypes; |
+ |
+ TypeSchemaEnvironmentTest() { |
+ program = createMockSdkProgram(); |
+ program.libraries.add(testLib..parent = program); |
+ coreTypes = new CoreTypes(program); |
+ } |
+ |
+ InterfaceType get doubleType => coreTypes.doubleClass.rawType; |
+ |
+ InterfaceType get functionType => coreTypes.functionClass.rawType; |
+ |
+ InterfaceType get intType => coreTypes.intClass.rawType; |
+ |
+ Class get iterableClass => coreTypes.iterableClass; |
+ |
+ Class get listClass => coreTypes.listClass; |
+ |
+ Class get mapClass => coreTypes.mapClass; |
+ |
+ InterfaceType get numType => coreTypes.numClass.rawType; |
+ |
+ Class get objectClass => coreTypes.objectClass; |
+ |
+ InterfaceType get objectType => objectClass.rawType; |
+ |
+ void test_glb_bottom() { |
+ var A = _addClass(_class('A')).rawType; |
+ var env = _makeEnv(); |
+ expect(env.getGreatestLowerBound(bottomType, A), same(bottomType)); |
+ expect(env.getGreatestLowerBound(A, bottomType), same(bottomType)); |
+ } |
+ |
+ void test_glb_function() { |
+ var A = _addClass(_class('A')).rawType; |
+ var B = |
+ _addClass(_class('B', supertype: A.classNode.asThisSupertype)).rawType; |
+ var env = _makeEnv(); |
+ // GLB(() -> A, () -> B) = () -> B |
+ expect( |
+ env.getGreatestLowerBound( |
+ new FunctionType([], A), new FunctionType([], B)), |
+ new FunctionType([], B)); |
+ // GLB(() -> void, (A, B) -> void) = ([A, B]) -> void |
+ expect( |
+ env.getGreatestLowerBound( |
+ new FunctionType([], voidType), new FunctionType([A, B], voidType)), |
+ new FunctionType([A, B], voidType, requiredParameterCount: 0)); |
+ expect( |
+ env.getGreatestLowerBound( |
+ new FunctionType([A, B], voidType), new FunctionType([], voidType)), |
+ new FunctionType([A, B], voidType, requiredParameterCount: 0)); |
+ // GLB((A) -> void, (B) -> void) = (A) -> void |
+ expect( |
+ env.getGreatestLowerBound( |
+ new FunctionType([A], voidType), new FunctionType([B], voidType)), |
+ new FunctionType([A], voidType)); |
+ expect( |
+ env.getGreatestLowerBound( |
+ new FunctionType([B], voidType), new FunctionType([A], voidType)), |
+ new FunctionType([A], voidType)); |
+ // GLB(({a: A}) -> void, ({b: B}) -> void) = ({a: A, b: B}) -> void |
+ expect( |
+ env.getGreatestLowerBound( |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('a', A)]), |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('b', B)])), |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('a', A), new NamedType('b', B)])); |
+ expect( |
+ env.getGreatestLowerBound( |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('b', B)]), |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('a', A)])), |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('a', A), new NamedType('b', B)])); |
+ // GLB(({a: A, c: A}) -> void, ({b: B, d: B}) -> void) |
+ // = ({a: A, b: B, c: A, d: B}) -> void |
+ expect( |
+ env.getGreatestLowerBound( |
+ new FunctionType([], voidType, |
+ namedParameters: [ |
+ new NamedType('a', A), |
+ new NamedType('c', A) |
+ ]), |
+ new FunctionType([], voidType, |
+ namedParameters: [ |
+ new NamedType('b', B), |
+ new NamedType('d', B) |
+ ])), |
+ new FunctionType([], voidType, |
+ namedParameters: [ |
+ new NamedType('a', A), |
+ new NamedType('b', B), |
+ new NamedType('c', A), |
+ new NamedType('d', B) |
+ ])); |
+ // GLB(({a: A, b: B}) -> void, ({a: B, b: A}) -> void) |
+ // = ({a: A, b: A}) -> void |
+ expect( |
+ env.getGreatestLowerBound( |
+ new FunctionType([], voidType, |
+ namedParameters: [ |
+ new NamedType('a', A), |
+ new NamedType('b', B) |
+ ]), |
+ new FunctionType([], voidType, |
+ namedParameters: [ |
+ new NamedType('a', B), |
+ new NamedType('b', A) |
+ ])), |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('a', A), new NamedType('b', A)])); |
+ expect( |
+ env.getGreatestLowerBound( |
+ new FunctionType([], voidType, |
+ namedParameters: [ |
+ new NamedType('a', B), |
+ new NamedType('b', A) |
+ ]), |
+ new FunctionType([], voidType, |
+ namedParameters: [ |
+ new NamedType('a', A), |
+ new NamedType('b', B) |
+ ])), |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('a', A), new NamedType('b', A)])); |
+ // GLB((B, {a: A}) -> void, (B) -> void) = (B, {a: A}) -> void |
+ expect( |
+ env.getGreatestLowerBound( |
+ new FunctionType([B], voidType, |
+ namedParameters: [new NamedType('a', A)]), |
+ new FunctionType([B], voidType)), |
+ new FunctionType([B], voidType, |
+ namedParameters: [new NamedType('a', A)])); |
+ // GLB(({a: A}) -> void, (B) -> void) = bottom |
+ expect( |
+ env.getGreatestLowerBound( |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('a', A)]), |
+ new FunctionType([B], voidType)), |
+ same(bottomType)); |
+ // GLB(({a: A}) -> void, ([B]) -> void) = bottom |
+ expect( |
+ env.getGreatestLowerBound( |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('a', A)]), |
+ new FunctionType([B], voidType, requiredParameterCount: 0)), |
+ same(bottomType)); |
+ } |
+ |
+ void test_glb_identical() { |
+ var A = _addClass(_class('A')).rawType; |
+ var env = _makeEnv(); |
+ expect(env.getGreatestLowerBound(A, A), same(A)); |
ahe
2017/05/02 18:32:56
You may want to also test this variant:
Class aCl
Paul Berry
2017/05/03 17:31:25
Done. I made a similar addition to the LUB test.
|
+ } |
+ |
+ void test_glb_subtype() { |
+ var A = _addClass(_class('A')).rawType; |
+ var B = |
+ _addClass(_class('B', supertype: A.classNode.asThisSupertype)).rawType; |
+ var env = _makeEnv(); |
+ expect(env.getGreatestLowerBound(A, B), same(B)); |
+ expect(env.getGreatestLowerBound(B, A), same(B)); |
+ } |
+ |
+ void test_glb_top() { |
+ var A = _addClass(_class('A')).rawType; |
+ var env = _makeEnv(); |
+ expect(env.getGreatestLowerBound(dynamicType, A), same(A)); |
+ expect(env.getGreatestLowerBound(A, dynamicType), same(A)); |
+ expect(env.getGreatestLowerBound(objectType, A), same(A)); |
+ expect(env.getGreatestLowerBound(A, objectType), same(A)); |
+ expect(env.getGreatestLowerBound(voidType, A), same(A)); |
+ expect(env.getGreatestLowerBound(A, voidType), same(A)); |
+ } |
+ |
+ void test_glb_unknown() { |
+ var A = _addClass(_class('A')).rawType; |
+ var env = _makeEnv(); |
+ expect(env.getGreatestLowerBound(A, unknownType), same(A)); |
+ expect(env.getGreatestLowerBound(unknownType, A), same(A)); |
+ } |
+ |
+ void test_glb_unrelated() { |
+ var A = _addClass(_class('A')).rawType; |
+ var B = _addClass(_class('B')).rawType; |
+ var env = _makeEnv(); |
+ expect(env.getGreatestLowerBound(A, B), same(bottomType)); |
+ } |
+ |
+ void test_lub_bottom() { |
+ var A = _addClass(_class('A')).rawType; |
+ var env = _makeEnv(); |
+ expect(env.getLeastUpperBound(bottomType, A), same(A)); |
+ expect(env.getLeastUpperBound(A, bottomType), same(A)); |
+ } |
+ |
+ void test_lub_classic() { |
+ // Make the class hierarchy: |
+ // |
+ // Object |
+ // | |
+ // A |
+ // /| |
+ // B C |
+ // |X| |
+ // D E |
+ var A = _addClass(_class('A')).rawType; |
+ var B = |
+ _addClass(_class('B', supertype: A.classNode.asThisSupertype)).rawType; |
+ var C = |
+ _addClass(_class('C', supertype: A.classNode.asThisSupertype)).rawType; |
+ var D = _addClass(_class('D', implementedTypes: [ |
+ B.classNode.asThisSupertype, |
+ C.classNode.asThisSupertype |
+ ])).rawType; |
+ var E = _addClass(_class('E', implementedTypes: [ |
+ B.classNode.asThisSupertype, |
+ C.classNode.asThisSupertype |
+ ])).rawType; |
+ var env = _makeEnv(); |
+ expect(env.getLeastUpperBound(D, E), A); |
+ } |
+ |
+ void test_lub_commonClass() { |
+ var env = _makeEnv(); |
+ expect(env.getLeastUpperBound(_list(intType), _list(doubleType)), |
+ _list(numType)); |
+ } |
+ |
+ void test_lub_function() { |
+ var A = _addClass(_class('A')).rawType; |
+ var B = |
+ _addClass(_class('B', supertype: A.classNode.asThisSupertype)).rawType; |
+ var env = _makeEnv(); |
+ // LUB(() -> A, () -> B) = () -> A |
+ expect( |
+ env.getLeastUpperBound( |
+ new FunctionType([], A), new FunctionType([], B)), |
+ new FunctionType([], A)); |
+ // LUB(([A]) -> void, (A) -> void) = Function |
+ expect( |
+ env.getLeastUpperBound( |
+ new FunctionType([A], voidType, requiredParameterCount: 0), |
+ new FunctionType([A], voidType)), |
+ functionType); |
+ // LUB(() -> void, (A, B) -> void) = Function |
+ expect( |
+ env.getLeastUpperBound( |
+ new FunctionType([], voidType), new FunctionType([A, B], voidType)), |
+ functionType); |
+ expect( |
+ env.getLeastUpperBound( |
+ new FunctionType([A, B], voidType), new FunctionType([], voidType)), |
+ functionType); |
+ // LUB((A) -> void, (B) -> void) = (B) -> void |
+ expect( |
+ env.getLeastUpperBound( |
+ new FunctionType([A], voidType), new FunctionType([B], voidType)), |
+ new FunctionType([B], voidType)); |
+ expect( |
+ env.getLeastUpperBound( |
+ new FunctionType([B], voidType), new FunctionType([A], voidType)), |
+ new FunctionType([B], voidType)); |
+ // LUB(({a: A}) -> void, ({b: B}) -> void) = () -> void |
+ expect( |
+ env.getLeastUpperBound( |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('a', A)]), |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('b', B)])), |
+ new FunctionType([], voidType)); |
+ expect( |
+ env.getLeastUpperBound( |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('b', B)]), |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('a', A)])), |
+ new FunctionType([], voidType)); |
+ // LUB(({a: A, c: A}) -> void, ({b: B, d: B}) -> void) = () -> void |
+ expect( |
+ env.getLeastUpperBound( |
+ new FunctionType([], voidType, |
+ namedParameters: [ |
+ new NamedType('a', A), |
+ new NamedType('c', A) |
+ ]), |
+ new FunctionType([], voidType, |
+ namedParameters: [ |
+ new NamedType('b', B), |
+ new NamedType('d', B) |
+ ])), |
+ new FunctionType([], voidType)); |
+ // LUB(({a: A, b: B}) -> void, ({a: B, b: A}) -> void) |
+ // = ({a: B, b: B}) -> void |
+ expect( |
+ env.getLeastUpperBound( |
+ new FunctionType([], voidType, |
+ namedParameters: [ |
+ new NamedType('a', A), |
+ new NamedType('b', B) |
+ ]), |
+ new FunctionType([], voidType, |
+ namedParameters: [ |
+ new NamedType('a', B), |
+ new NamedType('b', A) |
+ ])), |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('a', B), new NamedType('b', B)])); |
+ expect( |
+ env.getLeastUpperBound( |
+ new FunctionType([], voidType, |
+ namedParameters: [ |
+ new NamedType('a', B), |
+ new NamedType('b', A) |
+ ]), |
+ new FunctionType([], voidType, |
+ namedParameters: [ |
+ new NamedType('a', A), |
+ new NamedType('b', B) |
+ ])), |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('a', B), new NamedType('b', B)])); |
+ // LUB((B, {a: A}) -> void, (B) -> void) = (B) -> void |
+ expect( |
+ env.getLeastUpperBound( |
+ new FunctionType([B], voidType, |
+ namedParameters: [new NamedType('a', A)]), |
+ new FunctionType([B], voidType)), |
+ new FunctionType([B], voidType)); |
+ // LUB(({a: A}) -> void, (B) -> void) = Function |
+ expect( |
+ env.getLeastUpperBound( |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('a', A)]), |
+ new FunctionType([B], voidType)), |
+ functionType); |
+ // GLB(({a: A}) -> void, ([B]) -> void) = () -> void |
+ expect( |
+ env.getLeastUpperBound( |
+ new FunctionType([], voidType, |
+ namedParameters: [new NamedType('a', A)]), |
+ new FunctionType([B], voidType, requiredParameterCount: 0)), |
+ new FunctionType([], voidType)); |
+ } |
+ |
+ void test_lub_identical() { |
+ var A = _addClass(_class('A')).rawType; |
+ var env = _makeEnv(); |
+ expect(env.getLeastUpperBound(A, A), same(A)); |
+ } |
+ |
+ void test_lub_sameClass() { |
+ var A = _addClass(_class('A')).rawType; |
+ var B = |
+ _addClass(_class('B', supertype: A.classNode.asThisSupertype)).rawType; |
+ var env = _makeEnv(); |
+ expect(env.getLeastUpperBound(_map(A, B), _map(B, A)), _map(A, A)); |
+ } |
+ |
+ void test_lub_subtype() { |
+ var env = _makeEnv(); |
+ expect(env.getLeastUpperBound(_list(intType), _iterable(numType)), |
+ _iterable(numType)); |
+ expect(env.getLeastUpperBound(_iterable(numType), _list(intType)), |
+ _iterable(numType)); |
+ } |
+ |
+ void test_lub_top() { |
+ var A = _addClass(_class('A')).rawType; |
+ var env = _makeEnv(); |
+ expect(env.getLeastUpperBound(dynamicType, A), same(dynamicType)); |
+ expect(env.getLeastUpperBound(A, dynamicType), same(dynamicType)); |
+ expect(env.getLeastUpperBound(objectType, A), same(objectType)); |
+ expect(env.getLeastUpperBound(A, objectType), same(objectType)); |
+ expect(env.getLeastUpperBound(voidType, A), same(voidType)); |
+ expect(env.getLeastUpperBound(A, voidType), same(voidType)); |
+ expect(env.getLeastUpperBound(dynamicType, objectType), same(dynamicType)); |
+ // TODO(paulberry): see dartbug.com/28513. |
+ expect(env.getLeastUpperBound(objectType, dynamicType), same(objectType)); |
+ expect(env.getLeastUpperBound(dynamicType, voidType), same(dynamicType)); |
+ expect(env.getLeastUpperBound(voidType, dynamicType), same(dynamicType)); |
+ expect(env.getLeastUpperBound(objectType, voidType), same(voidType)); |
+ expect(env.getLeastUpperBound(voidType, objectType), same(voidType)); |
+ } |
+ |
+ void test_lub_typeParameter() { |
+ var T = new TypeParameterType(new TypeParameter('T')); |
+ T.parameter.bound = _list(T); |
+ var U = new TypeParameterType(new TypeParameter('U')); |
+ U.parameter.bound = _list(bottomType); |
+ var env = _makeEnv(); |
+ // LUB(T, T) = T |
+ expect(env.getLeastUpperBound(T, T), same(T)); |
+ // LUB(T, List<Bottom>) = LUB(List<Object>, List<Bottom>) = List<Object> |
+ expect(env.getLeastUpperBound(T, _list(bottomType)), _list(objectType)); |
+ expect(env.getLeastUpperBound(_list(bottomType), T), _list(objectType)); |
+ // LUB(T, U) = LUB(List<Object>, U) = LUB(List<Object>, List<Bottom>) |
+ // = List<Object> |
+ expect(env.getLeastUpperBound(T, U), _list(objectType)); |
+ expect(env.getLeastUpperBound(U, T), _list(objectType)); |
+ } |
+ |
+ void test_lub_unknown() { |
+ var A = _addClass(_class('A')).rawType; |
+ var env = _makeEnv(); |
+ expect(env.getGreatestLowerBound(A, unknownType), same(A)); |
+ expect(env.getGreatestLowerBound(unknownType, A), same(A)); |
+ } |
+ |
+ void test_unknown_at_bottom() { |
+ var A = _addClass(_class('A')).rawType; |
+ var env = _makeEnv(); |
+ expect(env.isSubtypeOf(unknownType, A), isTrue); |
+ } |
+ |
+ void test_unknown_at_top() { |
+ var A = _addClass(_class('A')).rawType; |
+ var env = _makeEnv(); |
+ expect(env.isSubtypeOf(A, unknownType), isTrue); |
+ } |
+ |
+ Class _addClass(Class c) { |
+ testLib.addClass(c); |
+ return c; |
+ } |
+ |
+ Class _class(String name, |
+ {Supertype supertype, |
+ List<TypeParameter> typeParameters, |
+ List<Supertype> implementedTypes}) { |
+ return new Class( |
+ name: name, |
+ supertype: supertype ?? objectClass.asThisSupertype, |
+ typeParameters: typeParameters, |
+ implementedTypes: implementedTypes); |
+ } |
+ |
+ DartType _iterable(DartType elementType) => |
+ new InterfaceType(iterableClass, [elementType]); |
+ |
+ DartType _list(DartType elementType) => |
+ new InterfaceType(listClass, [elementType]); |
+ |
+ TypeSchemaEnvironment _makeEnv() { |
+ return new TypeSchemaEnvironment(coreTypes, new ClassHierarchy(program)); |
+ } |
+ |
+ DartType _map(DartType key, DartType value) => |
+ new InterfaceType(mapClass, [key, value]); |
+} |