Version 2.10.0-123.0.dev

Merge commit '291b2dffc0d427bdc348b3c717b6926d8c8493f3' into 'dev'
diff --git a/benchmarks/EventLoopLatencyJson/dart/EventLoopLatencyJson.dart b/benchmarks/EventLoopLatencyJson/dart/EventLoopLatencyJson.dart
index 4261b2b..7a8c5ee 100644
--- a/benchmarks/EventLoopLatencyJson/dart/EventLoopLatencyJson.dart
+++ b/benchmarks/EventLoopLatencyJson/dart/EventLoopLatencyJson.dart
@@ -11,8 +11,7 @@
   // Start GC pressure from helper isolate.
   final exitPort = ReceivePort();
   final exitFuture = exitPort.first;
-  final isolate =
-      await Isolate.spawn(runSplay, null, onExit: exitPort.sendPort);
+  final isolate = await Isolate.spawn(run, null, onExit: exitPort.sendPort);
 
   // Measure event loop latency.
   const tickDuration = const Duration(milliseconds: 1);
@@ -28,7 +27,7 @@
   stats.report('EventLoopLatencyJson');
 }
 
-void runSplay(dynamic msg) async {
+void run(dynamic msg) {
   while (true) {
     JsonRoundTripBenchmark().run();
   }
diff --git a/benchmarks/EventLoopLatencyJson/dart2/EventLoopLatencyJson.dart b/benchmarks/EventLoopLatencyJson/dart2/EventLoopLatencyJson.dart
index 4261b2b..7a8c5ee 100644
--- a/benchmarks/EventLoopLatencyJson/dart2/EventLoopLatencyJson.dart
+++ b/benchmarks/EventLoopLatencyJson/dart2/EventLoopLatencyJson.dart
@@ -11,8 +11,7 @@
   // Start GC pressure from helper isolate.
   final exitPort = ReceivePort();
   final exitFuture = exitPort.first;
-  final isolate =
-      await Isolate.spawn(runSplay, null, onExit: exitPort.sendPort);
+  final isolate = await Isolate.spawn(run, null, onExit: exitPort.sendPort);
 
   // Measure event loop latency.
   const tickDuration = const Duration(milliseconds: 1);
@@ -28,7 +27,7 @@
   stats.report('EventLoopLatencyJson');
 }
 
-void runSplay(dynamic msg) async {
+void run(dynamic msg) {
   while (true) {
     JsonRoundTripBenchmark().run();
   }
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index a189dc1..1a6eb5d 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -14,24 +14,19 @@
         DartType,
         DynamicType,
         Expression,
-        Field,
         FunctionNode,
         FunctionType,
         FutureOrType,
         InterfaceType,
-        InvalidType,
         Member,
         MethodInvocation,
         Name,
         Nullability,
         Procedure,
-        ProcedureKind,
         ReturnStatement,
         Supertype,
         ThisExpression,
         TypeParameter,
-        TypeParameterType,
-        VariableDeclaration,
         VoidType,
         getAsTypeArguments;
 
@@ -39,8 +34,6 @@
 
 import 'package:kernel/core_types.dart' show CoreTypes;
 
-import 'package:kernel/src/legacy_erasure.dart';
-
 import 'package:kernel/text/text_serialization_verifier.dart';
 
 import 'package:kernel/type_algebra.dart' show Substitution, substitute;
@@ -62,9 +55,9 @@
 
 import '../modifier.dart';
 
-import '../names.dart' show equalsName, noSuchMethodName;
+import '../names.dart' show noSuchMethodName;
 
-import '../problems.dart' show internalProblem, unhandled, unimplemented;
+import '../problems.dart' show internalProblem, unhandled;
 
 import '../scope.dart';
 
@@ -201,36 +194,9 @@
       bool isSetter,
       callback(Member declaredMember, Member interfaceMember, bool isSetter));
 
-  void checkOverride(
-      Types types,
-      Member declaredMember,
-      Member interfaceMember,
-      bool isSetter,
-      callback(Member declaredMember, Member interfaceMember, bool isSetter),
-      {bool isInterfaceCheck = false});
-
   bool hasUserDefinedNoSuchMethod(
       Class klass, ClassHierarchy hierarchy, Class objectClass);
 
-  /// Returns whether a covariant parameter was seen and more methods thus have
-  /// to be checked.
-  bool checkMethodOverride(Types types, Procedure declaredMember,
-      Procedure interfaceMember, bool isInterfaceCheck);
-
-  void checkGetterOverride(Types types, Member declaredMember,
-      Member interfaceMember, bool isInterfaceCheck);
-
-  /// Returns whether a covariant parameter was seen and more methods thus have
-  /// to be checked.
-  bool checkSetterOverride(Types types, Member declaredMember,
-      Member interfaceMember, bool isInterfaceCheck);
-
-  // When the overriding member is inherited, report the class containing
-  // the conflict as the main error.
-  void reportInvalidOverride(bool isInterfaceCheck, Member declaredMember,
-      Message message, int fileOffset, int length,
-      {List<LocatedMessage> context});
-
   void checkMixinApplication(ClassHierarchy hierarchy, CoreTypes coreTypes);
 
   // Computes the function type of a given redirection target. Returns [null] if
@@ -776,77 +742,6 @@
   }
 
   @override
-  void checkOverride(
-      Types types,
-      Member declaredMember,
-      Member interfaceMember,
-      bool isSetter,
-      callback(Member declaredMember, Member interfaceMember, bool isSetter),
-      {bool isInterfaceCheck = false}) {
-    if (declaredMember == interfaceMember) {
-      return;
-    }
-    if (declaredMember is Constructor || interfaceMember is Constructor) {
-      unimplemented(
-          "Constructor in override check.", declaredMember.fileOffset, fileUri);
-    }
-    if (declaredMember is Procedure && interfaceMember is Procedure) {
-      if (declaredMember.kind == interfaceMember.kind) {
-        if (declaredMember.kind == ProcedureKind.Method ||
-            declaredMember.kind == ProcedureKind.Operator) {
-          bool seenCovariant = checkMethodOverride(
-              types, declaredMember, interfaceMember, isInterfaceCheck);
-          if (seenCovariant) {
-            handleSeenCovariant(
-                types, declaredMember, interfaceMember, isSetter, callback);
-          }
-        } else if (declaredMember.kind == ProcedureKind.Getter) {
-          checkGetterOverride(
-              types, declaredMember, interfaceMember, isInterfaceCheck);
-        } else if (declaredMember.kind == ProcedureKind.Setter) {
-          bool seenCovariant = checkSetterOverride(
-              types, declaredMember, interfaceMember, isInterfaceCheck);
-          if (seenCovariant) {
-            handleSeenCovariant(
-                types, declaredMember, interfaceMember, isSetter, callback);
-          }
-        } else {
-          assert(
-              false,
-              "Unexpected procedure kind in override check: "
-              "${declaredMember.kind}");
-        }
-      }
-    } else {
-      bool declaredMemberHasGetter = declaredMember is Field ||
-          declaredMember is Procedure && declaredMember.isGetter;
-      bool interfaceMemberHasGetter = interfaceMember is Field ||
-          interfaceMember is Procedure && interfaceMember.isGetter;
-      bool declaredMemberHasSetter = (declaredMember is Field &&
-              !declaredMember.isFinal &&
-              !declaredMember.isConst) ||
-          declaredMember is Procedure && declaredMember.isSetter;
-      bool interfaceMemberHasSetter = (interfaceMember is Field &&
-              !interfaceMember.isFinal &&
-              !interfaceMember.isConst) ||
-          interfaceMember is Procedure && interfaceMember.isSetter;
-      if (declaredMemberHasGetter && interfaceMemberHasGetter) {
-        checkGetterOverride(
-            types, declaredMember, interfaceMember, isInterfaceCheck);
-      }
-      if (declaredMemberHasSetter && interfaceMemberHasSetter) {
-        bool seenCovariant = checkSetterOverride(
-            types, declaredMember, interfaceMember, isInterfaceCheck);
-        if (seenCovariant) {
-          handleSeenCovariant(
-              types, declaredMember, interfaceMember, isSetter, callback);
-        }
-      }
-    }
-    // TODO(ahe): Handle other cases: accessors, operators, and fields.
-  }
-
-  @override
   bool hasUserDefinedNoSuchMethod(
       Class klass, ClassHierarchy hierarchy, Class objectClass) {
     Member noSuchMethod = hierarchy.getDispatchTarget(klass, noSuchMethodName);
@@ -855,8 +750,11 @@
 
   void transformProcedureToNoSuchMethodForwarder(
       Member noSuchMethodInterface, KernelTarget target, Procedure procedure) {
-    String prefix =
-        procedure.isGetter ? 'get:' : procedure.isSetter ? 'set:' : '';
+    String prefix = procedure.isGetter
+        ? 'get:'
+        : procedure.isSetter
+            ? 'set:'
+            : '';
     String invocationName = prefix + procedure.name.name;
     if (procedure.isSetter) invocationName += '=';
     Expression invocation = target.backendTarget.instantiateInvocation(
@@ -892,524 +790,6 @@
     procedure.forwardingStubSuperTarget = null;
   }
 
-  Uri _getMemberUri(Member member) {
-    if (member is Field) return member.fileUri;
-    if (member is Procedure) return member.fileUri;
-    // Other member types won't be seen because constructors don't participate
-    // in override relationships
-    return unhandled('${member.runtimeType}', '_getMemberUri', -1, null);
-  }
-
-  Substitution _computeInterfaceSubstitution(
-      Types types,
-      Member declaredMember,
-      Member interfaceMember,
-      FunctionNode declaredFunction,
-      FunctionNode interfaceFunction,
-      bool isInterfaceCheck) {
-    Substitution interfaceSubstitution = Substitution.empty;
-    if (interfaceMember.enclosingClass.typeParameters.isNotEmpty) {
-      Class enclosingClass = interfaceMember.enclosingClass;
-      interfaceSubstitution = Substitution.fromPairs(
-          enclosingClass.typeParameters,
-          types.hierarchy
-              .getTypeArgumentsAsInstanceOf(thisType, enclosingClass));
-    }
-
-    if (declaredFunction?.typeParameters?.length !=
-        interfaceFunction?.typeParameters?.length) {
-      reportInvalidOverride(
-          isInterfaceCheck,
-          declaredMember,
-          templateOverrideTypeVariablesMismatch.withArguments(
-              "${declaredMember.enclosingClass.name}."
-                  "${declaredMember.name.name}",
-              "${interfaceMember.enclosingClass.name}."
-                  "${interfaceMember.name.name}"),
-          declaredMember.fileOffset,
-          noLength,
-          context: [
-            templateOverriddenMethodCause
-                .withArguments(interfaceMember.name.name)
-                .withLocation(_getMemberUri(interfaceMember),
-                    interfaceMember.fileOffset, noLength)
-          ]);
-    } else if (declaredFunction?.typeParameters != null) {
-      Map<TypeParameter, DartType> substitutionMap =
-          <TypeParameter, DartType>{};
-      for (int i = 0; i < declaredFunction.typeParameters.length; ++i) {
-        substitutionMap[interfaceFunction.typeParameters[i]] =
-            new TypeParameterType.forAlphaRenaming(
-                interfaceFunction.typeParameters[i],
-                declaredFunction.typeParameters[i]);
-      }
-      Substitution substitution = Substitution.fromMap(substitutionMap);
-      for (int i = 0; i < declaredFunction.typeParameters.length; ++i) {
-        TypeParameter declaredParameter = declaredFunction.typeParameters[i];
-        TypeParameter interfaceParameter = interfaceFunction.typeParameters[i];
-        if (!interfaceParameter.isGenericCovariantImpl) {
-          DartType declaredBound = declaredParameter.bound;
-          DartType interfaceBound = interfaceParameter.bound;
-          if (interfaceSubstitution != null) {
-            declaredBound = interfaceSubstitution.substituteType(declaredBound);
-            interfaceBound =
-                interfaceSubstitution.substituteType(interfaceBound);
-          }
-          DartType computedBound = substitution.substituteType(interfaceBound);
-          if (!library.isNonNullableByDefault) {
-            computedBound =
-                legacyErasure(types.hierarchy.coreTypes, computedBound);
-          }
-          if (!types
-              .performNullabilityAwareMutualSubtypesCheck(
-                  declaredBound, computedBound)
-              .isSubtypeWhenUsingNullabilities()) {
-            reportInvalidOverride(
-                isInterfaceCheck,
-                declaredMember,
-                templateOverrideTypeVariablesBoundMismatch.withArguments(
-                    declaredBound,
-                    declaredParameter.name,
-                    "${declaredMember.enclosingClass.name}."
-                        "${declaredMember.name.name}",
-                    computedBound,
-                    "${interfaceMember.enclosingClass.name}."
-                        "${interfaceMember.name.name}",
-                    library.isNonNullableByDefault),
-                declaredMember.fileOffset,
-                noLength,
-                context: [
-                  templateOverriddenMethodCause
-                      .withArguments(interfaceMember.name.name)
-                      .withLocation(_getMemberUri(interfaceMember),
-                          interfaceMember.fileOffset, noLength)
-                ]);
-          }
-        }
-      }
-      interfaceSubstitution =
-          Substitution.combine(interfaceSubstitution, substitution);
-    }
-    return interfaceSubstitution;
-  }
-
-  Substitution _computeDeclaredSubstitution(
-      Types types, Member declaredMember) {
-    Substitution declaredSubstitution = Substitution.empty;
-    if (declaredMember.enclosingClass.typeParameters.isNotEmpty) {
-      Class enclosingClass = declaredMember.enclosingClass;
-      declaredSubstitution = Substitution.fromPairs(
-          enclosingClass.typeParameters,
-          types.hierarchy
-              .getTypeArgumentsAsInstanceOf(thisType, enclosingClass));
-    }
-    return declaredSubstitution;
-  }
-
-  void _checkTypes(
-      Types types,
-      Substitution interfaceSubstitution,
-      Substitution declaredSubstitution,
-      Member declaredMember,
-      Member interfaceMember,
-      DartType declaredType,
-      DartType interfaceType,
-      bool isCovariant,
-      VariableDeclaration declaredParameter,
-      bool isInterfaceCheck,
-      {bool asIfDeclaredParameter = false}) {
-    if (interfaceSubstitution != null) {
-      interfaceType = interfaceSubstitution.substituteType(interfaceType);
-    }
-    if (declaredSubstitution != null) {
-      declaredType = declaredSubstitution.substituteType(declaredType);
-    }
-
-    if (!declaredMember.isNonNullableByDefault &&
-        interfaceMember.isNonNullableByDefault) {
-      interfaceType = legacyErasure(types.hierarchy.coreTypes, interfaceType);
-    }
-
-    bool inParameter = declaredParameter != null || asIfDeclaredParameter;
-    DartType subtype = inParameter ? interfaceType : declaredType;
-    DartType supertype = inParameter ? declaredType : interfaceType;
-
-    if (types.isSubtypeOf(
-        subtype, supertype, SubtypeCheckMode.withNullabilities)) {
-      // No problem--the proper subtyping relation is satisfied.
-    } else if (isCovariant &&
-        types.isSubtypeOf(
-            supertype, subtype, SubtypeCheckMode.withNullabilities)) {
-      // 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) {
-      // Don't report a problem as something else is wrong that has already
-      // been reported.
-    } else {
-      // Report an error.
-      bool isErrorInNnbdOptedOutMode = !types.isSubtypeOf(
-              subtype, supertype, SubtypeCheckMode.ignoringNullabilities) &&
-          (!isCovariant ||
-              !types.isSubtypeOf(
-                  supertype, subtype, SubtypeCheckMode.ignoringNullabilities));
-      if (isErrorInNnbdOptedOutMode || library.isNonNullableByDefault) {
-        String declaredMemberName = '${declaredMember.enclosingClass.name}'
-            '.${declaredMember.name.name}';
-        String interfaceMemberName = '${interfaceMember.enclosingClass.name}'
-            '.${interfaceMember.name.name}';
-        Message message;
-        int fileOffset;
-        if (declaredParameter == null) {
-          if (asIfDeclaredParameter) {
-            // Setter overridden by field
-            message = templateOverrideTypeMismatchSetter.withArguments(
-                declaredMemberName,
-                declaredType,
-                interfaceType,
-                interfaceMemberName,
-                library.isNonNullableByDefault);
-          } else {
-            message = templateOverrideTypeMismatchReturnType.withArguments(
-                declaredMemberName,
-                declaredType,
-                interfaceType,
-                interfaceMemberName,
-                library.isNonNullableByDefault);
-          }
-          fileOffset = declaredMember.fileOffset;
-        } else {
-          message = templateOverrideTypeMismatchParameter.withArguments(
-              declaredParameter.name,
-              declaredMemberName,
-              declaredType,
-              interfaceType,
-              interfaceMemberName,
-              library.isNonNullableByDefault);
-          fileOffset = declaredParameter.fileOffset;
-        }
-        reportInvalidOverride(
-            isInterfaceCheck, declaredMember, message, fileOffset, noLength,
-            context: [
-              templateOverriddenMethodCause
-                  .withArguments(interfaceMember.name.name)
-                  .withLocation(_getMemberUri(interfaceMember),
-                      interfaceMember.fileOffset, noLength)
-            ]);
-      }
-    }
-  }
-
-  @override
-  bool checkMethodOverride(Types types, Procedure declaredMember,
-      Procedure interfaceMember, bool isInterfaceCheck) {
-    assert(declaredMember.kind == interfaceMember.kind);
-    assert(declaredMember.kind == ProcedureKind.Method ||
-        declaredMember.kind == ProcedureKind.Operator);
-    bool seenCovariant = false;
-    FunctionNode declaredFunction = declaredMember.function;
-    FunctionNode interfaceFunction = interfaceMember.function;
-
-    Substitution interfaceSubstitution = _computeInterfaceSubstitution(
-        types,
-        declaredMember,
-        interfaceMember,
-        declaredFunction,
-        interfaceFunction,
-        isInterfaceCheck);
-
-    Substitution declaredSubstitution =
-        _computeDeclaredSubstitution(types, declaredMember);
-
-    _checkTypes(
-        types,
-        interfaceSubstitution,
-        declaredSubstitution,
-        declaredMember,
-        interfaceMember,
-        declaredFunction.returnType,
-        interfaceFunction.returnType,
-        false,
-        null,
-        isInterfaceCheck);
-    if (declaredFunction.positionalParameters.length <
-        interfaceFunction.positionalParameters.length) {
-      reportInvalidOverride(
-          isInterfaceCheck,
-          declaredMember,
-          templateOverrideFewerPositionalArguments.withArguments(
-              "${declaredMember.enclosingClass.name}."
-                  "${declaredMember.name.name}",
-              "${interfaceMember.enclosingClass.name}."
-                  "${interfaceMember.name.name}"),
-          declaredMember.fileOffset,
-          noLength,
-          context: [
-            templateOverriddenMethodCause
-                .withArguments(interfaceMember.name.name)
-                .withLocation(interfaceMember.fileUri,
-                    interfaceMember.fileOffset, noLength)
-          ]);
-    }
-    if (interfaceFunction.requiredParameterCount <
-        declaredFunction.requiredParameterCount) {
-      reportInvalidOverride(
-          isInterfaceCheck,
-          declaredMember,
-          templateOverrideMoreRequiredArguments.withArguments(
-              "${declaredMember.enclosingClass.name}."
-                  "${declaredMember.name.name}",
-              "${interfaceMember.enclosingClass.name}."
-                  "${interfaceMember.name.name}"),
-          declaredMember.fileOffset,
-          noLength,
-          context: [
-            templateOverriddenMethodCause
-                .withArguments(interfaceMember.name.name)
-                .withLocation(interfaceMember.fileUri,
-                    interfaceMember.fileOffset, noLength)
-          ]);
-    }
-    for (int i = 0;
-        i < declaredFunction.positionalParameters.length &&
-            i < interfaceFunction.positionalParameters.length;
-        i++) {
-      VariableDeclaration declaredParameter =
-          declaredFunction.positionalParameters[i];
-      VariableDeclaration interfaceParameter =
-          interfaceFunction.positionalParameters[i];
-      if (i == 0 &&
-          declaredMember.name == equalsName &&
-          declaredParameter.type ==
-              types.hierarchy.coreTypes.objectNonNullableRawType &&
-          interfaceParameter.type is DynamicType) {
-        // TODO(johnniwinther): Add check for opt-in overrides of operator ==.
-        // `operator ==` methods in opt-out classes have type
-        // `bool Function(dynamic)`.
-        continue;
-      }
-
-      _checkTypes(
-          types,
-          interfaceSubstitution,
-          declaredSubstitution,
-          declaredMember,
-          interfaceMember,
-          declaredParameter.type,
-          interfaceParameter.type,
-          declaredParameter.isCovariant || interfaceParameter.isCovariant,
-          declaredParameter,
-          isInterfaceCheck);
-      if (declaredParameter.isCovariant) seenCovariant = true;
-    }
-    if (declaredFunction.namedParameters.isEmpty &&
-        interfaceFunction.namedParameters.isEmpty) {
-      return seenCovariant;
-    }
-    if (declaredFunction.namedParameters.length <
-        interfaceFunction.namedParameters.length) {
-      reportInvalidOverride(
-          isInterfaceCheck,
-          declaredMember,
-          templateOverrideFewerNamedArguments.withArguments(
-              "${declaredMember.enclosingClass.name}."
-                  "${declaredMember.name.name}",
-              "${interfaceMember.enclosingClass.name}."
-                  "${interfaceMember.name.name}"),
-          declaredMember.fileOffset,
-          noLength,
-          context: [
-            templateOverriddenMethodCause
-                .withArguments(interfaceMember.name.name)
-                .withLocation(interfaceMember.fileUri,
-                    interfaceMember.fileOffset, noLength)
-          ]);
-    }
-    int compareNamedParameters(VariableDeclaration p0, VariableDeclaration p1) {
-      return p0.name.compareTo(p1.name);
-    }
-
-    List<VariableDeclaration> sortedFromDeclared =
-        new List.from(declaredFunction.namedParameters)
-          ..sort(compareNamedParameters);
-    List<VariableDeclaration> sortedFromInterface =
-        new List.from(interfaceFunction.namedParameters)
-          ..sort(compareNamedParameters);
-    Iterator<VariableDeclaration> declaredNamedParameters =
-        sortedFromDeclared.iterator;
-    Iterator<VariableDeclaration> interfaceNamedParameters =
-        sortedFromInterface.iterator;
-    outer:
-    while (declaredNamedParameters.moveNext() &&
-        interfaceNamedParameters.moveNext()) {
-      while (declaredNamedParameters.current.name !=
-          interfaceNamedParameters.current.name) {
-        if (!declaredNamedParameters.moveNext()) {
-          reportInvalidOverride(
-              isInterfaceCheck,
-              declaredMember,
-              templateOverrideMismatchNamedParameter.withArguments(
-                  "${declaredMember.enclosingClass.name}."
-                      "${declaredMember.name.name}",
-                  interfaceNamedParameters.current.name,
-                  "${interfaceMember.enclosingClass.name}."
-                      "${interfaceMember.name.name}"),
-              declaredMember.fileOffset,
-              noLength,
-              context: [
-                templateOverriddenMethodCause
-                    .withArguments(interfaceMember.name.name)
-                    .withLocation(interfaceMember.fileUri,
-                        interfaceMember.fileOffset, noLength)
-              ]);
-          break outer;
-        }
-      }
-      VariableDeclaration declaredParameter = declaredNamedParameters.current;
-      _checkTypes(
-          types,
-          interfaceSubstitution,
-          declaredSubstitution,
-          declaredMember,
-          interfaceMember,
-          declaredParameter.type,
-          interfaceNamedParameters.current.type,
-          declaredParameter.isCovariant,
-          declaredParameter,
-          isInterfaceCheck);
-      if (declaredMember.isNonNullableByDefault &&
-          declaredParameter.isRequired &&
-          interfaceMember.isNonNullableByDefault &&
-          !interfaceNamedParameters.current.isRequired) {
-        reportInvalidOverride(
-            isInterfaceCheck,
-            declaredMember,
-            templateOverrideMismatchRequiredNamedParameter.withArguments(
-                declaredParameter.name,
-                "${declaredMember.enclosingClass.name}."
-                    "${declaredMember.name.name}",
-                "${interfaceMember.enclosingClass.name}."
-                    "${interfaceMember.name.name}"),
-            declaredParameter.fileOffset,
-            noLength,
-            context: [
-              templateOverriddenMethodCause
-                  .withArguments(interfaceMember.name.name)
-                  .withLocation(_getMemberUri(interfaceMember),
-                      interfaceMember.fileOffset, noLength)
-            ]);
-      }
-      if (declaredParameter.isCovariant) seenCovariant = true;
-    }
-    return seenCovariant;
-  }
-
-  void checkGetterOverride(Types types, Member declaredMember,
-      Member interfaceMember, bool isInterfaceCheck) {
-    Substitution interfaceSubstitution = _computeInterfaceSubstitution(
-        types, declaredMember, interfaceMember, null, null, isInterfaceCheck);
-    Substitution declaredSubstitution =
-        _computeDeclaredSubstitution(types, declaredMember);
-    DartType declaredType = declaredMember.getterType;
-    DartType interfaceType = interfaceMember.getterType;
-    _checkTypes(
-        types,
-        interfaceSubstitution,
-        declaredSubstitution,
-        declaredMember,
-        interfaceMember,
-        declaredType,
-        interfaceType,
-        false,
-        null,
-        isInterfaceCheck);
-  }
-
-  @override
-  bool checkSetterOverride(Types types, Member declaredMember,
-      Member interfaceMember, bool isInterfaceCheck) {
-    Substitution interfaceSubstitution = _computeInterfaceSubstitution(
-        types, declaredMember, interfaceMember, null, null, isInterfaceCheck);
-    Substitution declaredSubstitution =
-        _computeDeclaredSubstitution(types, declaredMember);
-    DartType declaredType = declaredMember.setterType;
-    DartType interfaceType = interfaceMember.setterType;
-    VariableDeclaration declaredParameter =
-        declaredMember.function?.positionalParameters?.elementAt(0);
-    bool isCovariant = declaredParameter?.isCovariant ?? false;
-    if (!isCovariant && declaredMember is Field) {
-      isCovariant = declaredMember.isCovariant;
-    }
-    if (!isCovariant && interfaceMember is Field) {
-      isCovariant = interfaceMember.isCovariant;
-    }
-    _checkTypes(
-        types,
-        interfaceSubstitution,
-        declaredSubstitution,
-        declaredMember,
-        interfaceMember,
-        declaredType,
-        interfaceType,
-        isCovariant,
-        declaredParameter,
-        isInterfaceCheck,
-        asIfDeclaredParameter: true);
-    return isCovariant;
-  }
-
-  @override
-  void reportInvalidOverride(bool isInterfaceCheck, Member declaredMember,
-      Message message, int fileOffset, int length,
-      {List<LocatedMessage> context}) {
-    if (shouldOverrideProblemBeOverlooked(this)) {
-      return;
-    }
-
-    if (declaredMember.enclosingClass == cls) {
-      // Ordinary override
-      library.addProblem(message, fileOffset, length, declaredMember.fileUri,
-          context: context);
-    } else {
-      context = [
-        message.withLocation(declaredMember.fileUri, fileOffset, length),
-        ...?context
-      ];
-      if (isInterfaceCheck) {
-        // Interface check
-        library.addProblem(
-            templateInterfaceCheck.withArguments(
-                declaredMember.name.name, cls.name),
-            cls.fileOffset,
-            cls.name.length,
-            cls.fileUri,
-            context: context);
-      } else {
-        if (cls.isAnonymousMixin) {
-          // Implicit mixin application class
-          String baseName = cls.superclass.demangledName;
-          String mixinName = cls.mixedInClass.name;
-          int classNameLength = cls.nameAsMixinApplicationSubclass.length;
-          library.addProblem(
-              templateImplicitMixinOverride.withArguments(
-                  mixinName, baseName, declaredMember.name.name),
-              cls.fileOffset,
-              classNameLength,
-              cls.fileUri,
-              context: context);
-        } else {
-          // Named mixin application class
-          library.addProblem(
-              templateNamedMixinOverride.withArguments(
-                  cls.name, declaredMember.name.name),
-              cls.fileOffset,
-              cls.name.length,
-              cls.fileUri,
-              context: context);
-        }
-      }
-    }
-  }
-
   @override
   String get fullNameForErrors {
     return isMixinApplication && !isNamedMixinApplication
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 29e6bd3..5b3cbd7 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
@@ -64,6 +64,7 @@
 
 import '../scope.dart' show Scope;
 
+import '../source/source_class_builder.dart';
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 
 import '../source/source_loader.dart' show SourceLoader;
@@ -354,7 +355,7 @@
   }
 
   void registerOverrideCheck(
-      ClassBuilder classBuilder, ClassMember a, ClassMember b) {
+      SourceClassBuilder classBuilder, ClassMember a, ClassMember b) {
     _overrideChecks.add(new DelayedOverrideCheck(classBuilder, a, b));
   }
 
@@ -1719,14 +1720,17 @@
 
     void registerOverrideCheck(
         ClassMember member, ClassMember overriddenMember) {
-      if (overriddenMember.hasDeclarations &&
-          classBuilder == overriddenMember.classBuilder) {
-        for (int i = 0; i < overriddenMember.declarations.length; i++) {
+      if (classBuilder is SourceClassBuilder) {
+        if (overriddenMember.hasDeclarations &&
+            classBuilder == overriddenMember.classBuilder) {
+          for (int i = 0; i < overriddenMember.declarations.length; i++) {
+            hierarchy.registerOverrideCheck(
+                classBuilder, member, overriddenMember.declarations[i]);
+          }
+        } else {
           hierarchy.registerOverrideCheck(
-              classBuilder, member, overriddenMember.declarations[i]);
+              classBuilder, member, overriddenMember);
         }
-      } else {
-        hierarchy.registerOverrideCheck(classBuilder, member, overriddenMember);
       }
     }
 
@@ -1960,6 +1964,7 @@
 
       void checkMemberVsSetter(
           ClassMember member, ClassMember overriddenMember) {
+        if (classBuilder is! SourceClassBuilder) return;
         if (overriddenMember.isStatic) return;
         if (member == overriddenMember) return;
         if (member.isDuplicate || overriddenMember.isDuplicate) {
@@ -2572,7 +2577,7 @@
 }
 
 class DelayedOverrideCheck {
-  final ClassBuilder classBuilder;
+  final SourceClassBuilder classBuilder;
   final ClassMember declaredMember;
   final ClassMember overriddenMember;
 
@@ -2802,11 +2807,13 @@
       return combinedMemberSignatureResult;
     }
     if (!classBuilder.isAbstract) {
-      for (int i = 0; i < declarations.length; i++) {
-        if (concreteMember != declarations[i]) {
-          new DelayedOverrideCheck(
-                  classBuilder, concreteMember, declarations[i])
-              .check(hierarchy);
+      if (classBuilder is SourceClassBuilder) {
+        for (int i = 0; i < declarations.length; i++) {
+          if (concreteMember != declarations[i]) {
+            new DelayedOverrideCheck(
+                    classBuilder, concreteMember, declarations[i])
+                .check(hierarchy);
+          }
         }
       }
     }
@@ -3166,9 +3173,11 @@
       _isChecked = true;
       if (!classBuilder.isAbstract &&
           !hierarchy.nodes[classBuilder.cls].hasNoSuchMethod) {
-        new DelayedOverrideCheck(
-                classBuilder, concreteImplementation, abstractMember)
-            .check(hierarchy);
+        if (classBuilder is SourceClassBuilder) {
+          new DelayedOverrideCheck(
+                  classBuilder, concreteImplementation, abstractMember)
+              .check(hierarchy);
+        }
       }
 
       ProcedureKind kind = ProcedureKind.Method;
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 53b4d1b..9e55d9d21 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
@@ -9,6 +9,8 @@
 import 'package:kernel/clone.dart' show CloneProcedureWithoutBody;
 import 'package:kernel/reference_from_index.dart' show IndexedClass;
 import 'package:kernel/src/bounds_checks.dart';
+import 'package:kernel/src/legacy_erasure.dart';
+import 'package:kernel/src/types.dart' show Types;
 import 'package:kernel/type_algebra.dart' show Substitution;
 import 'package:kernel/type_algebra.dart' as type_algebra
     show getSubstitutionMap;
@@ -43,9 +45,9 @@
 import '../kernel/type_algorithms.dart'
     show Variance, computeTypeVariableBuilderVariance;
 
-import '../names.dart' show noSuchMethodName;
+import '../names.dart' show equalsName, noSuchMethodName;
 
-import '../problems.dart' show unexpected, unhandled;
+import '../problems.dart' show unexpected, unhandled, unimplemented;
 
 import '../scope.dart';
 
@@ -1129,4 +1131,595 @@
     }
     return count;
   }
+
+  void checkOverride(
+      Types types,
+      Member declaredMember,
+      Member interfaceMember,
+      bool isSetter,
+      callback(Member declaredMember, Member interfaceMember, bool isSetter),
+      {bool isInterfaceCheck = false}) {
+    if (declaredMember == interfaceMember) {
+      return;
+    }
+    if (declaredMember is Constructor || interfaceMember is Constructor) {
+      unimplemented(
+          "Constructor in override check.", declaredMember.fileOffset, fileUri);
+    }
+    if (declaredMember is Procedure && interfaceMember is Procedure) {
+      if (declaredMember.kind == interfaceMember.kind) {
+        if (declaredMember.kind == ProcedureKind.Method ||
+            declaredMember.kind == ProcedureKind.Operator) {
+          bool seenCovariant = checkMethodOverride(
+              types, declaredMember, interfaceMember, isInterfaceCheck);
+          if (seenCovariant) {
+            handleSeenCovariant(
+                types, declaredMember, interfaceMember, isSetter, callback);
+          }
+        } else if (declaredMember.kind == ProcedureKind.Getter) {
+          checkGetterOverride(
+              types, declaredMember, interfaceMember, isInterfaceCheck);
+        } else if (declaredMember.kind == ProcedureKind.Setter) {
+          bool seenCovariant = checkSetterOverride(
+              types, declaredMember, interfaceMember, isInterfaceCheck);
+          if (seenCovariant) {
+            handleSeenCovariant(
+                types, declaredMember, interfaceMember, isSetter, callback);
+          }
+        } else {
+          assert(
+              false,
+              "Unexpected procedure kind in override check: "
+              "${declaredMember.kind}");
+        }
+      }
+    } else {
+      bool declaredMemberHasGetter = declaredMember is Field ||
+          declaredMember is Procedure && declaredMember.isGetter;
+      bool interfaceMemberHasGetter = interfaceMember is Field ||
+          interfaceMember is Procedure && interfaceMember.isGetter;
+      bool declaredMemberHasSetter = (declaredMember is Field &&
+              !declaredMember.isFinal &&
+              !declaredMember.isConst) ||
+          declaredMember is Procedure && declaredMember.isSetter;
+      bool interfaceMemberHasSetter = (interfaceMember is Field &&
+              !interfaceMember.isFinal &&
+              !interfaceMember.isConst) ||
+          interfaceMember is Procedure && interfaceMember.isSetter;
+      if (declaredMemberHasGetter && interfaceMemberHasGetter) {
+        checkGetterOverride(
+            types, declaredMember, interfaceMember, isInterfaceCheck);
+      }
+      if (declaredMemberHasSetter && interfaceMemberHasSetter) {
+        bool seenCovariant = checkSetterOverride(
+            types, declaredMember, interfaceMember, isInterfaceCheck);
+        if (seenCovariant) {
+          handleSeenCovariant(
+              types, declaredMember, interfaceMember, isSetter, callback);
+        }
+      }
+    }
+    // TODO(ahe): Handle other cases: accessors, operators, and fields.
+  }
+
+  Uri _getMemberUri(Member member) {
+    if (member is Field) return member.fileUri;
+    if (member is Procedure) return member.fileUri;
+    // Other member types won't be seen because constructors don't participate
+    // in override relationships
+    return unhandled('${member.runtimeType}', '_getMemberUri', -1, null);
+  }
+
+  Substitution _computeInterfaceSubstitution(
+      Types types,
+      Member declaredMember,
+      Member interfaceMember,
+      FunctionNode declaredFunction,
+      FunctionNode interfaceFunction,
+      bool isInterfaceCheck) {
+    Substitution interfaceSubstitution = Substitution.empty;
+    if (interfaceMember.enclosingClass.typeParameters.isNotEmpty) {
+      Class enclosingClass = interfaceMember.enclosingClass;
+      interfaceSubstitution = Substitution.fromPairs(
+          enclosingClass.typeParameters,
+          types.hierarchy
+              .getTypeArgumentsAsInstanceOf(thisType, enclosingClass));
+    }
+
+    if (declaredFunction?.typeParameters?.length !=
+        interfaceFunction?.typeParameters?.length) {
+      reportInvalidOverride(
+          isInterfaceCheck,
+          declaredMember,
+          templateOverrideTypeVariablesMismatch.withArguments(
+              "${declaredMember.enclosingClass.name}."
+                  "${declaredMember.name.name}",
+              "${interfaceMember.enclosingClass.name}."
+                  "${interfaceMember.name.name}"),
+          declaredMember.fileOffset,
+          noLength,
+          context: [
+            templateOverriddenMethodCause
+                .withArguments(interfaceMember.name.name)
+                .withLocation(_getMemberUri(interfaceMember),
+                    interfaceMember.fileOffset, noLength)
+          ]);
+    } else if (declaredFunction?.typeParameters != null) {
+      Map<TypeParameter, DartType> substitutionMap =
+          <TypeParameter, DartType>{};
+      for (int i = 0; i < declaredFunction.typeParameters.length; ++i) {
+        substitutionMap[interfaceFunction.typeParameters[i]] =
+            new TypeParameterType.forAlphaRenaming(
+                interfaceFunction.typeParameters[i],
+                declaredFunction.typeParameters[i]);
+      }
+      Substitution substitution = Substitution.fromMap(substitutionMap);
+      for (int i = 0; i < declaredFunction.typeParameters.length; ++i) {
+        TypeParameter declaredParameter = declaredFunction.typeParameters[i];
+        TypeParameter interfaceParameter = interfaceFunction.typeParameters[i];
+        if (!interfaceParameter.isGenericCovariantImpl) {
+          DartType declaredBound = declaredParameter.bound;
+          DartType interfaceBound = interfaceParameter.bound;
+          if (interfaceSubstitution != null) {
+            declaredBound = interfaceSubstitution.substituteType(declaredBound);
+            interfaceBound =
+                interfaceSubstitution.substituteType(interfaceBound);
+          }
+          DartType computedBound = substitution.substituteType(interfaceBound);
+          if (!library.isNonNullableByDefault) {
+            computedBound =
+                legacyErasure(types.hierarchy.coreTypes, computedBound);
+          }
+          if (!types
+              .performNullabilityAwareMutualSubtypesCheck(
+                  declaredBound, computedBound)
+              .isSubtypeWhenUsingNullabilities()) {
+            reportInvalidOverride(
+                isInterfaceCheck,
+                declaredMember,
+                templateOverrideTypeVariablesBoundMismatch.withArguments(
+                    declaredBound,
+                    declaredParameter.name,
+                    "${declaredMember.enclosingClass.name}."
+                        "${declaredMember.name.name}",
+                    computedBound,
+                    "${interfaceMember.enclosingClass.name}."
+                        "${interfaceMember.name.name}",
+                    library.isNonNullableByDefault),
+                declaredMember.fileOffset,
+                noLength,
+                context: [
+                  templateOverriddenMethodCause
+                      .withArguments(interfaceMember.name.name)
+                      .withLocation(_getMemberUri(interfaceMember),
+                          interfaceMember.fileOffset, noLength)
+                ]);
+          }
+        }
+      }
+      interfaceSubstitution =
+          Substitution.combine(interfaceSubstitution, substitution);
+    }
+    return interfaceSubstitution;
+  }
+
+  Substitution _computeDeclaredSubstitution(
+      Types types, Member declaredMember) {
+    Substitution declaredSubstitution = Substitution.empty;
+    if (declaredMember.enclosingClass.typeParameters.isNotEmpty) {
+      Class enclosingClass = declaredMember.enclosingClass;
+      declaredSubstitution = Substitution.fromPairs(
+          enclosingClass.typeParameters,
+          types.hierarchy
+              .getTypeArgumentsAsInstanceOf(thisType, enclosingClass));
+    }
+    return declaredSubstitution;
+  }
+
+  void _checkTypes(
+      Types types,
+      Substitution interfaceSubstitution,
+      Substitution declaredSubstitution,
+      Member declaredMember,
+      Member interfaceMember,
+      DartType declaredType,
+      DartType interfaceType,
+      bool isCovariant,
+      VariableDeclaration declaredParameter,
+      bool isInterfaceCheck,
+      {bool asIfDeclaredParameter = false}) {
+    if (interfaceSubstitution != null) {
+      interfaceType = interfaceSubstitution.substituteType(interfaceType);
+    }
+    if (declaredSubstitution != null) {
+      declaredType = declaredSubstitution.substituteType(declaredType);
+    }
+
+    if (!declaredMember.isNonNullableByDefault &&
+        interfaceMember.isNonNullableByDefault) {
+      interfaceType = legacyErasure(types.hierarchy.coreTypes, interfaceType);
+    }
+
+    bool inParameter = declaredParameter != null || asIfDeclaredParameter;
+    DartType subtype = inParameter ? interfaceType : declaredType;
+    DartType supertype = inParameter ? declaredType : interfaceType;
+
+    if (types.isSubtypeOf(
+        subtype, supertype, SubtypeCheckMode.withNullabilities)) {
+      // No problem--the proper subtyping relation is satisfied.
+    } else if (isCovariant &&
+        types.isSubtypeOf(
+            supertype, subtype, SubtypeCheckMode.withNullabilities)) {
+      // 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) {
+      // Don't report a problem as something else is wrong that has already
+      // been reported.
+    } else {
+      // Report an error.
+      bool isErrorInNnbdOptedOutMode = !types.isSubtypeOf(
+              subtype, supertype, SubtypeCheckMode.ignoringNullabilities) &&
+          (!isCovariant ||
+              !types.isSubtypeOf(
+                  supertype, subtype, SubtypeCheckMode.ignoringNullabilities));
+      if (isErrorInNnbdOptedOutMode || library.isNonNullableByDefault) {
+        String declaredMemberName = '${declaredMember.enclosingClass.name}'
+            '.${declaredMember.name.name}';
+        String interfaceMemberName = '${interfaceMember.enclosingClass.name}'
+            '.${interfaceMember.name.name}';
+        Message message;
+        int fileOffset;
+        if (declaredParameter == null) {
+          if (asIfDeclaredParameter) {
+            // Setter overridden by field
+            message = templateOverrideTypeMismatchSetter.withArguments(
+                declaredMemberName,
+                declaredType,
+                interfaceType,
+                interfaceMemberName,
+                library.isNonNullableByDefault);
+          } else {
+            message = templateOverrideTypeMismatchReturnType.withArguments(
+                declaredMemberName,
+                declaredType,
+                interfaceType,
+                interfaceMemberName,
+                library.isNonNullableByDefault);
+          }
+          fileOffset = declaredMember.fileOffset;
+        } else {
+          message = templateOverrideTypeMismatchParameter.withArguments(
+              declaredParameter.name,
+              declaredMemberName,
+              declaredType,
+              interfaceType,
+              interfaceMemberName,
+              library.isNonNullableByDefault);
+          fileOffset = declaredParameter.fileOffset;
+        }
+        reportInvalidOverride(
+            isInterfaceCheck, declaredMember, message, fileOffset, noLength,
+            context: [
+              templateOverriddenMethodCause
+                  .withArguments(interfaceMember.name.name)
+                  .withLocation(_getMemberUri(interfaceMember),
+                      interfaceMember.fileOffset, noLength)
+            ]);
+      }
+    }
+  }
+
+  /// Returns whether a covariant parameter was seen and more methods thus have
+  /// to be checked.
+  bool checkMethodOverride(Types types, Procedure declaredMember,
+      Procedure interfaceMember, bool isInterfaceCheck) {
+    assert(declaredMember.kind == interfaceMember.kind);
+    assert(declaredMember.kind == ProcedureKind.Method ||
+        declaredMember.kind == ProcedureKind.Operator);
+    bool seenCovariant = false;
+    FunctionNode declaredFunction = declaredMember.function;
+    FunctionNode interfaceFunction = interfaceMember.function;
+
+    Substitution interfaceSubstitution = _computeInterfaceSubstitution(
+        types,
+        declaredMember,
+        interfaceMember,
+        declaredFunction,
+        interfaceFunction,
+        isInterfaceCheck);
+
+    Substitution declaredSubstitution =
+        _computeDeclaredSubstitution(types, declaredMember);
+
+    _checkTypes(
+        types,
+        interfaceSubstitution,
+        declaredSubstitution,
+        declaredMember,
+        interfaceMember,
+        declaredFunction.returnType,
+        interfaceFunction.returnType,
+        false,
+        null,
+        isInterfaceCheck);
+    if (declaredFunction.positionalParameters.length <
+        interfaceFunction.positionalParameters.length) {
+      reportInvalidOverride(
+          isInterfaceCheck,
+          declaredMember,
+          templateOverrideFewerPositionalArguments.withArguments(
+              "${declaredMember.enclosingClass.name}."
+                  "${declaredMember.name.name}",
+              "${interfaceMember.enclosingClass.name}."
+                  "${interfaceMember.name.name}"),
+          declaredMember.fileOffset,
+          noLength,
+          context: [
+            templateOverriddenMethodCause
+                .withArguments(interfaceMember.name.name)
+                .withLocation(interfaceMember.fileUri,
+                    interfaceMember.fileOffset, noLength)
+          ]);
+    }
+    if (interfaceFunction.requiredParameterCount <
+        declaredFunction.requiredParameterCount) {
+      reportInvalidOverride(
+          isInterfaceCheck,
+          declaredMember,
+          templateOverrideMoreRequiredArguments.withArguments(
+              "${declaredMember.enclosingClass.name}."
+                  "${declaredMember.name.name}",
+              "${interfaceMember.enclosingClass.name}."
+                  "${interfaceMember.name.name}"),
+          declaredMember.fileOffset,
+          noLength,
+          context: [
+            templateOverriddenMethodCause
+                .withArguments(interfaceMember.name.name)
+                .withLocation(interfaceMember.fileUri,
+                    interfaceMember.fileOffset, noLength)
+          ]);
+    }
+    for (int i = 0;
+        i < declaredFunction.positionalParameters.length &&
+            i < interfaceFunction.positionalParameters.length;
+        i++) {
+      VariableDeclaration declaredParameter =
+          declaredFunction.positionalParameters[i];
+      VariableDeclaration interfaceParameter =
+          interfaceFunction.positionalParameters[i];
+      if (i == 0 &&
+          declaredMember.name == equalsName &&
+          declaredParameter.type ==
+              types.hierarchy.coreTypes.objectNonNullableRawType &&
+          interfaceParameter.type is DynamicType) {
+        // TODO(johnniwinther): Add check for opt-in overrides of operator ==.
+        // `operator ==` methods in opt-out classes have type
+        // `bool Function(dynamic)`.
+        continue;
+      }
+
+      _checkTypes(
+          types,
+          interfaceSubstitution,
+          declaredSubstitution,
+          declaredMember,
+          interfaceMember,
+          declaredParameter.type,
+          interfaceParameter.type,
+          declaredParameter.isCovariant || interfaceParameter.isCovariant,
+          declaredParameter,
+          isInterfaceCheck);
+      if (declaredParameter.isCovariant) seenCovariant = true;
+    }
+    if (declaredFunction.namedParameters.isEmpty &&
+        interfaceFunction.namedParameters.isEmpty) {
+      return seenCovariant;
+    }
+    if (declaredFunction.namedParameters.length <
+        interfaceFunction.namedParameters.length) {
+      reportInvalidOverride(
+          isInterfaceCheck,
+          declaredMember,
+          templateOverrideFewerNamedArguments.withArguments(
+              "${declaredMember.enclosingClass.name}."
+                  "${declaredMember.name.name}",
+              "${interfaceMember.enclosingClass.name}."
+                  "${interfaceMember.name.name}"),
+          declaredMember.fileOffset,
+          noLength,
+          context: [
+            templateOverriddenMethodCause
+                .withArguments(interfaceMember.name.name)
+                .withLocation(interfaceMember.fileUri,
+                    interfaceMember.fileOffset, noLength)
+          ]);
+    }
+    int compareNamedParameters(VariableDeclaration p0, VariableDeclaration p1) {
+      return p0.name.compareTo(p1.name);
+    }
+
+    List<VariableDeclaration> sortedFromDeclared =
+        new List.from(declaredFunction.namedParameters)
+          ..sort(compareNamedParameters);
+    List<VariableDeclaration> sortedFromInterface =
+        new List.from(interfaceFunction.namedParameters)
+          ..sort(compareNamedParameters);
+    Iterator<VariableDeclaration> declaredNamedParameters =
+        sortedFromDeclared.iterator;
+    Iterator<VariableDeclaration> interfaceNamedParameters =
+        sortedFromInterface.iterator;
+    outer:
+    while (declaredNamedParameters.moveNext() &&
+        interfaceNamedParameters.moveNext()) {
+      while (declaredNamedParameters.current.name !=
+          interfaceNamedParameters.current.name) {
+        if (!declaredNamedParameters.moveNext()) {
+          reportInvalidOverride(
+              isInterfaceCheck,
+              declaredMember,
+              templateOverrideMismatchNamedParameter.withArguments(
+                  "${declaredMember.enclosingClass.name}."
+                      "${declaredMember.name.name}",
+                  interfaceNamedParameters.current.name,
+                  "${interfaceMember.enclosingClass.name}."
+                      "${interfaceMember.name.name}"),
+              declaredMember.fileOffset,
+              noLength,
+              context: [
+                templateOverriddenMethodCause
+                    .withArguments(interfaceMember.name.name)
+                    .withLocation(interfaceMember.fileUri,
+                        interfaceMember.fileOffset, noLength)
+              ]);
+          break outer;
+        }
+      }
+      VariableDeclaration declaredParameter = declaredNamedParameters.current;
+      _checkTypes(
+          types,
+          interfaceSubstitution,
+          declaredSubstitution,
+          declaredMember,
+          interfaceMember,
+          declaredParameter.type,
+          interfaceNamedParameters.current.type,
+          declaredParameter.isCovariant,
+          declaredParameter,
+          isInterfaceCheck);
+      if (declaredMember.isNonNullableByDefault &&
+          declaredParameter.isRequired &&
+          interfaceMember.isNonNullableByDefault &&
+          !interfaceNamedParameters.current.isRequired) {
+        reportInvalidOverride(
+            isInterfaceCheck,
+            declaredMember,
+            templateOverrideMismatchRequiredNamedParameter.withArguments(
+                declaredParameter.name,
+                "${declaredMember.enclosingClass.name}."
+                    "${declaredMember.name.name}",
+                "${interfaceMember.enclosingClass.name}."
+                    "${interfaceMember.name.name}"),
+            declaredParameter.fileOffset,
+            noLength,
+            context: [
+              templateOverriddenMethodCause
+                  .withArguments(interfaceMember.name.name)
+                  .withLocation(_getMemberUri(interfaceMember),
+                      interfaceMember.fileOffset, noLength)
+            ]);
+      }
+      if (declaredParameter.isCovariant) seenCovariant = true;
+    }
+    return seenCovariant;
+  }
+
+  void checkGetterOverride(Types types, Member declaredMember,
+      Member interfaceMember, bool isInterfaceCheck) {
+    Substitution interfaceSubstitution = _computeInterfaceSubstitution(
+        types, declaredMember, interfaceMember, null, null, isInterfaceCheck);
+    Substitution declaredSubstitution =
+        _computeDeclaredSubstitution(types, declaredMember);
+    DartType declaredType = declaredMember.getterType;
+    DartType interfaceType = interfaceMember.getterType;
+    _checkTypes(
+        types,
+        interfaceSubstitution,
+        declaredSubstitution,
+        declaredMember,
+        interfaceMember,
+        declaredType,
+        interfaceType,
+        false,
+        null,
+        isInterfaceCheck);
+  }
+
+  /// Returns whether a covariant parameter was seen and more methods thus have
+  /// to be checked.
+  bool checkSetterOverride(Types types, Member declaredMember,
+      Member interfaceMember, bool isInterfaceCheck) {
+    Substitution interfaceSubstitution = _computeInterfaceSubstitution(
+        types, declaredMember, interfaceMember, null, null, isInterfaceCheck);
+    Substitution declaredSubstitution =
+        _computeDeclaredSubstitution(types, declaredMember);
+    DartType declaredType = declaredMember.setterType;
+    DartType interfaceType = interfaceMember.setterType;
+    VariableDeclaration declaredParameter =
+        declaredMember.function?.positionalParameters?.elementAt(0);
+    bool isCovariant = declaredParameter?.isCovariant ?? false;
+    if (!isCovariant && declaredMember is Field) {
+      isCovariant = declaredMember.isCovariant;
+    }
+    if (!isCovariant && interfaceMember is Field) {
+      isCovariant = interfaceMember.isCovariant;
+    }
+    _checkTypes(
+        types,
+        interfaceSubstitution,
+        declaredSubstitution,
+        declaredMember,
+        interfaceMember,
+        declaredType,
+        interfaceType,
+        isCovariant,
+        declaredParameter,
+        isInterfaceCheck,
+        asIfDeclaredParameter: true);
+    return isCovariant;
+  }
+
+  // When the overriding member is inherited, report the class containing
+  // the conflict as the main error.
+  void reportInvalidOverride(bool isInterfaceCheck, Member declaredMember,
+      Message message, int fileOffset, int length,
+      {List<LocatedMessage> context}) {
+    if (shouldOverrideProblemBeOverlooked(this)) {
+      return;
+    }
+
+    if (declaredMember.enclosingClass == cls) {
+      // Ordinary override
+      library.addProblem(message, fileOffset, length, declaredMember.fileUri,
+          context: context);
+    } else {
+      context = [
+        message.withLocation(declaredMember.fileUri, fileOffset, length),
+        ...?context
+      ];
+      if (isInterfaceCheck) {
+        // Interface check
+        library.addProblem(
+            templateInterfaceCheck.withArguments(
+                declaredMember.name.name, cls.name),
+            cls.fileOffset,
+            cls.name.length,
+            cls.fileUri,
+            context: context);
+      } else {
+        if (cls.isAnonymousMixin) {
+          // Implicit mixin application class
+          String baseName = cls.superclass.demangledName;
+          String mixinName = cls.mixedInClass.name;
+          int classNameLength = cls.nameAsMixinApplicationSubclass.length;
+          library.addProblem(
+              templateImplicitMixinOverride.withArguments(
+                  mixinName, baseName, declaredMember.name.name),
+              cls.fileOffset,
+              classNameLength,
+              cls.fileUri,
+              context: context);
+        } else {
+          // Named mixin application class
+          library.addProblem(
+              templateNamedMixinOverride.withArguments(
+                  cls.name, declaredMember.name.name),
+              cls.fileOffset,
+              cls.name.length,
+              cls.fileUri,
+              context: context);
+        }
+      }
+    }
+  }
 }
diff --git a/pkg/front_end/testcases/value_class/empty.dart.strong.expect b/pkg/front_end/testcases/value_class/empty.dart.strong.expect
index 129465c..e659acf 100644
--- a/pkg/front_end/testcases/value_class/empty.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/empty.dart.strong.expect
@@ -13,6 +13,8 @@
     return other is self::EmptyClass;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///empty.dartEmptyClass".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::EmptyClass::•();
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/empty.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/empty.dart.strong.transformed.expect
index 129465c..e659acf 100644
--- a/pkg/front_end/testcases/value_class/empty.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/empty.dart.strong.transformed.expect
@@ -13,6 +13,8 @@
     return other is self::EmptyClass;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///empty.dartEmptyClass".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::EmptyClass::•();
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/empty.dart.weak.expect b/pkg/front_end/testcases/value_class/empty.dart.weak.expect
index 129465c..e659acf 100644
--- a/pkg/front_end/testcases/value_class/empty.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/empty.dart.weak.expect
@@ -13,6 +13,8 @@
     return other is self::EmptyClass;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///empty.dartEmptyClass".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::EmptyClass::•();
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/empty.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/empty.dart.weak.transformed.expect
index 129465c..e659acf 100644
--- a/pkg/front_end/testcases/value_class/empty.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/empty.dart.weak.transformed.expect
@@ -13,6 +13,8 @@
     return other is self::EmptyClass;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///empty.dartEmptyClass".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::EmptyClass::•();
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.expect b/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.expect
index c465cf0..6852df4 100644
--- a/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.expect
@@ -13,6 +13,8 @@
     return other is self::A;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::A::•();
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
@@ -42,6 +44,8 @@
     return other is self::F;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartF".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::F::•();
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.transformed.expect
index 93db2ab..27d97db 100644
--- a/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.transformed.expect
@@ -13,6 +13,8 @@
     return other is self::A;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::A::•();
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
@@ -37,6 +39,8 @@
     return other is self::A;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::A::•();
 }
 class F extends self::B implements self::C /*isEliminatedMixin*/  {
   synthetic constructor •() → self::F
@@ -46,6 +50,8 @@
     return other is self::F;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartF".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::F::•();
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.expect b/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.expect
index c465cf0..6852df4 100644
--- a/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.expect
@@ -13,6 +13,8 @@
     return other is self::A;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::A::•();
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
@@ -42,6 +44,8 @@
     return other is self::F;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartF".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::F::•();
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.transformed.expect
index 93db2ab..27d97db 100644
--- a/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.transformed.expect
@@ -13,6 +13,8 @@
     return other is self::A;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::A::•();
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
@@ -37,6 +39,8 @@
     return other is self::A;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::A::•();
 }
 class F extends self::B implements self::C /*isEliminatedMixin*/  {
   synthetic constructor •() → self::F
@@ -46,6 +50,8 @@
     return other is self::F;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartF".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::F::•();
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.expect b/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.expect
index 32fe546..ae9077e 100644
--- a/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.expect
@@ -21,6 +21,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_final_field_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.transformed.expect
index 32fe546..ae9077e 100644
--- a/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.transformed.expect
@@ -21,6 +21,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_final_field_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.expect b/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.expect
index 32fe546..ae9077e 100644
--- a/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.expect
@@ -21,6 +21,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_final_field_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.transformed.expect
index 32fe546..ae9077e 100644
--- a/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.transformed.expect
@@ -21,6 +21,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_final_field_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.expect b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.expect
index e0bd784..805f287 100644
--- a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.expect
@@ -22,6 +22,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_extends_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 class Cat extends self::Animal {
   synthetic constructor •() → self::Cat
diff --git a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.transformed.expect
index e0bd784..805f287 100644
--- a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.transformed.expect
@@ -22,6 +22,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_extends_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 class Cat extends self::Animal {
   synthetic constructor •() → self::Cat
diff --git a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.expect b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.expect
index e0bd784..805f287 100644
--- a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.expect
@@ -22,6 +22,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_extends_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 class Cat extends self::Animal {
   synthetic constructor •() → self::Cat
diff --git a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.transformed.expect
index e0bd784..805f287 100644
--- a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.transformed.expect
@@ -22,6 +22,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_extends_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 class Cat extends self::Animal {
   synthetic constructor •() → self::Cat
diff --git a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.expect b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.expect
index 67b715f..95373ed 100644
--- a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.expect
@@ -27,6 +27,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_implements_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 class Cat extends core::Object implements self::Animal {
   final field core::int numberOfLegs = null;
diff --git a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.transformed.expect
index 67b715f..95373ed 100644
--- a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.transformed.expect
@@ -27,6 +27,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_implements_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 class Cat extends core::Object implements self::Animal {
   final field core::int numberOfLegs = null;
diff --git a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.expect b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.expect
index 67b715f..95373ed 100644
--- a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.expect
@@ -27,6 +27,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_implements_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 class Cat extends core::Object implements self::Animal {
   final field core::int numberOfLegs = null;
diff --git a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.transformed.expect
index 67b715f..95373ed 100644
--- a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.transformed.expect
@@ -27,6 +27,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_implements_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 class Cat extends core::Object implements self::Animal {
   final field core::int numberOfLegs = null;
diff --git a/pkg/front_end/testcases/value_class/simple.dart.strong.expect b/pkg/front_end/testcases/value_class/simple.dart.strong.expect
index 218ec9f..862862f 100644
--- a/pkg/front_end/testcases/value_class/simple.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/simple.dart.strong.expect
@@ -43,6 +43,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///simple.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 static method main() → dynamic {
   self::Animal firstAnimal = invalid-expression "pkg/front_end/testcases/value_class/simple.dart:13:31: Error: No named parameter with the name 'numberOfLegs'.
diff --git a/pkg/front_end/testcases/value_class/simple.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/simple.dart.strong.transformed.expect
index 9845aaa..3213a78 100644
--- a/pkg/front_end/testcases/value_class/simple.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/simple.dart.strong.transformed.expect
@@ -43,6 +43,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///simple.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 static method main() → dynamic {
   self::Animal firstAnimal = invalid-expression "pkg/front_end/testcases/value_class/simple.dart:13:31: Error: No named parameter with the name 'numberOfLegs'.
diff --git a/pkg/front_end/testcases/value_class/simple.dart.weak.expect b/pkg/front_end/testcases/value_class/simple.dart.weak.expect
index 218ec9f..862862f 100644
--- a/pkg/front_end/testcases/value_class/simple.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/simple.dart.weak.expect
@@ -43,6 +43,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///simple.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 static method main() → dynamic {
   self::Animal firstAnimal = invalid-expression "pkg/front_end/testcases/value_class/simple.dart:13:31: Error: No named parameter with the name 'numberOfLegs'.
diff --git a/pkg/front_end/testcases/value_class/simple.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/simple.dart.weak.transformed.expect
index 9845aaa..3213a78 100644
--- a/pkg/front_end/testcases/value_class/simple.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/simple.dart.weak.transformed.expect
@@ -43,6 +43,8 @@
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///simple.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs}) → dynamic
+    return new self::Animal::•(numberOfLegs: numberOfLegs);
 }
 static method main() → dynamic {
   self::Animal firstAnimal = invalid-expression "pkg/front_end/testcases/value_class/simple.dart:13:31: Error: No named parameter with the name 'numberOfLegs'.
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.expect b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.expect
index d3224ed..d02e298 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.expect
@@ -49,6 +49,8 @@
     return other is self::Cat && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Animal::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_extends_non_value.dartCat".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs, core::int numberOfWhiskers}) → dynamic
+    return new self::Cat::•(numberOfLegs: numberOfLegs, numberOfWhiskers: numberOfWhiskers);
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_extends_non_value.dart:18:22: Error: No named parameter with the name 'numberOfLegs'.
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.transformed.expect
index bf869ee..6ed1828 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.transformed.expect
@@ -49,6 +49,8 @@
     return other is self::Cat && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Animal::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_extends_non_value.dartCat".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs, core::int numberOfWhiskers}) → dynamic
+    return new self::Cat::•(numberOfLegs: numberOfLegs, numberOfWhiskers: numberOfWhiskers);
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_extends_non_value.dart:18:22: Error: No named parameter with the name 'numberOfLegs'.
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.expect b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.expect
index d3224ed..d02e298 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.expect
@@ -49,6 +49,8 @@
     return other is self::Cat && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Animal::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_extends_non_value.dartCat".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs, core::int numberOfWhiskers}) → dynamic
+    return new self::Cat::•(numberOfLegs: numberOfLegs, numberOfWhiskers: numberOfWhiskers);
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_extends_non_value.dart:18:22: Error: No named parameter with the name 'numberOfLegs'.
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.transformed.expect
index bf869ee..6ed1828 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.transformed.expect
@@ -49,6 +49,8 @@
     return other is self::Cat && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Animal::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_extends_non_value.dartCat".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs, core::int numberOfWhiskers}) → dynamic
+    return new self::Cat::•(numberOfLegs: numberOfLegs, numberOfWhiskers: numberOfWhiskers);
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_extends_non_value.dart:18:22: Error: No named parameter with the name 'numberOfLegs'.
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.expect b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.expect
index b1b9373..240ae96 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.expect
@@ -31,6 +31,8 @@
     return other is self::Cat;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::Cat::•();
 }
 class Animal2 extends core::Object {
   final field core::int numberOfLegs = null;
@@ -46,6 +48,8 @@
     return other is self::Cat2;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat2".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::Cat2::•();
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.transformed.expect
index b1b9373..240ae96 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.transformed.expect
@@ -31,6 +31,8 @@
     return other is self::Cat;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::Cat::•();
 }
 class Animal2 extends core::Object {
   final field core::int numberOfLegs = null;
@@ -46,6 +48,8 @@
     return other is self::Cat2;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat2".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::Cat2::•();
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.expect b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.expect
index b1b9373..240ae96 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.expect
@@ -31,6 +31,8 @@
     return other is self::Cat;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::Cat::•();
 }
 class Animal2 extends core::Object {
   final field core::int numberOfLegs = null;
@@ -46,6 +48,8 @@
     return other is self::Cat2;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat2".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::Cat2::•();
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.transformed.expect
index b1b9373..240ae96 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.transformed.expect
@@ -31,6 +31,8 @@
     return other is self::Cat;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::Cat::•();
 }
 class Animal2 extends core::Object {
   final field core::int numberOfLegs = null;
@@ -46,6 +48,8 @@
     return other is self::Cat2;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat2".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::Cat2::•();
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.expect b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.expect
index a0f49ac..81644f5 100644
--- a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.expect
@@ -92,6 +92,8 @@
     return other is self::Cat && this.{self::Cat::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat".{core::String::hashCode}, this.{self::Cat::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs, core::int numberOfWhiskers}) → dynamic
+    return new self::Cat::•(numberOfLegs: numberOfLegs, numberOfWhiskers: numberOfWhiskers);
 }
 abstract class Animal2 extends core::Object {
   synthetic constructor •() → self::Animal2
@@ -109,6 +111,8 @@
     return other is self::Cat2 && this.{self::Cat2::numberOfLegs}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfLegs}) && this.{self::Cat2::numberOfWhiskers}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfWhiskers});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat2".{core::String::hashCode}, this.{self::Cat2::numberOfLegs}.{core::num::hashCode}), this.{self::Cat2::numberOfWhiskers}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs, core::int numberOfWhiskers}) → dynamic
+    return new self::Cat2::•(numberOfLegs: numberOfLegs, numberOfWhiskers: numberOfWhiskers);
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_implements_non_value.dart:30:22: Error: No named parameter with the name 'numberOfLegs'.
diff --git a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.transformed.expect
index e412416..bcf2a6e 100644
--- a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.transformed.expect
@@ -92,6 +92,8 @@
     return other is self::Cat && this.{self::Cat::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat".{core::String::hashCode}, this.{self::Cat::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs, core::int numberOfWhiskers}) → dynamic
+    return new self::Cat::•(numberOfLegs: numberOfLegs, numberOfWhiskers: numberOfWhiskers);
 }
 abstract class Animal2 extends core::Object {
   synthetic constructor •() → self::Animal2
@@ -109,6 +111,8 @@
     return other is self::Cat2 && this.{self::Cat2::numberOfLegs}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfLegs}) && this.{self::Cat2::numberOfWhiskers}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfWhiskers});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat2".{core::String::hashCode}, this.{self::Cat2::numberOfLegs}.{core::num::hashCode}), this.{self::Cat2::numberOfWhiskers}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs, core::int numberOfWhiskers}) → dynamic
+    return new self::Cat2::•(numberOfLegs: numberOfLegs, numberOfWhiskers: numberOfWhiskers);
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_implements_non_value.dart:30:22: Error: No named parameter with the name 'numberOfLegs'.
diff --git a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.expect b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.expect
index 7ff4c88..5c550c6 100644
--- a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.expect
@@ -92,6 +92,8 @@
     return other is self::Cat && this.{self::Cat::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat".{core::String::hashCode}, this.{self::Cat::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs, core::int numberOfWhiskers}) → dynamic
+    return new self::Cat::•(numberOfLegs: numberOfLegs, numberOfWhiskers: numberOfWhiskers);
 }
 abstract class Animal2 extends core::Object {
   synthetic constructor •() → self::Animal2
@@ -109,6 +111,8 @@
     return other is self::Cat2 && this.{self::Cat2::numberOfLegs}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfLegs}) && this.{self::Cat2::numberOfWhiskers}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfWhiskers});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat2".{core::String::hashCode}, this.{self::Cat2::numberOfLegs}.{core::num::hashCode}), this.{self::Cat2::numberOfWhiskers}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs, core::int numberOfWhiskers}) → dynamic
+    return new self::Cat2::•(numberOfLegs: numberOfLegs, numberOfWhiskers: numberOfWhiskers);
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_implements_non_value.dart:30:22: Error: No named parameter with the name 'numberOfLegs'.
diff --git a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.transformed.expect
index 939015f..455ce4f 100644
--- a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.transformed.expect
@@ -92,6 +92,8 @@
     return other is self::Cat && this.{self::Cat::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat".{core::String::hashCode}, this.{self::Cat::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs, core::int numberOfWhiskers}) → dynamic
+    return new self::Cat::•(numberOfLegs: numberOfLegs, numberOfWhiskers: numberOfWhiskers);
 }
 abstract class Animal2 extends core::Object {
   synthetic constructor •() → self::Animal2
@@ -109,6 +111,8 @@
     return other is self::Cat2 && this.{self::Cat2::numberOfLegs}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfLegs}) && this.{self::Cat2::numberOfWhiskers}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfWhiskers});
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat2".{core::String::hashCode}, this.{self::Cat2::numberOfLegs}.{core::num::hashCode}), this.{self::Cat2::numberOfWhiskers}.{core::num::hashCode}));
+  method /*isNullableByDefault*/ copyWith({core::int numberOfLegs, core::int numberOfWhiskers}) → dynamic
+    return new self::Cat2::•(numberOfLegs: numberOfLegs, numberOfWhiskers: numberOfWhiskers);
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_implements_non_value.dart:30:22: Error: No named parameter with the name 'numberOfLegs'.
diff --git a/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.expect b/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.expect
index 7e226a5..f0c520b 100644
--- a/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.expect
@@ -13,6 +13,8 @@
     return other is self::A;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::A::•();
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
diff --git a/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.transformed.expect
index 6ae17d2..4ea2146 100644
--- a/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.transformed.expect
@@ -13,6 +13,8 @@
     return other is self::A;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::A::•();
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
@@ -27,6 +29,8 @@
     return other is self::A;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::A::•();
 }
 class C extends self::_C&B&A {
   synthetic constructor •() → self::C
diff --git a/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.expect b/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.expect
index 7e226a5..f0c520b 100644
--- a/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.expect
@@ -13,6 +13,8 @@
     return other is self::A;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::A::•();
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
diff --git a/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.transformed.expect
index 6ae17d2..4ea2146 100644
--- a/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.transformed.expect
@@ -13,6 +13,8 @@
     return other is self::A;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::A::•();
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
@@ -27,6 +29,8 @@
     return other is self::A;
   get /*isNullableByDefault*/ hashCode() → core::int
     return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
+  method /*isNullableByDefault*/ copyWith() → dynamic
+    return new self::A::•();
 }
 class C extends self::_C&B&A {
   synthetic constructor •() → self::C
diff --git a/pkg/kernel/lib/transformations/value_class.dart b/pkg/kernel/lib/transformations/value_class.dart
index dc2d71a..dfea2de 100644
--- a/pkg/kernel/lib/transformations/value_class.dart
+++ b/pkg/kernel/lib/transformations/value_class.dart
@@ -54,19 +54,7 @@
 
 void transformValueClass(
     Class cls, CoreTypes coreTypes, ClassHierarchy hierarchy) {
-  addConstructor(cls, coreTypes);
-  addEqualsOperator(cls, coreTypes, hierarchy);
-  addHashCode(cls, coreTypes, hierarchy);
-  // addCopyWith(cls);
-}
-
-void addConstructor(Class cls, CoreTypes coreTypes) {
-  Constructor superConstructor = null;
-  for (Constructor constructor in cls.superclass.constructors) {
-    if (constructor.name.name == "") {
-      superConstructor = constructor;
-    }
-  }
+  List<VariableDeclaration> allVariables = queryAllInstanceVariables(cls);
   Constructor syntheticConstructor = null;
   for (Constructor constructor in cls.constructors) {
     if (constructor.isSynthetic) {
@@ -74,6 +62,21 @@
     }
   }
 
+  addConstructor(cls, coreTypes, syntheticConstructor);
+  addEqualsOperator(cls, coreTypes, hierarchy, allVariables.toList());
+  addHashCode(cls, coreTypes, hierarchy, allVariables.toList());
+  addCopyWith(
+      cls, coreTypes, hierarchy, allVariables.toList(), syntheticConstructor);
+}
+
+void addConstructor(
+    Class cls, CoreTypes coreTypes, Constructor syntheticConstructor) {
+  Constructor superConstructor = null;
+  for (Constructor constructor in cls.superclass.constructors) {
+    if (constructor.name.name == "") {
+      superConstructor = constructor;
+    }
+  }
   List<VariableDeclaration> superParameters = superConstructor
       .function.namedParameters
       .map<VariableDeclaration>((e) => VariableDeclaration(e.name, type: e.type)
@@ -117,8 +120,8 @@
   cls.annotations.removeAt(valueClassAnnotationIndex);
 }
 
-void addEqualsOperator(
-    Class cls, CoreTypes coreTypes, ClassHierarchy hierarchy) {
+void addEqualsOperator(Class cls, CoreTypes coreTypes, ClassHierarchy hierarchy,
+    List<VariableDeclaration> allVariables) {
   for (Procedure procedure in cls.procedures) {
     if (procedure.kind == ProcedureKind.Operator &&
         procedure.name.name == "==") {
@@ -131,21 +134,8 @@
       : coreTypes.boolLegacyRawType;
   DartType myType = coreTypes.thisInterfaceType(cls, Nullability.nonNullable);
 
-  Constructor superConstructor = null;
-  for (Constructor constructor in cls.superclass.constructors) {
-    if (constructor.name.name == "") {
-      superConstructor = constructor;
-    }
-  }
   VariableDeclaration other = VariableDeclaration("other",
       type: coreTypes.objectRawType(Nullability.nonNullable));
-  List<VariableDeclaration> allVariables = superConstructor
-      .function.namedParameters
-      .map<VariableDeclaration>(
-          (f) => VariableDeclaration(f.name, type: f.type))
-      .toList()
-        ..addAll(cls.fields.map<VariableDeclaration>(
-            (f) => VariableDeclaration(f.name.name, type: f.type)));
 
   Map<VariableDeclaration, Member> targetsEquals = new Map();
   Map<VariableDeclaration, Member> targets = new Map();
@@ -186,7 +176,8 @@
   cls.addMember(equalsOperator);
 }
 
-void addHashCode(Class cls, CoreTypes coreTypes, ClassHierarchy hierarchy) {
+void addHashCode(Class cls, CoreTypes coreTypes, ClassHierarchy hierarchy,
+    List<VariableDeclaration> allVariables) {
   for (Procedure procedure in cls.procedures) {
     if (procedure.kind == ProcedureKind.Getter &&
         procedure.name.name == "hashCode") {
@@ -198,13 +189,6 @@
       ? coreTypes.intNonNullableRawType
       : coreTypes.intLegacyRawType;
 
-  Constructor superConstructor = null;
-  for (Constructor constructor in cls.superclass.constructors) {
-    if (constructor.name.name == "") {
-      superConstructor = constructor;
-    }
-  }
-
   Procedure hashCombine, hashFinish;
   HashCombineMethodsScanner hashCombineMethodsScanner =
       new HashCombineMethodsScanner();
@@ -219,14 +203,6 @@
     }
   }
 
-  List<VariableDeclaration> allVariables = superConstructor
-      .function.namedParameters
-      .map<VariableDeclaration>(
-          (f) => VariableDeclaration(f.name, type: f.type))
-      .toList()
-        ..addAll(cls.fields.map<VariableDeclaration>(
-            (f) => VariableDeclaration(f.name.name, type: f.type)));
-
   Map<VariableDeclaration, Member> targetsHashcode = new Map();
   Map<VariableDeclaration, Member> targets = new Map();
   for (VariableDeclaration variable in allVariables) {
@@ -269,17 +245,21 @@
     ..fileOffset = cls.fileOffset);
 }
 
-/*
-void addCopyWith(Class cls) {
-  Map<String, VariableDeclaration> environment = Map.fromIterable(cls.fields,
-      key: (f) => f.name.name,
-      value: (f) => VariableDeclaration(f.name.name, type: f.type));
-
-  Constructor syntheticConstructor = null;
-  for (Constructor constructor in cls.constructors) {
-    if (constructor.isSynthetic) {
-      syntheticConstructor = constructor;
+void addCopyWith(Class cls, CoreTypes coreTypes, ClassHierarchy hierarchy,
+    List<VariableDeclaration> allVariables, Constructor syntheticConstructor) {
+  Map<VariableDeclaration, Member> targetsEquals = new Map();
+  Map<VariableDeclaration, Member> targets = new Map();
+  for (VariableDeclaration variable in allVariables) {
+    Member target = coreTypes.objectEquals;
+    Member targetEquals = coreTypes.objectEquals;
+    DartType fieldsType = variable.type;
+    if (fieldsType is InterfaceType) {
+      targetEquals =
+          hierarchy.getInterfaceMember(fieldsType.classNode, Name("=="));
+      target = hierarchy.getInterfaceMember(cls, Name(variable.name));
     }
+    targetsEquals[variable] = targetEquals;
+    targets[variable] = target;
   }
 
   cls.addMember(Procedure(
@@ -288,15 +268,26 @@
       FunctionNode(
           ReturnStatement(ConstructorInvocation(
               syntheticConstructor,
-              Arguments(cls.fields
-                  .map((f) => ConditionalExpression(
-                      MethodInvocation(VariableGet(environment[f.name.name]),
-                          Name('=='), Arguments([NullLiteral()])),
-                      PropertyGet(ThisExpression(), f.name, f),
-                      VariableGet(environment[f.name.name]),
-                      f.type))
-                  .toList()))),
-          namedParameters:
-              cls.fields.map((f) => environment[f.name.name]).toList())));
+              Arguments([],
+                  named: allVariables
+                      .map((f) => NamedExpression(f.name, VariableGet(f)))
+                      .toList()))),
+          namedParameters: allVariables),
+      fileUri: cls.fileUri)
+    ..fileOffset = cls.fileOffset);
 }
-*/
+
+List<VariableDeclaration> queryAllInstanceVariables(Class cls) {
+  Constructor superConstructor = null;
+  for (Constructor constructor in cls.superclass.constructors) {
+    if (constructor.name.name == "") {
+      superConstructor = constructor;
+    }
+  }
+  return superConstructor.function.namedParameters
+      .map<VariableDeclaration>(
+          (f) => VariableDeclaration(f.name, type: f.type))
+      .toList()
+        ..addAll(cls.fields.map<VariableDeclaration>(
+            (f) => VariableDeclaration(f.name.name, type: f.type)));
+}
diff --git a/tools/VERSION b/tools/VERSION
index 4f2e8ca..8d4e282 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 10
 PATCH 0
-PRERELEASE 122
+PRERELEASE 123
 PRERELEASE_PATCH 0
\ No newline at end of file