[cfe] Create SourceClassBuilder throught ClassDeclaration+Fragment

Change-Id: I9e5c1f6b15ce7d1f0814682904a2281589c3931e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/408020
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/builder/class_builder.dart b/pkg/front_end/lib/src/builder/class_builder.dart
index 167dcaa..1825f76 100644
--- a/pkg/front_end/lib/src/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/builder/class_builder.dart
@@ -98,9 +98,6 @@
   /// The type in the `implements` clause of a class or mixin declaration.
   List<TypeBuilder>? get interfaceBuilders;
 
-  /// The types in the `on` clause of an extension or mixin declaration.
-  List<TypeBuilder>? get onTypes;
-
   @override
   Uri get fileUri;
 
@@ -124,7 +121,7 @@
 
   bool get isAnonymousMixinApplication;
 
-  abstract TypeBuilder? mixedInTypeBuilder;
+  TypeBuilder? get mixedInTypeBuilder;
 
   bool get isFutureOr;
 
diff --git a/pkg/front_end/lib/src/dill/dill_class_builder.dart b/pkg/front_end/lib/src/dill/dill_class_builder.dart
index 477fbb7..ada6e1c 100644
--- a/pkg/front_end/lib/src/dill/dill_class_builder.dart
+++ b/pkg/front_end/lib/src/dill/dill_class_builder.dart
@@ -7,7 +7,6 @@
 
 import '../base/loader.dart';
 import '../base/name_space.dart';
-import '../base/problems.dart' show unimplemented;
 import '../base/scope.dart';
 import '../builder/builder.dart';
 import '../builder/declaration_builders.dart';
@@ -148,10 +147,6 @@
     return supertype;
   }
 
-  @override
-  // Coverage-ignore(suite): Not run.
-  List<TypeBuilder>? get onTypes => null;
-
   void addField(Field field) {
     DillFieldBuilder builder =
         new DillFieldBuilder(field, libraryBuilder, this);
@@ -240,12 +235,6 @@
   }
 
   @override
-  // Coverage-ignore(suite): Not run.
-  void set mixedInTypeBuilder(TypeBuilder? mixin) {
-    unimplemented("mixedInType=", -1, null);
-  }
-
-  @override
   List<TypeBuilder>? get interfaceBuilders {
     if (cls.implementedTypes.isEmpty) return null;
     List<TypeBuilder>? interfaceBuilders = _interfaceBuilders;
diff --git a/pkg/front_end/lib/src/fragment/class/declaration.dart b/pkg/front_end/lib/src/fragment/class/declaration.dart
new file mode 100644
index 0000000..56f7480
--- /dev/null
+++ b/pkg/front_end/lib/src/fragment/class/declaration.dart
@@ -0,0 +1,238 @@
+// 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.
+
+part of '../fragment.dart';
+
+abstract class ClassDeclaration {
+  String get name;
+  List<MetadataBuilder>? get metadata;
+  LookupScope get compilationUnitScope;
+  Uri get fileUri;
+  int get nameOffset;
+  int get startOffset;
+  int get endOffset;
+  List<NominalParameterBuilder>? get typeParameters;
+  bool get isMixinDeclaration;
+
+  TypeBuilder? get supertype;
+  List<TypeBuilder>? get mixedInTypes;
+  List<TypeBuilder>? get interfaces;
+}
+
+class RegularClassDeclaration implements ClassDeclaration {
+  final ClassFragment _fragment;
+
+  RegularClassDeclaration(this._fragment);
+
+  @override
+  List<MetadataBuilder>? get metadata => _fragment.metadata;
+
+  @override
+  LookupScope get compilationUnitScope => _fragment.compilationUnitScope;
+
+  @override
+  Uri get fileUri => _fragment.fileUri;
+
+  @override
+  int get endOffset => _fragment.endOffset;
+
+  @override
+  String get name => _fragment.name;
+
+  @override
+  int get nameOffset => _fragment.nameOffset;
+
+  @override
+  int get startOffset => _fragment.startOffset;
+
+  @override
+  List<NominalParameterBuilder>? get typeParameters => _fragment.typeParameters;
+
+  @override
+  bool get isMixinDeclaration => false;
+
+  @override
+  TypeBuilder? get supertype => _fragment.supertype;
+
+  @override
+  List<TypeBuilder>? get mixedInTypes => _fragment.mixins;
+
+  @override
+  List<TypeBuilder>? get interfaces => _fragment.interfaces;
+}
+
+class EnumDeclaration implements ClassDeclaration {
+  final EnumFragment _fragment;
+
+  @override
+  final TypeBuilder supertype;
+
+  EnumDeclaration(this._fragment, this.supertype);
+
+  @override
+  List<MetadataBuilder>? get metadata => _fragment.metadata;
+
+  @override
+  LookupScope get compilationUnitScope => _fragment.compilationUnitScope;
+
+  @override
+  Uri get fileUri => _fragment.fileUri;
+
+  @override
+  int get endOffset => _fragment.endOffset;
+
+  @override
+  String get name => _fragment.name;
+
+  @override
+  int get nameOffset => _fragment.nameOffset;
+
+  @override
+  int get startOffset => _fragment.startOffset;
+
+  @override
+  List<NominalParameterBuilder>? get typeParameters => _fragment.typeParameters;
+
+  @override
+  bool get isMixinDeclaration => false;
+
+  @override
+  List<TypeBuilder>? get mixedInTypes => _fragment.mixins;
+
+  @override
+  List<TypeBuilder>? get interfaces => _fragment.interfaces;
+}
+
+class NamedMixinApplication implements ClassDeclaration {
+  final NamedMixinApplicationFragment _fragment;
+
+  @override
+  final List<TypeBuilder> mixedInTypes;
+
+  NamedMixinApplication(this._fragment, this.mixedInTypes);
+
+  @override
+  List<MetadataBuilder>? get metadata => _fragment.metadata;
+
+  @override
+  LookupScope get compilationUnitScope => _fragment.compilationUnitScope;
+
+  @override
+  Uri get fileUri => _fragment.fileUri;
+
+  @override
+  int get endOffset => _fragment.endOffset;
+
+  @override
+  String get name => _fragment.name;
+
+  @override
+  int get nameOffset => _fragment.nameOffset;
+
+  @override
+  int get startOffset => _fragment.startOffset;
+
+  @override
+  List<NominalParameterBuilder>? get typeParameters => _fragment.typeParameters;
+
+  @override
+  bool get isMixinDeclaration => false;
+
+  @override
+  TypeBuilder? get supertype => _fragment.supertype;
+
+  @override
+  List<TypeBuilder>? get interfaces => _fragment.interfaces;
+}
+
+class AnonymousMixinApplication implements ClassDeclaration {
+  @override
+  final String name;
+
+  @override
+  final LookupScope compilationUnitScope;
+
+  @override
+  final int nameOffset;
+
+  @override
+  final int startOffset;
+
+  @override
+  final int endOffset;
+
+  @override
+  final Uri fileUri;
+
+  @override
+  final List<NominalParameterBuilder>? typeParameters;
+
+  @override
+  final TypeBuilder? supertype;
+
+  @override
+  bool get isMixinDeclaration => false;
+
+  @override
+  List<TypeBuilder>? get mixedInTypes => null;
+
+  @override
+  final List<TypeBuilder>? interfaces;
+
+  AnonymousMixinApplication(
+      {required this.name,
+      required this.compilationUnitScope,
+      required this.fileUri,
+      required this.nameOffset,
+      required this.startOffset,
+      required this.endOffset,
+      required this.typeParameters,
+      required this.supertype,
+      required this.interfaces});
+
+  @override
+  List<MetadataBuilder>? get metadata => null;
+}
+
+class MixinDeclaration implements ClassDeclaration {
+  final MixinFragment _fragment;
+
+  MixinDeclaration(this._fragment);
+
+  @override
+  List<MetadataBuilder>? get metadata => _fragment.metadata;
+
+  @override
+  LookupScope get compilationUnitScope => _fragment.compilationUnitScope;
+
+  @override
+  Uri get fileUri => _fragment.fileUri;
+
+  @override
+  int get endOffset => _fragment.endOffset;
+
+  @override
+  String get name => _fragment.name;
+
+  @override
+  int get nameOffset => _fragment.nameOffset;
+
+  @override
+  int get startOffset => _fragment.startOffset;
+
+  @override
+  List<NominalParameterBuilder>? get typeParameters => _fragment.typeParameters;
+
+  @override
+  bool get isMixinDeclaration => true;
+
+  @override
+  TypeBuilder? get supertype => _fragment.supertype;
+
+  @override
+  List<TypeBuilder>? get mixedInTypes => _fragment.mixins;
+
+  @override
+  List<TypeBuilder>? get interfaces => _fragment.interfaces;
+}
diff --git a/pkg/front_end/lib/src/fragment/fragment.dart b/pkg/front_end/lib/src/fragment/fragment.dart
index c57b997..5fdae9c 100644
--- a/pkg/front_end/lib/src/fragment/fragment.dart
+++ b/pkg/front_end/lib/src/fragment/fragment.dart
@@ -62,6 +62,7 @@
 import '../type_inference/type_schema.dart';
 
 part 'class.dart';
+part 'class/declaration.dart';
 part 'constructor.dart';
 part 'enum.dart';
 part 'enum_element.dart';
diff --git a/pkg/front_end/lib/src/kernel/hierarchy/hierarchy_node.dart b/pkg/front_end/lib/src/kernel/hierarchy/hierarchy_node.dart
index 01ee717..907d6cc 100644
--- a/pkg/front_end/lib/src/kernel/hierarchy/hierarchy_node.dart
+++ b/pkg/front_end/lib/src/kernel/hierarchy/hierarchy_node.dart
@@ -10,10 +10,9 @@
 import '../../builder/builder.dart';
 import '../../builder/declaration_builders.dart';
 import '../../builder/library_builder.dart';
-import '../../builder/named_type_builder.dart';
-import '../../builder/nullability_builder.dart';
 import '../../builder/type_builder.dart';
 import '../../codes/cfe_codes.dart';
+import '../../source/source_class_builder.dart';
 import '../../source/source_library_builder.dart';
 import '../../testing/id_testing_utils.dart' show typeToText;
 import '../../type_inference/type_schema.dart' show UnknownType;
@@ -264,25 +263,15 @@
     if (typeArguments.isEmpty || typeArguments.first is! UnknownType) {
       return mixinNode;
     }
-    new BuilderMixinInferrer(_classBuilder, _hierarchy,
-            mixedInSupertype.classNode.typeParameters)
-        .infer(cls);
-    InterfaceType mixedInType = cls.mixedInType!.asInterfaceType;
-    TypeBuilder mixedInTypeBuilder = _classBuilder.mixedInTypeBuilder!;
-    _classBuilder.mixedInTypeBuilder = new NamedTypeBuilderImpl.forDartType(
-        mixedInType,
-        mixedInTypeBuilder.declaration!,
-        new NullabilityBuilder.fromNullability(Nullability.nonNullable),
-        arguments: new List<TypeBuilder>.generate(typeArguments.length,
-            (int i) => _hierarchy.loader.computeTypeBuilder(typeArguments[i]),
-            growable: false),
-        fileUri: mixedInTypeBuilder.fileUri,
-        charOffset: mixedInTypeBuilder.charOffset);
-    LibraryBuilder library = _classBuilder.libraryBuilder;
-    if (library is SourceLibraryBuilder) {
-      library.registerBoundsCheck(mixedInType, mixedInTypeBuilder.fileUri!,
-          mixedInTypeBuilder.charOffset!, TypeUse.classWithType,
-          inferred: true);
+    ClassBuilder classBuilder = _classBuilder;
+    if (classBuilder is SourceClassBuilder) {
+      new BuilderMixinInferrer(classBuilder, _hierarchy,
+              mixedInSupertype.classNode.typeParameters)
+          .infer(cls);
+      classBuilder.setInferredMixedInTypeArguments(
+          new List<TypeBuilder>.generate(typeArguments.length,
+              (int i) => _hierarchy.loader.computeTypeBuilder(typeArguments[i]),
+              growable: false));
     }
     return mixinNode;
   }
diff --git a/pkg/front_end/lib/src/kernel/hierarchy/mixin_inferrer.dart b/pkg/front_end/lib/src/kernel/hierarchy/mixin_inferrer.dart
index cb9989f..7bd371b 100644
--- a/pkg/front_end/lib/src/kernel/hierarchy/mixin_inferrer.dart
+++ b/pkg/front_end/lib/src/kernel/hierarchy/mixin_inferrer.dart
@@ -11,18 +11,18 @@
 import '../../base/messages.dart'
     show Message, templateMixinInferenceNoMatchingClass;
 import '../../base/problems.dart' show unexpected, unsupported;
-import '../../builder/declaration_builders.dart';
+import '../../source/source_class_builder.dart';
 import '../../type_inference/type_schema.dart';
 
 class BuilderMixinInferrer {
   final CoreTypes coreTypes;
   final _MixinInferenceSolution _mixinInferenceSolution;
   final List<TypeParameter> typeParametersToSolveFor;
-  final ClassBuilder cls;
+  final SourceClassBuilder classBuilder;
   final ClassHierarchyBase classHierarchyBase;
 
   BuilderMixinInferrer(
-      this.cls, this.classHierarchyBase, this.typeParametersToSolveFor)
+      this.classBuilder, this.classHierarchyBase, this.typeParametersToSolveFor)
       : coreTypes = classHierarchyBase.coreTypes,
         _mixinInferenceSolution =
             new _MixinInferenceSolution(typeParametersToSolveFor);
@@ -181,13 +181,16 @@
 
   // Coverage-ignore(suite): Not run.
   void reportProblem(Message message, Class kernelClass) {
-    int length = cls.isMixinApplication ? 1 : cls.fullNameForErrors.length;
-    cls.addProblem(message, cls.fileOffset, length);
+    int length = classBuilder.isMixinApplication
+        ? 1
+        : classBuilder.fullNameForErrors.length;
+    classBuilder.addProblem(message, classBuilder.fileOffset, length);
   }
 
   // Coverage-ignore(suite): Not run.
   Never reportUnsupportedProblem(String operation) {
-    return unsupported(operation, cls.fileOffset, cls.fileUri);
+    return unsupported(
+        operation, classBuilder.fileOffset, classBuilder.fileUri);
   }
 }
 
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 ba7dae6..5e50ac4 100644
--- a/pkg/front_end/lib/src/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/source/source_class_builder.dart
@@ -108,8 +108,6 @@
 
   final Modifiers _modifiers;
 
-  final List<MetadataBuilder>? metadata;
-
   final Class actualCls;
 
   final DeclarationNameSpaceBuilder nameSpaceBuilder;
@@ -128,23 +126,15 @@
 
   TypeBuilder? _supertypeBuilder;
 
-  @override
-  List<TypeBuilder>? interfaceBuilders;
-
-  @override
-  List<TypeBuilder>? onTypes;
+  List<TypeBuilder>? _interfaceBuilders;
 
   @override
   final List<ConstructorReferenceBuilder>? constructorReferences;
 
-  @override
-  TypeBuilder? mixedInTypeBuilder;
+  TypeBuilder? _mixedInTypeBuilder;
 
   final IndexedClass? indexedClass;
 
-  @override
-  bool isMixinDeclaration;
-
   bool? _isConflictingAugmentationMember;
 
   /// Returns `true` if this class is a class declared in an augmentation
@@ -163,31 +153,32 @@
 
   MergedClassMemberScope? _mergedScope;
 
-  ClassDeclaration _classDeclaration;
+  final ClassDeclaration _introductory;
 
   SourceClassBuilder(
-      {required this.metadata,
-      required Modifiers modifiers,
+      {required Modifiers modifiers,
       required this.name,
       required this.typeParameters,
-      required this.interfaceBuilders,
-      required this.onTypes,
       required this.typeParameterScope,
       required this.nameSpaceBuilder,
       required this.libraryBuilder,
       required this.constructorReferences,
       required this.fileUri,
-      required int startOffset,
       required this.nameOffset,
-      required int endOffset,
       this.indexedClass,
-      this.mixedInTypeBuilder,
-      this.isMixinDeclaration = false,
+      TypeBuilder? mixedInTypeBuilder,
       required ClassDeclaration classDeclaration})
       : _modifiers = modifiers,
-        _classDeclaration = classDeclaration,
-        actualCls = initializeClass(typeParameters, name, fileUri, startOffset,
-            nameOffset, endOffset, indexedClass,
+        _introductory = classDeclaration,
+        _mixedInTypeBuilder = mixedInTypeBuilder,
+        actualCls = initializeClass(
+            typeParameters,
+            name,
+            fileUri,
+            classDeclaration.startOffset,
+            classDeclaration.nameOffset,
+            classDeclaration.endOffset,
+            indexedClass,
             isAugmentation: modifiers.isAugment) {
     actualCls.hasConstConstructor = declaresConstConstructor;
   }
@@ -236,11 +227,16 @@
   bool get isAugment => _modifiers.isAugment;
 
   @override
+  bool get isMixinDeclaration => _introductory.isMixinDeclaration;
+
+  @override
   LookupScope get scope => _scope;
 
   @override
   DeclarationNameSpace get nameSpace => _nameSpace;
 
+  List<MetadataBuilder>? get metadata => _introductory.metadata;
+
   @override
   ConstructorScope get constructorScope => _constructorScope;
 
@@ -273,9 +269,9 @@
 
   SourceClassBuilder? actualOrigin;
 
-  bool _hasComputedSupertype = false;
+  bool _hasComputedSupertypes = false;
 
-  TypeBuilder? computeSupertypeBuilder({
+  void computeSupertypeBuilder({
     required SourceLoader loader,
     required ProblemReporting problemReporting,
     required List<NominalParameterBuilder> unboundNominalParameters,
@@ -283,25 +279,25 @@
     required Map<SourceClassBuilder, TypeBuilder> mixinApplications,
     required void Function(SourceClassBuilder) addAnonymousMixinClassBuilder,
   }) {
-    assert(!_hasComputedSupertype, "Supertype has already been computed.");
-    _hasComputedSupertype = true;
-    return _supertypeBuilder = _applyMixins(
+    assert(!_hasComputedSupertypes, "Supertypes have already been computed.");
+    _hasComputedSupertypes = true;
+    _supertypeBuilder = _applyMixins(
         unboundNominalParameters: unboundNominalParameters,
-        compilationUnitScope: _classDeclaration.compilationUnitScope,
+        compilationUnitScope: _introductory.compilationUnitScope,
         problemReporting: problemReporting,
         objectTypeBuilder: loader.target.objectType,
         enclosingLibraryBuilder: libraryBuilder,
-        fileUri: _classDeclaration.fileUri,
+        fileUri: _introductory.fileUri,
         indexedLibrary: indexedLibrary,
-        supertype: _classDeclaration.supertype,
-        mixins: _classDeclaration.mixins,
+        supertype: _introductory.supertype,
+        mixins: _introductory.mixedInTypes,
         mixinApplications: mixinApplications,
-        startOffset: _classDeclaration.startOffset,
-        nameOffset: _classDeclaration.nameOffset,
-        endOffset: _classDeclaration.endOffset,
-        subclassName: _classDeclaration.name,
-        isMixinDeclaration: _classDeclaration.isMixinDeclaration,
-        typeParameters: _classDeclaration.typeParameters,
+        startOffset: _introductory.startOffset,
+        nameOffset: _introductory.nameOffset,
+        endOffset: _introductory.endOffset,
+        subclassName: _introductory.name,
+        isMixinDeclaration: _introductory.isMixinDeclaration,
+        typeParameters: _introductory.typeParameters,
         modifiers: Modifiers.empty,
         onAnonymousMixin: (SourceClassBuilder anonymousMixinBuilder) {
           Reference? reference = anonymousMixinBuilder.indexedClass?.reference;
@@ -312,11 +308,12 @@
           addAnonymousMixinClassBuilder(anonymousMixinBuilder);
           anonymousMixinBuilder.buildScopes(loader.coreLibrary);
         });
+    _interfaceBuilders = _introductory.interfaces;
   }
 
   void markAsCyclic(ClassBuilder objectClass) {
-    assert(
-        _hasComputedSupertype, "Supertype of $this has not been computed yet.");
+    assert(_hasComputedSupertypes,
+        "Supertype of $this has not been computed yet.");
 
     // Ensure that the cycle is broken by removing superclass and
     // implemented interfaces.
@@ -327,8 +324,8 @@
         objectClass, const NullabilityBuilder.omitted(),
         instanceTypeParameterAccess:
             InstanceTypeParameterAccessState.Unexpected);
-    interfaceBuilders = null;
-    mixedInTypeBuilder = null;
+    _interfaceBuilders = null;
+    _mixedInTypeBuilder = null;
 
     // TODO(johnniwinther): Update the message for when a class depends on
     // a cycle but does not depend on itself.
@@ -336,15 +333,43 @@
         fileOffset, noLength);
   }
 
-  @override
-  TypeBuilder? get supertypeBuilder {
-    assert(
-        _hasComputedSupertype, "Supertype of $this has not been computed yet.");
-    return _supertypeBuilder;
+  // Coverage-ignore(suite): Not run.
+  /// Check that this class, which is the `Object` class,  has no supertypes.
+  /// Recover by removing any found.
+  void checkObjectSupertypes() {
+    if (_supertypeBuilder != null) {
+      _supertypeBuilder = null;
+      addProblem(messageObjectExtends, fileOffset, noLength);
+    }
+    if (_interfaceBuilders != null) {
+      addProblem(messageObjectImplements, fileOffset, noLength);
+      _interfaceBuilders = null;
+    }
+    if (_mixedInTypeBuilder != null) {
+      addProblem(messageObjectMixesIn, fileOffset, noLength);
+      _mixedInTypeBuilder = null;
+    }
   }
 
-  void set supertypeBuilder(TypeBuilder? value) {
-    _supertypeBuilder = value;
+  void installDefaultSupertypes(
+      ClassBuilder objectClassBuilder, Class objectClass) {
+    if (objectClass != cls) {
+      cls.supertype ??= objectClass.asRawSupertype;
+      _supertypeBuilder ??= new NamedTypeBuilderImpl.fromTypeDeclarationBuilder(
+          objectClassBuilder, const NullabilityBuilder.omitted(),
+          instanceTypeParameterAccess:
+              InstanceTypeParameterAccessState.Unexpected);
+    }
+    if (isMixinApplication) {
+      cls.mixedInType = mixedInTypeBuilder!.buildMixedInType(libraryBuilder);
+    }
+  }
+
+  @override
+  TypeBuilder? get supertypeBuilder {
+    assert(_hasComputedSupertypes,
+        "Supertype of $this has not been computed yet.");
+    return _supertypeBuilder;
   }
 
   @override
@@ -422,17 +447,16 @@
     }
     actualCls.supertype = supertype;
 
-    if (mixedInTypeBuilder != null) {
-      mixedInTypeBuilder = _checkSupertype(mixedInTypeBuilder!);
+    if (_mixedInTypeBuilder != null) {
+      _mixedInTypeBuilder = _checkSupertype(_mixedInTypeBuilder!);
     }
     Supertype? mixedInType =
-        mixedInTypeBuilder?.buildMixedInType(libraryBuilder);
+        _mixedInTypeBuilder?.buildMixedInType(libraryBuilder);
     if (mixedInType != null &&
         LibraryBuilder.isFunction(mixedInType.classNode, coreLibrary)) {
       mixedInType = null;
-      mixedInTypeBuilder = null;
+      _mixedInTypeBuilder = null;
       actualCls.isAnonymousMixin = false;
-      isMixinDeclaration = false;
     }
     actualCls.isMixinDeclaration = isMixinDeclaration;
     actualCls.mixedInType = mixedInType;
@@ -446,10 +470,11 @@
     cls.isInterface = isInterface;
     cls.isFinal = isFinal;
 
+    List<TypeBuilder>? interfaceBuilders = this.interfaceBuilders;
     if (interfaceBuilders != null) {
-      for (int i = 0; i < interfaceBuilders!.length; ++i) {
-        interfaceBuilders![i] = _checkSupertype(interfaceBuilders![i]);
-        Supertype? supertype = interfaceBuilders![i]
+      for (int i = 0; i < interfaceBuilders.length; ++i) {
+        interfaceBuilders[i] = _checkSupertype(interfaceBuilders[i]);
+        Supertype? supertype = interfaceBuilders[i]
             .buildSupertype(libraryBuilder, TypeUse.classImplementsType);
         if (supertype != null) {
           if (LibraryBuilder.isFunction(supertype.classNode, coreLibrary)) {
@@ -465,6 +490,30 @@
     return cls;
   }
 
+  @override
+  List<TypeBuilder>? get interfaceBuilders {
+    assert(_hasComputedSupertypes, "Interfaces have not been computed yet.");
+    return _interfaceBuilders;
+  }
+
+  @override
+  TypeBuilder? get mixedInTypeBuilder => _mixedInTypeBuilder;
+
+  void setInferredMixedInTypeArguments(List<TypeBuilder> typeArguments) {
+    InterfaceType mixedInType = cls.mixedInType!.asInterfaceType;
+    TypeBuilder mixedInTypeBuilder = _mixedInTypeBuilder!;
+    _mixedInTypeBuilder = new NamedTypeBuilderImpl.forDartType(
+        mixedInType,
+        mixedInTypeBuilder.declaration!,
+        new NullabilityBuilder.fromNullability(Nullability.nonNullable),
+        arguments: typeArguments,
+        fileUri: mixedInTypeBuilder.fileUri,
+        charOffset: mixedInTypeBuilder.charOffset);
+    libraryBuilder.registerBoundsCheck(mixedInType, mixedInTypeBuilder.fileUri!,
+        mixedInTypeBuilder.charOffset!, TypeUse.classWithType,
+        inferred: true);
+  }
+
   BodyBuilderContext createBodyBuilderContext() {
     return new ClassBodyBuilderContext(this);
   }
@@ -915,7 +964,7 @@
       }
     }
     if (classHierarchyNode.isMixinApplication) {
-      assert(mixedInTypeBuilder != null,
+      assert(_mixedInTypeBuilder != null,
           "No mixed in type builder for mixin application $this.");
       ClassHierarchyNode mixedInNode = classHierarchyNode.mixedInNode!;
       ClassHierarchyNode? mixinSuperClassNode =
@@ -926,7 +975,7 @@
         addProblem(
             templateMixinInheritsFromNotObject
                 .withArguments(mixedInNode.classBuilder.name),
-            mixedInTypeBuilder!.charOffset ?? TreeNode.noOffset,
+            _mixedInTypeBuilder!.charOffset ?? TreeNode.noOffset,
             noLength);
       }
     }
@@ -1355,7 +1404,8 @@
     } else if (objectClass != this) {
       result[objectClass] = null;
     }
-    final List<TypeBuilder>? interfaces = this.interfaceBuilders;
+
+    final List<TypeBuilder>? interfaces = interfaceBuilders;
     if (interfaces != null) {
       for (int i = 0; i < interfaces.length; i++) {
         TypeBuilder interface = interfaces[i];
@@ -1366,7 +1416,7 @@
             declaration is TypeAliasBuilder ? declaration : null;
       }
     }
-    final TypeBuilder? mixedInTypeBuilder = this.mixedInTypeBuilder;
+    final TypeBuilder? mixedInTypeBuilder = _mixedInTypeBuilder;
     if (mixedInTypeBuilder != null) {
       TypeDeclarationBuilder? declaration = mixedInTypeBuilder.declaration;
       TypeDeclarationBuilder? unaliasedDeclaration =
@@ -2136,205 +2186,6 @@
       classDeclaration._augmentations;
 }
 
-abstract class ClassDeclaration {
-  String get name;
-  LookupScope get compilationUnitScope;
-  Uri get fileUri;
-  int get nameOffset;
-  int get startOffset;
-  int get endOffset;
-  List<NominalParameterBuilder>? get typeParameters;
-  bool get isMixinDeclaration;
-  TypeBuilder? get supertype;
-  List<TypeBuilder>? get mixins;
-}
-
-class RegularClassDeclaration implements ClassDeclaration {
-  final ClassFragment _fragment;
-
-  RegularClassDeclaration(this._fragment);
-
-  @override
-  LookupScope get compilationUnitScope => _fragment.compilationUnitScope;
-
-  @override
-  Uri get fileUri => _fragment.fileUri;
-
-  @override
-  int get endOffset => _fragment.endOffset;
-
-  @override
-  String get name => _fragment.name;
-
-  @override
-  int get nameOffset => _fragment.nameOffset;
-
-  @override
-  int get startOffset => _fragment.startOffset;
-
-  @override
-  List<NominalParameterBuilder>? get typeParameters => _fragment.typeParameters;
-
-  @override
-  bool get isMixinDeclaration => false;
-
-  @override
-  TypeBuilder? get supertype => _fragment.supertype;
-
-  @override
-  List<TypeBuilder>? get mixins => _fragment.mixins;
-}
-
-class EnumDeclaration implements ClassDeclaration {
-  final EnumFragment _fragment;
-
-  @override
-  final TypeBuilder supertype;
-
-  EnumDeclaration(this._fragment, this.supertype);
-
-  @override
-  LookupScope get compilationUnitScope => _fragment.compilationUnitScope;
-
-  @override
-  Uri get fileUri => _fragment.fileUri;
-
-  @override
-  int get endOffset => _fragment.endOffset;
-
-  @override
-  String get name => _fragment.name;
-
-  @override
-  int get nameOffset => _fragment.nameOffset;
-
-  @override
-  int get startOffset => _fragment.startOffset;
-
-  @override
-  List<NominalParameterBuilder>? get typeParameters => _fragment.typeParameters;
-
-  @override
-  bool get isMixinDeclaration => false;
-
-  @override
-  List<TypeBuilder>? get mixins => _fragment.mixins;
-}
-
-class NamedMixinApplication implements ClassDeclaration {
-  final NamedMixinApplicationFragment _fragment;
-
-  @override
-  final List<TypeBuilder> mixins;
-
-  NamedMixinApplication(this._fragment, this.mixins);
-
-  @override
-  LookupScope get compilationUnitScope => _fragment.compilationUnitScope;
-
-  @override
-  Uri get fileUri => _fragment.fileUri;
-
-  @override
-  int get endOffset => _fragment.endOffset;
-
-  @override
-  String get name => _fragment.name;
-
-  @override
-  int get nameOffset => _fragment.nameOffset;
-
-  @override
-  int get startOffset => _fragment.startOffset;
-
-  @override
-  List<NominalParameterBuilder>? get typeParameters => _fragment.typeParameters;
-
-  @override
-  bool get isMixinDeclaration => false;
-
-  @override
-  TypeBuilder? get supertype => _fragment.supertype;
-}
-
-class AnonymousMixinApplication implements ClassDeclaration {
-  @override
-  final String name;
-
-  @override
-  final LookupScope compilationUnitScope;
-
-  @override
-  final int nameOffset;
-
-  @override
-  final int startOffset;
-
-  @override
-  final int endOffset;
-
-  @override
-  final Uri fileUri;
-
-  @override
-  final List<NominalParameterBuilder>? typeParameters;
-
-  @override
-  final TypeBuilder? supertype;
-
-  @override
-  bool get isMixinDeclaration => false;
-
-  @override
-  List<TypeBuilder>? get mixins => null;
-
-  AnonymousMixinApplication(
-      {required this.name,
-      required this.compilationUnitScope,
-      required this.fileUri,
-      required this.nameOffset,
-      required this.startOffset,
-      required this.endOffset,
-      required this.typeParameters,
-      required this.supertype});
-}
-
-class MixinDeclaration implements ClassDeclaration {
-  final MixinFragment _fragment;
-
-  MixinDeclaration(this._fragment);
-
-  @override
-  LookupScope get compilationUnitScope => _fragment.compilationUnitScope;
-
-  @override
-  Uri get fileUri => _fragment.fileUri;
-
-  @override
-  int get endOffset => _fragment.endOffset;
-
-  @override
-  String get name => _fragment.name;
-
-  @override
-  int get nameOffset => _fragment.nameOffset;
-
-  @override
-  int get startOffset => _fragment.startOffset;
-
-  @override
-  List<NominalParameterBuilder>? get typeParameters => _fragment.typeParameters;
-
-  @override
-  bool get isMixinDeclaration => true;
-
-  @override
-  TypeBuilder? get supertype => _fragment.supertype;
-
-  @override
-  List<TypeBuilder>? get mixins => _fragment.mixins;
-}
-
 TypeBuilder? _applyMixins(
     {required ProblemReporting problemReporting,
     required SourceLibraryBuilder enclosingLibraryBuilder,
@@ -2492,6 +2343,7 @@
         name: fullname,
         compilationUnitScope: compilationUnitScope,
         supertype: isMixinDeclaration ? null : supertype,
+        interfaces: isMixinDeclaration ? [supertype!, mixin] : null,
         typeParameters: applicationTypeParameters,
         fileUri: fileUri,
         startOffset: computedStartOffset,
@@ -2508,20 +2360,15 @@
     DeclarationNameSpaceBuilder nameSpaceBuilder =
         new DeclarationNameSpaceBuilder.empty();
     SourceClassBuilder application = new SourceClassBuilder(
-        metadata: null,
         modifiers: Modifiers.Abstract,
         name: fullname,
         typeParameters: applicationTypeParameters,
-        interfaceBuilders: isMixinDeclaration ? [supertype!, mixin] : null,
-        onTypes: null,
         typeParameterScope: typeParameterScope,
         nameSpaceBuilder: nameSpaceBuilder,
         libraryBuilder: enclosingLibraryBuilder,
         constructorReferences: [],
         fileUri: fileUri,
-        startOffset: computedStartOffset,
         nameOffset: nameOffset,
-        endOffset: endOffset,
         indexedClass: indexedClass,
         mixedInTypeBuilder: isMixinDeclaration ? null : mixin,
         classDeclaration: classDeclaration);
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 e00ca69..daf4e30 100644
--- a/pkg/front_end/lib/src/source/source_enum_builder.dart
+++ b/pkg/front_end/lib/src/source/source_enum_builder.dart
@@ -42,7 +42,7 @@
 import '../kernel/member_covariance.dart';
 import '../kernel/type_algorithms.dart';
 import 'name_scheme.dart';
-import 'source_class_builder.dart' show ClassDeclaration, SourceClassBuilder;
+import 'source_class_builder.dart' show SourceClassBuilder;
 import 'source_constructor_builder.dart';
 import 'source_library_builder.dart' show SourceLibraryBuilder;
 import 'source_member_builder.dart';
@@ -73,11 +73,9 @@
   late final _EnumValuesFieldDeclaration _enumValuesFieldDeclaration;
 
   SourceEnumBuilder.internal(
-      {required List<MetadataBuilder>? metadata,
-      required String name,
+      {required String name,
       required List<NominalParameterBuilder>? typeParameters,
       required TypeBuilder underscoreEnumTypeBuilder,
-      required List<TypeBuilder>? interfaceBuilders,
       required LookupScope typeParameterScope,
       required DeclarationNameSpaceBuilder nameSpaceBuilder,
       required List<EnumElementFragment> enumElements,
@@ -92,26 +90,20 @@
       : _underscoreEnumTypeBuilder = underscoreEnumTypeBuilder,
         _enumElements = enumElements,
         super(
-            metadata: metadata,
             modifiers: Modifiers.empty,
             name: name,
             typeParameters: typeParameters,
-            interfaceBuilders: interfaceBuilders,
-            onTypes: null,
             typeParameterScope: typeParameterScope,
             nameSpaceBuilder: nameSpaceBuilder,
             libraryBuilder: libraryBuilder,
             constructorReferences: constructorReferences,
             fileUri: fileUri,
-            startOffset: startOffset,
             nameOffset: nameOffset,
-            endOffset: endOffset,
             indexedClass: indexedClass,
             classDeclaration: classDeclaration);
 
   factory SourceEnumBuilder(
-      {required List<MetadataBuilder>? metadata,
-      required String name,
+      {required String name,
       required List<NominalParameterBuilder>? typeParameters,
       required TypeBuilder underscoreEnumTypeBuilder,
       required List<TypeBuilder>? interfaceBuilders,
@@ -127,11 +119,9 @@
       required DeclarationNameSpaceBuilder nameSpaceBuilder,
       required ClassDeclaration classDeclaration}) {
     SourceEnumBuilder enumBuilder = new SourceEnumBuilder.internal(
-        metadata: metadata,
         name: name,
         typeParameters: typeParameters,
         underscoreEnumTypeBuilder: underscoreEnumTypeBuilder,
-        interfaceBuilders: interfaceBuilders,
         typeParameterScope: typeParameterScope,
         nameSpaceBuilder: nameSpaceBuilder,
         enumElements: enumElements,
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 ec23a47..a00fefd 100644
--- a/pkg/front_end/lib/src/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/source/source_library_builder.dart
@@ -677,12 +677,11 @@
     state = SourceLibraryBuilderState.nameSpaceBuilt;
   }
 
-  TypeBuilder? _computeSupertypeBuilderForClass(
-      SourceClassBuilder classBuilder) {
+  void _computeSupertypeBuilderForClass(SourceClassBuilder classBuilder) {
     assert(checkState(required: [SourceLibraryBuilderState.nameSpaceBuilt]));
     assert(
         _mixinApplications != null, "Late registration of mixin application.");
-    return classBuilder.computeSupertypeBuilder(
+    classBuilder.computeSupertypeBuilder(
         loader: loader,
         problemReporting: this,
         unboundNominalParameters: _unboundNominalParameters,
@@ -760,19 +759,7 @@
     Iterator<SourceClassBuilder> iterator = localMembersIteratorOfType();
     while (iterator.moveNext()) {
       SourceClassBuilder declaration = iterator.current;
-      Class cls = declaration.cls;
-      if (cls != objectClass) {
-        cls.supertype ??= objectClass.asRawSupertype;
-        declaration.supertypeBuilder ??=
-            new NamedTypeBuilderImpl.fromTypeDeclarationBuilder(
-                objectClassBuilder, const NullabilityBuilder.omitted(),
-                instanceTypeParameterAccess:
-                    InstanceTypeParameterAccessState.Unexpected);
-      }
-      if (declaration.isMixinApplication) {
-        cls.mixedInType =
-            declaration.mixedInTypeBuilder!.buildMixedInType(this);
-      }
+      declaration.installDefaultSupertypes(objectClassBuilder, objectClass);
     }
   }
 
diff --git a/pkg/front_end/lib/src/source/source_loader.dart b/pkg/front_end/lib/src/source/source_loader.dart
index 2fba233..5dc01ef 100644
--- a/pkg/front_end/lib/src/source/source_loader.dart
+++ b/pkg/front_end/lib/src/source/source_loader.dart
@@ -1683,25 +1683,9 @@
   /// Check that [objectClass] has no supertypes. Recover by removing any
   /// found.
   void checkObjectClassHierarchy(ClassBuilder objectClass) {
-    if (objectClass is SourceClassBuilder &&
-        // Coverage-ignore(suite): Not run.
-        objectClass.libraryBuilder.loader == this) {
+    if (objectClass is SourceClassBuilder) {
       // Coverage-ignore-block(suite): Not run.
-      if (objectClass.supertypeBuilder != null) {
-        objectClass.supertypeBuilder = null;
-        objectClass.addProblem(
-            messageObjectExtends, objectClass.fileOffset, noLength);
-      }
-      if (objectClass.interfaceBuilders != null) {
-        objectClass.addProblem(
-            messageObjectImplements, objectClass.fileOffset, noLength);
-        objectClass.interfaceBuilders = null;
-      }
-      if (objectClass.mixedInTypeBuilder != null) {
-        objectClass.addProblem(
-            messageObjectMixesIn, objectClass.fileOffset, noLength);
-        objectClass.mixedInTypeBuilder = null;
-      }
+      objectClass.checkObjectSupertypes();
     }
   }
 
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 e4826da..a74d2cd 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
@@ -1234,22 +1234,16 @@
         IndexedClass? indexedClass =
             indexedLibrary?.lookupIndexedClass(fragment.name);
         SourceClassBuilder classBuilder = new SourceClassBuilder(
-            metadata: fragment.metadata,
             modifiers: fragment.modifiers,
             name: fragment.name,
             typeParameters: fragment.typeParameters,
-            interfaceBuilders: fragment.interfaces,
-            onTypes: null,
             typeParameterScope: fragment.typeParameterScope,
             nameSpaceBuilder: fragment.toDeclarationNameSpaceBuilder(),
             libraryBuilder: enclosingLibraryBuilder,
             constructorReferences: fragment.constructorReferences,
             fileUri: fragment.fileUri,
-            startOffset: fragment.startOffset,
             nameOffset: fragment.nameOffset,
-            endOffset: fragment.endOffset,
             indexedClass: indexedClass,
-            isMixinDeclaration: false,
             classDeclaration: new RegularClassDeclaration(fragment));
         fragment.builder = classBuilder;
         fragment.bodyScope.declarationBuilder = classBuilder;
@@ -1263,24 +1257,16 @@
         IndexedClass? indexedClass =
             indexedLibrary?.lookupIndexedClass(fragment.name);
         SourceClassBuilder mixinBuilder = new SourceClassBuilder(
-            metadata: fragment.metadata,
             modifiers: fragment.modifiers,
             name: fragment.name,
             typeParameters: fragment.typeParameters,
-            interfaceBuilders: fragment.interfaces,
-            // TODO(johnniwinther): Add the `on` clause types of a mixin
-            //  declaration here.
-            onTypes: null,
             typeParameterScope: fragment.typeParameterScope,
             nameSpaceBuilder: fragment.toDeclarationNameSpaceBuilder(),
             libraryBuilder: enclosingLibraryBuilder,
             constructorReferences: fragment.constructorReferences,
             fileUri: fragment.fileUri,
-            startOffset: fragment.startOffset,
             nameOffset: fragment.nameOffset,
-            endOffset: fragment.endOffset,
             indexedClass: indexedClass,
-            isMixinDeclaration: true,
             classDeclaration: new MixinDeclaration(fragment));
         fragment.builder = mixinBuilder;
         fragment.bodyScope.declarationBuilder = mixinBuilder;
@@ -1297,8 +1283,6 @@
             new NamedMixinApplication(fragment, mixins);
 
         String name = fragment.name;
-        int computedStartOffset =
-            fragment.metadata?.first.atOffset ?? fragment.startOffset;
 
         IndexedClass? referencesFromIndexedClass;
         if (indexedLibrary != null) {
@@ -1310,20 +1294,15 @@
         DeclarationNameSpaceBuilder nameSpaceBuilder =
             new DeclarationNameSpaceBuilder.empty();
         SourceClassBuilder classBuilder = new SourceClassBuilder(
-            metadata: fragment.metadata,
             modifiers: fragment.modifiers | Modifiers.NamedMixinApplication,
             name: name,
             typeParameters: fragment.typeParameters,
-            interfaceBuilders: fragment.interfaces,
-            onTypes: null,
             typeParameterScope: typeParameterScope,
             nameSpaceBuilder: nameSpaceBuilder,
             libraryBuilder: enclosingLibraryBuilder,
             constructorReferences: [],
             fileUri: fragment.fileUri,
-            startOffset: computedStartOffset,
             nameOffset: fragment.nameOffset,
-            endOffset: fragment.endOffset,
             indexedClass: referencesFromIndexedClass,
             mixedInTypeBuilder: mixin,
             classDeclaration: classDeclaration);
@@ -1339,7 +1318,6 @@
         IndexedClass? indexedClass =
             indexedLibrary?.lookupIndexedClass(fragment.name);
         SourceEnumBuilder enumBuilder = new SourceEnumBuilder(
-            metadata: fragment.metadata,
             name: fragment.name,
             typeParameters: fragment.typeParameters,
             underscoreEnumTypeBuilder: loader.target.underscoreEnumType,
diff --git a/pkg/front_end/test/coverage_suite_expected.dart b/pkg/front_end/test/coverage_suite_expected.dart
index 6f57a3a..d6611b9 100644
--- a/pkg/front_end/test/coverage_suite_expected.dart
+++ b/pkg/front_end/test/coverage_suite_expected.dart
@@ -469,6 +469,11 @@
     missCount: 0,
   ),
   // 100.0%.
+  "package:front_end/src/fragment/class/declaration.dart": (
+    hitCount: 138,
+    missCount: 0,
+  ),
+  // 100.0%.
   "package:front_end/src/fragment/constructor.dart": (
     hitCount: 50,
     missCount: 0,
@@ -670,7 +675,7 @@
   ),
   // 100.0%.
   "package:front_end/src/kernel/hierarchy/hierarchy_node.dart": (
-    hitCount: 403,
+    hitCount: 388,
     missCount: 0,
   ),
   // 100.0%.
@@ -840,7 +845,7 @@
   ),
   // 100.0%.
   "package:front_end/src/source/source_class_builder.dart": (
-    hitCount: 1485,
+    hitCount: 1411,
     missCount: 0,
   ),
   // 100.0%.
@@ -881,7 +886,7 @@
   ),
   // 100.0%.
   "package:front_end/src/source/source_library_builder.dart": (
-    hitCount: 1270,
+    hitCount: 1261,
     missCount: 0,
   ),
   // 100.0%.
@@ -921,7 +926,7 @@
   ),
   // 100.0%.
   "package:front_end/src/source/type_parameter_scope_builder.dart": (
-    hitCount: 1399,
+    hitCount: 1383,
     missCount: 0,
   ),
   // 100.0%.
diff --git a/pkg/front_end/test/extensions/extensions_test.dart b/pkg/front_end/test/extensions/extensions_test.dart
index 50926be..9aa1b9b 100644
--- a/pkg/front_end/test/extensions/extensions_test.dart
+++ b/pkg/front_end/test/extensions/extensions_test.dart
@@ -97,7 +97,6 @@
   static const String builderTypeParameters = 'builder-type-params';
   static const String builderSupertype = 'builder-supertype';
   static const String builderInterfaces = 'builder-interfaces';
-  static const String builderOnTypes = 'builder-onTypes';
   static const String builderOnType = 'builder-onType';
   static const String builderRequiredParameters = 'builder-params';
   static const String builderPositionalParameters = 'builder-pos-params';
@@ -176,11 +175,6 @@
         features.addElement(Tags.builderInterfaces, superinterface.typeName);
       }
     }
-    if (clsBuilder.onTypes != null) {
-      for (TypeBuilder onType in clsBuilder.onTypes!) {
-        features.addElement(Tags.builderOnTypes, typeBuilderToText(onType));
-      }
-    }
 
     features[Tags.clsName] = cls.name;
     for (TypeParameter typeParameter in cls.typeParameters) {