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>>>;
 """);
 }