[cfe] Patch declarations through fragments

Change-Id: I942f2b0b08e69012140d4671722411c86b073504
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/413681
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
diff --git a/pkg/front_end/lib/src/base/name_space.dart b/pkg/front_end/lib/src/base/name_space.dart
index 0410f0a..0f06f34 100644
--- a/pkg/front_end/lib/src/base/name_space.dart
+++ b/pkg/front_end/lib/src/base/name_space.dart
@@ -172,6 +172,7 @@
   }
 
   @override
+  // Coverage-ignore(suite): Not run.
   void forEachLocalMember(void Function(String name, Builder member) f) {
     if (_getables != null) {
       for (MapEntry<String, Builder> entry in _getables!.entries) {
@@ -181,6 +182,7 @@
   }
 
   @override
+  // Coverage-ignore(suite): Not run.
   void forEachLocalSetter(void Function(String name, MemberBuilder member) f) {
     if (_setables != null) {
       for (MapEntry<String, MemberBuilder> entry in _setables!.entries) {
diff --git a/pkg/front_end/lib/src/base/scope.dart b/pkg/front_end/lib/src/base/scope.dart
index 0fe5faa..f59d26a 100644
--- a/pkg/front_end/lib/src/base/scope.dart
+++ b/pkg/front_end/lib/src/base/scope.dart
@@ -19,12 +19,8 @@
 import '../kernel/type_algorithms.dart';
 import '../source/source_class_builder.dart';
 import '../source/source_extension_builder.dart';
-import '../source/source_extension_type_declaration_builder.dart';
-import '../source/source_function_builder.dart';
 import '../source/source_library_builder.dart';
 import '../source/source_member_builder.dart';
-import '../source/source_method_builder.dart';
-import '../source/source_property_builder.dart';
 import 'messages.dart';
 import 'name_space.dart';
 import 'uri_offset.dart';
@@ -1228,354 +1224,7 @@
   }
 }
 
-abstract class MergedScope<T extends Builder> {
-  final T _origin;
-  final NameSpace _originNameSpace;
-  Map<T, NameSpace> _augmentationNameSpaces = {};
-
-  MergedScope(this._origin, this._originNameSpace);
-
-  SourceLibraryBuilder get originLibrary;
-
-  // Coverage-ignore(suite): Not run.
-  void _addBuilderToMergedScope(
-      String name, Builder newBuilder, Builder? existingBuilder,
-      {required bool setter, required bool inPatchLibrary}) {
-    bool isAugmentationBuilder = inPatchLibrary
-        ? newBuilder.hasPatchAnnotation
-        : newBuilder.isAugmentation;
-    if (existingBuilder != null) {
-      if (isAugmentationBuilder) {
-        existingBuilder.applyAugmentation(newBuilder);
-      } else {
-        newBuilder.isConflictingAugmentationMember = true;
-        Message message;
-        Message context;
-        if (newBuilder is SourceMemberBuilder &&
-            existingBuilder is SourceMemberBuilder) {
-          if (_origin is SourceLibraryBuilder) {
-            message = inPatchLibrary
-                ? templateNonPatchLibraryMemberConflict.withArguments(name)
-                : templateNonAugmentationLibraryMemberConflict
-                    .withArguments(name);
-          } else {
-            message = inPatchLibrary
-                ? templateNonPatchClassMemberConflict.withArguments(name)
-                : templateNonAugmentationClassMemberConflict
-                    .withArguments(name);
-          }
-          context = messageNonAugmentationMemberConflictCause;
-        } else if (newBuilder is SourceClassBuilder &&
-            existingBuilder is SourceClassBuilder) {
-          message = inPatchLibrary
-              ? templateNonPatchClassConflict.withArguments(name)
-              : templateNonAugmentationClassConflict.withArguments(name);
-          context = messageNonAugmentationClassConflictCause;
-        } else {
-          if (_origin is SourceLibraryBuilder) {
-            message = inPatchLibrary
-                ? templateNonPatchLibraryConflict.withArguments(name)
-                : templateNonAugmentationLibraryConflict.withArguments(name);
-          } else {
-            message = inPatchLibrary
-                ? templateNonPatchClassMemberConflict.withArguments(name)
-                : templateNonAugmentationClassMemberConflict
-                    .withArguments(name);
-          }
-          context = messageNonAugmentationMemberConflictCause;
-        }
-        originLibrary.addProblem(
-            message, newBuilder.fileOffset, name.length, newBuilder.fileUri,
-            context: [
-              context.withLocation(existingBuilder.fileUri!,
-                  existingBuilder.fileOffset, name.length)
-            ]);
-      }
-    } else {
-      if (isAugmentationBuilder) {
-        Message message;
-        if (newBuilder is SourceMemberBuilder) {
-          if (_origin is SourceLibraryBuilder) {
-            message = inPatchLibrary
-                ? templateUnmatchedPatchLibraryMember.withArguments(name)
-                : templateUnmatchedAugmentationLibraryMember
-                    .withArguments(name);
-          } else {
-            message = inPatchLibrary
-                ? templateUnmatchedPatchClassMember.withArguments(name)
-                : templateUnmatchedAugmentationClassMember.withArguments(name);
-          }
-        } else if (newBuilder is SourceClassBuilder) {
-          message = inPatchLibrary
-              ? templateUnmatchedPatchClass.withArguments(name)
-              : templateUnmatchedAugmentationClass.withArguments(name);
-        } else {
-          message = inPatchLibrary
-              ? templateUnmatchedPatchDeclaration.withArguments(name)
-              : templateUnmatchedAugmentationDeclaration.withArguments(name);
-        }
-        originLibrary.addProblem(
-            message, newBuilder.fileOffset, name.length, newBuilder.fileUri);
-      } else {
-        if (inPatchLibrary &&
-            !name.startsWith('_') &&
-            !_allowInjectedPublicMember(newBuilder)) {
-          originLibrary.addProblem(
-              templatePatchInjectionFailed.withArguments(
-                  name, originLibrary.importUri),
-              newBuilder.fileOffset,
-              noLength,
-              newBuilder.fileUri);
-        }
-        _originNameSpace.addLocalMember(name, newBuilder, setter: setter);
-        if (newBuilder is ExtensionBuilder) {
-          _originNameSpace.addExtension(newBuilder);
-        }
-        for (NameSpace augmentationNameSpace
-            in _augmentationNameSpaces.values) {
-          _addBuilderToAugmentationNameSpace(
-              augmentationNameSpace, name, newBuilder,
-              setter: setter);
-        }
-      }
-    }
-  }
-
-  void _addBuilderToAugmentationNameSpace(
-      NameSpace augmentationNameSpace, String name, Builder member,
-      {required bool setter}) {
-    Builder? augmentationMember =
-        augmentationNameSpace.lookupLocalMember(name, setter: setter);
-    if (augmentationMember == null) {
-      augmentationNameSpace.addLocalMember(name, member, setter: setter);
-      if (member is ExtensionBuilder) {
-        // Coverage-ignore-block(suite): Not run.
-        augmentationNameSpace.addExtension(member);
-      }
-    }
-  }
-
-  void _addAugmentationScope(T parentBuilder, NameSpace nameSpace,
-      {required Map<String, List<Builder>>? augmentations,
-      required Map<String, List<Builder>>? setterAugmentations,
-      required bool inPatchLibrary}) {
-    // TODO(johnniwinther): Use `scope.filteredNameIterator` instead of
-    // `scope.forEachLocalMember`/`scope.forEachLocalSetter`.
-
-    // Include all augmentation scope members to the origin scope.
-    nameSpace.forEachLocalMember(
-        // Coverage-ignore(suite): Not run.
-        (String name, Builder member) {
-      // In case of duplicates we use the first declaration.
-      while (member.isDuplicate) {
-        member = member.next!;
-      }
-      _addBuilderToMergedScope(
-          name, member, _originNameSpace.lookupLocalMember(name, setter: false),
-          setter: false, inPatchLibrary: inPatchLibrary);
-    });
-    if (augmentations != null) {
-      // Coverage-ignore-block(suite): Not run.
-      for (String augmentedName in augmentations.keys) {
-        for (Builder augmentation in augmentations[augmentedName]!) {
-          _addBuilderToMergedScope(augmentedName, augmentation,
-              _originNameSpace.lookupLocalMember(augmentedName, setter: false),
-              setter: false, inPatchLibrary: inPatchLibrary);
-        }
-      }
-    }
-    nameSpace.forEachLocalSetter(
-        // Coverage-ignore(suite): Not run.
-        (String name, Builder member) {
-      // In case of duplicates we use the first declaration.
-      while (member.isDuplicate) {
-        member = member.next!;
-      }
-      _addBuilderToMergedScope(
-          name, member, _originNameSpace.lookupLocalMember(name, setter: true),
-          setter: true, inPatchLibrary: inPatchLibrary);
-    });
-    if (setterAugmentations != null) {
-      // Coverage-ignore-block(suite): Not run.
-      for (String augmentedName in setterAugmentations.keys) {
-        for (Builder augmentation in setterAugmentations[augmentedName]!) {
-          _addBuilderToMergedScope(augmentedName, augmentation,
-              _originNameSpace.lookupLocalMember(augmentedName, setter: true),
-              setter: true, inPatchLibrary: inPatchLibrary);
-        }
-      }
-    }
-    nameSpace.forEachLocalExtension(
-        // Coverage-ignore(suite): Not run.
-        (ExtensionBuilder extensionBuilder) {
-      if (extensionBuilder is SourceExtensionBuilder &&
-          extensionBuilder.isUnnamedExtension) {
-        _originNameSpace.addExtension(extensionBuilder);
-        for (NameSpace augmentationNameSpace
-            in _augmentationNameSpaces.values) {
-          augmentationNameSpace.addExtension(extensionBuilder);
-        }
-      }
-    });
-
-    // Include all origin scope members in the augmentation scope.
-    _originNameSpace.forEachLocalMember((String name, Builder originMember) {
-      _addBuilderToAugmentationNameSpace(nameSpace, name, originMember,
-          setter: false);
-    });
-    _originNameSpace.forEachLocalSetter((String name, Builder originMember) {
-      _addBuilderToAugmentationNameSpace(nameSpace, name, originMember,
-          setter: true);
-    });
-    _originNameSpace.forEachLocalExtension(
-        // Coverage-ignore(suite): Not run.
-        (ExtensionBuilder extensionBuilder) {
-      if (extensionBuilder is SourceExtensionBuilder &&
-          extensionBuilder.isUnnamedExtension) {
-        nameSpace.addExtension(extensionBuilder);
-      }
-    });
-
-    _augmentationNameSpaces[parentBuilder] = nameSpace;
-  }
-
-  bool _allowInjectedPublicMember(Builder newBuilder);
-}
-
-class MergedClassMemberScope extends MergedScope<SourceClassBuilder> {
-  final DeclarationNameSpace _originConstructorNameSpace;
-  Map<SourceClassBuilder, DeclarationNameSpace>
-      _augmentationConstructorNameSpaces = {};
-
-  MergedClassMemberScope(SourceClassBuilder origin)
-      : _originConstructorNameSpace = origin.nameSpace,
-        super(origin, origin.nameSpace);
-
-  @override
-  // Coverage-ignore(suite): Not run.
-  SourceLibraryBuilder get originLibrary => _origin.libraryBuilder;
-
-  void _addAugmentationConstructorScope(DeclarationNameSpace nameSpace,
-      {required bool inPatchLibrary}) {
-    nameSpace.forEachConstructor(
-        // Coverage-ignore(suite): Not run.
-        (String name, MemberBuilder newConstructor) {
-      MemberBuilder? existingConstructor =
-          _originConstructorNameSpace.lookupConstructor(name);
-      bool isAugmentationBuilder = inPatchLibrary
-          ? newConstructor.hasPatchAnnotation
-          : newConstructor.isAugmentation;
-      if (existingConstructor != null) {
-        if (isAugmentationBuilder) {
-          existingConstructor.applyAugmentation(newConstructor);
-        } else {
-          newConstructor.isConflictingAugmentationMember = true;
-          originLibrary.addProblem(
-              inPatchLibrary
-                  ? templateNonPatchConstructorConflict
-                      .withArguments(newConstructor.fullNameForErrors)
-                  : templateNonAugmentationConstructorConflict
-                      .withArguments(newConstructor.fullNameForErrors),
-              newConstructor.fileOffset,
-              noLength,
-              newConstructor.fileUri,
-              context: [
-                messageNonAugmentationConstructorConflictCause.withLocation(
-                    existingConstructor.fileUri!,
-                    existingConstructor.fileOffset,
-                    noLength)
-              ]);
-        }
-      } else {
-        if (isAugmentationBuilder) {
-          originLibrary.addProblem(
-              inPatchLibrary
-                  ? templateUnmatchedPatchConstructor
-                      .withArguments(newConstructor.fullNameForErrors)
-                  : templateUnmatchedAugmentationConstructor
-                      .withArguments(newConstructor.fullNameForErrors),
-              newConstructor.fileOffset,
-              noLength,
-              newConstructor.fileUri);
-        } else {
-          _originConstructorNameSpace.addConstructor(name, newConstructor);
-          for (DeclarationNameSpace augmentationConstructorNameSpace
-              in _augmentationConstructorNameSpaces.values) {
-            _addConstructorToAugmentationScope(
-                augmentationConstructorNameSpace, name, newConstructor);
-          }
-        }
-        if (inPatchLibrary &&
-            !name.startsWith('_') &&
-            !_allowInjectedPublicMember(newConstructor)) {
-          originLibrary.addProblem(
-              templatePatchInjectionFailed.withArguments(
-                  name, originLibrary.importUri),
-              newConstructor.fileOffset,
-              noLength,
-              newConstructor.fileUri);
-        }
-      }
-    });
-    _originConstructorNameSpace
-        .forEachConstructor((String name, MemberBuilder originConstructor) {
-      _addConstructorToAugmentationScope(nameSpace, name, originConstructor);
-    });
-  }
-
-  void _addConstructorToAugmentationScope(
-      DeclarationNameSpace augmentationConstructorNameSpace,
-      String name,
-      MemberBuilder constructor) {
-    Builder? augmentationConstructor =
-        augmentationConstructorNameSpace.lookupConstructor(name);
-    if (augmentationConstructor == null) {
-      augmentationConstructorNameSpace.addConstructor(name, constructor);
-    }
-  }
-
-  // TODO(johnniwinther): Check for conflicts between constructors and class
-  //  members.
-  void addAugmentationScope(SourceClassBuilder builder) {
-    _addAugmentationScope(builder, builder.nameSpace,
-        augmentations: null,
-        setterAugmentations: null,
-        inPatchLibrary: builder.libraryBuilder.isPatchLibrary);
-    _addAugmentationConstructorScope(builder.nameSpace,
-        inPatchLibrary: builder.libraryBuilder.isPatchLibrary);
-  }
-
-  @override
-  // Coverage-ignore(suite): Not run.
-  bool _allowInjectedPublicMember(Builder newBuilder) {
-    if (originLibrary.importUri.isScheme("dart") &&
-        originLibrary.importUri.path.startsWith("_")) {
-      return true;
-    }
-    if (newBuilder.isStatic) {
-      return _origin.name.startsWith('_');
-    }
-    // TODO(johnniwinther): Restrict the use of injected public class members.
-    return true;
-  }
-}
-
 extension on Builder {
-  // Coverage-ignore(suite): Not run.
-  bool get isAugmentation {
-    Builder self = this;
-    if (self is SourceLibraryBuilder) {
-      return self.isAugmentationLibrary;
-    } else if (self is SourceClassBuilder) {
-      return self.isAugmentation;
-    } else if (self is SourceMemberBuilder) {
-      return self.isAugmentation;
-    } else {
-      // TODO(johnniwinther): Handle all cases here.
-      return false;
-    }
-  }
-
   bool get isConflictingAugmentationMember {
     Builder self = this;
     if (self is SourceMemberBuilder) {
@@ -1586,49 +1235,6 @@
     // TODO(johnniwinther): Handle all cases here.
     return false;
   }
-
-  // Coverage-ignore(suite): Not run.
-  void set isConflictingAugmentationMember(bool value) {
-    Builder self = this;
-    if (self is SourceMemberBuilder) {
-      self.isConflictingAugmentationMember = value;
-    } else if (self is SourceClassBuilder) {
-      self.isConflictingAugmentationMember = value;
-    }
-    // TODO(johnniwinther): Handle all cases here.
-  }
-
-  // Coverage-ignore(suite): Not run.
-  bool _hasPatchAnnotation(Iterable<MetadataBuilder>? metadata) {
-    if (metadata == null) {
-      return false;
-    }
-    for (MetadataBuilder metadataBuilder in metadata) {
-      if (metadataBuilder.hasPatch) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  // Coverage-ignore(suite): Not run.
-  bool get hasPatchAnnotation {
-    Builder self = this;
-    if (self is SourceFunctionBuilder) {
-      return _hasPatchAnnotation(self.metadata);
-    } else if (self is SourceClassBuilder) {
-      return _hasPatchAnnotation(self.metadata);
-    } else if (self is SourceExtensionBuilder) {
-      return _hasPatchAnnotation(self.metadata);
-    } else if (self is SourcePropertyBuilder) {
-      return _hasPatchAnnotation(self.metadata);
-    } else if (self is SourceMethodBuilder) {
-      return _hasPatchAnnotation(self.metadata);
-    } else if (self is SourceExtensionTypeDeclarationBuilder) {
-      return _hasPatchAnnotation(self.metadata);
-    }
-    return false;
-  }
 }
 
 class IteratorSequence<T> implements Iterator<T> {
diff --git a/pkg/front_end/lib/src/fragment/class/declaration.dart b/pkg/front_end/lib/src/fragment/class/declaration.dart
index 6d867e5..e5b0616 100644
--- a/pkg/front_end/lib/src/fragment/class/declaration.dart
+++ b/pkg/front_end/lib/src/fragment/class/declaration.dart
@@ -23,8 +23,11 @@
   void buildOutlineExpressions(
       {required Annotatable annotatable,
       required SourceLibraryBuilder libraryBuilder,
+      required ClassHierarchy classHierarchy,
       required BodyBuilderContext bodyBuilderContext,
       required bool createFileUriExpression});
+
+  int resolveConstructorReferences(SourceLibraryBuilder libraryBuilder);
 }
 
 class RegularClassDeclaration implements ClassDeclaration {
@@ -77,6 +80,7 @@
   void buildOutlineExpressions(
       {required Annotatable annotatable,
       required SourceLibraryBuilder libraryBuilder,
+      required ClassHierarchy classHierarchy,
       required BodyBuilderContext bodyBuilderContext,
       required bool createFileUriExpression}) {
     MetadataBuilder.buildAnnotations(
@@ -87,6 +91,21 @@
         _fragment.fileUri,
         _fragment.enclosingScope,
         createFileUriExpression: createFileUriExpression);
+
+    if (typeParameters != null) {
+      for (int i = 0; i < typeParameters!.length; i++) {
+        typeParameters![i].buildOutlineExpressions(libraryBuilder,
+            bodyBuilderContext, classHierarchy, _fragment.typeParameterScope);
+      }
+    }
+  }
+
+  @override
+  int resolveConstructorReferences(SourceLibraryBuilder libraryBuilder) {
+    for (ConstructorReferenceBuilder ref in _fragment.constructorReferences) {
+      ref.resolveIn(bodyScope, libraryBuilder);
+    }
+    return _fragment.constructorReferences.length;
   }
 }
 
@@ -140,6 +159,7 @@
   void buildOutlineExpressions(
       {required Annotatable annotatable,
       required SourceLibraryBuilder libraryBuilder,
+      required ClassHierarchy classHierarchy,
       required BodyBuilderContext bodyBuilderContext,
       required bool createFileUriExpression}) {
     MetadataBuilder.buildAnnotations(
@@ -150,6 +170,21 @@
         _fragment.fileUri,
         _fragment.enclosingScope,
         createFileUriExpression: createFileUriExpression);
+
+    if (typeParameters != null) {
+      for (int i = 0; i < typeParameters!.length; i++) {
+        typeParameters![i].buildOutlineExpressions(libraryBuilder,
+            bodyBuilderContext, classHierarchy, _fragment.typeParameterScope);
+      }
+    }
+  }
+
+  @override
+  int resolveConstructorReferences(SourceLibraryBuilder libraryBuilder) {
+    for (ConstructorReferenceBuilder ref in _fragment.constructorReferences) {
+      ref.resolveIn(bodyScope, libraryBuilder);
+    }
+    return _fragment.constructorReferences.length;
   }
 }
 
@@ -204,6 +239,7 @@
   void buildOutlineExpressions(
       {required Annotatable annotatable,
       required SourceLibraryBuilder libraryBuilder,
+      required ClassHierarchy classHierarchy,
       required BodyBuilderContext bodyBuilderContext,
       required bool createFileUriExpression}) {
     MetadataBuilder.buildAnnotations(
@@ -214,6 +250,18 @@
         _fragment.fileUri,
         _fragment.enclosingScope,
         createFileUriExpression: createFileUriExpression);
+
+    if (typeParameters != null) {
+      for (int i = 0; i < typeParameters!.length; i++) {
+        typeParameters![i].buildOutlineExpressions(libraryBuilder,
+            bodyBuilderContext, classHierarchy, _fragment.typeParameterScope);
+      }
+    }
+  }
+
+  @override
+  int resolveConstructorReferences(SourceLibraryBuilder libraryBuilder) {
+    return 0;
   }
 }
 
@@ -274,8 +322,14 @@
   void buildOutlineExpressions(
       {required Annotatable annotatable,
       required SourceLibraryBuilder libraryBuilder,
+      required ClassHierarchy classHierarchy,
       required BodyBuilderContext bodyBuilderContext,
       required bool createFileUriExpression}) {}
+
+  @override
+  int resolveConstructorReferences(SourceLibraryBuilder libraryBuilder) {
+    return 0;
+  }
 }
 
 class MixinDeclaration implements ClassDeclaration {
@@ -329,6 +383,7 @@
   void buildOutlineExpressions(
       {required Annotatable annotatable,
       required SourceLibraryBuilder libraryBuilder,
+      required ClassHierarchy classHierarchy,
       required BodyBuilderContext bodyBuilderContext,
       required bool createFileUriExpression}) {
     MetadataBuilder.buildAnnotations(
@@ -339,5 +394,21 @@
         _fragment.fileUri,
         _fragment.enclosingScope,
         createFileUriExpression: createFileUriExpression);
+
+    if (typeParameters != null) {
+      for (int i = 0; i < typeParameters!.length; i++) {
+        typeParameters![i].buildOutlineExpressions(libraryBuilder,
+            bodyBuilderContext, classHierarchy, _fragment.typeParameterScope);
+      }
+    }
+  }
+
+  @override
+  int resolveConstructorReferences(SourceLibraryBuilder libraryBuilder) {
+    for (ConstructorReferenceBuilder ref in _fragment.constructorReferences) {
+      // Coverage-ignore-block(suite): Not run.
+      ref.resolveIn(bodyScope, libraryBuilder);
+    }
+    return _fragment.constructorReferences.length;
   }
 }
diff --git a/pkg/front_end/lib/src/fragment/named_mixin_application.dart b/pkg/front_end/lib/src/fragment/named_mixin_application.dart
index 49dc3e1..a1c1ca5 100644
--- a/pkg/front_end/lib/src/fragment/named_mixin_application.dart
+++ b/pkg/front_end/lib/src/fragment/named_mixin_application.dart
@@ -15,6 +15,7 @@
   final Modifiers modifiers;
   final List<MetadataBuilder>? metadata;
   final List<TypeParameterFragment>? typeParameters;
+  final LookupScope typeParameterScope;
   final TypeBuilder? supertype;
   final List<TypeBuilder> mixins;
   final List<TypeBuilder>? interfaces;
@@ -32,6 +33,7 @@
       required this.modifiers,
       required this.metadata,
       required this.typeParameters,
+      required this.typeParameterScope,
       required this.supertype,
       required this.mixins,
       required this.interfaces,
diff --git a/pkg/front_end/lib/src/source/builder_factory.dart b/pkg/front_end/lib/src/source/builder_factory.dart
index 521d669..21cbb25 100644
--- a/pkg/front_end/lib/src/source/builder_factory.dart
+++ b/pkg/front_end/lib/src/source/builder_factory.dart
@@ -13,6 +13,7 @@
 import '../base/identifiers.dart' show Identifier;
 import '../base/import.dart';
 import '../base/modifiers.dart';
+import '../base/scope.dart';
 import '../builder/constructor_reference_builder.dart';
 import '../builder/declaration_builders.dart';
 import '../builder/formal_parameter_builder.dart';
@@ -97,7 +98,10 @@
   void beginNamedMixinApplication(
       String name, int charOffset, List<TypeParameterFragment>? typeParameters);
 
-  void endNamedMixinApplication(String name);
+  // TODO(johnniwinther): Avoid returning the type parameter scope here. Should
+  // named mixin applications be created in the begin method, similar to the
+  // other declarations?
+  LookupScope endNamedMixinApplication(String name);
 
   void endNamedMixinApplicationForParserRecovery(
       List<TypeParameterFragment>? typeParameters);
diff --git a/pkg/front_end/lib/src/source/class_declaration.dart b/pkg/front_end/lib/src/source/class_declaration.dart
index 8a61f11..478c841 100644
--- a/pkg/front_end/lib/src/source/class_declaration.dart
+++ b/pkg/front_end/lib/src/source/class_declaration.dart
@@ -2,14 +2,10 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import '../base/problems.dart';
-import '../base/scope.dart';
 import '../builder/builder.dart';
-import '../builder/constructor_reference_builder.dart';
 import '../builder/declaration_builders.dart';
 import '../builder/member_builder.dart';
 import '../builder/name_iterator.dart';
-import 'source_factory_builder.dart';
 import 'source_library_builder.dart';
 
 /// Common interface for builders for a class declarations in source code, such
@@ -83,52 +79,6 @@
   Iterator<T> localConstructorIterator<T extends MemberBuilder>();
 }
 
-mixin ClassDeclarationBuilderMixin implements ClassDeclarationBuilder {
-  List<ConstructorReferenceBuilder> get constructorReferences;
-
-  List<ClassDeclarationBuilderMixin>? get augmentations;
-
-  LookupScope get bodyScope;
-
-  int resolveConstructorReferences(SourceLibraryBuilder library) {
-    int count = 0;
-    if (constructorReferences.isNotEmpty) {
-      for (ConstructorReferenceBuilder ref in constructorReferences) {
-        ref.resolveIn(bodyScope, library);
-      }
-    }
-    List<ClassDeclarationBuilderMixin>? augmentations = this.augmentations;
-    if (augmentations != null) {
-      for (ClassDeclarationBuilderMixin augmentation in augmentations) {
-        count += augmentation.resolveConstructorReferences(library);
-      }
-    }
-    return count;
-  }
-
-  void resolveConstructorRedirections() {
-    Iterator<MemberBuilder> iterator = nameSpace.filteredConstructorIterator(
-        parent: null, includeDuplicates: true, includeAugmentations: false);
-    while (iterator.moveNext()) {
-      MemberBuilder declaration = iterator.current;
-      if (declaration.declarationBuilder?.origin != origin) {
-        unexpected("$fileUri", "${declaration.declarationBuilder!.fileUri}",
-            fileOffset, fileUri);
-      }
-      if (declaration is SourceFactoryBuilder) {
-        declaration.resolveRedirectingFactory();
-      }
-    }
-  }
-
-  @override
-  int resolveConstructors(SourceLibraryBuilder library) {
-    int count = resolveConstructorReferences(library);
-    resolveConstructorRedirections();
-    return count;
-  }
-}
-
 abstract class ClassDeclarationAugmentationAccess<
     D extends ClassDeclarationBuilder> {
   D getOrigin(D classDeclaration);
@@ -145,8 +95,12 @@
   factory ClassDeclarationMemberIterator.full(
       ClassDeclarationAugmentationAccess<D> access, D classBuilder,
       {required bool includeDuplicates}) {
-    return new ClassDeclarationMemberIterator._(access.getOrigin(classBuilder),
-        access.getAugmentations(classBuilder)?.iterator,
+    return new ClassDeclarationMemberIterator._(
+        access.getOrigin(classBuilder),
+        access
+            .getAugmentations(classBuilder)
+            // Coverage-ignore(suite): Not run.
+            ?.iterator,
         includeDuplicates: includeDuplicates);
   }
 
@@ -172,7 +126,10 @@
         return true;
       }
     }
-    if (augmentationBuilders != null && augmentationBuilders!.moveNext()) {
+    if (augmentationBuilders != null &&
+        // Coverage-ignore(suite): Not run.
+        augmentationBuilders!.moveNext()) {
+      // Coverage-ignore-block(suite): Not run.
       D augmentationClassDeclaration = augmentationBuilders!.current;
       _iterator = augmentationClassDeclaration.nameSpace.filteredIterator<T>(
           parent: augmentationClassDeclaration,
@@ -258,7 +215,10 @@
       {required bool includeDuplicates}) {
     return new ClassDeclarationConstructorIterator._(
         access.getOrigin(classBuilder),
-        access.getAugmentations(classBuilder)?.iterator,
+        access
+            .getAugmentations(classBuilder)
+            // Coverage-ignore(suite): Not run.
+            ?.iterator,
         includeDuplicates: includeDuplicates);
   }
 
@@ -284,7 +244,10 @@
         return true;
       }
     }
-    if (augmentationBuilders != null && augmentationBuilders!.moveNext()) {
+    if (augmentationBuilders != null &&
+        // Coverage-ignore(suite): Not run.
+        augmentationBuilders!.moveNext()) {
+      // Coverage-ignore-block(suite): Not run.
       D augmentationClassDeclaration = augmentationBuilders!.current;
       _iterator = augmentationClassDeclaration.nameSpace
           .filteredConstructorIterator<T>(
@@ -317,7 +280,10 @@
       {required bool includeDuplicates}) {
     return new ClassDeclarationConstructorNameIterator._(
         access.getOrigin(classDeclaration),
-        access.getAugmentations(classDeclaration)?.iterator,
+        access
+            .getAugmentations(classDeclaration)
+            // Coverage-ignore(suite): Not run.
+            ?.iterator,
         includeDuplicates: includeDuplicates);
   }
 
@@ -336,7 +302,10 @@
         return true;
       }
     }
-    if (augmentationBuilders != null && augmentationBuilders!.moveNext()) {
+    if (augmentationBuilders != null &&
+        // Coverage-ignore(suite): Not run.
+        augmentationBuilders!.moveNext()) {
+      // Coverage-ignore-block(suite): Not run.
       D augmentationClassDeclaration = augmentationBuilders!.current;
       _iterator = augmentationClassDeclaration.nameSpace
           .filteredConstructorNameIterator<T>(
diff --git a/pkg/front_end/lib/src/source/source_builder_factory.dart b/pkg/front_end/lib/src/source/source_builder_factory.dart
index fc9ed2d..fbde17f 100644
--- a/pkg/front_end/lib/src/source/source_builder_factory.dart
+++ b/pkg/front_end/lib/src/source/source_builder_factory.dart
@@ -245,10 +245,11 @@
       List<TypeParameterFragment>? typeParameters) {}
 
   @override
-  void endNamedMixinApplication(String name) {
+  LookupScope endNamedMixinApplication(String name) {
     TypeScope typeParameterScope = _typeScopes.pop();
     assert(typeParameterScope.kind == TypeScopeKind.declarationTypeParameters,
         "Unexpected type scope: $typeParameterScope.");
+    return typeParameterScope.lookupScope;
   }
 
   @override
@@ -991,12 +992,14 @@
       required int nameOffset,
       required int endOffset}) {
     // Nested declaration began in `OutlineBuilder.beginNamedMixinApplication`.
-    endNamedMixinApplication(name);
+    LookupScope typeParameterScope = endNamedMixinApplication(name);
 
     assert(
         _mixinApplications != null, "Late registration of mixin application.");
 
-    _nominalParameterNameSpaces.pop().addTypeParameters(
+    NominalParameterNameSpace typeParameterNameSpace =
+        _nominalParameterNameSpaces.pop();
+    typeParameterNameSpace.addTypeParameters(
         _problemReporting, typeParameters?.builders,
         ownerName: name, allowNameConflict: false);
 
@@ -1009,6 +1012,7 @@
         modifiers: modifiers,
         metadata: metadata,
         typeParameters: typeParameters,
+        typeParameterScope: typeParameterScope,
         supertype: supertype,
         mixins: mixins,
         interfaces: interfaces,
diff --git a/pkg/front_end/lib/src/source/source_builder_mixins.dart b/pkg/front_end/lib/src/source/source_builder_mixins.dart
index cd25fde..ce6dd4f 100644
--- a/pkg/front_end/lib/src/source/source_builder_mixins.dart
+++ b/pkg/front_end/lib/src/source/source_builder_mixins.dart
@@ -15,8 +15,6 @@
 import '../builder/library_builder.dart';
 import '../builder/member_builder.dart';
 import '../builder/type_builder.dart';
-import '../kernel/body_builder_context.dart';
-import '../kernel/kernel_helper.dart';
 import '../kernel/type_algorithms.dart';
 import 'source_library_builder.dart';
 import 'source_loader.dart';
@@ -161,25 +159,6 @@
     });
   }
 
-  BodyBuilderContext createBodyBuilderContext();
-
-  void buildOutlineExpressions(ClassHierarchy classHierarchy,
-      List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
-    if (typeParameters != null) {
-      for (int i = 0; i < typeParameters!.length; i++) {
-        typeParameters![i].buildOutlineExpressions(libraryBuilder,
-            createBodyBuilderContext(), classHierarchy, typeParameterScope);
-      }
-    }
-
-    Iterator<SourceMemberBuilder> iterator = nameSpace.filteredIterator(
-        parent: this, includeDuplicates: false, includeAugmentations: true);
-    while (iterator.moveNext()) {
-      iterator.current
-          .buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners);
-    }
-  }
-
   void _buildMember(SourceMemberBuilder memberBuilder, Member member,
       Member? tearOff, BuiltMemberKind memberKind,
       {required bool addMembersToLibrary}) {
@@ -229,9 +208,6 @@
       Reference memberReference,
       Reference? tearOffReference);
 
-  /// The scope in which the [typeParameters] are declared.
-  LookupScope get typeParameterScope;
-
   @override
   List<DartType> buildAliasedTypeArguments(LibraryBuilder library,
       List<TypeBuilder>? arguments, ClassHierarchyBase? hierarchy) {
diff --git a/pkg/front_end/lib/src/source/source_class_builder.dart b/pkg/front_end/lib/src/source/source_class_builder.dart
index dd50324..6a2aacd 100644
--- a/pkg/front_end/lib/src/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/source/source_class_builder.dart
@@ -27,7 +27,6 @@
 import '../base/scope.dart';
 import '../builder/augmentation_iterator.dart';
 import '../builder/builder.dart';
-import '../builder/constructor_reference_builder.dart';
 import '../builder/declaration_builders.dart';
 import '../builder/formal_parameter_builder.dart';
 import '../builder/library_builder.dart';
@@ -90,7 +89,6 @@
 }
 
 class SourceClassBuilder extends ClassBuilderImpl
-    with ClassDeclarationBuilderMixin
     implements
         Comparable<SourceClassBuilder>,
         ClassDeclarationBuilder,
@@ -108,7 +106,8 @@
 
   final Modifiers _modifiers;
 
-  final Class actualCls;
+  @override
+  final Class cls;
 
   final DeclarationNameSpaceBuilder nameSpaceBuilder;
 
@@ -124,9 +123,6 @@
 
   List<TypeBuilder>? _interfaceBuilders;
 
-  @override
-  final List<ConstructorReferenceBuilder> constructorReferences;
-
   TypeBuilder? _mixedInTypeBuilder;
 
   final IndexedClass? indexedClass;
@@ -146,11 +142,8 @@
     _isConflictingAugmentationMember = value;
   }
 
-  List<SourceClassBuilder>? _augmentations;
-
-  MergedClassMemberScope? _mergedScope;
-
   final ClassDeclaration _introductory;
+  List<ClassDeclaration> _augmentations;
 
   SourceClassBuilder(
       {required Modifiers modifiers,
@@ -159,36 +152,50 @@
       required this.typeParameterScope,
       required this.nameSpaceBuilder,
       required this.libraryBuilder,
-      required this.constructorReferences,
       required this.fileUri,
       required this.nameOffset,
       this.indexedClass,
       TypeBuilder? mixedInTypeBuilder,
-      required ClassDeclaration classDeclaration})
+      required ClassDeclaration introductory,
+      List<ClassDeclaration> augmentations = const []})
       : _modifiers = modifiers,
-        _introductory = classDeclaration,
+        _introductory = introductory,
+        _augmentations = augmentations,
         _mixedInTypeBuilder = mixedInTypeBuilder,
-        actualCls = initializeClass(
+        cls = initializeClass(
             typeParameters,
             name,
             fileUri,
-            classDeclaration.startOffset,
-            classDeclaration.nameOffset,
-            classDeclaration.endOffset,
+            introductory.startOffset,
+            introductory.nameOffset,
+            introductory.endOffset,
             indexedClass,
             isAugmentation: modifiers.isAugment) {
-    actualCls.hasConstConstructor = declaresConstConstructor;
+    cls.hasConstConstructor = declaresConstConstructor;
   }
 
-  // TODO(johnniwinther): Remove this when augmentations are handled through
-  //  fragments.
   @override
-  List<SourceClassBuilder>? get augmentations => _augmentations;
-
-  // TODO(johnniwinther): Remove this when augmentations are handled through
-  //  fragments.
-  @override
-  LookupScope get bodyScope => _introductory.bodyScope;
+  int resolveConstructors(SourceLibraryBuilder libraryBuilder) {
+    int count = _introductory.resolveConstructorReferences(libraryBuilder);
+    for (ClassDeclaration augmentation in _augmentations) {
+      count += augmentation.resolveConstructorReferences(libraryBuilder);
+    }
+    if (count > 0) {
+      Iterator<MemberBuilder> iterator = nameSpace.filteredConstructorIterator(
+          parent: null, includeDuplicates: true, includeAugmentations: false);
+      while (iterator.moveNext()) {
+        MemberBuilder declaration = iterator.current;
+        if (declaration.declarationBuilder?.origin != origin) {
+          unexpected("$fileUri", "${declaration.declarationBuilder!.fileUri}",
+              fileOffset, fileUri);
+        }
+        if (declaration is SourceFactoryBuilder) {
+          declaration.resolveRedirectingFactory();
+        }
+      }
+    }
+    return count;
+  }
 
   @override
   int get fileOffset => nameOffset;
@@ -244,12 +251,6 @@
 
   @override
   void buildScopes(LibraryBuilder coreLibrary) {
-    List<SourceClassBuilder>? augmentations = _augmentations;
-    if (augmentations != null) {
-      for (SourceClassBuilder augmentation in augmentations) {
-        nameSpaceBuilder.includeBuilders(augmentation.nameSpaceBuilder);
-      }
-    }
     _nameSpace = nameSpaceBuilder.buildNameSpace(
         loader: libraryBuilder.loader,
         problemReporting: libraryBuilder,
@@ -259,25 +260,8 @@
         indexedContainer: indexedClass,
         containerType: ContainerType.Class,
         containerName: new ClassName(name));
-    if (augmentations != null) {
-      for (SourceClassBuilder augmentation in augmentations) {
-        augmentation.buildScopes(coreLibrary);
-        _applyAugmentation(augmentation);
-      }
-    }
   }
 
-  MergedClassMemberScope get mergedScope => _mergedScope ??= isAugmenting
-      ?
-      // Coverage-ignore(suite): Not run.
-      origin.mergedScope
-      : new MergedClassMemberScope(this);
-
-  // Coverage-ignore(suite): Not run.
-  List<SourceClassBuilder>? get augmentationsForTesting => _augmentations;
-
-  SourceClassBuilder? actualOrigin;
-
   bool _hasComputedSupertypes = false;
 
   void computeSupertypeBuilder({
@@ -382,10 +366,7 @@
   }
 
   @override
-  SourceClassBuilder get origin => actualOrigin ?? this;
-
-  @override
-  Class get cls => origin.actualCls;
+  SourceClassBuilder get origin => this;
 
   @override
   SourceLibraryBuilder get parent => libraryBuilder;
@@ -436,16 +417,16 @@
     Supertype? supertype = supertypeBuilder?.buildSupertype(libraryBuilder,
         isMixinDeclaration ? TypeUse.mixinOnType : TypeUse.classExtendsType);
     if (!isMixinDeclaration &&
-        actualCls.supertype != null &&
+        cls.supertype != null &&
         // Coverage-ignore(suite): Not run.
-        actualCls.superclass!.isMixinDeclaration) {
+        cls.superclass!.isMixinDeclaration) {
       // Coverage-ignore-block(suite): Not run.
       // Declared mixins have interfaces that can be implemented, but they
       // cannot be extended.  However, a mixin declaration with a single
       // superclass constraint is encoded with the constraint as the supertype,
       // and that is allowed to be a mixin's interface.
       libraryBuilder.addProblem(
-          templateSupertypeIsIllegal.withArguments(actualCls.superclass!.name),
+          templateSupertypeIsIllegal.withArguments(cls.superclass!.name),
           fileOffset,
           noLength,
           fileUri);
@@ -454,7 +435,7 @@
     if (supertype == null && _supertypeBuilder is! NamedTypeBuilder) {
       _supertypeBuilder = null;
     }
-    actualCls.supertype = supertype;
+    cls.supertype = supertype;
 
     if (_mixedInTypeBuilder != null) {
       _mixedInTypeBuilder = _checkSupertype(_mixedInTypeBuilder!);
@@ -463,13 +444,13 @@
         _mixedInTypeBuilder?.computeUnaliasedDeclaration(isUsedAsClass: false);
     if (LibraryBuilder.isFunction(mixedInDeclaration, coreLibrary)) {
       _mixedInTypeBuilder = null;
-      actualCls.isAnonymousMixin = false;
+      cls.isAnonymousMixin = false;
     }
     Supertype? mixedInType =
         _mixedInTypeBuilder?.buildMixedInType(libraryBuilder);
 
-    actualCls.isMixinDeclaration = isMixinDeclaration;
-    actualCls.mixedInType = mixedInType;
+    cls.isMixinDeclaration = isMixinDeclaration;
+    cls.mixedInType = mixedInType;
 
     // TODO(ahe): If `cls.supertype` is null, and this isn't Object, report a
     // compile-time error.
@@ -495,7 +476,7 @@
             .buildSupertype(libraryBuilder, TypeUse.classImplementsType);
         if (supertype != null) {
           // TODO(ahe): Report an error if supertype is null.
-          actualCls.implementedTypes.add(supertype);
+          cls.implementedTypes.add(supertype);
         }
       }
     }
@@ -540,17 +521,20 @@
           classHierarchy, delayedDefaultValueCloners);
     }
 
+    BodyBuilderContext bodyBuilderContext = createBodyBuilderContext();
     _introductory.buildOutlineExpressions(
-        annotatable: isAugmenting ? origin.cls : cls,
-        bodyBuilderContext: createBodyBuilderContext(),
+        annotatable: cls,
+        bodyBuilderContext: bodyBuilderContext,
         libraryBuilder: libraryBuilder,
+        classHierarchy: classHierarchy,
         createFileUriExpression: isAugmenting);
-
-    if (typeParameters != null) {
-      for (int i = 0; i < typeParameters!.length; i++) {
-        typeParameters![i].buildOutlineExpressions(libraryBuilder,
-            createBodyBuilderContext(), classHierarchy, typeParameterScope);
-      }
+    for (ClassDeclaration augmentation in _augmentations) {
+      augmentation.buildOutlineExpressions(
+          annotatable: cls,
+          bodyBuilderContext: bodyBuilderContext,
+          classHierarchy: classHierarchy,
+          libraryBuilder: libraryBuilder,
+          createFileUriExpression: true);
     }
 
     nameSpace
@@ -561,14 +545,6 @@
         .filteredIterator(
             parent: this, includeDuplicates: false, includeAugmentations: true)
         .forEach(build);
-
-    List<SourceClassBuilder>? augmentations = _augmentations;
-    if (augmentations != null) {
-      for (SourceClassBuilder augmentation in augmentations) {
-        augmentation.buildOutlineExpressions(
-            classHierarchy, delayedDefaultValueCloners);
-      }
-    }
   }
 
   @override
@@ -737,55 +713,6 @@
     return substitutionMap;
   }
 
-  @override
-  void addAugmentation(Builder augmentation) {
-    _addAugmentation(augmentation);
-  }
-
-  SourceClassBuilder? _addAugmentation(Builder augmentation) {
-    if (augmentation is SourceClassBuilder) {
-      augmentation.actualOrigin = this;
-      (_augmentations ??= []).add(augmentation);
-      return augmentation;
-    } else {
-      // Coverage-ignore-block(suite): Not run.
-      libraryBuilder.addProblem(messagePatchDeclarationMismatch,
-          augmentation.fileOffset, noLength, augmentation.fileUri, context: [
-        messagePatchDeclarationOrigin.withLocation(
-            fileUri, fileOffset, noLength)
-      ]);
-      return null;
-    }
-  }
-
-  @override
-  // Coverage-ignore(suite): Not run.
-  void applyAugmentation(Builder augmentation) {
-    SourceClassBuilder? classBuilder = _addAugmentation(augmentation);
-    if (classBuilder != null) {
-      _applyAugmentation(classBuilder);
-    }
-  }
-
-  void _applyAugmentation(SourceClassBuilder augmentation) {
-    mergedScope.addAugmentationScope(augmentation);
-
-    int originLength = typeParameters?.length ?? 0;
-    int augmentationLength = augmentation.typeParameters?.length ?? 0;
-    if (originLength != augmentationLength) {
-      // Coverage-ignore-block(suite): Not run.
-      augmentation.addProblem(messagePatchClassTypeParametersMismatch,
-          augmentation.fileOffset, noLength, context: [
-        messagePatchClassOrigin.withLocation(fileUri, fileOffset, noLength)
-      ]);
-    } else if (typeParameters != null) {
-      int count = 0;
-      for (NominalParameterBuilder t in augmentation.typeParameters!) {
-        typeParameters![count++].applyAugmentation(t);
-      }
-    }
-  }
-
   void checkSupertypes(
       CoreTypes coreTypes,
       ClassHierarchyBuilder hierarchyBuilder,
@@ -1402,9 +1329,7 @@
         // Coverage-ignore-block(suite): Not run.
         if (member is Field && member.isStatic ||
             member is Procedure && member.isStatic) {
-          member.name = new Name(
-              '${member.name}',
-              member.name.library);
+          member.name = new Name('${member.name}', member.name.library);
         } else {
           return;
         }
@@ -2169,8 +2094,7 @@
   /// Returns an iterator the origin class and all augmentations in application
   /// order.
   Iterator<SourceClassBuilder> get declarationIterator =>
-      new AugmentationIterator<SourceClassBuilder>(
-          origin, origin._augmentations);
+      new AugmentationIterator<SourceClassBuilder>(origin, null);
 
   @override
   // Coverage-ignore(suite): Not run.
@@ -2219,7 +2143,7 @@
   @override
   Iterable<SourceClassBuilder>? getAugmentations(
           SourceClassBuilder classDeclaration) =>
-      classDeclaration._augmentations;
+      null;
 }
 
 TypeBuilder? _applyMixins(
@@ -2403,12 +2327,11 @@
         typeParameterScope: typeParameterScope,
         nameSpaceBuilder: nameSpaceBuilder,
         libraryBuilder: enclosingLibraryBuilder,
-        constructorReferences: [],
         fileUri: fileUri,
         nameOffset: nameOffset,
         indexedClass: indexedClass,
         mixedInTypeBuilder: isMixinDeclaration ? null : mixin,
-        classDeclaration: classDeclaration);
+        introductory: classDeclaration);
     // TODO(ahe, kmillikin): Should always be true?
     // pkg/analyzer/test/src/summary/resynthesize_kernel_test.dart can't
     // handle that :(
diff --git a/pkg/front_end/lib/src/source/source_enum_builder.dart b/pkg/front_end/lib/src/source/source_enum_builder.dart
index 8eb6e25..376ef3b 100644
--- a/pkg/front_end/lib/src/source/source_enum_builder.dart
+++ b/pkg/front_end/lib/src/source/source_enum_builder.dart
@@ -15,7 +15,6 @@
 import '../base/modifiers.dart' show Modifiers;
 import '../base/scope.dart';
 import '../builder/builder.dart';
-import '../builder/constructor_reference_builder.dart';
 import '../builder/declaration_builders.dart';
 import '../builder/formal_parameter_builder.dart';
 import '../builder/library_builder.dart';
@@ -80,7 +79,6 @@
       required DeclarationNameSpaceBuilder nameSpaceBuilder,
       required List<EnumElementFragment> enumElements,
       required SourceLibraryBuilder libraryBuilder,
-      required List<ConstructorReferenceBuilder> constructorReferences,
       required Uri fileUri,
       required this.startOffset,
       required int nameOffset,
@@ -97,11 +95,10 @@
             typeParameterScope: typeParameterScope,
             nameSpaceBuilder: nameSpaceBuilder,
             libraryBuilder: libraryBuilder,
-            constructorReferences: constructorReferences,
             fileUri: fileUri,
             nameOffset: nameOffset,
             indexedClass: indexedClass,
-            classDeclaration: classDeclaration);
+            introductory: classDeclaration);
 
   factory SourceEnumBuilder(
       {required String name,
@@ -110,7 +107,6 @@
       required List<TypeBuilder>? interfaceBuilders,
       required List<EnumElementFragment> enumElements,
       required SourceLibraryBuilder libraryBuilder,
-      required List<ConstructorReferenceBuilder> constructorReferences,
       required Uri fileUri,
       required int startOffset,
       required int nameOffset,
@@ -127,7 +123,6 @@
         nameSpaceBuilder: nameSpaceBuilder,
         enumElements: enumElements,
         libraryBuilder: libraryBuilder,
-        constructorReferences: constructorReferences,
         fileUri: fileUri,
         startOffset: startOffset,
         nameOffset: nameOffset,
diff --git a/pkg/front_end/lib/src/source/source_extension_builder.dart b/pkg/front_end/lib/src/source/source_extension_builder.dart
index a16a8ad..a673fd0 100644
--- a/pkg/front_end/lib/src/source/source_extension_builder.dart
+++ b/pkg/front_end/lib/src/source/source_extension_builder.dart
@@ -8,19 +8,10 @@
 import '../base/modifiers.dart';
 import '../base/name_space.dart';
 import '../base/problems.dart';
-import '../base/scope.dart';
-import '../builder/builder.dart';
 import '../builder/declaration_builders.dart';
 import '../builder/library_builder.dart';
 import '../builder/metadata_builder.dart';
 import '../builder/type_builder.dart';
-import '../codes/cfe_codes.dart'
-    show
-        messagePatchDeclarationMismatch,
-        messagePatchDeclarationOrigin,
-        messagePatchExtensionOrigin,
-        messagePatchExtensionTypeParametersMismatch,
-        noLength;
 import '../fragment/fragment.dart';
 import '../kernel/body_builder_context.dart';
 import '../kernel/kernel_helper.dart';
@@ -33,7 +24,7 @@
 class SourceExtensionBuilder extends ExtensionBuilderImpl
     with SourceDeclarationBuilderMixin {
   @override
-  final SourceLibraryBuilder parent;
+  final SourceLibraryBuilder libraryBuilder;
 
   final int _nameOffset;
 
@@ -44,11 +35,6 @@
 
   late final Extension _extension;
 
-  SourceExtensionBuilder? _origin;
-  SourceExtensionBuilder? _augmentation;
-
-  MergedClassMemberScope? _mergedScope;
-
   final DeclarationNameSpaceBuilder _nameSpaceBuilder;
 
   late final DeclarationNameSpace _nameSpace;
@@ -57,9 +43,6 @@
   final List<NominalParameterBuilder>? typeParameters;
 
   @override
-  final LookupScope typeParameterScope;
-
-  @override
   final TypeBuilder onType;
 
   final ExtensionName extensionName;
@@ -68,29 +51,36 @@
 
   /// The `extension` declaration that introduces this extension. Subsequent
   /// extensions of the same name must be augmentations.
-  // TODO(johnniwinther): Add [_augmentations] field.
   final ExtensionFragment _introductory;
 
+  final List<ExtensionFragment> _augmentations;
+
   SourceExtensionBuilder(
       {required SourceLibraryBuilder enclosingLibraryBuilder,
       required this.fileUri,
       required int startOffset,
       required int nameOffset,
       required int endOffset,
-      required ExtensionFragment fragment,
+      required DeclarationNameSpaceBuilder nameSpaceBuilder,
+      required ExtensionFragment introductory,
+      required List<ExtensionFragment> augmentations,
       required Reference? reference})
-      : _introductory = fragment,
+      : _introductory = introductory,
+        _augmentations = augmentations,
         _reference = reference ?? new Reference(),
         _nameOffset = nameOffset,
-        parent = enclosingLibraryBuilder,
-        _modifiers = fragment.modifiers,
-        extensionName = fragment.extensionName,
-        typeParameters = fragment.typeParameters?.builders,
-        typeParameterScope = fragment.typeParameterScope,
-        onType = fragment.onType,
-        _nameSpaceBuilder = fragment.toDeclarationNameSpaceBuilder() {
+        libraryBuilder = enclosingLibraryBuilder,
+        _modifiers = introductory.modifiers,
+        extensionName = introductory.extensionName,
+        typeParameters = introductory.typeParameters?.builders,
+        onType = introductory.onType,
+        _nameSpaceBuilder = nameSpaceBuilder {
     _introductory.builder = this;
     _introductory.bodyScope.declarationBuilder = this;
+    for (ExtensionFragment augmentation in _augmentations) {
+      augmentation.builder = this;
+      augmentation.bodyScope.declarationBuilder = this;
+    }
 
     // TODO(johnniwinther): Move this to the [build] once augmentations are
     // handled through fragments.
@@ -130,15 +120,8 @@
   @override
   bool get isAugment => _modifiers.isAugment;
 
-  // Coverage-ignore(suite): Not run.
-  SourceExtensionBuilder? get augmentationForTesting => _augmentation;
-
   @override
   void buildScopes(LibraryBuilder coreLibrary) {
-    SourceExtensionBuilder? augmentation = _augmentation;
-    if (augmentation != null) {
-      _nameSpaceBuilder.includeBuilders(augmentation._nameSpaceBuilder);
-    }
     _nameSpace = _nameSpaceBuilder.buildNameSpace(
         loader: libraryBuilder.loader,
         problemReporting: libraryBuilder,
@@ -151,37 +134,23 @@
         containerType: ContainerType.Extension,
         containerName: extensionName,
         includeConstructors: false);
-    if (augmentation != null) {
-      augmentation.buildScopes(coreLibrary);
-      _applyAugmentation(augmentation);
-    }
   }
 
   @override
-  SourceLibraryBuilder get libraryBuilder =>
-      super.libraryBuilder as SourceLibraryBuilder;
+  SourceLibraryBuilder get parent => libraryBuilder;
 
   bool get isUnnamedExtension => extensionName.isUnnamedExtension;
 
   @override
-  SourceExtensionBuilder get origin => _origin ?? this;
-
-  // Coverage-ignore(suite): Not run.
-  // TODO(johnniwinther): Add merged scope for extensions.
-  MergedClassMemberScope get mergedScope => _mergedScope ??= isAugmenting
-      ? origin.mergedScope
-      : throw new UnimplementedError("SourceExtensionBuilder.mergedScope");
+  SourceExtensionBuilder get origin => this;
 
   @override
   Reference get reference => _reference;
 
   @override
-  Extension get extension {
-    return isAugmenting ? origin.extension : _extension;
-  }
+  Extension get extension => _extension;
 
-  @override
-  BodyBuilderContext createBodyBuilderContext() {
+  BodyBuilderContext _createBodyBuilderContext() {
     return new ExtensionBodyBuilderContext(this);
   }
 
@@ -204,23 +173,42 @@
     return _extension;
   }
 
-  @override
-  void buildOutlineExpressions(ClassHierarchy classHierarchy,
-      List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
+  void _buildOutlineExpressionsForFragment(ExtensionFragment fragment,
+      ClassHierarchy classHierarchy, BodyBuilderContext bodyBuilderContext) {
     MetadataBuilder.buildAnnotations(
         annotatable,
-        _introductory.metadata,
-        createBodyBuilderContext(),
+        fragment.metadata,
+        bodyBuilderContext,
         libraryBuilder,
-        _introductory.fileUri,
-        _introductory.enclosingScope);
+        fragment.fileUri,
+        fragment.enclosingScope);
 
-    super.buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners);
+    if (fragment.typeParameters != null) {
+      for (int i = 0; i < fragment.typeParameters!.length; i++) {
+        fragment.typeParameters![i].builder.buildOutlineExpressions(
+            libraryBuilder,
+            bodyBuilderContext,
+            classHierarchy,
+            fragment.typeParameterScope);
+      }
+    }
+  }
 
-    SourceExtensionBuilder? augmentation = _augmentation;
-    if (augmentation != null) {
-      augmentation.buildOutlineExpressions(
-          classHierarchy, delayedDefaultValueCloners);
+  void buildOutlineExpressions(ClassHierarchy classHierarchy,
+      List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
+    BodyBuilderContext bodyBuilderContext = _createBodyBuilderContext();
+    _buildOutlineExpressionsForFragment(
+        _introductory, classHierarchy, bodyBuilderContext);
+    for (ExtensionFragment augmentation in _augmentations) {
+      _buildOutlineExpressionsForFragment(
+          augmentation, classHierarchy, bodyBuilderContext);
+    }
+
+    Iterator<SourceMemberBuilder> iterator = nameSpace.filteredIterator(
+        parent: this, includeDuplicates: false, includeAugmentations: true);
+    while (iterator.moveNext()) {
+      iterator.current
+          .buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners);
     }
   }
 
@@ -286,69 +274,4 @@
         isStatic: memberBuilder.isStatic,
         kind: kind));
   }
-
-  @override
-  void addAugmentation(Builder augmentation) {
-    _addAugmentation(augmentation);
-  }
-
-  SourceExtensionBuilder? _addAugmentation(Builder augmentation) {
-    if (augmentation is SourceExtensionBuilder) {
-      augmentation._origin = this;
-      _augmentation = augmentation;
-      return augmentation;
-    } else {
-      // Coverage-ignore-block(suite): Not run.
-      libraryBuilder.addProblem(messagePatchDeclarationMismatch,
-          augmentation.fileOffset, noLength, augmentation.fileUri, context: [
-        messagePatchDeclarationOrigin.withLocation(
-            fileUri, fileOffset, noLength)
-      ]);
-      return null;
-    }
-  }
-
-  void _applyAugmentation(SourceExtensionBuilder augmentation) {
-    // TODO(johnniwinther): Check that on-type match with origin declaration.
-
-    int originLength = typeParameters?.length ?? 0;
-    int augmentationLength = augmentation.typeParameters?.length ?? 0;
-    if (originLength != augmentationLength) {
-      // Coverage-ignore-block(suite): Not run.
-      augmentation.addProblem(messagePatchExtensionTypeParametersMismatch,
-          augmentation.fileOffset, noLength, context: [
-        messagePatchExtensionOrigin.withLocation(fileUri, fileOffset, noLength)
-      ]);
-    } else if (typeParameters != null) {
-      int count = 0;
-      for (NominalParameterBuilder t in augmentation.typeParameters!) {
-        typeParameters![count++].applyAugmentation(t);
-      }
-    }
-    nameSpace.forEachLocalMember((String name, Builder member) {
-      Builder? memberAugmentation =
-          augmentation.nameSpace.lookupLocalMember(name, setter: false);
-      if (memberAugmentation != null) {
-        // Coverage-ignore-block(suite): Not run.
-        member.applyAugmentation(memberAugmentation);
-      }
-    });
-    nameSpace.forEachLocalSetter((String name, Builder member) {
-      Builder? memberAugmentation =
-          augmentation.nameSpace.lookupLocalMember(name, setter: true);
-      if (memberAugmentation != null) {
-        // Coverage-ignore-block(suite): Not run.
-        member.applyAugmentation(memberAugmentation);
-      }
-    });
-  }
-
-  @override
-  // Coverage-ignore(suite): Not run.
-  void applyAugmentation(Builder augmentation) {
-    SourceExtensionBuilder? extensionBuilder = _addAugmentation(augmentation);
-    if (extensionBuilder != null) {
-      _applyAugmentation(extensionBuilder);
-    }
-  }
 }
diff --git a/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart b/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart
index 17e2392c..5571675 100644
--- a/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart
+++ b/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart
@@ -13,7 +13,6 @@
 import '../base/modifiers.dart';
 import '../base/name_space.dart';
 import '../base/problems.dart';
-import '../base/scope.dart';
 import '../builder/augmentation_iterator.dart';
 import '../builder/builder.dart';
 import '../builder/constructor_reference_builder.dart';
@@ -42,7 +41,7 @@
 
 class SourceExtensionTypeDeclarationBuilder
     extends ExtensionTypeDeclarationBuilderImpl
-    with SourceDeclarationBuilderMixin, ClassDeclarationBuilderMixin
+    with SourceDeclarationBuilderMixin
     implements
         Comparable<SourceExtensionTypeDeclarationBuilder>,
         ClassDeclarationBuilder {
@@ -60,15 +59,10 @@
 
   final Modifiers _modifiers;
 
-  @override
   final List<ConstructorReferenceBuilder> constructorReferences;
 
   late final ExtensionTypeDeclaration _extensionTypeDeclaration;
 
-  SourceExtensionTypeDeclarationBuilder? _origin;
-
-  MergedClassMemberScope? _mergedScope;
-
   final DeclarationNameSpaceBuilder _nameSpaceBuilder;
 
   late final DeclarationNameSpace _nameSpace;
@@ -77,9 +71,6 @@
   final List<NominalParameterBuilder>? typeParameters;
 
   @override
-  final LookupScope typeParameterScope;
-
-  @override
   List<TypeBuilder>? interfaceBuilders;
 
   final ExtensionTypeFragment _introductory;
@@ -90,8 +81,6 @@
 
   Nullability? _nullability;
 
-  SourceExtensionTypeDeclarationBuilder? _augmentation;
-
   SourceExtensionTypeDeclarationBuilder(
       {required this.name,
       required SourceLibraryBuilder enclosingLibraryBuilder,
@@ -108,7 +97,6 @@
         _modifiers = fragment.modifiers,
         typeParameters = fragment.typeParameters?.builders,
         interfaceBuilders = fragment.interfaces,
-        typeParameterScope = fragment.typeParameterScope,
         _introductory = fragment,
         _nameSpaceBuilder = fragment.toDeclarationNameSpaceBuilder(),
         _representationFieldFragment = representationFieldFragment {
@@ -126,20 +114,31 @@
       ..fileOffset = nameOffset;
   }
 
-  // TODO(johnniwinther): Remove this when augmentations are handled through
-  //  fragments.
   @override
-  List<SourceExtensionTypeDeclarationBuilder>? get augmentations =>
-      _augmentation != null
-          ?
-          // Coverage-ignore(suite): Not run.
-          [_augmentation!]
-          : const [];
-
-  // TODO(johnniwinther): Remove this when augmentations are handled through
-  //  fragments.
-  @override
-  LookupScope get bodyScope => _introductory.bodyScope;
+  int resolveConstructors(SourceLibraryBuilder library) {
+    int count = 0;
+    if (constructorReferences.isNotEmpty) {
+      for (ConstructorReferenceBuilder ref in constructorReferences) {
+        ref.resolveIn(_introductory.bodyScope, library);
+      }
+      count += constructorReferences.length;
+    }
+    if (count > 0) {
+      Iterator<MemberBuilder> iterator = nameSpace.filteredConstructorIterator(
+          parent: null, includeDuplicates: true, includeAugmentations: false);
+      while (iterator.moveNext()) {
+        MemberBuilder declaration = iterator.current;
+        if (declaration.declarationBuilder?.origin != origin) {
+          unexpected("$fileUri", "${declaration.declarationBuilder!.fileUri}",
+              fileOffset, fileUri);
+        }
+        if (declaration is SourceFactoryBuilder) {
+          declaration.resolveRedirectingFactory();
+        }
+      }
+    }
+    return count;
+  }
 
   // Coverage-ignore(suite): Not run.
   // TODO(johnniwinther): Avoid exposing this. Annotations for macros and
@@ -174,11 +173,6 @@
         indexedContainer: indexedContainer,
         containerType: ContainerType.ExtensionType,
         containerName: new ClassName(name));
-    SourceExtensionTypeDeclarationBuilder? augmentation = _augmentation;
-    if (augmentation != null) {
-      // Coverage-ignore-block(suite): Not run.
-      _applyAugmentation(augmentation);
-    }
   }
 
   @override
@@ -190,14 +184,7 @@
       _representationFieldFragment?.type;
 
   @override
-  SourceExtensionTypeDeclarationBuilder get origin => _origin ?? this;
-
-  // Coverage-ignore(suite): Not run.
-  // TODO(johnniwinther): Add merged scope for extension type declarations.
-  MergedClassMemberScope get mergedScope => _mergedScope ??= isAugmenting
-      ? origin.mergedScope
-      : throw new UnimplementedError(
-          "SourceExtensionTypeDeclarationBuilder.mergedScope");
+  SourceExtensionTypeDeclarationBuilder get origin => this;
 
   @override
   ExtensionTypeDeclaration get extensionTypeDeclaration => isAugmenting
@@ -733,7 +720,6 @@
     }
   }
 
-  @override
   void buildOutlineExpressions(ClassHierarchy classHierarchy,
       List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
     MetadataBuilder.buildAnnotations(
@@ -744,15 +730,30 @@
         _introductory.fileUri,
         _introductory.enclosingScope);
 
-    super.buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners);
+    if (_introductory.typeParameters != null) {
+      for (int i = 0; i < _introductory.typeParameters!.length; i++) {
+        _introductory.typeParameters![i].builder.buildOutlineExpressions(
+            libraryBuilder,
+            createBodyBuilderContext(),
+            classHierarchy,
+            _introductory.typeParameterScope);
+      }
+    }
 
-    Iterator<SourceMemberBuilder> iterator =
-        nameSpace.filteredConstructorIterator(
-            parent: this, includeDuplicates: false, includeAugmentations: true);
+    Iterator<SourceMemberBuilder> iterator = nameSpace.filteredIterator(
+        parent: this, includeDuplicates: false, includeAugmentations: true);
     while (iterator.moveNext()) {
       iterator.current
           .buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners);
     }
+
+    Iterator<SourceMemberBuilder> constructorIterator =
+        nameSpace.filteredConstructorIterator(
+            parent: this, includeDuplicates: false, includeAugmentations: true);
+    while (constructorIterator.moveNext()) {
+      constructorIterator.current
+          .buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners);
+    }
   }
 
   @override
@@ -850,60 +851,6 @@
             kind: kind));
   }
 
-  @override
-  // Coverage-ignore(suite): Not run.
-  void addAugmentation(Builder augmentation) {
-    _addAugmentation(augmentation);
-  }
-
-  // Coverage-ignore(suite): Not run.
-  SourceExtensionTypeDeclarationBuilder? _addAugmentation(
-      Builder augmentation) {
-    if (augmentation is SourceExtensionTypeDeclarationBuilder) {
-      augmentation._origin = this;
-      _augmentation = augmentation;
-      return augmentation;
-    } else {
-      libraryBuilder.addProblem(messagePatchDeclarationMismatch,
-          augmentation.fileOffset, noLength, augmentation.fileUri, context: [
-        messagePatchDeclarationOrigin.withLocation(
-            fileUri, fileOffset, noLength)
-      ]);
-      return null;
-    }
-  }
-
-  // Coverage-ignore(suite): Not run.
-  void _applyAugmentation(SourceExtensionTypeDeclarationBuilder augmentation) {
-    nameSpace.forEachLocalMember((String name, Builder member) {
-      Builder? memberAugmentation =
-          augmentation.nameSpace.lookupLocalMember(name, setter: false);
-      if (memberAugmentation != null) {
-        member.applyAugmentation(memberAugmentation);
-      }
-    });
-    nameSpace.forEachLocalSetter((String name, Builder member) {
-      Builder? memberAugmentation =
-          augmentation.nameSpace.lookupLocalMember(name, setter: true);
-      if (memberAugmentation != null) {
-        member.applyAugmentation(memberAugmentation);
-      }
-    });
-
-    // TODO(johnniwinther): Check that type parameters and on-type match
-    // with origin declaration.
-  }
-
-  @override
-  // Coverage-ignore(suite): Not run.
-  void applyAugmentation(Builder augmentation) {
-    SourceExtensionTypeDeclarationBuilder? extensionTypeDeclarationBuilder =
-        _addAugmentation(augmentation);
-    if (extensionTypeDeclarationBuilder != null) {
-      _applyAugmentation(extensionTypeDeclarationBuilder);
-    }
-  }
-
   /// Looks up the constructor by [name] on the class built by this class
   /// builder.
   SourceConstructorBuilderImpl? lookupConstructor(Name name) {
@@ -960,7 +907,6 @@
   // Coverage-ignore(suite): Not run.
   bool get isMixinDeclaration => false;
 
-  @override
   BodyBuilderContext createBodyBuilderContext() {
     return new ExtensionTypeBodyBuilderContext(this);
   }
diff --git a/pkg/front_end/lib/src/source/source_library_builder.dart b/pkg/front_end/lib/src/source/source_library_builder.dart
index ca2064d..5298033 100644
--- a/pkg/front_end/lib/src/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/source/source_library_builder.dart
@@ -335,6 +335,7 @@
   /// `true` if this is an augmentation library.
   bool get isAugmentationLibrary => compilationUnit.forAugmentationLibrary;
 
+  // Coverage-ignore(suite): Not run.
   /// `true` if this is a patch library.
   bool get isPatchLibrary => compilationUnit.forPatchLibrary;
 
@@ -648,11 +649,11 @@
     // recording the non-synthetic instance fields and getters of each.
     Iterator<SourceClassBuilder> classIterator = localMembersIteratorOfType();
     while (classIterator.moveNext()) {
-      SourceClassBuilder class_ = classIterator.current;
-      ClassInfo<Class> classInfo = fieldPromotability.addClass(class_.actualCls,
-          isAbstract: class_.isAbstract);
+      SourceClassBuilder classBuilder = classIterator.current;
+      ClassInfo<Class> classInfo = fieldPromotability.addClass(classBuilder.cls,
+          isAbstract: classBuilder.isAbstract);
       Iterator<SourceMemberBuilder> memberIterator =
-          class_.fullMemberIterator<SourceMemberBuilder>();
+          classBuilder.fullMemberIterator<SourceMemberBuilder>();
       while (memberIterator.moveNext()) {
         SourceMemberBuilder member = memberIterator.current;
         if (member.isStatic) continue;
diff --git a/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart b/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart
index a15f6da..01a6feb 100644
--- a/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart
+++ b/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart
@@ -107,7 +107,9 @@
   /// map the [NameSpace], they are not directly marked as duplicate if they
   /// do not conflict with other setters.
   void createBuilders(
-      void Function(Fragment, {bool conflictingSetter}) createBuilder);
+      void Function(Fragment,
+              {bool conflictingSetter, List<Fragment>? augmentations})
+          createBuilder);
 }
 
 /// [_PreBuilder] for properties, i.e. fields, getters and setters.
@@ -732,7 +734,9 @@
 
   @override
   void createBuilders(
-      void Function(Fragment, {bool conflictingSetter}) createBuilder) {
+      void Function(Fragment,
+              {bool conflictingSetter, List<Fragment>? augmentations})
+          createBuilder) {
     if (getter != null) {
       createBuilder(getter!.fragment);
     }
@@ -856,11 +860,11 @@
 
   @override
   void createBuilders(
-      void Function(Fragment, {bool conflictingSetter}) createBuilder) {
-    createBuilder(fragment.fragment);
-    for (_FragmentName fragmentName in augmentations) {
-      createBuilder(fragmentName.fragment);
-    }
+      void Function(Fragment,
+              {bool conflictingSetter, List<Fragment>? augmentations})
+          createBuilder) {
+    createBuilder(fragment.fragment,
+        augmentations: augmentations.map((f) => f.fragment).toList());
   }
 }
 
@@ -984,11 +988,11 @@
 
   @override
   void createBuilders(
-      void Function(Fragment, {bool conflictingSetter}) createBuilder) {
-    createBuilder(fragment.fragment);
-    for (_FragmentName fragmentName in augmentations) {
-      createBuilder(fragmentName.fragment);
-    }
+      void Function(Fragment,
+              {bool conflictingSetter, List<Fragment>? augmentations})
+          createBuilder) {
+    createBuilder(fragment.fragment,
+        augmentations: augmentations.map((f) => f.fragment).toList());
   }
 }
 
@@ -1215,7 +1219,8 @@
     }
   }
 
-  void createBuilder(Fragment fragment, {bool conflictingSetter = false}) {
+  void createBuilder(Fragment fragment,
+      {bool conflictingSetter = false, List<Fragment>? augmentations}) {
     switch (fragment) {
       case TypedefFragment():
         Reference? reference = indexedLibrary?.lookupTypedef(fragment.name);
@@ -1233,22 +1238,75 @@
           loader.buildersCreatedWithReferences[reference] = typedefBuilder;
         }
       case ClassFragment():
-        IndexedClass? indexedClass =
-            indexedLibrary?.lookupIndexedClass(fragment.name);
+        String name = fragment.name;
+        DeclarationNameSpaceBuilder nameSpaceBuilder =
+            fragment.toDeclarationNameSpaceBuilder();
+        ClassDeclaration introductoryDeclaration =
+            new RegularClassDeclaration(fragment);
+
+        Modifiers modifiers = fragment.modifiers;
+        List<ClassDeclaration> augmentationDeclarations = [];
+        if (augmentations != null) {
+          int introductoryTypeParameterCount =
+              fragment.typeParameters?.length ?? 0;
+          for (Fragment augmentation in augmentations) {
+            // Promote [augmentation] to [ClassFragment].
+            augmentation as ClassFragment;
+
+            // TODO(johnniwinther): Check that other modifiers are consistent.
+            if (augmentation.modifiers.declaresConstConstructor) {
+              modifiers |= Modifiers.DeclaresConstConstructor;
+            }
+            augmentationDeclarations
+                .add(new RegularClassDeclaration(augmentation));
+            nameSpaceBuilder
+                .includeBuilders(augmentation.toDeclarationNameSpaceBuilder());
+
+            int augmentationTypeParameterCount =
+                augmentation.typeParameters?.length ?? 0;
+            if (introductoryTypeParameterCount !=
+                augmentationTypeParameterCount) {
+              problemReporting.addProblem(
+                  messagePatchClassTypeParametersMismatch,
+                  augmentation.nameOffset,
+                  name.length,
+                  augmentation.fileUri,
+                  context: [
+                    messagePatchClassOrigin.withLocation(
+                        fragment.fileUri, fragment.nameOffset, name.length)
+                  ]);
+            } else if (augmentation.typeParameters != null) {
+              int count = 0;
+              for (TypeParameterFragment t in augmentation.typeParameters!) {
+                fragment.typeParameters![count++].builder
+                    .applyAugmentation(t.builder);
+              }
+            }
+          }
+        }
+        IndexedClass? indexedClass = indexedLibrary?.lookupIndexedClass(name);
         SourceClassBuilder classBuilder = new SourceClassBuilder(
-            modifiers: fragment.modifiers,
-            name: fragment.name,
+            modifiers: modifiers,
+            name: name,
             typeParameters: fragment.typeParameters?.builders,
             typeParameterScope: fragment.typeParameterScope,
-            nameSpaceBuilder: fragment.toDeclarationNameSpaceBuilder(),
+            nameSpaceBuilder: nameSpaceBuilder,
             libraryBuilder: enclosingLibraryBuilder,
-            constructorReferences: fragment.constructorReferences,
             fileUri: fragment.fileUri,
             nameOffset: fragment.nameOffset,
             indexedClass: indexedClass,
-            classDeclaration: new RegularClassDeclaration(fragment));
+            introductory: introductoryDeclaration,
+            augmentations: augmentationDeclarations);
         fragment.builder = classBuilder;
         fragment.bodyScope.declarationBuilder = classBuilder;
+        if (augmentations != null) {
+          for (Fragment augmentation in augmentations) {
+            augmentation as ClassFragment;
+            augmentation.builder = classBuilder;
+            augmentation.bodyScope.declarationBuilder = classBuilder;
+          }
+          augmentations = null;
+        }
         builders.add(new _AddBuilder(
             fragment.name, classBuilder, fragment.fileUri, fragment.fileOffset,
             inPatch: fragment.enclosingCompilationUnit.isPatch));
@@ -1268,11 +1326,10 @@
             typeParameterScope: fragment.typeParameterScope,
             nameSpaceBuilder: fragment.toDeclarationNameSpaceBuilder(),
             libraryBuilder: enclosingLibraryBuilder,
-            constructorReferences: fragment.constructorReferences,
             fileUri: fragment.fileUri,
             nameOffset: fragment.nameOffset,
             indexedClass: indexedClass,
-            classDeclaration: new MixinDeclaration(fragment));
+            introductory: new MixinDeclaration(fragment));
         fragment.builder = mixinBuilder;
         fragment.bodyScope.declarationBuilder = mixinBuilder;
         builders.add(new _AddBuilder(
@@ -1306,12 +1363,11 @@
             typeParameterScope: typeParameterScope,
             nameSpaceBuilder: nameSpaceBuilder,
             libraryBuilder: enclosingLibraryBuilder,
-            constructorReferences: [],
             fileUri: fragment.fileUri,
             nameOffset: fragment.nameOffset,
             indexedClass: referencesFromIndexedClass,
             mixedInTypeBuilder: mixin,
-            classDeclaration: classDeclaration);
+            introductory: classDeclaration);
         mixinApplications[classBuilder] = mixin;
         fragment.builder = classBuilder;
         builders.add(new _AddBuilder(
@@ -1333,7 +1389,6 @@
             interfaceBuilders: fragment.interfaces,
             enumElements: fragment.enumElements,
             libraryBuilder: enclosingLibraryBuilder,
-            constructorReferences: fragment.constructorReferences,
             fileUri: fragment.fileUri,
             startOffset: fragment.startOffset,
             nameOffset: fragment.nameOffset,
@@ -1353,6 +1408,45 @@
               enumBuilder;
         }
       case ExtensionFragment():
+        DeclarationNameSpaceBuilder nameSpaceBuilder =
+            fragment.toDeclarationNameSpaceBuilder();
+        List<ExtensionFragment> augmentationFragments = [];
+        if (augmentations != null) {
+          int introductoryTypeParameterCount =
+              fragment.typeParameters?.length ?? 0;
+          int nameLength = fragment.isUnnamed ? noLength : fragment.name.length;
+
+          for (Fragment augmentation in augmentations) {
+            // Promote [augmentation] to [ExtensionFragment].
+            augmentation as ExtensionFragment;
+
+            augmentationFragments.add(augmentation);
+            nameSpaceBuilder
+                .includeBuilders(augmentation.toDeclarationNameSpaceBuilder());
+
+            int augmentationTypeParameterCount =
+                augmentation.typeParameters?.length ?? 0;
+            if (introductoryTypeParameterCount !=
+                augmentationTypeParameterCount) {
+              problemReporting.addProblem(
+                  messagePatchExtensionTypeParametersMismatch,
+                  augmentation.nameOrExtensionOffset,
+                  nameLength,
+                  augmentation.fileUri,
+                  context: [
+                    messagePatchExtensionOrigin.withLocation(fragment.fileUri,
+                        fragment.nameOrExtensionOffset, nameLength)
+                  ]);
+            } else if (augmentation.typeParameters != null) {
+              int count = 0;
+              for (TypeParameterFragment t in augmentation.typeParameters!) {
+                fragment.typeParameters![count++].builder
+                    .applyAugmentation(t.builder);
+              }
+            }
+          }
+          augmentations = null;
+        }
         Reference? reference;
         if (!fragment.extensionName.isUnnamedExtension) {
           reference = indexedLibrary?.lookupExtension(fragment.name);
@@ -1363,7 +1457,9 @@
             startOffset: fragment.startOffset,
             nameOffset: fragment.nameOrExtensionOffset,
             endOffset: fragment.endOffset,
-            fragment: fragment,
+            introductory: fragment,
+            augmentations: augmentationFragments,
+            nameSpaceBuilder: nameSpaceBuilder,
             reference: reference);
         builders.add(new _AddBuilder(fragment.name, extensionBuilder,
             fragment.fileUri, fragment.fileOffset,
@@ -1970,6 +2066,11 @@
             fragment.fileUri, fragment.nameOffset,
             inPatch: fragment.enclosingDeclaration.isPatch));
     }
+    if (augmentations != null) {
+      for (Fragment augmentation in augmentations) {
+        createBuilder(augmentation);
+      }
+    }
   }
 
   for (_PreBuilder preBuilder in nonConstructorPreBuilders) {
@@ -2114,7 +2215,6 @@
         // output.
         extensions.add(declaration as SourceExtensionBuilder);
       } else if (declaration.isAugment) {
-        // Coverage-ignore-block(suite): Not run.
         if (existing == null) {
           // TODO(cstefantsova): Report an error.
         }
@@ -2392,6 +2492,8 @@
       if (addBuilder.inPatch &&
           !name.startsWith('_') &&
           !_allowInjectedPublicMember(enclosingLibraryBuilder, declaration)) {
+        // TODO(johnniwinther): Test adding a no-name constructor in the patch,
+        // either as an injected or duplicated constructor.
         problemReporting.addProblem(
             templatePatchInjectionFailed.withArguments(
                 name, enclosingLibraryBuilder.importUri),
diff --git a/pkg/front_end/test/coverage_suite_expected.dart b/pkg/front_end/test/coverage_suite_expected.dart
index 185ddf9..afb0410 100644
--- a/pkg/front_end/test/coverage_suite_expected.dart
+++ b/pkg/front_end/test/coverage_suite_expected.dart
@@ -190,7 +190,7 @@
   ),
   // 100.0%.
   "package:front_end/src/base/name_space.dart": (
-    hitCount: 153,
+    hitCount: 137,
     missCount: 0,
   ),
   // 100.0%.
@@ -210,7 +210,7 @@
   ),
   // 100.0%.
   "package:front_end/src/base/scope.dart": (
-    hitCount: 455,
+    hitCount: 412,
     missCount: 0,
   ),
   // 100.0%.
@@ -470,7 +470,7 @@
   ),
   // 100.0%.
   "package:front_end/src/fragment/class/declaration.dart": (
-    hitCount: 168,
+    hitCount: 234,
     missCount: 0,
   ),
   // 100.0%.
@@ -815,7 +815,7 @@
   ),
   // 100.0%.
   "package:front_end/src/source/class_declaration.dart": (
-    hitCount: 110,
+    hitCount: 57,
     missCount: 0,
   ),
   // 100.0%.
@@ -850,22 +850,22 @@
   ),
   // 100.0%.
   "package:front_end/src/source/source_builder_factory.dart": (
-    hitCount: 1190,
+    hitCount: 1191,
     missCount: 0,
   ),
   // 100.0%.
   "package:front_end/src/source/source_builder_mixins.dart": (
-    hitCount: 131,
+    hitCount: 114,
     missCount: 0,
   ),
   // 100.0%.
   "package:front_end/src/source/source_class_builder.dart": (
-    hitCount: 1398,
+    hitCount: 1354,
     missCount: 0,
   ),
   // 100.0%.
   "package:front_end/src/source/source_compilation_unit.dart": (
-    hitCount: 669,
+    hitCount: 668,
     missCount: 0,
   ),
   // 100.0%.
@@ -880,13 +880,13 @@
   ),
   // 100.0%.
   "package:front_end/src/source/source_extension_builder.dart": (
-    hitCount: 158,
+    hitCount: 137,
     missCount: 0,
   ),
   // 100.0%.
   "package:front_end/src/source/source_extension_type_declaration_builder.dart":
       (
-    hitCount: 514,
+    hitCount: 550,
     missCount: 0,
   ),
   // 100.0%.
@@ -901,12 +901,12 @@
   ),
   // 100.0%.
   "package:front_end/src/source/source_library_builder.dart": (
-    hitCount: 1120,
+    hitCount: 1085,
     missCount: 0,
   ),
   // 100.0%.
   "package:front_end/src/source/source_loader.dart": (
-    hitCount: 1792,
+    hitCount: 1790,
     missCount: 0,
   ),
   // 100.0%.
@@ -941,7 +941,7 @@
   ),
   // 100.0%.
   "package:front_end/src/source/type_parameter_scope_builder.dart": (
-    hitCount: 1496,
+    hitCount: 1567,
     missCount: 0,
   ),
   // 100.0%.
diff --git a/pkg/front_end/test/patching/patching_test.dart b/pkg/front_end/test/patching/patching_test.dart
index 0271767..23dc46a 100644
--- a/pkg/front_end/test/patching/patching_test.dart
+++ b/pkg/front_end/test/patching/patching_test.dart
@@ -130,7 +130,7 @@
       features.addElement(Tags.scope, name);
     });
 
-    for (Member m in clsBuilder.actualCls.members) {
+    for (Member m in clsBuilder.cls.members) {
       if (m is Procedure &&
           (m.isMemberSignature ||
               (m.isForwardingStub && !m.isForwardingSemiStub))) {
diff --git a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.expect b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.expect
index 1eaf61d..f776adc 100644
--- a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.expect
+++ b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.expect
@@ -16,7 +16,7 @@
 import "dart:_internal";
 
 @/* from org-dartlang-testcase:///patch_lib.dart */ #C1
-class Class extends core::Object {
+class Class extends core::Object /*hasConstConstructor*/  {
   final field core::bool defaultValue /* from org-dartlang-testcase:///patch_lib.dart */;
   const constructor /* from org-dartlang-testcase:///patch_lib.dart */ _internal({core::bool defaultValue = #C2}) → test::Class
     : test::Class::defaultValue = defaultValue, super core::Object::•()
diff --git a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.modular.expect b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.modular.expect
index 1eaf61d..f776adc 100644
--- a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.modular.expect
+++ b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.modular.expect
@@ -16,7 +16,7 @@
 import "dart:_internal";
 
 @/* from org-dartlang-testcase:///patch_lib.dart */ #C1
-class Class extends core::Object {
+class Class extends core::Object /*hasConstConstructor*/  {
   final field core::bool defaultValue /* from org-dartlang-testcase:///patch_lib.dart */;
   const constructor /* from org-dartlang-testcase:///patch_lib.dart */ _internal({core::bool defaultValue = #C2}) → test::Class
     : test::Class::defaultValue = defaultValue, super core::Object::•()
diff --git a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.outline.expect b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.outline.expect
index 20b5b94..d02c957 100644
--- a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.outline.expect
+++ b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.outline.expect
@@ -14,7 +14,7 @@
 import "dart:_internal";
 
 @/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch
-class Class extends core::Object {
+class Class extends core::Object /*hasConstConstructor*/  {
   final field core::bool defaultValue /* from org-dartlang-testcase:///patch_lib.dart */;
   const constructor /* from org-dartlang-testcase:///patch_lib.dart */ _internal({core::bool defaultValue = false}) → self2::Class
     : self2::Class::defaultValue = defaultValue, super core::Object::•()
diff --git a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.transformed.expect b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.transformed.expect
index 1eaf61d..f776adc 100644
--- a/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/dartdevc/factory_patch/main.dart.strong.transformed.expect
@@ -16,7 +16,7 @@
 import "dart:_internal";
 
 @/* from org-dartlang-testcase:///patch_lib.dart */ #C1
-class Class extends core::Object {
+class Class extends core::Object /*hasConstConstructor*/  {
   final field core::bool defaultValue /* from org-dartlang-testcase:///patch_lib.dart */;
   const constructor /* from org-dartlang-testcase:///patch_lib.dart */ _internal({core::bool defaultValue = #C2}) → test::Class
     : test::Class::defaultValue = defaultValue, super core::Object::•()
diff --git a/pkg/front_end/testcases/general/constructor_patch/main.dart b/pkg/front_end/testcases/general/constructor_patch/main.dart
index 57977cc..2c5f44e 100644
--- a/pkg/front_end/testcases/general/constructor_patch/main.dart
+++ b/pkg/front_end/testcases/general/constructor_patch/main.dart
@@ -7,6 +7,7 @@
 test() {
   new Class._private(); // Error
   new Class._privateInjected(); // Error
+  new Class3(); // Error
 }
 
 main() {
diff --git a/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.expect b/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.expect
index 35fd7d7..8b5ac71 100644
--- a/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.expect
+++ b/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.expect
@@ -10,6 +10,10 @@
 //   new Class._privateInjected(); // Error
 //             ^^^^^^^^^^^^^^^^
 //
+// pkg/front_end/testcases/general/constructor_patch/main.dart:10:7: Error: Couldn't find constructor 'Class3'.
+//   new Class3(); // Error
+//       ^^^^^^
+//
 import self as self;
 import "dart:test" as test;
 
@@ -22,6 +26,9 @@
   invalid-expression "pkg/front_end/testcases/general/constructor_patch/main.dart:9:13: Error: Couldn't find constructor 'Class._privateInjected'.
   new Class._privateInjected(); // Error
             ^^^^^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/general/constructor_patch/main.dart:10:7: Error: Couldn't find constructor 'Class3'.
+  new Class3(); // Error
+      ^^^^^^";
 }
 static method main() → dynamic {
   new test::Class::generative();
@@ -77,15 +84,23 @@
     : super test::Class::_privateInjected()
     ;
 }
+@/* from org-dartlang-testcase:///patch_lib.dart */ #C3
+class Class3 extends core::Object /*hasConstConstructor*/  {
+  const constructor /* from org-dartlang-testcase:///patch_lib.dart */ _() → test::Class3
+    : super core::Object::•()
+    ;
+}
 static method test() → dynamic {
   new test::Class::_private();
   new test::Class::_privateInjected();
+  #C4;
 }
 
 constants  {
   #C1 = true
   #C2 = test::Class {defaultValue:#C1}
   #C3 = _in::_Patch {}
+  #C4 = test::Class3 {}
 }
 
 
@@ -93,3 +108,7 @@
 org-dartlang-testcase:///main.dart:
 - Class.constGenerative (from org-dartlang-testcase:///patch_lib.dart:16:9)
 - Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
+
+org-dartlang-testcase:///origin_lib.dart:
+- Class3._ (from org-dartlang-testcase:///patch_lib.dart:38:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.modular.expect b/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.modular.expect
index 35fd7d7..8b5ac71 100644
--- a/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.modular.expect
+++ b/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.modular.expect
@@ -10,6 +10,10 @@
 //   new Class._privateInjected(); // Error
 //             ^^^^^^^^^^^^^^^^
 //
+// pkg/front_end/testcases/general/constructor_patch/main.dart:10:7: Error: Couldn't find constructor 'Class3'.
+//   new Class3(); // Error
+//       ^^^^^^
+//
 import self as self;
 import "dart:test" as test;
 
@@ -22,6 +26,9 @@
   invalid-expression "pkg/front_end/testcases/general/constructor_patch/main.dart:9:13: Error: Couldn't find constructor 'Class._privateInjected'.
   new Class._privateInjected(); // Error
             ^^^^^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/general/constructor_patch/main.dart:10:7: Error: Couldn't find constructor 'Class3'.
+  new Class3(); // Error
+      ^^^^^^";
 }
 static method main() → dynamic {
   new test::Class::generative();
@@ -77,15 +84,23 @@
     : super test::Class::_privateInjected()
     ;
 }
+@/* from org-dartlang-testcase:///patch_lib.dart */ #C3
+class Class3 extends core::Object /*hasConstConstructor*/  {
+  const constructor /* from org-dartlang-testcase:///patch_lib.dart */ _() → test::Class3
+    : super core::Object::•()
+    ;
+}
 static method test() → dynamic {
   new test::Class::_private();
   new test::Class::_privateInjected();
+  #C4;
 }
 
 constants  {
   #C1 = true
   #C2 = test::Class {defaultValue:#C1}
   #C3 = _in::_Patch {}
+  #C4 = test::Class3 {}
 }
 
 
@@ -93,3 +108,7 @@
 org-dartlang-testcase:///main.dart:
 - Class.constGenerative (from org-dartlang-testcase:///patch_lib.dart:16:9)
 - Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
+
+org-dartlang-testcase:///origin_lib.dart:
+- Class3._ (from org-dartlang-testcase:///patch_lib.dart:38:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.outline.expect b/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.outline.expect
index c444a46..f4e3cc1 100644
--- a/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.outline.expect
+++ b/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.outline.expect
@@ -46,6 +46,12 @@
   constructor privateInjected() → self2::Subclass
     ;
 }
+@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch
+class Class3 extends core::Object /*hasConstConstructor*/  {
+  const constructor /* from org-dartlang-testcase:///patch_lib.dart */ _() → self2::Class3
+    : super core::Object::•()
+    ;
+}
 static method test() → dynamic
   ;
 
@@ -57,4 +63,5 @@
 Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:17:8 -> InstanceConstant(const _Patch{})
 Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:28:1 -> InstanceConstant(const _Patch{})
 Evaluated: StaticGet @ (unknown position in org-dartlang-testcase:///origin_lib.dart) -> InstanceConstant(const _Patch{})
-Extra constant evaluation: evaluated: 7, effectively constant: 6
+Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:36:1 -> InstanceConstant(const _Patch{})
+Extra constant evaluation: evaluated: 8, effectively constant: 7
diff --git a/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.transformed.expect
index 35fd7d7..8b5ac71 100644
--- a/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/constructor_patch/main.dart.strong.transformed.expect
@@ -10,6 +10,10 @@
 //   new Class._privateInjected(); // Error
 //             ^^^^^^^^^^^^^^^^
 //
+// pkg/front_end/testcases/general/constructor_patch/main.dart:10:7: Error: Couldn't find constructor 'Class3'.
+//   new Class3(); // Error
+//       ^^^^^^
+//
 import self as self;
 import "dart:test" as test;
 
@@ -22,6 +26,9 @@
   invalid-expression "pkg/front_end/testcases/general/constructor_patch/main.dart:9:13: Error: Couldn't find constructor 'Class._privateInjected'.
   new Class._privateInjected(); // Error
             ^^^^^^^^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/general/constructor_patch/main.dart:10:7: Error: Couldn't find constructor 'Class3'.
+  new Class3(); // Error
+      ^^^^^^";
 }
 static method main() → dynamic {
   new test::Class::generative();
@@ -77,15 +84,23 @@
     : super test::Class::_privateInjected()
     ;
 }
+@/* from org-dartlang-testcase:///patch_lib.dart */ #C3
+class Class3 extends core::Object /*hasConstConstructor*/  {
+  const constructor /* from org-dartlang-testcase:///patch_lib.dart */ _() → test::Class3
+    : super core::Object::•()
+    ;
+}
 static method test() → dynamic {
   new test::Class::_private();
   new test::Class::_privateInjected();
+  #C4;
 }
 
 constants  {
   #C1 = true
   #C2 = test::Class {defaultValue:#C1}
   #C3 = _in::_Patch {}
+  #C4 = test::Class3 {}
 }
 
 
@@ -93,3 +108,7 @@
 org-dartlang-testcase:///main.dart:
 - Class.constGenerative (from org-dartlang-testcase:///patch_lib.dart:16:9)
 - Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
+
+org-dartlang-testcase:///origin_lib.dart:
+- Class3._ (from org-dartlang-testcase:///patch_lib.dart:38:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/general/constructor_patch/origin_lib.dart b/pkg/front_end/testcases/general/constructor_patch/origin_lib.dart
index 9f48201..50547af 100644
--- a/pkg/front_end/testcases/general/constructor_patch/origin_lib.dart
+++ b/pkg/front_end/testcases/general/constructor_patch/origin_lib.dart
@@ -17,9 +17,12 @@
 test() {
   new Class._private(); // Ok
   new Class._privateInjected(); // Ok
+  const Class3._(); // Ok
 }
 
 class Subclass extends Class {
   Subclass.private() : super._private(); // Ok
   Subclass.privateInjected() : super._privateInjected(); // Ok
 }
+
+class Class3 {}
diff --git a/pkg/front_end/testcases/general/constructor_patch/patch_lib.dart b/pkg/front_end/testcases/general/constructor_patch/patch_lib.dart
index ed5bfee..8de4517 100644
--- a/pkg/front_end/testcases/general/constructor_patch/patch_lib.dart
+++ b/pkg/front_end/testcases/general/constructor_patch/patch_lib.dart
@@ -32,3 +32,8 @@
   @patch
   Class2(this.field) : injectedField = field;
 }
+
+@patch
+class Class3 {
+  const Class3._();
+}
diff --git a/pkg/front_end/testcases/general/factory_patch/main.dart.strong.expect b/pkg/front_end/testcases/general/factory_patch/main.dart.strong.expect
index e2d7f06..2461e05 100644
--- a/pkg/front_end/testcases/general/factory_patch/main.dart.strong.expect
+++ b/pkg/front_end/testcases/general/factory_patch/main.dart.strong.expect
@@ -24,7 +24,7 @@
 import "dart:_internal";
 
 @/* from org-dartlang-testcase:///patch_lib.dart */ #C1
-class Class extends core::Object {
+class Class extends core::Object /*hasConstConstructor*/  {
   final field core::bool defaultValue /* from org-dartlang-testcase:///patch_lib.dart */;
   const constructor /* from org-dartlang-testcase:///patch_lib.dart */ _internal({core::bool defaultValue = #C2}) → test::Class
     : test::Class::defaultValue = defaultValue, super core::Object::•()
diff --git a/pkg/front_end/testcases/general/factory_patch/main.dart.strong.modular.expect b/pkg/front_end/testcases/general/factory_patch/main.dart.strong.modular.expect
index e2d7f06..2461e05 100644
--- a/pkg/front_end/testcases/general/factory_patch/main.dart.strong.modular.expect
+++ b/pkg/front_end/testcases/general/factory_patch/main.dart.strong.modular.expect
@@ -24,7 +24,7 @@
 import "dart:_internal";
 
 @/* from org-dartlang-testcase:///patch_lib.dart */ #C1
-class Class extends core::Object {
+class Class extends core::Object /*hasConstConstructor*/  {
   final field core::bool defaultValue /* from org-dartlang-testcase:///patch_lib.dart */;
   const constructor /* from org-dartlang-testcase:///patch_lib.dart */ _internal({core::bool defaultValue = #C2}) → test::Class
     : test::Class::defaultValue = defaultValue, super core::Object::•()
diff --git a/pkg/front_end/testcases/general/factory_patch/main.dart.strong.outline.expect b/pkg/front_end/testcases/general/factory_patch/main.dart.strong.outline.expect
index 0746810..91a92f6 100644
--- a/pkg/front_end/testcases/general/factory_patch/main.dart.strong.outline.expect
+++ b/pkg/front_end/testcases/general/factory_patch/main.dart.strong.outline.expect
@@ -14,7 +14,7 @@
 import "dart:_internal";
 
 @/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch
-class Class extends core::Object {
+class Class extends core::Object /*hasConstConstructor*/  {
   final field core::bool defaultValue /* from org-dartlang-testcase:///patch_lib.dart */;
   const constructor /* from org-dartlang-testcase:///patch_lib.dart */ _internal({core::bool defaultValue = false}) → self2::Class
     : self2::Class::defaultValue = defaultValue, super core::Object::•()
diff --git a/pkg/front_end/testcases/general/factory_patch/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/factory_patch/main.dart.strong.transformed.expect
index e2d7f06..2461e05 100644
--- a/pkg/front_end/testcases/general/factory_patch/main.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/factory_patch/main.dart.strong.transformed.expect
@@ -24,7 +24,7 @@
 import "dart:_internal";
 
 @/* from org-dartlang-testcase:///patch_lib.dart */ #C1
-class Class extends core::Object {
+class Class extends core::Object /*hasConstConstructor*/  {
   final field core::bool defaultValue /* from org-dartlang-testcase:///patch_lib.dart */;
   const constructor /* from org-dartlang-testcase:///patch_lib.dart */ _internal({core::bool defaultValue = #C2}) → test::Class
     : test::Class::defaultValue = defaultValue, super core::Object::•()
diff --git a/pkg/front_end/testcases/general/invalid_patch/libraries.json b/pkg/front_end/testcases/general/invalid_patch/libraries.json
new file mode 100644
index 0000000..79373ad
--- /dev/null
+++ b/pkg/front_end/testcases/general/invalid_patch/libraries.json
@@ -0,0 +1,13 @@
+{
+  "vm": {
+    "comment:0": "This adds to the default libraries found in the platform.",
+    "libraries": {
+      "test": {
+        "patches": [
+          "patch_lib.dart"
+        ],
+        "uri": "origin_lib.dart"
+      }
+    }
+  }
+}
diff --git a/pkg/front_end/testcases/general/invalid_patch/main.dart b/pkg/front_end/testcases/general/invalid_patch/main.dart
new file mode 100644
index 0000000..c345588
--- /dev/null
+++ b/pkg/front_end/testcases/general/invalid_patch/main.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.expect b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.expect
new file mode 100644
index 0000000..85f0092
--- /dev/null
+++ b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.expect
@@ -0,0 +1,90 @@
+library;
+import self as self;
+
+import "dart:test";
+
+static method main() → dynamic {}
+
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:9:7: Error: A patch class must have the same number of type variables as its origin class.
+// class InvalidClassTypeParameterCount1<T> /* Error */ {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:5:7: Context: This is the origin class.
+// class InvalidClassTypeParameterCount1 {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:12:7: Error: A patch class must have the same number of type variables as its origin class.
+// class InvalidClassTypeParameterCount2 /* Error */ {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:7:7: Context: This is the origin class.
+// class InvalidClassTypeParameterCount2<T> {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:15:7: Error: A patch class must have the same number of type variables as its origin class.
+// class InvalidClassTypeParameterCount3<T> /* Error */ {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:9:7: Context: This is the origin class.
+// class InvalidClassTypeParameterCount3<T, S> {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:18:11: Error: A patch extension must have the same number of type variables as its origin extension.
+// extension InvalidExtensionTypeParameterCount1<T> on int /* Error */ {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:11:11: Context: This is the origin extension.
+// extension InvalidExtensionTypeParameterCount1 on int {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:21:11: Error: A patch extension must have the same number of type variables as its origin extension.
+// extension InvalidExtensionTypeParameterCount2 on int /* Error */ {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:13:11: Context: This is the origin extension.
+// extension InvalidExtensionTypeParameterCount2<T> on int {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:24:11: Error: A patch extension must have the same number of type variables as its origin extension.
+// extension InvalidExtensionTypeParameterCount3<T> on int /* Error */ {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:15:11: Context: This is the origin extension.
+// extension InvalidExtensionTypeParameterCount3<T, S> on int {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+import self as self2;
+import "dart:_internal" as _in;
+import "dart:core" as core;
+
+import "dart:_internal";
+
+@/* from org-dartlang-testcase:///patch_lib.dart */ #C1
+class InvalidClassTypeParameterCount1 extends core::Object {
+  synthetic constructor •() → self2::InvalidClassTypeParameterCount1
+    : super core::Object::•()
+    ;
+}
+@/* from org-dartlang-testcase:///patch_lib.dart */ #C1
+class InvalidClassTypeParameterCount2<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self2::InvalidClassTypeParameterCount2<self2::InvalidClassTypeParameterCount2::T%>
+    : super core::Object::•()
+    ;
+}
+@/* from org-dartlang-testcase:///patch_lib.dart */ #C1
+class InvalidClassTypeParameterCount3<T extends core::Object? = dynamic, S extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self2::InvalidClassTypeParameterCount3<self2::InvalidClassTypeParameterCount3::T%, self2::InvalidClassTypeParameterCount3::S%>
+    : super core::Object::•()
+    ;
+}
+@#C1
+extension InvalidExtensionTypeParameterCount1 on core::int {
+}
+@#C1
+extension InvalidExtensionTypeParameterCount2<T extends core::Object? = dynamic> on core::int {
+}
+@#C1
+extension InvalidExtensionTypeParameterCount3<T extends core::Object? = dynamic, S extends core::Object? = dynamic> on core::int {
+}
+
+constants  {
+  #C1 = _in::_Patch {}
+}
diff --git a/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.modular.expect b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.modular.expect
new file mode 100644
index 0000000..85f0092
--- /dev/null
+++ b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.modular.expect
@@ -0,0 +1,90 @@
+library;
+import self as self;
+
+import "dart:test";
+
+static method main() → dynamic {}
+
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:9:7: Error: A patch class must have the same number of type variables as its origin class.
+// class InvalidClassTypeParameterCount1<T> /* Error */ {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:5:7: Context: This is the origin class.
+// class InvalidClassTypeParameterCount1 {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:12:7: Error: A patch class must have the same number of type variables as its origin class.
+// class InvalidClassTypeParameterCount2 /* Error */ {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:7:7: Context: This is the origin class.
+// class InvalidClassTypeParameterCount2<T> {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:15:7: Error: A patch class must have the same number of type variables as its origin class.
+// class InvalidClassTypeParameterCount3<T> /* Error */ {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:9:7: Context: This is the origin class.
+// class InvalidClassTypeParameterCount3<T, S> {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:18:11: Error: A patch extension must have the same number of type variables as its origin extension.
+// extension InvalidExtensionTypeParameterCount1<T> on int /* Error */ {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:11:11: Context: This is the origin extension.
+// extension InvalidExtensionTypeParameterCount1 on int {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:21:11: Error: A patch extension must have the same number of type variables as its origin extension.
+// extension InvalidExtensionTypeParameterCount2 on int /* Error */ {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:13:11: Context: This is the origin extension.
+// extension InvalidExtensionTypeParameterCount2<T> on int {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:24:11: Error: A patch extension must have the same number of type variables as its origin extension.
+// extension InvalidExtensionTypeParameterCount3<T> on int /* Error */ {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:15:11: Context: This is the origin extension.
+// extension InvalidExtensionTypeParameterCount3<T, S> on int {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+import self as self2;
+import "dart:_internal" as _in;
+import "dart:core" as core;
+
+import "dart:_internal";
+
+@/* from org-dartlang-testcase:///patch_lib.dart */ #C1
+class InvalidClassTypeParameterCount1 extends core::Object {
+  synthetic constructor •() → self2::InvalidClassTypeParameterCount1
+    : super core::Object::•()
+    ;
+}
+@/* from org-dartlang-testcase:///patch_lib.dart */ #C1
+class InvalidClassTypeParameterCount2<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self2::InvalidClassTypeParameterCount2<self2::InvalidClassTypeParameterCount2::T%>
+    : super core::Object::•()
+    ;
+}
+@/* from org-dartlang-testcase:///patch_lib.dart */ #C1
+class InvalidClassTypeParameterCount3<T extends core::Object? = dynamic, S extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self2::InvalidClassTypeParameterCount3<self2::InvalidClassTypeParameterCount3::T%, self2::InvalidClassTypeParameterCount3::S%>
+    : super core::Object::•()
+    ;
+}
+@#C1
+extension InvalidExtensionTypeParameterCount1 on core::int {
+}
+@#C1
+extension InvalidExtensionTypeParameterCount2<T extends core::Object? = dynamic> on core::int {
+}
+@#C1
+extension InvalidExtensionTypeParameterCount3<T extends core::Object? = dynamic, S extends core::Object? = dynamic> on core::int {
+}
+
+constants  {
+  #C1 = _in::_Patch {}
+}
diff --git a/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.outline.expect b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.outline.expect
new file mode 100644
index 0000000..59d64c6
--- /dev/null
+++ b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.outline.expect
@@ -0,0 +1,94 @@
+library;
+import self as self;
+
+import "dart:test";
+
+static method main() → dynamic
+  ;
+
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:9:7: Error: A patch class must have the same number of type variables as its origin class.
+// class InvalidClassTypeParameterCount1<T> /* Error */ {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:5:7: Context: This is the origin class.
+// class InvalidClassTypeParameterCount1 {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:12:7: Error: A patch class must have the same number of type variables as its origin class.
+// class InvalidClassTypeParameterCount2 /* Error */ {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:7:7: Context: This is the origin class.
+// class InvalidClassTypeParameterCount2<T> {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:15:7: Error: A patch class must have the same number of type variables as its origin class.
+// class InvalidClassTypeParameterCount3<T> /* Error */ {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:9:7: Context: This is the origin class.
+// class InvalidClassTypeParameterCount3<T, S> {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:18:11: Error: A patch extension must have the same number of type variables as its origin extension.
+// extension InvalidExtensionTypeParameterCount1<T> on int /* Error */ {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:11:11: Context: This is the origin extension.
+// extension InvalidExtensionTypeParameterCount1 on int {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:21:11: Error: A patch extension must have the same number of type variables as its origin extension.
+// extension InvalidExtensionTypeParameterCount2 on int /* Error */ {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:13:11: Context: This is the origin extension.
+// extension InvalidExtensionTypeParameterCount2<T> on int {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:24:11: Error: A patch extension must have the same number of type variables as its origin extension.
+// extension InvalidExtensionTypeParameterCount3<T> on int /* Error */ {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:15:11: Context: This is the origin extension.
+// extension InvalidExtensionTypeParameterCount3<T, S> on int {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+import self as self2;
+import "dart:_internal" as _in;
+import "dart:core" as core;
+
+import "dart:_internal";
+
+@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch
+class InvalidClassTypeParameterCount1 extends core::Object {
+  synthetic constructor •() → self2::InvalidClassTypeParameterCount1
+    ;
+}
+@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch
+class InvalidClassTypeParameterCount2<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self2::InvalidClassTypeParameterCount2<self2::InvalidClassTypeParameterCount2::T%>
+    ;
+}
+@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch
+class InvalidClassTypeParameterCount3<T extends core::Object? = dynamic, S extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self2::InvalidClassTypeParameterCount3<self2::InvalidClassTypeParameterCount3::T%, self2::InvalidClassTypeParameterCount3::S%>
+    ;
+}
+@_in::patch
+extension InvalidExtensionTypeParameterCount1 on core::int {
+}
+@_in::patch
+extension InvalidExtensionTypeParameterCount2<T extends core::Object? = dynamic> on core::int {
+}
+@_in::patch
+extension InvalidExtensionTypeParameterCount3<T extends core::Object? = dynamic, S extends core::Object? = dynamic> on core::int {
+}
+
+
+Extra constant evaluation status:
+Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:8:1 -> InstanceConstant(const _Patch{})
+Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:11:1 -> InstanceConstant(const _Patch{})
+Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:14:1 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:14:1 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ (unknown position in org-dartlang-testcase:///origin_lib.dart) -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ (unknown position in org-dartlang-testcase:///origin_lib.dart) -> InstanceConstant(const _Patch{})
+Extra constant evaluation: evaluated: 6, effectively constant: 6
diff --git a/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.transformed.expect
new file mode 100644
index 0000000..85f0092
--- /dev/null
+++ b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.transformed.expect
@@ -0,0 +1,90 @@
+library;
+import self as self;
+
+import "dart:test";
+
+static method main() → dynamic {}
+
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:9:7: Error: A patch class must have the same number of type variables as its origin class.
+// class InvalidClassTypeParameterCount1<T> /* Error */ {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:5:7: Context: This is the origin class.
+// class InvalidClassTypeParameterCount1 {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:12:7: Error: A patch class must have the same number of type variables as its origin class.
+// class InvalidClassTypeParameterCount2 /* Error */ {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:7:7: Context: This is the origin class.
+// class InvalidClassTypeParameterCount2<T> {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:15:7: Error: A patch class must have the same number of type variables as its origin class.
+// class InvalidClassTypeParameterCount3<T> /* Error */ {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:9:7: Context: This is the origin class.
+// class InvalidClassTypeParameterCount3<T, S> {}
+//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:18:11: Error: A patch extension must have the same number of type variables as its origin extension.
+// extension InvalidExtensionTypeParameterCount1<T> on int /* Error */ {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:11:11: Context: This is the origin extension.
+// extension InvalidExtensionTypeParameterCount1 on int {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:21:11: Error: A patch extension must have the same number of type variables as its origin extension.
+// extension InvalidExtensionTypeParameterCount2 on int /* Error */ {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:13:11: Context: This is the origin extension.
+// extension InvalidExtensionTypeParameterCount2<T> on int {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/invalid_patch/patch_lib.dart:24:11: Error: A patch extension must have the same number of type variables as its origin extension.
+// extension InvalidExtensionTypeParameterCount3<T> on int /* Error */ {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// pkg/front_end/testcases/general/invalid_patch/origin_lib.dart:15:11: Context: This is the origin extension.
+// extension InvalidExtensionTypeParameterCount3<T, S> on int {}
+//           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+import self as self2;
+import "dart:_internal" as _in;
+import "dart:core" as core;
+
+import "dart:_internal";
+
+@/* from org-dartlang-testcase:///patch_lib.dart */ #C1
+class InvalidClassTypeParameterCount1 extends core::Object {
+  synthetic constructor •() → self2::InvalidClassTypeParameterCount1
+    : super core::Object::•()
+    ;
+}
+@/* from org-dartlang-testcase:///patch_lib.dart */ #C1
+class InvalidClassTypeParameterCount2<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self2::InvalidClassTypeParameterCount2<self2::InvalidClassTypeParameterCount2::T%>
+    : super core::Object::•()
+    ;
+}
+@/* from org-dartlang-testcase:///patch_lib.dart */ #C1
+class InvalidClassTypeParameterCount3<T extends core::Object? = dynamic, S extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self2::InvalidClassTypeParameterCount3<self2::InvalidClassTypeParameterCount3::T%, self2::InvalidClassTypeParameterCount3::S%>
+    : super core::Object::•()
+    ;
+}
+@#C1
+extension InvalidExtensionTypeParameterCount1 on core::int {
+}
+@#C1
+extension InvalidExtensionTypeParameterCount2<T extends core::Object? = dynamic> on core::int {
+}
+@#C1
+extension InvalidExtensionTypeParameterCount3<T extends core::Object? = dynamic, S extends core::Object? = dynamic> on core::int {
+}
+
+constants  {
+  #C1 = _in::_Patch {}
+}
diff --git a/pkg/front_end/testcases/general/invalid_patch/main.dart.textual_outline.expect b/pkg/front_end/testcases/general/invalid_patch/main.dart.textual_outline.expect
new file mode 100644
index 0000000..3c9c90e
--- /dev/null
+++ b/pkg/front_end/testcases/general/invalid_patch/main.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/general/invalid_patch/main.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/invalid_patch/main.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..3c9c90e
--- /dev/null
+++ b/pkg/front_end/testcases/general/invalid_patch/main.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/general/invalid_patch/origin_lib.dart b/pkg/front_end/testcases/general/invalid_patch/origin_lib.dart
new file mode 100644
index 0000000..d83a119
--- /dev/null
+++ b/pkg/front_end/testcases/general/invalid_patch/origin_lib.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class InvalidClassTypeParameterCount1 {}
+
+class InvalidClassTypeParameterCount2<T> {}
+
+class InvalidClassTypeParameterCount3<T, S> {}
+
+extension InvalidExtensionTypeParameterCount1 on int {}
+
+extension InvalidExtensionTypeParameterCount2<T> on int {}
+
+extension InvalidExtensionTypeParameterCount3<T, S> on int {}
diff --git a/pkg/front_end/testcases/general/invalid_patch/patch_lib.dart b/pkg/front_end/testcases/general/invalid_patch/patch_lib.dart
new file mode 100644
index 0000000..e7e4e9c
--- /dev/null
+++ b/pkg/front_end/testcases/general/invalid_patch/patch_lib.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore: import_internal_library
+import 'dart:_internal';
+
+@patch
+class InvalidClassTypeParameterCount1<T> /* Error */ {}
+
+@patch
+class InvalidClassTypeParameterCount2 /* Error */ {}
+
+@patch
+class InvalidClassTypeParameterCount3<T> /* Error */ {}
+
+@patch
+extension InvalidExtensionTypeParameterCount1<T> on int /* Error */ {}
+
+@patch
+extension InvalidExtensionTypeParameterCount2 on int /* Error */ {}
+
+@patch
+extension InvalidExtensionTypeParameterCount3<T> on int /* Error */ {}
diff --git a/pkg/front_end/testcases/general/patch_internal/internal_lib.dart b/pkg/front_end/testcases/general/patch_internal/internal_lib.dart
new file mode 100644
index 0000000..8d70e16
--- /dev/null
+++ b/pkg/front_end/testcases/general/patch_internal/internal_lib.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:test';
+
+class ClassImpl implements Class {}
diff --git a/pkg/front_end/testcases/general/patch_internal/libraries.json b/pkg/front_end/testcases/general/patch_internal/libraries.json
new file mode 100644
index 0000000..4ee8fa5
--- /dev/null
+++ b/pkg/front_end/testcases/general/patch_internal/libraries.json
@@ -0,0 +1,16 @@
+{
+  "vm": {
+    "comment:0": "This adds to the default libraries found in the platform.",
+    "libraries": {
+      "test": {
+        "patches": [
+          "patch_lib.dart"
+        ],
+        "uri": "origin_lib.dart"
+      },
+      "_test_internal": {
+        "uri": "internal_lib.dart"
+      }
+    }
+  }
+}
diff --git a/pkg/front_end/testcases/general/patch_internal/main.dart b/pkg/front_end/testcases/general/patch_internal/main.dart
new file mode 100644
index 0000000..9e5172c
--- /dev/null
+++ b/pkg/front_end/testcases/general/patch_internal/main.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:test';
+
+main() {
+  new Class();
+}
diff --git a/pkg/front_end/testcases/general/patch_internal/main.dart.strong.expect b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.expect
new file mode 100644
index 0000000..a0b5275
--- /dev/null
+++ b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.expect
@@ -0,0 +1,42 @@
+library;
+import self as self;
+import "dart:_test_internal" as _te;
+
+import "dart:test";
+
+static method main() → dynamic {
+  new _te::ClassImpl::•();
+}
+
+library;
+import self as self2;
+import "dart:_internal" as _in;
+import "dart:core" as core;
+import "dart:_test_internal" as _te;
+
+import "dart:_internal";
+import "dart:_test_internal";
+
+@/* from org-dartlang-testcase:///patch_lib.dart */ #C1
+class Class extends core::Object {
+  @#C1
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ •() → self2::Class /* redirection-target: _te::ClassImpl::• */
+    return new _te::ClassImpl::•();
+}
+
+library /*isUnsupported*/;
+import self as _te;
+import "dart:core" as core;
+import "dart:test" as self2;
+
+import "dart:test";
+
+class ClassImpl extends core::Object implements self2::Class {
+  synthetic constructor •() → _te::ClassImpl
+    : super core::Object::•()
+    ;
+}
+
+constants  {
+  #C1 = _in::_Patch {}
+}
diff --git a/pkg/front_end/testcases/general/patch_internal/main.dart.strong.modular.expect b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.modular.expect
new file mode 100644
index 0000000..a0b5275
--- /dev/null
+++ b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.modular.expect
@@ -0,0 +1,42 @@
+library;
+import self as self;
+import "dart:_test_internal" as _te;
+
+import "dart:test";
+
+static method main() → dynamic {
+  new _te::ClassImpl::•();
+}
+
+library;
+import self as self2;
+import "dart:_internal" as _in;
+import "dart:core" as core;
+import "dart:_test_internal" as _te;
+
+import "dart:_internal";
+import "dart:_test_internal";
+
+@/* from org-dartlang-testcase:///patch_lib.dart */ #C1
+class Class extends core::Object {
+  @#C1
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ •() → self2::Class /* redirection-target: _te::ClassImpl::• */
+    return new _te::ClassImpl::•();
+}
+
+library /*isUnsupported*/;
+import self as _te;
+import "dart:core" as core;
+import "dart:test" as self2;
+
+import "dart:test";
+
+class ClassImpl extends core::Object implements self2::Class {
+  synthetic constructor •() → _te::ClassImpl
+    : super core::Object::•()
+    ;
+}
+
+constants  {
+  #C1 = _in::_Patch {}
+}
diff --git a/pkg/front_end/testcases/general/patch_internal/main.dart.strong.outline.expect b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.outline.expect
new file mode 100644
index 0000000..8f6d2b5
--- /dev/null
+++ b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.outline.expect
@@ -0,0 +1,41 @@
+library;
+import self as self;
+
+import "dart:test";
+
+static method main() → dynamic
+  ;
+
+library;
+import self as self2;
+import "dart:_internal" as _in;
+import "dart:core" as core;
+import "dart:_test_internal" as _te;
+
+import "dart:_internal";
+import "dart:_test_internal";
+
+@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch
+class Class extends core::Object {
+  @_in::patch
+  external static factory •() → self2::Class /* redirection-target: _te::ClassImpl::• */
+    return new _te::ClassImpl::•();
+}
+
+library /*isUnsupported*/;
+import self as _te;
+import "dart:core" as core;
+import "dart:test" as self2;
+
+import "dart:test";
+
+class ClassImpl extends core::Object implements self2::Class {
+  synthetic constructor •() → _te::ClassImpl
+    ;
+}
+
+
+Extra constant evaluation status:
+Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:9:1 -> InstanceConstant(const _Patch{})
+Evaluated: StaticGet @ (unknown position in org-dartlang-testcase:///origin_lib.dart) -> InstanceConstant(const _Patch{})
+Extra constant evaluation: evaluated: 3, effectively constant: 2
diff --git a/pkg/front_end/testcases/general/patch_internal/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.transformed.expect
new file mode 100644
index 0000000..a0b5275
--- /dev/null
+++ b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.transformed.expect
@@ -0,0 +1,42 @@
+library;
+import self as self;
+import "dart:_test_internal" as _te;
+
+import "dart:test";
+
+static method main() → dynamic {
+  new _te::ClassImpl::•();
+}
+
+library;
+import self as self2;
+import "dart:_internal" as _in;
+import "dart:core" as core;
+import "dart:_test_internal" as _te;
+
+import "dart:_internal";
+import "dart:_test_internal";
+
+@/* from org-dartlang-testcase:///patch_lib.dart */ #C1
+class Class extends core::Object {
+  @#C1
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ •() → self2::Class /* redirection-target: _te::ClassImpl::• */
+    return new _te::ClassImpl::•();
+}
+
+library /*isUnsupported*/;
+import self as _te;
+import "dart:core" as core;
+import "dart:test" as self2;
+
+import "dart:test";
+
+class ClassImpl extends core::Object implements self2::Class {
+  synthetic constructor •() → _te::ClassImpl
+    : super core::Object::•()
+    ;
+}
+
+constants  {
+  #C1 = _in::_Patch {}
+}
diff --git a/pkg/front_end/testcases/general/patch_internal/main.dart.textual_outline.expect b/pkg/front_end/testcases/general/patch_internal/main.dart.textual_outline.expect
new file mode 100644
index 0000000..3c9c90e
--- /dev/null
+++ b/pkg/front_end/testcases/general/patch_internal/main.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/general/patch_internal/main.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/patch_internal/main.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..3c9c90e
--- /dev/null
+++ b/pkg/front_end/testcases/general/patch_internal/main.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/general/patch_internal/origin_lib.dart b/pkg/front_end/testcases/general/patch_internal/origin_lib.dart
new file mode 100644
index 0000000..76d3e5f
--- /dev/null
+++ b/pkg/front_end/testcases/general/patch_internal/origin_lib.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class {
+  external factory Class();
+}
diff --git a/pkg/front_end/testcases/general/patch_internal/patch_lib.dart b/pkg/front_end/testcases/general/patch_internal/patch_lib.dart
new file mode 100644
index 0000000..0afb1b5
--- /dev/null
+++ b/pkg/front_end/testcases/general/patch_internal/patch_lib.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// ignore: import_internal_library
+import 'dart:_internal';
+import 'dart:_test_internal';
+
+@patch
+class Class {
+  @patch
+  factory Class() = ClassImpl;
+}
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index 769106e..b7108eb 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -95,6 +95,7 @@
 general/factory_patch/main: SemiFuzzFailure
 general/inject_private_patch/main: SemiFuzzFailure
 general/inject_public/main: SemiFuzzFailure
+general/invalid_patch/main: SemiFuzzFailure
 general/issue45101/main: SemiFuzzFailure
 general/mixin_from_patch/main: SemiFuzzFailure
 general/multiple_class_patches/main: SemiFuzzFailure
@@ -105,6 +106,7 @@
 general/patch_extends_implements/main: SemiFuzzFailure
 general/patch_extension_scope/main: SemiFuzzFailure
 general/patch_getter/main: SemiFuzzFailure
+general/patch_internal/main: SemiFuzzFailure
 general/patch_prefix_access/main: SemiFuzzFailure
 general/patch_type_parameters/main: SemiFuzzFailure
 general/tear_off_patch/main: SemiFuzzFailure