Version 2.17.0-6.0.dev

Merge commit '226d3c69f4de8ecd784a03c611d33d9a8e15badf' into 'dev'
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 c6b977b..f5454a5 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -10,8 +10,6 @@
         Constructor,
         DartType,
         DynamicType,
-        FunctionNode,
-        FunctionType,
         FutureOrType,
         InterfaceType,
         Member,
@@ -19,47 +17,27 @@
         NullType,
         Nullability,
         Supertype,
-        TreeNode,
-        TypeParameter,
         getAsTypeArguments;
-import 'package:kernel/class_hierarchy.dart'
-    show ClassHierarchy, ClassHierarchyMembers;
-import 'package:kernel/core_types.dart' show CoreTypes;
+import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
 import 'package:kernel/src/legacy_erasure.dart';
 import 'package:kernel/text/text_serialization_verifier.dart';
-import 'package:kernel/type_algebra.dart' show Substitution, substitute;
-import 'package:kernel/type_environment.dart'
-    show SubtypeCheckMode, TypeEnvironment;
 
 import '../fasta_codes.dart';
-import '../kernel/kernel_helper.dart';
-import '../kernel/redirecting_factory_body.dart' show RedirectingFactoryBody;
-import '../loader.dart';
 import '../modifier.dart';
-import '../names.dart' show noSuchMethodName;
 import '../problems.dart' show internalProblem, unhandled;
 import '../scope.dart';
-import '../source/source_factory_builder.dart';
-import '../source/source_library_builder.dart' show SourceLibraryBuilder;
-import '../source/source_loader.dart';
-import '../source/source_member_builder.dart';
 import '../type_inference/type_schema.dart' show UnknownType;
-import '../util/helpers.dart' show DelayedActionPerformer;
 import 'builder.dart';
-import 'constructor_reference_builder.dart';
 import 'declaration_builder.dart';
-import 'function_builder.dart';
 import 'library_builder.dart';
 import 'member_builder.dart';
 import 'metadata_builder.dart';
 import 'named_type_builder.dart';
-import 'never_type_declaration_builder.dart';
 import 'nullability_builder.dart';
 import 'type_alias_builder.dart';
 import 'type_builder.dart';
 import 'type_declaration_builder.dart';
 import 'type_variable_builder.dart';
-import 'void_type_declaration_builder.dart';
 
 abstract class ClassBuilder implements DeclarationBuilder {
   /// The type variables declared on a class, extension or mixin declaration.
@@ -100,12 +78,6 @@
 
   abstract TypeBuilder? mixedInTypeBuilder;
 
-  void buildOutlineExpressions(
-      SourceLibraryBuilder library,
-      ClassHierarchy classHierarchy,
-      List<DelayedActionPerformer> delayedActionPerformers,
-      List<SynthesizedFunctionNode> synthesizedFunctionNodes);
-
   /// Registers a constructor redirection for this class and returns true if
   /// this redirection gives rise to a cycle that has not been reported before.
   bool checkConstructorCyclic(String source, String target);
@@ -147,50 +119,6 @@
   Supertype buildMixedInType(
       LibraryBuilder library, List<TypeBuilder>? arguments);
 
-  void checkSupertypes(CoreTypes coreTypes);
-
-  void handleSeenCovariant(
-      ClassHierarchyMembers memberHierarchy,
-      Member interfaceMember,
-      bool isSetter,
-      callback(Member interfaceMember, bool isSetter));
-
-  bool hasUserDefinedNoSuchMethod(
-      Class klass, ClassHierarchy hierarchy, Class objectClass);
-
-  void checkMixinApplication(ClassHierarchy hierarchy, CoreTypes coreTypes);
-
-  // Computes the function type of a given redirection target. Returns [null] if
-  // the type of the target could not be computed.
-  FunctionType? computeRedirecteeType(
-      RedirectingFactoryBuilder factory, TypeEnvironment typeEnvironment);
-
-  String computeRedirecteeName(ConstructorReferenceBuilder redirectionTarget);
-
-  void checkRedirectingFactory(
-      RedirectingFactoryBuilder factory, TypeEnvironment typeEnvironment);
-
-  void checkRedirectingFactories(TypeEnvironment typeEnvironment);
-
-  /// Returns a map which maps the type variables of [superclass] to their
-  /// respective values as defined by the superclass clause of this class (and
-  /// its superclasses).
-  ///
-  /// It's assumed that [superclass] is a superclass of this class.
-  ///
-  /// For example, given:
-  ///
-  ///     class Box<T> {}
-  ///     class BeatBox extends Box<Beat> {}
-  ///     class Beat {}
-  ///
-  /// We have:
-  ///
-  ///     [[BeatBox]].getSubstitutionMap([[Box]]) -> {[[Box::T]]: Beat]]}.
-  ///
-  /// It's an error if [superclass] isn't a superclass.
-  Map<TypeParameter, DartType> getSubstitutionMap(Class superclass);
-
   /// Looks up the member by [name] on the class built by this class builder.
   ///
   /// If [isSetter] is `false`, only fields, methods, and getters with that name
@@ -306,31 +234,6 @@
     }
   }
 
-  @override
-  void buildOutlineExpressions(
-      SourceLibraryBuilder library,
-      ClassHierarchy classHierarchy,
-      List<DelayedActionPerformer> delayedActionPerformers,
-      List<SynthesizedFunctionNode> synthesizedFunctionNodes) {
-    void build(String ignore, Builder declaration) {
-      SourceMemberBuilder member = declaration as SourceMemberBuilder;
-      member.buildOutlineExpressions(library, classHierarchy,
-          delayedActionPerformers, synthesizedFunctionNodes);
-    }
-
-    MetadataBuilder.buildAnnotations(isPatch ? origin.cls : cls, metadata,
-        library, this, null, fileUri, library.scope);
-    if (typeVariables != null) {
-      for (int i = 0; i < typeVariables!.length; i++) {
-        typeVariables![i].buildOutlineExpressions(library, this, null,
-            classHierarchy, delayedActionPerformers, scope.parent!);
-      }
-    }
-
-    constructors.forEach(build);
-    scope.forEach(build);
-  }
-
   /// Registers a constructor redirection for this class and returns true if
   /// this redirection gives rise to a cycle that has not been reported before.
   @override
@@ -490,44 +393,6 @@
   }
 
   @override
-  int get typeVariablesCount => typeVariables?.length ?? 0;
-
-  @override
-  List<DartType> buildTypeArguments(
-      LibraryBuilder library, List<TypeBuilder>? arguments) {
-    if (arguments == null && typeVariables == null) {
-      return <DartType>[];
-    }
-
-    if (arguments == null && typeVariables != null) {
-      List<DartType> result = new List<DartType>.generate(typeVariables!.length,
-          (int i) => typeVariables![i].defaultType!.build(library),
-          growable: true);
-      if (library is SourceLibraryBuilder) {
-        library.inferredTypes.addAll(result);
-      }
-      return result;
-    }
-
-    if (arguments != null && arguments.length != typeVariablesCount) {
-      // That should be caught and reported as a compile-time error earlier.
-      return unhandled(
-          templateTypeArgumentMismatch
-              .withArguments(typeVariablesCount)
-              .problemMessage,
-          "buildTypeArguments",
-          -1,
-          null);
-    }
-
-    assert(arguments!.length == typeVariablesCount);
-    List<DartType> result = new List<DartType>.generate(
-        arguments!.length, (int i) => arguments[i].build(library),
-        growable: true);
-    return result;
-  }
-
-  @override
   DartType buildType(LibraryBuilder library,
       NullabilityBuilder nullabilityBuilder, List<TypeBuilder>? arguments) {
     return buildTypeWithBuiltArguments(
@@ -565,145 +430,6 @@
   }
 
   @override
-  void checkSupertypes(CoreTypes coreTypes) {
-    // This method determines whether the class (that's being built) its super
-    // class appears both in 'extends' and 'implements' clauses and whether any
-    // interface appears multiple times in the 'implements' clause.
-    // Moreover, it checks that `FutureOr` and `void` are not among the
-    // supertypes.
-
-    void fail(NamedTypeBuilder target, Message message,
-        TypeAliasBuilder? aliasBuilder) {
-      int nameOffset = target.nameOffset;
-      int nameLength = target.nameLength;
-      // TODO(eernst): nameOffset not fully implemented; use backup.
-      if (nameOffset == -1) {
-        nameOffset = this.charOffset;
-        nameLength = noLength;
-      }
-      if (aliasBuilder != null) {
-        addProblem(message, nameOffset, nameLength, context: [
-          messageTypedefCause.withLocation(
-              aliasBuilder.fileUri, aliasBuilder.charOffset, noLength),
-        ]);
-      } else {
-        addProblem(message, nameOffset, nameLength);
-      }
-    }
-
-    // Extract and check superclass (if it exists).
-    ClassBuilder? superClass;
-    TypeBuilder? superClassType = supertypeBuilder;
-    if (superClassType is NamedTypeBuilder) {
-      TypeDeclarationBuilder? decl = superClassType.declaration;
-      TypeAliasBuilder? aliasBuilder; // Non-null if a type alias is use.
-      if (decl is TypeAliasBuilder) {
-        aliasBuilder = decl;
-        decl = aliasBuilder.unaliasDeclaration(superClassType.arguments,
-            isUsedAsClass: true,
-            usedAsClassCharOffset: superClassType.charOffset,
-            usedAsClassFileUri: superClassType.fileUri);
-      }
-      // TODO(eernst): Should gather 'restricted supertype' checks in one place,
-      // e.g., dynamic/int/String/Null and more are checked elsewhere.
-      if (decl is VoidTypeDeclarationBuilder) {
-        fail(superClassType, messageExtendsVoid, aliasBuilder);
-      } else if (decl is NeverTypeDeclarationBuilder) {
-        fail(superClassType, messageExtendsNever, aliasBuilder);
-      } else if (decl is ClassBuilder) {
-        superClass = decl;
-      }
-    }
-    if (interfaceBuilders == null) return;
-
-    // Validate interfaces.
-    Map<ClassBuilder, int>? problems;
-    Map<ClassBuilder, int>? problemsOffsets;
-    Set<ClassBuilder> implemented = new Set<ClassBuilder>();
-    for (TypeBuilder type in interfaceBuilders!) {
-      if (type is NamedTypeBuilder) {
-        int? charOffset = type.charOffset;
-        TypeDeclarationBuilder? typeDeclaration = type.declaration;
-        TypeDeclarationBuilder? decl;
-        TypeAliasBuilder? aliasBuilder; // Non-null if a type alias is used.
-        if (typeDeclaration is TypeAliasBuilder) {
-          aliasBuilder = typeDeclaration;
-          decl = aliasBuilder.unaliasDeclaration(type.arguments,
-              isUsedAsClass: true,
-              usedAsClassCharOffset: type.charOffset,
-              usedAsClassFileUri: type.fileUri);
-        } else {
-          decl = typeDeclaration;
-        }
-        if (decl is ClassBuilder) {
-          ClassBuilder interface = decl;
-          if (superClass == interface) {
-            addProblem(
-                templateImplementsSuperClass.withArguments(interface.name),
-                this.charOffset,
-                noLength);
-          } else if (interface.cls.name == "FutureOr" &&
-              interface.cls.enclosingLibrary.importUri.scheme == "dart" &&
-              interface.cls.enclosingLibrary.importUri.path == "async") {
-            addProblem(messageImplementsFutureOr, this.charOffset, noLength);
-          } else if (implemented.contains(interface)) {
-            // Aggregate repetitions.
-            problems ??= <ClassBuilder, int>{};
-            problems[interface] ??= 0;
-            problems[interface] = problems[interface]! + 1;
-            problemsOffsets ??= <ClassBuilder, int>{};
-            problemsOffsets[interface] ??= charOffset ?? TreeNode.noOffset;
-          } else {
-            implemented.add(interface);
-          }
-        }
-        if (decl != superClass) {
-          // TODO(eernst): Have all 'restricted supertype' checks in one place.
-          if (decl is VoidTypeDeclarationBuilder) {
-            fail(type, messageImplementsVoid, aliasBuilder);
-          } else if (decl is NeverTypeDeclarationBuilder) {
-            fail(type, messageImplementsNever, aliasBuilder);
-          }
-        }
-      }
-    }
-    if (problems != null) {
-      problems.forEach((ClassBuilder interface, int repetitions) {
-        addProblem(
-            templateImplementsRepeated.withArguments(
-                interface.name, repetitions),
-            problemsOffsets![interface]!,
-            noLength);
-      });
-    }
-  }
-
-  @override
-  void handleSeenCovariant(
-      ClassHierarchyMembers memberHierarchy,
-      Member interfaceMember,
-      bool isSetter,
-      callback(Member interfaceMember, bool isSetter)) {
-    // When a parameter is covariant we have to check that we also
-    // override the same member in all parents.
-    for (Supertype supertype in interfaceMember.enclosingClass!.supers) {
-      Member? member = memberHierarchy.getInterfaceMember(
-          supertype.classNode, interfaceMember.name,
-          setter: isSetter);
-      if (member != null) {
-        callback(member, isSetter);
-      }
-    }
-  }
-
-  @override
-  bool hasUserDefinedNoSuchMethod(
-      Class klass, ClassHierarchy hierarchy, Class objectClass) {
-    Member? noSuchMethod = hierarchy.getDispatchTarget(klass, noSuchMethodName);
-    return noSuchMethod != null && noSuchMethod.enclosingClass != objectClass;
-  }
-
-  @override
   String get fullNameForErrors {
     return isMixinApplication && !isNamedMixinApplication
         ? "${supertypeBuilder!.fullNameForErrors} with "
@@ -712,292 +438,6 @@
   }
 
   @override
-  void checkMixinApplication(ClassHierarchy hierarchy, CoreTypes coreTypes) {
-    TypeEnvironment typeEnvironment = new TypeEnvironment(coreTypes, hierarchy);
-    // A mixin declaration can only be applied to a class that implements all
-    // the declaration's superclass constraints.
-    InterfaceType supertype = cls.supertype!.asInterfaceType;
-    Substitution substitution = Substitution.fromSupertype(cls.mixedInType!);
-    for (Supertype constraint in cls.mixedInClass!.superclassConstraints()) {
-      InterfaceType requiredInterface =
-          substitution.substituteSupertype(constraint).asInterfaceType;
-      InterfaceType? implementedInterface = hierarchy.getTypeAsInstanceOf(
-          supertype, requiredInterface.classNode, library.library);
-      if (implementedInterface == null ||
-          !typeEnvironment.areMutualSubtypes(
-              implementedInterface,
-              requiredInterface,
-              library.isNonNullableByDefault
-                  ? SubtypeCheckMode.withNullabilities
-                  : SubtypeCheckMode.ignoringNullabilities)) {
-        library.addProblem(
-            templateMixinApplicationIncompatibleSupertype.withArguments(
-                supertype,
-                requiredInterface,
-                cls.mixedInType!.asInterfaceType,
-                library.isNonNullableByDefault),
-            cls.fileOffset,
-            noLength,
-            cls.fileUri);
-      }
-    }
-  }
-
-  @override
-  FunctionType? computeRedirecteeType(
-      RedirectingFactoryBuilder factory, TypeEnvironment typeEnvironment) {
-    ConstructorReferenceBuilder redirectionTarget = factory.redirectionTarget;
-    Builder? targetBuilder = redirectionTarget.target;
-    FunctionNode targetNode;
-    if (targetBuilder == null) return null;
-    if (targetBuilder is FunctionBuilder) {
-      targetNode = targetBuilder.function;
-    } else if (targetBuilder is AmbiguousBuilder) {
-      // Multiple definitions with the same name: An error has already been
-      // issued.
-      // TODO(http://dartbug.com/35294): Unfortunate error; see also
-      // https://dart-review.googlesource.com/c/sdk/+/85390/.
-      return null;
-    } else {
-      unhandled("${redirectionTarget.target}", "computeRedirecteeType",
-          charOffset, fileUri);
-    }
-
-    List<DartType>? typeArguments = factory.getTypeArguments();
-    FunctionType targetFunctionType =
-        targetNode.computeFunctionType(library.nonNullable);
-    if (typeArguments != null &&
-        targetFunctionType.typeParameters.length != typeArguments.length) {
-      addProblemForRedirectingFactory(
-          factory,
-          templateTypeArgumentMismatch
-              .withArguments(targetFunctionType.typeParameters.length),
-          redirectionTarget.charOffset,
-          noLength);
-      return null;
-    }
-
-    // Compute the substitution of the target class type parameters if
-    // [redirectionTarget] has any type arguments.
-    Substitution? substitution;
-    bool hasProblem = false;
-    if (typeArguments != null && typeArguments.length > 0) {
-      substitution = Substitution.fromPairs(
-          targetFunctionType.typeParameters, typeArguments);
-      for (int i = 0; i < targetFunctionType.typeParameters.length; i++) {
-        TypeParameter typeParameter = targetFunctionType.typeParameters[i];
-        DartType typeParameterBound =
-            substitution.substituteType(typeParameter.bound);
-        DartType typeArgument = typeArguments[i];
-        // Check whether the [typeArgument] respects the bounds of
-        // [typeParameter].
-        Loader loader = library.loader;
-        if (!typeEnvironment.isSubtypeOf(typeArgument, typeParameterBound,
-            SubtypeCheckMode.ignoringNullabilities)) {
-          addProblemForRedirectingFactory(
-              factory,
-              templateRedirectingFactoryIncompatibleTypeArgument.withArguments(
-                  typeArgument,
-                  typeParameterBound,
-                  library.isNonNullableByDefault),
-              redirectionTarget.charOffset,
-              noLength);
-          hasProblem = true;
-        } else if (library.isNonNullableByDefault && loader is SourceLoader) {
-          if (!typeEnvironment.isSubtypeOf(typeArgument, typeParameterBound,
-              SubtypeCheckMode.withNullabilities)) {
-            addProblemForRedirectingFactory(
-                factory,
-                templateRedirectingFactoryIncompatibleTypeArgument
-                    .withArguments(typeArgument, typeParameterBound,
-                        library.isNonNullableByDefault),
-                redirectionTarget.charOffset,
-                noLength);
-            hasProblem = true;
-          }
-        }
-      }
-    } else if (typeArguments == null &&
-        targetFunctionType.typeParameters.length > 0) {
-      // TODO(hillerstrom): In this case, we need to perform type inference on
-      // the redirectee to obtain actual type arguments which would allow the
-      // following program to type check:
-      //
-      //    class A<T> {
-      //       factory A() = B;
-      //    }
-      //    class B<T> implements A<T> {
-      //       B();
-      //    }
-      //
-      return null;
-    }
-
-    // Substitute if necessary.
-    targetFunctionType = substitution == null
-        ? targetFunctionType
-        : (substitution.substituteType(targetFunctionType.withoutTypeParameters)
-            as FunctionType);
-
-    return hasProblem ? null : targetFunctionType;
-  }
-
-  @override
-  String computeRedirecteeName(ConstructorReferenceBuilder redirectionTarget) {
-    String targetName = redirectionTarget.fullNameForErrors;
-    if (targetName == "") {
-      return redirectionTarget.target!.parent!.fullNameForErrors;
-    } else {
-      return targetName;
-    }
-  }
-
-  bool _isCyclicRedirectingFactory(RedirectingFactoryBuilder factory) {
-    // We use the [tortoise and hare algorithm]
-    // (https://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare) to
-    // handle cycles.
-    Builder? tortoise = factory;
-    Builder? hare = factory.redirectionTarget.target;
-    if (hare == factory) {
-      return true;
-    }
-    while (tortoise != hare) {
-      // Hare moves 2 steps forward.
-      if (hare is! RedirectingFactoryBuilder) {
-        return false;
-      }
-      hare = hare.redirectionTarget.target;
-      if (hare == factory) {
-        return true;
-      }
-      if (hare is! RedirectingFactoryBuilder) {
-        return false;
-      }
-      hare = hare.redirectionTarget.target;
-      if (hare == factory) {
-        return true;
-      }
-      // Tortoise moves one step forward. No need to test type of tortoise
-      // as it follows hare which already checked types.
-      tortoise =
-          (tortoise as RedirectingFactoryBuilder).redirectionTarget.target;
-    }
-    // Cycle found, but original factory doesn't belong to a cycle.
-    return false;
-  }
-
-  void addProblemForRedirectingFactory(RedirectingFactoryBuilder factory,
-      Message message, int charOffset, int length) {
-    addProblem(message, charOffset, length);
-    String text = library.loader.target.context
-        .format(
-            message.withLocation(fileUri, charOffset, length), Severity.error)
-        .plain;
-    factory.body = new RedirectingFactoryBody.error(text);
-  }
-
-  @override
-  void checkRedirectingFactory(
-      RedirectingFactoryBuilder factory, TypeEnvironment typeEnvironment) {
-    // Check that factory declaration is not cyclic.
-    if (_isCyclicRedirectingFactory(factory)) {
-      addProblemForRedirectingFactory(
-          factory,
-          templateCyclicRedirectingFactoryConstructors
-              .withArguments("${factory.member.enclosingClass!.name}"
-                  "${factory.name == '' ? '' : '.${factory.name}'}"),
-          factory.charOffset,
-          noLength);
-      return;
-    }
-
-    // The factory type cannot contain any type parameters other than those of
-    // its enclosing class, because constructors cannot specify type parameters
-    // of their own.
-    FunctionType factoryType = factory.function
-        .computeThisFunctionType(library.nonNullable)
-        .withoutTypeParameters;
-    FunctionType? redirecteeType =
-        computeRedirecteeType(factory, typeEnvironment);
-
-    // TODO(hillerstrom): It would be preferable to know whether a failure
-    // happened during [_computeRedirecteeType].
-    if (redirecteeType == null) {
-      return;
-    }
-
-    // Check whether [redirecteeType] <: [factoryType].
-    Loader loader = library.loader;
-    if (!typeEnvironment.isSubtypeOf(
-        redirecteeType, factoryType, SubtypeCheckMode.ignoringNullabilities)) {
-      addProblemForRedirectingFactory(
-          factory,
-          templateIncompatibleRedirecteeFunctionType.withArguments(
-              redirecteeType, factoryType, library.isNonNullableByDefault),
-          factory.redirectionTarget.charOffset,
-          noLength);
-    } else if (library.isNonNullableByDefault && loader is SourceLoader) {
-      if (!typeEnvironment.isSubtypeOf(
-          redirecteeType, factoryType, SubtypeCheckMode.withNullabilities)) {
-        addProblemForRedirectingFactory(
-            factory,
-            templateIncompatibleRedirecteeFunctionType.withArguments(
-                redirecteeType, factoryType, library.isNonNullableByDefault),
-            factory.redirectionTarget.charOffset,
-            noLength);
-      }
-    }
-  }
-
-  @override
-  void checkRedirectingFactories(TypeEnvironment typeEnvironment) {
-    Map<String, MemberBuilder> constructors = this.constructors.local;
-    for (Builder? constructor in constructors.values) {
-      do {
-        if (constructor is RedirectingFactoryBuilder) {
-          checkRedirectingFactory(constructor, typeEnvironment);
-        }
-        constructor = constructor!.next;
-      } while (constructor != null);
-    }
-  }
-
-  @override
-  Map<TypeParameter, DartType> getSubstitutionMap(Class superclass) {
-    Supertype? supertype = cls.supertype;
-    Map<TypeParameter, DartType> substitutionMap = <TypeParameter, DartType>{};
-    List<DartType> arguments;
-    List<TypeParameter> variables;
-    Class? classNode;
-
-    while (classNode != superclass) {
-      classNode = supertype!.classNode;
-      arguments = supertype.typeArguments;
-      variables = classNode.typeParameters;
-      supertype = classNode.supertype;
-      if (variables.isNotEmpty) {
-        Map<TypeParameter, DartType> directSubstitutionMap =
-            <TypeParameter, DartType>{};
-        for (int i = 0; i < variables.length; i++) {
-          DartType argument =
-              i < arguments.length ? arguments[i] : const DynamicType();
-          // ignore: unnecessary_null_comparison
-          if (substitutionMap != null) {
-            // TODO(ahe): Investigate if requiring the caller to use
-            // `substituteDeep` from `package:kernel/type_algebra.dart` instead
-            // of `substitute` is faster. If so, we can simply this code.
-            argument = substitute(argument, substitutionMap);
-          }
-          directSubstitutionMap[variables[i]] = argument;
-        }
-        substitutionMap = directSubstitutionMap;
-      }
-    }
-
-    return substitutionMap;
-  }
-
-  @override
   Member? lookupInstanceMember(ClassHierarchy hierarchy, Name name,
       {bool isSetter: false, bool isSuper: false}) {
     Class? instanceClass = cls;
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 e645c59..3faf679 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
@@ -7,6 +7,7 @@
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart'
     show ClassHierarchy, ClassHierarchyMembers;
+import 'package:kernel/core_types.dart';
 import 'package:kernel/reference_from_index.dart' show IndexedClass;
 import 'package:kernel/src/bounds_checks.dart';
 import 'package:kernel/src/legacy_erasure.dart';
@@ -16,6 +17,7 @@
         FreshTypeParameters,
         Substitution,
         getFreshTypeParameters,
+        substitute,
         updateBoundNullabilities;
 import 'package:kernel/type_environment.dart';
 
@@ -28,17 +30,20 @@
 import '../builder/member_builder.dart';
 import '../builder/metadata_builder.dart';
 import '../builder/named_type_builder.dart';
+import '../builder/never_type_declaration_builder.dart';
 import '../builder/nullability_builder.dart';
 import '../builder/type_alias_builder.dart';
 import '../builder/type_builder.dart';
 import '../builder/type_declaration_builder.dart';
 import '../builder/type_variable_builder.dart';
+import '../builder/void_type_declaration_builder.dart';
 import '../dill/dill_member_builder.dart';
 import '../fasta_codes.dart';
 import '../kernel/combined_member_signature.dart';
 import '../kernel/kernel_helper.dart';
 import '../kernel/kernel_target.dart' show KernelTarget;
-import '../kernel/redirecting_factory_body.dart' show redirectingName;
+import '../kernel/redirecting_factory_body.dart'
+    show RedirectingFactoryBody, redirectingName;
 import '../kernel/type_algorithms.dart' show computeTypeVariableBuilderVariance;
 import '../kernel/utils.dart' show compareProcedures;
 import '../names.dart' show equalsName, noSuchMethodName;
@@ -188,7 +193,7 @@
     scope.forEach(buildBuilders);
     constructors.forEach(buildBuilders);
     if (supertypeBuilder != null) {
-      supertypeBuilder = checkSupertype(supertypeBuilder!);
+      supertypeBuilder = _checkSupertype(supertypeBuilder!);
     }
     Supertype? supertype =
         supertypeBuilder?.buildSupertype(library, charOffset, fileUri);
@@ -222,7 +227,7 @@
     actualCls.supertype = supertype;
 
     if (mixedInTypeBuilder != null) {
-      mixedInTypeBuilder = checkSupertype(mixedInTypeBuilder!);
+      mixedInTypeBuilder = _checkSupertype(mixedInTypeBuilder!);
     }
     Supertype? mixedInType =
         mixedInTypeBuilder?.buildMixedInType(library, charOffset, fileUri);
@@ -245,7 +250,7 @@
     cls.isMacro = isMacro;
     if (interfaceBuilders != null) {
       for (int i = 0; i < interfaceBuilders!.length; ++i) {
-        interfaceBuilders![i] = checkSupertype(interfaceBuilders![i]);
+        interfaceBuilders![i] = _checkSupertype(interfaceBuilders![i]);
         Supertype? supertype =
             interfaceBuilders![i].buildSupertype(library, charOffset, fileUri);
         if (supertype != null) {
@@ -314,6 +319,30 @@
     return false;
   }
 
+  void buildOutlineExpressions(
+      SourceLibraryBuilder library,
+      ClassHierarchy classHierarchy,
+      List<DelayedActionPerformer> delayedActionPerformers,
+      List<SynthesizedFunctionNode> synthesizedFunctionNodes) {
+    void build(String ignore, Builder declaration) {
+      SourceMemberBuilder member = declaration as SourceMemberBuilder;
+      member.buildOutlineExpressions(library, classHierarchy,
+          delayedActionPerformers, synthesizedFunctionNodes);
+    }
+
+    MetadataBuilder.buildAnnotations(isPatch ? origin.cls : cls, metadata,
+        library, this, null, fileUri, library.scope);
+    if (typeVariables != null) {
+      for (int i = 0; i < typeVariables!.length; i++) {
+        typeVariables![i].buildOutlineExpressions(library, this, null,
+            classHierarchy, delayedActionPerformers, scope.parent!);
+      }
+    }
+
+    constructors.forEach(build);
+    scope.forEach(build);
+  }
+
   @override
   void forEachConstructor(void Function(String, MemberBuilder) f,
       {bool includeInjectedConstructors: false}) {
@@ -383,6 +412,95 @@
   }
 
   @override
+  int get typeVariablesCount => typeVariables?.length ?? 0;
+
+  @override
+  List<DartType> buildTypeArguments(
+      LibraryBuilder library, List<TypeBuilder>? arguments) {
+    if (arguments == null && typeVariables == null) {
+      return <DartType>[];
+    }
+
+    if (arguments == null && typeVariables != null) {
+      List<DartType> result = new List<DartType>.generate(typeVariables!.length,
+          (int i) => typeVariables![i].defaultType!.build(library),
+          growable: true);
+      if (library is SourceLibraryBuilder) {
+        library.inferredTypes.addAll(result);
+      }
+      return result;
+    }
+
+    if (arguments != null && arguments.length != typeVariablesCount) {
+      // That should be caught and reported as a compile-time error earlier.
+      return unhandled(
+          templateTypeArgumentMismatch
+              .withArguments(typeVariablesCount)
+              .problemMessage,
+          "buildTypeArguments",
+          -1,
+          null);
+    }
+
+    assert(arguments!.length == typeVariablesCount);
+    List<DartType> result = new List<DartType>.generate(
+        arguments!.length, (int i) => arguments[i].build(library),
+        growable: true);
+    return result;
+  }
+
+  /// Returns a map which maps the type variables of [superclass] to their
+  /// respective values as defined by the superclass clause of this class (and
+  /// its superclasses).
+  ///
+  /// It's assumed that [superclass] is a superclass of this class.
+  ///
+  /// For example, given:
+  ///
+  ///     class Box<T> {}
+  ///     class BeatBox extends Box<Beat> {}
+  ///     class Beat {}
+  ///
+  /// We have:
+  ///
+  ///     [[BeatBox]].getSubstitutionMap([[Box]]) -> {[[Box::T]]: Beat]]}.
+  ///
+  /// It's an error if [superclass] isn't a superclass.
+  Map<TypeParameter, DartType> getSubstitutionMap(Class superclass) {
+    Supertype? supertype = cls.supertype;
+    Map<TypeParameter, DartType> substitutionMap = <TypeParameter, DartType>{};
+    List<DartType> arguments;
+    List<TypeParameter> variables;
+    Class? classNode;
+
+    while (classNode != superclass) {
+      classNode = supertype!.classNode;
+      arguments = supertype.typeArguments;
+      variables = classNode.typeParameters;
+      supertype = classNode.supertype;
+      if (variables.isNotEmpty) {
+        Map<TypeParameter, DartType> directSubstitutionMap =
+            <TypeParameter, DartType>{};
+        for (int i = 0; i < variables.length; i++) {
+          DartType argument =
+              i < arguments.length ? arguments[i] : const DynamicType();
+          // ignore: unnecessary_null_comparison
+          if (substitutionMap != null) {
+            // TODO(ahe): Investigate if requiring the caller to use
+            // `substituteDeep` from `package:kernel/type_algebra.dart` instead
+            // of `substitute` is faster. If so, we can simply this code.
+            argument = substitute(argument, substitutionMap);
+          }
+          directSubstitutionMap[variables[i]] = argument;
+        }
+        substitutionMap = directSubstitutionMap;
+      }
+    }
+
+    return substitutionMap;
+  }
+
+  @override
   void applyPatch(Builder patch) {
     if (patch is SourceClassBuilder) {
       patch.actualOrigin = this;
@@ -431,7 +549,357 @@
     }
   }
 
-  TypeBuilder checkSupertype(TypeBuilder supertype) {
+  void checkSupertypes(CoreTypes coreTypes) {
+    // This method determines whether the class (that's being built) its super
+    // class appears both in 'extends' and 'implements' clauses and whether any
+    // interface appears multiple times in the 'implements' clause.
+    // Moreover, it checks that `FutureOr` and `void` are not among the
+    // supertypes.
+
+    void fail(NamedTypeBuilder target, Message message,
+        TypeAliasBuilder? aliasBuilder) {
+      int nameOffset = target.nameOffset;
+      int nameLength = target.nameLength;
+      // TODO(eernst): nameOffset not fully implemented; use backup.
+      if (nameOffset == -1) {
+        nameOffset = this.charOffset;
+        nameLength = noLength;
+      }
+      if (aliasBuilder != null) {
+        addProblem(message, nameOffset, nameLength, context: [
+          messageTypedefCause.withLocation(
+              aliasBuilder.fileUri, aliasBuilder.charOffset, noLength),
+        ]);
+      } else {
+        addProblem(message, nameOffset, nameLength);
+      }
+    }
+
+    // Extract and check superclass (if it exists).
+    ClassBuilder? superClass;
+    TypeBuilder? superClassType = supertypeBuilder;
+    if (superClassType is NamedTypeBuilder) {
+      TypeDeclarationBuilder? decl = superClassType.declaration;
+      TypeAliasBuilder? aliasBuilder; // Non-null if a type alias is use.
+      if (decl is TypeAliasBuilder) {
+        aliasBuilder = decl;
+        decl = aliasBuilder.unaliasDeclaration(superClassType.arguments,
+            isUsedAsClass: true,
+            usedAsClassCharOffset: superClassType.charOffset,
+            usedAsClassFileUri: superClassType.fileUri);
+      }
+      // TODO(eernst): Should gather 'restricted supertype' checks in one place,
+      // e.g., dynamic/int/String/Null and more are checked elsewhere.
+      if (decl is VoidTypeDeclarationBuilder) {
+        fail(superClassType, messageExtendsVoid, aliasBuilder);
+      } else if (decl is NeverTypeDeclarationBuilder) {
+        fail(superClassType, messageExtendsNever, aliasBuilder);
+      } else if (decl is ClassBuilder) {
+        superClass = decl;
+      }
+    }
+    if (interfaceBuilders == null) return;
+
+    // Validate interfaces.
+    Map<ClassBuilder, int>? problems;
+    Map<ClassBuilder, int>? problemsOffsets;
+    Set<ClassBuilder> implemented = new Set<ClassBuilder>();
+    for (TypeBuilder type in interfaceBuilders!) {
+      if (type is NamedTypeBuilder) {
+        int? charOffset = type.charOffset;
+        TypeDeclarationBuilder? typeDeclaration = type.declaration;
+        TypeDeclarationBuilder? decl;
+        TypeAliasBuilder? aliasBuilder; // Non-null if a type alias is used.
+        if (typeDeclaration is TypeAliasBuilder) {
+          aliasBuilder = typeDeclaration;
+          decl = aliasBuilder.unaliasDeclaration(type.arguments,
+              isUsedAsClass: true,
+              usedAsClassCharOffset: type.charOffset,
+              usedAsClassFileUri: type.fileUri);
+        } else {
+          decl = typeDeclaration;
+        }
+        if (decl is ClassBuilder) {
+          ClassBuilder interface = decl;
+          if (superClass == interface) {
+            addProblem(
+                templateImplementsSuperClass.withArguments(interface.name),
+                this.charOffset,
+                noLength);
+          } else if (interface.cls.name == "FutureOr" &&
+              interface.cls.enclosingLibrary.importUri.scheme == "dart" &&
+              interface.cls.enclosingLibrary.importUri.path == "async") {
+            addProblem(messageImplementsFutureOr, this.charOffset, noLength);
+          } else if (implemented.contains(interface)) {
+            // Aggregate repetitions.
+            problems ??= <ClassBuilder, int>{};
+            problems[interface] ??= 0;
+            problems[interface] = problems[interface]! + 1;
+            problemsOffsets ??= <ClassBuilder, int>{};
+            problemsOffsets[interface] ??= charOffset ?? TreeNode.noOffset;
+          } else {
+            implemented.add(interface);
+          }
+        }
+        if (decl != superClass) {
+          // TODO(eernst): Have all 'restricted supertype' checks in one place.
+          if (decl is VoidTypeDeclarationBuilder) {
+            fail(type, messageImplementsVoid, aliasBuilder);
+          } else if (decl is NeverTypeDeclarationBuilder) {
+            fail(type, messageImplementsNever, aliasBuilder);
+          }
+        }
+      }
+    }
+    if (problems != null) {
+      problems.forEach((ClassBuilder interface, int repetitions) {
+        addProblem(
+            templateImplementsRepeated.withArguments(
+                interface.name, repetitions),
+            problemsOffsets![interface]!,
+            noLength);
+      });
+    }
+  }
+
+  void checkMixinApplication(ClassHierarchy hierarchy, CoreTypes coreTypes) {
+    TypeEnvironment typeEnvironment = new TypeEnvironment(coreTypes, hierarchy);
+    // A mixin declaration can only be applied to a class that implements all
+    // the declaration's superclass constraints.
+    InterfaceType supertype = cls.supertype!.asInterfaceType;
+    Substitution substitution = Substitution.fromSupertype(cls.mixedInType!);
+    for (Supertype constraint in cls.mixedInClass!.superclassConstraints()) {
+      InterfaceType requiredInterface =
+          substitution.substituteSupertype(constraint).asInterfaceType;
+      InterfaceType? implementedInterface = hierarchy.getTypeAsInstanceOf(
+          supertype, requiredInterface.classNode, library.library);
+      if (implementedInterface == null ||
+          !typeEnvironment.areMutualSubtypes(
+              implementedInterface,
+              requiredInterface,
+              library.isNonNullableByDefault
+                  ? SubtypeCheckMode.withNullabilities
+                  : SubtypeCheckMode.ignoringNullabilities)) {
+        library.addProblem(
+            templateMixinApplicationIncompatibleSupertype.withArguments(
+                supertype,
+                requiredInterface,
+                cls.mixedInType!.asInterfaceType,
+                library.isNonNullableByDefault),
+            cls.fileOffset,
+            noLength,
+            cls.fileUri);
+      }
+    }
+  }
+
+  // Computes the function type of a given redirection target. Returns [null] if
+  // the type of the target could not be computed.
+  FunctionType? _computeRedirecteeType(
+      RedirectingFactoryBuilder factory, TypeEnvironment typeEnvironment) {
+    ConstructorReferenceBuilder redirectionTarget = factory.redirectionTarget;
+    Builder? targetBuilder = redirectionTarget.target;
+    FunctionNode targetNode;
+    if (targetBuilder == null) return null;
+    if (targetBuilder is FunctionBuilder) {
+      targetNode = targetBuilder.function;
+    } else if (targetBuilder is AmbiguousBuilder) {
+      // Multiple definitions with the same name: An error has already been
+      // issued.
+      // TODO(http://dartbug.com/35294): Unfortunate error; see also
+      // https://dart-review.googlesource.com/c/sdk/+/85390/.
+      return null;
+    } else {
+      unhandled("${redirectionTarget.target}", "computeRedirecteeType",
+          charOffset, fileUri);
+    }
+
+    List<DartType>? typeArguments = factory.getTypeArguments();
+    FunctionType targetFunctionType =
+        targetNode.computeFunctionType(library.nonNullable);
+    if (typeArguments != null &&
+        targetFunctionType.typeParameters.length != typeArguments.length) {
+      _addProblemForRedirectingFactory(
+          factory,
+          templateTypeArgumentMismatch
+              .withArguments(targetFunctionType.typeParameters.length),
+          redirectionTarget.charOffset,
+          noLength);
+      return null;
+    }
+
+    // Compute the substitution of the target class type parameters if
+    // [redirectionTarget] has any type arguments.
+    Substitution? substitution;
+    bool hasProblem = false;
+    if (typeArguments != null && typeArguments.length > 0) {
+      substitution = Substitution.fromPairs(
+          targetFunctionType.typeParameters, typeArguments);
+      for (int i = 0; i < targetFunctionType.typeParameters.length; i++) {
+        TypeParameter typeParameter = targetFunctionType.typeParameters[i];
+        DartType typeParameterBound =
+            substitution.substituteType(typeParameter.bound);
+        DartType typeArgument = typeArguments[i];
+        // Check whether the [typeArgument] respects the bounds of
+        // [typeParameter].
+        if (!typeEnvironment.isSubtypeOf(typeArgument, typeParameterBound,
+            SubtypeCheckMode.ignoringNullabilities)) {
+          _addProblemForRedirectingFactory(
+              factory,
+              templateRedirectingFactoryIncompatibleTypeArgument.withArguments(
+                  typeArgument,
+                  typeParameterBound,
+                  library.isNonNullableByDefault),
+              redirectionTarget.charOffset,
+              noLength);
+          hasProblem = true;
+        } else if (library.isNonNullableByDefault) {
+          if (!typeEnvironment.isSubtypeOf(typeArgument, typeParameterBound,
+              SubtypeCheckMode.withNullabilities)) {
+            _addProblemForRedirectingFactory(
+                factory,
+                templateRedirectingFactoryIncompatibleTypeArgument
+                    .withArguments(typeArgument, typeParameterBound,
+                        library.isNonNullableByDefault),
+                redirectionTarget.charOffset,
+                noLength);
+            hasProblem = true;
+          }
+        }
+      }
+    } else if (typeArguments == null &&
+        targetFunctionType.typeParameters.length > 0) {
+      // TODO(hillerstrom): In this case, we need to perform type inference on
+      // the redirectee to obtain actual type arguments which would allow the
+      // following program to type check:
+      //
+      //    class A<T> {
+      //       factory A() = B;
+      //    }
+      //    class B<T> implements A<T> {
+      //       B();
+      //    }
+      //
+      return null;
+    }
+
+    // Substitute if necessary.
+    targetFunctionType = substitution == null
+        ? targetFunctionType
+        : (substitution.substituteType(targetFunctionType.withoutTypeParameters)
+            as FunctionType);
+
+    return hasProblem ? null : targetFunctionType;
+  }
+
+  bool _isCyclicRedirectingFactory(RedirectingFactoryBuilder factory) {
+    // We use the [tortoise and hare algorithm]
+    // (https://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare) to
+    // handle cycles.
+    Builder? tortoise = factory;
+    Builder? hare = factory.redirectionTarget.target;
+    if (hare == factory) {
+      return true;
+    }
+    while (tortoise != hare) {
+      // Hare moves 2 steps forward.
+      if (hare is! RedirectingFactoryBuilder) {
+        return false;
+      }
+      hare = hare.redirectionTarget.target;
+      if (hare == factory) {
+        return true;
+      }
+      if (hare is! RedirectingFactoryBuilder) {
+        return false;
+      }
+      hare = hare.redirectionTarget.target;
+      if (hare == factory) {
+        return true;
+      }
+      // Tortoise moves one step forward. No need to test type of tortoise
+      // as it follows hare which already checked types.
+      tortoise =
+          (tortoise as RedirectingFactoryBuilder).redirectionTarget.target;
+    }
+    // Cycle found, but original factory doesn't belong to a cycle.
+    return false;
+  }
+
+  void _addProblemForRedirectingFactory(RedirectingFactoryBuilder factory,
+      Message message, int charOffset, int length) {
+    addProblem(message, charOffset, length);
+    String text = library.loader.target.context
+        .format(
+            message.withLocation(fileUri, charOffset, length), Severity.error)
+        .plain;
+    factory.body = new RedirectingFactoryBody.error(text);
+  }
+
+  void _checkRedirectingFactory(
+      RedirectingFactoryBuilder factory, TypeEnvironment typeEnvironment) {
+    // Check that factory declaration is not cyclic.
+    if (_isCyclicRedirectingFactory(factory)) {
+      _addProblemForRedirectingFactory(
+          factory,
+          templateCyclicRedirectingFactoryConstructors
+              .withArguments("${factory.member.enclosingClass!.name}"
+                  "${factory.name == '' ? '' : '.${factory.name}'}"),
+          factory.charOffset,
+          noLength);
+      return;
+    }
+
+    // The factory type cannot contain any type parameters other than those of
+    // its enclosing class, because constructors cannot specify type parameters
+    // of their own.
+    FunctionType factoryType = factory.function
+        .computeThisFunctionType(library.nonNullable)
+        .withoutTypeParameters;
+    FunctionType? redirecteeType =
+        _computeRedirecteeType(factory, typeEnvironment);
+
+    // TODO(hillerstrom): It would be preferable to know whether a failure
+    // happened during [_computeRedirecteeType].
+    if (redirecteeType == null) {
+      return;
+    }
+
+    // Check whether [redirecteeType] <: [factoryType].
+    if (!typeEnvironment.isSubtypeOf(
+        redirecteeType, factoryType, SubtypeCheckMode.ignoringNullabilities)) {
+      _addProblemForRedirectingFactory(
+          factory,
+          templateIncompatibleRedirecteeFunctionType.withArguments(
+              redirecteeType, factoryType, library.isNonNullableByDefault),
+          factory.redirectionTarget.charOffset,
+          noLength);
+    } else if (library.isNonNullableByDefault) {
+      if (!typeEnvironment.isSubtypeOf(
+          redirecteeType, factoryType, SubtypeCheckMode.withNullabilities)) {
+        _addProblemForRedirectingFactory(
+            factory,
+            templateIncompatibleRedirecteeFunctionType.withArguments(
+                redirecteeType, factoryType, library.isNonNullableByDefault),
+            factory.redirectionTarget.charOffset,
+            noLength);
+      }
+    }
+  }
+
+  void checkRedirectingFactories(TypeEnvironment typeEnvironment) {
+    Map<String, MemberBuilder> constructors = this.constructors.local;
+    for (Builder? constructor in constructors.values) {
+      do {
+        if (constructor is RedirectingFactoryBuilder) {
+          _checkRedirectingFactory(constructor, typeEnvironment);
+        }
+        constructor = constructor!.next;
+      } while (constructor != null);
+    }
+  }
+
+  TypeBuilder _checkSupertype(TypeBuilder supertype) {
     if (typeVariables == null) return supertype;
     Message? message;
     for (int i = 0; i < typeVariables!.length; ++i) {
@@ -802,6 +1270,12 @@
     return charOffset.compareTo(other.charOffset);
   }
 
+  bool _hasUserDefinedNoSuchMethod(
+      Class klass, ClassHierarchy hierarchy, Class objectClass) {
+    Member? noSuchMethod = hierarchy.getDispatchTarget(klass, noSuchMethodName);
+    return noSuchMethod != null && noSuchMethod.enclosingClass != objectClass;
+  }
+
   bool _addMissingNoSuchMethodForwarders(
       KernelTarget target, Set<Member> existingForwarders,
       {required bool forSetters}) {
@@ -820,7 +1294,7 @@
     Procedure noSuchMethod = ClassHierarchy.findMemberByName(
         hierarchy.getInterfaceMembers(cls), noSuchMethodName) as Procedure;
     bool clsHasUserDefinedNoSuchMethod =
-        hasUserDefinedNoSuchMethod(cls, hierarchy, target.objectClass);
+        _hasUserDefinedNoSuchMethod(cls, hierarchy, target.objectClass);
 
     bool changed = false;
 
@@ -890,7 +1364,7 @@
         nearestConcreteSuperclass = nearestConcreteSuperclass.superclass;
       }
       if (nearestConcreteSuperclass != null) {
-        bool superHasUserDefinedNoSuchMethod = hasUserDefinedNoSuchMethod(
+        bool superHasUserDefinedNoSuchMethod = _hasUserDefinedNoSuchMethod(
             nearestConcreteSuperclass, hierarchy, target.objectClass);
         {
           List<Member> concrete =
@@ -1085,14 +1559,14 @@
               } else if (targetBuilder is DillMemberBuilder) {
                 targetNode = targetBuilder.member;
               } else if (targetBuilder is AmbiguousBuilder) {
-                addProblemForRedirectingFactory(
+                _addProblemForRedirectingFactory(
                     declaration,
                     templateDuplicatedDeclarationUse
                         .withArguments(redirectionTarget.fullNameForErrors),
                     redirectionTarget.charOffset,
                     noLength);
               } else {
-                addProblemForRedirectingFactory(
+                _addProblemForRedirectingFactory(
                     declaration,
                     templateRedirectionTargetNotFound
                         .withArguments(redirectionTarget.fullNameForErrors),
@@ -1102,7 +1576,7 @@
               if (targetNode != null &&
                   targetNode is Constructor &&
                   targetNode.enclosingClass.isAbstract) {
-                addProblemForRedirectingFactory(
+                _addProblemForRedirectingFactory(
                     declaration,
                     templateAbstractRedirectedClassInstantiation
                         .withArguments(redirectionTarget.fullNameForErrors),
@@ -1127,6 +1601,23 @@
     return count;
   }
 
+  void _handleSeenCovariant(
+      ClassHierarchyMembers memberHierarchy,
+      Member interfaceMember,
+      bool isSetter,
+      callback(Member interfaceMember, bool isSetter)) {
+    // When a parameter is covariant we have to check that we also
+    // override the same member in all parents.
+    for (Supertype supertype in interfaceMember.enclosingClass!.supers) {
+      Member? member = memberHierarchy.getInterfaceMember(
+          supertype.classNode, interfaceMember.name,
+          setter: isSetter);
+      if (member != null) {
+        callback(member, isSetter);
+      }
+    }
+  }
+
   void checkOverride(
       Types types,
       ClassHierarchyMembers memberHierarchy,
@@ -1161,7 +1652,7 @@
               isInterfaceCheck,
               declaredNeedsLegacyErasure);
           if (seenCovariant) {
-            handleSeenCovariant(
+            _handleSeenCovariant(
                 memberHierarchy, interfaceMember, isSetter, callback);
           }
         } else if (declaredMember.kind == ProcedureKind.Getter) {
@@ -1181,7 +1672,7 @@
               isInterfaceCheck,
               declaredNeedsLegacyErasure);
           if (seenCovariant) {
-            handleSeenCovariant(
+            _handleSeenCovariant(
                 memberHierarchy, interfaceMember, isSetter, callback);
           }
         } else {
@@ -1222,7 +1713,7 @@
             isInterfaceCheck,
             declaredNeedsLegacyErasure);
         if (seenCovariant) {
-          handleSeenCovariant(
+          _handleSeenCovariant(
               memberHierarchy, interfaceMember, isSetter, callback);
         }
       }
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 915ff8d..28267ee 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -2963,7 +2963,7 @@
     Iterator<Builder> iterator = this.iterator;
     while (iterator.moveNext()) {
       Builder declaration = iterator.current;
-      if (declaration is ClassBuilder) {
+      if (declaration is SourceClassBuilder) {
         declaration.buildOutlineExpressions(this, classHierarchy,
             delayedActionPerformers, synthesizedFunctionNodes);
       } else if (declaration is ExtensionBuilder) {
diff --git a/pkg/front_end/test/patching/patching_test.dart b/pkg/front_end/test/patching/patching_test.dart
index a3b4829..9828fd4 100644
--- a/pkg/front_end/test/patching/patching_test.dart
+++ b/pkg/front_end/test/patching/patching_test.dart
@@ -10,8 +10,8 @@
 import 'package:front_end/src/api_prototype/compiler_options.dart';
 import 'package:front_end/src/api_prototype/experimental_flags.dart';
 import 'package:front_end/src/fasta/builder/builder.dart';
-import 'package:front_end/src/fasta/builder/class_builder.dart';
 import 'package:front_end/src/fasta/builder/member_builder.dart';
+import 'package:front_end/src/fasta/source/source_class_builder.dart';
 import 'package:front_end/src/fasta/source/source_member_builder.dart';
 import 'package:front_end/src/testing/id_testing_helper.dart';
 import 'package:front_end/src/testing/id_testing_utils.dart';
@@ -128,7 +128,8 @@
 
   @override
   Features computeClassValue(Id id, Class cls) {
-    ClassBuilder clsBuilder = lookupClassBuilder(compilerResult, cls)!;
+    SourceClassBuilder clsBuilder =
+        lookupClassBuilder(compilerResult, cls) as SourceClassBuilder;
 
     Features features = new Features();
     if (cls.isAbstract) {
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index a6d5418..aa1d703 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -3572,60 +3572,6 @@
   }
 }
 
-void FlowGraphCompiler::EmitMoveConst(const compiler::ffi::NativeLocation& dst,
-                                      Location src,
-                                      Representation src_type,
-                                      TemporaryRegisterAllocator* temp) {
-  ASSERT(src.IsConstant());
-  const auto& dst_type = dst.payload_type();
-  if (dst.IsExpressibleAsLocation() &&
-      dst_type.IsExpressibleAsRepresentation() &&
-      dst_type.AsRepresentationOverApprox(zone_) == src_type) {
-    // We can directly emit the const in the right place and representation.
-    const Location dst_loc = dst.AsLocation();
-    EmitMove(dst_loc, src, temp);
-  } else {
-    // We need an intermediate location.
-    Location intermediate;
-    if (dst_type.IsInt()) {
-      if (TMP == kNoRegister) {
-        Register scratch = temp->AllocateTemporary();
-        Location::RegisterLocation(scratch);
-      } else {
-        intermediate = Location::RegisterLocation(TMP);
-      }
-    } else {
-      ASSERT(dst_type.IsFloat());
-      intermediate = Location::FpuRegisterLocation(FpuTMP);
-    }
-
-    if (src.IsPairLocation()) {
-      for (intptr_t i : {0, 1}) {
-        const Representation src_type_split =
-            compiler::ffi::NativeType::FromUnboxedRepresentation(zone_,
-                                                                 src_type)
-                .Split(zone_, i)
-                .AsRepresentation();
-        const auto& intermediate_native =
-            compiler::ffi::NativeLocation::FromLocation(zone_, intermediate,
-                                                        src_type_split);
-        EmitMove(intermediate, src.AsPairLocation()->At(i), temp);
-        EmitNativeMove(dst.Split(zone_, 2, i), intermediate_native, temp);
-      }
-    } else {
-      const auto& intermediate_native =
-          compiler::ffi::NativeLocation::FromLocation(zone_, intermediate,
-                                                      src_type);
-      EmitMove(intermediate, src, temp);
-      EmitNativeMove(dst, intermediate_native, temp);
-    }
-
-    if (dst_type.IsInt() && TMP == kNoRegister) {
-      temp->ReleaseTemporary();
-    }
-  }
-  return;
-}
 
 // The assignment to loading units here must match that in
 // AssignLoadingUnitsCodeVisitor, which runs after compilation is done.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index 975e431..f53e11f 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -613,12 +613,6 @@
                           const compiler::ffi::NativeLocation& src,
                           TemporaryRegisterAllocator* temp);
 
-  // Emits a Dart const to a native location.
-  void EmitMoveConst(const compiler::ffi::NativeLocation& dst,
-                     Location src,
-                     Representation src_type,
-                     TemporaryRegisterAllocator* temp);
-
   bool CheckAssertAssignableTypeTestingABILocations(
       const LocationSummary& locs);
 
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 878bcec..02daa82 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -6504,7 +6504,10 @@
 
       ConstantTemporaryAllocator temp_alloc(temp);
       if (origin.IsConstant()) {
-        compiler->EmitMoveConst(def_target, origin, origin_rep, &temp_alloc);
+        // Can't occur because we currently don't inline FFI trampolines (see
+        // http://dartbug.com/45055), which means all incomming arguments
+        // originate from parameters and thus are non-constant.
+        UNREACHABLE();
       } else {
         compiler->EmitMoveToNative(def_target, origin, origin_rep, &temp_alloc);
       }
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index cb4dcdf..4ed246d 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -8173,9 +8173,11 @@
   // being inlined (for now).
   if (ForceOptimize()) {
     if (IsFfiTrampoline()) {
-      // The CallSiteInliner::InlineCall asserts in PrepareGraphs that
-      // GraphEntryInstr::SuccessorCount() == 1, but FFI trampoline has two
-      // entries (a normal and a catch entry).
+      // We currently don't support inlining FFI trampolines. Some of them
+      // are naturally non-inlinable because they contain a try/catch block,
+      // but this condition is broader than strictly necessary.
+      // The work necessary for inlining FFI trampolines is tracked by
+      // http://dartbug.com/45055.
       return false;
     }
     return CompilerState::Current().is_aot();
diff --git a/sdk/lib/core/bigint.dart b/sdk/lib/core/bigint.dart
index 63f9198..e5a871c 100644
--- a/sdk/lib/core/bigint.dart
+++ b/sdk/lib/core/bigint.dart
@@ -8,6 +8,39 @@
 ///
 /// Big integers are signed and can have an arbitrary number of
 /// significant digits, only limited by memory.
+///
+/// To create a big integer from the provided number, use [BigInt.from].
+/// ```dart
+/// var bigInteger = BigInt.from(-1); // -1
+/// bigInteger = BigInt.from(0.9999); // 0
+/// bigInteger = BigInt.from(-10.99); // -10
+/// bigInteger = BigInt.from(0x7FFFFFFFFFFFFFFF); // 9223372036854775807
+/// bigInteger = BigInt.from(1e+30); // 1000000000000000019884624838656
+/// ```
+/// To parse a large integer value from a string, use [parse] or [tryParse].
+/// ```dart
+/// var value = BigInt.parse('0x1ffffffffffffffff'); // 36893488147419103231
+/// value = BigInt.parse('12345678901234567890'); // 12345678901234567890
+/// ```
+/// To check whether a big integer can be represented as an [int] without losing
+/// precision, use [isValidInt].
+/// ```dart continued
+/// print(bigNumber.isValidInt); // false
+/// ```
+/// To convert a big integer into an [int], use [toInt].
+/// To convert a big integer into an [double], use [toDouble].
+/// ```dart
+/// var bigValue = BigInt.from(10).pow(3);
+/// print(bigValue.isValidInt); // true
+/// print(bigValue.toInt()); // 1000
+/// print(bigValue.toDouble()); // 1000.0
+/// ```
+/// **See also:**
+/// * [int]: An integer number.
+/// * [double]: A double-precision floating point number.
+/// * [num]: The super class for [int] and [double].
+/// * [Numbers](https://dart.dev/guides/language/numbers) in
+/// [A tour of the Dart language](https://dart.dev/guides/language/language-tour).
 abstract class BigInt implements Comparable<BigInt> {
   /// A big integer with the numerical value 0.
   external static BigInt get zero;
@@ -39,6 +72,31 @@
   ///
   /// Throws a [FormatException] if the [source] is not a valid integer literal,
   /// optionally prefixed by a sign.
+  /// Examples:
+  /// ```dart
+  /// print(BigInt.parse('-12345678901234567890')); // -12345678901234567890
+  /// print(BigInt.parse('0xFF')); // 255
+  /// print(BigInt.parse('0xffffffffffffffff')); // 18446744073709551615
+  ///
+  /// // From binary (base 2) value.
+  /// print(BigInt.parse('1100', radix: 2)); // 12
+  /// print(BigInt.parse('00011111', radix: 2)); // 31
+  /// print(BigInt.parse('011111100101', radix: 2)); // 2021
+  /// // From octal (base 8) value.
+  /// print(BigInt.parse('14', radix: 8)); // 12
+  /// print(BigInt.parse('37', radix: 8)); // 31
+  /// print(BigInt.parse('3745', radix: 8)); // 2021
+  /// // From hexadecimal (base 16) value.
+  /// print(BigInt.parse('c', radix: 16)); // 12
+  /// print(BigInt.parse('1f', radix: 16)); // 31
+  /// print(BigInt.parse('7e5', radix: 16)); // 2021
+  /// // From base 35 value.
+  /// print(BigInt.parse('y1', radix: 35)); // 1191 == 34 * 35 + 1
+  /// print(BigInt.parse('z1', radix: 35)); // Throws.
+  /// // From base 36 value.
+  /// print(BigInt.parse('y1', radix: 36)); // 1225 == 34 * 36 + 1
+  /// print(BigInt.parse('z1', radix: 36)); // 1261 == 35 * 36 + 1
+  /// ```
   external static BigInt parse(String source, {int? radix});
 
   /// Parses [source] as a, possibly signed, integer literal and returns its
@@ -46,9 +104,42 @@
   ///
   /// As [parse] except that this method returns `null` if the input is not
   /// valid
+  ///
+  /// Examples:
+  /// ```dart
+  /// print(BigInt.tryParse('-12345678901234567890')); // -12345678901234567890
+  /// print(BigInt.tryParse('0xFF')); // 255
+  /// print(BigInt.tryParse('0xffffffffffffffff')); // 18446744073709551615
+  ///
+  /// // From binary (base 2) value.
+  /// print(BigInt.tryParse('1100', radix: 2)); // 12
+  /// print(BigInt.tryParse('00011111', radix: 2)); // 31
+  /// print(BigInt.tryParse('011111100101', radix: 2)); // 2021
+  /// // From octal (base 8) value.
+  /// print(BigInt.tryParse('14', radix: 8)); // 12
+  /// print(BigInt.tryParse('37', radix: 8)); // 31
+  /// print(BigInt.tryParse('3745', radix: 8)); // 2021
+  /// // From hexadecimal (base 16) value.
+  /// print(BigInt.tryParse('c', radix: 16)); // 12
+  /// print(BigInt.tryParse('1f', radix: 16)); // 31
+  /// print(BigInt.tryParse('7e5', radix: 16)); // 2021
+  /// // From base 35 value.
+  /// print(BigInt.tryParse('y1', radix: 35)); // 1191 == 34 * 35 + 1
+  /// print(BigInt.tryParse('z1', radix: 35)); // null
+  /// // From base 36 value.
+  /// print(BigInt.tryParse('y1', radix: 36)); // 1225 == 34 * 36 + 1
+  /// print(BigInt.tryParse('z1', radix: 36)); // 1261 == 35 * 36 + 1
+  /// ```
   external static BigInt? tryParse(String source, {int? radix});
 
-  /// Allocates a big integer from the provided [value] number.
+  /// Creates a big integer from the provided [value] number.
+  ///
+  /// Examples:
+  /// ```dart
+  /// var bigInteger = BigInt.from(1); // 1
+  /// bigInteger = BigInt.from(0.9999); // 0
+  /// bigInteger = BigInt.from(-10.99); // -10
+  /// ```
   external factory BigInt.from(num value);
 
   /// Returns the absolute value of this integer.
@@ -83,7 +174,14 @@
   /// this operation first performs [toDouble] on both this big integer
   /// and [other], then does [double.operator/] on those values and
   /// returns the result.
-  /// The initial [toDouble] conversion may lose precision.
+  ///
+  /// **Note:** The initial [toDouble] conversion may lose precision.
+  ///
+  /// Example:
+  /// ```dart
+  /// print(BigInt.from(1) / BigInt.from(2)); // 0.5
+  /// print(BigInt.from(1.99999) / BigInt.from(2)); // 0.5
+  /// ```
   double operator /(BigInt other);
 
   /// Truncating integer division operator.
@@ -114,6 +212,14 @@
   /// The sign of the returned value `r` is always positive.
   ///
   /// See [remainder] for the remainder of the truncating division.
+  ///
+  /// Example:
+  /// ```dart
+  /// print(BigInt.from(5) % BigInt.from(3)); // 2
+  /// print(BigInt.from(-5) % BigInt.from(3)); // 1
+  /// print(BigInt.from(5) % BigInt.from(-3)); // 2
+  /// print(BigInt.from(-5) % BigInt.from(-3)); // 1
+  /// ```
   BigInt operator %(BigInt other);
 
   /// Returns the remainder of the truncating division of `this` by [other].
@@ -121,6 +227,14 @@
   /// The result `r` of this operation satisfies:
   /// `this == (this ~/ other) * other + r`.
   /// As a consequence the remainder `r` has the same sign as the divider `this`.
+  ///
+  /// Example:
+  /// ```dart
+  /// print(BigInt.from(5).remainder(BigInt.from(3))); // 2
+  /// print(BigInt.from(-5).remainder(BigInt.from(3))); // -2
+  /// print(BigInt.from(5).remainder(BigInt.from(-3))); // 2
+  /// print(BigInt.from(-5).remainder(BigInt.from(-3))); // -2
+  /// ```
   BigInt remainder(BigInt other);
 
   /// Shift the bits of this integer to the left by [shiftAmount].
@@ -198,12 +312,19 @@
   ///
   /// Returns a negative number if `this` is less than `other`, zero if they are
   /// equal, and a positive number if `this` is greater than `other`.
+  ///
+  /// Example:
+  /// ```dart
+  /// print(BigInt.from(1).compareTo(BigInt.from(2))); // => -1
+  /// print(BigInt.from(2).compareTo(BigInt.from(1))); // => 1
+  /// print(BigInt.from(1).compareTo(BigInt.from(1))); // => 0
+  /// ```
   int compareTo(BigInt other);
 
   /// Returns the minimum number of bits required to store this big integer.
   ///
   /// The number of bits excludes the sign bit, which gives the natural length
-  /// for non-negative (unsigned) values.  Negative values are complemented to
+  /// for non-negative (unsigned) values. Negative values are complemented to
   /// return the bit position of the first bit that differs from the sign bit.
   ///
   /// To find the number of bits needed to store the value as a signed value,
@@ -246,6 +367,20 @@
   ///
   /// The result is always equal to the mathematical result of this to the power
   /// [exponent], only limited by the available memory.
+  ///
+  /// Example:
+  /// ```dart
+  /// var value = BigInt.from(1000);
+  /// print(value.pow(0)); // 1
+  /// print(value.pow(1)); // 1000
+  /// print(value.pow(2)); // 1000000
+  /// print(value.pow(3)); // 1000000000
+  /// print(value.pow(4)); // 1000000000000
+  /// print(value.pow(5)); // 1000000000000000
+  /// print(value.pow(6)); // 1000000000000000000
+  /// print(value.pow(7)); // 1000000000000000000000
+  /// print(value.pow(8)); // 1000000000000000000000000
+  /// ```
   BigInt pow(int exponent);
 
   /// Returns this integer to the power of [exponent] modulo [modulus].
@@ -269,15 +404,24 @@
   /// integer dividing both `this` and `other`.
   ///
   /// The greatest common divisor is independent of the order,
-  /// so `x.gcd(y)` is  always the same as `y.gcd(x)`.
+  /// so `x.gcd(y)` is always the same as `y.gcd(x)`.
   ///
   /// For any integer `x`, `x.gcd(x)` is `x.abs()`.
   ///
   /// If both `this` and `other` is zero, the result is also zero.
+  ///
+  /// Example:
+  /// ```dart
+  /// print(BigInt.from(4).gcd(BigInt.from(2))); // 2
+  /// print(BigInt.from(8).gcd(BigInt.from(4))); // 4
+  /// print(BigInt.from(10).gcd(BigInt.from(12))); // 2
+  /// print(BigInt.from(10).gcd(BigInt.from(10))); // 10
+  /// print(BigInt.from(-2).gcd(BigInt.from(-3))); // 1
+  /// ```
   BigInt gcd(BigInt other);
 
   /// Returns the least significant [width] bits of this big integer as a
-  /// non-negative number (i.e. unsigned representation).  The returned value has
+  /// non-negative number (i.e. unsigned representation). The returned value has
   /// zeros in all bit positions higher than [width].
   ///
   /// ```dart
@@ -294,7 +438,7 @@
   /// `q` will count from `0` up to `255` and then wrap around to `0`.
   ///
   /// If the input fits in [width] bits without truncation, the result is the
-  /// same as the input.  The minimum width needed to avoid truncation of `x` is
+  /// same as the input. The minimum width needed to avoid truncation of `x` is
   /// given by `x.bitLength`, i.e.
   ///
   /// ```dart
@@ -303,8 +447,8 @@
   BigInt toUnsigned(int width);
 
   /// Returns the least significant [width] bits of this integer, extending the
-  /// highest retained bit to the sign.  This is the same as truncating the value
-  /// to fit in [width] bits using an signed 2-s complement representation.  The
+  /// highest retained bit to the sign. This is the same as truncating the value
+  /// to fit in [width] bits using an signed 2-s complement representation. The
   /// returned value has the same bit value in all positions higher than [width].
   ///
   /// ```dart
@@ -328,7 +472,7 @@
   /// `127`.
   ///
   /// If the input value fits in [width] bits without truncation, the result is
-  /// the same as the input.  The minimum width needed to avoid truncation of `x`
+  /// the same as the input. The minimum width needed to avoid truncation of `x`
   /// is `x.bitLength + 1`, i.e.
   ///
   /// ```dart
@@ -339,9 +483,18 @@
   /// Whether this big integer can be represented as an `int` without losing
   /// precision.
   ///
-  /// Warning: this function may give a different result on
+  /// **Warning:** this function may give a different result on
   /// dart2js, dev compiler, and the VM, due to the differences in
   /// integer precision.
+  ///
+  /// Example:
+  /// ```dart
+  /// var bigNumber = BigInt.parse('100000000000000000000000');
+  /// print(bigNumber.isValidInt); // false
+  ///
+  /// var value = BigInt.parse('0xFF'); // 255
+  /// print(value.isValidInt); // true
+  /// ```
   bool get isValidInt;
 
   /// Returns this [BigInt] as an [int].
@@ -349,9 +502,15 @@
   /// If the number does not fit, clamps to the max (or min)
   /// integer.
   ///
-  /// Warning: the clamping behaves differently on dart2js, dev
-  /// compiler, and the VM, due to the differences in integer
-  /// precision.
+  /// **Warning:** the clamping behaves differently between the web and
+  /// native platforms due to the differences in integer precision.
+  ///
+  /// Example:
+  /// ```dart
+  /// var bigNumber = BigInt.parse('100000000000000000000000');
+  /// print(bigNumber.isValidInt); // false
+  /// print(bigNumber.toInt()); // 9223372036854775807
+  /// ```
   int toInt();
 
   /// Returns this [BigInt] as a [double].
@@ -359,6 +518,12 @@
   /// If the number is not representable as a [double], an
   /// approximation is returned. For numerically large integers, the
   /// approximation may be infinite.
+  ///
+  /// Example:
+  /// ```dart
+  /// var bigNumber = BigInt.parse('100000000000000000000000');
+  /// print(bigNumber.toDouble()); // 1e+23
+  /// ```
   double toDouble();
 
   /// Returns a String-representation of this integer.
@@ -366,6 +531,12 @@
   /// The returned string is parsable by [parse].
   /// For any `BigInt` `i`, it is guaranteed that
   /// `i == BigInt.parse(i.toString())`.
+  ///
+  /// Example:
+  /// ```dart
+  /// var bigNumber = BigInt.parse('100000000000000000000000');
+  /// print(bigNumber.toString()); // "100000000000000000000000"
+  /// ```
   String toString();
 
   /// Converts [this] to a string representation in the given [radix].
@@ -374,5 +545,24 @@
   /// '9', with 'a' being 10 an 'z' being 35.
   ///
   /// The [radix] argument must be an integer in the range 2 to 36.
+  ///
+  /// Example:
+  /// ```dart
+  /// // Binary (base 2).
+  /// print(BigInt.from(12).toRadixString(2)); // 1100
+  /// print(BigInt.from(31).toRadixString(2)); // 11111
+  /// print(BigInt.from(2021).toRadixString(2)); // 11111100101
+  /// print(BigInt.from(-12).toRadixString(2)); // -1100
+  /// // Octal (base 8).
+  /// print(BigInt.from(12).toRadixString(8)); // 14
+  /// print(BigInt.from(31).toRadixString(8)); // 37
+  /// print(BigInt.from(2021).toRadixString(8)); // 3745
+  /// // Hexadecimal (base 16).
+  /// print(BigInt.from(12).toRadixString(16)); // c
+  /// print(BigInt.from(31).toRadixString(16)); // 1f
+  /// print(BigInt.from(2021).toRadixString(16)); // 7e5
+  /// // Base 36.
+  /// print(BigInt.from(35 * 36 + 1).toRadixString(36)); // z1
+  /// ```
   String toRadixString(int radix);
 }
diff --git a/sdk/lib/core/identical.dart b/sdk/lib/core/identical.dart
index a8bdedf..c13ab27 100644
--- a/sdk/lib/core/identical.dart
+++ b/sdk/lib/core/identical.dart
@@ -5,6 +5,18 @@
 part of dart.core;
 
 /// Check whether two references are to the same object.
+///
+/// Example:
+/// ```dart
+/// var o = new Object();
+/// var isIdentical = identical(o, new Object()); // false, different objects.
+/// isIdentical = identical(o, o); // true, same object
+/// isIdentical = identical(const Object(), const Object()); // true, const canonicalizes
+/// isIdentical = identical([1], [1]); // false
+/// isIdentical = identical(const [1], const [1]); // true
+/// isIdentical = identical(const [1], const [2]); // false
+/// isIdentical = identical(2, 1 + 1); // true, integers canonicalizes
+/// ```
 external bool identical(Object? a, Object? b);
 
 /// The identity hash code of [object].
@@ -14,5 +26,14 @@
 ///
 /// This hash code is compatible with [identical],
 /// which just means that it's guaranteed to be stable over time.
+/// ```dart import:dart:collection
+/// var identitySet = HashSet(equals: identical, hashCode: identityHashCode);
+/// var dt1 = DateTime.now();
+/// var dt2 = DateTime.fromMicrosecondsSinceEpoch(dt1.microsecondsSinceEpoch);
+/// assert(dt1 == dt2);
+/// identitySet.add(dt1);
+/// print(identitySet.contains(dt1)); // true
+/// print(identitySet.contains(dt2)); // false
+/// ```
 @pragma("vm:entry-point")
 external int identityHashCode(Object? object);
diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart
index f6c6caf..ae091be 100644
--- a/sdk/lib/core/map.dart
+++ b/sdk/lib/core/map.dart
@@ -451,11 +451,32 @@
 }
 
 /// A key/value pair representing an entry in a [Map].
+///
+/// The [Map] interface contains various methods that can
+/// inspect or modify the map based on entry objects.
+/// ```dart
+/// final map = {'1': 'A', '2': 'B'};
+/// map.addEntries([
+///  MapEntry('3', 'C'),
+///  MapEntry('4', 'D'),
+/// ]);
+/// print(map); // {1: A, 2: B, 3: C, 4: D}
+/// ```
 class MapEntry<K, V> {
   /// The key of the entry.
+  /// ```dart
+  /// final map = {'theKey': 'theValue'};
+  /// var entry = map.entries.first;
+  /// print(entry.key); // theKey
+  /// ```
   final K key;
 
   /// The value associated to [key] in the map.
+  /// ```dart
+  /// final map = {'theKey': 'theValue'};
+  /// var entry = map.entries.first;
+  /// print(entry.value); // theValue
+  /// ```
   final V value;
 
   /// Creates an entry with [key] and [value].
diff --git a/tools/VERSION b/tools/VERSION
index 0b7b793..dbe4c2a 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 5
+PRERELEASE 6
 PRERELEASE_PATCH 0
\ No newline at end of file