[cfe] Add ExtensionTypeHierarchyNode(Builder)

This adds checks for conflicting supertypes and prepares for computation
of extension type members.

Change-Id: If997fe84bac929274a6014b315ecea4f3856eedd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315441
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
diff --git a/pkg/front_end/lib/src/fasta/builder/inline_class_builder.dart b/pkg/front_end/lib/src/fasta/builder/inline_class_builder.dart
index 92e3d53..0f95412 100644
--- a/pkg/front_end/lib/src/fasta/builder/inline_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/inline_class_builder.dart
@@ -25,6 +25,10 @@
   /// Return the [InlineClass] built by this builder.
   InlineClass get inlineClass;
 
+  /// Returns a list of the classes and extension types implemented by this
+  /// extension type.
+  List<TypeBuilder>? get interfaceBuilders;
+
   /// Looks up inline class member by [name] taking privacy into account.
   ///
   /// If [setter] is `true` the sought member is a setter or assignable field.
@@ -40,6 +44,9 @@
 
   /// Calls [f] for each member declared in this extension.
   void forEach(void f(String name, Builder builder));
+
+  @override
+  Uri get fileUri;
 }
 
 abstract class InlineClassBuilderImpl extends DeclarationBuilderImpl
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_loader.dart b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
index bc994b4..13c75df 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
@@ -6,9 +6,11 @@
 
 import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
 
-import 'package:kernel/ast.dart' show Class, Component, DartType, Library;
+import 'package:kernel/ast.dart'
+    show Class, Component, DartType, InlineClass, Library;
 
 import '../builder/class_builder.dart';
+import '../builder/inline_class_builder.dart';
 import '../builder/library_builder.dart';
 import '../builder/type_builder.dart';
 
@@ -331,6 +333,19 @@
     return library!.lookupLocalMember(cls.name, required: true) as ClassBuilder;
   }
 
+  @override
+  InlineClassBuilder computeExtensionTypeBuilderFromTargetExtensionType(
+      InlineClass extensionType) {
+    Library kernelLibrary = extensionType.enclosingLibrary;
+    LibraryBuilder? library = lookupLibraryBuilder(kernelLibrary.importUri);
+    if (library == null) {
+      library =
+          currentSourceLoader?.lookupLibraryBuilder(kernelLibrary.importUri);
+    }
+    return library!.lookupLocalMember(extensionType.name, required: true)
+        as InlineClassBuilder;
+  }
+
   late TypeBuilderComputer _typeBuilderComputer = new TypeBuilderComputer(this);
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index 8c3421c..4f26a28 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -1497,7 +1497,7 @@
 
       // Get all classes touched by fasta class hierarchy.
       if (builderHierarchy != null) {
-        for (Class c in builderHierarchy.nodes.keys) {
+        for (Class c in builderHierarchy.classNodes.keys) {
           if (classes.add(c)) worklist.add(c);
         }
       }
diff --git a/pkg/front_end/lib/src/fasta/kernel/hierarchy/hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/hierarchy/hierarchy_builder.dart
index 19f1592..55e6c66 100644
--- a/pkg/front_end/lib/src/fasta/kernel/hierarchy/hierarchy_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/hierarchy/hierarchy_builder.dart
@@ -12,15 +12,19 @@
 import 'package:kernel/type_algebra.dart' show Substitution, uniteNullabilities;
 
 import '../../builder/class_builder.dart';
-import '../../builder/type_builder.dart';
+import '../../builder/inline_class_builder.dart';
 import '../../loader.dart' show Loader;
+import '../../source/source_class_builder.dart';
+import '../../source/source_inline_class_builder.dart';
 import '../../source/source_loader.dart' show SourceLoader;
 import 'hierarchy_node.dart';
 
 class ClassHierarchyBuilder
     with ClassHierarchyInlineClassMixin
     implements ClassHierarchyBase {
-  final Map<Class, ClassHierarchyNode> nodes = <Class, ClassHierarchyNode>{};
+  final Map<Class, ClassHierarchyNode> classNodes = {};
+
+  final Map<InlineClass, ExtensionTypeHierarchyNode> extensionTypeNodes = {};
 
   final ClassBuilder objectClassBuilder;
 
@@ -45,22 +49,32 @@
   }
 
   void clear() {
-    nodes.clear();
+    classNodes.clear();
+    extensionTypeNodes.clear();
   }
 
   ClassHierarchyNode getNodeFromClassBuilder(ClassBuilder classBuilder) {
-    return nodes[classBuilder.cls] ??=
+    return classNodes[classBuilder.cls] ??=
         new ClassHierarchyNodeBuilder(this, classBuilder).build();
   }
 
-  ClassHierarchyNode? getNodeFromTypeBuilder(TypeBuilder type) {
-    ClassBuilder? cls = getClass(type);
-    return cls == null ? null : getNodeFromClassBuilder(cls);
+  ClassHierarchyNode getNodeFromClass(Class cls) {
+    return classNodes[cls] ??
+        getNodeFromClassBuilder(loader.computeClassBuilderFromTargetClass(cls));
   }
 
-  ClassHierarchyNode getNodeFromClass(Class cls) {
-    return nodes[cls] ??
-        getNodeFromClassBuilder(loader.computeClassBuilderFromTargetClass(cls));
+  ExtensionTypeHierarchyNode getNodeFromExtensionTypeBuilder(
+      InlineClassBuilder extensionTypeBuilder) {
+    return extensionTypeNodes[extensionTypeBuilder.inlineClass] ??=
+        new ExtensionTypeHierarchyNodeBuilder(this, extensionTypeBuilder)
+            .build();
+  }
+
+  ExtensionTypeHierarchyNode getNodeFromExtensionType(
+      InlineClass extensionType) {
+    return extensionTypeNodes[extensionType] ??
+        getNodeFromExtensionTypeBuilder(loader
+            .computeExtensionTypeBuilderFromTargetExtensionType(extensionType));
   }
 
   Supertype? asSupertypeOf(InterfaceType subtype, Class supertype) {
@@ -183,19 +197,26 @@
         uniteNullabilities(type1.nullability, type2.nullability));
   }
 
-  static ClassHierarchyBuilder build(ClassBuilder objectClass,
-      List<ClassBuilder> classes, SourceLoader loader, CoreTypes coreTypes) {
+  static ClassHierarchyBuilder build(
+      ClassBuilder objectClass,
+      List<SourceClassBuilder> classes,
+      List<SourceInlineClassBuilder> extensionTypes,
+      SourceLoader loader,
+      CoreTypes coreTypes) {
     ClassHierarchyBuilder hierarchy =
         new ClassHierarchyBuilder(objectClass, loader, coreTypes);
     for (int i = 0; i < classes.length; i++) {
-      ClassBuilder classBuilder = classes[i];
-      if (!classBuilder.isPatch) {
-        hierarchy.nodes[classBuilder.cls] =
-            new ClassHierarchyNodeBuilder(hierarchy, classBuilder).build();
-      } else {
-        // TODO(ahe): Merge the injected members of patch into the hierarchy
-        // node of `cls.origin`.
-      }
+      SourceClassBuilder classBuilder = classes[i];
+      assert(!classBuilder.isPatch);
+      hierarchy.classNodes[classBuilder.cls] =
+          new ClassHierarchyNodeBuilder(hierarchy, classBuilder).build();
+    }
+    for (int i = 0; i < extensionTypes.length; i++) {
+      SourceInlineClassBuilder extensionTypeBuilder = extensionTypes[i];
+      assert(!extensionTypeBuilder.isPatch);
+      hierarchy.extensionTypeNodes[extensionTypeBuilder.inlineClass] =
+          new ExtensionTypeHierarchyNodeBuilder(hierarchy, extensionTypeBuilder)
+              .build();
     }
     return hierarchy;
   }
diff --git a/pkg/front_end/lib/src/fasta/kernel/hierarchy/hierarchy_node.dart b/pkg/front_end/lib/src/fasta/kernel/hierarchy/hierarchy_node.dart
index 4d5141a..18695d4 100644
--- a/pkg/front_end/lib/src/fasta/kernel/hierarchy/hierarchy_node.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/hierarchy/hierarchy_node.dart
@@ -13,6 +13,7 @@
 import '../../../testing/id_testing_utils.dart' show typeToText;
 import '../../builder/builder.dart';
 import '../../builder/class_builder.dart';
+import '../../builder/inline_class_builder.dart';
 import '../../builder/library_builder.dart';
 import '../../builder/named_type_builder.dart';
 import '../../builder/type_alias_builder.dart';
@@ -23,145 +24,50 @@
 import 'hierarchy_builder.dart';
 import 'mixin_inferrer.dart';
 
-class ClassHierarchyNodeBuilder {
-  final ClassHierarchyBuilder hierarchy;
+abstract class HierarchyNodeBuilder {
+  final ClassHierarchyBuilder _hierarchy;
 
-  final ClassBuilder classBuilder;
+  HierarchyNodeBuilder(this._hierarchy);
 
-  bool hasNoSuchMethod = false;
+  LibraryBuilder get _libraryBuilder;
 
-  ClassHierarchyNodeBuilder(this.hierarchy, this.classBuilder);
+  String get _name;
 
-  ClassBuilder get objectClass => hierarchy.objectClassBuilder;
+  int get _fileOffset;
 
-  ClassHierarchyNode build() {
-    assert(!classBuilder.isPatch);
-    ClassHierarchyNode? supernode;
-    if (objectClass != classBuilder.origin) {
-      supernode =
-          hierarchy.getNodeFromTypeBuilder(classBuilder.supertypeBuilder!);
-      if (supernode == null) {
-        supernode = hierarchy.getNodeFromClassBuilder(objectClass);
+  Uri get _fileUri;
+
+  Supertype _resolveSupertypeConflict(Supertype type, Supertype superclass) {
+    if (_libraryBuilder.isNonNullableByDefault) {
+      Supertype? merge = nnbdTopMergeSupertype(
+          _hierarchy.coreTypes,
+          normSupertype(_hierarchy.coreTypes, superclass),
+          normSupertype(_hierarchy.coreTypes, type));
+      if (merge != null) {
+        return merge;
       }
+    } else if (type == superclass) {
+      return superclass;
     }
-
-    List<Supertype> superclasses;
-    List<Supertype> interfacesList;
-    int maxInheritancePath;
-
-    ClassHierarchyNode? mixedInNode;
-    List<ClassHierarchyNode>? interfaceNodes;
-
-    if (classBuilder.isMixinApplication) {
-      mixedInNode = inferMixinApplication();
+    LibraryBuilder libraryBuilder = _libraryBuilder;
+    if (libraryBuilder is SourceLibraryBuilder) {
+      libraryBuilder.addProblem(
+          templateAmbiguousSupertypes.withArguments(
+              _name,
+              superclass.asInterfaceType,
+              type.asInterfaceType,
+              libraryBuilder.isNonNullableByDefault),
+          _fileOffset,
+          noLength,
+          _fileUri);
     }
-
-    if (supernode == null) {
-      // This should be Object.
-      superclasses = new List<Supertype>.filled(0, dummySupertype);
-      interfacesList = new List<Supertype>.filled(0, dummySupertype);
-      maxInheritancePath = 0;
-    } else {
-      maxInheritancePath = supernode.maxInheritancePath + 1;
-
-      superclasses = new List<Supertype>.filled(
-          supernode.superclasses.length + 1, dummySupertype);
-      Supertype? supertype = classBuilder.supertypeBuilder!
-          .buildSupertype(classBuilder.libraryBuilder);
-      if (supertype == null) {
-        // If the superclass is not an interface type we use Object instead.
-        // A similar normalization is performed on [supernode] above.
-        supertype =
-            new Supertype(hierarchy.coreTypes.objectClass, const <DartType>[]);
-      }
-      superclasses.setRange(0, superclasses.length - 1,
-          substSupertypes(supertype, supernode.superclasses));
-      superclasses[superclasses.length - 1] = supertype;
-      if (!classBuilder.libraryBuilder.isNonNullableByDefault &&
-          supernode.classBuilder.libraryBuilder.isNonNullableByDefault) {
-        for (int i = 0; i < superclasses.length; i++) {
-          superclasses[i] = legacyErasureSupertype(superclasses[i]);
-        }
-      }
-
-      List<TypeBuilder>? directInterfaceBuilders =
-          ignoreFunction(classBuilder.interfaceBuilders);
-      if (classBuilder.isMixinApplication) {
-        if (directInterfaceBuilders == null) {
-          directInterfaceBuilders = <TypeBuilder>[
-            classBuilder.mixedInTypeBuilder!
-          ];
-        } else {
-          directInterfaceBuilders = <TypeBuilder>[
-            classBuilder.mixedInTypeBuilder!
-          ]..addAll(directInterfaceBuilders);
-        }
-      }
-
-      List<Supertype> superclassInterfaces = supernode.interfaces;
-      if (superclassInterfaces.isNotEmpty) {
-        superclassInterfaces = substSupertypes(supertype, superclassInterfaces);
-      }
-
-      if (directInterfaceBuilders != null) {
-        Map<Class, Supertype> interfaces = {};
-        if (superclassInterfaces.isNotEmpty) {
-          for (int i = 0; i < superclassInterfaces.length; i++) {
-            addInterface(interfaces, superclasses, superclassInterfaces[i]);
-          }
-        }
-
-        for (int i = 0; i < directInterfaceBuilders.length; i++) {
-          Supertype? directInterface = directInterfaceBuilders[i]
-              .buildSupertype(classBuilder.libraryBuilder);
-          if (directInterface != null) {
-            addInterface(interfaces, superclasses, directInterface);
-            ClassHierarchyNode interfaceNode =
-                hierarchy.getNodeFromClass(directInterface.classNode);
-            (interfaceNodes ??= []).add(interfaceNode);
-
-            if (maxInheritancePath < interfaceNode.maxInheritancePath + 1) {
-              maxInheritancePath = interfaceNode.maxInheritancePath + 1;
-            }
-
-            List<Supertype> types =
-                substSupertypes(directInterface, interfaceNode.superclasses);
-            for (int i = 0; i < types.length; i++) {
-              addInterface(interfaces, superclasses, types[i]);
-            }
-            if (interfaceNode.interfaces.isNotEmpty) {
-              List<Supertype> types =
-                  substSupertypes(directInterface, interfaceNode.interfaces);
-              for (int i = 0; i < types.length; i++) {
-                addInterface(interfaces, superclasses, types[i]);
-              }
-            }
-          }
-        }
-        interfacesList = interfaces.values.toList();
-      } else if (superclassInterfaces.isNotEmpty &&
-          !classBuilder.libraryBuilder.isNonNullableByDefault &&
-          supernode.classBuilder.libraryBuilder.isNonNullableByDefault) {
-        Map<Class, Supertype> interfaces = {};
-        for (int i = 0; i < superclassInterfaces.length; i++) {
-          addInterface(interfaces, superclasses, superclassInterfaces[i]);
-        }
-        interfacesList = interfaces.values.toList();
-      } else {
-        interfacesList = superclassInterfaces;
-      }
-    }
-
-    return new ClassHierarchyNode(classBuilder, supernode, mixedInNode,
-        interfaceNodes, superclasses, interfacesList, maxInheritancePath);
+    return superclass;
   }
 
-  List<Supertype> substSupertypes(
+  List<Supertype> _substSupertypes(
       Supertype supertype, List<Supertype> supertypes) {
     List<TypeParameter> typeVariables = supertype.classNode.typeParameters;
     if (typeVariables.isEmpty) {
-      debug?.log("In ${this.classBuilder.fullNameForErrors} "
-          "$supertypes aren't substed");
       return supertypes;
     }
     Map<TypeParameter, DartType> map = <TypeParameter, DartType>{};
@@ -175,51 +81,181 @@
       Supertype supertype = supertypes[i];
       Supertype substituted = substitution.substituteSupertype(supertype);
       if (supertype != substituted) {
-        debug?.log("In ${this.classBuilder.fullNameForErrors} $supertype"
-            " -> $substituted");
         result ??= supertypes.toList();
         result[i] = substituted;
-      } else {
-        debug?.log("In ${this.classBuilder.fullNameForErrors} "
-            "$supertype isn't substed");
       }
     }
     return result ?? supertypes;
   }
 
-  Supertype _resolveSupertypeConflict(Supertype type, Supertype superclass) {
-    if (classBuilder.libraryBuilder.isNonNullableByDefault) {
-      Supertype? merge = nnbdTopMergeSupertype(
-          hierarchy.coreTypes,
-          normSupertype(hierarchy.coreTypes, superclass),
-          normSupertype(hierarchy.coreTypes, type));
-      if (merge != null) {
-        return merge;
+  /// The class Function from dart:core is supposed to be ignored when used as
+  /// an interface.
+  List<TypeBuilder>? _ignoreFunction(List<TypeBuilder>? interfaces) {
+    if (interfaces == null) return null;
+    for (int i = 0; i < interfaces!.length; i++) {
+      ClassBuilder? classBuilder = getClass(interfaces[i]);
+      if (classBuilder != null &&
+          classBuilder.cls == _hierarchy.functionClass) {
+        if (interfaces.length == 1) {
+          return null;
+        } else {
+          interfaces = interfaces.toList();
+          interfaces.removeAt(i);
+          return _ignoreFunction(interfaces);
+        }
       }
-    } else if (type == superclass) {
-      return superclass;
     }
-    LibraryBuilder libraryBuilder = classBuilder.libraryBuilder;
-    if (libraryBuilder is SourceLibraryBuilder) {
-      libraryBuilder.addProblem(
-          templateAmbiguousSupertypes.withArguments(
-              classBuilder.name,
-              superclass.asInterfaceType,
-              type.asInterfaceType,
-              libraryBuilder.isNonNullableByDefault),
-          classBuilder.charOffset,
-          noLength,
-          classBuilder.fileUri);
+    return interfaces;
+  }
+}
+
+class ClassHierarchyNodeBuilder extends HierarchyNodeBuilder {
+  final ClassBuilder _classBuilder;
+
+  ClassHierarchyNodeBuilder(super.hierarchy, this._classBuilder);
+
+  ClassBuilder get _objectClass => _hierarchy.objectClassBuilder;
+
+  @override
+  LibraryBuilder get _libraryBuilder => _classBuilder.libraryBuilder;
+
+  @override
+  String get _name => _classBuilder.name;
+
+  @override
+  int get _fileOffset => _classBuilder.charOffset;
+
+  @override
+  Uri get _fileUri => _classBuilder.fileUri;
+
+  ClassHierarchyNode build() {
+    assert(!_classBuilder.isPatch);
+    ClassHierarchyNode? supernode;
+    if (_objectClass != _classBuilder.origin) {
+      ClassBuilder? superClassBuilder =
+          getClass(_classBuilder.supertypeBuilder!);
+      supernode =
+          _hierarchy.getNodeFromClassBuilder(superClassBuilder ?? _objectClass);
     }
-    return superclass;
+
+    List<Supertype> superclasses;
+    List<Supertype> interfacesList;
+    int maxInheritancePath;
+
+    ClassHierarchyNode? mixedInNode;
+    List<ClassHierarchyNode>? interfaceNodes;
+
+    if (_classBuilder.isMixinApplication) {
+      mixedInNode = _inferMixinApplication();
+    }
+
+    if (supernode == null) {
+      // This should be Object.
+      superclasses = new List<Supertype>.filled(0, dummySupertype);
+      interfacesList = new List<Supertype>.filled(0, dummySupertype);
+      maxInheritancePath = 0;
+    } else {
+      maxInheritancePath = supernode.maxInheritancePath + 1;
+
+      superclasses = new List<Supertype>.filled(
+          supernode.superclasses.length + 1, dummySupertype);
+      Supertype? supertype = _classBuilder.supertypeBuilder!
+          .buildSupertype(_classBuilder.libraryBuilder);
+      if (supertype == null) {
+        // If the superclass is not an interface type we use Object instead.
+        // A similar normalization is performed on [supernode] above.
+        supertype =
+            new Supertype(_hierarchy.coreTypes.objectClass, const <DartType>[]);
+      }
+      superclasses.setRange(0, superclasses.length - 1,
+          _substSupertypes(supertype, supernode.superclasses));
+      superclasses[superclasses.length - 1] = supertype;
+      if (!_classBuilder.libraryBuilder.isNonNullableByDefault &&
+          supernode.classBuilder.libraryBuilder.isNonNullableByDefault) {
+        for (int i = 0; i < superclasses.length; i++) {
+          superclasses[i] = legacyErasureSupertype(superclasses[i]);
+        }
+      }
+
+      List<TypeBuilder>? directInterfaceBuilders =
+          _ignoreFunction(_classBuilder.interfaceBuilders);
+      if (_classBuilder.isMixinApplication) {
+        if (directInterfaceBuilders == null) {
+          directInterfaceBuilders = <TypeBuilder>[
+            _classBuilder.mixedInTypeBuilder!
+          ];
+        } else {
+          directInterfaceBuilders = <TypeBuilder>[
+            _classBuilder.mixedInTypeBuilder!
+          ]..addAll(directInterfaceBuilders);
+        }
+      }
+
+      List<Supertype> superclassInterfaces = supernode.interfaces;
+      if (superclassInterfaces.isNotEmpty) {
+        superclassInterfaces =
+            _substSupertypes(supertype, superclassInterfaces);
+      }
+
+      if (directInterfaceBuilders != null) {
+        Map<Class, Supertype> interfaces = {};
+        if (superclassInterfaces.isNotEmpty) {
+          for (int i = 0; i < superclassInterfaces.length; i++) {
+            _addInterface(interfaces, superclasses, superclassInterfaces[i]);
+          }
+        }
+
+        for (int i = 0; i < directInterfaceBuilders.length; i++) {
+          Supertype? directInterface = directInterfaceBuilders[i]
+              .buildSupertype(_classBuilder.libraryBuilder);
+          if (directInterface != null) {
+            _addInterface(interfaces, superclasses, directInterface);
+            ClassHierarchyNode interfaceNode =
+                _hierarchy.getNodeFromClass(directInterface.classNode);
+            (interfaceNodes ??= []).add(interfaceNode);
+
+            if (maxInheritancePath < interfaceNode.maxInheritancePath + 1) {
+              maxInheritancePath = interfaceNode.maxInheritancePath + 1;
+            }
+
+            List<Supertype> types =
+                _substSupertypes(directInterface, interfaceNode.superclasses);
+            for (int i = 0; i < types.length; i++) {
+              _addInterface(interfaces, superclasses, types[i]);
+            }
+            if (interfaceNode.interfaces.isNotEmpty) {
+              List<Supertype> types =
+                  _substSupertypes(directInterface, interfaceNode.interfaces);
+              for (int i = 0; i < types.length; i++) {
+                _addInterface(interfaces, superclasses, types[i]);
+              }
+            }
+          }
+        }
+        interfacesList = interfaces.values.toList();
+      } else if (superclassInterfaces.isNotEmpty &&
+          !_classBuilder.libraryBuilder.isNonNullableByDefault &&
+          supernode.classBuilder.libraryBuilder.isNonNullableByDefault) {
+        Map<Class, Supertype> interfaces = {};
+        for (int i = 0; i < superclassInterfaces.length; i++) {
+          _addInterface(interfaces, superclasses, superclassInterfaces[i]);
+        }
+        interfacesList = interfaces.values.toList();
+      } else {
+        interfacesList = superclassInterfaces;
+      }
+    }
+
+    return new ClassHierarchyNode(_classBuilder, supernode, mixedInNode,
+        interfaceNodes, superclasses, interfacesList, maxInheritancePath);
   }
 
-  void addInterface(Map<Class, Supertype> interfaces,
+  void _addInterface(Map<Class, Supertype> interfaces,
       List<Supertype> superclasses, Supertype type) {
-    if (!classBuilder.libraryBuilder.isNonNullableByDefault) {
+    if (!_libraryBuilder.isNonNullableByDefault) {
       type = legacyErasureSupertype(type);
     }
-    ClassHierarchyNode node = hierarchy.getNodeFromClass(type.classNode);
+    ClassHierarchyNode node = _hierarchy.getNodeFromClass(type.classNode);
     int depth = node.depth;
     int myDepth = superclasses.length;
     Supertype? superclass = depth < myDepth ? superclasses[depth] : null;
@@ -238,52 +274,33 @@
     interfaces[type.classNode] = type;
   }
 
-  ClassHierarchyNode? inferMixinApplication() {
-    Class cls = classBuilder.cls;
+  ClassHierarchyNode? _inferMixinApplication() {
+    Class cls = _classBuilder.cls;
     Supertype? mixedInType = cls.mixedInType;
     if (mixedInType == null) return null;
     ClassHierarchyNode? mixinNode =
-        hierarchy.getNodeFromClass(mixedInType.classNode);
+        _hierarchy.getNodeFromClass(mixedInType.classNode);
     List<DartType> typeArguments = mixedInType.typeArguments;
     if (typeArguments.isEmpty || typeArguments.first is! UnknownType) {
       return mixinNode;
     }
     new BuilderMixinInferrer(
-            classBuilder,
-            hierarchy.coreTypes,
+            _classBuilder,
+            _hierarchy.coreTypes,
             new TypeBuilderConstraintGatherer(
-                hierarchy, mixedInType.classNode.typeParameters,
+                _hierarchy, mixedInType.classNode.typeParameters,
                 isNonNullableByDefault:
                     cls.enclosingLibrary.isNonNullableByDefault))
         .infer(cls);
     List<TypeBuilder> inferredArguments = new List<TypeBuilder>.generate(
         typeArguments.length,
-        (int i) => hierarchy.loader.computeTypeBuilder(typeArguments[i]),
+        (int i) => _hierarchy.loader.computeTypeBuilder(typeArguments[i]),
         growable: false);
     NamedTypeBuilder mixedInTypeBuilder =
-        classBuilder.mixedInTypeBuilder as NamedTypeBuilder;
+        _classBuilder.mixedInTypeBuilder as NamedTypeBuilder;
     mixedInTypeBuilder.arguments = inferredArguments;
     return mixinNode;
   }
-
-  /// The class Function from dart:core is supposed to be ignored when used as
-  /// an interface.
-  List<TypeBuilder>? ignoreFunction(List<TypeBuilder>? interfaces) {
-    if (interfaces == null) return null;
-    for (int i = 0; i < interfaces!.length; i++) {
-      ClassBuilder? classBuilder = getClass(interfaces[i]);
-      if (classBuilder != null && classBuilder.cls == hierarchy.functionClass) {
-        if (interfaces.length == 1) {
-          return null;
-        } else {
-          interfaces = interfaces.toList();
-          interfaces.removeAt(i);
-          return ignoreFunction(interfaces);
-        }
-      }
-    }
-    return interfaces;
-  }
 }
 
 class ClassHierarchyNode {
@@ -385,6 +402,209 @@
   }
 }
 
+class ExtensionTypeHierarchyNodeBuilder extends HierarchyNodeBuilder {
+  final InlineClassBuilder _extensionTypeBuilder;
+
+  ExtensionTypeHierarchyNodeBuilder(
+      super._hierarchy, this._extensionTypeBuilder);
+
+  @override
+  LibraryBuilder get _libraryBuilder => _extensionTypeBuilder.libraryBuilder;
+
+  @override
+  String get _name => _extensionTypeBuilder.name;
+
+  @override
+  int get _fileOffset => _extensionTypeBuilder.charOffset;
+
+  @override
+  Uri get _fileUri => _extensionTypeBuilder.fileUri;
+
+  ExtensionTypeHierarchyNode build() {
+    assert(!_extensionTypeBuilder.isPatch);
+    Map<Class, Supertype> superclasses = {};
+    Map<InlineClass, InlineType> superExtensionTypes = {};
+    List<ClassHierarchyNode>? superclassNodes;
+    List<ExtensionTypeHierarchyNode>? superExtensionTypeNodes;
+    int maxInheritancePath = 1;
+
+    List<TypeBuilder>? directInterfaceBuilders =
+        _ignoreFunction(_extensionTypeBuilder.interfaceBuilders);
+    if (directInterfaceBuilders != null) {
+      for (int i = 0; i < directInterfaceBuilders.length; i++) {
+        DartType directInterface = directInterfaceBuilders[i]
+            .build(_extensionTypeBuilder.libraryBuilder, TypeUse.superType);
+        if (directInterface is InterfaceType) {
+          Supertype supertype = new Supertype.byReference(
+              directInterface.classReference, directInterface.typeArguments);
+          _addSuperClass(superclasses, supertype);
+          ClassHierarchyNode interfaceNode =
+              _hierarchy.getNodeFromClass(directInterface.classNode);
+          (superclassNodes ??= []).add(interfaceNode);
+
+          if (maxInheritancePath < interfaceNode.maxInheritancePath + 1) {
+            maxInheritancePath = interfaceNode.maxInheritancePath + 1;
+          }
+
+          List<Supertype> types =
+              _substSupertypes(supertype, interfaceNode.superclasses);
+          for (int i = 0; i < types.length; i++) {
+            _addSuperClass(superclasses, types[i]);
+          }
+          if (interfaceNode.interfaces.isNotEmpty) {
+            List<Supertype> types =
+                _substSupertypes(supertype, interfaceNode.interfaces);
+            for (int i = 0; i < types.length; i++) {
+              _addSuperClass(superclasses, types[i]);
+            }
+          }
+        } else if (directInterface is InlineType) {
+          _addSuperExtensionType(superExtensionTypes, directInterface);
+          ExtensionTypeHierarchyNode interfaceNode =
+              _hierarchy.getNodeFromExtensionType(directInterface.inlineClass);
+          (superExtensionTypeNodes ??= []).add(interfaceNode);
+
+          if (maxInheritancePath < interfaceNode.maxInheritancePath + 1) {
+            maxInheritancePath = interfaceNode.maxInheritancePath + 1;
+          }
+
+          List<InlineType> types = _substSuperExtensionTypes(
+              directInterface, interfaceNode.superExtensionTypes);
+          for (int i = 0; i < types.length; i++) {
+            _addSuperExtensionType(superExtensionTypes, types[i]);
+          }
+          if (interfaceNode.superExtensionTypes.isNotEmpty) {
+            List<InlineType> types = _substSuperExtensionTypes(
+                directInterface, interfaceNode.superExtensionTypes);
+            for (int i = 0; i < types.length; i++) {
+              _addSuperExtensionType(superExtensionTypes, types[i]);
+            }
+          }
+        }
+      }
+    }
+
+    return new ExtensionTypeHierarchyNode(
+        _extensionTypeBuilder,
+        superclasses.values.toList(),
+        superExtensionTypes.values.toList(),
+        superclassNodes,
+        superExtensionTypeNodes,
+        maxInheritancePath);
+  }
+
+  void _addSuperClass(Map<Class, Supertype> superClasses, Supertype type) {
+    if (!_libraryBuilder.isNonNullableByDefault) {
+      type = legacyErasureSupertype(type);
+    }
+    Supertype? interface = superClasses[type.classNode];
+    if (interface != null) {
+      // This is a potential conflict.
+      superClasses[type.classNode] = _resolveSupertypeConflict(type, interface);
+      return;
+    }
+    superClasses[type.classNode] = type;
+  }
+
+  InlineType _resolveSuperExtensionTypeConflict(
+      InlineType type, InlineType superclass) {
+    if (_libraryBuilder.isNonNullableByDefault) {
+      DartType? merge = nnbdTopMerge(
+          _hierarchy.coreTypes,
+          norm(_hierarchy.coreTypes, superclass),
+          norm(_hierarchy.coreTypes, type));
+      if (merge != null) {
+        return merge as InlineType;
+      }
+    } else if (type == superclass) {
+      return superclass;
+    }
+    LibraryBuilder libraryBuilder = _libraryBuilder;
+    if (libraryBuilder is SourceLibraryBuilder) {
+      libraryBuilder.addProblem(
+          templateAmbiguousSupertypes.withArguments(
+              _name, superclass, type, libraryBuilder.isNonNullableByDefault),
+          _fileOffset,
+          noLength,
+          _fileUri);
+    }
+    return superclass;
+  }
+
+  void _addSuperExtensionType(
+      Map<InlineClass, InlineType> interfaces, InlineType type) {
+    if (!_libraryBuilder.isNonNullableByDefault) {
+      type = legacyErasure(type) as InlineType;
+    }
+    InlineType? interface = interfaces[type.inlineClass];
+    if (interface != null) {
+      // This is a potential conflict.
+      interfaces[type.inlineClass] =
+          _resolveSuperExtensionTypeConflict(type, interface);
+      return;
+    }
+    interfaces[type.inlineClass] = type;
+  }
+
+  List<InlineType> _substSuperExtensionTypes(
+      InlineType superExtensionType, List<InlineType> superExtensionTypes) {
+    List<TypeParameter> typeVariables =
+        superExtensionType.inlineClass.typeParameters;
+    if (typeVariables.isEmpty) {
+      return superExtensionTypes;
+    }
+    Map<TypeParameter, DartType> map = <TypeParameter, DartType>{};
+    List<DartType> arguments = superExtensionType.typeArguments;
+    for (int i = 0; i < typeVariables.length; i++) {
+      map[typeVariables[i]] = arguments[i];
+    }
+    Substitution substitution = Substitution.fromMap(map);
+    List<InlineType>? result;
+    for (int i = 0; i < superExtensionTypes.length; i++) {
+      InlineType supertype = superExtensionTypes[i];
+      InlineType substituted =
+          substitution.substituteType(supertype) as InlineType;
+      if (supertype != substituted) {
+        result ??= superExtensionTypes.toList();
+        result[i] = substituted;
+      }
+    }
+    return result ?? superExtensionTypes;
+  }
+}
+
+class ExtensionTypeHierarchyNode {
+  /// The extension type corresponding to this hierarchy node.
+  final InlineClassBuilder extensionTypeBuilder;
+
+  /// The list of all classes implemented by [extensionTypeBuilder] and its
+  /// superclasses.
+  final List<Supertype> superclasses;
+
+  /// The list of all extension types implemented by [extensionTypeBuilder]
+  /// and its super extension types.
+  final List<InlineType> superExtensionTypes;
+
+  /// The [ClassHierarchyNode]s for the direct superclasses of
+  /// [extensionTypeBuilder].
+  final List<ClassHierarchyNode>? directSuperclassNodes;
+
+  /// The [ExtensionTypeHierarchyNode]s for the direct super extension types of
+  /// [extensionTypeBuilder].
+  final List<ExtensionTypeHierarchyNode>? directSuperExtensionTypeNodes;
+
+  /// The longest inheritance path from [extensionTypeBuilder] to `Object`.
+  final int maxInheritancePath;
+
+  ExtensionTypeHierarchyNode(
+      this.extensionTypeBuilder,
+      this.superclasses,
+      this.superExtensionTypes,
+      this.directSuperclassNodes,
+      this.directSuperExtensionTypeNodes,
+      this.maxInheritancePath);
+}
+
 ClassBuilder? getClass(TypeBuilder type) {
   Builder? declaration = type.declaration;
   if (declaration is TypeAliasBuilder) {
@@ -394,11 +614,3 @@
   }
   return declaration is ClassBuilder ? declaration : null;
 }
-
-const DebugLogger? debug =
-    const bool.fromEnvironment("debug.hierarchy") ? const DebugLogger() : null;
-
-class DebugLogger {
-  const DebugLogger();
-  void log(Object message) => print(message);
-}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index 525ab30..cfc72da 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -432,7 +432,6 @@
 
       benchmarker?.enterPhase(BenchmarkPhases.outline_checkSemantics);
       List<SourceClassBuilder>? sortedSourceClassBuilders;
-      // ignore: unused_local_variable
       List<SourceInlineClassBuilder>? sortedSourceExtensionTypeBuilders;
       (sortedSourceClassBuilders, sortedSourceExtensionTypeBuilders) =
           loader.checkClassCycles(objectClassBuilder);
@@ -459,7 +458,8 @@
       computeCoreTypes();
 
       benchmarker?.enterPhase(BenchmarkPhases.outline_buildClassHierarchy);
-      loader.buildClassHierarchy(sortedSourceClassBuilders, objectClassBuilder);
+      loader.buildClassHierarchy(sortedSourceClassBuilders,
+          sortedSourceExtensionTypeBuilders, objectClassBuilder);
 
       benchmarker?.enterPhase(BenchmarkPhases.outline_checkSupertypes);
       loader.checkSupertypes(sortedSourceClassBuilders, objectClass, enumClass,
diff --git a/pkg/front_end/lib/src/fasta/loader.dart b/pkg/front_end/lib/src/fasta/loader.dart
index 116eb5c..1c9fd94 100644
--- a/pkg/front_end/lib/src/fasta/loader.dart
+++ b/pkg/front_end/lib/src/fasta/loader.dart
@@ -6,9 +6,10 @@
 
 import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
 
-import 'package:kernel/ast.dart' show Class, DartType;
+import 'package:kernel/ast.dart' show Class, DartType, InlineClass;
 
 import 'builder/class_builder.dart';
+import 'builder/inline_class_builder.dart';
 import 'builder/library_builder.dart';
 import 'builder/type_builder.dart';
 
@@ -35,6 +36,9 @@
 
   ClassBuilder computeClassBuilderFromTargetClass(Class cls);
 
+  InlineClassBuilder computeExtensionTypeBuilderFromTargetExtensionType(
+      InlineClass extensionType);
+
   TypeBuilder computeTypeBuilder(DartType type);
 
   LibraryBuilder get coreLibrary;
diff --git a/pkg/front_end/lib/src/fasta/source/source_inline_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_inline_class_builder.dart
index efb754f..f4db5a4 100644
--- a/pkg/front_end/lib/src/fasta/source/source_inline_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_inline_class_builder.dart
@@ -51,6 +51,7 @@
   @override
   final List<TypeVariableBuilder>? typeParameters;
 
+  @override
   List<TypeBuilder>? interfaceBuilders;
 
   final SourceFieldBuilder? representationFieldBuilder;
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 706818b..c8f7eb1 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -44,6 +44,7 @@
 import '../builder/builder.dart';
 import '../builder/class_builder.dart';
 import '../builder/extension_builder.dart';
+import '../builder/inline_class_builder.dart';
 import '../builder/invalid_type_declaration_builder.dart';
 import '../builder/library_builder.dart';
 import '../builder/member_builder.dart';
@@ -2817,10 +2818,12 @@
   }
 
   void buildClassHierarchy(
-      List<SourceClassBuilder> sourceClasses, ClassBuilder objectClass) {
+      List<SourceClassBuilder> sourceClasses,
+      List<SourceInlineClassBuilder> sourceExtensionTypes,
+      ClassBuilder objectClass) {
     ClassHierarchyBuilder hierarchyBuilder = _hierarchyBuilder =
         ClassHierarchyBuilder.build(
-            objectClass, sourceClasses, this, coreTypes);
+            objectClass, sourceClasses, sourceExtensionTypes, this, coreTypes);
     typeInferenceEngine.hierarchyBuilder = hierarchyBuilder;
     ticker.logMs("Built class hierarchy");
   }
@@ -3038,6 +3041,19 @@
     return library.lookupLocalMember(cls.name, required: true) as ClassBuilder;
   }
 
+  @override
+  InlineClassBuilder computeExtensionTypeBuilderFromTargetExtensionType(
+      InlineClass extensionType) {
+    Library kernelLibrary = extensionType.enclosingLibrary;
+    LibraryBuilder? library = lookupLibraryBuilder(kernelLibrary.importUri);
+    if (library == null) {
+      return target.dillTarget.loader
+          .computeExtensionTypeBuilderFromTargetExtensionType(extensionType);
+    }
+    return library.lookupLocalMember(extensionType.name, required: true)
+        as InlineClassBuilder;
+  }
+
   late TypeBuilderComputer _typeBuilderComputer = new TypeBuilderComputer(this);
 
   @override
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index 38eb0fb..3158613 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -2606,7 +2606,7 @@
     KernelTarget target = result.sourceTarget;
     ClassHierarchyBuilder hierarchy = target.loader.hierarchyBuilder;
     StringBuffer sb = new StringBuffer();
-    for (ClassHierarchyNode node in hierarchy.nodes.values) {
+    for (ClassHierarchyNode node in hierarchy.classNodes.values) {
       sb.writeln(node);
     }
     return context.match<ComponentResult>(
diff --git a/pkg/front_end/test/fasta/types/dill_hierarchy_test.dart b/pkg/front_end/test/fasta/types/dill_hierarchy_test.dart
index eed27c8..639ee03 100644
--- a/pkg/front_end/test/fasta/types/dill_hierarchy_test.dart
+++ b/pkg/front_end/test/fasta/types/dill_hierarchy_test.dart
@@ -106,6 +106,6 @@
           hierarchy.getNodeFromClass(cls);
         }
         Expect.stringEquals(
-            expectedHierarchy, hierarchy.nodes.values.join("\n"));
+            expectedHierarchy, hierarchy.classNodes.values.join("\n"));
       }));
 }
diff --git a/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart
new file mode 100644
index 0000000..81031de
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2023, 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.
+
+extension type A<T>(int it) {}
+
+extension type B<T>(int it) implements A<T> {}
+
+extension type C<T>(int it) implements A<T> {}
+
+extension type D(int it) implements A<int>, B<String> {}
+
+extension type E(int it) implements B<int>, C<String> {}
diff --git a/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.strong.expect b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.strong.expect
new file mode 100644
index 0000000..aa8e3c36
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.strong.expect
@@ -0,0 +1,65 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart:11:16: Error: 'D' can't implement both 'A<int>' and 'A<String>'
+// extension type D(int it) implements A<int>, B<String> {}
+//                ^
+//
+// pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart:13:16: Error: 'E' can't implement both 'A<int>' and 'A<String>'
+// extension type E(int it) implements B<int>, C<String> {}
+//                ^
+//
+import self as self;
+import "dart:core" as core;
+
+inline class A<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ {
+  constructor • = self::A|;
+  tearoff • = self::A|_#new#tearOff;
+}
+inline class B<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ implements self::A<T%> {
+  constructor • = self::B|;
+  tearoff • = self::B|_#new#tearOff;
+}
+inline class C<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ implements self::A<T%> {
+  constructor • = self::C|;
+  tearoff • = self::C|_#new#tearOff;
+}
+inline class D /* declaredRepresentationType = core::int */ implements self::A<core::int>, self::B<core::String> {
+  constructor • = self::D|;
+  tearoff • = self::D|_#new#tearOff;
+}
+inline class E /* declaredRepresentationType = core::int */ implements self::B<core::int>, self::C<core::String> {
+  constructor • = self::E|;
+  tearoff • = self::E|_#new#tearOff;
+}
+static inline-class-member method A|<T extends core::Object? = dynamic>(dynamic it) → self::A<self::A|::T%> {
+  lowered final self::A<self::A|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method A|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::A<self::A|_#new#tearOff::T%>
+  return self::A|<self::A|_#new#tearOff::T%>(it);
+static inline-class-member method B|<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|::T%> {
+  lowered final self::B<self::B|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method B|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|_#new#tearOff::T%>
+  return self::B|<self::B|_#new#tearOff::T%>(it);
+static inline-class-member method C|<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|::T%> {
+  lowered final self::C<self::C|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method C|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|_#new#tearOff::T%>
+  return self::C|<self::C|_#new#tearOff::T%>(it);
+static inline-class-member method D|(dynamic it) → self::D {
+  lowered final self::D #this = it;
+  return #this;
+}
+static inline-class-member method D|_#new#tearOff(dynamic it) → self::D
+  return self::D|(it);
+static inline-class-member method E|(dynamic it) → self::E {
+  lowered final self::E #this = it;
+  return #this;
+}
+static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
+  return self::E|(it);
diff --git a/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.strong.transformed.expect b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.strong.transformed.expect
new file mode 100644
index 0000000..aa8e3c36
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.strong.transformed.expect
@@ -0,0 +1,65 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart:11:16: Error: 'D' can't implement both 'A<int>' and 'A<String>'
+// extension type D(int it) implements A<int>, B<String> {}
+//                ^
+//
+// pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart:13:16: Error: 'E' can't implement both 'A<int>' and 'A<String>'
+// extension type E(int it) implements B<int>, C<String> {}
+//                ^
+//
+import self as self;
+import "dart:core" as core;
+
+inline class A<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ {
+  constructor • = self::A|;
+  tearoff • = self::A|_#new#tearOff;
+}
+inline class B<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ implements self::A<T%> {
+  constructor • = self::B|;
+  tearoff • = self::B|_#new#tearOff;
+}
+inline class C<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ implements self::A<T%> {
+  constructor • = self::C|;
+  tearoff • = self::C|_#new#tearOff;
+}
+inline class D /* declaredRepresentationType = core::int */ implements self::A<core::int>, self::B<core::String> {
+  constructor • = self::D|;
+  tearoff • = self::D|_#new#tearOff;
+}
+inline class E /* declaredRepresentationType = core::int */ implements self::B<core::int>, self::C<core::String> {
+  constructor • = self::E|;
+  tearoff • = self::E|_#new#tearOff;
+}
+static inline-class-member method A|<T extends core::Object? = dynamic>(dynamic it) → self::A<self::A|::T%> {
+  lowered final self::A<self::A|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method A|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::A<self::A|_#new#tearOff::T%>
+  return self::A|<self::A|_#new#tearOff::T%>(it);
+static inline-class-member method B|<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|::T%> {
+  lowered final self::B<self::B|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method B|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|_#new#tearOff::T%>
+  return self::B|<self::B|_#new#tearOff::T%>(it);
+static inline-class-member method C|<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|::T%> {
+  lowered final self::C<self::C|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method C|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|_#new#tearOff::T%>
+  return self::C|<self::C|_#new#tearOff::T%>(it);
+static inline-class-member method D|(dynamic it) → self::D {
+  lowered final self::D #this = it;
+  return #this;
+}
+static inline-class-member method D|_#new#tearOff(dynamic it) → self::D
+  return self::D|(it);
+static inline-class-member method E|(dynamic it) → self::E {
+  lowered final self::E #this = it;
+  return #this;
+}
+static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
+  return self::E|(it);
diff --git a/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.textual_outline.expect b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.textual_outline.expect
new file mode 100644
index 0000000..1c578a5
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.textual_outline.expect
@@ -0,0 +1 @@
+extension type A<T>(int it) {} extension type B<T>(int it) implements A<T> {} extension type C<T>(int it) implements A<T> {} extension type D(int it) implements A<int>, B<String> {} extension type E(int it) implements B<int>, C<String> {}
diff --git a/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.weak.expect b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.weak.expect
new file mode 100644
index 0000000..aa8e3c36
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.weak.expect
@@ -0,0 +1,65 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart:11:16: Error: 'D' can't implement both 'A<int>' and 'A<String>'
+// extension type D(int it) implements A<int>, B<String> {}
+//                ^
+//
+// pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart:13:16: Error: 'E' can't implement both 'A<int>' and 'A<String>'
+// extension type E(int it) implements B<int>, C<String> {}
+//                ^
+//
+import self as self;
+import "dart:core" as core;
+
+inline class A<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ {
+  constructor • = self::A|;
+  tearoff • = self::A|_#new#tearOff;
+}
+inline class B<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ implements self::A<T%> {
+  constructor • = self::B|;
+  tearoff • = self::B|_#new#tearOff;
+}
+inline class C<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ implements self::A<T%> {
+  constructor • = self::C|;
+  tearoff • = self::C|_#new#tearOff;
+}
+inline class D /* declaredRepresentationType = core::int */ implements self::A<core::int>, self::B<core::String> {
+  constructor • = self::D|;
+  tearoff • = self::D|_#new#tearOff;
+}
+inline class E /* declaredRepresentationType = core::int */ implements self::B<core::int>, self::C<core::String> {
+  constructor • = self::E|;
+  tearoff • = self::E|_#new#tearOff;
+}
+static inline-class-member method A|<T extends core::Object? = dynamic>(dynamic it) → self::A<self::A|::T%> {
+  lowered final self::A<self::A|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method A|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::A<self::A|_#new#tearOff::T%>
+  return self::A|<self::A|_#new#tearOff::T%>(it);
+static inline-class-member method B|<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|::T%> {
+  lowered final self::B<self::B|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method B|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|_#new#tearOff::T%>
+  return self::B|<self::B|_#new#tearOff::T%>(it);
+static inline-class-member method C|<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|::T%> {
+  lowered final self::C<self::C|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method C|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|_#new#tearOff::T%>
+  return self::C|<self::C|_#new#tearOff::T%>(it);
+static inline-class-member method D|(dynamic it) → self::D {
+  lowered final self::D #this = it;
+  return #this;
+}
+static inline-class-member method D|_#new#tearOff(dynamic it) → self::D
+  return self::D|(it);
+static inline-class-member method E|(dynamic it) → self::E {
+  lowered final self::E #this = it;
+  return #this;
+}
+static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
+  return self::E|(it);
diff --git a/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.weak.modular.expect b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.weak.modular.expect
new file mode 100644
index 0000000..aa8e3c36
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.weak.modular.expect
@@ -0,0 +1,65 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart:11:16: Error: 'D' can't implement both 'A<int>' and 'A<String>'
+// extension type D(int it) implements A<int>, B<String> {}
+//                ^
+//
+// pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart:13:16: Error: 'E' can't implement both 'A<int>' and 'A<String>'
+// extension type E(int it) implements B<int>, C<String> {}
+//                ^
+//
+import self as self;
+import "dart:core" as core;
+
+inline class A<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ {
+  constructor • = self::A|;
+  tearoff • = self::A|_#new#tearOff;
+}
+inline class B<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ implements self::A<T%> {
+  constructor • = self::B|;
+  tearoff • = self::B|_#new#tearOff;
+}
+inline class C<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ implements self::A<T%> {
+  constructor • = self::C|;
+  tearoff • = self::C|_#new#tearOff;
+}
+inline class D /* declaredRepresentationType = core::int */ implements self::A<core::int>, self::B<core::String> {
+  constructor • = self::D|;
+  tearoff • = self::D|_#new#tearOff;
+}
+inline class E /* declaredRepresentationType = core::int */ implements self::B<core::int>, self::C<core::String> {
+  constructor • = self::E|;
+  tearoff • = self::E|_#new#tearOff;
+}
+static inline-class-member method A|<T extends core::Object? = dynamic>(dynamic it) → self::A<self::A|::T%> {
+  lowered final self::A<self::A|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method A|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::A<self::A|_#new#tearOff::T%>
+  return self::A|<self::A|_#new#tearOff::T%>(it);
+static inline-class-member method B|<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|::T%> {
+  lowered final self::B<self::B|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method B|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|_#new#tearOff::T%>
+  return self::B|<self::B|_#new#tearOff::T%>(it);
+static inline-class-member method C|<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|::T%> {
+  lowered final self::C<self::C|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method C|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|_#new#tearOff::T%>
+  return self::C|<self::C|_#new#tearOff::T%>(it);
+static inline-class-member method D|(dynamic it) → self::D {
+  lowered final self::D #this = it;
+  return #this;
+}
+static inline-class-member method D|_#new#tearOff(dynamic it) → self::D
+  return self::D|(it);
+static inline-class-member method E|(dynamic it) → self::E {
+  lowered final self::E #this = it;
+  return #this;
+}
+static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
+  return self::E|(it);
diff --git a/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.weak.outline.expect b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.weak.outline.expect
new file mode 100644
index 0000000..b848d6b
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.weak.outline.expect
@@ -0,0 +1,55 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart:11:16: Error: 'D' can't implement both 'A<int>' and 'A<String>'
+// extension type D(int it) implements A<int>, B<String> {}
+//                ^
+//
+// pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart:13:16: Error: 'E' can't implement both 'A<int>' and 'A<String>'
+// extension type E(int it) implements B<int>, C<String> {}
+//                ^
+//
+import self as self;
+import "dart:core" as core;
+
+inline class A<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ {
+  constructor • = self::A|;
+  tearoff • = self::A|_#new#tearOff;
+}
+inline class B<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ implements self::A<T%> {
+  constructor • = self::B|;
+  tearoff • = self::B|_#new#tearOff;
+}
+inline class C<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ implements self::A<T%> {
+  constructor • = self::C|;
+  tearoff • = self::C|_#new#tearOff;
+}
+inline class D /* declaredRepresentationType = core::int */ implements self::A<core::int>, self::B<core::String> {
+  constructor • = self::D|;
+  tearoff • = self::D|_#new#tearOff;
+}
+inline class E /* declaredRepresentationType = core::int */ implements self::B<core::int>, self::C<core::String> {
+  constructor • = self::E|;
+  tearoff • = self::E|_#new#tearOff;
+}
+static inline-class-member method A|<T extends core::Object? = dynamic>(dynamic it) → self::A<self::A|::T%>
+  ;
+static inline-class-member method A|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::A<self::A|_#new#tearOff::T%>
+  return self::A|<self::A|_#new#tearOff::T%>(it);
+static inline-class-member method B|<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|::T%>
+  ;
+static inline-class-member method B|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|_#new#tearOff::T%>
+  return self::B|<self::B|_#new#tearOff::T%>(it);
+static inline-class-member method C|<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|::T%>
+  ;
+static inline-class-member method C|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|_#new#tearOff::T%>
+  return self::C|<self::C|_#new#tearOff::T%>(it);
+static inline-class-member method D|(dynamic it) → self::D
+  ;
+static inline-class-member method D|_#new#tearOff(dynamic it) → self::D
+  return self::D|(it);
+static inline-class-member method E|(dynamic it) → self::E
+  ;
+static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
+  return self::E|(it);
diff --git a/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.weak.transformed.expect b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.weak.transformed.expect
new file mode 100644
index 0000000..aa8e3c36
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart.weak.transformed.expect
@@ -0,0 +1,65 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart:11:16: Error: 'D' can't implement both 'A<int>' and 'A<String>'
+// extension type D(int it) implements A<int>, B<String> {}
+//                ^
+//
+// pkg/front_end/testcases/inline_class/extension_types/super_extension_type_conflict.dart:13:16: Error: 'E' can't implement both 'A<int>' and 'A<String>'
+// extension type E(int it) implements B<int>, C<String> {}
+//                ^
+//
+import self as self;
+import "dart:core" as core;
+
+inline class A<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ {
+  constructor • = self::A|;
+  tearoff • = self::A|_#new#tearOff;
+}
+inline class B<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ implements self::A<T%> {
+  constructor • = self::B|;
+  tearoff • = self::B|_#new#tearOff;
+}
+inline class C<T extends core::Object? = dynamic> /* declaredRepresentationType = core::int */ implements self::A<T%> {
+  constructor • = self::C|;
+  tearoff • = self::C|_#new#tearOff;
+}
+inline class D /* declaredRepresentationType = core::int */ implements self::A<core::int>, self::B<core::String> {
+  constructor • = self::D|;
+  tearoff • = self::D|_#new#tearOff;
+}
+inline class E /* declaredRepresentationType = core::int */ implements self::B<core::int>, self::C<core::String> {
+  constructor • = self::E|;
+  tearoff • = self::E|_#new#tearOff;
+}
+static inline-class-member method A|<T extends core::Object? = dynamic>(dynamic it) → self::A<self::A|::T%> {
+  lowered final self::A<self::A|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method A|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::A<self::A|_#new#tearOff::T%>
+  return self::A|<self::A|_#new#tearOff::T%>(it);
+static inline-class-member method B|<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|::T%> {
+  lowered final self::B<self::B|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method B|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|_#new#tearOff::T%>
+  return self::B|<self::B|_#new#tearOff::T%>(it);
+static inline-class-member method C|<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|::T%> {
+  lowered final self::C<self::C|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method C|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|_#new#tearOff::T%>
+  return self::C|<self::C|_#new#tearOff::T%>(it);
+static inline-class-member method D|(dynamic it) → self::D {
+  lowered final self::D #this = it;
+  return #this;
+}
+static inline-class-member method D|_#new#tearOff(dynamic it) → self::D
+  return self::D|(it);
+static inline-class-member method E|(dynamic it) → self::E {
+  lowered final self::E #this = it;
+  return #this;
+}
+static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
+  return self::E|(it);
diff --git a/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart
new file mode 100644
index 0000000..7025596
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2023, 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 A<T> {}
+
+extension type B<T>(A<T> it) implements A<T> {}
+
+extension type C<T>(A<T> it) implements C<T> {}
+
+extension type D(A<Never> it) implements A<int>, B<String> {}
+
+extension type E(A<Never> it) implements B<int>, C<String> {}
diff --git a/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.strong.expect b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.strong.expect
new file mode 100644
index 0000000..4b905a6
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.strong.expect
@@ -0,0 +1,60 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart:9:16: Error: 'C' is a supertype of itself.
+// extension type C<T>(A<T> it) implements C<T> {}
+//                ^
+//
+// pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart:13:16: Error: 'E' is a supertype of itself.
+// extension type E(A<Never> it) implements B<int>, C<String> {}
+//                ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::T%>
+    : super core::Object::•()
+    ;
+}
+inline class B<T extends core::Object? = dynamic> /* declaredRepresentationType = self::A<T%> */ {
+  constructor • = self::B|;
+  tearoff • = self::B|_#new#tearOff;
+}
+inline class C<T extends core::Object? = dynamic> /* declaredRepresentationType = self::A<T%> */ {
+  constructor • = self::C|;
+  tearoff • = self::C|_#new#tearOff;
+}
+inline class D /* declaredRepresentationType = self::A<Never> */ implements self::B<core::String> {
+  constructor • = self::D|;
+  tearoff • = self::D|_#new#tearOff;
+}
+inline class E /* declaredRepresentationType = self::A<Never> */ {
+  constructor • = self::E|;
+  tearoff • = self::E|_#new#tearOff;
+}
+static inline-class-member method B|<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|::T%> {
+  lowered final self::B<self::B|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method B|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|_#new#tearOff::T%>
+  return self::B|<self::B|_#new#tearOff::T%>(it);
+static inline-class-member method C|<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|::T%> {
+  lowered final self::C<self::C|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method C|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|_#new#tearOff::T%>
+  return self::C|<self::C|_#new#tearOff::T%>(it);
+static inline-class-member method D|(dynamic it) → self::D {
+  lowered final self::D #this = it;
+  return #this;
+}
+static inline-class-member method D|_#new#tearOff(dynamic it) → self::D
+  return self::D|(it);
+static inline-class-member method E|(dynamic it) → self::E {
+  lowered final self::E #this = it;
+  return #this;
+}
+static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
+  return self::E|(it);
diff --git a/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.strong.transformed.expect b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.strong.transformed.expect
new file mode 100644
index 0000000..4b905a6
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.strong.transformed.expect
@@ -0,0 +1,60 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart:9:16: Error: 'C' is a supertype of itself.
+// extension type C<T>(A<T> it) implements C<T> {}
+//                ^
+//
+// pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart:13:16: Error: 'E' is a supertype of itself.
+// extension type E(A<Never> it) implements B<int>, C<String> {}
+//                ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::T%>
+    : super core::Object::•()
+    ;
+}
+inline class B<T extends core::Object? = dynamic> /* declaredRepresentationType = self::A<T%> */ {
+  constructor • = self::B|;
+  tearoff • = self::B|_#new#tearOff;
+}
+inline class C<T extends core::Object? = dynamic> /* declaredRepresentationType = self::A<T%> */ {
+  constructor • = self::C|;
+  tearoff • = self::C|_#new#tearOff;
+}
+inline class D /* declaredRepresentationType = self::A<Never> */ implements self::B<core::String> {
+  constructor • = self::D|;
+  tearoff • = self::D|_#new#tearOff;
+}
+inline class E /* declaredRepresentationType = self::A<Never> */ {
+  constructor • = self::E|;
+  tearoff • = self::E|_#new#tearOff;
+}
+static inline-class-member method B|<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|::T%> {
+  lowered final self::B<self::B|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method B|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|_#new#tearOff::T%>
+  return self::B|<self::B|_#new#tearOff::T%>(it);
+static inline-class-member method C|<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|::T%> {
+  lowered final self::C<self::C|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method C|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|_#new#tearOff::T%>
+  return self::C|<self::C|_#new#tearOff::T%>(it);
+static inline-class-member method D|(dynamic it) → self::D {
+  lowered final self::D #this = it;
+  return #this;
+}
+static inline-class-member method D|_#new#tearOff(dynamic it) → self::D
+  return self::D|(it);
+static inline-class-member method E|(dynamic it) → self::E {
+  lowered final self::E #this = it;
+  return #this;
+}
+static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
+  return self::E|(it);
diff --git a/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.textual_outline.expect b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.textual_outline.expect
new file mode 100644
index 0000000..3066c1a1
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.textual_outline.expect
@@ -0,0 +1,2 @@
+class A<T> {}
+extension type B<T>(A<T> it) implements A<T> {} extension type C<T>(A<T> it) implements C<T> {} extension type D(A<Never> it) implements A<int>, B<String> {} extension type E(A<Never> it) implements B<int>, C<String> {}
diff --git a/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.weak.expect b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.weak.expect
new file mode 100644
index 0000000..4b905a6
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.weak.expect
@@ -0,0 +1,60 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart:9:16: Error: 'C' is a supertype of itself.
+// extension type C<T>(A<T> it) implements C<T> {}
+//                ^
+//
+// pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart:13:16: Error: 'E' is a supertype of itself.
+// extension type E(A<Never> it) implements B<int>, C<String> {}
+//                ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::T%>
+    : super core::Object::•()
+    ;
+}
+inline class B<T extends core::Object? = dynamic> /* declaredRepresentationType = self::A<T%> */ {
+  constructor • = self::B|;
+  tearoff • = self::B|_#new#tearOff;
+}
+inline class C<T extends core::Object? = dynamic> /* declaredRepresentationType = self::A<T%> */ {
+  constructor • = self::C|;
+  tearoff • = self::C|_#new#tearOff;
+}
+inline class D /* declaredRepresentationType = self::A<Never> */ implements self::B<core::String> {
+  constructor • = self::D|;
+  tearoff • = self::D|_#new#tearOff;
+}
+inline class E /* declaredRepresentationType = self::A<Never> */ {
+  constructor • = self::E|;
+  tearoff • = self::E|_#new#tearOff;
+}
+static inline-class-member method B|<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|::T%> {
+  lowered final self::B<self::B|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method B|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|_#new#tearOff::T%>
+  return self::B|<self::B|_#new#tearOff::T%>(it);
+static inline-class-member method C|<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|::T%> {
+  lowered final self::C<self::C|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method C|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|_#new#tearOff::T%>
+  return self::C|<self::C|_#new#tearOff::T%>(it);
+static inline-class-member method D|(dynamic it) → self::D {
+  lowered final self::D #this = it;
+  return #this;
+}
+static inline-class-member method D|_#new#tearOff(dynamic it) → self::D
+  return self::D|(it);
+static inline-class-member method E|(dynamic it) → self::E {
+  lowered final self::E #this = it;
+  return #this;
+}
+static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
+  return self::E|(it);
diff --git a/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.weak.modular.expect b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.weak.modular.expect
new file mode 100644
index 0000000..4b905a6
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.weak.modular.expect
@@ -0,0 +1,60 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart:9:16: Error: 'C' is a supertype of itself.
+// extension type C<T>(A<T> it) implements C<T> {}
+//                ^
+//
+// pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart:13:16: Error: 'E' is a supertype of itself.
+// extension type E(A<Never> it) implements B<int>, C<String> {}
+//                ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::T%>
+    : super core::Object::•()
+    ;
+}
+inline class B<T extends core::Object? = dynamic> /* declaredRepresentationType = self::A<T%> */ {
+  constructor • = self::B|;
+  tearoff • = self::B|_#new#tearOff;
+}
+inline class C<T extends core::Object? = dynamic> /* declaredRepresentationType = self::A<T%> */ {
+  constructor • = self::C|;
+  tearoff • = self::C|_#new#tearOff;
+}
+inline class D /* declaredRepresentationType = self::A<Never> */ implements self::B<core::String> {
+  constructor • = self::D|;
+  tearoff • = self::D|_#new#tearOff;
+}
+inline class E /* declaredRepresentationType = self::A<Never> */ {
+  constructor • = self::E|;
+  tearoff • = self::E|_#new#tearOff;
+}
+static inline-class-member method B|<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|::T%> {
+  lowered final self::B<self::B|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method B|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|_#new#tearOff::T%>
+  return self::B|<self::B|_#new#tearOff::T%>(it);
+static inline-class-member method C|<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|::T%> {
+  lowered final self::C<self::C|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method C|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|_#new#tearOff::T%>
+  return self::C|<self::C|_#new#tearOff::T%>(it);
+static inline-class-member method D|(dynamic it) → self::D {
+  lowered final self::D #this = it;
+  return #this;
+}
+static inline-class-member method D|_#new#tearOff(dynamic it) → self::D
+  return self::D|(it);
+static inline-class-member method E|(dynamic it) → self::E {
+  lowered final self::E #this = it;
+  return #this;
+}
+static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
+  return self::E|(it);
diff --git a/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.weak.outline.expect b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.weak.outline.expect
new file mode 100644
index 0000000..1d75f0b
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.weak.outline.expect
@@ -0,0 +1,51 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart:9:16: Error: 'C' is a supertype of itself.
+// extension type C<T>(A<T> it) implements C<T> {}
+//                ^
+//
+// pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart:13:16: Error: 'E' is a supertype of itself.
+// extension type E(A<Never> it) implements B<int>, C<String> {}
+//                ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::T%>
+    ;
+}
+inline class B<T extends core::Object? = dynamic> /* declaredRepresentationType = self::A<T%> */ {
+  constructor • = self::B|;
+  tearoff • = self::B|_#new#tearOff;
+}
+inline class C<T extends core::Object? = dynamic> /* declaredRepresentationType = self::A<T%> */ {
+  constructor • = self::C|;
+  tearoff • = self::C|_#new#tearOff;
+}
+inline class D /* declaredRepresentationType = self::A<Never> */ implements self::B<core::String> {
+  constructor • = self::D|;
+  tearoff • = self::D|_#new#tearOff;
+}
+inline class E /* declaredRepresentationType = self::A<Never> */ {
+  constructor • = self::E|;
+  tearoff • = self::E|_#new#tearOff;
+}
+static inline-class-member method B|<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|::T%>
+  ;
+static inline-class-member method B|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|_#new#tearOff::T%>
+  return self::B|<self::B|_#new#tearOff::T%>(it);
+static inline-class-member method C|<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|::T%>
+  ;
+static inline-class-member method C|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|_#new#tearOff::T%>
+  return self::C|<self::C|_#new#tearOff::T%>(it);
+static inline-class-member method D|(dynamic it) → self::D
+  ;
+static inline-class-member method D|_#new#tearOff(dynamic it) → self::D
+  return self::D|(it);
+static inline-class-member method E|(dynamic it) → self::E
+  ;
+static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
+  return self::E|(it);
diff --git a/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.weak.transformed.expect b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.weak.transformed.expect
new file mode 100644
index 0000000..4b905a6
--- /dev/null
+++ b/pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart.weak.transformed.expect
@@ -0,0 +1,60 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart:9:16: Error: 'C' is a supertype of itself.
+// extension type C<T>(A<T> it) implements C<T> {}
+//                ^
+//
+// pkg/front_end/testcases/inline_class/extension_types/supertype_conflict.dart:13:16: Error: 'E' is a supertype of itself.
+// extension type E(A<Never> it) implements B<int>, C<String> {}
+//                ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::T%>
+    : super core::Object::•()
+    ;
+}
+inline class B<T extends core::Object? = dynamic> /* declaredRepresentationType = self::A<T%> */ {
+  constructor • = self::B|;
+  tearoff • = self::B|_#new#tearOff;
+}
+inline class C<T extends core::Object? = dynamic> /* declaredRepresentationType = self::A<T%> */ {
+  constructor • = self::C|;
+  tearoff • = self::C|_#new#tearOff;
+}
+inline class D /* declaredRepresentationType = self::A<Never> */ implements self::B<core::String> {
+  constructor • = self::D|;
+  tearoff • = self::D|_#new#tearOff;
+}
+inline class E /* declaredRepresentationType = self::A<Never> */ {
+  constructor • = self::E|;
+  tearoff • = self::E|_#new#tearOff;
+}
+static inline-class-member method B|<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|::T%> {
+  lowered final self::B<self::B|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method B|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::B<self::B|_#new#tearOff::T%>
+  return self::B|<self::B|_#new#tearOff::T%>(it);
+static inline-class-member method C|<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|::T%> {
+  lowered final self::C<self::C|::T%> #this = it;
+  return #this;
+}
+static inline-class-member method C|_#new#tearOff<T extends core::Object? = dynamic>(dynamic it) → self::C<self::C|_#new#tearOff::T%>
+  return self::C|<self::C|_#new#tearOff::T%>(it);
+static inline-class-member method D|(dynamic it) → self::D {
+  lowered final self::D #this = it;
+  return #this;
+}
+static inline-class-member method D|_#new#tearOff(dynamic it) → self::D
+  return self::D|(it);
+static inline-class-member method E|(dynamic it) → self::E {
+  lowered final self::E #this = it;
+  return #this;
+}
+static inline-class-member method E|_#new#tearOff(dynamic it) → self::E
+  return self::E|(it);
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index ee5554a..9b2eb84 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -148,6 +148,8 @@
 inline_class/extension_types/method_access: FormatterCrash
 inline_class/extension_types/procedures: FormatterCrash
 inline_class/extension_types/representation: FormatterCrash
+inline_class/extension_types/supertype_conflict: FormatterCrash
+inline_class/extension_types/super_extension_type_conflict: FormatterCrash
 late_lowering/later: FormatterCrash
 macros/augment_class: FormatterCrash
 macros/augment_concrete: FormatterCrash