Copy subtype tests
The tests are copied from pkg/kernel/test/type_subtype_test.dart
Change-Id: I1120aa7ae1928fc20982f24fab14925b9ee851c8
Reviewed-on: https://dart-review.googlesource.com/c/90229
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
diff --git a/pkg/front_end/test/fasta/types/kernel_type_parser.dart b/pkg/front_end/test/fasta/types/kernel_type_parser.dart
index b535020..6ed496b 100644
--- a/pkg/front_end/test/fasta/types/kernel_type_parser.dart
+++ b/pkg/front_end/test/fasta/types/kernel_type_parser.dart
@@ -32,10 +32,11 @@
ParsedVoidType,
Visitor;
-Library parseLibrary(Uri uri, String text, {Uri fileUri}) {
+Library parseLibrary(Uri uri, String text,
+ {Uri fileUri, KernelEnvironment environment}) {
fileUri ??= uri;
+ environment ??= new KernelEnvironment(uri, fileUri);
Library library = new Library(uri, fileUri: fileUri);
- KernelEnvironment environment = new KernelEnvironment(uri, fileUri);
for (ParsedType type in type_parser.parse(text)) {
Node node = environment.kernelFromParsedType(type);
if (node is Class) {
@@ -144,7 +145,14 @@
FunctionType visitFunctionType(
ParsedFunctionType node, KernelEnvironment environment) {
- throw "not implemented: $node";
+ DartType returnType =
+ node.returnType?.accept<Node, KernelEnvironment>(this, environment);
+ List<DartType> arguments = <DartType>[];
+ for (ParsedType argument in node.arguments.required) {
+ arguments
+ .add(argument.accept<Node, KernelEnvironment>(this, environment));
+ }
+ return new FunctionType(arguments, returnType);
}
VoidType visitVoidType(ParsedVoidType node, KernelEnvironment environment) {
diff --git a/pkg/front_end/test/fasta/types/kernel_type_parser_test.dart b/pkg/front_end/test/fasta/types/kernel_type_parser_test.dart
index b348d20..5fbc8a9 100644
--- a/pkg/front_end/test/fasta/types/kernel_type_parser_test.dart
+++ b/pkg/front_end/test/fasta/types/kernel_type_parser_test.dart
@@ -4,13 +4,21 @@
import "package:expect/expect.dart" show Expect;
-import "package:kernel/ast.dart" show Component, Library;
+import "package:kernel/ast.dart" show Component, DartType, Library;
import "package:kernel/class_hierarchy.dart" show ClassHierarchy;
+import "package:kernel/core_types.dart" show CoreTypes;
+
import "package:kernel/text/ast_to_text.dart" show Printer;
-import "kernel_type_parser.dart" show parseLibrary;
+import "package:kernel/type_environment.dart" show TypeEnvironment;
+
+import "kernel_type_parser.dart" show KernelEnvironment, parseLibrary;
+
+import "shared_type_tests.dart" show SubtypeTest;
+
+import "type_parser.dart" as type_parser show parse;
const String testSdk = """
class Object;
@@ -23,6 +31,7 @@
class Future<T>;
class FutureOr<T>;
class Null;
+ class Function;
""";
const String expectedSdk = """
@@ -49,14 +58,39 @@
}
class Null extends self::Object {
}
+class Function extends self::Object {
+}
""";
main() {
- Library library = parseLibrary(Uri.parse("dart:core"), testSdk);
+ Uri uri = Uri.parse("dart:core");
+ KernelEnvironment environment = new KernelEnvironment(uri, uri);
+ Library library = parseLibrary(uri, testSdk, environment: environment);
StringBuffer sb = new StringBuffer();
Printer printer = new Printer(sb);
printer.writeLibraryFile(library);
Expect.stringEquals(expectedSdk, "$sb");
Component component = new Component(libraries: <Library>[library]);
- new ClassHierarchy(component);
+ ClassHierarchy hierarchy = new ClassHierarchy(component);
+ CoreTypes coreTypes = new CoreTypes(component);
+ new KernelSubtypeTest(coreTypes, hierarchy, environment).run();
+}
+
+class KernelSubtypeTest extends SubtypeTest<DartType> {
+ final CoreTypes coreTypes;
+
+ final ClassHierarchy hierarchy;
+
+ final KernelEnvironment environment;
+
+ KernelSubtypeTest(this.coreTypes, this.hierarchy, this.environment);
+
+ DartType toType(String text) {
+ return environment.kernelFromParsedType(type_parser.parse(text).single);
+ }
+
+ bool isSubtypeImpl(DartType subtype, DartType supertype, bool legacyMode) {
+ return new TypeEnvironment(coreTypes, hierarchy, legacyMode: legacyMode)
+ .isSubtypeOf(subtype, supertype);
+ }
}
diff --git a/pkg/front_end/test/fasta/types/shared_type_tests.dart b/pkg/front_end/test/fasta/types/shared_type_tests.dart
new file mode 100644
index 0000000..c57d385
--- /dev/null
+++ b/pkg/front_end/test/fasta/types/shared_type_tests.dart
@@ -0,0 +1,170 @@
+// Copyright (c) 2019, 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:expect/expect.dart" show Expect;
+
+abstract class SubtypeTest<T> {
+ void isSubtype(String subtypeString, String supertypeString,
+ {bool legacyMode: false, String typeParameters}) {
+ T subtype = toType(subtypeString);
+ T supertype = toType(supertypeString);
+ String mode = legacyMode ? " (legacy)" : "";
+ Expect.isTrue(isSubtypeImpl(subtype, supertype, legacyMode),
+ "$subtype should be a subtype of $supertype$mode.");
+ }
+
+ void isNotSubtype(String subtypeString, String supertypeString,
+ {bool legacyMode: false, String typeParameters}) {
+ T subtype = toType(subtypeString);
+ T supertype = toType(supertypeString);
+ String mode = legacyMode ? " (legacy)" : "";
+ Expect.isFalse(isSubtypeImpl(subtype, supertype, legacyMode),
+ "$subtype shouldn't be a subtype of $supertype$mode.");
+ }
+
+ T toType(String text);
+
+ bool isSubtypeImpl(T subtype, T supertype, bool legacyMode);
+
+ void run() {
+ isSubtype('int', 'num', legacyMode: true);
+ isSubtype('int', 'Comparable<num>', legacyMode: true);
+ isSubtype('int', 'Comparable<Object>', legacyMode: true);
+ isSubtype('int', 'Object', legacyMode: true);
+ isSubtype('double', 'num', legacyMode: true);
+
+ isNotSubtype('int', 'double', legacyMode: true);
+ isNotSubtype('int', 'Comparable<int>', legacyMode: true);
+ isNotSubtype('int', 'Iterable<int>', legacyMode: true);
+ isNotSubtype('Comparable<int>', 'Iterable<int>', legacyMode: true);
+
+ isSubtype('List<int>', 'List<int>', legacyMode: true);
+ isSubtype('List<int>', 'Iterable<int>', legacyMode: true);
+ isSubtype('List<int>', 'List<num>', legacyMode: true);
+ isSubtype('List<int>', 'Iterable<num>', legacyMode: true);
+ isSubtype('List<int>', 'List<Object>', legacyMode: true);
+ isSubtype('List<int>', 'Iterable<Object>', legacyMode: true);
+ isSubtype('List<int>', 'Object', legacyMode: true);
+ isSubtype('List<int>', 'List<Comparable<Object>>', legacyMode: true);
+ isSubtype('List<int>', 'List<Comparable<num>>', legacyMode: true);
+ isSubtype('List<int>', 'List<Comparable<Comparable<num>>>',
+ legacyMode: true);
+
+ isNotSubtype('List<int>', 'List<double>', legacyMode: true);
+ isNotSubtype('List<int>', 'Iterable<double>', legacyMode: true);
+ isNotSubtype('List<int>', 'Comparable<int>', legacyMode: true);
+ isNotSubtype('List<int>', 'List<Comparable<int>>', legacyMode: true);
+ isNotSubtype('List<int>', 'List<Comparable<Comparable<int>>>',
+ legacyMode: true);
+
+ isSubtype('(num) -> num', '(int) -> num', legacyMode: true);
+ isSubtype('(num) -> int', '(num) -> num', legacyMode: true);
+ isSubtype('(num) -> int', '(int) -> num', legacyMode: true);
+ isNotSubtype('(int) -> int', '(num) -> num', legacyMode: true);
+
+ isSubtype('(num) -> (num) -> num', '(num) -> (int) -> num',
+ legacyMode: true);
+ isNotSubtype('(num) -> (int) -> int', '(num) -> (num) -> num',
+ legacyMode: true);
+
+ // TODO(ahe): Remove this as the implementation improves.
+ return;
+
+ // ignore: dead_code
+ isSubtype('(x:num) -> num', '(x:int) -> num',
+ legacyMode: true); // named parameters
+ isSubtype('(num,x:num) -> num', '(int,x:int) -> num', legacyMode: true);
+ isSubtype('(x:num) -> int', '(x:num) -> num', legacyMode: true);
+ isNotSubtype('(x:int) -> int', '(x:num) -> num', legacyMode: true);
+
+ isSubtype('<E>(E) -> int', '<E>(E) -> num',
+ legacyMode: true); // type parameters
+ isSubtype('<E>(num) -> E', '<E>(int) -> E', legacyMode: true);
+ isSubtype('<E>(E,num) -> E', '<E>(E,int) -> E', legacyMode: true);
+ isNotSubtype('<E>(E,num) -> E', '<E>(E,E) -> E', legacyMode: true);
+
+ isSubtype('<E>(E) -> (E) -> E', '<F>(F) -> (F) -> F', legacyMode: true);
+ isSubtype('<E>(E, (int,E) -> E) -> E', '<E>(E, (int,E) -> E) -> E',
+ legacyMode: true);
+ isSubtype('<E>(E, (int,E) -> E) -> E', '<E>(E, (num,E) -> E) -> E',
+ legacyMode: true);
+ isNotSubtype('<E,F>(E) -> (F) -> E', '<E>(E) -> <F>(F) -> E',
+ legacyMode: true);
+ isNotSubtype('<E,F>(E) -> (F) -> E', '<F,E>(E) -> (F) -> E',
+ legacyMode: true);
+
+ isNotSubtype('<E>(E,num) -> E', '<E:num>(E,E) -> E', legacyMode: true);
+ isNotSubtype('<E:num>(E) -> int', '<E:int>(E) -> int', legacyMode: true);
+ isNotSubtype('<E:num>(E) -> E', '<E:int>(E) -> E', legacyMode: true);
+ isNotSubtype('<E:num>(int) -> E', '<E:int>(int) -> E', legacyMode: true);
+ isSubtype('<E:num>(E) -> E', '<F:num>(F) -> num', legacyMode: true);
+ isSubtype('<E:int>(E) -> E', '<F:int>(F) -> num', legacyMode: true);
+ isSubtype('<E:int>(E) -> E', '<F:int>(F) -> int', legacyMode: true);
+ isNotSubtype('<E>(int) -> int', '(int) -> int', legacyMode: true);
+ isNotSubtype('<E,F>(int) -> int', '<E>(int) -> int', legacyMode: true);
+
+ isSubtype('<E:List<E>>(E) -> E', '<F:List<F>>(F) -> F', legacyMode: true);
+ isNotSubtype('<E:Iterable<E>>(E) -> E', '<F:List<F>>(F) -> F',
+ legacyMode: true);
+ isNotSubtype('<E>(E,List<Object>) -> E', '<F:List<F>>(F,F) -> F',
+ legacyMode: true);
+ isNotSubtype('<E>(E,List<Object>) -> List<E>', '<F:List<F>>(F,F) -> F',
+ legacyMode: true);
+ isNotSubtype('<E>(E,List<Object>) -> int', '<F:List<F>>(F,F) -> F',
+ legacyMode: true);
+ isNotSubtype('<E>(E,List<Object>) -> E', '<F:List<F>>(F,F) -> void',
+ legacyMode: true);
+
+ isSubtype('int', 'FutureOr<int>');
+ isSubtype('int', 'FutureOr<num>');
+ isSubtype('Future<int>', 'FutureOr<int>');
+ isSubtype('Future<int>', 'FutureOr<num>');
+ isSubtype('Future<int>', 'FutureOr<Object>');
+ isSubtype('FutureOr<int>', 'FutureOr<int>');
+ isSubtype('FutureOr<int>', 'FutureOr<num>');
+ isSubtype('FutureOr<int>', 'Object');
+ isNotSubtype('int', 'FutureOr<double>');
+ isNotSubtype('FutureOr<double>', 'int');
+ isNotSubtype('FutureOr<int>', 'Future<num>');
+ isNotSubtype('FutureOr<int>', 'num');
+
+ // T & B <: T & A if B <: A
+ isSubtype('T & int', 'T & int', legacyMode: true);
+ isSubtype('T & int', 'T & num', legacyMode: true);
+ isSubtype('T & num', 'T & num', legacyMode: true);
+ isNotSubtype('T & num', 'T & int', legacyMode: true);
+
+ // T & B <: T extends A if B <: A
+ // (Trivially satisfied since promoted bounds are always a isSubtype of the
+ // original bound)
+ isSubtype('T & int', 'T', legacyMode: true, typeParameters: 'T: int');
+ isSubtype('T & int', 'T', legacyMode: true, typeParameters: 'T: num');
+ isSubtype('T & num', 'T', legacyMode: true, typeParameters: 'T: num');
+
+ // T extends B <: T & A if B <: A
+ isSubtype('T', 'T & int', legacyMode: true, typeParameters: 'T: int');
+ isSubtype('T', 'T & num', legacyMode: true, typeParameters: 'T: int');
+ isSubtype('T', 'T & num', legacyMode: true, typeParameters: 'T: num');
+ isNotSubtype('T', 'T & int', legacyMode: true, typeParameters: 'T: num');
+
+ // T extends A <: T extends A
+ isSubtype('T', 'T', legacyMode: true, typeParameters: 'T: num');
+
+ // S & B <: A if B <: A, A is not S (or a promotion thereof)
+ isSubtype('S & int', 'int', legacyMode: true);
+ isSubtype('S & int', 'num', legacyMode: true);
+ isSubtype('S & num', 'num', legacyMode: true);
+ isNotSubtype('S & num', 'int', legacyMode: true);
+ isNotSubtype('S & num', 'T', legacyMode: true);
+ isNotSubtype('S & num', 'T & num', legacyMode: true);
+
+ // S extends B <: A if B <: A, A is not S (or a promotion thereof)
+ isSubtype('S', 'int', legacyMode: true, typeParameters: 'S: int');
+ isSubtype('S', 'num', legacyMode: true, typeParameters: 'S: int');
+ isSubtype('S', 'num', legacyMode: true, typeParameters: 'S: num');
+ isNotSubtype('S', 'int', legacyMode: true, typeParameters: 'S: num');
+ isNotSubtype('S', 'T', legacyMode: true, typeParameters: 'S: num');
+ isNotSubtype('S', 'T & num', legacyMode: true, typeParameters: 'S: num');
+ }
+}
diff --git a/pkg/front_end/test/fasta/types/type_parser.dart b/pkg/front_end/test/fasta/types/type_parser.dart
index b1cd825..ec404ec 100644
--- a/pkg/front_end/test/fasta/types/type_parser.dart
+++ b/pkg/front_end/test/fasta/types/type_parser.dart
@@ -4,6 +4,9 @@
import "package:front_end/src/fasta/scanner.dart" show scanString, Token;
+import "package:front_end/src/fasta/parser/type_info_impl.dart"
+ show splitCloser;
+
abstract class ParsedType {
R accept<R, A>(Visitor<R, A> visitor, [A a]);
}
@@ -136,7 +139,14 @@
ParsedTypeVariable(this.name, this.bound);
- String toString() => name;
+ String toString() {
+ if (bound == null) return name;
+ StringBuffer sb = new StringBuffer();
+ sb.write(name);
+ sb.write(" extends ");
+ sb.write(bound);
+ return "$sb";
+ }
R accept<R, A>(Visitor<R, A> visitor, [A a]) {
return visitor.visitTypeVariable(this, a);
@@ -228,6 +238,7 @@
advance();
arguments.add(parseType());
}
+ peek = splitCloser(peek);
expect(">");
}
return new ParsedInterfaceType(name, arguments);
@@ -291,6 +302,7 @@
do {
typeVariables.add(parseTypeVariable());
} while (optionalAdvance(","));
+ peek = splitCloser(peek);
expect(">");
}
return typeVariables;
diff --git a/pkg/front_end/test/fasta/types/type_parser_test.dart b/pkg/front_end/test/fasta/types/type_parser_test.dart
index e24fa15..c92c0bc 100644
--- a/pkg/front_end/test/fasta/types/type_parser_test.dart
+++ b/pkg/front_end/test/fasta/types/type_parser_test.dart
@@ -33,5 +33,9 @@
typedef StringList List<String>;
typedef VoidFunction () -> void;
typedef GenericFunction<T> () -> T;
+List<List<Object>>
+List<List<List<Object>>>
+class A<T extends List<Object>>;
+class B<T extends List<List<Object>>>;
""");
}