Add ClassHierarchyBuilder.getKernelTypeAsInstanceOf

Change-Id: I81a1a139f9d18f0b07e0719a924f0952c1759790
Reviewed-on: https://dart-review.googlesource.com/c/92128
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Commit-Queue: Peter von der Ahé <ahe@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
index c9fde87..89f7efa 100644
--- a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
@@ -172,6 +172,29 @@
     return null;
   }
 
+  InterfaceType getKernelTypeAsInstanceOf(
+      InterfaceType type, Class superclass) {
+    Class kernelClass = type.classNode;
+    if (kernelClass == superclass) return type;
+    if (kernelClass == nullKernelClass) {
+      if (superclass.typeParameters.isEmpty) {
+        return superclass.rawType;
+      } else {
+        // This is a safe fall-back for dealing with `Null`. It will likely be
+        // faster to check for `Null` before calling this method.
+        return new InterfaceType(
+            superclass,
+            new List<DartType>.filled(
+                superclass.typeParameters.length, nullKernelClass.rawType));
+      }
+    }
+    KernelNamedTypeBuilder supertype = asSupertypeOf(kernelClass, superclass);
+    if (supertype == null) return null;
+    if (supertype.arguments == null) return superclass.rawType;
+    return Substitution.fromInterfaceType(type)
+        .substituteType(supertype.build(null));
+  }
+
   static ClassHierarchyBuilder build(
       KernelClassBuilder objectClass,
       List<KernelClassBuilder> classes,
@@ -1001,13 +1024,7 @@
 
   @override
   InterfaceType getTypeAsInstanceOf(InterfaceType type, Class superclass) {
-    if (type.classNode == superclass) return type;
-    KernelNamedTypeBuilder supertype =
-        hierarchy.asSupertypeOf(type.classNode, superclass);
-    if (supertype == null) return null;
-    if (supertype.arguments == null) return superclass.rawType;
-    return Substitution.fromInterfaceType(type)
-        .substituteType(supertype.build(null));
+    return hierarchy.getKernelTypeAsInstanceOf(type, superclass);
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/kernel/types.dart b/pkg/front_end/lib/src/fasta/kernel/types.dart
index 5fbed2e..d7207b5 100644
--- a/pkg/front_end/lib/src/fasta/kernel/types.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/types.dart
@@ -21,7 +21,7 @@
 
 import 'package:kernel/type_algebra.dart' show Substitution;
 
-import 'kernel_builder.dart' show ClassHierarchyBuilder, KernelNamedTypeBuilder;
+import 'kernel_builder.dart' show ClassHierarchyBuilder;
 
 class Types {
   final ClassHierarchyBuilder hierarchy;
@@ -220,19 +220,19 @@
 
   @override
   bool isInterfaceRelated(InterfaceType s, InterfaceType t, Types types) {
-    Class cls = s.classNode;
-    if (cls == t.classNode) {
-      return types.areSubtypesOfKernel(s.typeArguments, t.typeArguments);
+    if (s.classNode == types.hierarchy.nullKernelClass) {
+      // This is an optimization, to avoid instantating unnecessary type
+      // arguments in getKernelTypeAsInstanceOf.
+      return true;
     }
-    if (cls == types.hierarchy.nullKernelClass) return true;
-    KernelNamedTypeBuilder supertype =
-        types.hierarchy.asSupertypeOf(s.classNode, t.classNode);
-    if (supertype == null) return false;
-    if (supertype.arguments == null) return true;
     InterfaceType asSupertype =
-        Substitution.fromInterfaceType(s).substituteType(supertype.build(null));
-    return types.areSubtypesOfKernel(
-        asSupertype.typeArguments, t.typeArguments);
+        types.hierarchy.getKernelTypeAsInstanceOf(s, t.classNode);
+    if (asSupertype == null) {
+      return false;
+    } else {
+      return types.areSubtypesOfKernel(
+          asSupertype.typeArguments, t.typeArguments);
+    }
   }
 
   @override