Reland "Combine override checks and override-based inference in one phase"

Original CL description:

> Combine override checks and override-based inference in one phase
>
> Change-Id: I2760f72f4eaa44bd192747179e843f017db30874
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97301
> Commit-Queue: Peter von der Ahé <ahe@google.com>
> Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>

Change-Id: I8408b35819a89336d10bb11e36c7b1bee707994d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/100580
Reviewed-by: Aske Simon Christensen <askesc@google.com>
diff --git a/pkg/front_end/lib/src/fasta/builder/library_builder.dart b/pkg/front_end/lib/src/fasta/builder/library_builder.dart
index 51e0852..a818b67 100644
--- a/pkg/front_end/lib/src/fasta/builder/library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/library_builder.dart
@@ -27,6 +27,7 @@
     show
         ClassBuilder,
         Declaration,
+        FieldBuilder,
         ModifierBuilder,
         NameIterator,
         PrefixBuilder,
@@ -237,6 +238,8 @@
   void recordAccess(int charOffset, int length, Uri fileUri) {}
 
   void buildOutlineExpressions() {}
+
+  List<FieldBuilder> takeImplicitlyTypedFields() => null;
 }
 
 class LibraryLocalDeclarationIterator implements Iterator<Declaration> {
diff --git a/pkg/front_end/lib/src/fasta/builder/member_builder.dart b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
index 0b99bf5..e714210 100644
--- a/pkg/front_end/lib/src/fasta/builder/member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
@@ -4,6 +4,8 @@
 
 library fasta.member_builder;
 
+import '../problems.dart' show unsupported;
+
 import 'builder.dart'
     show ClassBuilder, Declaration, LibraryBuilder, ModifierBuilder;
 
@@ -41,4 +43,10 @@
 
   @override
   String get fullNameForErrors => name;
+
+  void inferType() => unsupported("inferType", charOffset, fileUri);
+
+  void inferCopiedType(covariant Object other) {
+    unsupported("inferType", charOffset, fileUri);
+  }
 }
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index de913de..aaa62c8 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -590,6 +590,36 @@
     tip: r"""Try specifying the file explicitly with the --packages option.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String name)>
+    templateCantInferReturnTypeDueToInconsistentOverrides =
+    const Template<Message Function(String name)>(
+        messageTemplate:
+            r"""Can't infer a return type for '#name' as some of the inherited members have different types.""",
+        tipTemplate: r"""Try adding an explicit type.""",
+        withArguments:
+            _withArgumentsCantInferReturnTypeDueToInconsistentOverrides);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+    codeCantInferReturnTypeDueToInconsistentOverrides =
+    const Code<Message Function(String name)>(
+        "CantInferReturnTypeDueToInconsistentOverrides",
+        templateCantInferReturnTypeDueToInconsistentOverrides,
+        analyzerCodes: <String>["INVALID_METHOD_OVERRIDE"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsCantInferReturnTypeDueToInconsistentOverrides(
+    String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeCantInferReturnTypeDueToInconsistentOverrides,
+      message:
+          """Can't infer a return type for '${name}' as some of the inherited members have different types.""",
+      tip: """Try adding an explicit type.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
     Message Function(
         String
@@ -786,6 +816,38 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
     Message Function(
+        String name,
+        String
+            name2)> templateCombinedMemberSignatureFailed = const Template<
+        Message Function(String name, String name2)>(
+    messageTemplate:
+        r"""Class '#name' inherits multiple members named '#name2' with incompatible signatures.""",
+    tipTemplate: r"""Try adding a declaration of '#name2' to '#name'.""",
+    withArguments: _withArgumentsCombinedMemberSignatureFailed);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name, String name2)>
+    codeCombinedMemberSignatureFailed =
+    const Code<Message Function(String name, String name2)>(
+        "CombinedMemberSignatureFailed", templateCombinedMemberSignatureFailed,
+        analyzerCodes: <String>["INCONSISTENT_INHERITANCE"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsCombinedMemberSignatureFailed(String name, String name2) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  if (name2.isEmpty) throw 'No name provided';
+  name2 = demangleMixinApplicationName(name2);
+  return new Message(codeCombinedMemberSignatureFailed,
+      message:
+          """Class '${name}' inherits multiple members named '${name2}' with incompatible signatures.""",
+      tip: """Try adding a declaration of '${name2}' to '${name}'.""",
+      arguments: {'name': name, 'name2': name2});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
         String string,
         String
             string2)> templateConflictingModifiers = const Template<
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 2593336..697f844 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
@@ -8,14 +8,19 @@
     show
         Class,
         DartType,
+        Field,
+        FunctionNode,
         InterfaceType,
-        TypeParameter,
+        InvalidType,
         Library,
         Member,
         Name,
         Procedure,
         ProcedureKind,
-        Supertype;
+        Supertype,
+        TypeParameter,
+        TypeParameterType,
+        VariableDeclaration;
 
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
 
@@ -23,6 +28,8 @@
 
 import 'package:kernel/type_algebra.dart' show Substitution;
 
+import '../dill/dill_member_builder.dart' show DillMemberBuilder;
+
 import '../loader.dart' show Loader;
 
 import '../messages.dart'
@@ -36,15 +43,23 @@
         messageInheritedMembersConflictCause2,
         messageStaticAndInstanceConflict,
         messageStaticAndInstanceConflictCause,
+        templateCantInferReturnTypeDueToInconsistentOverrides,
+        templateCantInferTypeDueToInconsistentOverrides,
+        templateCombinedMemberSignatureFailed,
         templateDuplicatedDeclaration,
         templateDuplicatedDeclarationCause,
+        templateDuplicatedDeclarationUse,
         templateMissingImplementationCause,
         templateMissingImplementationNotAbstract;
 
 import '../names.dart' show noSuchMethodName;
 
+import '../problems.dart' show unhandled;
+
 import '../scope.dart' show Scope;
 
+import '../source/source_loader.dart' show SourceLoader;
+
 import '../type_inference/standard_bounds.dart' show StandardBounds;
 
 import '../type_inference/type_constraint_gatherer.dart'
@@ -56,18 +71,35 @@
 
 import '../type_inference/type_schema_environment.dart' show TypeConstraint;
 
+import 'forwarding_node.dart' show ForwardingNode;
+
 import 'kernel_builder.dart'
     show
         Declaration,
+        FormalParameterBuilder,
+        ImplicitFieldType,
         KernelClassBuilder,
+        KernelFieldBuilder,
+        KernelLibraryBuilder,
         KernelNamedTypeBuilder,
+        KernelProcedureBuilder,
         KernelTypeBuilder,
+        KernelTypeVariableBuilder,
         LibraryBuilder,
+        MemberBuilder,
         TypeBuilder,
         TypeVariableBuilder;
 
 import 'types.dart' show Types;
 
+const DebugLogger debug =
+    const bool.fromEnvironment("debug.hierarchy") ? const DebugLogger() : null;
+
+class DebugLogger {
+  const DebugLogger();
+  void log(Object message) => print(message);
+}
+
 int compareDeclarations(Declaration a, Declaration b) {
   return ClassHierarchy.compareMembers(a.target, b.target);
 }
@@ -94,6 +126,7 @@
   if (b.isField) return !(a.isField || a.isGetter || a.isSetter);
   if (a.isSetter) return !(b.isGetter || b.isSetter);
   if (b.isSetter) return !(a.isGetter || a.isSetter);
+  if (a is InterfaceConflict || b is InterfaceConflict) return false;
   return true;
 }
 
@@ -101,6 +134,68 @@
   return declaration.isField && !(declaration.isFinal || declaration.isConst);
 }
 
+bool hasSameSignature(FunctionNode a, FunctionNode b) {
+  List<TypeParameter> aTypeParameters = a.typeParameters;
+  List<TypeParameter> bTypeParameters = b.typeParameters;
+  int typeParameterCount = aTypeParameters.length;
+  if (typeParameterCount != bTypeParameters.length) return false;
+  Substitution substitution;
+  if (typeParameterCount != 0) {
+    List<DartType> types = new List<DartType>(typeParameterCount);
+    for (int i = 0; i < typeParameterCount; i++) {
+      types[i] = new TypeParameterType(aTypeParameters[i]);
+    }
+    substitution = Substitution.fromPairs(bTypeParameters, types);
+    for (int i = 0; i < typeParameterCount; i++) {
+      DartType aBound = aTypeParameters[i].bound;
+      DartType bBound = substitution.substituteType(bTypeParameters[i].bound);
+      if (aBound != bBound) return false;
+    }
+  }
+
+  if (a.requiredParameterCount != b.requiredParameterCount) return false;
+  List<VariableDeclaration> aPositionalParameters = a.positionalParameters;
+  List<VariableDeclaration> bPositionalParameters = b.positionalParameters;
+  if (aPositionalParameters.length != bPositionalParameters.length) {
+    return false;
+  }
+  for (int i = 0; i < aPositionalParameters.length; i++) {
+    VariableDeclaration aParameter = aPositionalParameters[i];
+    VariableDeclaration bParameter = bPositionalParameters[i];
+    if (aParameter.isCovariant != bParameter.isCovariant) return false;
+    DartType aType = aParameter.type;
+    DartType bType = bParameter.type;
+    if (substitution != null) {
+      bType = substitution.substituteType(bType);
+    }
+    if (aType != bType) return false;
+  }
+
+  List<VariableDeclaration> aNamedParameters = a.namedParameters;
+  List<VariableDeclaration> bNamedParameters = b.namedParameters;
+  if (aNamedParameters.length != bNamedParameters.length) return false;
+  for (int i = 0; i < aNamedParameters.length; i++) {
+    VariableDeclaration aParameter = aNamedParameters[i];
+    VariableDeclaration bParameter = bNamedParameters[i];
+    if (aParameter.isCovariant != bParameter.isCovariant) return false;
+    if (aParameter.name != bParameter.name) return false;
+    DartType aType = aParameter.type;
+    DartType bType = bParameter.type;
+    if (substitution != null) {
+      bType = substitution.substituteType(bType);
+    }
+    if (aType != bType) return false;
+  }
+
+  DartType aReturnType = a.returnType;
+  DartType bReturnType = b.returnType;
+  if (substitution != null) {
+    bReturnType = substitution.substituteType(bReturnType);
+  }
+
+  return aReturnType == bReturnType;
+}
+
 class ClassHierarchyBuilder {
   final Map<Class, ClassHierarchyNode> nodes = <Class, ClassHierarchyNode>{};
 
@@ -118,6 +213,10 @@
 
   final Class nullKernelClass;
 
+  final List<DelayedOverrideCheck> overrideChecks = <DelayedOverrideCheck>[];
+
+  final List<DelayedMember> delayedMemberChecks = <DelayedMember>[];
+
   // TODO(ahe): Remove this.
   final CoreTypes coreTypes;
 
@@ -138,10 +237,8 @@
   }
 
   ClassHierarchyNode getNodeFromType(KernelTypeBuilder type) {
-    Declaration declaration = type.declaration;
-    return declaration is KernelClassBuilder
-        ? getNodeFromClass(declaration)
-        : null;
+    KernelClassBuilder cls = getClass(type);
+    return cls == null ? null : getNodeFromClass(cls);
   }
 
   ClassHierarchyNode getNodeFromKernelClass(Class cls) {
@@ -190,7 +287,9 @@
     }
     KernelNamedTypeBuilder supertype = asSupertypeOf(kernelClass, superclass);
     if (supertype == null) return null;
-    if (supertype.arguments == null) return superclass.rawType;
+    if (supertype.arguments == null && superclass.typeParameters.isEmpty) {
+      return superclass.rawType;
+    }
     return Substitution.fromInterfaceType(type)
         .substituteType(supertype.build(null));
   }
@@ -232,17 +331,54 @@
     return objectKernelClass.rawType;
   }
 
+  Member getInterfaceMemberKernel(Class cls, Name name, bool isSetter) {
+    return getNodeFromKernelClass(cls)
+        .getInterfaceMember(name, isSetter)
+        ?.target;
+  }
+
+  Member getDispatchTargetKernel(Class cls, Name name, bool isSetter) {
+    return getNodeFromKernelClass(cls)
+        .getDispatchTarget(name, isSetter)
+        ?.target;
+  }
+
+  Member getCombinedMemberSignatureKernel(Class cls, Name name, bool isSetter,
+      int charOffset, KernelLibraryBuilder library) {
+    Declaration declaration =
+        getNodeFromKernelClass(cls).getInterfaceMember(name, isSetter);
+    if (declaration?.isStatic ?? true) return null;
+    if (declaration.next != null) {
+      library?.addProblem(
+          templateDuplicatedDeclarationUse.withArguments(name.name),
+          charOffset,
+          name.name.length,
+          library.fileUri);
+      return null;
+    }
+    if (declaration is DelayedMember) {
+      return declaration.check(this);
+    } else {
+      return declaration.target;
+    }
+  }
+
   static ClassHierarchyBuilder build(
       KernelClassBuilder objectClass,
       List<KernelClassBuilder> classes,
-      Loader<Object> loader,
+      SourceLoader loader,
       CoreTypes coreTypes) {
     ClassHierarchyBuilder hierarchy =
         new ClassHierarchyBuilder(objectClass, loader, coreTypes);
     for (int i = 0; i < classes.length; i++) {
       KernelClassBuilder cls = classes[i];
-      hierarchy.nodes[cls.target] =
-          new ClassHierarchyNodeBuilder(hierarchy, cls).build();
+      if (!cls.isPatch) {
+        hierarchy.nodes[cls.target] =
+            new ClassHierarchyNodeBuilder(hierarchy, cls).build();
+      } else {
+        // TODO(ahe): Merge the injected members of patch into the hierarchy
+        // node of `cls.origin`.
+      }
     }
     return hierarchy;
   }
@@ -261,6 +397,8 @@
 
   KernelClassBuilder get objectClass => hierarchy.objectClass;
 
+  final Map<Class, Substitution> substitutions = <Class, Substitution>{};
+
   /// When merging `aList` and `bList`, [a] (from `aList`) and [b] (from
   /// `bList`) each have the same name.
   ///
@@ -271,44 +409,563 @@
   ///
   /// If [mergeKind] is `MergeKind.supertypes`, [a] should implement [b], and
   /// [b] is implicitly abstract.
-  Declaration handleMergeConflict(KernelClassBuilder cls, Declaration a,
-      Declaration b, MergeKind mergeKind) {
+  Declaration handleMergeConflict(
+      Declaration a, Declaration b, MergeKind mergeKind) {
+    debug?.log(
+        "handleMergeConflict: ${fullName(a)} ${fullName(b)} ${mergeKind}");
+    // TODO(ahe): Enable this optimization, but be careful about abstract
+    // methods overriding concrete methods.
+    // if (cls is DillClassBuilder) return a;
     if (a == b) return a;
     if (a.next != null || b.next != null) {
       // Don't check overrides involving duplicated members.
       return a;
     }
-    if (isInheritanceConflict(a, b)) {
-      reportInheritanceConflict(cls, a, b);
-    }
-    Declaration result = a;
-    if (mergeKind == MergeKind.accessors) {
-    } else if (mergeKind == MergeKind.interfaces) {
-      // TODO(ahe): Combine the signatures of a and b.  See the section named
-      // "Combined Member Signatures" in [Dart Programming Language
-      // Specification](
-      // ../../../../../../docs/language/dartLangSpec.tex#combinedMemberSignatures).
-    } else if (a.target.isAbstract) {
-      if (mergeKind == MergeKind.superclass && !b.target.isAbstract) {
-        // An abstract method doesn't override an implemention inherited from a
-        // superclass.
-        result = b;
-      } else {
-        (abstractMembers ??= <Declaration>[]).add(a);
-      }
-    }
+    Declaration result = checkInheritanceConflict(a, b);
+    if (result != null) return result;
+    result = a;
+    switch (mergeKind) {
+      case MergeKind.superclassMembers:
+      case MergeKind.superclassSetters:
+        // [a] is a method declared in [cls]. This means it defines the
+        // interface of this class regardless if its abstract.
+        debug?.log(
+            "superclass: checkValidOverride(${cls.fullNameForErrors}, ${fullName(a)}, ${fullName(b)})");
+        checkValidOverride(
+            a, AbstractMemberOverridingImplementation.selectAbstract(b));
 
-    if (mergeKind == MergeKind.superclass &&
-        result.fullNameForErrors == noSuchMethodName.name &&
-        result.parent != objectClass) {
-      hasNoSuchMethod = true;
+        if (isAbstract(a)) {
+          if (isAbstract(b)) {
+            recordAbstractMember(a);
+          } else {
+            if (!cls.isAbstract) {
+              // The interface of this class is [a]. But the implementation is
+              // [b]. So [b] must implement [a], unless [cls] is abstract.
+              checkValidOverride(b, a);
+            }
+            result = new AbstractMemberOverridingImplementation(
+                cls,
+                a,
+                AbstractMemberOverridingImplementation.selectConcrete(b),
+                mergeKind == MergeKind.superclassSetters,
+                cls.library.loader == hierarchy.loader);
+            hierarchy.delayedMemberChecks.add(result);
+          }
+        }
+
+        Member target = result.target;
+        if (target.enclosingClass != objectClass.cls &&
+            target.name == noSuchMethodName) {
+          hasNoSuchMethod = true;
+        }
+        break;
+
+      case MergeKind.membersWithSetters:
+      case MergeKind.settersWithMembers:
+        if (a.parent == cls && b.parent != cls) {
+          if (a is KernelFieldBuilder) {
+            if (a.isFinal && b.isSetter) {
+              hierarchy.overrideChecks.add(new DelayedOverrideCheck(cls, a, b));
+            } else {
+              if (!inferFieldTypes(a, b)) {
+                hierarchy.overrideChecks
+                    .add(new DelayedOverrideCheck(cls, a, b));
+              }
+            }
+          } else if (a is KernelProcedureBuilder) {
+            if (!inferMethodTypes(a, b)) {
+              hierarchy.overrideChecks.add(new DelayedOverrideCheck(cls, a, b));
+            }
+          }
+        }
+        break;
+
+      case MergeKind.interfacesMembers:
+        result = InterfaceConflict.combined(
+            cls, a, b, false, cls.library.loader == hierarchy.loader);
+        break;
+
+      case MergeKind.interfacesSetters:
+        result = InterfaceConflict.combined(
+            cls, a, b, true, cls.library.loader == hierarchy.loader);
+        break;
+
+      case MergeKind.supertypesMembers:
+      case MergeKind.supertypesSetters:
+        // [b] is inherited from an interface so it is implicitly abstract.
+
+        a = AbstractMemberOverridingImplementation.selectAbstract(a);
+        b = AbstractMemberOverridingImplementation.selectAbstract(b);
+
+        // If [a] is declared in this class, it defines the interface.
+        if (a.parent == cls) {
+          debug?.log(
+              "supertypes: checkValidOverride(${cls.fullNameForErrors}, ${fullName(a)}, ${fullName(b)})");
+          checkValidOverride(a, b);
+        } else {
+          if (isAbstract(a)) {
+            result = InterfaceConflict.combined(
+                cls,
+                a,
+                b,
+                mergeKind == MergeKind.supertypesSetters,
+                cls.library.loader == hierarchy.loader);
+          } else {
+            result = InheritedImplementationInterfaceConflict.combined(
+                cls,
+                a,
+                b,
+                mergeKind == MergeKind.supertypesSetters,
+                cls.library.loader == hierarchy.loader);
+          }
+          debug?.log("supertypes: ${result}");
+          if (result is DelayedMember) {
+            hierarchy.delayedMemberChecks.add(result);
+          }
+        }
+        break;
     }
 
     return result;
   }
 
-  void reportInheritanceConflict(
-      KernelClassBuilder cls, Declaration a, Declaration b) {
+  Declaration checkInheritanceConflict(Declaration a, Declaration b) {
+    if (a is DelayedMember) {
+      Declaration result;
+      for (int i = 0; i < a.declarations.length; i++) {
+        Declaration d = checkInheritanceConflict(a.declarations[i], b);
+        result ??= d;
+      }
+      return result;
+    }
+    if (b is DelayedMember) {
+      Declaration result;
+      for (int i = 0; i < b.declarations.length; i++) {
+        Declaration d = checkInheritanceConflict(a, b.declarations[i]);
+        result ??= d;
+      }
+      return result;
+    }
+    if (isInheritanceConflict(a, b)) {
+      reportInheritanceConflict(a, b);
+      return a;
+    }
+    return null;
+  }
+
+  bool inferMethodTypes(KernelProcedureBuilder a, Declaration b) {
+    debug?.log(
+        "Trying to infer types for ${fullName(a)} based on ${fullName(b)}");
+    if (b is DelayedMember) {
+      bool hasSameSignature = true;
+      List<Declaration> declarations = b.declarations;
+      for (int i = 0; i < declarations.length; i++) {
+        if (!inferMethodTypes(a, declarations[i])) {
+          hasSameSignature = false;
+        }
+      }
+      return hasSameSignature;
+    }
+    if (a.isGetter) {
+      return inferGetterType(a, b);
+    } else if (a.isSetter) {
+      return inferSetterType(a, b);
+    }
+    bool hadTypesInferred = a.hadTypesInferred;
+    KernelClassBuilder aCls = a.parent;
+    Substitution aSubstitution;
+    if (cls != aCls) {
+      assert(substitutions.containsKey(aCls.target),
+          "${cls.fullNameForErrors} ${aCls.fullNameForErrors}");
+      aSubstitution = substitutions[aCls.target];
+      debug?.log(
+          "${cls.fullNameForErrors} -> ${aCls.fullNameForErrors} $aSubstitution");
+    }
+    KernelClassBuilder bCls = b.parent;
+    Substitution bSubstitution;
+    if (cls != bCls) {
+      assert(substitutions.containsKey(bCls.target),
+          "${cls.fullNameForErrors} ${bCls.fullNameForErrors}");
+      bSubstitution = substitutions[bCls.target];
+      debug?.log(
+          "${cls.fullNameForErrors} -> ${bCls.fullNameForErrors} $bSubstitution");
+    }
+    Procedure aProcedure = a.target;
+    if (b.target is! Procedure) {
+      debug?.log("Giving up 1");
+      return false;
+    }
+    Procedure bProcedure = b.target;
+    FunctionNode aFunction = aProcedure.function;
+    FunctionNode bFunction = bProcedure.function;
+
+    List<TypeParameter> aTypeParameters = aFunction.typeParameters;
+    List<TypeParameter> bTypeParameters = bFunction.typeParameters;
+    int typeParameterCount = aTypeParameters.length;
+    if (typeParameterCount != bTypeParameters.length) {
+      debug?.log("Giving up 2");
+      return false;
+    }
+    Substitution substitution;
+    if (typeParameterCount != 0) {
+      List<DartType> types = new List<DartType>(typeParameterCount);
+      for (int i = 0; i < typeParameterCount; i++) {
+        types[i] = new TypeParameterType(aTypeParameters[i]);
+      }
+      substitution = Substitution.fromPairs(bTypeParameters, types);
+      for (int i = 0; i < typeParameterCount; i++) {
+        DartType aBound = aTypeParameters[i].bound;
+        DartType bBound = substitution.substituteType(bTypeParameters[i].bound);
+        if (aBound != bBound) {
+          debug?.log("Giving up 3");
+          return false;
+        }
+      }
+    }
+
+    DartType aReturnType = aFunction.returnType;
+    if (aSubstitution != null) {
+      aReturnType = aSubstitution.substituteType(aReturnType);
+    }
+    DartType bReturnType = bFunction.returnType;
+    if (bSubstitution != null) {
+      bReturnType = bSubstitution.substituteType(bReturnType);
+    }
+    if (substitution != null) {
+      bReturnType = substitution.substituteType(bReturnType);
+    }
+    bool result = true;
+    if (aFunction.requiredParameterCount > bFunction.requiredParameterCount) {
+      debug?.log("Giving up 4");
+      return false;
+    }
+    List<VariableDeclaration> aPositional = aFunction.positionalParameters;
+    List<VariableDeclaration> bPositional = bFunction.positionalParameters;
+    if (aPositional.length < bPositional.length) {
+      debug?.log("Giving up 5");
+      return false;
+    }
+
+    if (aReturnType != bReturnType) {
+      if (a.parent == cls && a.returnType == null) {
+        result =
+            inferReturnType(cls, a, bReturnType, hadTypesInferred, hierarchy);
+      } else {
+        debug?.log("Giving up 6");
+        result = false;
+      }
+    }
+
+    for (int i = 0; i < bPositional.length; i++) {
+      VariableDeclaration aParameter = aPositional[i];
+      VariableDeclaration bParameter = bPositional[i];
+      copyParameterCovariance(a.parent, aParameter, bParameter);
+      DartType aType = aParameter.type;
+      if (aSubstitution != null) {
+        aType = aSubstitution.substituteType(aType);
+      }
+      DartType bType = bParameter.type;
+      if (bSubstitution != null) {
+        bType = bSubstitution.substituteType(bType);
+      }
+      if (substitution != null) {
+        bType = substitution.substituteType(bType);
+      }
+      if (aType != bType) {
+        if (a.parent == cls && a.formals[i].type == null) {
+          result = inferParameterType(
+              cls, a, a.formals[i], bType, hadTypesInferred, hierarchy);
+        } else {
+          debug?.log("Giving up 8");
+          result = false;
+        }
+      }
+    }
+
+    List<VariableDeclaration> aNamed = aFunction.namedParameters;
+    List<VariableDeclaration> bNamed = bFunction.namedParameters;
+    named:
+    if (aNamed.isNotEmpty || bNamed.isNotEmpty) {
+      if (aPositional.length != bPositional.length) {
+        debug?.log("Giving up 9");
+        result = false;
+        break named;
+      }
+      if (aFunction.requiredParameterCount !=
+          bFunction.requiredParameterCount) {
+        debug?.log("Giving up 10");
+        result = false;
+        break named;
+      }
+
+      aNamed = aNamed.toList()..sort(compareNamedParameters);
+      bNamed = bNamed.toList()..sort(compareNamedParameters);
+      int aCount = 0;
+      for (int bCount = 0; bCount < bNamed.length; bCount++) {
+        String name = bNamed[bCount].name;
+        for (; aCount < aNamed.length; aCount++) {
+          if (aNamed[aCount].name == name) break;
+        }
+        if (aCount == aNamed.length) {
+          debug?.log("Giving up 11");
+          result = false;
+          break named;
+        }
+        VariableDeclaration aParameter = aNamed[aCount];
+        VariableDeclaration bParameter = bNamed[bCount];
+        copyParameterCovariance(a.parent, aParameter, bParameter);
+        DartType aType = aParameter.type;
+        DartType bType = bParameter.type;
+        if (substitution != null) {
+          bType = substitution.substituteType(bType);
+        }
+        if (aType != bType) {
+          FormalParameterBuilder<KernelTypeBuilder> parameter =
+              a.formals[aPositional.length + aCount];
+          if (a.parent == cls && parameter.type == null) {
+            result = inferParameterType(
+                cls, a, parameter, bType, hadTypesInferred, hierarchy);
+          } else {
+            debug?.log("Giving up 12");
+            result = false;
+          }
+        }
+      }
+    }
+    debug?.log("Inferring types for ${fullName(a)} based on ${fullName(b)} " +
+        (result ? "succeeded." : "failed."));
+    return result;
+  }
+
+  bool inferGetterType(KernelProcedureBuilder a, Declaration b) {
+    debug?.log(
+        "Inferring getter types for ${fullName(a)} based on ${fullName(b)}");
+    Member bTarget = b.target;
+    DartType bType;
+    if (bTarget is Field) {
+      bType = bTarget.type;
+    } else if (bTarget is Procedure) {
+      if (b.isSetter) {
+        VariableDeclaration bParameter =
+            bTarget.function.positionalParameters.single;
+        bType = bParameter.type;
+        if (!hasExplictlyTypedFormalParameter(b, 0)) {
+          debug?.log("Giving up (type may be inferred)");
+          return false;
+        }
+      } else if (b.isGetter) {
+        bType = bTarget.function.returnType;
+        if (!hasExplicitReturnType(b)) {
+          debug?.log("Giving up (return type may be inferred)");
+          return false;
+        }
+      } else {
+        debug?.log("Giving up (not accessor: ${bTarget.kind})");
+        return false;
+      }
+    } else {
+      debug?.log("Giving up (not field/procedure: ${bTarget.runtimeType})");
+      return false;
+    }
+    return a.target.function.returnType == bType;
+  }
+
+  bool inferSetterType(KernelProcedureBuilder a, Declaration b) {
+    debug?.log(
+        "Inferring getter types for ${fullName(a)} based on ${fullName(b)}");
+    Member bTarget = b.target;
+    Procedure aProcedure = a.target;
+    VariableDeclaration aParameter =
+        aProcedure.function.positionalParameters.single;
+    DartType bType;
+    if (bTarget is Field) {
+      bType = bTarget.type;
+      copyParameterCovarianceFromField(a.parent, aParameter, bTarget);
+    }
+    if (bTarget is Procedure) {
+      if (b.isSetter) {
+        VariableDeclaration bParameter =
+            bTarget.function.positionalParameters.single;
+        bType = bParameter.type;
+        copyParameterCovariance(a.parent, aParameter, bParameter);
+        if (!hasExplictlyTypedFormalParameter(b, 0)) {
+          debug?.log("Giving up (type may be inferred)");
+          return false;
+        }
+      } else if (b.isGetter) {
+        bType = bTarget.function.returnType;
+        if (!hasExplicitReturnType(b)) {
+          debug?.log("Giving up (return type may be inferred)");
+          return false;
+        }
+      } else {
+        debug?.log("Giving up (not accessor: ${bTarget.kind})");
+        return false;
+      }
+    } else {
+      debug?.log("Giving up (not field/procedure: ${bTarget.runtimeType})");
+      return false;
+    }
+    return aParameter.type == bType;
+  }
+
+  void checkValidOverride(Declaration a, Declaration b) {
+    debug?.log(
+        "checkValidOverride(${fullName(a)}, ${fullName(b)}) ${a.runtimeType}");
+    if (a is KernelProcedureBuilder) {
+      if (inferMethodTypes(a, b)) return;
+    } else if (a.isField) {
+      if (inferFieldTypes(a, b)) return;
+    }
+    Member aTarget = a.target;
+    Member bTarget = b.target;
+    if (aTarget is Procedure && !aTarget.isAccessor && bTarget is Procedure) {
+      if (hasSameSignature(aTarget.function, bTarget.function)) return;
+    }
+
+    if (b is DelayedMember) {
+      for (int i = 0; i < b.declarations.length; i++) {
+        hierarchy.overrideChecks
+            .add(new DelayedOverrideCheck(cls, a, b.declarations[i]));
+      }
+    } else {
+      hierarchy.overrideChecks.add(new DelayedOverrideCheck(cls, a, b));
+    }
+  }
+
+  bool inferFieldTypes(MemberBuilder a, Declaration b) {
+    debug?.log(
+        "Trying to infer field types for ${fullName(a)} based on ${fullName(b)}");
+    if (b is DelayedMember) {
+      bool hasSameSignature = true;
+      List<Declaration> declarations = b.declarations;
+      for (int i = 0; i < declarations.length; i++) {
+        if (!inferFieldTypes(a, declarations[i])) {
+          hasSameSignature = false;
+        }
+      }
+      return hasSameSignature;
+    }
+    Member bTarget = b.target;
+    DartType inheritedType;
+    if (bTarget is Procedure) {
+      if (bTarget.isSetter) {
+        VariableDeclaration parameter =
+            bTarget.function.positionalParameters.single;
+        // inheritedType = parameter.type;
+        copyFieldCovarianceFromParameter(a.parent, a.target, parameter);
+        if (!hasExplictlyTypedFormalParameter(b, 0)) {
+          debug?.log("Giving up (type may be inferred)");
+          return false;
+        }
+      } else if (bTarget.isGetter) {
+        if (!hasExplicitReturnType(b)) return false;
+        inheritedType = bTarget.function.returnType;
+      }
+    } else if (bTarget is Field) {
+      copyFieldCovariance(a.parent, a.target, bTarget);
+      inheritedType = bTarget.type;
+    }
+    if (inheritedType == null) {
+      debug?.log("Giving up (inheritedType == null)\n${StackTrace.current}");
+      return false;
+    }
+    KernelClassBuilder aCls = a.parent;
+    Substitution aSubstitution;
+    if (cls != aCls) {
+      assert(substitutions.containsKey(aCls.target),
+          "${cls.fullNameForErrors} ${aCls.fullNameForErrors}");
+      aSubstitution = substitutions[aCls.target];
+      debug?.log(
+          "${cls.fullNameForErrors} -> ${aCls.fullNameForErrors} $aSubstitution");
+    }
+    KernelClassBuilder bCls = b.parent;
+    Substitution bSubstitution;
+    if (cls != bCls) {
+      assert(substitutions.containsKey(bCls.target),
+          "${cls.fullNameForErrors} ${bCls.fullNameForErrors}");
+      bSubstitution = substitutions[bCls.target];
+      debug?.log(
+          "${cls.fullNameForErrors} -> ${bCls.fullNameForErrors} $bSubstitution");
+    }
+    if (bSubstitution != null) {
+      inheritedType = bSubstitution.substituteType(inheritedType);
+    }
+
+    DartType declaredType = a.target.type;
+    if (aSubstitution != null) {
+      declaredType = aSubstitution.substituteType(declaredType);
+    }
+    if (declaredType == inheritedType) return true;
+
+    bool result = false;
+    if (a is KernelFieldBuilder) {
+      if (a.parent == cls && a.type == null) {
+        if (a.hadTypesInferred) {
+          reportCantInferFieldType(cls, a);
+          inheritedType = const InvalidType();
+        } else {
+          result = true;
+          a.hadTypesInferred = true;
+        }
+        if (inheritedType is ImplicitFieldType) {
+          KernelLibraryBuilder library = cls.library;
+          (library.implicitlyTypedFields ??= <KernelFieldBuilder>[]).add(a);
+        }
+        a.target.type = inheritedType;
+      }
+    }
+    return result;
+  }
+
+  void copyParameterCovariance(Declaration parent,
+      VariableDeclaration aParameter, VariableDeclaration bParameter) {
+    if (parent == cls) {
+      if (bParameter.isCovariant) {
+        aParameter.isCovariant = true;
+      }
+      if (bParameter.isGenericCovariantImpl) {
+        aParameter.isGenericCovariantImpl = true;
+      }
+    }
+  }
+
+  void copyParameterCovarianceFromField(
+      Declaration parent, VariableDeclaration aParameter, Field bField) {
+    if (parent == cls) {
+      if (bField.isCovariant) {
+        aParameter.isCovariant = true;
+      }
+      if (bField.isGenericCovariantImpl) {
+        aParameter.isGenericCovariantImpl = true;
+      }
+    }
+  }
+
+  void copyFieldCovariance(Declaration parent, Field aField, Field bField) {
+    if (parent == cls) {
+      if (bField.isCovariant) {
+        aField.isCovariant = true;
+      }
+      if (bField.isGenericCovariantImpl) {
+        aField.isGenericCovariantImpl = true;
+      }
+    }
+  }
+
+  void copyFieldCovarianceFromParameter(
+      Declaration parent, Field aField, VariableDeclaration bParameter) {
+    if (parent == cls) {
+      if (bParameter.isCovariant) {
+        aField.isCovariant = true;
+      }
+      if (bParameter.isGenericCovariantImpl) {
+        aField.isGenericCovariantImpl = true;
+      }
+    }
+  }
+
+  void reportInheritanceConflict(Declaration a, Declaration b) {
     String name = a.fullNameForErrors;
     if (a.parent != b.parent) {
       if (a.parent == cls) {
@@ -374,8 +1031,17 @@
   /// If [mergeKind] is `MergeKind.supertypes`, [member] isn't
   /// implementing/overriding anything.
   void handleOnlyA(Declaration member, MergeKind mergeKind) {
-    if (mergeKind == MergeKind.superclass && member.target.isAbstract) {
-      (abstractMembers ??= <Declaration>[]).add(member);
+    if (mergeKind == MergeKind.interfacesMembers ||
+        mergeKind == MergeKind.interfacesSetters) {
+      return;
+    }
+    // TODO(ahe): Enable this optimization:
+    // if (cls is DillClassBuilder) return;
+    // assert(mergeKind == MergeKind.interfaces || member is! InterfaceConflict);
+    if ((mergeKind == MergeKind.superclassMembers ||
+            mergeKind == MergeKind.superclassSetters) &&
+        isAbstract(member)) {
+      recordAbstractMember(member);
     }
   }
 
@@ -388,30 +1054,49 @@
   ///
   /// If [mergeKind] is `MergeKind.supertypes`, [member] is implicitly
   /// abstract, and not implemented.
-  void handleOnlyB(
-      KernelClassBuilder cls, Declaration member, MergeKind mergeKind) {
+  Declaration handleOnlyB(Declaration member, MergeKind mergeKind) {
+    if (mergeKind == MergeKind.interfacesMembers ||
+        mergeKind == MergeKind.interfacesSetters) {
+      return member;
+    }
+    // TODO(ahe): Enable this optimization:
+    // if (cls is DillClassBuilder) return member;
     Member target = member.target;
-    if (mergeKind == MergeKind.supertypes ||
-        (mergeKind == MergeKind.superclass && target.isAbstract)) {
+    if ((mergeKind == MergeKind.supertypesMembers ||
+            mergeKind == MergeKind.supertypesSetters) ||
+        ((mergeKind == MergeKind.superclassMembers ||
+                mergeKind == MergeKind.superclassSetters) &&
+            target.isAbstract)) {
       if (isNameVisibleIn(target.name, cls.library)) {
-        (abstractMembers ??= <Declaration>[]).add(member);
+        recordAbstractMember(member);
       }
     }
-    if (member.parent != objectClass &&
-        target.name == noSuchMethodName &&
-        !target.isAbstract) {
+    if (mergeKind == MergeKind.superclassMembers &&
+        target.enclosingClass != objectClass.cls &&
+        target.name == noSuchMethodName) {
       hasNoSuchMethod = true;
     }
+    if (mergeKind != MergeKind.membersWithSetters &&
+        mergeKind != MergeKind.settersWithMembers &&
+        member is DelayedMember) {
+      hierarchy.delayedMemberChecks.add(member.withParent(cls));
+    }
+    return member;
+  }
+
+  void recordAbstractMember(Declaration member) {
+    abstractMembers ??= <Declaration>[];
+    if (member is DelayedMember) {
+      abstractMembers.addAll(member.declarations);
+    } else {
+      abstractMembers.add(member);
+    }
   }
 
   ClassHierarchyNode build() {
-    if (cls.isPatch) {
-      // TODO(ahe): What about patch classes. Have we injected patched members
-      // into the class-builder's scope?
-      return null;
-    }
+    assert(!cls.isPatch);
     ClassHierarchyNode supernode;
-    if (objectClass != cls) {
+    if (objectClass != cls.origin) {
       supernode = hierarchy.getNodeFromType(cls.supertype);
       if (supernode == null) {
         supernode = hierarchy.getNodeFromClass(objectClass);
@@ -423,8 +1108,10 @@
     if (cls.isMixinApplication) {
       Declaration mixin = cls.mixedInType.declaration;
       inferMixinApplication();
+      // recordSupertype(cls.mixedInType);
       while (mixin.isNamedMixinApplication) {
         KernelClassBuilder named = mixin;
+        // recordSupertype(named.mixedInType);
         mixin = named.mixedInType.declaration;
       }
       if (mixin is KernelClassBuilder) {
@@ -443,7 +1130,7 @@
           ..sort(compareDeclarations);
 
     // Add implied setters from fields in [localMembers].
-    localSetters = mergeAccessors(cls, localMembers, localSetters);
+    localSetters = mergeAccessors(localMembers, localSetters);
 
     /// Members (excluding setters) declared in [cls] or its superclasses. This
     /// includes static methods of [cls], but not its superclasses.
@@ -482,23 +1169,9 @@
           new List<KernelTypeBuilder>(supernode.superclasses.length + 1);
       superclasses.setRange(0, superclasses.length - 1,
           substSupertypes(cls.supertype, supernode.superclasses));
-      superclasses[superclasses.length - 1] = cls.supertype;
+      superclasses[superclasses.length - 1] = recordSupertype(cls.supertype);
 
-      classMembers = merge(
-          cls, localMembers, supernode.classMembers, MergeKind.superclass);
-      classSetters = merge(
-          cls, localSetters, supernode.classSetters, MergeKind.superclass);
-
-      // Check if local members conflict with inherited setters. This check has
-      // already been performed in the superclass, so we only need to check the
-      // local members.
-      merge(cls, localMembers, classSetters, MergeKind.accessors);
-
-      // Check if local setters conflict with inherited members. As above, we
-      // only need to check the local setters.
-      merge(cls, localSetters, classMembers, MergeKind.accessors);
-
-      List<KernelTypeBuilder> directInterfaces = cls.interfaces;
+      List<KernelTypeBuilder> directInterfaces = ignoreFunction(cls.interfaces);
       if (cls.isMixinApplication) {
         if (directInterfaces == null) {
           directInterfaces = <KernelTypeBuilder>[cls.mixedInType];
@@ -508,15 +1181,29 @@
         }
       }
       if (directInterfaces != null) {
-        MergeResult result = mergeInterfaces(cls, supernode, directInterfaces);
+        for (int i = 0; i < directInterfaces.length; i++) {
+          recordSupertype(directInterfaces[i]);
+        }
+      }
+      List<KernelTypeBuilder> superclassInterfaces = supernode.interfaces;
+      if (superclassInterfaces != null) {
+        superclassInterfaces =
+            substSupertypes(cls.supertype, superclassInterfaces);
+      }
+
+      classMembers = merge(
+          localMembers, supernode.classMembers, MergeKind.superclassMembers);
+      classSetters = merge(
+          localSetters, supernode.classSetters, MergeKind.superclassSetters);
+
+      if (directInterfaces != null) {
+        MergeResult result = mergeInterfaces(supernode, directInterfaces);
         interfaceMembers = result.mergedMembers;
         interfaceSetters = result.mergedSetters;
         interfaces = <KernelTypeBuilder>[];
-        if (supernode.interfaces != null) {
-          List<KernelTypeBuilder> types =
-              substSupertypes(cls.supertype, supernode.interfaces);
-          for (int i = 0; i < types.length; i++) {
-            addInterface(interfaces, superclasses, types[i]);
+        if (superclassInterfaces != null) {
+          for (int i = 0; i < superclassInterfaces.length; i++) {
+            addInterface(interfaces, superclasses, superclassInterfaces[i]);
           }
         }
         for (int i = 0; i < directInterfaces.length; i++) {
@@ -546,30 +1233,41 @@
       } else {
         interfaceMembers = supernode.interfaceMembers;
         interfaceSetters = supernode.interfaceSetters;
-        interfaces = substSupertypes(cls.supertype, supernode.interfaces);
+        interfaces = superclassInterfaces;
       }
+
+      // Check if local members conflict with inherited setters. This check has
+      // already been performed in the superclass, so we only need to check the
+      // local members. These checks have to occur late to enable inferring
+      // types between setters and getters, or from a setter to a final field.
+      merge(localMembers, classSetters, MergeKind.membersWithSetters);
+
+      // Check if local setters conflict with inherited members. As above, we
+      // only need to check the local setters.
+      merge(localSetters, classMembers, MergeKind.settersWithMembers);
+
       if (interfaceMembers != null) {
         interfaceMembers =
-            merge(cls, classMembers, interfaceMembers, MergeKind.supertypes);
+            merge(classMembers, interfaceMembers, MergeKind.supertypesMembers);
 
         // Check if class setters conflict with members inherited from
         // interfaces.
-        merge(cls, classSetters, interfaceMembers, MergeKind.accessors);
+        merge(classSetters, interfaceMembers, MergeKind.settersWithMembers);
       }
       if (interfaceSetters != null) {
         interfaceSetters =
-            merge(cls, classSetters, interfaceSetters, MergeKind.supertypes);
+            merge(classSetters, interfaceSetters, MergeKind.supertypesSetters);
 
         // Check if class members conflict with setters inherited from
         // interfaces.
-        merge(cls, classMembers, interfaceSetters, MergeKind.accessors);
+        merge(classMembers, interfaceSetters, MergeKind.membersWithSetters);
       }
     }
     if (abstractMembers != null && !cls.isAbstract) {
       if (!hasNoSuchMethod) {
-        reportMissingMembers(cls);
+        reportMissingMembers();
       } else {
-        installNsmHandlers(cls);
+        installNsmHandlers();
       }
     }
     return new ClassHierarchyNode(
@@ -584,6 +1282,41 @@
     );
   }
 
+  KernelTypeBuilder recordSupertype(KernelTypeBuilder supertype) {
+    if (supertype is KernelNamedTypeBuilder) {
+      debug?.log(
+          "In ${this.cls.fullNameForErrors} recordSupertype(${supertype.fullNameForErrors})");
+      Declaration declaration = supertype.declaration;
+      if (declaration is! KernelClassBuilder) return supertype;
+      KernelClassBuilder cls = declaration;
+      if (cls.isMixinApplication) {
+        recordSupertype(cls.mixedInType);
+      }
+      List<TypeVariableBuilder<TypeBuilder, Object>> typeVariables =
+          cls.typeVariables;
+      if (typeVariables == null) {
+        substitutions[cls.target] = Substitution.empty;
+        assert(cls.target.typeParameters.isEmpty);
+      } else {
+        List<KernelTypeBuilder> arguments =
+            supertype.arguments ?? computeDefaultTypeArguments(supertype);
+        if (arguments.length != typeVariables.length) {
+          arguments = computeDefaultTypeArguments(supertype);
+        }
+        List<DartType> kernelArguments = new List<DartType>(arguments.length);
+        List<TypeParameter> kernelParameters =
+            new List<TypeParameter>(arguments.length);
+        for (int i = 0; i < arguments.length; i++) {
+          kernelParameters[i] = typeVariables[i].target;
+          kernelArguments[i] = arguments[i].build(this.cls.parent);
+        }
+        substitutions[cls.target] =
+            Substitution.fromPairs(kernelParameters, kernelArguments);
+      }
+    }
+    return supertype;
+  }
+
   List<KernelTypeBuilder> substSupertypes(
       KernelNamedTypeBuilder supertype, List<KernelTypeBuilder> supertypes) {
     Declaration declaration = supertype.declaration;
@@ -591,7 +1324,13 @@
     KernelClassBuilder cls = declaration;
     List<TypeVariableBuilder<TypeBuilder, Object>> typeVariables =
         cls.typeVariables;
-    if (typeVariables == null) return supertypes;
+    if (typeVariables == null) {
+      debug?.log("In ${this.cls.fullNameForErrors} $supertypes aren't substed");
+      for (int i = 0; i < supertypes.length; i++) {
+        recordSupertype(supertypes[i]);
+      }
+      return supertypes;
+    }
     Map<TypeVariableBuilder<TypeBuilder, Object>, TypeBuilder> substitution =
         <TypeVariableBuilder<TypeBuilder, Object>, TypeBuilder>{};
     List<KernelTypeBuilder> arguments =
@@ -602,10 +1341,14 @@
     List<KernelTypeBuilder> result;
     for (int i = 0; i < supertypes.length; i++) {
       KernelTypeBuilder supertype = supertypes[i];
-      KernelTypeBuilder substed = supertype.subst(substitution);
+      KernelTypeBuilder substed =
+          recordSupertype(supertype.subst(substitution));
       if (supertype != substed) {
+        debug?.log("In ${this.cls.fullNameForErrors} $supertype -> $substed");
         result ??= supertypes.toList();
         result[i] = substed;
+      } else {
+        debug?.log("In ${this.cls.fullNameForErrors} $supertype isn't substed");
       }
     }
     return result ?? supertypes;
@@ -616,7 +1359,9 @@
     List<KernelTypeBuilder> result =
         new List<KernelTypeBuilder>(cls.typeVariables.length);
     for (int i = 0; i < result.length; ++i) {
-      result[i] = cls.typeVariables[i].defaultType;
+      KernelTypeVariableBuilder tv = cls.typeVariables[i];
+      result[i] = tv.defaultType ??
+          cls.library.loader.computeTypeBuilder(tv.target.defaultType);
     }
     return result;
   }
@@ -644,8 +1389,10 @@
     return null;
   }
 
-  MergeResult mergeInterfaces(KernelClassBuilder cls,
+  MergeResult mergeInterfaces(
       ClassHierarchyNode supernode, List<KernelTypeBuilder> interfaces) {
+    debug?.log(
+        "mergeInterfaces($cls (${this.cls}) ${supernode.interfaces} ${interfaces}");
     List<List<Declaration>> memberLists =
         new List<List<Declaration>>(interfaces.length + 1);
     List<List<Declaration>> setterLists =
@@ -665,12 +1412,12 @@
             interfaceNode.interfaceSetters ?? interfaceNode.classSetters;
       }
     }
-    return new MergeResult(
-        mergeLists(cls, memberLists), mergeLists(cls, setterLists));
+    return new MergeResult(mergeLists(memberLists, MergeKind.interfacesMembers),
+        mergeLists(setterLists, MergeKind.interfacesSetters));
   }
 
   List<Declaration> mergeLists(
-      KernelClassBuilder cls, List<List<Declaration>> input) {
+      List<List<Declaration>> input, MergeKind mergeKind) {
     // This is a k-way merge sort (where k is `input.length + 1`). We merge the
     // lists pairwise, which reduces the number of lists to merge by half on
     // each iteration. Consequently, we perform O(log k) merges.
@@ -684,7 +1431,7 @@
         } else if (second == null) {
           output.add(first);
         } else {
-          output.add(merge(cls, first, second, MergeKind.interfaces));
+          output.add(merge(first, second, mergeKind));
         }
       }
       if (input.length.isOdd) {
@@ -698,7 +1445,7 @@
   /// Merge [and check] accessors. This entails copying mutable fields to
   /// setters to simulate implied setters, and checking that setters don't
   /// override regular methods.
-  List<Declaration> mergeAccessors(KernelClassBuilder cls,
+  List<Declaration> mergeAccessors(
       List<Declaration> members, List<Declaration> setters) {
     final List<Declaration> mergedSetters = new List<Declaration>.filled(
         members.length + setters.length, null,
@@ -743,7 +1490,7 @@
     }
   }
 
-  void reportMissingMembers(KernelClassBuilder cls) {
+  void reportMissingMembers() {
     Map<String, LocatedMessage> contextMap = <String, LocatedMessage>{};
     for (int i = 0; i < abstractMembers.length; i++) {
       Declaration declaration = abstractMembers[i];
@@ -773,12 +1520,12 @@
         context: context);
   }
 
-  void installNsmHandlers(KernelClassBuilder cls) {
+  void installNsmHandlers() {
     // TOOD(ahe): Implement this.
   }
 
-  List<Declaration> merge(KernelClassBuilder cls, List<Declaration> aList,
-      List<Declaration> bList, MergeKind mergeKind) {
+  List<Declaration> merge(
+      List<Declaration> aList, List<Declaration> bList, MergeKind mergeKind) {
     final List<Declaration> result = new List<Declaration>.filled(
         aList.length + bList.length, null,
         growable: true);
@@ -788,7 +1535,9 @@
     while (i < aList.length && j < bList.length) {
       final Declaration a = aList[i];
       final Declaration b = bList[j];
-      if (mergeKind == MergeKind.interfaces && a.isStatic) {
+      if ((mergeKind == MergeKind.interfacesMembers ||
+              mergeKind == MergeKind.interfacesSetters) &&
+          a.isStatic) {
         i++;
         continue;
       }
@@ -798,7 +1547,7 @@
       }
       final int compare = compareDeclarations(a, b);
       if (compare == 0) {
-        result[storeIndex++] = handleMergeConflict(cls, a, b, mergeKind);
+        result[storeIndex++] = handleMergeConflict(a, b, mergeKind);
         i++;
         j++;
       } else if (compare < 0) {
@@ -806,14 +1555,15 @@
         result[storeIndex++] = a;
         i++;
       } else {
-        handleOnlyB(cls, b, mergeKind);
-        result[storeIndex++] = b;
+        result[storeIndex++] = handleOnlyB(b, mergeKind);
         j++;
       }
     }
     while (i < aList.length) {
       final Declaration a = aList[i];
-      if (mergeKind != MergeKind.interfaces || !a.isStatic) {
+      if (!(mergeKind == MergeKind.interfacesMembers ||
+              mergeKind == MergeKind.interfacesSetters) ||
+          !a.isStatic) {
         handleOnlyA(a, mergeKind);
         result[storeIndex++] = a;
       }
@@ -822,8 +1572,7 @@
     while (j < bList.length) {
       final Declaration b = bList[j];
       if (!b.isStatic) {
-        handleOnlyB(cls, b, mergeKind);
-        result[storeIndex++] = b;
+        result[storeIndex++] = handleOnlyB(b, mergeKind);
       }
       j++;
     }
@@ -853,6 +1602,25 @@
     KernelNamedTypeBuilder mixedInType = cls.mixedInType;
     mixedInType.arguments = inferredArguments;
   }
+
+  /// The class Function from dart:core is supposed to be ignored when used as
+  /// an interface.
+  List<KernelTypeBuilder> ignoreFunction(List<KernelTypeBuilder> interfaces) {
+    if (interfaces == null) return null;
+    for (int i = 0; i < interfaces.length; i++) {
+      KernelClassBuilder cls = getClass(interfaces[i]);
+      if (cls != null && cls.target == hierarchy.functionKernelClass) {
+        if (interfaces.length == 1) {
+          return null;
+        } else {
+          interfaces = interfaces.toList();
+          interfaces.removeAt(i);
+          return ignoreFunction(interfaces);
+        }
+      }
+    }
+    return interfaces;
+  }
 }
 
 class ClassHierarchyNode {
@@ -980,6 +1748,42 @@
     }
   }
 
+  Declaration getInterfaceMember(Name name, bool isSetter) {
+    return findMember(
+        name,
+        isSetter
+            ? interfaceSetters ?? classSetters
+            : interfaceMembers ?? classMembers);
+  }
+
+  Declaration findMember(Name name, List<Declaration> declarations) {
+    // TODO(ahe): Consider creating a map or scope. The obvious choice would be
+    // to use scopes, but they don't handle private names correctly.
+
+    // This is a copy of `ClassHierarchy.findMemberByName`.
+    int low = 0, high = declarations.length - 1;
+    while (low <= high) {
+      int mid = low + ((high - low) >> 1);
+      Declaration pivot = declarations[mid];
+      int comparison = ClassHierarchy.compareNames(name, pivot.target.name);
+      if (comparison < 0) {
+        high = mid - 1;
+      } else if (comparison > 0) {
+        low = mid + 1;
+      } else if (high != mid) {
+        // Ensure we find the first element of the given name.
+        high = mid;
+      } else {
+        return pivot;
+      }
+    }
+    return null;
+  }
+
+  Declaration getDispatchTarget(Name name, bool isSetter) {
+    return findMember(name, isSetter ? classSetters : classMembers);
+  }
+
   static int compareMaxInheritancePath(
       ClassHierarchyNode a, ClassHierarchyNode b) {
     return b.maxInheritancePath.compareTo(a.maxInheritancePath);
@@ -996,17 +1800,28 @@
 
 enum MergeKind {
   /// Merging superclass members with the current class.
-  superclass,
+  superclassMembers,
 
-  /// Merging two interfaces.
-  interfaces,
+  /// Merging superclass setters with the current class.
+  superclassSetters,
+
+  /// Merging members of two interfaces.
+  interfacesMembers,
+
+  /// Merging setters of two interfaces.
+  interfacesSetters,
 
   /// Merging class members with interface members.
-  supertypes,
+  supertypesMembers,
 
-  /// Merging members with inherited setters, or setters with inherited
-  /// members.
-  accessors,
+  /// Merging class setters with interface setters.
+  supertypesSetters,
+
+  /// Merging members with inherited setters.
+  membersWithSetters,
+
+  /// Merging setters with inherited members.
+  settersWithMembers,
 }
 
 List<LocatedMessage> inheritedConflictContext(Declaration a, Declaration b) {
@@ -1123,3 +1938,627 @@
     return hierarchy.getKernelLegacyLeastUpperBound(type1, type2);
   }
 }
+
+class DelayedOverrideCheck {
+  final KernelClassBuilder cls;
+  final Declaration a;
+  final Declaration b;
+
+  const DelayedOverrideCheck(this.cls, this.a, this.b);
+
+  void check(ClassHierarchyBuilder hierarchy) {
+    void callback(
+        Member declaredMember, Member interfaceMember, bool isSetter) {
+      cls.checkOverride(
+          hierarchy.types, declaredMember, interfaceMember, isSetter, callback,
+          isInterfaceCheck: !cls.isMixinApplication);
+    }
+
+    Declaration a = this.a;
+    debug?.log(
+        "Delayed override check of ${fullName(a)} ${fullName(b)} wrt. ${cls.fullNameForErrors}");
+    if (cls == a.parent) {
+      if (a is KernelProcedureBuilder) {
+        if (a.isGetter && !hasExplicitReturnType(a)) {
+          DartType type;
+          if (b.isGetter) {
+            Procedure bTarget = b.target;
+            type = bTarget.function.returnType;
+          } else if (b.isSetter) {
+            Procedure bTarget = b.target;
+            type = bTarget.function.positionalParameters.single.type;
+          } else if (b.isField) {
+            Field bTarget = b.target;
+            type = bTarget.type;
+          }
+          if (type != null) {
+            type = Substitution.fromInterfaceType(
+                    hierarchy.getKernelTypeAsInstanceOf(
+                        cls.cls.thisType, b.target.enclosingClass))
+                .substituteType(type);
+            if (!a.hadTypesInferred || !b.isSetter) {
+              inferReturnType(cls, a, type, a.hadTypesInferred, hierarchy);
+            }
+          }
+        } else if (a.isSetter && !hasExplictlyTypedFormalParameter(a, 0)) {
+          DartType type;
+          if (b.isGetter) {
+            Procedure bTarget = b.target;
+            type = bTarget.function.returnType;
+          } else if (b.isSetter) {
+            Procedure bTarget = b.target;
+            type = bTarget.function.positionalParameters.single.type;
+          } else if (b.isField) {
+            Field bTarget = b.target;
+            type = bTarget.type;
+          }
+          if (type != null) {
+            type = Substitution.fromInterfaceType(
+                    hierarchy.getKernelTypeAsInstanceOf(
+                        cls.cls.thisType, b.target.enclosingClass))
+                .substituteType(type);
+            if (!a.hadTypesInferred || !b.isGetter) {
+              inferParameterType(cls, a, a.formals.single, type,
+                  a.hadTypesInferred, hierarchy);
+            }
+          }
+        }
+        a.hadTypesInferred = true;
+      } else if (a is KernelFieldBuilder && a.type == null) {
+        DartType type;
+        if (b.isGetter) {
+          Procedure bTarget = b.target;
+          type = bTarget.function.returnType;
+        } else if (b.isSetter) {
+          Procedure bTarget = b.target;
+          type = bTarget.function.positionalParameters.single.type;
+        } else if (b.isField) {
+          Field bTarget = b.target;
+          type = bTarget.type;
+        }
+        if (type != null) {
+          type = Substitution.fromInterfaceType(
+                  hierarchy.getKernelTypeAsInstanceOf(
+                      cls.cls.thisType, b.target.enclosingClass))
+              .substituteType(type);
+          if (type != a.target.type) {
+            if (a.hadTypesInferred) {
+              if (b.isSetter &&
+                  (!impliesSetter(a) ||
+                      hierarchy.types.isSubtypeOfKernel(type, a.target.type))) {
+                type = a.target.type;
+              } else {
+                reportCantInferFieldType(cls, a);
+                type = const InvalidType();
+              }
+            }
+            debug?.log("Inferred type ${type} for ${fullName(a)}");
+            a.target.type = type;
+          }
+        }
+        a.hadTypesInferred = true;
+      }
+    }
+
+    callback(a.target, b.target, a.isSetter);
+  }
+}
+
+abstract class DelayedMember extends Declaration {
+  /// The class which has inherited [declarations].
+  @override
+  final KernelClassBuilder parent;
+
+  /// Conflicting declarations.
+  final List<Declaration> declarations;
+
+  final isSetter;
+
+  final bool modifyKernel;
+
+  DelayedMember(
+      this.parent, this.declarations, this.isSetter, this.modifyKernel);
+
+  void addAllDeclarationsTo(List<Declaration> declarations) {
+    for (int i = 0; i < this.declarations.length; i++) {
+      addDeclarationIfDifferent(this.declarations[i], declarations);
+    }
+    assert(declarations.toSet().length == declarations.length);
+  }
+
+  Member check(ClassHierarchyBuilder hierarchy);
+
+  DelayedMember withParent(KernelClassBuilder parent);
+
+  @override
+  Uri get fileUri => parent.fileUri;
+
+  @override
+  int get charOffset => parent.charOffset;
+
+  @override
+  String get fullNameForErrors => declarations.map(fullName).join("%");
+
+  @override
+  Member get target => declarations.first.target;
+}
+
+/// This represents a concrete implementation inherited from a superclass that
+/// has conflicts with methods inherited from an interface. The concrete
+/// implementation is the first element of [declarations].
+class InheritedImplementationInterfaceConflict extends DelayedMember {
+  Member combinedMemberSignatureResult;
+
+  InheritedImplementationInterfaceConflict(KernelClassBuilder parent,
+      List<Declaration> declarations, bool isSetter, bool modifyKernel)
+      : super(parent, declarations, isSetter, modifyKernel);
+
+  @override
+  String toString() {
+    return "InheritedImplementationInterfaceConflict("
+        "${parent.fullNameForErrors}, "
+        "[${declarations.map(fullName).join(', ')}])";
+  }
+
+  @override
+  Member check(ClassHierarchyBuilder hierarchy) {
+    if (combinedMemberSignatureResult != null) {
+      return combinedMemberSignatureResult;
+    }
+    if (!parent.isAbstract) {
+      Declaration concreteImplementation = declarations.first;
+      for (int i = 1; i < declarations.length; i++) {
+        new DelayedOverrideCheck(
+                parent, concreteImplementation, declarations[i])
+            .check(hierarchy);
+      }
+    }
+    return combinedMemberSignatureResult =
+        new InterfaceConflict(parent, declarations, isSetter, modifyKernel)
+            .check(hierarchy);
+  }
+
+  @override
+  DelayedMember withParent(KernelClassBuilder parent) {
+    return parent == this.parent
+        ? this
+        : new InheritedImplementationInterfaceConflict(
+            parent, declarations, isSetter, modifyKernel);
+  }
+
+  static Declaration combined(
+      KernelClassBuilder parent,
+      Declaration concreteImplementation,
+      Declaration other,
+      bool isSetter,
+      bool createForwarders) {
+    List<Declaration> declarations = <Declaration>[];
+    if (concreteImplementation is DelayedMember) {
+      concreteImplementation.addAllDeclarationsTo(declarations);
+    } else {
+      declarations.add(concreteImplementation);
+    }
+    if (other is DelayedMember) {
+      other.addAllDeclarationsTo(declarations);
+    } else {
+      addDeclarationIfDifferent(other, declarations);
+    }
+    if (declarations.length == 1) {
+      return declarations.single;
+    } else {
+      return new InheritedImplementationInterfaceConflict(
+          parent, declarations, isSetter, createForwarders);
+    }
+  }
+}
+
+class InterfaceConflict extends DelayedMember {
+  InterfaceConflict(KernelClassBuilder parent, List<Declaration> declarations,
+      bool isSetter, bool modifyKernel)
+      : super(parent, declarations, isSetter, modifyKernel);
+
+  Member combinedMemberSignatureResult;
+
+  @override
+  String toString() {
+    return "InterfaceConflict(${parent.fullNameForErrors}, "
+        "[${declarations.map(fullName).join(', ')}])";
+  }
+
+  DartType computeMemberType(
+      ClassHierarchyBuilder hierarchy, DartType thisType, Member member) {
+    DartType type;
+    if (member is Procedure) {
+      if (member.isGetter) {
+        type = member.getterType;
+      } else if (member.isSetter) {
+        type = member.setterType;
+      } else {
+        type = member.function.functionType;
+      }
+    } else if (member is Field) {
+      type = member.type;
+    } else {
+      unhandled("${member.runtimeType}", "$member", parent.charOffset,
+          parent.fileUri);
+    }
+    return Substitution.fromInterfaceType(hierarchy.getKernelTypeAsInstanceOf(
+            thisType, member.enclosingClass))
+        .substituteType(type);
+  }
+
+  bool isMoreSpecific(ClassHierarchyBuilder hierarchy, DartType a, DartType b) {
+    if (isSetter) {
+      return hierarchy.types.isSubtypeOfKernel(b, a);
+    } else {
+      return hierarchy.types.isSubtypeOfKernel(a, b);
+    }
+  }
+
+  @override
+  Member check(ClassHierarchyBuilder hierarchy) {
+    if (combinedMemberSignatureResult != null) {
+      return combinedMemberSignatureResult;
+    }
+    if (parent.library is! KernelLibraryBuilder) {
+      return combinedMemberSignatureResult = declarations.first.target;
+    }
+    DartType thisType = parent.cls.thisType;
+    Declaration bestSoFar;
+    DartType bestTypeSoFar;
+    for (int i = declarations.length - 1; i >= 0; i--) {
+      Declaration candidate = declarations[i];
+      Member target = candidate.target;
+      DartType candidateType = computeMemberType(hierarchy, thisType, target);
+      if (bestSoFar == null) {
+        bestSoFar = candidate;
+        bestTypeSoFar = candidateType;
+      } else {
+        if (isMoreSpecific(hierarchy, candidateType, bestTypeSoFar)) {
+          debug?.log(
+              "Combined Member Signature: ${fullName(candidate)} ${candidateType} <: ${fullName(bestSoFar)} ${bestTypeSoFar}");
+          bestSoFar = candidate;
+          bestTypeSoFar = candidateType;
+        } else {
+          debug?.log(
+              "Combined Member Signature: ${fullName(candidate)} !<: ${fullName(bestSoFar)}");
+        }
+      }
+    }
+    if (bestSoFar != null) {
+      debug?.log("Combined Member Signature bestSoFar: ${fullName(bestSoFar)}");
+      for (int i = 0; i < declarations.length; i++) {
+        Declaration candidate = declarations[i];
+        Member target = candidate.target;
+        DartType candidateType = computeMemberType(hierarchy, thisType, target);
+        if (!isMoreSpecific(hierarchy, bestTypeSoFar, candidateType)) {
+          debug?.log(
+              "Combined Member Signature: ${fullName(bestSoFar)} !<: ${fullName(candidate)}");
+
+          String uri = '${parent.library.uri}';
+          if (uri == 'dart:js' &&
+                  parent.fileUri.pathSegments.last == 'js_dart2js.dart' ||
+              uri == 'dart:_interceptors' &&
+                  parent.fileUri.pathSegments.last == 'js_number.dart') {
+            // TODO(johnniwinther): Fix the dart2js libraries and remove the
+            // above URIs.
+          } else {
+            bestSoFar = null;
+            bestTypeSoFar = null;
+          }
+          break;
+        }
+      }
+    }
+    if (bestSoFar == null) {
+      String name = parent.fullNameForErrors;
+      int length = parent.isAnonymousMixinApplication ? 1 : name.length;
+      List<LocatedMessage> context = declarations.map((Declaration d) {
+        return messageDeclaredMemberConflictsWithInheritedMemberCause
+            .withLocation(d.fileUri, d.charOffset, d.fullNameForErrors.length);
+      }).toList();
+
+      parent.addProblem(
+          templateCombinedMemberSignatureFailed.withArguments(
+              parent.fullNameForErrors, declarations.first.fullNameForErrors),
+          parent.charOffset,
+          length,
+          context: context);
+      return null;
+    }
+    debug?.log(
+        "Combined Member Signature of ${fullNameForErrors}: ${fullName(bestSoFar)}");
+
+    ProcedureKind kind = ProcedureKind.Method;
+    if (bestSoFar.isField || bestSoFar.isSetter || bestSoFar.isGetter) {
+      kind = isSetter ? ProcedureKind.Setter : ProcedureKind.Getter;
+    }
+
+    if (modifyKernel) {
+      debug?.log(
+          "Combined Member Signature of ${fullNameForErrors}: new ForwardingNode($parent, $bestSoFar, $declarations, $kind)");
+      Member stub =
+          new ForwardingNode(hierarchy, parent, bestSoFar, declarations, kind)
+              .finalize();
+      if (parent.cls == stub.enclosingClass) {
+        parent.cls.addMember(stub);
+        KernelLibraryBuilder library = parent.library;
+        if (bestSoFar.target is Procedure) {
+          library.forwardersOrigins..add(stub)..add(bestSoFar.target);
+        }
+        debug?.log(
+            "Combined Member Signature of ${fullNameForErrors}: added stub $stub");
+        if (parent.isMixinApplication) {
+          return combinedMemberSignatureResult = bestSoFar.target;
+        } else {
+          return combinedMemberSignatureResult = stub;
+        }
+      }
+    }
+
+    debug?.log(
+        "Combined Member Signature of ${fullNameForErrors}: picked bestSoFar");
+    return combinedMemberSignatureResult = bestSoFar.target;
+  }
+
+  @override
+  DelayedMember withParent(KernelClassBuilder parent) {
+    return parent == this.parent
+        ? this
+        : new InterfaceConflict(parent, declarations, isSetter, modifyKernel);
+  }
+
+  static Declaration combined(KernelClassBuilder parent, Declaration a,
+      Declaration b, bool isSetter, bool createForwarders) {
+    List<Declaration> declarations = <Declaration>[];
+    if (a is DelayedMember) {
+      a.addAllDeclarationsTo(declarations);
+    } else {
+      declarations.add(a);
+    }
+    if (b is DelayedMember) {
+      b.addAllDeclarationsTo(declarations);
+    } else {
+      addDeclarationIfDifferent(b, declarations);
+    }
+    if (declarations.length == 1) {
+      return declarations.single;
+    } else {
+      return new InterfaceConflict(
+          parent, declarations, isSetter, createForwarders);
+    }
+  }
+}
+
+class AbstractMemberOverridingImplementation extends DelayedMember {
+  AbstractMemberOverridingImplementation(
+      KernelClassBuilder parent,
+      Declaration abstractMember,
+      Declaration concreteImplementation,
+      bool isSetter,
+      bool modifyKernel)
+      : super(parent, <Declaration>[concreteImplementation, abstractMember],
+            isSetter, modifyKernel);
+
+  Declaration get concreteImplementation => declarations[0];
+
+  Declaration get abstractMember => declarations[1];
+
+  Member check(ClassHierarchyBuilder hierarchy) {
+    if (!parent.isAbstract) {
+      new DelayedOverrideCheck(parent, concreteImplementation, abstractMember)
+          .check(hierarchy);
+    }
+
+    ProcedureKind kind = ProcedureKind.Method;
+    if (abstractMember.isSetter || abstractMember.isGetter) {
+      kind = isSetter ? ProcedureKind.Setter : ProcedureKind.Getter;
+    }
+    if (modifyKernel) {
+      // This call will add a body to the abstract method if needed for
+      // isGenericCovariantImpl checks.
+      new ForwardingNode(hierarchy, parent, abstractMember, declarations, kind)
+          .finalize();
+    }
+    return abstractMember.target;
+  }
+
+  @override
+  DelayedMember withParent(KernelClassBuilder parent) {
+    return parent == this.parent
+        ? this
+        : new AbstractMemberOverridingImplementation(parent, abstractMember,
+            concreteImplementation, isSetter, modifyKernel);
+  }
+
+  static Declaration selectAbstract(Declaration declaration) {
+    if (declaration is AbstractMemberOverridingImplementation) {
+      return declaration.abstractMember;
+    } else {
+      return declaration;
+    }
+  }
+
+  static Declaration selectConcrete(Declaration declaration) {
+    if (declaration is AbstractMemberOverridingImplementation) {
+      return declaration.concreteImplementation;
+    } else {
+      return declaration;
+    }
+  }
+}
+
+void addDeclarationIfDifferent(
+    Declaration declaration, List<Declaration> declarations) {
+  Member target = declaration.target;
+  if (target is Procedure) {
+    FunctionNode function = target.function;
+    for (int i = 0; i < declarations.length; i++) {
+      Member other = declarations[i].target;
+      if (other is Procedure) {
+        if (hasSameSignature(function, other.function)) return;
+      }
+    }
+  } else {
+    for (int i = 0; i < declarations.length; i++) {
+      if (declaration == declarations[i]) return;
+    }
+  }
+  declarations.add(declaration);
+}
+
+String fullName(Declaration declaration) {
+  if (declaration is DelayedMember) return declaration.fullNameForErrors;
+  Declaration parent = declaration.parent;
+  return parent == null
+      ? declaration.fullNameForErrors
+      : "${parent.fullNameForErrors}.${declaration.fullNameForErrors}";
+}
+
+int compareNamedParameters(VariableDeclaration a, VariableDeclaration b) {
+  return a.name.compareTo(b.name);
+}
+
+bool isAbstract(Declaration declaration) {
+  return declaration.target.isAbstract || declaration is InterfaceConflict;
+}
+
+bool inferParameterType(
+    KernelClassBuilder cls,
+    KernelProcedureBuilder member,
+    FormalParameterBuilder<KernelTypeBuilder> parameter,
+    DartType type,
+    bool hadTypesInferred,
+    ClassHierarchyBuilder hierarchy) {
+  debug?.log("Inferred type ${type} for ${parameter}");
+  if (type == parameter.target.type) return true;
+  bool result = true;
+  if (hadTypesInferred) {
+    reportCantInferParameterType(cls, member, parameter, hierarchy);
+    type = const InvalidType();
+    result = false;
+  }
+  parameter.target.type = type;
+  member.hadTypesInferred = true;
+  return result;
+}
+
+void reportCantInferParameterType(
+    KernelClassBuilder cls,
+    MemberBuilder member,
+    FormalParameterBuilder<KernelTypeBuilder> parameter,
+    ClassHierarchyBuilder hierarchy) {
+  String name = parameter.name;
+  cls.addProblem(
+      templateCantInferTypeDueToInconsistentOverrides.withArguments(name),
+      parameter.charOffset,
+      name.length,
+      wasHandled: true);
+}
+
+bool inferReturnType(KernelClassBuilder cls, KernelProcedureBuilder member,
+    DartType type, bool hadTypesInferred, ClassHierarchyBuilder hierarchy) {
+  if (type == member.target.function.returnType) return true;
+  bool result = true;
+  if (hadTypesInferred) {
+    reportCantInferReturnType(cls, member, hierarchy);
+    type = const InvalidType();
+    result = false;
+  } else {
+    member.hadTypesInferred = true;
+  }
+  member.target.function.returnType = type;
+  return result;
+}
+
+void reportCantInferReturnType(KernelClassBuilder cls, MemberBuilder member,
+    ClassHierarchyBuilder hierarchy) {
+  String name = member.fullNameForErrors;
+  List<LocatedMessage> context;
+  // // TODO(ahe): The following is for debugging, but could be cleaned up and
+  // // used to improve this error message in general.
+  //
+  // context = <LocatedMessage>[];
+  // ClassHierarchyNode supernode = hierarchy.getNodeFromType(cls.supertype);
+  // // TODO(ahe): Wrong template.
+  // Template<Message Function(String)> template =
+  //     templateMissingImplementationCause;
+  // if (supernode != null) {
+  //   Declaration superMember =
+  //       supernode.getInterfaceMember(new Name(name), false);
+  //   if (superMember != null) {
+  //     context.add(template
+  //         .withArguments(name)
+  //         .withLocation(
+  //             superMember.fileUri, superMember.charOffset, name.length));
+  //   }
+  //   superMember = supernode.getInterfaceMember(new Name(name), true);
+  //   if (superMember != null) {
+  //     context.add(template
+  //         .withArguments(name)
+  //         .withLocation(
+  //             superMember.fileUri, superMember.charOffset, name.length));
+  //   }
+  // }
+  // List<KernelTypeBuilder> directInterfaces = cls.interfaces;
+  // for (int i = 0; i < directInterfaces.length; i++) {
+  //   ClassHierarchyNode supernode =
+  //       hierarchy.getNodeFromType(directInterfaces[i]);
+  //   if (supernode != null) {
+  //     Declaration superMember =
+  //         supernode.getInterfaceMember(new Name(name), false);
+  //     if (superMember != null) {
+  //       context.add(template
+  //           .withArguments(name)
+  //           .withLocation(
+  //               superMember.fileUri, superMember.charOffset, name.length));
+  //     }
+  //     superMember = supernode.getInterfaceMember(new Name(name), true);
+  //     if (superMember != null) {
+  //       context.add(template
+  //           .withArguments(name)
+  //           .withLocation(
+  //               superMember.fileUri, superMember.charOffset, name.length));
+  //     }
+  //   }
+  // }
+  cls.addProblem(
+      templateCantInferReturnTypeDueToInconsistentOverrides.withArguments(name),
+      member.charOffset,
+      name.length,
+      wasHandled: true,
+      context: context);
+}
+
+void reportCantInferFieldType(
+    KernelClassBuilder cls, KernelFieldBuilder member) {
+  String name = member.fullNameForErrors;
+  cls.addProblem(
+      templateCantInferTypeDueToInconsistentOverrides.withArguments(name),
+      member.charOffset,
+      name.length,
+      wasHandled: true);
+}
+
+KernelClassBuilder getClass(KernelTypeBuilder type) {
+  Declaration declaration = type.declaration;
+  return declaration is KernelClassBuilder ? declaration : null;
+}
+
+bool hasExplicitReturnType(Declaration declaration) {
+  assert(
+      declaration is KernelProcedureBuilder || declaration is DillMemberBuilder,
+      "${declaration.runtimeType}");
+  return declaration is KernelProcedureBuilder
+      ? declaration.returnType != null
+      : true;
+}
+
+bool hasExplictlyTypedFormalParameter(Declaration declaration, int index) {
+  assert(
+      declaration is KernelProcedureBuilder || declaration is DillMemberBuilder,
+      "${declaration.runtimeType}");
+  return declaration is KernelProcedureBuilder
+      ? declaration.formals[index].type != null
+      : true;
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart b/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
new file mode 100644
index 0000000..441c827
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
@@ -0,0 +1,416 @@
+// 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:kernel/ast.dart"
+    show
+        Arguments,
+        Class,
+        DartType,
+        Expression,
+        Field,
+        FunctionNode,
+        Member,
+        Name,
+        NamedExpression,
+        Procedure,
+        ProcedureKind,
+        ReturnStatement,
+        SuperMethodInvocation,
+        SuperPropertyGet,
+        SuperPropertySet,
+        TypeParameter,
+        TypeParameterType,
+        VariableDeclaration,
+        VariableGet,
+        VoidType;
+
+import 'package:kernel/transformations/flags.dart' show TransformerFlag;
+
+import "package:kernel/type_algebra.dart" show Substitution;
+
+import "../problems.dart" show unhandled;
+
+import "../type_inference/type_inference_engine.dart"
+    show IncludesTypeParametersCovariantly;
+
+import "../type_inference/type_inferrer.dart" show getNamedFormal;
+
+import "kernel_builder.dart"
+    show ClassHierarchyBuilder, Declaration, DelayedMember, KernelClassBuilder;
+
+class ForwardingNode {
+  final ClassHierarchyBuilder hierarchy;
+
+  final KernelClassBuilder parent;
+
+  final Declaration combinedMemberSignatureResult;
+
+  final ProcedureKind kind;
+
+  /// A list containing the directly implemented and directly inherited
+  /// procedures of the class in question.
+  final List<Declaration> _candidates;
+
+  ForwardingNode(this.hierarchy, this.parent,
+      this.combinedMemberSignatureResult, this._candidates, this.kind);
+
+  Name get name => combinedMemberSignatureResult.target.name;
+
+  Class get enclosingClass => parent.cls;
+
+  /// Finishes handling of this node by propagating covariance and creating
+  /// forwarding stubs if necessary.
+  Member finalize() => _computeCovarianceFixes();
+
+  /// Tag the parameters of [interfaceMember] that need type checks
+  ///
+  /// Parameters can need type checks for calls coming from statically typed
+  /// call sites, due to covariant generics and overrides with explicit
+  /// `covariant` parameters.
+  ///
+  /// Tag parameters of [interfaceMember] that need such checks when the member
+  /// occurs in [enclosingClass]'s interface.  If parameters need checks but
+  /// they would not be checked in an inherited implementation, a forwarding
+  /// stub is introduced as a place to put the checks.
+  Member _computeCovarianceFixes() {
+    Member interfaceMember = combinedMemberSignatureResult.target;
+    Substitution substitution =
+        _substitutionFor(interfaceMember, enclosingClass);
+    // We always create a forwarding stub when we've inherited a member from an
+    // interface other than the first override candidate.  This is to work
+    // around a bug in the Kernel type checker where it chooses the first
+    // override candidate.
+    //
+    // TODO(kmillikin): Fix the Kernel type checker and stop creating these
+    // extra stubs.
+    Member stub = interfaceMember.enclosingClass == enclosingClass ||
+            interfaceMember == getCandidateAt(0)
+        ? interfaceMember
+        : _createForwardingStub(substitution, interfaceMember);
+
+    FunctionNode interfaceFunction = interfaceMember.function;
+    List<VariableDeclaration> interfacePositionalParameters =
+        getPositionalParameters(interfaceMember);
+    List<VariableDeclaration> interfaceNamedParameters =
+        interfaceFunction?.namedParameters ?? [];
+    List<TypeParameter> interfaceTypeParameters =
+        interfaceFunction?.typeParameters ?? [];
+
+    void createStubIfNeeded() {
+      if (stub != interfaceMember) return;
+      if (interfaceMember.enclosingClass == enclosingClass) return;
+      stub = _createForwardingStub(substitution, interfaceMember);
+    }
+
+    bool isImplCreated = false;
+    void createImplIfNeeded() {
+      if (isImplCreated) return;
+      createStubIfNeeded();
+      _createForwardingImplIfNeeded(stub.function);
+      isImplCreated = true;
+    }
+
+    IncludesTypeParametersCovariantly needsCheckVisitor = enclosingClass
+            .typeParameters.isEmpty
+        ? null
+        // TODO(ahe): It may be necessary to cache this object.
+        : new IncludesTypeParametersCovariantly(enclosingClass.typeParameters);
+    bool needsCheck(DartType type) => needsCheckVisitor == null
+        ? false
+        : substitution.substituteType(type).accept(needsCheckVisitor);
+    for (int i = 0; i < interfacePositionalParameters.length; i++) {
+      VariableDeclaration parameter = interfacePositionalParameters[i];
+      bool isGenericCovariantImpl =
+          parameter.isGenericCovariantImpl || needsCheck(parameter.type);
+      bool isCovariant = parameter.isCovariant;
+      VariableDeclaration superParameter = parameter;
+      for (int j = 0; j < _candidates.length; j++) {
+        Member otherMember = getCandidateAt(j);
+        if (otherMember is ForwardingNode) continue;
+        List<VariableDeclaration> otherPositionalParameters =
+            getPositionalParameters(otherMember);
+        if (otherPositionalParameters.length <= i) continue;
+        VariableDeclaration otherParameter = otherPositionalParameters[i];
+        if (j == 0) superParameter = otherParameter;
+        if (identical(otherMember, interfaceMember)) continue;
+        if (otherParameter.isGenericCovariantImpl) {
+          isGenericCovariantImpl = true;
+        }
+        if (otherParameter.isCovariant) {
+          isCovariant = true;
+        }
+      }
+      if (isGenericCovariantImpl) {
+        if (!superParameter.isGenericCovariantImpl) {
+          createImplIfNeeded();
+        }
+        if (!parameter.isGenericCovariantImpl) {
+          createStubIfNeeded();
+          stub.function.positionalParameters[i].isGenericCovariantImpl = true;
+        }
+      }
+      if (isCovariant) {
+        if (!superParameter.isCovariant) {
+          createImplIfNeeded();
+        }
+        if (!parameter.isCovariant) {
+          createStubIfNeeded();
+          stub.function.positionalParameters[i].isCovariant = true;
+        }
+      }
+    }
+    for (int i = 0; i < interfaceNamedParameters.length; i++) {
+      VariableDeclaration parameter = interfaceNamedParameters[i];
+      bool isGenericCovariantImpl =
+          parameter.isGenericCovariantImpl || needsCheck(parameter.type);
+      bool isCovariant = parameter.isCovariant;
+      VariableDeclaration superParameter = parameter;
+      for (int j = 0; j < _candidates.length; j++) {
+        Member otherMember = getCandidateAt(j);
+        if (otherMember is ForwardingNode) continue;
+        VariableDeclaration otherParameter =
+            getNamedFormal(otherMember.function, parameter.name);
+        if (otherParameter == null) continue;
+        if (j == 0) superParameter = otherParameter;
+        if (identical(otherMember, interfaceMember)) continue;
+        if (otherParameter.isGenericCovariantImpl) {
+          isGenericCovariantImpl = true;
+        }
+        if (otherParameter.isCovariant) {
+          isCovariant = true;
+        }
+      }
+      if (isGenericCovariantImpl) {
+        if (!superParameter.isGenericCovariantImpl) {
+          createImplIfNeeded();
+        }
+        if (!parameter.isGenericCovariantImpl) {
+          createStubIfNeeded();
+          stub.function.namedParameters[i].isGenericCovariantImpl = true;
+        }
+      }
+      if (isCovariant) {
+        if (!superParameter.isCovariant) {
+          createImplIfNeeded();
+        }
+        if (!parameter.isCovariant) {
+          createStubIfNeeded();
+          stub.function.namedParameters[i].isCovariant = true;
+        }
+      }
+    }
+    for (int i = 0; i < interfaceTypeParameters.length; i++) {
+      TypeParameter typeParameter = interfaceTypeParameters[i];
+      bool isGenericCovariantImpl = typeParameter.isGenericCovariantImpl ||
+          needsCheck(typeParameter.bound);
+      TypeParameter superTypeParameter = typeParameter;
+      for (int j = 0; j < _candidates.length; j++) {
+        Member otherMember = getCandidateAt(j);
+        if (otherMember is ForwardingNode) continue;
+        List<TypeParameter> otherTypeParameters =
+            otherMember.function.typeParameters;
+        if (otherTypeParameters.length <= i) continue;
+        TypeParameter otherTypeParameter = otherTypeParameters[i];
+        if (j == 0) superTypeParameter = otherTypeParameter;
+        if (identical(otherMember, interfaceMember)) continue;
+        if (otherTypeParameter.isGenericCovariantImpl) {
+          isGenericCovariantImpl = true;
+        }
+      }
+      if (isGenericCovariantImpl) {
+        if (!superTypeParameter.isGenericCovariantImpl) {
+          createImplIfNeeded();
+        }
+        if (!typeParameter.isGenericCovariantImpl) {
+          createStubIfNeeded();
+          stub.function.typeParameters[i].isGenericCovariantImpl = true;
+        }
+      }
+    }
+    return stub;
+  }
+
+  void _createForwardingImplIfNeeded(FunctionNode function) {
+    if (function.body != null) {
+      // There is already an implementation; nothing further needs to be done.
+      return;
+    }
+    // Find the concrete implementation in the superclass; this is what we need
+    // to forward to.  If we can't find one, then the method is fully abstract
+    // and we don't need to do anything.
+    Class superclass = enclosingClass.superclass;
+    if (superclass == null) return;
+    Procedure procedure = function.parent;
+    Member superTarget = hierarchy.getDispatchTargetKernel(
+        superclass, procedure.name, kind == ProcedureKind.Setter);
+    if (superTarget == null) return;
+    if (superTarget is Procedure && superTarget.isForwardingStub) {
+      superTarget = _getForwardingStubSuperTarget(superTarget);
+    }
+    procedure.isAbstract = false;
+    if (!procedure.isForwardingStub) {
+      // This procedure exists abstractly in the source code; we need to make it
+      // concrete and give it a body that is a forwarding stub.  This situation
+      // is called a "forwarding semi-stub".
+      procedure.isForwardingStub = true;
+      procedure.isForwardingSemiStub = true;
+    }
+    List<Expression> positionalArguments = function.positionalParameters
+        .map<Expression>((parameter) => new VariableGet(parameter))
+        .toList();
+    List<NamedExpression> namedArguments = function.namedParameters
+        .map((parameter) =>
+            new NamedExpression(parameter.name, new VariableGet(parameter)))
+        .toList();
+    List<DartType> typeArguments = function.typeParameters
+        .map<DartType>((typeParameter) => new TypeParameterType(typeParameter))
+        .toList();
+    Arguments arguments = new Arguments(positionalArguments,
+        types: typeArguments, named: namedArguments);
+    Expression superCall;
+    switch (kind) {
+      case ProcedureKind.Method:
+      case ProcedureKind.Operator:
+        superCall = new SuperMethodInvocation(name, arguments, superTarget);
+        break;
+      case ProcedureKind.Getter:
+        superCall = new SuperPropertyGet(name, superTarget);
+        break;
+      case ProcedureKind.Setter:
+        superCall =
+            new SuperPropertySet(name, positionalArguments[0], superTarget);
+        break;
+      default:
+        unhandled('$kind', '_createForwardingImplIfNeeded', -1, null);
+        break;
+    }
+    function.body = new ReturnStatement(superCall)..parent = function;
+    procedure.transformerFlags |= TransformerFlag.superCalls;
+    procedure.forwardingStubSuperTarget = superTarget;
+  }
+
+  /// Creates a forwarding stub based on the given [target].
+  Procedure _createForwardingStub(Substitution substitution, Member target) {
+    VariableDeclaration copyParameter(VariableDeclaration parameter) {
+      return new VariableDeclaration(parameter.name,
+          type: substitution.substituteType(parameter.type),
+          isCovariant: parameter.isCovariant)
+        ..isGenericCovariantImpl = parameter.isGenericCovariantImpl;
+    }
+
+    List<TypeParameter> targetTypeParameters =
+        target.function?.typeParameters ?? [];
+    List<TypeParameter> typeParameters;
+    if (targetTypeParameters.isNotEmpty) {
+      typeParameters =
+          new List<TypeParameter>.filled(targetTypeParameters.length, null);
+      Map<TypeParameter, DartType> additionalSubstitution =
+          <TypeParameter, DartType>{};
+      for (int i = 0; i < targetTypeParameters.length; i++) {
+        TypeParameter targetTypeParameter = targetTypeParameters[i];
+        TypeParameter typeParameter = new TypeParameter(
+            targetTypeParameter.name, null)
+          ..isGenericCovariantImpl = targetTypeParameter.isGenericCovariantImpl;
+        typeParameters[i] = typeParameter;
+        additionalSubstitution[targetTypeParameter] =
+            new TypeParameterType(typeParameter);
+      }
+      substitution = Substitution.combine(
+          substitution, Substitution.fromMap(additionalSubstitution));
+      for (int i = 0; i < typeParameters.length; i++) {
+        typeParameters[i].bound =
+            substitution.substituteType(targetTypeParameters[i].bound);
+      }
+    }
+    List<VariableDeclaration> positionalParameters =
+        getPositionalParameters(target).map(copyParameter).toList();
+    List<VariableDeclaration> namedParameters =
+        target.function?.namedParameters?.map(copyParameter)?.toList() ?? [];
+    FunctionNode function = new FunctionNode(null,
+        positionalParameters: positionalParameters,
+        namedParameters: namedParameters,
+        typeParameters: typeParameters,
+        requiredParameterCount: getRequiredParameterCount(target),
+        returnType: substitution.substituteType(getReturnType(target)));
+    Member finalTarget;
+    if (target is Procedure && target.isForwardingStub) {
+      finalTarget = target.forwardingStubInterfaceTarget;
+    } else {
+      finalTarget = target;
+    }
+    return new Procedure(name, kind, function,
+        isAbstract: true,
+        isForwardingStub: true,
+        fileUri: enclosingClass.fileUri,
+        forwardingStubInterfaceTarget: finalTarget)
+      ..startFileOffset = enclosingClass.fileOffset
+      ..fileOffset = enclosingClass.fileOffset
+      ..parent = enclosingClass;
+  }
+
+  /// Returns the [i]th element of [_candidates], finalizing it if necessary.
+  Member getCandidateAt(int i) {
+    Declaration candidate = _candidates[i];
+    assert(candidate is! DelayedMember);
+    return candidate.target;
+  }
+
+  static Member _getForwardingStubSuperTarget(Procedure forwardingStub) {
+    // TODO(paulberry): when dartbug.com/31562 is fixed, this should become
+    // easier.
+    ReturnStatement body = forwardingStub.function.body;
+    Expression expression = body.expression;
+    if (expression is SuperMethodInvocation) {
+      return expression.interfaceTarget;
+    } else if (expression is SuperPropertySet) {
+      return expression.interfaceTarget;
+    } else {
+      return unhandled('${expression.runtimeType}',
+          '_getForwardingStubSuperTarget', -1, null);
+    }
+  }
+
+  Substitution _substitutionFor(Member candidate, Class class_) {
+    return Substitution.fromInterfaceType(hierarchy.getKernelTypeAsInstanceOf(
+        class_.thisType, candidate.enclosingClass));
+  }
+
+  List<VariableDeclaration> getPositionalParameters(Member member) {
+    if (member is Field) {
+      if (kind == ProcedureKind.Setter) {
+        return <VariableDeclaration>[
+          new VariableDeclaration("_",
+              type: member.type, isCovariant: member.isCovariant)
+            ..isGenericCovariantImpl = member.isGenericCovariantImpl
+        ];
+      } else {
+        return <VariableDeclaration>[];
+      }
+    } else {
+      return member.function.positionalParameters;
+    }
+  }
+
+  int getRequiredParameterCount(Member member) {
+    switch (kind) {
+      case ProcedureKind.Getter:
+        return 0;
+      case ProcedureKind.Setter:
+        return 1;
+      default:
+        return member.function.requiredParameterCount;
+    }
+  }
+
+  DartType getReturnType(Member member) {
+    switch (kind) {
+      case ProcedureKind.Getter:
+        return member is Field ? member.type : member.function.returnType;
+      case ProcedureKind.Setter:
+        return const VoidType();
+      default:
+        return member.function.returnType;
+    }
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
index fedc609..1074242 100644
--- a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
@@ -16,6 +16,7 @@
 class ImplicitFieldType extends DartType {
   final MemberBuilder member;
   Token initializerToken;
+  bool isStarted = false;
 
   get nullability =>
       unsupported("nullability", member.charOffset, member.fileUri);
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_builder.dart
index 0206595..146b7b2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_builder.dart
@@ -16,7 +16,8 @@
 
 export '../builder/builder.dart';
 
-export 'class_hierarchy_builder.dart' show ClassHierarchyBuilder;
+export 'class_hierarchy_builder.dart'
+    show ClassHierarchyBuilder, DelayedMember, DelayedOverrideCheck;
 
 export 'implicit_field_type.dart' show ImplicitFieldType;
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
index b36770c..fd09cca 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
@@ -123,6 +123,8 @@
 
 import 'kernel_target.dart' show KernelTarget;
 
+import 'types.dart' show Types;
+
 abstract class KernelClassBuilder
     extends ClassBuilder<KernelTypeBuilder, InterfaceType> {
   KernelClassBuilder actualOrigin;
@@ -538,7 +540,7 @@
   }
 
   void handleSeenCovariant(
-      ClassHierarchy hierarchy,
+      Types types,
       Member declaredMember,
       Member interfaceMember,
       bool isSetter,
@@ -546,9 +548,8 @@
     // When a parameter is covariant we have to check that we also
     // override the same member in all parents.
     for (Supertype supertype in interfaceMember.enclosingClass.supers) {
-      Member m = hierarchy.getInterfaceMember(
-          supertype.classNode, interfaceMember.name,
-          setter: isSetter);
+      Member m = types.hierarchy.getInterfaceMemberKernel(
+          supertype.classNode, interfaceMember.name, isSetter);
       if (m != null) {
         callback(declaredMember, m, isSetter);
       }
@@ -556,8 +557,7 @@
   }
 
   void checkOverride(
-      ClassHierarchy hierarchy,
-      TypeEnvironment typeEnvironment,
+      Types types,
       Member declaredMember,
       Member interfaceMember,
       bool isSetter,
@@ -573,25 +573,25 @@
     if (declaredMember is Procedure && interfaceMember is Procedure) {
       if (declaredMember.kind == ProcedureKind.Method &&
           interfaceMember.kind == ProcedureKind.Method) {
-        bool seenCovariant = checkMethodOverride(hierarchy, typeEnvironment,
-            declaredMember, interfaceMember, isInterfaceCheck);
+        bool seenCovariant = checkMethodOverride(
+            types, declaredMember, interfaceMember, isInterfaceCheck);
         if (seenCovariant) {
           handleSeenCovariant(
-              hierarchy, declaredMember, interfaceMember, isSetter, callback);
+              types, declaredMember, interfaceMember, isSetter, callback);
         }
       }
       if (declaredMember.kind == ProcedureKind.Getter &&
           interfaceMember.kind == ProcedureKind.Getter) {
-        checkGetterOverride(hierarchy, typeEnvironment, declaredMember,
-            interfaceMember, isInterfaceCheck);
+        checkGetterOverride(
+            types, declaredMember, interfaceMember, isInterfaceCheck);
       }
       if (declaredMember.kind == ProcedureKind.Setter &&
           interfaceMember.kind == ProcedureKind.Setter) {
-        bool seenCovariant = checkSetterOverride(hierarchy, typeEnvironment,
-            declaredMember, interfaceMember, isInterfaceCheck);
+        bool seenCovariant = checkSetterOverride(
+            types, declaredMember, interfaceMember, isInterfaceCheck);
         if (seenCovariant) {
           handleSeenCovariant(
-              hierarchy, declaredMember, interfaceMember, isSetter, callback);
+              types, declaredMember, interfaceMember, isSetter, callback);
         }
       }
     } else {
@@ -599,19 +599,24 @@
           declaredMember is Procedure && declaredMember.isGetter;
       bool interfaceMemberHasGetter = interfaceMember is Field ||
           interfaceMember is Procedure && interfaceMember.isGetter;
-      bool declaredMemberHasSetter = declaredMember is Field ||
+      bool declaredMemberHasSetter = (declaredMember is Field &&
+              !declaredMember.isFinal &&
+              !declaredMember.isConst) ||
           declaredMember is Procedure && declaredMember.isSetter;
-      bool interfaceMemberHasSetter = interfaceMember is Field ||
+      bool interfaceMemberHasSetter = (interfaceMember is Field &&
+              !interfaceMember.isFinal &&
+              !interfaceMember.isConst) ||
           interfaceMember is Procedure && interfaceMember.isSetter;
       if (declaredMemberHasGetter && interfaceMemberHasGetter) {
-        checkGetterOverride(hierarchy, typeEnvironment, declaredMember,
-            interfaceMember, isInterfaceCheck);
-      } else if (declaredMemberHasSetter && interfaceMemberHasSetter) {
-        bool seenCovariant = checkSetterOverride(hierarchy, typeEnvironment,
-            declaredMember, interfaceMember, isInterfaceCheck);
+        checkGetterOverride(
+            types, declaredMember, interfaceMember, isInterfaceCheck);
+      }
+      if (declaredMemberHasSetter && interfaceMemberHasSetter) {
+        bool seenCovariant = checkSetterOverride(
+            types, declaredMember, interfaceMember, isInterfaceCheck);
         if (seenCovariant) {
           handleSeenCovariant(
-              hierarchy, declaredMember, interfaceMember, isSetter, callback);
+              types, declaredMember, interfaceMember, isSetter, callback);
         }
       }
     }
@@ -619,85 +624,10 @@
   }
 
   void checkOverrides(
-      ClassHierarchy hierarchy, TypeEnvironment typeEnvironment) {
-    void overridePairCallback(
-        Member declaredMember, Member interfaceMember, bool isSetter) {
-      checkOverride(hierarchy, typeEnvironment, declaredMember, interfaceMember,
-          isSetter, overridePairCallback);
-    }
-
-    hierarchy.forEachOverridePair(cls, overridePairCallback);
-  }
+      ClassHierarchy hierarchy, TypeEnvironment typeEnvironment) {}
 
   void checkAbstractMembers(CoreTypes coreTypes, ClassHierarchy hierarchy,
-      TypeEnvironment typeEnvironment) {
-    // TODO(ahe): Move this to [ClassHierarchyBuilder].
-    if (isAbstract) {
-      // Unimplemented members allowed
-      return;
-    }
-
-    bool mustHaveImplementation(Member member) {
-      // Public member
-      if (!member.name.isPrivate) return true;
-      // Private member in different library
-      if (member.enclosingLibrary != cls.enclosingLibrary) return false;
-      // Private member in patch
-      if (member.fileUri != member.enclosingClass.fileUri) return false;
-      // Private member in same library
-      return true;
-    }
-
-    void overridePairCallback(
-        Member declaredMember, Member interfaceMember, bool isSetter) {
-      checkOverride(hierarchy, typeEnvironment, declaredMember, interfaceMember,
-          isSetter, overridePairCallback,
-          isInterfaceCheck: true);
-    }
-
-    void findMissingImplementations({bool setters}) {
-      List<Member> dispatchTargets =
-          hierarchy.getDispatchTargets(cls, setters: setters);
-      int targetIndex = 0;
-      for (Member interfaceMember
-          in hierarchy.getInterfaceMembers(cls, setters: setters)) {
-        if (mustHaveImplementation(interfaceMember)) {
-          while (targetIndex < dispatchTargets.length &&
-              ClassHierarchy.compareMembers(
-                      dispatchTargets[targetIndex], interfaceMember) <
-                  0) {
-            targetIndex++;
-          }
-          bool foundTarget = targetIndex < dispatchTargets.length &&
-              ClassHierarchy.compareMembers(
-                      dispatchTargets[targetIndex], interfaceMember) <=
-                  0;
-          if (foundTarget) {
-            Member dispatchTarget = dispatchTargets[targetIndex];
-            while (dispatchTarget is Procedure &&
-                !dispatchTarget.isExternal &&
-                dispatchTarget.forwardingStubSuperTarget != null) {
-              dispatchTarget =
-                  (dispatchTarget as Procedure).forwardingStubSuperTarget;
-            }
-            while (interfaceMember is Procedure &&
-                !interfaceMember.isExternal &&
-                interfaceMember.forwardingStubInterfaceTarget != null) {
-              interfaceMember =
-                  (interfaceMember as Procedure).forwardingStubInterfaceTarget;
-            }
-            if (!hierarchy.isSubtypeOf(dispatchTarget.enclosingClass,
-                interfaceMember.enclosingClass)) {
-              overridePairCallback(dispatchTarget, interfaceMember, setters);
-            }
-          }
-        }
-      }
-    }
-
-    findMissingImplementations(setters: false);
-    findMissingImplementations(setters: true);
-  }
+      TypeEnvironment typeEnvironment) {}
 
   bool hasUserDefinedNoSuchMethod(
       Class klass, ClassHierarchy hierarchy, Class objectClass) {
@@ -924,7 +854,7 @@
   }
 
   Substitution _computeInterfaceSubstitution(
-      ClassHierarchy hierarchy,
+      Types types,
       Member declaredMember,
       Member interfaceMember,
       FunctionNode declaredFunction,
@@ -932,8 +862,9 @@
       bool isInterfaceCheck) {
     Substitution interfaceSubstitution = Substitution.empty;
     if (interfaceMember.enclosingClass.typeParameters.isNotEmpty) {
-      interfaceSubstitution = Substitution.fromSupertype(
-          hierarchy.getClassAsInstanceOf(cls, interfaceMember.enclosingClass));
+      interfaceSubstitution = Substitution.fromInterfaceType(types.hierarchy
+          .getKernelTypeAsInstanceOf(
+              cls.thisType, interfaceMember.enclosingClass));
     }
     if (declaredFunction?.typeParameters?.length !=
         interfaceFunction?.typeParameters?.length) {
@@ -1000,17 +931,18 @@
   }
 
   Substitution _computeDeclaredSubstitution(
-      ClassHierarchy hierarchy, Member declaredMember) {
+      Types types, Member declaredMember) {
     Substitution declaredSubstitution = Substitution.empty;
     if (declaredMember.enclosingClass.typeParameters.isNotEmpty) {
-      declaredSubstitution = Substitution.fromSupertype(
-          hierarchy.getClassAsInstanceOf(cls, declaredMember.enclosingClass));
+      declaredSubstitution = Substitution.fromInterfaceType(types.hierarchy
+          .getKernelTypeAsInstanceOf(
+              cls.thisType, declaredMember.enclosingClass));
     }
     return declaredSubstitution;
   }
 
-  bool _checkTypes(
-      TypeEnvironment typeEnvironment,
+  void _checkTypes(
+      Types types,
       Substitution interfaceSubstitution,
       Substitution declaredSubstitution,
       Member declaredMember,
@@ -1021,7 +953,7 @@
       VariableDeclaration declaredParameter,
       bool isInterfaceCheck,
       {bool asIfDeclaredParameter = false}) {
-    if (library.loader.target.backendTarget.legacyMode) return false;
+    if (library.loader.target.backendTarget.legacyMode) return;
 
     if (interfaceSubstitution != null) {
       interfaceType = interfaceSubstitution.substituteType(interfaceType);
@@ -1034,9 +966,9 @@
     DartType subtype = inParameter ? interfaceType : declaredType;
     DartType supertype = inParameter ? declaredType : interfaceType;
 
-    if (typeEnvironment.isSubtypeOf(subtype, supertype)) {
+    if (types.isSubtypeOfKernel(subtype, supertype)) {
       // No problem--the proper subtyping relation is satisfied.
-    } else if (isCovariant && typeEnvironment.isSubtypeOf(supertype, subtype)) {
+    } else if (isCovariant && types.isSubtypeOfKernel(supertype, subtype)) {
       // No problem--the overriding parameter is marked "covariant" and has
       // a type which is a subtype of the parameter it overrides.
     } else if (subtype is InvalidType || supertype is InvalidType) {
@@ -1074,19 +1006,13 @@
                         interfaceMember.fileOffset, noLength)
               ] +
               inheritedContext(isInterfaceCheck, declaredMember));
-      return true;
     }
-    return false;
   }
 
   /// Returns whether a covariant parameter was seen and more methods thus have
   /// to be checked.
-  bool checkMethodOverride(
-      ClassHierarchy hierarchy,
-      TypeEnvironment typeEnvironment,
-      Procedure declaredMember,
-      Procedure interfaceMember,
-      bool isInterfaceCheck) {
+  bool checkMethodOverride(Types types, Procedure declaredMember,
+      Procedure interfaceMember, bool isInterfaceCheck) {
     assert(declaredMember.kind == ProcedureKind.Method);
     assert(interfaceMember.kind == ProcedureKind.Method);
     bool seenCovariant = false;
@@ -1094,7 +1020,7 @@
     FunctionNode interfaceFunction = interfaceMember.function;
 
     Substitution interfaceSubstitution = _computeInterfaceSubstitution(
-        hierarchy,
+        types,
         declaredMember,
         interfaceMember,
         declaredFunction,
@@ -1102,10 +1028,10 @@
         isInterfaceCheck);
 
     Substitution declaredSubstitution =
-        _computeDeclaredSubstitution(hierarchy, declaredMember);
+        _computeDeclaredSubstitution(types, declaredMember);
 
     _checkTypes(
-        typeEnvironment,
+        types,
         interfaceSubstitution,
         declaredSubstitution,
         declaredMember,
@@ -1160,7 +1086,7 @@
       var declaredParameter = declaredFunction.positionalParameters[i];
       var interfaceParameter = interfaceFunction.positionalParameters[i];
       _checkTypes(
-          typeEnvironment,
+          types,
           interfaceSubstitution,
           declaredSubstitution,
           declaredMember,
@@ -1237,7 +1163,7 @@
       }
       var declaredParameter = declaredNamedParameters.current;
       _checkTypes(
-          typeEnvironment,
+          types,
           interfaceSubstitution,
           declaredSubstitution,
           declaredMember,
@@ -1252,25 +1178,16 @@
     return seenCovariant;
   }
 
-  void checkGetterOverride(
-      ClassHierarchy hierarchy,
-      TypeEnvironment typeEnvironment,
-      Member declaredMember,
-      Member interfaceMember,
-      bool isInterfaceCheck) {
+  void checkGetterOverride(Types types, Member declaredMember,
+      Member interfaceMember, bool isInterfaceCheck) {
     Substitution interfaceSubstitution = _computeInterfaceSubstitution(
-        hierarchy,
-        declaredMember,
-        interfaceMember,
-        null,
-        null,
-        isInterfaceCheck);
+        types, declaredMember, interfaceMember, null, null, isInterfaceCheck);
     Substitution declaredSubstitution =
-        _computeDeclaredSubstitution(hierarchy, declaredMember);
+        _computeDeclaredSubstitution(types, declaredMember);
     var declaredType = declaredMember.getterType;
     var interfaceType = interfaceMember.getterType;
     _checkTypes(
-        typeEnvironment,
+        types,
         interfaceSubstitution,
         declaredSubstitution,
         declaredMember,
@@ -1284,29 +1201,25 @@
 
   /// Returns whether a covariant parameter was seen and more methods thus have
   /// to be checked.
-  bool checkSetterOverride(
-      ClassHierarchy hierarchy,
-      TypeEnvironment typeEnvironment,
-      Member declaredMember,
-      Member interfaceMember,
-      bool isInterfaceCheck) {
+  bool checkSetterOverride(Types types, Member declaredMember,
+      Member interfaceMember, bool isInterfaceCheck) {
     Substitution interfaceSubstitution = _computeInterfaceSubstitution(
-        hierarchy,
-        declaredMember,
-        interfaceMember,
-        null,
-        null,
-        isInterfaceCheck);
+        types, declaredMember, interfaceMember, null, null, isInterfaceCheck);
     Substitution declaredSubstitution =
-        _computeDeclaredSubstitution(hierarchy, declaredMember);
+        _computeDeclaredSubstitution(types, declaredMember);
     var declaredType = declaredMember.setterType;
     var interfaceType = interfaceMember.setterType;
     var declaredParameter =
         declaredMember.function?.positionalParameters?.elementAt(0);
     bool isCovariant = declaredParameter?.isCovariant ?? false;
-    if (declaredMember is Field) isCovariant = declaredMember.isCovariant;
+    if (!isCovariant && declaredMember is Field) {
+      isCovariant = declaredMember.isCovariant;
+    }
+    if (!isCovariant && interfaceMember is Field) {
+      isCovariant = interfaceMember.isCovariant;
+    }
     _checkTypes(
-        typeEnvironment,
+        types,
         interfaceSubstitution,
         declaredSubstitution,
         declaredMember,
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_enum_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_enum_builder.dart
index 484c95e..8ee7d22 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_enum_builder.dart
@@ -25,8 +25,6 @@
         ThisExpression,
         VariableGet;
 
-import 'kernel_shadow_ast.dart' show ShadowClass;
-
 import '../fasta_codes.dart'
     show
         LocatedMessage,
@@ -85,7 +83,7 @@
       String name,
       Scope scope,
       Scope constructors,
-      ShadowClass cls,
+      Class cls,
       this.enumConstantInfos,
       this.intType,
       this.listType,
@@ -115,7 +113,7 @@
     KernelTypeBuilder stringType = new KernelNamedTypeBuilder("String", null);
     KernelNamedTypeBuilder objectType =
         new KernelNamedTypeBuilder("Object", null);
-    ShadowClass cls = new ShadowClass(name: name);
+    Class cls = new Class(name: name);
     Map<String, MemberBuilder> members = <String, MemberBuilder>{};
     Map<String, MemberBuilder> constructors = <String, MemberBuilder>{};
     KernelNamedTypeBuilder selfType = new KernelNamedTypeBuilder(name, null);
@@ -255,7 +253,6 @@
     members.forEach(setParent);
     constructors.forEach(setParent);
     selfType.bind(enumBuilder);
-    ShadowClass.setBuilder(cls, enumBuilder);
     return enumBuilder;
   }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
index 88a91b4..d750874 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
@@ -5,13 +5,16 @@
 library fasta.kernel_field_builder;
 
 import 'package:kernel/ast.dart'
-    show Class, DartType, DynamicType, Expression, Field, Name, NullLiteral;
+    show Class, DartType, Expression, Field, InvalidType, Name, NullLiteral;
 
 import '../constant_context.dart' show ConstantContext;
 
-import '../fasta_codes.dart' show messageInternalProblemAlreadyInitialized;
+import '../fasta_codes.dart'
+    show
+        messageInternalProblemAlreadyInitialized,
+        templateCantInferTypeDueToCircularity;
 
-import '../problems.dart' show internalProblem, unsupported;
+import '../problems.dart' show internalProblem;
 
 import '../scanner.dart' show Token;
 
@@ -22,6 +25,10 @@
 import '../type_inference/type_inference_engine.dart'
     show IncludesTypeParametersCovariantly;
 
+import '../type_inference/type_inferrer.dart' show TypeInferrerImpl;
+
+import '../type_inference/type_schema.dart' show UnknownType;
+
 import 'kernel_body_builder.dart' show KernelBodyBuilder;
 
 import 'kernel_builder.dart'
@@ -36,18 +43,17 @@
         LibraryBuilder,
         MetadataBuilder;
 
-import 'kernel_shadow_ast.dart' show ShadowField;
-
 class KernelFieldBuilder extends FieldBuilder<Expression> {
-  final ShadowField field;
+  final Field field;
   final List<MetadataBuilder> metadata;
   final KernelTypeBuilder type;
   Token constInitializerToken;
 
+  bool hadTypesInferred = false;
+
   KernelFieldBuilder(this.metadata, this.type, String name, int modifiers,
       Declaration compilationUnit, int charOffset, int charEndOffset)
-      : field = new ShadowField(null, type == null,
-            fileUri: compilationUnit?.fileUri)
+      : field = new Field(null, fileUri: compilationUnit?.fileUri)
           ..fileOffset = charOffset
           ..fileEndOffset = charEndOffset,
         super(name, modifiers, compilationUnit, charOffset);
@@ -95,10 +101,6 @@
       ..hasImplicitGetter = isInstanceMember
       ..hasImplicitSetter = isInstanceMember && !isConst && !isFinal
       ..isStatic = !isInstanceMember;
-    if (isEligibleForInference && !isInstanceMember) {
-      library.loader.typeInferenceEngine
-          .recordStaticFieldInferenceCandidate(field, library);
-    }
     return field;
   }
 
@@ -130,27 +132,75 @@
 
   Field get target => field;
 
-  void prepareTopLevelInference() {
-    if (!isEligibleForInference) return;
+  @override
+  void inferType() {
     KernelLibraryBuilder library = this.library;
-    var typeInferrer = library.loader.typeInferenceEngine
-        .createTopLevelTypeInferrer(
-            field.enclosingClass?.thisType, field, null);
-    if (hasInitializer) {
-      if (field.type is! ImplicitFieldType) {
-        unsupported(
-            "$name has unexpected type ${field.type}", charOffset, fileUri);
-        return;
-      }
-      ImplicitFieldType type = field.type;
-      field.type = const DynamicType();
-      KernelBodyBuilder bodyBuilder =
-          new KernelBodyBuilder.forField(this, typeInferrer);
-      bodyBuilder.constantContext =
-          isConst ? ConstantContext.inferred : ConstantContext.none;
-      initializer = bodyBuilder.parseFieldInitializer(type.initializerToken);
-      type.initializerToken = null;
+    if (field.type is! ImplicitFieldType) {
+      // We have already inferred a type.
+      return;
     }
+    ImplicitFieldType type = field.type;
+    if (type.member != this) {
+      // The implicit type was inherited.
+      KernelFieldBuilder other = type.member;
+      other.inferCopiedType(field);
+      return;
+    }
+    if (type.isStarted) {
+      library.addProblem(
+          templateCantInferTypeDueToCircularity.withArguments(name),
+          charOffset,
+          name.length,
+          fileUri);
+      field.type = const InvalidType();
+      return;
+    }
+    type.isStarted = true;
+    TypeInferrerImpl typeInferrer = library.loader.typeInferenceEngine
+        .createTopLevelTypeInferrer(
+            fileUri, field.enclosingClass?.thisType, null);
+    KernelBodyBuilder bodyBuilder =
+        new KernelBodyBuilder.forField(this, typeInferrer);
+    bodyBuilder.constantContext =
+        isConst ? ConstantContext.inferred : ConstantContext.none;
+    initializer = bodyBuilder.parseFieldInitializer(type.initializerToken);
+    type.initializerToken = null;
+
+    DartType inferredType = typeInferrer.inferDeclarationType(typeInferrer
+        .inferExpression(field.initializer, const UnknownType(), true,
+            isVoidAllowed: true));
+
+    if (field.type is ImplicitFieldType) {
+      // `field.type` may have changed if a circularity was detected when
+      // [inferredType] was computed.
+      field.type = inferredType;
+
+      IncludesTypeParametersCovariantly needsCheckVisitor;
+      if (parent is ClassBuilder) {
+        Class enclosingClass = parent.target;
+        if (enclosingClass.typeParameters.isNotEmpty) {
+          needsCheckVisitor = new IncludesTypeParametersCovariantly(
+              enclosingClass.typeParameters);
+        }
+      }
+      if (needsCheckVisitor != null) {
+        if (field.type.accept(needsCheckVisitor)) {
+          field.isGenericCovariantImpl = true;
+        }
+      }
+    }
+
+    // The following is a hack. The outline should contain the compiled
+    // initializers, however, as top-level inference is subtly different from
+    // we need to compile the field initializer again when everything else is
+    // compiled.
+    field.initializer = null;
+  }
+
+  void inferCopiedType(Field other) {
+    inferType();
+    other.type = field.type;
+    other.initializer = null;
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
index 91a846a..6c5e907 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
@@ -103,6 +103,8 @@
         namedMixinApplicationMask,
         staticMask;
 
+import '../names.dart' show indexSetName;
+
 import '../problems.dart' show unexpected, unhandled;
 
 import '../severity.dart' show Severity;
@@ -203,6 +205,8 @@
 
   List<KernelFormalParameterBuilder> untypedInitializingFormals;
 
+  List<KernelFieldBuilder> implicitlyTypedFields;
+
   KernelLibraryBuilder(Uri uri, Uri fileUri, Loader loader, this.actualOrigin,
       [Scope scope, Library target])
       : library = target ??
@@ -648,6 +652,7 @@
     addBuilder(name, field, charOffset);
     if (!legacyMode && type == null && initializerToken != null) {
       field.target.type = new ImplicitFieldType(field, initializerToken);
+      (implicitlyTypedFields ??= <KernelFieldBuilder>[]).add(field);
     }
     loader.target.metadataCollector
         ?.setDocumentationComment(field.target, documentationComment);
@@ -713,6 +718,14 @@
       String nativeMethodName,
       {bool isTopLevel}) {
     MetadataCollector metadataCollector = loader.target.metadataCollector;
+    if (returnType == null) {
+      if (kind == ProcedureKind.Operator &&
+          identical(name, indexSetName.name)) {
+        returnType = addVoidType(charOffset);
+      } else if (kind == ProcedureKind.Setter) {
+        returnType = addVoidType(charOffset);
+      }
+    }
     ProcedureBuilder procedure = new KernelProcedureBuilder(
         metadata,
         modifiers,
@@ -1361,9 +1374,9 @@
   }
 
   @override
-  void includePart(
+  bool includePart(
       covariant KernelLibraryBuilder part, Set<Uri> usedParts, int partOffset) {
-    super.includePart(part, usedParts, partOffset);
+    if (!super.includePart(part, usedParts, partOffset)) return false;
     nativeMethods.addAll(part.nativeMethods);
     boundlessTypeVariables.addAll(part.boundlessTypeVariables);
     // Check that the targets are different. This is not normally a problem
@@ -1372,6 +1385,16 @@
       target.problemsAsJson ??= <String>[];
       target.problemsAsJson.addAll(part.target.problemsAsJson);
     }
+    List<KernelFieldBuilder> partImplicitlyTypedFields =
+        part.takeImplicitlyTypedFields();
+    if (partImplicitlyTypedFields != null) {
+      if (implicitlyTypedFields == null) {
+        implicitlyTypedFields = partImplicitlyTypedFields;
+      } else {
+        implicitlyTypedFields.addAll(partImplicitlyTypedFields);
+      }
+    }
+    return true;
   }
 
   @override
@@ -1827,6 +1850,13 @@
     untypedInitializingFormals = null;
     return count;
   }
+
+  @override
+  List<KernelFieldBuilder> takeImplicitlyTypedFields() {
+    List<KernelFieldBuilder> result = implicitlyTypedFields;
+    implicitlyTypedFields = null;
+    return result;
+  }
 }
 
 Uri computeLibraryUri(Declaration declaration) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_procedure_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_procedure_builder.dart
index 0e9e42e..d751f8c 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_procedure_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_procedure_builder.dart
@@ -30,7 +30,6 @@
         TypeParameter,
         TypeParameterType,
         VariableDeclaration,
-        VoidType,
         setParents;
 
 import 'package:kernel/type_algebra.dart' show containsTypeVariable, substitute;
@@ -74,8 +73,7 @@
         TypeVariableBuilder,
         isRedirectingGenerativeConstructorImplementation;
 
-import 'kernel_shadow_ast.dart'
-    show ShadowProcedure, VariableDeclarationJudgment;
+import 'kernel_shadow_ast.dart' show VariableDeclarationJudgment;
 
 import 'redirecting_factory_body.dart' show RedirectingFactoryBody;
 
@@ -275,7 +273,7 @@
 }
 
 class KernelProcedureBuilder extends KernelFunctionBuilder {
-  final ShadowProcedure procedure;
+  final Procedure procedure;
   final int charOpenParenOffset;
 
   AsyncMarker actualAsyncModifier = AsyncMarker.Sync;
@@ -283,6 +281,8 @@
   @override
   KernelProcedureBuilder actualOrigin;
 
+  bool hadTypesInferred = false;
+
   KernelProcedureBuilder(
       List<MetadataBuilder> metadata,
       int modifiers,
@@ -297,11 +297,11 @@
       this.charOpenParenOffset,
       int charEndOffset,
       [String nativeMethodName])
-      : procedure = new ShadowProcedure(null, kind, null, returnType == null,
-            fileUri: compilationUnit?.fileUri)
-          ..startFileOffset = startCharOffset
-          ..fileOffset = charOffset
-          ..fileEndOffset = charEndOffset,
+      : procedure =
+            new Procedure(null, kind, null, fileUri: compilationUnit?.fileUri)
+              ..startFileOffset = startCharOffset
+              ..fileOffset = charOffset
+              ..fileEndOffset = charEndOffset,
         super(metadata, modifiers, returnType, name, typeVariables, formals,
             compilationUnit, charOffset, nativeMethodName);
 
@@ -354,11 +354,6 @@
       procedure.isConst = isConst;
       procedure.name = new Name(name, library.target);
     }
-    if (!library.loader.target.legacyMode &&
-        (isSetter || (isOperator && name == '[]=')) &&
-        returnType == null) {
-      procedure.function.returnType = const VoidType();
-    }
     return procedure;
   }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
index e91b0a4..4a5bc98 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
@@ -59,10 +59,8 @@
 
 import '../type_inference/inference_helper.dart' show InferenceHelper;
 
-import '../type_inference/interface_resolver.dart' show InterfaceResolver;
-
 import '../type_inference/type_inference_engine.dart'
-    show IncludesTypeParametersCovariantly, InferenceNode, TypeInferenceEngine;
+    show IncludesTypeParametersCovariantly, TypeInferenceEngine;
 
 import '../type_inference/type_inferrer.dart'
     show ExpressionInferenceResult, TypeInferrer, TypeInferrerImpl;
@@ -280,59 +278,6 @@
   }
 }
 
-/// Shadow object representing a class in kernel form.
-class ShadowClass extends Class {
-  ClassInferenceInfo _inferenceInfo;
-
-  ShadowClass(
-      {String name,
-      Supertype supertype,
-      Supertype mixedInType,
-      List<TypeParameter> typeParameters,
-      List<Supertype> implementedTypes,
-      List<Procedure> procedures,
-      List<Field> fields})
-      : super(
-            name: name,
-            supertype: supertype,
-            mixedInType: mixedInType,
-            typeParameters: typeParameters,
-            implementedTypes: implementedTypes,
-            procedures: procedures,
-            fields: fields);
-
-  /// Resolves all forwarding nodes for this class, propagates covariance
-  /// annotations, and creates forwarding stubs as needed.
-  void finalizeCovariance(InterfaceResolver interfaceResolver) {
-    interfaceResolver.finalizeCovariance(
-        this, _inferenceInfo.gettersAndMethods, _inferenceInfo.builder.library);
-    interfaceResolver.finalizeCovariance(
-        this, _inferenceInfo.setters, _inferenceInfo.builder.library);
-  }
-
-  /// Creates API members for this class.
-  void setupApiMembers(InterfaceResolver interfaceResolver) {
-    interfaceResolver.createApiMembers(this, _inferenceInfo.gettersAndMethods,
-        _inferenceInfo.setters, _inferenceInfo.builder.library);
-  }
-
-  static void clearClassInferenceInfo(ShadowClass class_) {
-    class_._inferenceInfo = null;
-  }
-
-  static ClassInferenceInfo getClassInferenceInfo(Class class_) {
-    if (class_ is ShadowClass) return class_._inferenceInfo;
-    return null;
-  }
-
-  /// Initializes the class inference information associated with the given
-  /// [class_], starting with the fact that it is associated with the given
-  /// [builder].
-  static void setBuilder(ShadowClass class_, SourceClassBuilder builder) {
-    class_._inferenceInfo = new ClassInferenceInfo(builder);
-  }
-}
-
 /// Abstract shadow object representing a complex assignment in kernel form.
 ///
 /// Since there are many forms a complex assignment might have been desugared
@@ -635,32 +580,6 @@
   }
 }
 
-/// Concrete shadow object representing a field in kernel form.
-class ShadowField extends Field implements ShadowMember {
-  @override
-  InferenceNode inferenceNode;
-
-  ShadowTypeInferrer _typeInferrer;
-
-  final bool _isImplicitlyTyped;
-
-  ShadowField(Name name, this._isImplicitlyTyped, {Uri fileUri})
-      : super(name, fileUri: fileUri) {}
-
-  @override
-  void setInferredType(
-      TypeInferenceEngine engine, Uri uri, DartType inferredType) {
-    type = inferredType;
-  }
-
-  static bool isImplicitlyTyped(ShadowField field) => field._isImplicitlyTyped;
-
-  static void setInferenceNode(ShadowField field, InferenceNode node) {
-    assert(field.inferenceNode == null);
-    field.inferenceNode = node;
-  }
-}
-
 /// Concrete shadow object representing a field initializer in kernel form.
 class ShadowFieldInitializer extends FieldInitializer
     implements InitializerJudgment {
@@ -1000,18 +919,6 @@
   }
 }
 
-/// Abstract shadow object representing a field or procedure in kernel form.
-abstract class ShadowMember implements Member {
-  Uri get fileUri;
-
-  InferenceNode get inferenceNode;
-
-  void set inferenceNode(InferenceNode value);
-
-  void setInferredType(
-      TypeInferenceEngine engine, Uri uri, DartType inferredType);
-}
-
 /// Shadow object for [MethodInvocation].
 class MethodInvocationJudgment extends MethodInvocation
     implements ExpressionJudgment {
@@ -1110,37 +1017,6 @@
   }
 }
 
-/// Concrete shadow object representing a procedure in kernel form.
-class ShadowProcedure extends Procedure implements ShadowMember {
-  @override
-  InferenceNode inferenceNode;
-
-  final bool _hasImplicitReturnType;
-
-  ShadowProcedure(Name name, ProcedureKind kind, FunctionNode function,
-      this._hasImplicitReturnType,
-      {Uri fileUri, bool isAbstract: false})
-      : super(name, kind, function, fileUri: fileUri, isAbstract: isAbstract);
-
-  @override
-  void setInferredType(
-      TypeInferenceEngine engine, Uri uri, DartType inferredType) {
-    if (isSetter) {
-      if (function.positionalParameters.length > 0) {
-        function.positionalParameters[0].type = inferredType;
-      }
-    } else if (isGetter) {
-      function.returnType = inferredType;
-    } else {
-      unhandled("setInferredType", "not accessor", fileOffset, uri);
-    }
-  }
-
-  static bool hasImplicitReturnType(ShadowProcedure procedure) {
-    return procedure._hasImplicitReturnType;
-  }
-}
-
 /// Concrete shadow object representing an assignment to a property.
 class PropertyAssignmentJudgment extends ComplexAssignmentJudgmentWithReceiver {
   /// If this assignment uses null-aware access (`?.`), the conditional
@@ -1470,14 +1346,8 @@
 
   @override
   ShadowTypeInferrer createTopLevelTypeInferrer(
-      InterfaceType thisType, ShadowField field, KernelLibraryBuilder library) {
-    return field._typeInferrer =
-        new TypeInferrer(this, field.fileUri, true, thisType, library);
-  }
-
-  @override
-  ShadowTypeInferrer getFieldTypeInferrer(ShadowField field) {
-    return field._typeInferrer;
+      Uri uri, InterfaceType thisType, KernelLibraryBuilder library) {
+    return new TypeInferrer(this, uri, true, thisType, library);
   }
 }
 
@@ -1493,7 +1363,7 @@
         super.private(engine, uri, topLevel, thisType, library);
 
   @override
-  Expression getFieldInitializer(ShadowField field) {
+  Expression getFieldInitializer(Field field) {
     return field.initializer;
   }
 
@@ -1536,13 +1406,6 @@
   }
 
   @override
-  DartType inferFieldTopLevel(ShadowField field) {
-    if (field.initializer == null) return const DynamicType();
-    return inferExpression(field.initializer, const UnknownType(), true,
-        isVoidAllowed: true);
-  }
-
-  @override
   void inferInitializer(
       InferenceHelper helper, kernel.Initializer initializer) {
     assert(initializer is InitializerJudgment);
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index 5d67c40..0128ab2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -87,7 +87,6 @@
 import 'kernel_builder.dart'
     show
         ClassBuilder,
-        ClassHierarchyBuilder,
         Declaration,
         InvalidTypeBuilder,
         KernelClassBuilder,
@@ -152,8 +151,6 @@
     loader = createLoader();
   }
 
-  void set builderHierarchy(ClassHierarchyBuilder o) {}
-
   SourceLoader createLoader() =>
       new SourceLoader(fileSystem, includeComments, this);
 
@@ -268,8 +265,7 @@
       component =
           link(new List<Library>.from(loader.libraries), nameRoot: nameRoot);
       computeCoreTypes();
-      builderHierarchy =
-          loader.buildClassHierarchy(myClasses, objectClassBuilder);
+      loader.buildClassHierarchy(myClasses, objectClassBuilder);
       loader.computeHierarchy();
       loader.performTopLevelInference(myClasses);
       loader.checkSupertypes(myClasses);
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 09cd1c9..3adef89 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -41,21 +41,19 @@
         TypeVariableBuilder,
         compareProcedures;
 
-import '../kernel/kernel_shadow_ast.dart' show ShadowClass;
-
 import '../kernel/type_algorithms.dart' show Variance, computeVariance;
 
 import '../problems.dart' show unexpected, unhandled;
 
-ShadowClass initializeClass(
-    ShadowClass cls,
+Class initializeClass(
+    Class cls,
     List<TypeVariableBuilder> typeVariables,
     String name,
     KernelLibraryBuilder parent,
     int startCharOffset,
     int charOffset,
     int charEndOffset) {
-  cls ??= new ShadowClass(
+  cls ??= new Class(
       name: name,
       typeParameters:
           KernelTypeVariableBuilder.kernelTypeParametersFromBuilders(
@@ -105,12 +103,10 @@
       : actualCls = initializeClass(cls, typeVariables, name, parent,
             startCharOffset, charOffset, charEndOffset),
         super(metadata, modifiers, name, typeVariables, supertype, interfaces,
-            scope, constructors, parent, charOffset) {
-    ShadowClass.setBuilder(this.cls, this);
-  }
+            scope, constructors, parent, charOffset);
 
   @override
-  ShadowClass get cls => origin.actualCls;
+  Class get cls => origin.actualCls;
 
   @override
   KernelLibraryBuilder get library => super.library;
@@ -278,20 +274,6 @@
     constructorScopeBuilder.addMember(name, memberBuilder);
   }
 
-  void prepareTopLevelInference() {
-    scope.forEach((String name, Declaration declaration) {
-      do {
-        if (declaration is KernelFieldBuilder) {
-          declaration.prepareTopLevelInference();
-        }
-        declaration = declaration.next;
-      } while (declaration != null);
-    });
-    if (!isPatch) {
-      cls.setupApiMembers(library.loader.interfaceResolver);
-    }
-  }
-
   @override
   int finishPatch() {
     if (!isPatch) return 0;
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 89abbb2..6fba08ef 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -703,7 +703,7 @@
     }
   }
 
-  void includePart(
+  bool includePart(
       SourceLibraryBuilder<T, R> part, Set<Uri> usedParts, int partOffset) {
     if (part.partOfUri != null) {
       if (uriIsValid(part.partOfUri) && part.partOfUri != uri) {
@@ -715,7 +715,7 @@
             partOffset,
             noLength,
             fileUri);
-        return;
+        return false;
       }
     } else if (part.partOfName != null) {
       if (name != null) {
@@ -728,7 +728,7 @@
               partOffset,
               noLength,
               fileUri);
-          return;
+          return false;
         }
       } else {
         // This is an error, but the part is not removed from the list of parts,
@@ -739,7 +739,7 @@
             partOffset,
             noLength,
             fileUri);
-        return;
+        return false;
       }
     } else {
       // This is an error, but the part is not removed from the list of parts,
@@ -749,7 +749,7 @@
         addProblem(templateMissingPartOf.withArguments(part.fileUri),
             partOffset, noLength, fileUri);
       }
-      return;
+      return false;
     }
     part.validatePart(this, usedParts);
     NameIterator partDeclarations = part.nameIterator;
@@ -798,6 +798,7 @@
     part.partOfLibrary = this;
     part.scope.becomePartOf(scope);
     // TODO(ahe): Include metadata from part?
+    return true;
   }
 
   void buildInitialScopes() {
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 3040e27..74fcaa1 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -68,17 +68,18 @@
         templateSourceOutlineSummary,
         templateUntranslatableUri;
 
-import '../kernel/kernel_shadow_ast.dart'
-    show ShadowClass, ShadowTypeInferenceEngine;
+import '../kernel/kernel_shadow_ast.dart' show ShadowTypeInferenceEngine;
 
 import '../kernel/kernel_builder.dart'
     show
         ClassBuilder,
         ClassHierarchyBuilder,
         Declaration,
+        DelayedMember,
+        DelayedOverrideCheck,
         EnumBuilder,
+        FieldBuilder,
         KernelClassBuilder,
-        KernelFieldBuilder,
         KernelProcedureBuilder,
         KernelTypeBuilder,
         LibraryBuilder,
@@ -107,8 +108,6 @@
 import '../scanner.dart'
     show ErrorToken, ScannerConfiguration, ScannerResult, Token, scan;
 
-import '../type_inference/interface_resolver.dart' show InterfaceResolver;
-
 import 'diet_listener.dart' show DietListener;
 
 import 'diet_parser.dart' show DietParser;
@@ -128,6 +127,8 @@
 
   final Map<Uri, List<int>> sourceBytes = <Uri, List<int>>{};
 
+  ClassHierarchyBuilder builderHierarchy;
+
   // Used when building directly to kernel.
   ClassHierarchy hierarchy;
   CoreTypes coreTypes;
@@ -138,8 +139,6 @@
 
   ShadowTypeInferenceEngine typeInferenceEngine;
 
-  InterfaceResolver interfaceResolver;
-
   Instrumentation instrumentation;
 
   CollectionTransformer collectionTransformer;
@@ -609,6 +608,10 @@
             break;
           }
         }
+        if (allSupertypesProcessed && cls.isPatch) {
+          allSupertypesProcessed =
+              topologicallySortedClasses.contains(cls.origin);
+        }
         if (allSupertypesProcessed) {
           topologicallySortedClasses.add(cls);
           checkClassSupertypes(cls, directSupertypes, blackListedClasses);
@@ -884,27 +887,33 @@
   }
 
   void checkOverrides(List<SourceClassBuilder> sourceClasses) {
-    assert(hierarchy != null);
-    for (SourceClassBuilder builder in sourceClasses) {
-      if (builder.library.loader == this && !builder.isPatch) {
-        builder.checkOverrides(
-            hierarchy, typeInferenceEngine?.typeSchemaEnvironment);
-      }
+    List<DelayedOverrideCheck> overrideChecks =
+        builderHierarchy.overrideChecks.toList();
+    builderHierarchy.overrideChecks.clear();
+    for (int i = 0; i < overrideChecks.length; i++) {
+      overrideChecks[i].check(builderHierarchy);
     }
-    ticker.logMs("Checked overrides");
+    ticker.logMs("Checked ${overrideChecks.length} overrides");
+
+    typeInferenceEngine?.finishTopLevelInitializingFormals();
+    ticker.logMs("Finished initializing formals");
   }
 
   void checkAbstractMembers(List<SourceClassBuilder> sourceClasses) {
-    // TODO(ahe): Move this to [ClassHierarchyBuilder].
-    if (target.legacyMode) return;
-    assert(hierarchy != null);
-    for (SourceClassBuilder builder in sourceClasses) {
-      if (builder.library.loader == this && !builder.isPatch) {
-        builder.checkAbstractMembers(
-            coreTypes, hierarchy, typeInferenceEngine.typeSchemaEnvironment);
-      }
+    List<DelayedMember> delayedMemberChecks =
+        builderHierarchy.delayedMemberChecks.toList();
+    builderHierarchy.delayedMemberChecks.clear();
+    Set<Class> changedClasses = new Set<Class>();
+    for (int i = 0; i < delayedMemberChecks.length; i++) {
+      delayedMemberChecks[i].check(builderHierarchy);
+      changedClasses.add(delayedMemberChecks[i].parent.cls);
     }
-    ticker.logMs("Checked abstract members");
+    ticker.logMs(
+        "Computed ${delayedMemberChecks.length} combined member signatures");
+
+    hierarchy.applyMemberChanges(changedClasses, findDescendants: false);
+    ticker
+        .logMs("Updated ${changedClasses.length} classes in kernel hierarchy");
   }
 
   void checkRedirectingFactories(List<SourceClassBuilder> sourceClasses) {
@@ -968,12 +977,12 @@
     });
   }
 
-  ClassHierarchyBuilder buildClassHierarchy(
+  void buildClassHierarchy(
       List<SourceClassBuilder> sourceClasses, ClassBuilder objectClass) {
-    ClassHierarchyBuilder hierarchy = ClassHierarchyBuilder.build(
+    builderHierarchy = ClassHierarchyBuilder.build(
         objectClass, sourceClasses, this, coreTypes);
+    typeInferenceEngine?.hierarchyBuilder = builderHierarchy;
     ticker.logMs("Built class hierarchy");
-    return hierarchy;
   }
 
   void createTypeInferenceEngine() {
@@ -989,58 +998,30 @@
     /// might be subject to type inference, and records dependencies between
     /// them.
     typeInferenceEngine.prepareTopLevel(coreTypes, hierarchy);
-    interfaceResolver = new InterfaceResolver(typeInferenceEngine,
-        typeInferenceEngine.typeSchemaEnvironment, instrumentation);
+    List<FieldBuilder> allImplicitlyTypedFields = <FieldBuilder>[];
     for (LibraryBuilder library in builders.values) {
       if (library.loader == this) {
-        Iterator<Declaration> iterator = library.iterator;
-        while (iterator.moveNext()) {
-          Declaration member = iterator.current;
-          if (member is KernelFieldBuilder) {
-            member.prepareTopLevelInference();
-          }
+        List<FieldBuilder> implicitlyTypedFields =
+            library.takeImplicitlyTypedFields();
+        if (implicitlyTypedFields != null) {
+          allImplicitlyTypedFields.addAll(implicitlyTypedFields);
         }
       }
     }
-    for (int i = 0; i < sourceClasses.length; i++) {
-      sourceClasses[i].prepareTopLevelInference();
+
+    for (int i = 0; i < allImplicitlyTypedFields.length; i++) {
+      // TODO(ahe): This can cause a crash for parts that failed to get
+      // included, see for example,
+      // tests/standalone_2/io/http_cookie_date_test.dart.
+      allImplicitlyTypedFields[i].inferType();
     }
+
     typeInferenceEngine.isTypeInferencePrepared = true;
-    ticker.logMs("Prepared top level inference");
 
-    /// The second phase of top level initializer inference, which is to visit
-    /// fields and top level variables in topologically-sorted order and assign
-    /// their types.
-    typeInferenceEngine.finishTopLevelFields();
-    List<Class> changedClasses = new List<Class>();
-    for (var builder in sourceClasses) {
-      if (builder.isPatch) continue;
-      ShadowClass class_ = builder.target;
-      int memberCount = class_.fields.length +
-          class_.constructors.length +
-          class_.procedures.length +
-          class_.redirectingFactoryConstructors.length;
-      class_.finalizeCovariance(interfaceResolver);
-      ShadowClass.clearClassInferenceInfo(class_);
-      int newMemberCount = class_.fields.length +
-          class_.constructors.length +
-          class_.procedures.length +
-          class_.redirectingFactoryConstructors.length;
-      if (newMemberCount != memberCount) {
-        // The inference potentially adds new members (but doesn't otherwise
-        // change the classes), so if the member count has changed we need to
-        // update the class in the class hierarchy.
-        changedClasses.add(class_);
-      }
-    }
-
-    typeInferenceEngine.finishTopLevelInitializingFormals();
-    interfaceResolver = null;
     // Since finalization of covariance may have added forwarding stubs, we need
     // to recompute the class hierarchy so that method compilation will properly
     // target those forwarding stubs.
     hierarchy.onAmbiguousSupertypes = ignoreAmbiguousSupertypes;
-    hierarchy.applyMemberChanges(changedClasses, findDescendants: true);
     ticker.logMs("Performed top level inference");
   }
 
diff --git a/pkg/front_end/lib/src/fasta/type_inference/interface_resolver.dart b/pkg/front_end/lib/src/fasta/type_inference/interface_resolver.dart
deleted file mode 100644
index 5c8dbfa..0000000
--- a/pkg/front_end/lib/src/fasta/type_inference/interface_resolver.dart
+++ /dev/null
@@ -1,1235 +0,0 @@
-// 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.md file.
-
-import 'package:kernel/ast.dart'
-    show
-        Arguments,
-        Class,
-        DartType,
-        DynamicType,
-        Expression,
-        Field,
-        FunctionNode,
-        FunctionType,
-        InvalidType,
-        Member,
-        Name,
-        NamedExpression,
-        Procedure,
-        ProcedureKind,
-        ReturnStatement,
-        SuperMethodInvocation,
-        SuperPropertyGet,
-        SuperPropertySet,
-        TypeParameter,
-        TypeParameterType,
-        VariableDeclaration,
-        VariableGet,
-        VoidType;
-
-import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
-
-import 'package:kernel/transformations/flags.dart' show TransformerFlag;
-
-import 'package:kernel/type_algebra.dart' show Substitution;
-
-import 'package:kernel/src/hierarchy_based_type_environment.dart'
-    show HierarchyBasedTypeEnvironment;
-
-import '../../base/instrumentation.dart'
-    show Instrumentation, InstrumentationValueLiteral;
-
-import '../builder/builder.dart' show LibraryBuilder;
-
-import '../kernel/kernel_library_builder.dart' show KernelLibraryBuilder;
-
-import '../kernel/kernel_shadow_ast.dart'
-    show ShadowClass, ShadowField, ShadowProcedure, VariableDeclarationJudgment;
-
-import '../messages.dart'
-    show
-        noLength,
-        templateCantInferTypeDueToCircularity,
-        templateCantInferTypeDueToInconsistentOverrides;
-
-import '../names.dart' show indexSetName;
-
-import '../problems.dart' show unhandled;
-
-import 'type_inference_engine.dart'
-    show
-        FieldInitializerInferenceNode,
-        IncludesTypeParametersCovariantly,
-        InferenceNode,
-        TypeInferenceEngine;
-
-import 'type_inferrer.dart' show getNamedFormal;
-
-import 'type_schema_environment.dart'
-    show
-        getNamedParameterType,
-        getPositionalParameterType,
-        substituteTypeParams;
-
-/// Concrete class derived from [InferenceNode] to represent type inference of
-/// getters, setters, and fields based on inheritance.
-class AccessorInferenceNode extends InferenceNode {
-  final InterfaceResolver _interfaceResolver;
-
-  /// The method whose return type and/or parameter types should be inferred.
-  final Procedure _declaredMethod;
-
-  /// A list containing the methods overridden by [_declaredMethod], if any.
-  final List<Member> _candidates;
-
-  /// The index of the first method in [_candidates] overridden by
-  /// [_declaredMethod].
-  final int _start;
-
-  /// The past-the-end index of the last method in [_candidates] overridden by
-  /// [_declaredMethod].
-  final int _end;
-
-  final LibraryBuilder _library;
-
-  final Uri _fileUri;
-
-  AccessorInferenceNode(this._interfaceResolver, this._declaredMethod,
-      this._candidates, this._start, this._end, this._library, this._fileUri);
-
-  String get _name {
-    if (_declaredMethod is! SyntheticAccessor && _declaredMethod.isSetter) {
-      return _declaredMethod.function.positionalParameters[0].name;
-    }
-    return _declaredMethod.name.name;
-  }
-
-  int get _offset {
-    if (_declaredMethod is! SyntheticAccessor && _declaredMethod.isSetter) {
-      return _declaredMethod.function.positionalParameters[0].fileOffset;
-    }
-    return _declaredMethod.fileOffset;
-  }
-
-  @override
-  void resolveInternal() {
-    var declaredMethod = _declaredMethod;
-    var kind = declaredMethod.kind;
-    var overriddenTypes = _computeAccessorOverriddenTypes();
-    DartType inferredType;
-    if (isCircular) {
-      inferredType = const InvalidType();
-      _library.addProblem(
-          templateCantInferTypeDueToCircularity.withArguments(_name),
-          _offset,
-          noLength,
-          _fileUri);
-    } else {
-      inferredType = _interfaceResolver.matchTypes(
-          overriddenTypes, _library, _name, _fileUri, _offset);
-    }
-    if (declaredMethod is SyntheticAccessor) {
-      declaredMethod._field.type = inferredType;
-      declaredMethod._field.initializer = null;
-    } else {
-      if (kind == ProcedureKind.Getter) {
-        declaredMethod.function.returnType = inferredType;
-      } else {
-        declaredMethod.function.positionalParameters[0].type = inferredType;
-      }
-    }
-  }
-
-  /// Computes the types of the getters and setters overridden by
-  /// [_declaredMethod], with appropriate type parameter substitutions.
-  List<DartType> _computeAccessorOverriddenTypes() {
-    var overriddenTypes = <DartType>[];
-    for (int i = _start; i < _end; i++) {
-      var candidate = _candidates[i];
-      Procedure resolvedCandidate;
-      if (candidate is ForwardingNode) {
-        resolvedCandidate = candidate.resolve();
-      } else {
-        resolvedCandidate = candidate;
-      }
-      DartType overriddenType;
-      if (resolvedCandidate is SyntheticAccessor) {
-        var field = resolvedCandidate._field;
-        TypeInferenceEngine.resolveInferenceNode(field);
-        overriddenType = field.type;
-      } else if (resolvedCandidate.function != null) {
-        switch (resolvedCandidate.kind) {
-          case ProcedureKind.Getter:
-            overriddenType = resolvedCandidate.function.returnType;
-            break;
-          case ProcedureKind.Setter:
-            overriddenType =
-                resolvedCandidate.function.positionalParameters[0].type;
-            break;
-          default:
-            // Illegal override (error will be reported elsewhere).  Just skip
-            // this override.
-            continue;
-        }
-      } else {
-        // This can happen if there are errors.  Just skip this override.
-        continue;
-      }
-      overriddenTypes.add(_interfaceResolver
-          ._substitutionFor(resolvedCandidate, _declaredMethod.enclosingClass)
-          .substituteType(overriddenType));
-    }
-    return overriddenTypes;
-  }
-}
-
-/// A [ForwardingNode] represents a method, getter, or setter within a class's
-/// interface that is either implemented in the class directly or inherited from
-/// a superclass.
-///
-/// This class allows us to defer the determination of exactly which member is
-/// inherited, as well as the propagation of covariance annotations, and
-/// the creation of forwarding stubs, until type inference.
-class ForwardingNode extends Procedure {
-  /// The [InterfaceResolver] that created this [ForwardingNode].
-  final InterfaceResolver _interfaceResolver;
-
-  /// A list containing the directly implemented and directly inherited
-  /// procedures of the class in question.
-  ///
-  /// Note that many [ForwardingNode]s share the same [_candidates] list;
-  /// consult [_start] and [_end] to see which entries in this list are relevant
-  /// to this [ForwardingNode].
-  final List<Member> _candidates;
-
-  /// Index of the first entry in [_candidates] relevant to this
-  /// [ForwardingNode].
-  final int _start;
-
-  /// Index just beyond the last entry in [_candidates] relevant to this
-  /// [ForwardingNode].
-  final int _end;
-
-  /// The member this node resolves to (if it has been computed); otherwise
-  /// `null`.
-  Member _resolution;
-
-  /// The result of finalizing this node (if the node has been finalized);
-  /// otherwise `null`.
-  Member _finalResolution;
-
-  /// If this forwarding node represents a member that needs type inference, the
-  /// corresponding [InferenceNode]; otherwise `null`.
-  InferenceNode _inferenceNode;
-
-  ForwardingNode(this._interfaceResolver, this._inferenceNode, Class class_,
-      Name name, ProcedureKind kind, this._candidates, this._start, this._end)
-      : super(name, kind, null) {
-    parent = class_;
-  }
-
-  /// Finishes handling of this node by propagating covariance and creating
-  /// forwarding stubs if necessary.
-  Procedure finalize() => _finalResolution ??= _finalize();
-
-  /// Returns the declared or inherited member this node resolves to.
-  ///
-  /// Does not create forwarding stubs.
-  Procedure resolve() => _resolution ??= _resolve();
-
-  /// Tag the parameters of [interfaceMember] that need type checks
-  ///
-  /// Parameters can need type checks for calls coming from statically typed
-  /// call sites, due to covariant generics and overrides with explicit
-  /// `covariant` parameters.
-  ///
-  /// Tag parameters of [interfaceMember] that need such checks when the member
-  /// occurs in [enclosingClass]'s interface.  If parameters need checks but
-  /// they would not be checked in an inherited implementation, a forwarding
-  /// stub is introduced as a place to put the checks.
-  Procedure _computeCovarianceFixes(Procedure interfaceMember) {
-    var substitution =
-        _interfaceResolver._substitutionFor(interfaceMember, enclosingClass);
-    // We always create a forwarding stub when we've inherited a member from an
-    // interface other than the first override candidate.  This is to work
-    // around a bug in the Kernel type checker where it chooses the first
-    // override candidate.
-    //
-    // TODO(kmillikin): Fix the Kernel type checker and stop creating these
-    // extra stubs.
-    var stub = interfaceMember.enclosingClass == enclosingClass ||
-            interfaceMember == _resolvedCandidate(_start)
-        ? interfaceMember
-        : _createForwardingStub(substitution, interfaceMember);
-
-    var interfaceFunction = interfaceMember.function;
-    var interfacePositionalParameters = interfaceFunction.positionalParameters;
-    var interfaceNamedParameters = interfaceFunction.namedParameters;
-    var interfaceTypeParameters = interfaceFunction.typeParameters;
-
-    void createStubIfNeeded() {
-      if (stub != interfaceMember) return;
-      if (interfaceMember.enclosingClass == enclosingClass) return;
-      stub = _createForwardingStub(substitution, interfaceMember);
-    }
-
-    bool isImplCreated = false;
-    void createImplIfNeeded() {
-      if (isImplCreated) return;
-      createStubIfNeeded();
-      _createForwardingImplIfNeeded(stub.function);
-      isImplCreated = true;
-    }
-
-    IncludesTypeParametersCovariantly needsCheckVisitor =
-        enclosingClass.typeParameters.isEmpty
-            ? null
-            : ShadowClass.getClassInferenceInfo(enclosingClass)
-                    .needsCheckVisitor ??=
-                new IncludesTypeParametersCovariantly(
-                    enclosingClass.typeParameters);
-    bool needsCheck(DartType type) => needsCheckVisitor == null
-        ? false
-        : substitution.substituteType(type).accept(needsCheckVisitor);
-    for (int i = 0; i < interfacePositionalParameters.length; i++) {
-      var parameter = interfacePositionalParameters[i];
-      var isGenericCovariantImpl =
-          parameter.isGenericCovariantImpl || needsCheck(parameter.type);
-      var isCovariant = parameter.isCovariant;
-      var superParameter = parameter;
-      for (int j = _start; j < _end; j++) {
-        var otherMember = _finalizedCandidate(j);
-        if (otherMember is ForwardingNode) continue;
-        var otherPositionalParameters =
-            otherMember.function.positionalParameters;
-        if (otherPositionalParameters.length <= i) continue;
-        var otherParameter = otherPositionalParameters[i];
-        if (j == _start) superParameter = otherParameter;
-        if (identical(otherMember, interfaceMember)) continue;
-        if (otherParameter.isGenericCovariantImpl) {
-          isGenericCovariantImpl = true;
-        }
-        if (otherParameter.isCovariant) {
-          isCovariant = true;
-        }
-      }
-      if (isGenericCovariantImpl) {
-        if (!superParameter.isGenericCovariantImpl) {
-          createImplIfNeeded();
-        }
-        if (!parameter.isGenericCovariantImpl) {
-          createStubIfNeeded();
-          stub.function.positionalParameters[i].isGenericCovariantImpl = true;
-        }
-      }
-      if (isCovariant) {
-        if (!superParameter.isCovariant) {
-          createImplIfNeeded();
-        }
-        if (!parameter.isCovariant) {
-          createStubIfNeeded();
-          stub.function.positionalParameters[i].isCovariant = true;
-        }
-      }
-    }
-    for (int i = 0; i < interfaceNamedParameters.length; i++) {
-      var parameter = interfaceNamedParameters[i];
-      var isGenericCovariantImpl =
-          parameter.isGenericCovariantImpl || needsCheck(parameter.type);
-      var isCovariant = parameter.isCovariant;
-      var superParameter = parameter;
-      for (int j = _start; j < _end; j++) {
-        var otherMember = _finalizedCandidate(j);
-        if (otherMember is ForwardingNode) continue;
-        var otherParameter =
-            getNamedFormal(otherMember.function, parameter.name);
-        if (otherParameter == null) continue;
-        if (j == _start) superParameter = otherParameter;
-        if (identical(otherMember, interfaceMember)) continue;
-        if (otherParameter.isGenericCovariantImpl) {
-          isGenericCovariantImpl = true;
-        }
-        if (otherParameter.isCovariant) {
-          isCovariant = true;
-        }
-      }
-      if (isGenericCovariantImpl) {
-        if (!superParameter.isGenericCovariantImpl) {
-          createImplIfNeeded();
-        }
-        if (!parameter.isGenericCovariantImpl) {
-          createStubIfNeeded();
-          stub.function.namedParameters[i].isGenericCovariantImpl = true;
-        }
-      }
-      if (isCovariant) {
-        if (!superParameter.isCovariant) {
-          createImplIfNeeded();
-        }
-        if (!parameter.isCovariant) {
-          createStubIfNeeded();
-          stub.function.namedParameters[i].isCovariant = true;
-        }
-      }
-    }
-    for (int i = 0; i < interfaceTypeParameters.length; i++) {
-      var typeParameter = interfaceTypeParameters[i];
-      var isGenericCovariantImpl = typeParameter.isGenericCovariantImpl;
-      var superTypeParameter = typeParameter;
-      for (int j = _start; j < _end; j++) {
-        var otherMember = _finalizedCandidate(j);
-        if (otherMember is ForwardingNode) continue;
-        var otherTypeParameters = otherMember.function.typeParameters;
-        if (otherTypeParameters.length <= i) continue;
-        var otherTypeParameter = otherTypeParameters[i];
-        if (j == _start) superTypeParameter = otherTypeParameter;
-        if (identical(otherMember, interfaceMember)) continue;
-        if (otherTypeParameter.isGenericCovariantImpl) {
-          isGenericCovariantImpl = true;
-        }
-      }
-      if (isGenericCovariantImpl) {
-        if (!superTypeParameter.isGenericCovariantImpl) {
-          createImplIfNeeded();
-        }
-        if (!typeParameter.isGenericCovariantImpl) {
-          createStubIfNeeded();
-          stub.function.typeParameters[i].isGenericCovariantImpl = true;
-        }
-      }
-    }
-    return stub;
-  }
-
-  void _createForwardingImplIfNeeded(FunctionNode function) {
-    if (function.body != null) {
-      // There is already an implementation; nothing further needs to be done.
-      return;
-    }
-    // Find the concrete implementation in the superclass; this is what we need
-    // to forward to.  If we can't find one, then the method is fully abstract
-    // and we don't need to do anything.
-    var superclass = enclosingClass.superclass;
-    if (superclass == null) return;
-    Procedure procedure = function.parent;
-    var superTarget = _interfaceResolver._typeEnvironment.hierarchy
-        .getDispatchTarget(superclass, procedure.name,
-            setter: kind == ProcedureKind.Setter);
-    if (superTarget == null) return;
-    if (superTarget is Procedure && superTarget.isForwardingStub) {
-      superTarget = _getForwardingStubSuperTarget(superTarget);
-    }
-    procedure.isAbstract = false;
-    if (!procedure.isForwardingStub) {
-      // This procedure exists abstractly in the source code; we need to make it
-      // concrete and give it a body that is a forwarding stub.  This situation
-      // is called a "forwarding semi-stub".
-      procedure.isForwardingStub = true;
-      procedure.isForwardingSemiStub = true;
-      _interfaceResolver._instrumentation?.record(
-          procedure.fileUri,
-          procedure.fileOffset,
-          'forwardingStub',
-          new InstrumentationValueLiteral('semi-stub'));
-    }
-    var positionalArguments = function.positionalParameters
-        .map<Expression>((parameter) => new VariableGet(parameter))
-        .toList();
-    var namedArguments = function.namedParameters
-        .map((parameter) =>
-            new NamedExpression(parameter.name, new VariableGet(parameter)))
-        .toList();
-    var typeArguments = function.typeParameters
-        .map<DartType>((typeParameter) => new TypeParameterType(typeParameter))
-        .toList();
-    var arguments = new Arguments(positionalArguments,
-        types: typeArguments, named: namedArguments);
-    Expression superCall;
-    switch (kind) {
-      case ProcedureKind.Method:
-      case ProcedureKind.Operator:
-        superCall = new SuperMethodInvocation(name, arguments, superTarget);
-        break;
-      case ProcedureKind.Getter:
-        superCall = new SuperPropertyGet(
-            name,
-            superTarget is SyntheticAccessor
-                ? superTarget._field
-                : superTarget);
-        break;
-      case ProcedureKind.Setter:
-        superCall = new SuperPropertySet(
-            name,
-            positionalArguments[0],
-            superTarget is SyntheticAccessor
-                ? superTarget._field
-                : superTarget);
-        break;
-      default:
-        unhandled('$kind', '_createForwardingImplIfNeeded', -1, null);
-        break;
-    }
-    function.body = new ReturnStatement(superCall)..parent = function;
-    procedure.transformerFlags |= TransformerFlag.superCalls;
-    procedure.forwardingStubSuperTarget = superTarget;
-  }
-
-  /// Creates a forwarding stub based on the given [target].
-  Procedure _createForwardingStub(Substitution substitution, Procedure target) {
-    VariableDeclaration copyParameter(VariableDeclaration parameter) {
-      return new VariableDeclaration(parameter.name,
-          type: substitution.substituteType(parameter.type),
-          isCovariant: parameter.isCovariant)
-        ..isGenericCovariantImpl = parameter.isGenericCovariantImpl;
-    }
-
-    var targetTypeParameters = target.function.typeParameters;
-    List<TypeParameter> typeParameters;
-    if (targetTypeParameters.isNotEmpty) {
-      typeParameters =
-          new List<TypeParameter>.filled(targetTypeParameters.length, null);
-      var additionalSubstitution = <TypeParameter, DartType>{};
-      for (int i = 0; i < targetTypeParameters.length; i++) {
-        var targetTypeParameter = targetTypeParameters[i];
-        var typeParameter = new TypeParameter(targetTypeParameter.name, null)
-          ..isGenericCovariantImpl = targetTypeParameter.isGenericCovariantImpl;
-        typeParameters[i] = typeParameter;
-        additionalSubstitution[targetTypeParameter] =
-            new TypeParameterType(typeParameter);
-      }
-      substitution = Substitution.combine(
-          substitution, Substitution.fromMap(additionalSubstitution));
-      for (int i = 0; i < typeParameters.length; i++) {
-        typeParameters[i].bound =
-            substitution.substituteType(targetTypeParameters[i].bound);
-      }
-    }
-    var positionalParameters =
-        target.function.positionalParameters.map(copyParameter).toList();
-    var namedParameters =
-        target.function.namedParameters.map(copyParameter).toList();
-    var function = new FunctionNode(null,
-        positionalParameters: positionalParameters,
-        namedParameters: namedParameters,
-        typeParameters: typeParameters,
-        requiredParameterCount: target.function.requiredParameterCount,
-        returnType: substitution.substituteType(target.function.returnType));
-    Member finalTarget;
-    if (target is Procedure && target.isForwardingStub) {
-      finalTarget = target.forwardingStubInterfaceTarget;
-    } else if (target is SyntheticAccessor) {
-      finalTarget = target._field;
-    } else {
-      finalTarget = target;
-    }
-    return new Procedure(name, kind, function,
-        isAbstract: true,
-        isForwardingStub: true,
-        fileUri: enclosingClass.fileUri,
-        forwardingStubInterfaceTarget: finalTarget)
-      ..startFileOffset = enclosingClass.fileOffset
-      ..fileOffset = enclosingClass.fileOffset
-      ..parent = enclosingClass;
-  }
-
-  /// Creates a forwarding stub for this node if necessary, and propagates
-  /// covariance information.
-  Procedure _finalize() {
-    return _computeCovarianceFixes(resolve());
-  }
-
-  /// Returns the [i]th element of [_candidates], finalizing it if necessary.
-  Procedure _finalizedCandidate(int i) {
-    Procedure candidate = _candidates[i];
-    return candidate is ForwardingNode &&
-            _interfaceResolver.isTypeInferencePrepared
-        ? candidate.finalize()
-        : candidate;
-  }
-
-  /// Determines which inherited member this node resolves to, and also performs
-  /// type inference.
-  Procedure _resolve() {
-    Procedure inheritedMember = _candidates[_start];
-    bool isDeclaredInThisClass =
-        identical(inheritedMember.enclosingClass, enclosingClass);
-    if (isDeclaredInThisClass) {
-      if (_inferenceNode != null) {
-        _inferenceNode.resolve();
-        _inferenceNode = null;
-      }
-    } else {
-      // If there are multiple inheritance candidates, the inherited member is
-      // the member whose type is a subtype of all the others.  We can find it
-      // by two passes over the list of members.  For the first pass, we step
-      // through the candidates, updating inheritedMember each time we find a
-      // member whose type is a subtype of the previous inheritedMember.  As we
-      // do this, we also work out the necessary substitution for matching up
-      // type parameters between this class and the corresponding superclass.
-      //
-      // Since the subtyping relation is reflexive, we will favor the most
-      // recently visited candidate in the case where the types are the same.
-      // We want to favor earlier candidates, so we visit the candidate list
-      // backwards.
-      inheritedMember = _resolvedCandidate(_end - 1);
-      var inheritedMemberSubstitution =
-          _interfaceResolver._substitutionFor(inheritedMember, enclosingClass);
-      var inheritedMemberType = inheritedMember is ForwardingNode
-          ? const DynamicType()
-          : inheritedMemberSubstitution.substituteType(
-              kind == ProcedureKind.Setter
-                  ? inheritedMember.setterType
-                  : inheritedMember.getterType);
-      for (int i = _end - 2; i >= _start; i--) {
-        var candidate = _resolvedCandidate(i);
-        var substitution =
-            _interfaceResolver._substitutionFor(candidate, enclosingClass);
-        bool isBetter;
-        DartType type;
-        if (kind == ProcedureKind.Setter) {
-          type = candidate is ForwardingNode
-              ? const DynamicType()
-              : substitution.substituteType(candidate.setterType);
-          // Setters are contravariant in their setter type, so we have to
-          // reverse the check.
-          isBetter = _interfaceResolver._typeEnvironment
-              .isSubtypeOf(inheritedMemberType, type);
-        } else {
-          type = candidate is ForwardingNode
-              ? const DynamicType()
-              : substitution.substituteType(candidate.getterType);
-          isBetter = _interfaceResolver._typeEnvironment
-              .isSubtypeOf(type, inheritedMemberType);
-        }
-        if (isBetter) {
-          inheritedMember = candidate;
-          inheritedMemberSubstitution = substitution;
-          inheritedMemberType = type;
-        }
-      }
-      // For the second pass, we verify that inheritedMember is a subtype of all
-      // the other potentially inherited members.
-      // TODO(paulberry): implement this.
-    }
-    return inheritedMember;
-  }
-
-  /// Returns the [i]th element of [_candidates], resolving it if necessary.
-  Procedure _resolvedCandidate(int i) {
-    Procedure candidate = _candidates[i];
-    return candidate is ForwardingNode &&
-            _interfaceResolver.isTypeInferencePrepared
-        ? candidate.resolve()
-        : candidate;
-  }
-
-  static void createForwardingImplIfNeededForTesting(
-      ForwardingNode node, FunctionNode function) {
-    node._createForwardingImplIfNeeded(function);
-  }
-
-  /// Public method allowing tests to access [_createForwardingStub].
-  ///
-  /// This method is static so that it can be easily eliminated by tree shaking
-  /// when not needed.
-  static Procedure createForwardingStubForTesting(
-      ForwardingNode node, Substitution substitution, Procedure target) {
-    return node._createForwardingStub(substitution, target);
-  }
-
-  /// For testing: get the list of candidates relevant to a given node.
-  static List<Procedure> getCandidates(ForwardingNode node) {
-    return node._candidates.sublist(node._start, node._end);
-  }
-
-  static Member _getForwardingStubSuperTarget(Procedure forwardingStub) {
-    // TODO(paulberry): when dartbug.com/31562 is fixed, this should become
-    // easier.
-    ReturnStatement body = forwardingStub.function.body;
-    var expression = body.expression;
-    if (expression is SuperMethodInvocation) {
-      return expression.interfaceTarget;
-    } else if (expression is SuperPropertySet) {
-      return expression.interfaceTarget;
-    } else {
-      return unhandled('${expression.runtimeType}',
-          '_getForwardingStubSuperTarget', -1, null);
-    }
-  }
-}
-
-/// An [InterfaceResolver] keeps track of the information necessary to resolve
-/// method calls, gets, and sets within a chunk of code being compiled, to
-/// infer covariance annotations, and to create forwarwding stubs when necessary
-/// to meet covariance requirements.
-class InterfaceResolver {
-  final TypeInferenceEngine _typeInferenceEngine;
-
-  final HierarchyBasedTypeEnvironment _typeEnvironment;
-
-  final Instrumentation _instrumentation;
-
-  InterfaceResolver(
-      this._typeInferenceEngine, this._typeEnvironment, this._instrumentation);
-
-  /// Indicates whether the "prepare" phase of type inference is complete.
-  bool get isTypeInferencePrepared =>
-      _typeInferenceEngine.isTypeInferencePrepared;
-
-  /// Report an error if all types in [types] are not equal using `==`.
-  ///
-  /// Returns the type if there is at least one and they are all equal,
-  /// otherwise the type `dynamic`.  [library], [name], [fileUri], and
-  /// [charOffset] are used to report the error.
-  DartType matchTypes(Iterable<DartType> types, LibraryBuilder library,
-      String name, Uri fileUri, int charOffset) {
-    DartType first;
-    for (var type in types) {
-      if (first == null) {
-        first = type;
-      } else if (first != type) {
-        // Types don't match.  Report an error.
-        library.addProblem(
-            templateCantInferTypeDueToInconsistentOverrides.withArguments(name),
-            charOffset,
-            noLength,
-            fileUri);
-        return const DynamicType();
-      }
-    }
-    // If there are no overridden types, infer `dynamic`.
-    return first ?? const DynamicType();
-  }
-
-  /// Computes the types of the methods overridden by [method] in [class_].
-  ///
-  /// The types have the type parameters of [class_] substituted appropriately.
-  ///
-  /// [candidates] has the list of inherited interface methods with the same
-  /// name as [method] as a sublist from [start] inclusive to [end] exclusive.
-  List<FunctionType> _computeMethodOverriddenTypes(Class class_,
-      Procedure method, List<Member> candidates, int start, int end) {
-    var overriddenTypes = <FunctionType>[];
-    var declaredTypeParameters = method.function.typeParameters;
-    for (int i = start; i < end; ++i) {
-      var candidate = candidates[i];
-      if (candidate is SyntheticAccessor) {
-        // This can happen if there are errors.  Just skip this override.
-        continue;
-      }
-      var candidateFunction = candidate.function;
-      if (candidateFunction == null) {
-        // This can happen if there are errors.  Just skip this override.
-        continue;
-      }
-      var substitution = _substitutionFor(candidate, class_);
-      FunctionType overriddenType =
-          substitution.substituteType(candidateFunction.functionType);
-      var overriddenTypeParameters = overriddenType.typeParameters;
-      if (overriddenTypeParameters.length != declaredTypeParameters.length) {
-        // Generic arity mismatch.  Don't do any inference for this method.
-        // TODO(paulberry): report an error.
-        overriddenTypes.clear();
-        break;
-      } else if (overriddenTypeParameters.isNotEmpty) {
-        var substitutionMap = <TypeParameter, DartType>{};
-        for (int i = 0; i < declaredTypeParameters.length; ++i) {
-          substitutionMap[overriddenTypeParameters[i]] =
-              new TypeParameterType(declaredTypeParameters[i]);
-        }
-        overriddenType = substituteTypeParams(
-            overriddenType, substitutionMap, declaredTypeParameters);
-      }
-      overriddenTypes.add(overriddenType);
-    }
-    return overriddenTypes;
-  }
-
-  void inferMethodType(LibraryBuilder library, Class class_, Procedure method,
-      List<Member> candidates, int start, int end) {
-    var overriddenTypes =
-        _computeMethodOverriddenTypes(class_, method, candidates, start, end);
-    if (ShadowProcedure.hasImplicitReturnType(method) &&
-        method.name != indexSetName) {
-      method.function.returnType = matchTypes(
-          overriddenTypes.map((type) => type.returnType),
-          library,
-          method.name.name,
-          class_.fileUri,
-          method.fileOffset);
-    }
-    var positionalParameters = method.function.positionalParameters;
-    for (int i = 0; i < positionalParameters.length; ++i) {
-      if (VariableDeclarationJudgment.isImplicitlyTyped(
-          positionalParameters[i])) {
-        // Note that if the parameter is not present in the overridden method,
-        // getPositionalParameterType treats it as dynamic.  This is consistent
-        // with the behavior called for in the informal top level type inference
-        // spec, which says:
-        //
-        //     If there is no corresponding parameter position in the overridden
-        //     method to infer from and the signatures are compatible, it is
-        //     treated as dynamic (e.g. overriding a one parameter method with a
-        //     method that takes a second optional parameter).  Note: if there
-        //     is no corresponding parameter position in the overridden method to
-        //     infer from and the signatures are incompatible (e.g. overriding a
-        //     one parameter method with a method that takes a second
-        //     non-optional parameter), the inference result is not defined and
-        //     tools are free to either emit an error, or to defer the error to
-        //     override checking.
-        positionalParameters[i].type = matchTypes(
-            overriddenTypes.map((type) => getPositionalParameterType(type, i)),
-            library,
-            positionalParameters[i].name,
-            class_.fileUri,
-            positionalParameters[i].fileOffset);
-      }
-    }
-    var namedParameters = method.function.namedParameters;
-    for (int i = 0; i < namedParameters.length; i++) {
-      if (VariableDeclarationJudgment.isImplicitlyTyped(namedParameters[i])) {
-        var name = namedParameters[i].name;
-        namedParameters[i].type = matchTypes(
-            overriddenTypes.map((type) => getNamedParameterType(type, name)),
-            library,
-            namedParameters[i].name,
-            class_.fileUri,
-            namedParameters[i].fileOffset);
-      }
-    }
-  }
-
-  /// Populates [getters] and [setters] with the members of the given [class_]'s
-  /// interface.
-  ///
-  /// [getters] will contain methods and getters, [setters] will contain
-  /// setters.  Some members cannot be resolved immediately.  For instance,
-  /// top-level type inference has not yet inferred field types based on
-  /// initializers and so we cannot yet do override based resolution of getters
-  /// and setters.  Members of the class's interface that need to be resolved
-  /// later are represented by a [ForwardingNode] object.
-  void createApiMembers(Class class_, List<Member> getters,
-      List<Member> setters, LibraryBuilder library) {
-    var candidates = ClassHierarchy.mergeSortedLists(
-        getCandidates(class_, false), getCandidates(class_, true));
-    // Now create getter and perhaps setter forwarding nodes for each unique
-    // name.
-    getters.length = candidates.length;
-    setters.length = candidates.length;
-    int getterIndex = 0;
-    int setterIndex = 0;
-    // To detect conflicts between instance members (possibly inherited ones)
-    // and static members, use a map from names to lists of members.  There can
-    // be more than one static member with a given name, e.g., if there is a
-    // getter and a setter.  We will report both conflicts.
-    forEachApiMember(candidates, (int start, int end, Name name) {
-      Procedure member = candidates[start];
-      ProcedureKind kind = _kindOf(member);
-      if (kind != ProcedureKind.Getter && kind != ProcedureKind.Setter) {
-        for (int i = start + 1; i < end; ++i) {
-          if (_kindOf(candidates[i]) != kind) return;
-        }
-        if (member.enclosingClass == class_ && _requiresTypeInference(member)) {
-          inferMethodType(library, class_, member, candidates, start + 1, end);
-        }
-        var forwardingNode = new ForwardingNode(
-            this, null, class_, name, kind, candidates, start, end);
-        getters[getterIndex++] = forwardingNode.finalize();
-        if (library is KernelLibraryBuilder &&
-            forwardingNode.finalize() != forwardingNode.resolve()) {
-          library.forwardersOrigins.add(forwardingNode.finalize());
-          library.forwardersOrigins.add(forwardingNode.resolve());
-        }
-        return;
-      }
-
-      Procedure declaredGetter;
-      int inheritedGetterStart = start;
-      int getterEnd = start;
-      if (kind == ProcedureKind.Getter) {
-        if (member.enclosingClass == class_) {
-          declaredGetter = member;
-          ++inheritedGetterStart;
-        }
-        while (++getterEnd < end) {
-          ProcedureKind currentKind = _kindOf(candidates[getterEnd]);
-          if (currentKind == ProcedureKind.Setter) break;
-          if (currentKind != ProcedureKind.Getter) return;
-        }
-      }
-
-      Procedure declaredSetter;
-      int inheritedSetterStart = getterEnd;
-      if (getterEnd < end) {
-        member = candidates[getterEnd];
-        if (member.enclosingClass == class_) {
-          declaredSetter = member;
-          ++inheritedSetterStart;
-        }
-      }
-
-      InferenceNode getterInferenceNode;
-      if (start < getterEnd) {
-        if (declaredGetter != null) {
-          getterInferenceNode = _createInferenceNode(
-              class_,
-              declaredGetter,
-              candidates,
-              inheritedGetterStart,
-              getterEnd,
-              inheritedSetterStart,
-              end,
-              library,
-              class_.fileUri);
-        }
-        // Getters need to be resolved later, as part of type inference, so just
-        // save the forwarding node for now.
-        //
-        // Choose a representative to use for error reporting, such as if a
-        // class inherits this getter and tries to declare a method with the
-        // same name.
-        Member representative = candidates[start];
-        getters[getterIndex++] = new ForwardingNode(this, getterInferenceNode,
-            class_, name, ProcedureKind.Getter, candidates, start, getterEnd)
-          ..fileUri = representative.fileUri
-          ..fileOffset = representative.fileOffset
-          ..fileEndOffset = representative.fileEndOffset;
-      }
-      if (getterEnd < end) {
-        InferenceNode setterInferenceNode;
-        if (declaredSetter != null) {
-          setterInferenceNode = declaredSetter is SyntheticAccessor
-              ? getterInferenceNode
-              : _createInferenceNode(
-                  class_,
-                  declaredSetter,
-                  candidates,
-                  inheritedSetterStart,
-                  end,
-                  inheritedGetterStart,
-                  getterEnd,
-                  library,
-                  class_.fileUri);
-        }
-        Member representative = candidates[getterEnd];
-        var forwardingNode = new ForwardingNode(this, setterInferenceNode,
-            class_, name, ProcedureKind.Setter, candidates, getterEnd, end)
-          ..fileUri = representative.fileUri
-          ..fileOffset = representative.fileOffset
-          ..fileEndOffset = representative.fileEndOffset;
-        // Setters need to be resolved later, as part of type inference, so just
-        // save the forwarding node for now.
-        setters[setterIndex++] = forwardingNode;
-      }
-    });
-    getters.length = getterIndex;
-    setters.length = setterIndex;
-  }
-
-  void finalizeCovariance(
-      Class class_, List<Member> apiMembers, LibraryBuilder library) {
-    for (int i = 0; i < apiMembers.length; i++) {
-      var member = apiMembers[i];
-      Member resolution;
-      if (member is ForwardingNode) {
-        apiMembers[i] = resolution = member.finalize();
-        if (library is KernelLibraryBuilder &&
-            member.finalize() != member.resolve()) {
-          library.forwardersOrigins.add(member.finalize());
-          library.forwardersOrigins.add(member.resolve());
-        }
-      } else {
-        resolution = member;
-      }
-      if (resolution is Procedure &&
-          resolution.isSyntheticForwarder &&
-          identical(resolution.enclosingClass, class_)) {
-        class_.addMember(resolution);
-      }
-    }
-  }
-
-  /// Gets a list of members implemented or potentially inherited by [class_],
-  /// sorted so that members with the same name are contiguous.
-  ///
-  /// If [setters] is `true`, setters are reported; otherwise getters, methods,
-  /// and operators are reported.
-  List<Procedure> getCandidates(Class class_, bool setters) {
-    // First create a list of candidates for inheritance based on the members
-    // declared directly in the class.
-    List<Procedure> candidates = _typeEnvironment.hierarchy
-        .getDeclaredMembers(class_, setters: setters)
-        .map((member) => makeCandidate(member, setters))
-        .toList();
-    // Merge in candidates from superclasses.
-    if (class_.superclass != null) {
-      candidates = _mergeCandidates(candidates, class_.superclass, setters);
-    }
-    for (var supertype in class_.implementedTypes) {
-      candidates = _mergeCandidates(candidates, supertype.classNode, setters);
-    }
-    return candidates;
-  }
-
-  /// Creates the appropriate [InferenceNode] for inferring [procedure] in the
-  /// context of [class_].
-  ///
-  /// [candidates] a list containing the procedures overridden by [procedure],
-  /// if any.  [start] is the index of the first such procedure, and [end] is
-  /// the past-the-end index of the last such procedure.
-  ///
-  /// For getters and setters, [crossStart] and [crossEnd] are the start and end
-  /// indices of the corresponding overridden setters/getters, respectively.
-  InferenceNode _createInferenceNode(
-      Class class_,
-      Procedure procedure,
-      List<Member> candidates,
-      int start,
-      int end,
-      int crossStart,
-      int crossEnd,
-      LibraryBuilder library,
-      Uri fileUri) {
-    InferenceNode node;
-    if (procedure.isAccessor && _requiresTypeInference(procedure)) {
-      if (start < end) {
-        node = new AccessorInferenceNode(
-            this, procedure, candidates, start, end, library, fileUri);
-      } else if (crossStart < crossEnd) {
-        node = new AccessorInferenceNode(this, procedure, candidates,
-            crossStart, crossEnd, library, fileUri);
-      } else if (procedure is SyntheticAccessor &&
-          procedure._field.initializer != null) {
-        node = new FieldInitializerInferenceNode(
-            _typeInferenceEngine, procedure._field, library);
-      }
-
-      if (node != null && procedure is SyntheticAccessor) {
-        ShadowField.setInferenceNode(procedure._field, node);
-      }
-    }
-    return node;
-  }
-
-  /// Retrieves a list of the interface members of the given [class_].
-  ///
-  /// If [setters] is true, setters are retrieved; otherwise getters and methods
-  /// are retrieved.
-  List<Member> _getInterfaceMembers(Class class_, bool setters) {
-    // If class_ is being compiled from source, retrieve its forwarding nodes.
-    var inferenceInfo = ShadowClass.getClassInferenceInfo(class_);
-    if (inferenceInfo != null) {
-      return setters ? inferenceInfo.setters : inferenceInfo.gettersAndMethods;
-    } else {
-      return _typeEnvironment.hierarchy
-          .getInterfaceMembers(class_, setters: setters);
-    }
-  }
-
-  /// Merges together the list of interface inheritance candidates in
-  /// [candidates] with interface inheritance candidates from superclass
-  /// [class_].
-  ///
-  /// Any candidates from [class_] are converted into interface inheritance
-  /// candidates using [_makeCandidate].
-  List<Procedure> _mergeCandidates(
-      List<Procedure> candidates, Class class_, bool setters) {
-    List<Member> members = _getInterfaceMembers(class_, setters);
-    if (candidates.isEmpty) {
-      return members.map((member) => makeCandidate(member, setters)).toList();
-    }
-    if (members.isEmpty) return candidates;
-    List<Procedure> result = <Procedure>[]..length =
-        candidates.length + members.length;
-    int storeIndex = 0;
-    int i = 0, j = 0;
-    while (i < candidates.length && j < members.length) {
-      Procedure candidate = candidates[i];
-      Member member = members[j];
-      int compare = ClassHierarchy.compareMembers(candidate, member);
-      if (compare <= 0) {
-        result[storeIndex++] = candidate;
-        ++i;
-        // If the same member occurs in both lists, skip the duplicate.
-        if (identical(candidate, member)) ++j;
-      } else {
-        result[storeIndex++] = makeCandidate(member, setters);
-        ++j;
-      }
-    }
-    while (i < candidates.length) {
-      result[storeIndex++] = candidates[i++];
-    }
-    while (j < members.length) {
-      result[storeIndex++] = makeCandidate(members[j++], setters);
-    }
-    result.length = storeIndex;
-    return result;
-  }
-
-  /// Determines the appropriate substitution to translate type parameters
-  /// mentioned in the given [candidate] to type parameters on [class_].
-  Substitution _substitutionFor(Procedure candidate, Class class_) {
-    return Substitution.fromInterfaceType(_typeEnvironment.getTypeAsInstanceOf(
-        class_.thisType, candidate.enclosingClass));
-  }
-
-  /// Executes [callback] once for each uniquely named member of [candidates].
-  ///
-  /// The [start] and [end] values passed to [callback] are the start and
-  /// past-the-end indices into [candidates] of a group of members having the
-  /// same name.  The [name] value passed to [callback] is the common name.
-  static void forEachApiMember(
-      List<Member> candidates, void callback(int start, int end, Name name)) {
-    int i = 0;
-    while (i < candidates.length) {
-      var name = candidates[i].name;
-      int j = i + 1;
-      while (j < candidates.length && candidates[j].name == name) {
-        j++;
-      }
-      callback(i, j, name);
-      i = j;
-    }
-  }
-
-  /// Transforms [member] into a candidate for interface inheritance.
-  ///
-  /// Fields are transformed into getters and setters; methods are passed
-  /// through unchanged.
-  static Procedure makeCandidate(Member member, bool setter) {
-    if (member is Procedure) return member;
-    if (member is Field) {
-      // TODO(paulberry): don't set the type or covariance annotations here,
-      // since they might not have been inferred yet.  Instead, ensure that this
-      // information is propagated to the getter/setter during type inference.
-      var type = member.type;
-      var isGenericCovariantImpl = member.isGenericCovariantImpl;
-      var isCovariant = member.isCovariant;
-      if (setter) {
-        var valueParam = new VariableDeclaration('_', type: type)
-          ..isGenericCovariantImpl = isGenericCovariantImpl
-          ..isCovariant = isCovariant;
-        var function = new FunctionNode(null,
-            positionalParameters: [valueParam], returnType: const VoidType());
-        return new SyntheticAccessor(
-            member.name, ProcedureKind.Setter, function, member)
-          ..parent = member.enclosingClass;
-      } else {
-        var function = new FunctionNode(null, returnType: type);
-        return new SyntheticAccessor(
-            member.name, ProcedureKind.Getter, function, member)
-          ..parent = member.enclosingClass;
-      }
-    }
-    return unhandled('${member.runtimeType}', 'makeCandidate', -1, null);
-  }
-
-  static ProcedureKind _kindOf(Procedure procedure) => procedure.kind;
-
-  /// Determines whether the given [procedure] will require type inference.
-  static bool _requiresTypeInference(Procedure procedure) {
-    if (procedure is SyntheticAccessor) {
-      return ShadowField.isImplicitlyTyped(procedure._field);
-    }
-    if (procedure.kind != ProcedureKind.Setter &&
-        ShadowProcedure.hasImplicitReturnType(procedure)) {
-      // Inference of the return type of `[]=` is handled separately by
-      // KernelProcedureBuilder.build, since there are no dependencies.
-      if (procedure.kind != ProcedureKind.Operator ||
-          procedure.name.name != '[]=') {
-        return true;
-      }
-    }
-    var function = procedure.function;
-    for (var parameter in function.positionalParameters) {
-      if (VariableDeclarationJudgment.isImplicitlyTyped(parameter)) return true;
-    }
-    for (var parameter in function.namedParameters) {
-      if (VariableDeclarationJudgment.isImplicitlyTyped(parameter)) return true;
-    }
-    return false;
-  }
-}
-
-/// A [SyntheticAccessor] represents the getter or setter implied by a field.
-class SyntheticAccessor extends Procedure {
-  /// The field associated with the synthetic accessor.
-  final Field _field;
-
-  SyntheticAccessor(
-      Name name, ProcedureKind kind, FunctionNode function, this._field)
-      : super(
-            name,
-            kind,
-            kind == ProcedureKind.Setter
-                ? new SyntheticAccessorFunctionNode.setter(_field)
-                : new SyntheticAccessorFunctionNode.getter(_field),
-            fileUri: _field.fileUri) {
-    fileOffset = _field.fileOffset;
-  }
-
-  @override
-  DartType get getterType => _field.type;
-
-  static getField(SyntheticAccessor accessor) => accessor._field;
-}
-
-/// A [SyntheticAccessorFunctionNode] represents the [FunctionNode] part of the
-/// getter or setter implied by a field.
-///
-/// For getters, [returnType] maps to the underlying field's type, so that if
-/// type inference fills in the type of the field, the change will automatically
-/// be reflected in the synthetic getter.
-class SyntheticAccessorFunctionNode extends FunctionNode {
-  final Field _field;
-
-  SyntheticAccessorFunctionNode.getter(this._field)
-      : super(new ReturnStatement());
-
-  SyntheticAccessorFunctionNode.setter(this._field)
-      : super(new ReturnStatement(),
-            positionalParameters: [new SyntheticSetterParameter(_field)]);
-
-  @override
-  DartType get returnType =>
-      positionalParameters.isEmpty ? _field.type : const VoidType();
-}
-
-/// A [SyntheticSetterParameter] represents the "value" parameter of the setter
-/// implied by a field.
-///
-/// The getters [isCovariant], [isGenericCovariantImpl],
-/// [isGenericCovariantInterface], and [type] map to the underlying field's
-/// properties, so that if these properties are modified on the field, the
-/// change will automatically be reflected in the synthetic setter.  Similarly,
-/// the setters [isCovariant], [isGenericCovariantImpl], and
-/// [isGenericCovariantInterface] update the corresponding properties on the
-/// field, so that covariance propagation logic can act uniformly on [Procedure]
-/// objects without having to have special case handling for fields.
-class SyntheticSetterParameter extends VariableDeclaration {
-  final Field _field;
-
-  SyntheticSetterParameter(this._field)
-      : super('_', isCovariant: _field.isCovariant);
-
-  @override
-  bool get isCovariant => _field.isCovariant;
-
-  @override
-  void set isCovariant(bool value) {
-    _field.isCovariant = value;
-  }
-
-  @override
-  bool get isGenericCovariantImpl => _field.isGenericCovariantImpl;
-
-  @override
-  void set isGenericCovariantImpl(bool value) {
-    _field.isGenericCovariantImpl = value;
-  }
-
-  @override
-  DartType get type => _field.type;
-}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
index bbf090a..b28fc43 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
@@ -11,7 +11,6 @@
         Field,
         FunctionType,
         InterfaceType,
-        InvalidType,
         Member,
         TypeParameter,
         TypeParameterType,
@@ -25,63 +24,16 @@
 import '../../base/instrumentation.dart' show Instrumentation;
 
 import '../kernel/kernel_builder.dart'
-    show LibraryBuilder, KernelLibraryBuilder;
+    show
+        ClassHierarchyBuilder,
+        ImplicitFieldType,
+        LibraryBuilder,
+        KernelLibraryBuilder;
 
-import '../kernel/kernel_shadow_ast.dart' show ShadowField, ShadowMember;
-
-import '../messages.dart' show noLength, templateCantInferTypeDueToCircularity;
-
-import 'type_inferrer.dart' show TypeInferrer, TypeInferrerImpl;
+import 'type_inferrer.dart' show TypeInferrer;
 
 import 'type_schema_environment.dart' show TypeSchemaEnvironment;
 
-/// Concrete class derived from [InferenceNode] to represent type inference of a
-/// field based on its initializer.
-class FieldInitializerInferenceNode extends InferenceNode {
-  final TypeInferenceEngine _typeInferenceEngine;
-
-  /// The field whose type should be inferred.
-  final ShadowField field;
-
-  final LibraryBuilder _library;
-
-  FieldInitializerInferenceNode(
-      this._typeInferenceEngine, this.field, this._library);
-
-  @override
-  void resolveInternal() {
-    var typeInferrer = _typeInferenceEngine.getFieldTypeInferrer(field);
-    // Note: in the event that there is erroneous code, it's possible for
-    // typeInferrer to be null.  If this happens, just skip type inference for
-    // this field.
-    if (typeInferrer != null) {
-      var inferredType = typeInferrer
-          .inferDeclarationType(typeInferrer.inferFieldTopLevel(field));
-      if (isCircular) {
-        // Report the appropriate error.
-        _library.addProblem(
-            templateCantInferTypeDueToCircularity
-                .withArguments(field.name.name),
-            field.fileOffset,
-            noLength,
-            field.fileUri);
-        inferredType = const InvalidType();
-      }
-      field.setInferredType(
-          _typeInferenceEngine, typeInferrer.uri, inferredType);
-      // TODO(paulberry): if type != null, then check that the type of the
-      // initializer is assignable to it.
-    }
-    // TODO(paulberry): the following is a hack so that outlines don't contain
-    // initializers.  But it means that we rebuild the initializers when doing
-    // a full compile.  There should be a better way.
-    field.initializer = null;
-  }
-
-  @override
-  String toString() => field.toString();
-}
-
 /// Visitor to check whether a given type mentions any of a class's type
 /// parameters in a covariant fashion.
 class IncludesTypeParametersCovariantly extends DartTypeVisitor<bool> {
@@ -131,67 +83,6 @@
   }
 }
 
-/// Base class for tracking dependencies during top level type inference.
-///
-/// Fields, accessors, and methods can have their types inferred in a variety of
-/// ways; there will a derived class for each kind of inference.
-abstract class InferenceNode {
-  /// The node currently being evaluated, or `null` if no node is being
-  /// evaluated.
-  static InferenceNode _currentNode;
-
-  /// Indicates whether the type inference corresponding to this node has been
-  /// completed.
-  bool _isResolved = false;
-
-  /// Indicates whether this node participates in a circularity.
-  bool _isCircular = false;
-
-  /// If this node is currently being evaluated, and its evaluation caused a
-  /// recursive call to another node's [resolve] method, a pointer to the latter
-  /// node; otherwise `null`.
-  InferenceNode _nextNode;
-
-  /// Indicates whether this node participates in a circularity.
-  ///
-  /// This may be called at the end of [resolveInternal] to check whether a
-  /// circularity was detected during evaluation.
-  bool get isCircular => _isCircular;
-
-  /// Evaluates this node, properly accounting for circularities.
-  void resolve() {
-    if (_isResolved) return;
-    if (_nextNode != null || identical(_currentNode, this)) {
-      // An accessor depends on itself (possibly by way of intermediate
-      // accessors).  Mark all accessors involved as circular.
-      var node = this;
-      do {
-        node._isCircular = true;
-        node._isResolved = true;
-        node = node._nextNode;
-      } while (node != null);
-    } else {
-      var previousNode = _currentNode;
-      assert(previousNode?._nextNode == null);
-      _currentNode = this;
-      previousNode?._nextNode = this;
-      resolveInternal();
-      assert(identical(_currentNode, this));
-      previousNode?._nextNode = null;
-      _currentNode = previousNode;
-      _isResolved = true;
-    }
-  }
-
-  /// Evaluates this node, possibly by making recursive calls to the [resolve]
-  /// method of this node or other nodes.
-  ///
-  /// Circularity detection is handled by [resolve], which calls this method.
-  /// Once this method has made all recursive calls to [resolve], it may use
-  /// [isCircular] to detect whether a circularity has occurred.
-  void resolveInternal();
-}
-
 /// Keeps track of the global state for the type inference that occurs outside
 /// of method bodies and initializers.
 ///
@@ -201,6 +92,8 @@
 abstract class TypeInferenceEngine {
   ClassHierarchy classHierarchy;
 
+  ClassHierarchyBuilder hierarchyBuilder;
+
   CoreTypes coreTypes;
 
   /// Indicates whether the "prepare" phase of type inference is complete.
@@ -208,8 +101,6 @@
 
   TypeSchemaEnvironment typeSchemaEnvironment;
 
-  final staticInferenceNodes = <FieldInitializerInferenceNode>[];
-
   /// A map containing constructors with initializing formals whose types
   /// need to be inferred.
   ///
@@ -237,21 +128,7 @@
   /// Creates a [TypeInferrer] object which is ready to perform type inference
   /// on the given [field].
   TypeInferrer createTopLevelTypeInferrer(
-      InterfaceType thisType, ShadowField field, KernelLibraryBuilder library);
-
-  /// Retrieve the [TypeInferrer] for the given [field], which was created by
-  /// a previous call to [createTopLevelTypeInferrer].
-  TypeInferrerImpl getFieldTypeInferrer(ShadowField field);
-
-  /// Performs the second phase of top level initializer inference, which is to
-  /// visit all accessors and top level variables that were passed to
-  /// [recordAccessor] in topologically-sorted order and assign their types.
-  void finishTopLevelFields() {
-    for (var node in staticInferenceNodes) {
-      node.resolve();
-    }
-    staticInferenceNodes.clear();
-  }
+      Uri uri, InterfaceType thisType, KernelLibraryBuilder library);
 
   /// Performs the third phase of top level inference, which is to visit all
   /// constructors still needing inference and infer the types of their
@@ -295,20 +172,17 @@
         new TypeSchemaEnvironment(coreTypes, hierarchy);
   }
 
-  /// Records that the given static [field] will need top level type inference.
-  void recordStaticFieldInferenceCandidate(
-      ShadowField field, LibraryBuilder library) {
-    var node = new FieldInitializerInferenceNode(this, field, library);
-    ShadowField.setInferenceNode(field, node);
-    staticInferenceNodes.add(node);
-  }
-
-  static void resolveInferenceNode(Member member) {
-    if (member is ShadowMember) {
-      if (member.inferenceNode != null) {
-        member.inferenceNode.resolve();
-        member.inferenceNode = null;
+  static Member resolveInferenceNode(Member member) {
+    if (member is Field) {
+      DartType type = member.type;
+      if (type is ImplicitFieldType) {
+        if (type.member.target != member) {
+          type.member.inferCopiedType(member);
+        } else {
+          type.member.inferType();
+        }
       }
     }
+    return member;
   }
 }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index bbe6899..5c01672 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -103,8 +103,6 @@
 import '../kernel/kernel_shadow_ast.dart'
     show
         ExpressionJudgment,
-        ShadowClass,
-        ShadowField,
         ShadowTypeInferenceEngine,
         ShadowTypeInferrer,
         VariableDeclarationJudgment,
@@ -119,8 +117,6 @@
 
 import 'inference_helper.dart' show InferenceHelper;
 
-import 'interface_resolver.dart' show ForwardingNode, SyntheticAccessor;
-
 import 'type_constraint_gatherer.dart' show TypeConstraintGatherer;
 
 import 'type_inference_engine.dart'
@@ -750,7 +746,8 @@
     Class classNode = receiverType is InterfaceType
         ? receiverType.classNode
         : coreTypes.objectClass;
-    Member interfaceMember = _getInterfaceMember(classNode, name, setter);
+    Member interfaceMember =
+        _getInterfaceMember(classNode, name, setter, fileOffset);
     if (instrumented &&
         receiverType != const DynamicType() &&
         interfaceMember != null) {
@@ -911,7 +908,8 @@
     if (calleeType is FunctionType) {
       return calleeType;
     } else if (followCall && calleeType is InterfaceType) {
-      var member = _getInterfaceMember(calleeType.classNode, callName, false);
+      var member =
+          _getInterfaceMember(calleeType.classNode, callName, false, -1);
       var callType = getCalleeType(member, calleeType);
       if (callType is FunctionType) {
         return callType;
@@ -969,7 +967,7 @@
 
   /// Gets the initializer for the given [field], or `null` if there is no
   /// initializer.
-  Expression getFieldInitializer(ShadowField field);
+  Expression getFieldInitializer(Field field);
 
   /// If the [member] is a forwarding stub, return the target it forwards to.
   /// Otherwise return the given [member].
@@ -1160,12 +1158,6 @@
     this.helper = null;
   }
 
-  /// Performs type inference on the given [field]'s initializer expression.
-  ///
-  /// Derived classes should provide an implementation that calls
-  /// [inferExpression] for the given [field]'s initializer expression.
-  DartType inferFieldTopLevel(ShadowField field);
-
   @override
   void inferFunctionBody(InferenceHelper helper, DartType returnType,
       AsyncMarker asyncMarker, Statement body) {
@@ -1830,25 +1822,16 @@
     }
   }
 
-  Member _getInterfaceMember(Class class_, Name name, bool setter) {
-    if (class_ is ShadowClass) {
-      var classInferenceInfo = ShadowClass.getClassInferenceInfo(class_);
-      if (classInferenceInfo != null) {
-        var member = ClassHierarchy.findMemberByName(
-            setter
-                ? classInferenceInfo.setters
-                : classInferenceInfo.gettersAndMethods,
-            name);
-        if (member == null) return null;
-        member = member is ForwardingNode ? member.resolve() : member;
-        member = member is SyntheticAccessor
-            ? SyntheticAccessor.getField(member)
-            : member;
-        TypeInferenceEngine.resolveInferenceNode(member);
-        return member;
-      }
+  Member _getInterfaceMember(
+      Class class_, Name name, bool setter, int charOffset) {
+    Member member = engine.hierarchyBuilder.getCombinedMemberSignatureKernel(
+        class_, name, setter, charOffset, library);
+    if (member == null && (library?.isPatch ?? false)) {
+      // TODO(dmitryas): Hack for parts.
+      member ??=
+          classHierarchy.getInterfaceMember(class_, name, setter: setter);
     }
-    return classHierarchy.getInterfaceMember(class_, name, setter: setter);
+    return TypeInferenceEngine.resolveInferenceNode(member);
   }
 
   /// Determines if the given [expression]'s type is precisely known at compile
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 0ea1a63..9446be4 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -44,7 +44,6 @@
 CantInferPackagesFromPackageUri/analyzerCode: Fail
 CantInferPackagesFromPackageUri/example: Fail
 CantInferTypeDueToCircularity/example: Fail
-CantInferTypeDueToInconsistentOverrides/example: Fail
 CantReadFile/part_wrapped_script: Fail # Importing file in the (now) part.
 CantUseControlFlowOrSpreadAsConstant/example: Fail
 CantUseDeferredPrefixAsConstant/part_wrapped_script: Fail # Importing file in the (now) part.
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index d94388d..b0ff217 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -2926,6 +2926,13 @@
   template: "Can't infer a type for '#name' as some of the inherited members have different types."
   tip: "Try adding an explicit type."
   analyzerCode: INVALID_METHOD_OVERRIDE
+  external: testcases/inference/inconsistent_overrides.dart
+
+CantInferReturnTypeDueToInconsistentOverrides:
+  template: "Can't infer a return type for '#name' as some of the inherited members have different types."
+  tip: "Try adding an explicit type."
+  analyzerCode: INVALID_METHOD_OVERRIDE
+  external: testcases/inference/inconsistent_overrides.dart
 
 CantInferTypeDueToCircularity:
   template: "Can't infer the type of '#string': circularity found during type inference."
@@ -3569,3 +3576,19 @@
 
 BytecodeLimitExceededTooManyArguments:
   template: "Dart bytecode limit exceeded: too many arguments."
+
+CombinedMemberSignatureFailed:
+  template: "Class '#name' inherits multiple members named '#name2' with incompatible signatures."
+  tip: "Try adding a declaration of '#name2' to '#name'."
+  analyzerCode: INCONSISTENT_INHERITANCE
+  script:
+    - |
+      abstract class I1 {
+        foo(x);
+      }
+
+      abstract class I2 {
+        foo();
+      }
+
+      abstract class C implements I2, I1 {}
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index c183abd..87a52d9 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -368,7 +368,7 @@
       UriTranslator uriTranslator = new UriTranslator(
           const TargetLibrariesSpecification('vm'),
           context.uriTranslator.packages);
-      KernelTarget sourceTarget = new KernelTestingTarget(
+      KernelTarget sourceTarget = new KernelTarget(
           StandardFileSystem.instance, false, dillTarget, uriTranslator);
 
       sourceTarget.setEntryPoints(<Uri>[description.uri]);
@@ -463,15 +463,6 @@
   }
 }
 
-class KernelTestingTarget extends KernelTarget {
-  @override
-  ClassHierarchyBuilder builderHierarchy;
-
-  KernelTestingTarget(StandardFileSystem fileSystem, bool includeComments,
-      DillTarget dillTarget, UriTranslator uriTranslator)
-      : super(fileSystem, includeComments, dillTarget, uriTranslator);
-}
-
 class MatchHierarchy extends Step<Component, Component, FastaContext> {
   const MatchHierarchy();
 
@@ -481,8 +472,8 @@
       Component component, FastaContext context) async {
     Uri uri =
         component.uriToSource.keys.firstWhere((uri) => uri?.scheme == "file");
-    KernelTestingTarget target = context.componentToTarget[component];
-    ClassHierarchyBuilder hierarchy = target.builderHierarchy;
+    KernelTarget target = context.componentToTarget[component];
+    ClassHierarchyBuilder hierarchy = target.loader.builderHierarchy;
     StringBuffer sb = new StringBuffer();
     for (ClassHierarchyNode node in hierarchy.nodes.values) {
       node.toString(sb);
diff --git a/pkg/front_end/test/fasta/type_inference/interface_resolver_test.dart b/pkg/front_end/test/fasta/type_inference/interface_resolver_test.dart
deleted file mode 100644
index b19a80f..0000000
--- a/pkg/front_end/test/fasta/type_inference/interface_resolver_test.dart
+++ /dev/null
@@ -1,1049 +0,0 @@
-// 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/kernel/kernel_shadow_ast.dart';
-import 'package:front_end/src/fasta/type_inference/interface_resolver.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_component.dart';
-import 'package:kernel/type_algebra.dart';
-import 'package:test/test.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(InterfaceResolverTest);
-  });
-}
-
-@reflectiveTest
-class InterfaceResolverTest {
-  final Library testLib;
-
-  final Component component;
-
-  final CoreTypes coreTypes;
-
-  ClassHierarchy cachedClassHierarchy;
-
-  TypeSchemaEnvironment cachedTypeEnvironment;
-
-  InterfaceResolver cachedInterfaceResolver;
-
-  InterfaceResolverTest()
-      : this._(new Library(Uri.parse('org-dartlang:///test.dart'), name: 'lib'),
-            createMockSdkComponent());
-
-  InterfaceResolverTest._(this.testLib, Component component)
-      : component = component..libraries.add(testLib..parent = component),
-        coreTypes = new CoreTypes(component);
-
-  ClassHierarchy get classHierarchy {
-    return cachedClassHierarchy ??= new ClassHierarchy(component);
-  }
-
-  TypeSchemaEnvironment get typeEnvironment {
-    return cachedTypeEnvironment ??=
-        new TypeSchemaEnvironment(coreTypes, classHierarchy);
-  }
-
-  InterfaceResolver get interfaceResolver {
-    return cachedInterfaceResolver ??=
-        new InterfaceResolver(null, typeEnvironment, null);
-  }
-
-  InterfaceType get intType => coreTypes.intClass.rawType;
-
-  Class get listClass => coreTypes.listClass;
-
-  InterfaceType get numType => coreTypes.numClass.rawType;
-
-  Class get objectClass => coreTypes.objectClass;
-
-  InterfaceType get objectType => objectClass.rawType;
-
-  void checkCandidate(Procedure procedure, bool setter) {
-    var class_ = makeClass(procedures: [procedure]);
-    var candidate = getCandidate(class_, setter);
-    expect(candidate, same(procedure));
-  }
-
-  void checkCandidateOrder(Class class_, Member member) {
-    // Check that InterfaceResolver prioritizes [member]
-    var candidates = getCandidates(class_, false);
-    expect(candidates[0], same(member));
-
-    // Check that both implementations of [ClassHierarchy] prioritize [member]
-    // ahead of [other]
-    void check(ClassHierarchy classHierarchy) {
-      var interfaceMember =
-          classHierarchy.getInterfaceMember(class_, member.name);
-      expect(interfaceMember, same(member));
-    }
-
-    check(new ClassHierarchy(component));
-  }
-
-  Procedure getCandidate(Class class_, bool setter) {
-    var candidates = getCandidates(class_, setter);
-    expect(candidates, hasLength(1));
-    return candidates[0];
-  }
-
-  List<Procedure> getCandidates(Class class_, bool setters) =>
-      interfaceResolver.getCandidates(class_, setters);
-
-  ForwardingNode getForwardingNode(Class class_, bool setter) {
-    var forwardingNodes = getForwardingNodes(class_, setter);
-    expect(forwardingNodes, hasLength(1));
-    return forwardingNodes[0];
-  }
-
-  List<ForwardingNode> getForwardingNodes(Class class_, bool setters) {
-    var forwardingNodes = <ForwardingNode>[];
-    var candidates = getCandidates(class_, setters);
-    InterfaceResolver.forEachApiMember(candidates,
-        (int start, int end, Name name) {
-      forwardingNodes.add(new ForwardingNode(interfaceResolver, null, class_,
-          name, candidates[start].kind, candidates, start, end));
-    });
-    return forwardingNodes;
-  }
-
-  Member getStubTarget(Procedure stub) {
-    var body = stub.function.body;
-    if (body == null) return null;
-    if (body is ReturnStatement) {
-      var expression = body.expression;
-      if (expression is SuperMethodInvocation) {
-        return expression.interfaceTarget;
-      } else if (expression is SuperPropertySet) {
-        return expression.interfaceTarget;
-      } else {
-        fail('Unexpected expression type: ${expression.runtimeType}');
-      }
-    } else {
-      fail('Unexpected body type: ${body.runtimeType}');
-    }
-  }
-
-  Class makeClass(
-      {String name,
-      Supertype supertype,
-      Supertype mixedInType,
-      List<TypeParameter> typeParameters,
-      List<Supertype> implementedTypes,
-      List<Procedure> procedures,
-      List<Field> fields}) {
-    resetInterfaceResolver();
-    var class_ = new ShadowClass(
-        name: name ?? 'C',
-        supertype: supertype ?? objectClass.asThisSupertype,
-        mixedInType: mixedInType,
-        typeParameters: typeParameters,
-        implementedTypes: implementedTypes,
-        procedures: procedures,
-        fields: fields);
-    testLib.addClass(class_);
-    return class_;
-  }
-
-  Procedure makeEmptyMethod(
-      {ProcedureKind kind: ProcedureKind.Method,
-      String name: 'foo',
-      List<TypeParameter> typeParameters,
-      List<VariableDeclaration> positionalParameters,
-      List<VariableDeclaration> namedParameters,
-      int requiredParameterCount,
-      DartType returnType: const VoidType(),
-      bool isAbstract: false}) {
-    var body = isAbstract ? null : new ReturnStatement(new NullLiteral());
-    var function = new FunctionNode(body,
-        typeParameters: typeParameters,
-        positionalParameters: positionalParameters,
-        namedParameters: namedParameters,
-        requiredParameterCount: requiredParameterCount,
-        returnType: returnType);
-    return new ShadowProcedure(new Name(name), kind, function, false,
-        isAbstract: isAbstract);
-  }
-
-  Field makeField(
-      {String name: 'foo',
-      DartType type: const DynamicType(),
-      bool isFinal: false}) {
-    return new Field(new Name(name), type: type, isFinal: isFinal);
-  }
-
-  Procedure makeForwardingStub(Procedure method, bool setter,
-      {Substitution substitution}) {
-    var a = makeClass(name: 'A', procedures: [method]);
-    var b = makeClass(name: 'B', supertype: a.asThisSupertype);
-    var node = getForwardingNode(b, setter);
-    var stub = ForwardingNode.createForwardingStubForTesting(
-        node, substitution ?? Substitution.empty, method);
-    ForwardingNode.createForwardingImplIfNeededForTesting(node, stub.function);
-    return stub;
-  }
-
-  Procedure makeGetter(
-      {String name: 'foo', DartType getterType: const DynamicType()}) {
-    var body = new ReturnStatement(new NullLiteral());
-    var function = new FunctionNode(body, returnType: getterType);
-    return new ShadowProcedure(
-        new Name(name), ProcedureKind.Getter, function, false);
-  }
-
-  Procedure makeSetter(
-      {String name: 'foo',
-      DartType setterType: const DynamicType(),
-      bool isCovariant: false}) {
-    var parameter = new VariableDeclarationJudgment('value', 0,
-        type: setterType, isCovariant: isCovariant);
-    var body = new Block([]);
-    var function = new FunctionNode(body,
-        positionalParameters: [parameter], returnType: const VoidType());
-    return new ShadowProcedure(
-        new Name(name), ProcedureKind.Setter, function, false);
-  }
-
-  void resetInterfaceResolver() {
-    cachedClassHierarchy = null;
-    cachedTypeEnvironment = null;
-    cachedInterfaceResolver = null;
-  }
-
-  void test_candidate_for_field_getter() {
-    var field = makeField();
-    var class_ = makeClass(fields: [field]);
-    var candidate = getCandidate(class_, false);
-    expect(candidate, const TypeMatcher<SyntheticAccessor>());
-    expect(candidate.parent, same(class_));
-    expect(candidate.name, field.name);
-    expect(candidate.kind, ProcedureKind.Getter);
-    expect(candidate.function.positionalParameters, isEmpty);
-    expect(candidate.function.namedParameters, isEmpty);
-    expect(candidate.function.typeParameters, isEmpty);
-  }
-
-  void test_candidate_for_field_setter() {
-    var field = makeField();
-    var class_ = makeClass(fields: [field]);
-    var candidate = getCandidate(class_, true);
-    expect(candidate, const TypeMatcher<SyntheticAccessor>());
-    expect(candidate.parent, same(class_));
-    expect(candidate.name, field.name);
-    expect(candidate.kind, ProcedureKind.Setter);
-    expect(candidate.function.positionalParameters, hasLength(1));
-    expect(candidate.function.positionalParameters[0].name, '_');
-    expect(candidate.function.namedParameters, isEmpty);
-    expect(candidate.function.typeParameters, isEmpty);
-    expect(candidate.function.returnType, const VoidType());
-  }
-
-  void test_candidate_for_getter() {
-    var function = new FunctionNode(null);
-    var getter = new ShadowProcedure(
-        new Name('foo'), ProcedureKind.Getter, function, false);
-    checkCandidate(getter, false);
-  }
-
-  void test_candidate_for_method() {
-    checkCandidate(makeEmptyMethod(), false);
-  }
-
-  void test_candidate_for_setter() {
-    var parameter = new VariableDeclarationJudgment('value', 0);
-    var function = new FunctionNode(null,
-        positionalParameters: [parameter], returnType: const VoidType());
-    var setter = new ShadowProcedure(
-        new Name('foo'), ProcedureKind.Setter, function, false);
-    checkCandidate(setter, true);
-  }
-
-  void test_candidate_from_interface() {
-    var method = makeEmptyMethod();
-    var a = makeClass(name: 'A', procedures: [method]);
-    var b = makeClass(name: 'B', implementedTypes: [a.asThisSupertype]);
-    var candidate = getCandidate(b, false);
-    expect(candidate, same(method));
-  }
-
-  void test_candidate_from_mixin() {
-    var method = makeEmptyMethod();
-    var a = makeClass(name: 'A', procedures: [method]);
-    var b = makeClass(name: 'B', mixedInType: a.asThisSupertype);
-    var candidate = getCandidate(b, false);
-    expect(candidate, same(method));
-  }
-
-  void test_candidate_from_superclass() {
-    var method = makeEmptyMethod();
-    var a = makeClass(name: 'A', procedures: [method]);
-    var b = makeClass(name: 'B', supertype: a.asThisSupertype);
-    var candidate = getCandidate(b, false);
-    expect(candidate, same(method));
-  }
-
-  void test_candidate_order_interfaces() {
-    var methodA = makeEmptyMethod();
-    var methodB = makeEmptyMethod();
-    var a = makeClass(name: 'A', procedures: [methodA]);
-    var b = makeClass(name: 'B', procedures: [methodB]);
-    var c = makeClass(
-        name: 'C', implementedTypes: [a.asThisSupertype, b.asThisSupertype]);
-    checkCandidateOrder(c, methodA);
-  }
-
-  void test_candidate_order_mixin_before_superclass() {
-    var methodA = makeEmptyMethod();
-    var methodB = makeEmptyMethod();
-    var a = makeClass(name: 'A', procedures: [methodA]);
-    var b = makeClass(name: 'B', procedures: [methodB]);
-    var c = makeClass(
-        name: 'C',
-        supertype: a.asThisSupertype,
-        mixedInType: b.asThisSupertype);
-    checkCandidateOrder(c, methodB);
-  }
-
-  void test_candidate_order_superclass_before_interface() {
-    var methodA = makeEmptyMethod();
-    var methodB = makeEmptyMethod();
-    var a = makeClass(name: 'A', procedures: [methodA]);
-    var b = makeClass(name: 'B', procedures: [methodB]);
-    var c = makeClass(
-        name: 'C',
-        supertype: a.asThisSupertype,
-        implementedTypes: [b.asThisSupertype]);
-    checkCandidateOrder(c, methodA);
-  }
-
-  void test_createForwardingStub_abstract() {
-    var method = makeEmptyMethod(isAbstract: true);
-    var stub = makeForwardingStub(method, false);
-    expect(stub.isAbstract, isTrue);
-    expect(stub.function.body, isNull);
-  }
-
-  void test_createForwardingStub_getter() {
-    var getter = makeGetter(getterType: numType);
-    var stub = makeForwardingStub(getter, false);
-    expect(stub.name, getter.name);
-    expect(stub.kind, ProcedureKind.Getter);
-    expect(stub.function.positionalParameters, isEmpty);
-    expect(stub.function.namedParameters, isEmpty);
-    expect(stub.function.typeParameters, isEmpty);
-    expect(stub.function.requiredParameterCount, 0);
-    expect(stub.function.returnType, numType);
-    var body = stub.function.body as ReturnStatement;
-    var expression = body.expression as SuperPropertyGet;
-    expect(expression.name, getter.name);
-    expect(expression.interfaceTarget, same(getter));
-  }
-
-  void test_createForwardingStub_getter_for_field() {
-    var field = makeField(type: numType);
-    var stub = makeForwardingStub(
-        InterfaceResolver.makeCandidate(field, false), false);
-    expect(stub.name, field.name);
-    expect(stub.kind, ProcedureKind.Getter);
-    expect(stub.function.positionalParameters, isEmpty);
-    expect(stub.function.namedParameters, isEmpty);
-    expect(stub.function.typeParameters, isEmpty);
-    expect(stub.function.requiredParameterCount, 0);
-    expect(stub.function.returnType, numType);
-    var body = stub.function.body as ReturnStatement;
-    var expression = body.expression as SuperPropertyGet;
-    expect(expression.name, field.name);
-    expect(expression.interfaceTarget, same(field));
-  }
-
-  void test_createForwardingStub_operator() {
-    var operator = makeEmptyMethod(
-        kind: ProcedureKind.Operator,
-        name: '[]=',
-        positionalParameters: [
-          new VariableDeclarationJudgment('index', 0, type: intType),
-          new VariableDeclarationJudgment('value', 0, type: numType)
-        ]);
-    var stub = makeForwardingStub(operator, false);
-    expect(stub.name, operator.name);
-    expect(stub.kind, ProcedureKind.Operator);
-    expect(stub.function.positionalParameters, hasLength(2));
-    expect(stub.function.positionalParameters[0].name,
-        operator.function.positionalParameters[0].name);
-    expect(stub.function.positionalParameters[0].type, intType);
-    expect(stub.function.positionalParameters[1].name,
-        operator.function.positionalParameters[1].name);
-    expect(stub.function.positionalParameters[1].type, numType);
-    expect(stub.function.namedParameters, isEmpty);
-    expect(stub.function.typeParameters, isEmpty);
-    expect(stub.function.requiredParameterCount, 2);
-    expect(stub.function.returnType, const VoidType());
-    var body = stub.function.body as ReturnStatement;
-    var expression = body.expression as SuperMethodInvocation;
-    expect(expression.name, operator.name);
-    expect(expression.interfaceTarget, same(operator));
-    var arguments = expression.arguments;
-    expect(arguments.positional, hasLength(2));
-    expect((arguments.positional[0] as VariableGet).variable,
-        same(stub.function.positionalParameters[0]));
-    expect((arguments.positional[1] as VariableGet).variable,
-        same(stub.function.positionalParameters[1]));
-  }
-
-  void test_createForwardingStub_optionalNamedParameter() {
-    var parameter = new VariableDeclarationJudgment('x', 0, type: intType);
-    var method = makeEmptyMethod(namedParameters: [parameter]);
-    var stub = makeForwardingStub(method, false);
-    expect(stub.function.namedParameters, hasLength(1));
-    expect(stub.function.namedParameters[0].name, 'x');
-    expect(stub.function.namedParameters[0].type, intType);
-    expect(stub.function.requiredParameterCount, 0);
-    var arguments = ((stub.function.body as ReturnStatement).expression
-            as SuperMethodInvocation)
-        .arguments;
-    expect(arguments.named, hasLength(1));
-    expect(arguments.named[0].name, 'x');
-    expect((arguments.named[0].value as VariableGet).variable,
-        same(stub.function.namedParameters[0]));
-  }
-
-  void test_createForwardingStub_optionalPositionalParameter() {
-    var parameter = new VariableDeclarationJudgment('x', 0, type: intType);
-    var method = makeEmptyMethod(
-        positionalParameters: [parameter], requiredParameterCount: 0);
-    var stub = makeForwardingStub(method, false);
-    expect(stub.function.positionalParameters, hasLength(1));
-    expect(stub.function.positionalParameters[0].name, 'x');
-    expect(stub.function.positionalParameters[0].type, intType);
-    expect(stub.function.requiredParameterCount, 0);
-    var arguments = ((stub.function.body as ReturnStatement).expression
-            as SuperMethodInvocation)
-        .arguments;
-    expect(arguments.positional, hasLength(1));
-    expect((arguments.positional[0] as VariableGet).variable,
-        same(stub.function.positionalParameters[0]));
-  }
-
-  void test_createForwardingStub_requiredParameter() {
-    var parameter = new VariableDeclarationJudgment('x', 0, type: intType);
-    var method = makeEmptyMethod(positionalParameters: [parameter]);
-    var stub = makeForwardingStub(method, false);
-    expect(stub.function.positionalParameters, hasLength(1));
-    expect(stub.function.positionalParameters[0].name, 'x');
-    expect(stub.function.positionalParameters[0].type, intType);
-    expect(stub.function.requiredParameterCount, 1);
-    var arguments = ((stub.function.body as ReturnStatement).expression
-            as SuperMethodInvocation)
-        .arguments;
-    expect(arguments.positional, hasLength(1));
-    expect((arguments.positional[0] as VariableGet).variable,
-        same(stub.function.positionalParameters[0]));
-  }
-
-  void test_createForwardingStub_setter() {
-    var setter = makeSetter(setterType: numType);
-    var stub = makeForwardingStub(setter, true);
-    expect(stub.name, setter.name);
-    expect(stub.kind, ProcedureKind.Setter);
-    expect(stub.function.positionalParameters, hasLength(1));
-    expect(stub.function.positionalParameters[0].name,
-        setter.function.positionalParameters[0].name);
-    expect(stub.function.positionalParameters[0].type, numType);
-    expect(stub.function.namedParameters, isEmpty);
-    expect(stub.function.typeParameters, isEmpty);
-    expect(stub.function.requiredParameterCount, 1);
-    expect(stub.function.returnType, const VoidType());
-    var body = stub.function.body as ReturnStatement;
-    var expression = body.expression as SuperPropertySet;
-    expect(expression.name, setter.name);
-    expect(expression.interfaceTarget, same(setter));
-    expect((expression.value as VariableGet).variable,
-        same(stub.function.positionalParameters[0]));
-  }
-
-  void test_createForwardingStub_setter_for_field() {
-    var field = makeField(type: numType);
-    var stub =
-        makeForwardingStub(InterfaceResolver.makeCandidate(field, true), true);
-    expect(stub.name, field.name);
-    expect(stub.kind, ProcedureKind.Setter);
-    expect(stub.function.positionalParameters, hasLength(1));
-    expect(stub.function.positionalParameters[0].name, '_');
-    expect(stub.function.positionalParameters[0].type, numType);
-    expect(stub.function.namedParameters, isEmpty);
-    expect(stub.function.typeParameters, isEmpty);
-    expect(stub.function.requiredParameterCount, 1);
-    expect(stub.function.returnType, const VoidType());
-    var body = stub.function.body as ReturnStatement;
-    var expression = body.expression as SuperPropertySet;
-    expect(expression.name, field.name);
-    expect(expression.interfaceTarget, same(field));
-    expect((expression.value as VariableGet).variable,
-        same(stub.function.positionalParameters[0]));
-  }
-
-  void test_createForwardingStub_simple() {
-    var method = makeEmptyMethod();
-    var stub = makeForwardingStub(method, false);
-    expect(stub.name, method.name);
-    expect(stub.kind, ProcedureKind.Method);
-    expect(stub.isAbstract, isFalse);
-    expect(stub.function.positionalParameters, isEmpty);
-    expect(stub.function.namedParameters, isEmpty);
-    expect(stub.function.typeParameters, isEmpty);
-    expect(stub.function.requiredParameterCount, 0);
-    expect(stub.function.returnType, const VoidType());
-    var body = stub.function.body as ReturnStatement;
-    var expression = body.expression as SuperMethodInvocation;
-    expect(expression.name, method.name);
-    expect(expression.interfaceTarget, same(method));
-    expect(expression.arguments.positional, isEmpty);
-    expect(expression.arguments.named, isEmpty);
-    expect(expression.arguments.types, isEmpty);
-  }
-
-  void test_createForwardingStub_substitute() {
-    // class C<T> { T foo(T x, {T y}); }
-    var T = new TypeParameter('T', objectType);
-    var x =
-        new VariableDeclarationJudgment('x', 0, type: new TypeParameterType(T));
-    var y =
-        new VariableDeclarationJudgment('y', 0, type: new TypeParameterType(T));
-    var method = makeEmptyMethod(
-        positionalParameters: [x],
-        namedParameters: [y],
-        returnType: new TypeParameterType(T));
-    var substitution = Substitution.fromPairs([T], [intType]);
-    var stub = makeForwardingStub(method, false, substitution: substitution);
-    expect(stub.function.positionalParameters[0].type, intType);
-    expect(stub.function.namedParameters[0].type, intType);
-    expect(stub.function.returnType, intType);
-  }
-
-  void test_createForwardingStub_typeParameter() {
-    var typeParameter = new TypeParameter('T', numType);
-    var method = makeEmptyMethod(typeParameters: [typeParameter]);
-    var stub = makeForwardingStub(method, false);
-    expect(stub.function.typeParameters, hasLength(1));
-    expect(stub.function.typeParameters[0].name, 'T');
-    expect(stub.function.typeParameters[0].bound, numType);
-    var arguments = ((stub.function.body as ReturnStatement).expression
-            as SuperMethodInvocation)
-        .arguments;
-    expect(arguments.types, hasLength(1));
-    var typeArgument = arguments.types[0] as TypeParameterType;
-    expect(typeArgument.parameter, same(stub.function.typeParameters[0]));
-    expect(typeArgument.promotedBound, isNull);
-  }
-
-  void test_createForwardingStub_typeParameter_and_substitution() {
-    // class C<T> { void foo<U>(T x, U y); }
-    var T = new TypeParameter('T', objectType);
-    var U = new TypeParameter('U', objectType);
-    var x =
-        new VariableDeclarationJudgment('x', 0, type: new TypeParameterType(T));
-    var y =
-        new VariableDeclarationJudgment('y', 0, type: new TypeParameterType(U));
-    var method =
-        makeEmptyMethod(typeParameters: [U], positionalParameters: [x, y]);
-    var substitution = Substitution.fromPairs([T], [intType]);
-    var stub = makeForwardingStub(method, false, substitution: substitution);
-    expect(stub.function.positionalParameters[0].type, intType);
-    var stubYType =
-        stub.function.positionalParameters[1].type as TypeParameterType;
-    expect(stubYType.parameter, same(stub.function.typeParameters[0]));
-  }
-
-  void test_createForwardingStub_typeParameter_substituteUses() {
-    // class C { void foo<T>(T x); }
-    var typeParameter = new TypeParameter('T', objectType);
-    var param = new VariableDeclarationJudgment('x', 0,
-        type: new TypeParameterType(typeParameter));
-    var method = makeEmptyMethod(
-        typeParameters: [typeParameter], positionalParameters: [param]);
-    var stub = makeForwardingStub(method, false);
-    var stubXType =
-        stub.function.positionalParameters[0].type as TypeParameterType;
-    expect(stubXType.parameter, same(stub.function.typeParameters[0]));
-  }
-
-  void test_createForwardingStub_typeParameter_substituteUses_fBounded() {
-    // class C { void foo<T extends List<T>>(T x); }
-    var typeParameter = new TypeParameter('T', null);
-    typeParameter.bound =
-        new InterfaceType(listClass, [new TypeParameterType(typeParameter)]);
-    var param = new VariableDeclarationJudgment('x', 0,
-        type: new TypeParameterType(typeParameter));
-    var method = makeEmptyMethod(
-        typeParameters: [typeParameter], positionalParameters: [param]);
-    var stub = makeForwardingStub(method, false);
-    var stubTypeParameter = stub.function.typeParameters[0];
-    var stubTypeParameterBound = stubTypeParameter.bound as InterfaceType;
-    var stubTypeParameterBoundArg =
-        stubTypeParameterBound.typeArguments[0] as TypeParameterType;
-    expect(stubTypeParameterBoundArg.parameter, same(stubTypeParameter));
-    var stubXType =
-        stub.function.positionalParameters[0].type as TypeParameterType;
-    expect(stubXType.parameter, same(stubTypeParameter));
-  }
-
-  void test_direct_isGenericCovariant() {
-    var typeParameter = new TypeParameter('T', objectType);
-    var u = new TypeParameter('U', new TypeParameterType(typeParameter))
-      ..isGenericCovariantImpl = true;
-    var x = new VariableDeclarationJudgment('x', 0,
-        type: new TypeParameterType(typeParameter));
-    var y = new VariableDeclarationJudgment('y', 0,
-        type: new TypeParameterType(typeParameter));
-    var method = makeEmptyMethod(
-        typeParameters: [u], positionalParameters: [x], namedParameters: [y]);
-    var class_ =
-        makeClass(typeParameters: [typeParameter], procedures: [method]);
-    var node = getForwardingNode(class_, false);
-    ShadowClass.setBuilder(class_, null);
-    var resolvedMethod = node.finalize();
-    expect(resolvedMethod, same(method));
-    expect(u.isGenericCovariantImpl, isTrue);
-    expect(x.isGenericCovariantImpl, isTrue);
-    expect(x.isCovariant, isFalse);
-    expect(y.isGenericCovariantImpl, isTrue);
-    expect(y.isCovariant, isFalse);
-  }
-
-  void test_direct_isGenericCovariant_field() {
-    var typeParameter = new TypeParameter('T', objectType);
-    var field = makeField(type: new TypeParameterType(typeParameter));
-    var class_ = makeClass(typeParameters: [typeParameter], fields: [field]);
-    var node = getForwardingNode(class_, true);
-    ShadowClass.setBuilder(class_, null);
-    var resolvedAccessor = node.finalize() as SyntheticAccessor;
-    expect(SyntheticAccessor.getField(resolvedAccessor), same(field));
-    expect(field.isGenericCovariantImpl, isTrue);
-    expect(field.isCovariant, isFalse);
-  }
-
-  void test_field_isCovariant_inherited() {
-    var fieldA = makeField(type: numType)..isCovariant = true;
-    var fieldB = makeField(type: numType);
-    var a = makeClass(name: 'A', fields: [fieldA]);
-    var b = makeClass(
-        name: 'B', implementedTypes: [a.asThisSupertype], fields: [fieldB]);
-    var node = getForwardingNode(b, true);
-    var resolvedAccessor = node.finalize() as SyntheticAccessor;
-    expect(SyntheticAccessor.getField(resolvedAccessor), same(fieldB));
-    expect(fieldB.isGenericCovariantImpl, isFalse);
-    expect(fieldB.isCovariant, isTrue);
-  }
-
-  void test_field_isGenericCovariantImpl_inherited() {
-    var typeParameter = new TypeParameter('T', objectType);
-    var fieldA = makeField(type: new TypeParameterType(typeParameter))
-      ..isGenericCovariantImpl = true;
-    var fieldB = makeField(type: numType);
-    var a =
-        makeClass(name: 'A', typeParameters: [typeParameter], fields: [fieldA]);
-    var b = makeClass(name: 'B', implementedTypes: [
-      new Supertype(a, [numType])
-    ], fields: [
-      fieldB
-    ]);
-    var node = getForwardingNode(b, true);
-    var resolvedAccessor = node.finalize() as SyntheticAccessor;
-    expect(SyntheticAccessor.getField(resolvedAccessor), same(fieldB));
-    expect(fieldB.isGenericCovariantImpl, isTrue);
-    expect(fieldB.isCovariant, isFalse);
-  }
-
-  void test_forwardingNodes_multiple() {
-    var methodAf = makeEmptyMethod(name: 'f');
-    var methodBf = makeEmptyMethod(name: 'f');
-    var methodAg = makeEmptyMethod(name: 'g');
-    var methodBg = makeEmptyMethod(name: 'g');
-    var a = makeClass(name: 'A', procedures: [methodAf, methodAg]);
-    var b = makeClass(
-        name: 'B',
-        supertype: a.asThisSupertype,
-        procedures: [methodBf, methodBg]);
-    var forwardingNodes = getForwardingNodes(b, false);
-    expect(forwardingNodes, hasLength(2));
-    var nodef = ClassHierarchy.findMemberByName(forwardingNodes, methodAf.name);
-    var nodeg = ClassHierarchy.findMemberByName(forwardingNodes, methodAg.name);
-    expect(nodef, isNot(same(nodeg)));
-    expect(nodef.parent, b);
-    expect(nodeg.parent, b);
-    {
-      var candidates = ForwardingNode.getCandidates(nodef);
-      expect(candidates, hasLength(2));
-      expect(candidates[0], same(methodBf));
-      expect(candidates[1], same(methodAf));
-    }
-    {
-      var candidates = ForwardingNode.getCandidates(nodeg);
-      expect(candidates, hasLength(2));
-      expect(candidates[0], same(methodBg));
-      expect(candidates[1], same(methodAg));
-    }
-  }
-
-  void test_forwardingNodes_single() {
-    var methodA = makeEmptyMethod();
-    var methodB = makeEmptyMethod();
-    var a = makeClass(name: 'A', procedures: [methodA]);
-    var b = makeClass(
-        name: 'B', supertype: a.asThisSupertype, procedures: [methodB]);
-    var forwardingNodes = getForwardingNodes(b, false);
-    expect(forwardingNodes, hasLength(1));
-    expect(forwardingNodes[0].parent, b);
-    expect(forwardingNodes[0].name, methodA.name);
-    var candidates = ForwardingNode.getCandidates(forwardingNodes[0]);
-    expect(candidates, hasLength(2));
-    expect(candidates[0], same(methodB));
-    expect(candidates[1], same(methodA));
-  }
-
-  void test_forwardingStub_isCovariant_inherited() {
-    var methodA = makeEmptyMethod(positionalParameters: [
-      new VariableDeclarationJudgment('x', 0, type: numType)
-    ], namedParameters: [
-      new VariableDeclarationJudgment('y', 0, type: numType)
-    ]);
-    var methodB = makeEmptyMethod(positionalParameters: [
-      new VariableDeclarationJudgment('x', 0, type: intType)..isCovariant = true
-    ], namedParameters: [
-      new VariableDeclarationJudgment('y', 0, type: intType)..isCovariant = true
-    ]);
-    var a = makeClass(name: 'A', procedures: [methodA]);
-    var b = makeClass(name: 'B', procedures: [methodB]);
-    var c = makeClass(
-        name: 'C',
-        supertype: a.asThisSupertype,
-        implementedTypes: [b.asThisSupertype]);
-    var node = getForwardingNode(c, false);
-    var stub = node.finalize();
-    var x = stub.function.positionalParameters[0];
-    expect(x.isGenericCovariantImpl, isFalse);
-    expect(x.isCovariant, isTrue);
-    var y = stub.function.namedParameters[0];
-    expect(y.isGenericCovariantImpl, isFalse);
-    expect(y.isCovariant, isTrue);
-    expect(stub.forwardingStubInterfaceTarget, same(methodA));
-    expect(getStubTarget(stub), same(methodA));
-  }
-
-  void test_forwardingStub_isGenericCovariantImpl_inherited() {
-    var methodA = makeEmptyMethod(typeParameters: [
-      new TypeParameter('U', numType)
-    ], positionalParameters: [
-      new VariableDeclarationJudgment('x', 0, type: numType)
-    ], namedParameters: [
-      new VariableDeclarationJudgment('y', 0, type: numType)
-    ]);
-    var typeParameterB = new TypeParameter('T', objectType);
-    var methodB = makeEmptyMethod(typeParameters: [
-      new TypeParameter('U', new TypeParameterType(typeParameterB))
-        ..isGenericCovariantImpl = true
-    ], positionalParameters: [
-      new VariableDeclarationJudgment('x', 0,
-          type: new TypeParameterType(typeParameterB))
-        ..isGenericCovariantImpl = true
-    ], namedParameters: [
-      new VariableDeclarationJudgment('y', 0,
-          type: new TypeParameterType(typeParameterB))
-        ..isGenericCovariantImpl = true
-    ]);
-    var a = makeClass(name: 'A', procedures: [methodA]);
-    var b = makeClass(
-        name: 'B', typeParameters: [typeParameterB], procedures: [methodB]);
-    var c =
-        makeClass(name: 'C', supertype: a.asThisSupertype, implementedTypes: [
-      new Supertype(b, [numType])
-    ]);
-    var node = getForwardingNode(c, false);
-    var stub = node.finalize();
-    var u = stub.function.typeParameters[0];
-    expect(u.isGenericCovariantImpl, isTrue);
-    var x = stub.function.positionalParameters[0];
-    expect(x.isGenericCovariantImpl, isTrue);
-    expect(x.isCovariant, isFalse);
-    var y = stub.function.namedParameters[0];
-    expect(y.isGenericCovariantImpl, isTrue);
-    expect(y.isCovariant, isFalse);
-    expect(stub.forwardingStubInterfaceTarget, same(methodA));
-    expect(getStubTarget(stub), same(methodA));
-  }
-
-  void test_interfaceTarget_cascaded() {
-    var methodC = makeEmptyMethod(positionalParameters: [
-      new VariableDeclaration('x', type: intType),
-      new VariableDeclaration('y', type: intType)
-    ]);
-    var c = makeClass(name: 'C', procedures: [methodC]);
-    var t = new TypeParameter('T', objectType);
-    var methodI1 = makeEmptyMethod(positionalParameters: [
-      new VariableDeclaration('x', type: new TypeParameterType(t))
-        ..isGenericCovariantImpl = true,
-      new VariableDeclaration('y', type: intType)
-    ]);
-    var i1 = makeClass(name: 'I1', typeParameters: [t], procedures: [methodI1]);
-    // Let's say D was previously compiled, so it already has a forwarding stub
-    var d =
-        makeClass(name: 'D', supertype: c.asThisSupertype, implementedTypes: [
-      new Supertype(i1, [intType])
-    ]);
-    var nodeD = getForwardingNode(d, false);
-    var methodD = ForwardingNode.createForwardingStubForTesting(
-        nodeD, Substitution.empty, methodC);
-    d.addMember(methodD);
-    ForwardingNode.createForwardingImplIfNeededForTesting(
-        nodeD, methodD.function);
-    // To ensure that we don't accidentally make use of information that was
-    // computed prior to adding the forwarding stub, reset the interface
-    // resolver.
-    resetInterfaceResolver();
-    var u = new TypeParameter('U', objectType);
-    var methodI2 = makeEmptyMethod(positionalParameters: [
-      new VariableDeclaration('x', type: intType),
-      new VariableDeclaration('y', type: new TypeParameterType(u))
-        ..isGenericCovariantImpl = true
-    ]);
-    var i2 = makeClass(name: 'I2', typeParameters: [u], procedures: [methodI2]);
-    var e =
-        makeClass(name: 'E', supertype: d.asThisSupertype, implementedTypes: [
-      new Supertype(i2, [intType])
-    ]);
-    var nodeE = getForwardingNode(e, false);
-    var stub = nodeE.finalize();
-    expect(stub.forwardingStubInterfaceTarget, same(methodC));
-    expect(getStubTarget(stub), same(methodC));
-  }
-
-  void test_interfaceTarget_cascaded_setter() {
-    var setterC = makeSetter(setterType: intType);
-    var c = makeClass(name: 'C', procedures: [setterC]);
-    var t = new TypeParameter('T', objectType);
-    var setterI1 = makeSetter(setterType: new TypeParameterType(t));
-    var i1 = makeClass(name: 'I1', typeParameters: [t], procedures: [setterI1]);
-    // Let's say D was previously compiled, so it already has a forwarding stub
-    var d =
-        makeClass(name: 'D', supertype: c.asThisSupertype, implementedTypes: [
-      new Supertype(i1, [intType])
-    ]);
-    var nodeD = getForwardingNode(d, true);
-    var setterD = ForwardingNode.createForwardingStubForTesting(
-        nodeD, Substitution.empty, setterC);
-    d.addMember(setterD);
-    ForwardingNode.createForwardingImplIfNeededForTesting(
-        nodeD, setterD.function);
-    // To ensure that we don't accidentally make use of information that was
-    // computed prior to adding the forwarding stub, reset the interface
-    // resolver.
-    resetInterfaceResolver();
-    var setterI2 = makeSetter(setterType: intType, isCovariant: true);
-    var i2 = makeClass(name: 'I2', procedures: [setterI2]);
-    var e = makeClass(
-        name: 'E',
-        supertype: d.asThisSupertype,
-        implementedTypes: [i2.asThisSupertype]);
-    var nodeE = getForwardingNode(e, true);
-    var stub = nodeE.finalize();
-    expect(stub.forwardingStubInterfaceTarget, same(setterC));
-    expect(getStubTarget(stub), same(setterC));
-  }
-
-  void test_interfaceTarget_field() {
-    var fieldA = makeField(type: numType, isFinal: true);
-    var fieldB = makeField(type: intType, isFinal: true);
-    var a = makeClass(name: 'A', fields: [fieldA]);
-    var b = makeClass(name: 'B', fields: [fieldB]);
-    var c = makeClass(
-        name: 'C',
-        supertype: a.asThisSupertype,
-        implementedTypes: [b.asThisSupertype]);
-    var node = getForwardingNode(c, false);
-    var stub = node.finalize();
-    expect(stub.forwardingStubInterfaceTarget, same(fieldB));
-  }
-
-  void test_merge_candidates_including_mixin() {
-    var methodA = makeEmptyMethod();
-    var methodB = makeEmptyMethod();
-    var methodC = makeEmptyMethod();
-    var a = makeClass(name: 'A', procedures: [methodA]);
-    var b = makeClass(name: 'B', procedures: [methodB]);
-    var c = makeClass(name: 'C', procedures: [methodC]);
-    var d = makeClass(
-        name: 'D',
-        supertype: a.asThisSupertype,
-        mixedInType: b.asThisSupertype,
-        implementedTypes: [c.asThisSupertype]);
-    var candidates = getCandidates(d, false);
-    expect(candidates, hasLength(3));
-    expect(candidates[0], same(methodB));
-    expect(candidates[1], same(methodA));
-    expect(candidates[2], same(methodC));
-  }
-
-  void test_merge_candidates_not_including_mixin() {
-    var methodA = makeEmptyMethod();
-    var methodB = makeEmptyMethod();
-    var methodC = makeEmptyMethod();
-    var a = makeClass(name: 'A', procedures: [methodA]);
-    var b = makeClass(name: 'B', procedures: [methodB]);
-    var c = makeClass(
-        name: 'C',
-        supertype: a.asThisSupertype,
-        implementedTypes: [b.asThisSupertype],
-        procedures: [methodC]);
-    var candidates = getCandidates(c, false);
-    expect(candidates, hasLength(3));
-    expect(candidates[0], same(methodC));
-    expect(candidates[1], same(methodA));
-    expect(candidates[2], same(methodB));
-  }
-
-  void test_resolve_directly_declared() {
-    var parameterA = new VariableDeclarationJudgment('x', 0,
-        type: objectType, isCovariant: true);
-    var methodA = makeEmptyMethod(positionalParameters: [parameterA]);
-    var parameterB = new VariableDeclarationJudgment('x', 0,
-        type: intType, isCovariant: true);
-    var methodB = makeEmptyMethod(positionalParameters: [parameterB]);
-    var a = makeClass(name: 'A', procedures: [methodA]);
-    var b = makeClass(
-        name: 'B', supertype: a.asThisSupertype, procedures: [methodB]);
-    var node = getForwardingNode(b, false);
-    expect(node.finalize(), same(methodB));
-  }
-
-  void test_resolve_favor_first() {
-    // When multiple methods have equivalent types, favor the first one.
-    var methodA = makeEmptyMethod();
-    var methodB = makeEmptyMethod();
-    var a = makeClass(name: 'A', procedures: [methodA]);
-    var b = makeClass(name: 'B', procedures: [methodB]);
-    var c = makeClass(
-        name: 'C', implementedTypes: [a.asThisSupertype, b.asThisSupertype]);
-    var node = getForwardingNode(c, false);
-    expect(node.finalize(), same(methodA));
-  }
-
-  void test_resolve_field() {
-    var field = makeField();
-    var a = makeClass(name: 'A', fields: [field]);
-    var b = makeClass(name: 'B', supertype: a.asThisSupertype);
-    var node = getForwardingNode(b, false);
-    var accessor = node.finalize() as SyntheticAccessor;
-    expect(SyntheticAccessor.getField(accessor), same(field));
-  }
-
-  void test_resolve_first() {
-    var methodA = makeEmptyMethod(returnType: intType);
-    var methodB = makeEmptyMethod(returnType: numType);
-    var a = makeClass(name: 'A', procedures: [methodA]);
-    var b = makeClass(name: 'B', procedures: [methodB]);
-    var c = makeClass(
-        name: 'C', implementedTypes: [a.asThisSupertype, b.asThisSupertype]);
-    var node = getForwardingNode(c, false);
-    expect(node.finalize(), same(methodA));
-  }
-
-  void test_resolve_second() {
-    var methodA = makeEmptyMethod(returnType: numType);
-    var methodB = makeEmptyMethod(returnType: intType);
-    var a = makeClass(name: 'A', procedures: [methodA]);
-    var b = makeClass(name: 'B', procedures: [methodB]);
-    var c = makeClass(
-        name: 'C', implementedTypes: [a.asThisSupertype, b.asThisSupertype]);
-    var node = getForwardingNode(c, false);
-    var stub = node.finalize();
-    expect(stub.forwardingStubInterfaceTarget, same(methodB));
-    expect(getStubTarget(stub), isNull);
-    expect(stub.function.returnType, intType);
-  }
-
-  void test_resolve_setters() {
-    var setterA = makeSetter(setterType: intType);
-    var setterB = makeSetter(setterType: objectType);
-    var setterC = makeSetter(setterType: numType);
-    var a = makeClass(name: 'A', procedures: [setterA]);
-    var b = makeClass(name: 'B', procedures: [setterB]);
-    var c = makeClass(name: 'C', procedures: [setterC]);
-    var d = makeClass(name: 'D', implementedTypes: [
-      a.asThisSupertype,
-      b.asThisSupertype,
-      c.asThisSupertype
-    ]);
-    var node = getForwardingNode(d, true);
-    var stub = node.finalize();
-    expect(stub.forwardingStubInterfaceTarget, same(setterB));
-    expect(getStubTarget(stub), isNull);
-    expect(stub.function.positionalParameters[0].type, objectType);
-  }
-
-  void test_resolve_with_added_implementation() {
-    var methodA = makeEmptyMethod(positionalParameters: [
-      new VariableDeclarationJudgment('x', 0, type: numType)
-    ]);
-    var typeParamB = new TypeParameter('T', objectType);
-    var methodB = makeEmptyMethod(positionalParameters: [
-      new VariableDeclarationJudgment('x', 0,
-          type: new TypeParameterType(typeParamB))
-        ..isGenericCovariantImpl = true
-    ]);
-    var methodC = makeEmptyMethod(positionalParameters: [
-      new VariableDeclarationJudgment('x', 0, type: numType)
-    ], isAbstract: true);
-    var a = makeClass(name: 'A', procedures: [methodA]);
-    var b = makeClass(
-        name: 'B', typeParameters: [typeParamB], procedures: [methodB]);
-    var c =
-        makeClass(name: 'C', supertype: a.asThisSupertype, implementedTypes: [
-      new Supertype(b, [numType])
-    ], procedures: [
-      methodC
-    ]);
-    var node = getForwardingNode(c, false);
-    expect(methodC.function.body, isNull);
-    var resolvedMethod = node.finalize();
-    expect(resolvedMethod, same(methodC));
-    expect(methodC.function.body, isNotNull);
-    expect(methodC.forwardingStubInterfaceTarget, isNull);
-    expect(getStubTarget(methodC), same(methodA));
-  }
-
-  void test_resolve_with_substitutions() {
-    var typeParamA = new TypeParameter('T', objectType);
-    var typeParamB = new TypeParameter('T', objectType);
-    var typeParamC = new TypeParameter('T', objectType);
-    var methodA =
-        makeEmptyMethod(returnType: new TypeParameterType(typeParamA));
-    var methodB =
-        makeEmptyMethod(returnType: new TypeParameterType(typeParamB));
-    var methodC =
-        makeEmptyMethod(returnType: new TypeParameterType(typeParamC));
-    var a = makeClass(
-        name: 'A', typeParameters: [typeParamA], procedures: [methodA]);
-    var b = makeClass(
-        name: 'B', typeParameters: [typeParamB], procedures: [methodB]);
-    var c = makeClass(
-        name: 'C', typeParameters: [typeParamC], procedures: [methodC]);
-    var d = makeClass(
-        name: 'D',
-        supertype: new Supertype(a, [objectType]),
-        implementedTypes: [
-          new Supertype(b, [intType]),
-          new Supertype(c, [numType])
-        ]);
-    var node = getForwardingNode(d, false);
-    var stub = node.finalize();
-    expect(stub.forwardingStubInterfaceTarget, same(methodB));
-    expect(getStubTarget(stub), isNull);
-    expect(stub.function.returnType, intType);
-  }
-}
diff --git a/pkg/front_end/testcases/ignore_function.dart b/pkg/front_end/testcases/ignore_function.dart
new file mode 100644
index 0000000..83c33eb
--- /dev/null
+++ b/pkg/front_end/testcases/ignore_function.dart
@@ -0,0 +1,21 @@
+// 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 "dart:core" as core;
+
+class A implements core.Function {
+  // No error here: core.Function is ignored.
+  operator ==(other) => false;
+}
+
+class B implements Function {
+  // Error here Object.== and Function.== disagree on the type of other.
+  operator ==(other) => false;
+}
+
+class Function {
+  core.bool operator ==(core.Object other) => false;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/inference/circular_reference_via_closures.dart b/pkg/front_end/testcases/inference/circular_reference_via_closures.dart
index b63fb9a..69efb53 100644
--- a/pkg/front_end/testcases/inference/circular_reference_via_closures.dart
+++ b/pkg/front_end/testcases/inference/circular_reference_via_closures.dart
@@ -5,7 +5,7 @@
 /*@testedFeatures=inference*/
 library test;
 
-var x = /*@returnType=invalid-type*/ () => y;
+var x = /*@returnType=() -> invalid-type*/ () => y;
 var y = /*@returnType=invalid-type*/ () => x;
 
 main() {}
diff --git a/pkg/front_end/testcases/inference/circular_reference_via_closures_initializer_types.dart b/pkg/front_end/testcases/inference/circular_reference_via_closures_initializer_types.dart
index b63fb9a..69efb53 100644
--- a/pkg/front_end/testcases/inference/circular_reference_via_closures_initializer_types.dart
+++ b/pkg/front_end/testcases/inference/circular_reference_via_closures_initializer_types.dart
@@ -5,7 +5,7 @@
 /*@testedFeatures=inference*/
 library test;
 
-var x = /*@returnType=invalid-type*/ () => y;
+var x = /*@returnType=() -> invalid-type*/ () => y;
 var y = /*@returnType=invalid-type*/ () => x;
 
 main() {}
diff --git a/pkg/front_end/testcases/inference/conflicting_fields.dart b/pkg/front_end/testcases/inference/conflicting_fields.dart
index 72edc67..8dacd55 100644
--- a/pkg/front_end/testcases/inference/conflicting_fields.dart
+++ b/pkg/front_end/testcases/inference/conflicting_fields.dart
@@ -17,6 +17,8 @@
 class B extends A implements I {
   get field1 => null;
   get field2 => null;
+  set field1(value) {}
+  set field2(value) {}
 }
 
 main() {}
diff --git a/pkg/front_end/testcases/inference/inconsistent_overrides.dart b/pkg/front_end/testcases/inference/inconsistent_overrides.dart
new file mode 100644
index 0000000..9030aea
--- /dev/null
+++ b/pkg/front_end/testcases/inference/inconsistent_overrides.dart
@@ -0,0 +1,27 @@
+// 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.
+
+library test;
+
+/*@testedFeatures=inference*/
+
+class A {
+  A f(A x, {A y}) {}
+  A g(A x, {A y}) {}
+  A h(A x, {A y}) {}
+}
+
+class B extends A implements I {
+  f(x, {y}) {}
+  g(x, {y}) {}
+  h(x, {y}) {}
+}
+
+class I {
+  I f(I x, {I y}) {}
+  A g(I x, {I y}) {}
+  A h(A x, {I y}) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/inference_new/dependency_only_if_generic_method.dart b/pkg/front_end/testcases/inference_new/dependency_only_if_generic_method.dart
index 5d9af14..cf441f7 100644
--- a/pkg/front_end/testcases/inference_new/dependency_only_if_generic_method.dart
+++ b/pkg/front_end/testcases/inference_new/dependency_only_if_generic_method.dart
@@ -15,8 +15,8 @@
 // There's a circularity between b and c because a.f is generic, so the type of
 // c is required to infer b, and vice versa.
 
-var b = /*@returnType=invalid-type*/ () =>
-    a. /*@typeArgs=invalid-type*/ /*@target=A::f*/ f(c);
+var b = /*@returnType=() -> invalid-type*/ () =>
+    a. /*@typeArgs=() -> invalid-type*/ /*@target=A::f*/ f(c);
 var c = /*@returnType=invalid-type*/ () =>
     a. /*@typeArgs=invalid-type*/ /*@target=A::f*/ f(b);
 
diff --git a/pkg/front_end/testcases/inference_new/infer_field_override_accessors.dart b/pkg/front_end/testcases/inference_new/infer_field_override_accessors.dart
new file mode 100644
index 0000000..d6f3096
--- /dev/null
+++ b/pkg/front_end/testcases/inference_new/infer_field_override_accessors.dart
@@ -0,0 +1,20 @@
+// 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.
+
+abstract class A {
+  A get x;
+  void set x(B value);
+
+  B get y;
+  void set y(A value);
+}
+
+abstract class B extends A {}
+
+class C extends B {
+  var x;
+  var y;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/inference_new/infer_instance_field_ref_circular.dart b/pkg/front_end/testcases/inference_new/infer_instance_field_ref_circular.dart
index 9ffd8ea..f24c3f1 100644
--- a/pkg/front_end/testcases/inference_new/infer_instance_field_ref_circular.dart
+++ b/pkg/front_end/testcases/inference_new/infer_instance_field_ref_circular.dart
@@ -8,12 +8,12 @@
 // In the code below, there is a circularity between A.b and x.
 
 class A {
-  var b = /*@returnType=invalid-type*/ () => x;
-  var c = /*@returnType=invalid-type*/ () => x;
+  var b = /*@returnType=() -> invalid-type*/ () => x;
+  var c = /*@returnType=() -> invalid-type*/ () => x;
 }
 
 var a = new A();
 var x = /*@returnType=invalid-type*/ () => a. /*@target=A::b*/ b;
-var y = /*@returnType=() -> invalid-type*/ () => a. /*@target=A::c*/ c;
+var y = /*@returnType=() -> () -> invalid-type*/ () => a. /*@target=A::c*/ c;
 
 main() {}
diff --git a/pkg/front_end/testcases/inference_new/strongly_connected_component.dart b/pkg/front_end/testcases/inference_new/strongly_connected_component.dart
index 788e92f..d378992 100644
--- a/pkg/front_end/testcases/inference_new/strongly_connected_component.dart
+++ b/pkg/front_end/testcases/inference_new/strongly_connected_component.dart
@@ -14,7 +14,7 @@
 // circularity, and for error recovery their type is set to `dynamic`.
 // Thereafter, z infers without problems.
 
-var x = /*@returnType=invalid-type*/ () => f() ? y : z;
+var x = /*@returnType=() -> invalid-type*/ () => f() ? y : z;
 var y = /*@returnType=invalid-type*/ () => x;
 var z = /*@returnType=invalid-type*/ () => x;
 
diff --git a/pkg/front_end/testcases/issue129167943.dart b/pkg/front_end/testcases/issue129167943.dart
new file mode 100644
index 0000000..c7560ea
--- /dev/null
+++ b/pkg/front_end/testcases/issue129167943.dart
@@ -0,0 +1,59 @@
+// 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.
+
+abstract class A {}
+
+abstract class B {
+  void foo(num x);
+}
+
+abstract class C implements B {
+  void foo(covariant int x);
+}
+
+abstract class D1 implements A, C, B {
+  void foo(covariant int x);
+}
+
+class D2 implements A, C, B {
+  void foo(covariant int x) {}
+}
+
+abstract class D3 implements A, C, B {}
+
+abstract class D4 implements A, C, B {
+  void foo(int x);
+}
+
+abstract class D5 implements A, C, B {
+  void foo(num x);
+}
+
+abstract class E {
+  void set foo(num x);
+}
+
+abstract class G implements E {
+  void set foo(covariant int x);
+}
+
+abstract class H1 implements A, E, G {
+  void set foo(covariant int x);
+}
+
+class H2 implements A, E, G {
+  void set foo(covariant int x) {}
+}
+
+abstract class H3 implements A, E, G {}
+
+abstract class H4 implements A, E, G {
+  void set foo(int x);
+}
+
+abstract class H5 implements A, E, G {
+  void set foo(num x);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/runtime_checks_new/abstract_override_becomes_forwarding_stub.dart b/pkg/front_end/testcases/runtime_checks_new/abstract_override_becomes_forwarding_stub.dart
index 4b4ea07..47824ee 100644
--- a/pkg/front_end/testcases/runtime_checks_new/abstract_override_becomes_forwarding_stub.dart
+++ b/pkg/front_end/testcases/runtime_checks_new/abstract_override_becomes_forwarding_stub.dart
@@ -14,7 +14,7 @@
 }
 
 class C extends B implements I<num> {
-  void /*@forwardingStub=semi-stub*/ f(num x);
+  void f(num x);
 }
 
 main() {}
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index c42599d..e6e64b1 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -107,6 +107,7 @@
 hello: TextSerializationFailure # Was: Pass
 having_part_with_part_and_annotation: TextSerializationFailure
 having_part_with_parts_and_annotation: TextSerializationFailure
+ignore_function: TypeCheckError
 illegal_named_function_expression: TextSerializationFailure # Was: Pass
 illegal_named_function_expression_scope: TextSerializationFailure # Was: Pass
 implicit_const_with_static_fields: TextSerializationFailure # Was: Pass
@@ -163,6 +164,7 @@
 inference/complex_predecrement: TextSerializationFailure # Was: Pass
 inference/conditional_lub: TextSerializationFailure # Was: Pass
 inference/conditional_upwards_inference: TextSerializationFailure # Was: Pass
+inference/conflicting_fields: ExpectationFileMismatch
 inference/conflicting_fields: TypeCheckError
 inference/conflicts_can_happen2: TypeCheckError
 inference/conflicts_can_happen: TypeCheckError
@@ -278,6 +280,7 @@
 inference/generic_methods_nested_generic_instantiation: TextSerializationFailure # Was: Pass
 inference/generic_methods_uses_greatest_lower_bound: TextSerializationFailure # Was: Pass
 inference/greatest_closure_multiple_params: TextSerializationFailure # Was: Pass
+inference/inconsistent_overrides: TypeCheckError
 inference/index_assign_operator_return_type: TextSerializationFailure # Was: Pass
 inference/index_assign_operator_return_type_2: TextSerializationFailure # Was: Pass
 inference/infer_accessor_from_later_inferred_field: TextSerializationFailure # Was: Pass
@@ -341,6 +344,7 @@
 inference/infer_local_function_referenced_before_declaration: TextSerializationFailure # Was: Pass
 inference/infer_local_function_return_type: TextSerializationFailure # Was: Pass
 inference/infer_method_function_typed: TextSerializationFailure # Was: Pass
+inference/infer_method_missing_params: ExpectationFileMismatch
 inference/infer_method_missing_params: TypeCheckError
 inference/infer_parameter_type_setter_from_field: TextSerializationFailure # Was: Pass
 inference/infer_parameter_type_setter_from_setter: TextSerializationFailure # Was: Pass
@@ -587,6 +591,7 @@
 inference_new/infer_assign_to_static: TextSerializationFailure # Was: Pass
 inference_new/infer_assign_to_static_upwards: TextSerializationFailure # Was: Pass
 inference_new/infer_field_getter_setter_mismatch: TypeCheckError
+inference_new/infer_field_override_accessors: TypeCheckError
 inference_new/infer_field_override_getter_overrides_setter: TypeCheckError
 inference_new/infer_field_override_setter_overrides_getter: TextSerializationFailure # Was: Pass
 inference_new/infer_instance_accessor_ref: TextSerializationFailure # Was: Pass
@@ -606,6 +611,7 @@
 inference_new/super_index_get: TextSerializationFailure # Was: Pass
 inference_new/super_index_get_substitution: TextSerializationFailure # Was: Pass
 inference_new/switch: TextSerializationFailure # Was: Pass
+inference_new/top_level_field_depends_on_multiple_inheritance: ExpectationFileMismatch
 inference_new/top_level_field_depends_on_multiple_inheritance: TextSerializationFailure # Was: Pass
 inference_new/unsafe_block_closure_inference_function_call_explicit_dynamic_param_via_expr2: TextSerializationFailure # Was: Pass
 inference_new/unsafe_block_closure_inference_function_call_explicit_type_param_via_expr2: TextSerializationFailure # Was: Pass
@@ -681,6 +687,7 @@
 invalid_cast: TextSerializationFailure # Was: Pass
 invalid_type: TypeCheckError
 invocations: TextSerializationFailure # Was: RuntimeError
+issue129167943: TextSerializationFailure
 issue34515: TextSerializationFailure
 issue34899: TypeCheckError
 issue35875: TextSerializationFailure
@@ -696,6 +703,7 @@
 minimum_int: TextSerializationFailure # Was: Pass
 missing_constructor: TextSerializationFailure # Was: Pass
 mixin: TextSerializationFailure # Was: Pass
+mixin_application_override: ExpectationFileMismatch
 mixin_application_override: TypeCheckError
 mixin_conflicts: TextSerializationFailure
 mixin_constructors_with_default_values: TextSerializationFailure # Was: Pass
@@ -967,6 +975,7 @@
 runtime_checks/dynamic_invocation: TextSerializationFailure # Was: Pass
 runtime_checks/dynamic_invocation_generic: TextSerializationFailure # Was: Pass
 runtime_checks/dynamic_invocation_of_getter: TextSerializationFailure # Was: Pass
+runtime_checks/field_forwarding_stub_generic_covariant: ExpectationFileMismatch
 runtime_checks/field_forwarding_stub_generic_covariant: TextSerializationFailure # Was: Pass
 runtime_checks/forwarding_stub_with_default_values: TextSerializationFailure # Was: Pass
 runtime_checks/forwarding_stub_with_non_covariant_param: TextSerializationFailure # Was: Pass
@@ -980,6 +989,7 @@
 runtime_checks/implicit_downcast_if: TextSerializationFailure # Was: Pass
 runtime_checks/implicit_downcast_not: TextSerializationFailure # Was: Pass
 runtime_checks/implicit_downcast_while: TextSerializationFailure # Was: Pass
+runtime_checks_new/abstract_override_becomes_forwarding_stub: ExpectationFileMismatch
 runtime_checks_new/abstract_override_becomes_forwarding_stub: TextSerializationFailure # Was: Pass
 runtime_checks_new/call_through_this: TextSerializationFailure # Was: Pass
 runtime_checks_new/contravariant_combiner: TextSerializationFailure # Was: Pass
@@ -989,12 +999,15 @@
 runtime_checks_new/contravariant_index_get: TextSerializationFailure # Was: Pass
 runtime_checks_new/derived_class_typed: TextSerializationFailure # Was: Pass
 runtime_checks_new/field_forwarding_stub_abstract_generic_covariant: TextSerializationFailure # Was: Pass
+runtime_checks_new/field_forwarding_stub_explicit_covariant: ExpectationFileMismatch
 runtime_checks_new/field_forwarding_stub_explicit_covariant: TextSerializationFailure # Was: Pass
 runtime_checks_new/for_in_call_kinds: TextSerializationFailure # Was: Pass
 runtime_checks_new/generic_covariance_based_on_inference: TextSerializationFailure # Was: Pass
 runtime_checks_new/implicit_downcast_field: TextSerializationFailure # Was: Pass
+runtime_checks_new/mixin_forwarding_stub_field: ExpectationFileMismatch
 runtime_checks_new/mixin_forwarding_stub_field: TypeCheckError
 runtime_checks_new/mixin_forwarding_stub_getter: TypeCheckError
+runtime_checks_new/mixin_forwarding_stub_setter: ExpectationFileMismatch
 runtime_checks_new/mixin_forwarding_stub_setter: TypeCheckError
 runtime_checks_new/stub_checked_via_target: TextSerializationFailure # Was: Pass
 runtime_checks_new/stub_from_interface_contravariant_from_class: TextSerializationFailure # Was: Pass
diff --git a/pkg/kernel/lib/class_hierarchy.dart b/pkg/kernel/lib/class_hierarchy.dart
index 474f907..ed156b1 100644
--- a/pkg/kernel/lib/class_hierarchy.dart
+++ b/pkg/kernel/lib/class_hierarchy.dart
@@ -247,14 +247,14 @@
   /// Compares members by name, using the same sort order as
   /// [getDeclaredMembers] and [getInterfaceMembers].
   static int compareMembers(Member first, Member second) {
-    return _compareNames(first.name, second.name);
+    return compareNames(first.name, second.name);
   }
 
   /// Compares names, using the same sort order as [getDeclaredMembers] and
   /// [getInterfaceMembers].
   ///
   /// This is an arbitrary as-fast-as-possible sorting criterion.
-  static int _compareNames(Name firstName, Name secondName) {
+  static int compareNames(Name firstName, Name secondName) {
     int firstHash = firstName.hashCode;
     int secondHash = secondName.hashCode;
     if (firstHash != secondHash) return firstHash - secondHash;
@@ -291,7 +291,7 @@
     while (low <= high) {
       int mid = low + ((high - low) >> 1);
       Member pivot = members[mid];
-      int comparison = _compareNames(name, pivot.name);
+      int comparison = compareNames(name, pivot.name);
       if (comparison < 0) {
         high = mid - 1;
       } else if (comparison > 0) {