Index: pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_test.dart |
diff --git a/pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_test.dart b/pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..97d2a863ce9ce1698370904df7ddb0e505f43f3a |
--- /dev/null |
+++ b/pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_test.dart |
@@ -0,0 +1,172 @@ |
+// 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_constraint_gatherer.dart'; |
+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'; |
+ |
+main() { |
+ defineReflectiveSuite(() { |
+ defineReflectiveTests(TypeConstraintGathererTest); |
+ }); |
+} |
+ |
+@reflectiveTest |
+class TypeConstraintGathererTest { |
+ static const UnknownType unknownType = const UnknownType(); |
+ |
+ static const DynamicType dynamicType = const DynamicType(); |
+ |
+ static const VoidType voidType = const VoidType(); |
+ |
+ final testLib = |
+ new Library(Uri.parse('org-dartlang:///test.dart'), name: 'lib'); |
+ |
+ Program program; |
+ |
+ CoreTypes coreTypes; |
+ |
+ TypeParameterType T1; |
+ |
+ TypeParameterType T2; |
+ |
+ Class classP; |
+ |
+ Class classQ; |
+ |
+ TypeConstraintGathererTest() { |
+ program = createMockSdkProgram(); |
+ program.libraries.add(testLib..parent = program); |
+ coreTypes = new CoreTypes(program); |
+ T1 = new TypeParameterType(new TypeParameter('T1', objectType)); |
+ T2 = new TypeParameterType(new TypeParameter('T2', objectType)); |
+ classP = _addClass(_class('P')); |
+ classQ = _addClass(_class('Q')); |
+ } |
+ |
+ Class get iterableClass => coreTypes.tryGetClass('dart:core', 'Iterable'); |
+ |
+ Class get listClass => coreTypes.listClass; |
+ |
+ Class get mapClass => coreTypes.mapClass; |
+ |
+ InterfaceType get nullType => coreTypes.nullClass.rawType; |
+ |
+ Class get objectClass => coreTypes.objectClass; |
+ |
+ InterfaceType get objectType => objectClass.rawType; |
+ |
+ InterfaceType get P => classP.rawType; |
+ |
+ InterfaceType get Q => classQ.rawType; |
+ |
+ void test_any_subtype_parameter() { |
+ _checkConstraints(Q, T1, ['lib::Q <: T1']); |
+ } |
+ |
+ void test_any_subtype_top() { |
+ _checkConstraints(P, dynamicType, []); |
+ _checkConstraints(P, objectType, []); |
+ _checkConstraints(P, voidType, []); |
+ } |
+ |
+ void test_any_subtype_unknown() { |
+ _checkConstraints(P, unknownType, []); |
+ _checkConstraints(T1, unknownType, []); |
+ } |
+ |
+ void test_different_classes() { |
+ _checkConstraints(_list(T1), _iterable(Q), ['T1 <: lib::Q']); |
+ _checkConstraints(_iterable(T1), _list(Q), null); |
+ } |
+ |
+ void test_equal_types() { |
+ _checkConstraints(P, P, []); |
+ } |
+ |
+ void test_nonInferredParameter_subtype_any() { |
+ var U = new TypeParameterType(new TypeParameter('U', _list(P))); |
+ _checkConstraints(U, _list(T1), ['lib::P <: T1']); |
+ } |
+ |
+ void test_null_subtype_any() { |
+ _checkConstraints(nullType, T1, ['dart.core::Null <: T1']); |
+ _checkConstraints(nullType, Q, []); |
+ } |
+ |
+ void test_parameter_subtype_any() { |
+ _checkConstraints(T1, Q, ['T1 <: lib::Q']); |
+ } |
+ |
+ void test_same_classes() { |
+ _checkConstraints(_list(T1), _list(Q), ['T1 <: lib::Q']); |
+ } |
+ |
+ void test_typeParameters() { |
+ _checkConstraints( |
+ _map(T1, T2), _map(P, Q), ['T1 <: lib::P', 'T2 <: lib::Q']); |
+ } |
+ |
+ void test_unknown_subtype_any() { |
+ _checkConstraints(unknownType, Q, []); |
+ _checkConstraints(unknownType, T1, []); |
+ } |
+ |
+ Class _addClass(Class c) { |
+ testLib.addClass(c); |
+ return c; |
+ } |
+ |
+ void _checkConstraints( |
+ DartType a, DartType b, List<String> expectedConstraints) { |
+ var typeSchemaEnvironment = |
+ new TypeSchemaEnvironment(coreTypes, new ClassHierarchy(program)); |
+ var constraints = |
+ subtypeMatch(typeSchemaEnvironment, [T1.parameter, T2.parameter], a, b); |
+ if (expectedConstraints == null) { |
+ expect(constraints, isNull); |
+ return; |
+ } |
+ var constraintStrings = <String>[]; |
+ constraints.forEach((t, constraint) { |
+ if (constraint.lower is! UnknownType || |
+ constraint.upper is! UnknownType) { |
+ var s = t.name; |
+ if (constraint.lower is! UnknownType) { |
+ s = '${typeSchemaToString(constraint.lower)} <: $s'; |
+ } |
+ if (constraint.upper is! UnknownType) { |
+ s = '$s <: ${typeSchemaToString(constraint.upper)}'; |
+ } |
+ constraintStrings.add(s); |
+ } |
+ }); |
+ expect(constraintStrings, unorderedEquals(expectedConstraints)); |
+ } |
+ |
+ 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 element) => |
+ new InterfaceType(iterableClass, [element]); |
+ |
+ DartType _list(DartType element) => new InterfaceType(listClass, [element]); |
+ |
+ DartType _map(DartType key, DartType value) => |
+ new InterfaceType(mapClass, [key, value]); |
+} |