[cfe] Allow mixins in enums

Part of https://github.com/dart-lang/sdk/issues/47453

Change-Id: I04d0a7690b6619ca61f364da756917319e6081b8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/227541
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
index 77c43b7..99fa6f1 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -50,6 +50,8 @@
     show InferenceDataForTesting, TypeInferenceEngine;
 import '../type_inference/type_inferrer.dart' show TypeInferrer;
 import 'diet_parser.dart';
+import 'source_constructor_builder.dart';
+import 'source_enum_builder.dart';
 import 'source_field_builder.dart';
 import 'source_function_builder.dart';
 import 'source_library_builder.dart' show SourceLibraryBuilder;
@@ -962,6 +964,19 @@
   void endEnum(Token enumKeyword, Token leftBrace, int memberCount) {
     debugEvent("Enum");
     checkEmpty(enumKeyword.charOffset);
+
+    SourceEnumBuilder? enumBuilder = currentClass as SourceEnumBuilder?;
+    if (enumBuilder != null) {
+      DeclaredSourceConstructorBuilder? defaultConstructorBuilder =
+          enumBuilder.synthesizedDefaultConstructorBuilder;
+      if (defaultConstructorBuilder != null) {
+        BodyBuilder bodyBuilder =
+            createFunctionListener(defaultConstructorBuilder);
+        bodyBuilder.finishConstructor(
+            defaultConstructorBuilder, AsyncMarker.Sync, new EmptyStatement());
+      }
+    }
+
     currentDeclaration = null;
     memberScope = libraryBuilder.scope;
   }
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index 820c2d5..6fe3c15 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -2329,7 +2329,7 @@
 
     // We pop more values than needed to reach typeVariables, offset and name.
     List<TypeBuilder>? interfaces = pop() as List<TypeBuilder>?;
-    List<TypeBuilder>? mixins = pop() as List<TypeBuilder>?;
+    Object? mixins = pop();
     List<TypeVariableBuilder>? typeVariables =
         pop() as List<TypeVariableBuilder>?;
     int charOffset = popCharOffset(); // identifier char offset.
@@ -2341,7 +2341,7 @@
     push(name ?? NullValue.Name);
     push(charOffset);
     push(typeVariables ?? NullValue.TypeVariables);
-    push(mixins ?? NullValue.TypeBuilderList);
+    push(mixins ?? NullValue.TypeBuilder);
     push(interfaces ?? NullValue.TypeBuilderList);
 
     push(enumKeyword.charOffset); // start char offset.
@@ -2364,7 +2364,7 @@
     int endCharOffset = popCharOffset();
     int startCharOffset = popCharOffset();
     pop() as List<TypeBuilder>?; // interfaces.
-    pop() as List<TypeBuilder>?; // mixins.
+    MixinApplicationBuilder? mixinBuilder = pop() as MixinApplicationBuilder?;
     List<TypeVariableBuilder>? typeVariables =
         pop() as List<TypeVariableBuilder>?;
     int charOffset = popCharOffset(); // identifier char offset.
@@ -2373,8 +2373,15 @@
     checkEmpty(startCharOffset);
 
     if (name is! ParserRecovery) {
-      libraryBuilder.addEnum(metadata, name as String, typeVariables,
-          enumConstantInfos, startCharOffset, charOffset, endCharOffset);
+      libraryBuilder.addEnum(
+          metadata,
+          name as String,
+          typeVariables,
+          mixinBuilder,
+          enumConstantInfos,
+          startCharOffset,
+          charOffset,
+          endCharOffset);
     } else {
       libraryBuilder
           .endNestedDeclaration(
@@ -3199,15 +3206,23 @@
     if (mixins is ParserRecovery) {
       push(new ParserRecovery(withKeyword.charOffset));
     } else {
-      // TODO(cstefantsova): Handle enum mixins here.
-      push(mixins);
+      NamedTypeBuilder enumType = new NamedTypeBuilder(
+          "_Enum",
+          const NullabilityBuilder.omitted(),
+          /* arguments = */ null,
+          /* fileUri = */ null,
+          /* charOffset = */ null,
+          instanceTypeVariableAccess:
+              InstanceTypeVariableAccessState.Unexpected);
+      push(libraryBuilder.addMixinApplication(
+          enumType, mixins as List<TypeBuilder>, withKeyword.charOffset));
     }
   }
 
   @override
   void handleEnumNoWithClause() {
     debugEvent("EnumNoWithClause");
-    push(NullValue.TypeBuilderList);
+    push(NullValue.TypeBuilder);
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 3faf679..c95900c 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -105,6 +105,8 @@
 
   SourceClassBuilder? _patchBuilder;
 
+  final bool isEnumMixin;
+
   SourceClassBuilder(
       List<MetadataBuilder>? metadata,
       int modifiers,
@@ -124,7 +126,8 @@
       {Class? cls,
       this.mixedInTypeBuilder,
       this.isMixinDeclaration = false,
-      this.isMacro: false})
+      this.isMacro: false,
+      this.isEnumMixin: false})
       : actualCls = initializeClass(cls, typeVariables, name, parent,
             startCharOffset, nameOffset, charEndOffset, referencesFromIndexed),
         super(metadata, modifiers, name, typeVariables, supertype, interfaces,
@@ -195,6 +198,11 @@
     if (supertypeBuilder != null) {
       supertypeBuilder = _checkSupertype(supertypeBuilder!);
     }
+    if (isEnumMixin) {
+      assert(supertypeBuilder?.name == "_Enum");
+      supertypeBuilder?.resolveIn(coreLibrary.scope,
+          supertypeBuilder?.charOffset ?? charOffset, fileUri, library);
+    }
     Supertype? supertype =
         supertypeBuilder?.buildSupertype(library, charOffset, fileUri);
     if (supertype != null) {
diff --git a/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart b/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart
index 2f84424..9a0fe61 100644
--- a/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart
@@ -46,6 +46,7 @@
 import '../builder/nullability_builder.dart';
 import '../builder/procedure_builder.dart';
 import '../builder/type_builder.dart';
+import '../builder/type_declaration_builder.dart';
 import '../builder/type_variable_builder.dart';
 import '../fasta_codes.dart'
     show
@@ -86,7 +87,7 @@
 
   final NamedTypeBuilder listType;
 
-  DeclaredSourceConstructorBuilder? _synthesizedDefaultConstructorBuilder;
+  DeclaredSourceConstructorBuilder? synthesizedDefaultConstructorBuilder;
 
   SourceEnumBuilder.internal(
       List<MetadataBuilder>? metadata,
@@ -99,7 +100,7 @@
       this.intType,
       this.listType,
       this.objectType,
-      TypeBuilder enumType,
+      TypeBuilder supertypeBuilder,
       this.stringType,
       SourceLibraryBuilder parent,
       int startCharOffset,
@@ -111,7 +112,7 @@
             0,
             name,
             typeVariables,
-            enumType,
+            supertypeBuilder,
             /* interfaces = */ null,
             /* onTypes = */ null,
             scope,
@@ -128,6 +129,7 @@
       List<MetadataBuilder>? metadata,
       String name,
       List<TypeVariableBuilder>? typeVariables,
+      TypeBuilder? supertypeBuilder,
       List<EnumConstantInfo?>? enumConstantInfos,
       SourceLibraryBuilder parent,
       int startCharOffset,
@@ -173,7 +175,7 @@
         /* fileUri = */ null,
         /* charOffset = */ null,
         instanceTypeVariableAccess: InstanceTypeVariableAccessState.Unexpected);
-    NamedTypeBuilder enumType = new NamedTypeBuilder(
+    supertypeBuilder ??= new NamedTypeBuilder(
         "_Enum",
         const NullabilityBuilder.omitted(),
         /* arguments = */ null,
@@ -418,14 +420,14 @@
         intType,
         listType,
         objectType,
-        enumType,
+        supertypeBuilder,
         stringType,
         parent,
         startCharOffsetComputed,
         charOffset,
         charEndOffset,
         referencesFromIndexed)
-      .._synthesizedDefaultConstructorBuilder =
+      ..synthesizedDefaultConstructorBuilder =
           synthesizedDefaultConstructorBuilder;
 
     void setParent(String name, MemberBuilder? builder) {
@@ -458,9 +460,21 @@
         coreLibrary.scope, charOffset, fileUri, libraryBuilder);
     objectType.resolveIn(
         coreLibrary.scope, charOffset, fileUri, libraryBuilder);
-    TypeBuilder supertypeBuilder = this.supertypeBuilder!;
-    supertypeBuilder.resolveIn(
-        coreLibrary.scope, charOffset, fileUri, libraryBuilder);
+    TypeBuilder? supertypeBuilder = this.supertypeBuilder;
+    NamedTypeBuilder? enumType;
+
+    while (enumType == null && supertypeBuilder is NamedTypeBuilder) {
+      TypeDeclarationBuilder? superclassBuilder = supertypeBuilder.declaration;
+      if (superclassBuilder is ClassBuilder &&
+          superclassBuilder.isMixinApplication) {
+        supertypeBuilder = superclassBuilder.supertypeBuilder;
+      } else {
+        enumType = supertypeBuilder;
+      }
+    }
+    assert(enumType is NamedTypeBuilder && enumType.name == "_Enum");
+    enumType!.resolveIn(coreLibrary.scope, charOffset, fileUri, libraryBuilder);
+
     listType.resolveIn(coreLibrary.scope, charOffset, fileUri, libraryBuilder);
 
     List<Expression> values = <Expression>[];
@@ -481,34 +495,39 @@
     valuesBuilder.build(libraryBuilder);
 
     // The super initializer for the synthesized default constructor is
-    // inserted here. Other constructors are handled in
-    // [BodyBuilder.finishConstructor], as they are processed via the pipeline
-    // for constructor parsing and building.
-    if (_synthesizedDefaultConstructorBuilder != null) {
-      Constructor constructor =
-          _synthesizedDefaultConstructorBuilder!.build(libraryBuilder);
-      ClassBuilder objectClass = objectType.declaration as ClassBuilder;
-      ClassBuilder enumClass = supertypeBuilder.declaration as ClassBuilder;
-      MemberBuilder? superConstructor = enumClass.findConstructorOrFactory(
-          "", charOffset, fileUri, libraryBuilder);
-      if (superConstructor == null || !superConstructor.isConstructor) {
-        // TODO(ahe): Ideally, we would also want to check that [Object]'s
-        // unnamed constructor requires no arguments. But that information
-        // isn't always available at this point, and it's not really a
-        // situation that can happen unless you start modifying the SDK
-        // sources. (We should add a correct message. We no longer depend on
-        // Object here.)
-        library.addProblem(
-            messageNoUnnamedConstructorInObject,
-            objectClass.charOffset,
-            objectClass.name.length,
-            objectClass.fileUri);
-      } else {
-        constructor.initializers.add(new SuperInitializer(
-            superConstructor.member as Constructor,
-            new Arguments.forwarded(
-                constructor.function, libraryBuilder.library))
-          ..parent = constructor);
+    // inserted here if the enum's supertype is _Enum to preserve the legacy
+    // behavior or having the old-style enum constants built in the outlines.
+    // Other constructors are handled in [BodyBuilder.finishConstructor] as
+    // they are processed via the pipeline for constructor parsing and
+    // building.
+    if (identical(this.supertypeBuilder, enumType)) {
+      if (synthesizedDefaultConstructorBuilder != null) {
+        Constructor constructor =
+            synthesizedDefaultConstructorBuilder!.build(libraryBuilder);
+        ClassBuilder objectClass = objectType.declaration as ClassBuilder;
+        ClassBuilder enumClass = enumType.declaration as ClassBuilder;
+        MemberBuilder? superConstructor = enumClass.findConstructorOrFactory(
+            "", charOffset, fileUri, libraryBuilder);
+        if (superConstructor == null || !superConstructor.isConstructor) {
+          // TODO(ahe): Ideally, we would also want to check that [Object]'s
+          // unnamed constructor requires no arguments. But that information
+          // isn't always available at this point, and it's not really a
+          // situation that can happen unless you start modifying the SDK
+          // sources. (We should add a correct message. We no longer depend on
+          // Object here.)
+          library.addProblem(
+              messageNoUnnamedConstructorInObject,
+              objectClass.charOffset,
+              objectClass.name.length,
+              objectClass.fileUri);
+        } else {
+          constructor.initializers.add(new SuperInitializer(
+              superConstructor.member as Constructor,
+              new Arguments.forwarded(
+                  constructor.function, libraryBuilder.library))
+            ..parent = constructor);
+        }
+        synthesizedDefaultConstructorBuilder = null;
       }
     }
 
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 28267ee..0ef86e7 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -2103,7 +2103,8 @@
       List<TypeVariableBuilder>? typeVariables,
       int modifiers: 0,
       List<TypeBuilder>? interfaces,
-      required bool isMacro}) {
+      required bool isMacro,
+      bool isEnumMixin: false}) {
     if (name == null) {
       // The following parameters should only be used when building a named
       // mixin application.
@@ -2322,7 +2323,8 @@
             charEndOffset,
             referencesFromIndexedClass,
             mixedInTypeBuilder: isMixinDeclaration ? null : mixin,
-            isMacro: isNamedMixinApplication && isMacro);
+            isMacro: isNamedMixinApplication && isMacro,
+            isEnumMixin: isEnumMixin && i == 0);
         // TODO(ahe, kmillikin): Should always be true?
         // pkg/analyzer/test/src/summary/resynthesize_kernel_test.dart can't
         // handle that :(
@@ -2791,6 +2793,7 @@
       List<MetadataBuilder>? metadata,
       String name,
       List<TypeVariableBuilder>? typeVariables,
+      TypeBuilder? supertypeBuilder,
       List<EnumConstantInfo?>? enumConstantInfos,
       int startCharOffset,
       int charOffset,
@@ -2812,6 +2815,9 @@
         metadata,
         name,
         typeVariables,
+        applyMixins(supertypeBuilder, startCharOffset, charOffset,
+            charEndOffset, name, /* isMixinDeclaration = */ false,
+            typeVariables: typeVariables, isMacro: false, isEnumMixin: true),
         enumConstantInfos,
         this,
         startCharOffset,
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 3f775f2..09b0c93 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -1029,6 +1029,7 @@
 entries
 entry
 enum
+enum's
 enumerated
 enumeration
 enumerations
diff --git a/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart
new file mode 100644
index 0000000..81e592e
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2022, 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 {
+  String get foo => "foo";
+}
+
+class B {
+  int bar() => 42;
+}
+
+mixin M {
+  void set callOnAssignment(void Function() f) {
+    f();
+  }
+}
+
+enum E1 with A { one, two }
+
+enum E2 with A, B { one, two }
+
+enum E3 with M { one, two }
+
+expectEquals(x, y) {
+  if (x != y) {
+    throw "Expected '$x' and '$y' to be equal.";
+  }
+}
+
+expectThrows(void Function() f) {
+  try {
+    f();
+    throw "Expected function to throw.";
+  } catch (e) {}
+}
+
+void throwOnCall() {
+  throw 42;
+}
+
+main() {
+  expectEquals(E1.one.foo, "foo");
+  expectEquals(E1.two.foo, "foo");
+  expectEquals(E2.one.foo, "foo");
+  expectEquals(E2.two.foo, "foo");
+  expectEquals(E2.one.bar(), "bar");
+  expectEquals(E2.two.bar(), "bar");
+  expectThrows(E3.one.callOnAssignment = throwOnCall);
+  expectThrows(E3.two.callOnAssignment = throwOnCall);
+}
diff --git a/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.strong.expect b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.strong.expect
new file mode 100644
index 0000000..6e10e5c
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.strong.expect
@@ -0,0 +1,137 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  get foo() → core::String
+    return "foo";
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  method bar() → core::int
+    return 42;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/  {
+  set callOnAssignment(() → void f) → void {
+    f(){() → void};
+  }
+}
+abstract class _E1&_Enum&A = core::_Enum with self::A /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E1&_Enum&A
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get foo() → core::String
+    return super.{self::A::foo};
+}
+class E1 extends self::_E1&_Enum&A /*isEnum*/  {
+  static const field core::List<self::E1> values = #C7;
+  static const field self::E1 one = #C3;
+  static const field self::E1 two = #C6;
+  const constructor •(core::int index, core::String name) → self::E1
+    : super self::_E1&_Enum&A::•(index, name)
+    ;
+  method toString() → core::String
+    ;
+}
+abstract class _E2&_Enum&A = core::_Enum with self::A /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get foo() → core::String
+    return super.{self::A::foo};
+}
+abstract class _E2&_Enum&A&B = self::_E2&_Enum&A with self::B /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A&B
+    : super self::_E2&_Enum&A::•(index, _name)
+    ;
+  mixin-super-stub method bar() → core::int
+    return super.{self::B::bar}();
+}
+class E2 extends self::_E2&_Enum&A&B /*isEnum*/  {
+  static const field core::List<self::E2> values = #C10;
+  static const field self::E2 one = #C8;
+  static const field self::E2 two = #C9;
+  const constructor •(core::int index, core::String name) → self::E2
+    : super self::_E2&_Enum&A&B::•(index, name)
+    ;
+  method toString() → core::String
+    ;
+}
+abstract class _E3&_Enum&M = core::_Enum with self::M /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E3&_Enum&M
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub set callOnAssignment(() → void f) → void
+    return super.{self::M::callOnAssignment} = f;
+}
+class E3 extends self::_E3&_Enum&M /*isEnum*/  {
+  static const field core::List<self::E3> values = #C13;
+  static const field self::E3 one = #C11;
+  static const field self::E3 two = #C12;
+  const constructor •(core::int index, core::String name) → self::E3
+    : super self::_E3&_Enum&M::•(index, name)
+    ;
+  method toString() → core::String
+    ;
+}
+static method expectEquals(dynamic x, dynamic y) → dynamic {
+  if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
+    throw "Expected '${x}' and '${y}' to be equal.";
+  }
+}
+static method expectThrows(() → void f) → dynamic {
+  try {
+    f(){() → void};
+    throw "Expected function to throw.";
+  }
+  on core::Object catch(final core::Object e) {
+  }
+}
+static method throwOnCall() → void {
+  throw 42;
+}
+static method main() → dynamic {
+  self::expectEquals(#C3.{self::_E1&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C6.{self::_E1&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C8.{self::_E2&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C9.{self::_E2&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C8.{self::_E2&_Enum&A&B::bar}(){() → core::int}, "bar");
+  self::expectEquals(#C9.{self::_E2&_Enum&A&B::bar}(){() → core::int}, "bar");
+  self::expectThrows(#C11.{self::_E3&_Enum&M::callOnAssignment} = #C14);
+  self::expectThrows(#C12.{self::_E3&_Enum&M::callOnAssignment} = #C14);
+}
+
+constants  {
+  #C1 = 0
+  #C2 = "one"
+  #C3 = self::E1 {index:#C1, _name:#C2}
+  #C4 = 1
+  #C5 = "two"
+  #C6 = self::E1 {index:#C4, _name:#C5}
+  #C7 = <self::E1>[#C3, #C6]
+  #C8 = self::E2 {index:#C1, _name:#C2}
+  #C9 = self::E2 {index:#C4, _name:#C5}
+  #C10 = <self::E2>[#C8, #C9]
+  #C11 = self::E3 {index:#C1, _name:#C2}
+  #C12 = self::E3 {index:#C4, _name:#C5}
+  #C13 = <self::E3>[#C11, #C12]
+  #C14 = static-tearoff self::throwOnCall
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///simple_mixins.dart:
+- E1. (from org-dartlang-testcase:///simple_mixins.dart:19:6)
+- _E1&_Enum&A. (from org-dartlang-testcase:///simple_mixins.dart:19:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:76:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- E2. (from org-dartlang-testcase:///simple_mixins.dart:21:6)
+- _E2&_Enum&A&B. (from org-dartlang-testcase:///simple_mixins.dart:21:6)
+- _E2&_Enum&A. (from org-dartlang-testcase:///simple_mixins.dart:21:6)
+- E3. (from org-dartlang-testcase:///simple_mixins.dart:23:6)
+- _E3&_Enum&M. (from org-dartlang-testcase:///simple_mixins.dart:23:6)
diff --git a/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.strong.transformed.expect b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.strong.transformed.expect
new file mode 100644
index 0000000..4a5994b
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.strong.transformed.expect
@@ -0,0 +1,138 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  get foo() → core::String
+    return "foo";
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  method bar() → core::int
+    return 42;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/  {
+  set callOnAssignment(() → void f) → void {
+    f(){() → void};
+  }
+}
+abstract class _E1&_Enum&A extends core::_Enum implements self::A /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E1&_Enum&A
+    : super core::_Enum::•(index, _name)
+    ;
+  get foo() → core::String
+    return "foo";
+}
+class E1 extends self::_E1&_Enum&A /*isEnum*/  {
+  static const field core::List<self::E1> values = #C7;
+  static const field self::E1 one = #C3;
+  static const field self::E1 two = #C6;
+  const constructor •(core::int index, core::String name) → self::E1
+    : super self::_E1&_Enum&A::•(index, name)
+    ;
+  method toString() → core::String
+    ;
+}
+abstract class _E2&_Enum&A extends core::_Enum implements self::A /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A
+    : super core::_Enum::•(index, _name)
+    ;
+  get foo() → core::String
+    return "foo";
+}
+abstract class _E2&_Enum&A&B extends self::_E2&_Enum&A implements self::B /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A&B
+    : super self::_E2&_Enum&A::•(index, _name)
+    ;
+  method bar() → core::int
+    return 42;
+}
+class E2 extends self::_E2&_Enum&A&B /*isEnum*/  {
+  static const field core::List<self::E2> values = #C10;
+  static const field self::E2 one = #C8;
+  static const field self::E2 two = #C9;
+  const constructor •(core::int index, core::String name) → self::E2
+    : super self::_E2&_Enum&A&B::•(index, name)
+    ;
+  method toString() → core::String
+    ;
+}
+abstract class _E3&_Enum&M extends core::_Enum implements self::M /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E3&_Enum&M
+    : super core::_Enum::•(index, _name)
+    ;
+  set callOnAssignment(() → void f) → void {
+    f(){() → void};
+  }
+}
+class E3 extends self::_E3&_Enum&M /*isEnum*/  {
+  static const field core::List<self::E3> values = #C13;
+  static const field self::E3 one = #C11;
+  static const field self::E3 two = #C12;
+  const constructor •(core::int index, core::String name) → self::E3
+    : super self::_E3&_Enum&M::•(index, name)
+    ;
+  method toString() → core::String
+    ;
+}
+static method expectEquals(dynamic x, dynamic y) → dynamic {
+  if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
+    throw "Expected '${x}' and '${y}' to be equal.";
+  }
+}
+static method expectThrows(() → void f) → dynamic {
+  try {
+    f(){() → void};
+    throw "Expected function to throw.";
+  }
+  on core::Object catch(final core::Object e) {
+  }
+}
+static method throwOnCall() → void {
+  throw 42;
+}
+static method main() → dynamic {
+  self::expectEquals(#C3.{self::_E1&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C6.{self::_E1&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C8.{self::_E2&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C9.{self::_E2&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C8.{self::_E2&_Enum&A&B::bar}(){() → core::int}, "bar");
+  self::expectEquals(#C9.{self::_E2&_Enum&A&B::bar}(){() → core::int}, "bar");
+  self::expectThrows(#C11.{self::_E3&_Enum&M::callOnAssignment} = #C14);
+  self::expectThrows(#C12.{self::_E3&_Enum&M::callOnAssignment} = #C14);
+}
+
+constants  {
+  #C1 = 0
+  #C2 = "one"
+  #C3 = self::E1 {index:#C1, _name:#C2}
+  #C4 = 1
+  #C5 = "two"
+  #C6 = self::E1 {index:#C4, _name:#C5}
+  #C7 = <self::E1>[#C3, #C6]
+  #C8 = self::E2 {index:#C1, _name:#C2}
+  #C9 = self::E2 {index:#C4, _name:#C5}
+  #C10 = <self::E2>[#C8, #C9]
+  #C11 = self::E3 {index:#C1, _name:#C2}
+  #C12 = self::E3 {index:#C4, _name:#C5}
+  #C13 = <self::E3>[#C11, #C12]
+  #C14 = static-tearoff self::throwOnCall
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///simple_mixins.dart:
+- E1. (from org-dartlang-testcase:///simple_mixins.dart:19:6)
+- _E1&_Enum&A. (from org-dartlang-testcase:///simple_mixins.dart:19:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:76:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- E2. (from org-dartlang-testcase:///simple_mixins.dart:21:6)
+- _E2&_Enum&A&B. (from org-dartlang-testcase:///simple_mixins.dart:21:6)
+- _E2&_Enum&A. (from org-dartlang-testcase:///simple_mixins.dart:21:6)
+- E3. (from org-dartlang-testcase:///simple_mixins.dart:23:6)
+- _E3&_Enum&M. (from org-dartlang-testcase:///simple_mixins.dart:23:6)
diff --git a/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.textual_outline.expect b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.textual_outline.expect
new file mode 100644
index 0000000..8e3abd8
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.textual_outline.expect
@@ -0,0 +1,16 @@
+class A {
+  String get foo => "foo";
+}
+class B {
+  int bar() => 42;
+}
+mixin M {
+  void set callOnAssignment(void Function() f) {}
+}
+enum E1 with A { one, two }
+enum E2 with A, B { one, two }
+enum E3 with M { one, two }
+expectEquals(x, y) {}
+expectThrows(void Function() f) {}
+void throwOnCall() {}
+main() {}
diff --git a/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.weak.expect b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.weak.expect
new file mode 100644
index 0000000..82c66e8
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.weak.expect
@@ -0,0 +1,137 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  get foo() → core::String
+    return "foo";
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  method bar() → core::int
+    return 42;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/  {
+  set callOnAssignment(() → void f) → void {
+    f(){() → void};
+  }
+}
+abstract class _E1&_Enum&A = core::_Enum with self::A /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E1&_Enum&A
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get foo() → core::String
+    return super.{self::A::foo};
+}
+class E1 extends self::_E1&_Enum&A /*isEnum*/  {
+  static const field core::List<self::E1> values = #C7;
+  static const field self::E1 one = #C3;
+  static const field self::E1 two = #C6;
+  const constructor •(core::int index, core::String name) → self::E1
+    : super self::_E1&_Enum&A::•(index, name)
+    ;
+  method toString() → core::String
+    ;
+}
+abstract class _E2&_Enum&A = core::_Enum with self::A /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get foo() → core::String
+    return super.{self::A::foo};
+}
+abstract class _E2&_Enum&A&B = self::_E2&_Enum&A with self::B /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A&B
+    : super self::_E2&_Enum&A::•(index, _name)
+    ;
+  mixin-super-stub method bar() → core::int
+    return super.{self::B::bar}();
+}
+class E2 extends self::_E2&_Enum&A&B /*isEnum*/  {
+  static const field core::List<self::E2> values = #C10;
+  static const field self::E2 one = #C8;
+  static const field self::E2 two = #C9;
+  const constructor •(core::int index, core::String name) → self::E2
+    : super self::_E2&_Enum&A&B::•(index, name)
+    ;
+  method toString() → core::String
+    ;
+}
+abstract class _E3&_Enum&M = core::_Enum with self::M /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E3&_Enum&M
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub set callOnAssignment(() → void f) → void
+    return super.{self::M::callOnAssignment} = f;
+}
+class E3 extends self::_E3&_Enum&M /*isEnum*/  {
+  static const field core::List<self::E3> values = #C13;
+  static const field self::E3 one = #C11;
+  static const field self::E3 two = #C12;
+  const constructor •(core::int index, core::String name) → self::E3
+    : super self::_E3&_Enum&M::•(index, name)
+    ;
+  method toString() → core::String
+    ;
+}
+static method expectEquals(dynamic x, dynamic y) → dynamic {
+  if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
+    throw "Expected '${x}' and '${y}' to be equal.";
+  }
+}
+static method expectThrows(() → void f) → dynamic {
+  try {
+    f(){() → void};
+    throw "Expected function to throw.";
+  }
+  on core::Object catch(final core::Object e) {
+  }
+}
+static method throwOnCall() → void {
+  throw 42;
+}
+static method main() → dynamic {
+  self::expectEquals(#C3.{self::_E1&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C6.{self::_E1&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C8.{self::_E2&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C9.{self::_E2&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C8.{self::_E2&_Enum&A&B::bar}(){() → core::int}, "bar");
+  self::expectEquals(#C9.{self::_E2&_Enum&A&B::bar}(){() → core::int}, "bar");
+  self::expectThrows(#C11.{self::_E3&_Enum&M::callOnAssignment} = #C14);
+  self::expectThrows(#C12.{self::_E3&_Enum&M::callOnAssignment} = #C14);
+}
+
+constants  {
+  #C1 = 0
+  #C2 = "one"
+  #C3 = self::E1 {index:#C1, _name:#C2}
+  #C4 = 1
+  #C5 = "two"
+  #C6 = self::E1 {index:#C4, _name:#C5}
+  #C7 = <self::E1*>[#C3, #C6]
+  #C8 = self::E2 {index:#C1, _name:#C2}
+  #C9 = self::E2 {index:#C4, _name:#C5}
+  #C10 = <self::E2*>[#C8, #C9]
+  #C11 = self::E3 {index:#C1, _name:#C2}
+  #C12 = self::E3 {index:#C4, _name:#C5}
+  #C13 = <self::E3*>[#C11, #C12]
+  #C14 = static-tearoff self::throwOnCall
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///simple_mixins.dart:
+- E1. (from org-dartlang-testcase:///simple_mixins.dart:19:6)
+- _E1&_Enum&A. (from org-dartlang-testcase:///simple_mixins.dart:19:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:76:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- E2. (from org-dartlang-testcase:///simple_mixins.dart:21:6)
+- _E2&_Enum&A&B. (from org-dartlang-testcase:///simple_mixins.dart:21:6)
+- _E2&_Enum&A. (from org-dartlang-testcase:///simple_mixins.dart:21:6)
+- E3. (from org-dartlang-testcase:///simple_mixins.dart:23:6)
+- _E3&_Enum&M. (from org-dartlang-testcase:///simple_mixins.dart:23:6)
diff --git a/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.weak.modular.expect b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.weak.modular.expect
new file mode 100644
index 0000000..82c66e8
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.weak.modular.expect
@@ -0,0 +1,137 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  get foo() → core::String
+    return "foo";
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  method bar() → core::int
+    return 42;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/  {
+  set callOnAssignment(() → void f) → void {
+    f(){() → void};
+  }
+}
+abstract class _E1&_Enum&A = core::_Enum with self::A /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E1&_Enum&A
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get foo() → core::String
+    return super.{self::A::foo};
+}
+class E1 extends self::_E1&_Enum&A /*isEnum*/  {
+  static const field core::List<self::E1> values = #C7;
+  static const field self::E1 one = #C3;
+  static const field self::E1 two = #C6;
+  const constructor •(core::int index, core::String name) → self::E1
+    : super self::_E1&_Enum&A::•(index, name)
+    ;
+  method toString() → core::String
+    ;
+}
+abstract class _E2&_Enum&A = core::_Enum with self::A /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get foo() → core::String
+    return super.{self::A::foo};
+}
+abstract class _E2&_Enum&A&B = self::_E2&_Enum&A with self::B /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A&B
+    : super self::_E2&_Enum&A::•(index, _name)
+    ;
+  mixin-super-stub method bar() → core::int
+    return super.{self::B::bar}();
+}
+class E2 extends self::_E2&_Enum&A&B /*isEnum*/  {
+  static const field core::List<self::E2> values = #C10;
+  static const field self::E2 one = #C8;
+  static const field self::E2 two = #C9;
+  const constructor •(core::int index, core::String name) → self::E2
+    : super self::_E2&_Enum&A&B::•(index, name)
+    ;
+  method toString() → core::String
+    ;
+}
+abstract class _E3&_Enum&M = core::_Enum with self::M /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E3&_Enum&M
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub set callOnAssignment(() → void f) → void
+    return super.{self::M::callOnAssignment} = f;
+}
+class E3 extends self::_E3&_Enum&M /*isEnum*/  {
+  static const field core::List<self::E3> values = #C13;
+  static const field self::E3 one = #C11;
+  static const field self::E3 two = #C12;
+  const constructor •(core::int index, core::String name) → self::E3
+    : super self::_E3&_Enum&M::•(index, name)
+    ;
+  method toString() → core::String
+    ;
+}
+static method expectEquals(dynamic x, dynamic y) → dynamic {
+  if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
+    throw "Expected '${x}' and '${y}' to be equal.";
+  }
+}
+static method expectThrows(() → void f) → dynamic {
+  try {
+    f(){() → void};
+    throw "Expected function to throw.";
+  }
+  on core::Object catch(final core::Object e) {
+  }
+}
+static method throwOnCall() → void {
+  throw 42;
+}
+static method main() → dynamic {
+  self::expectEquals(#C3.{self::_E1&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C6.{self::_E1&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C8.{self::_E2&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C9.{self::_E2&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C8.{self::_E2&_Enum&A&B::bar}(){() → core::int}, "bar");
+  self::expectEquals(#C9.{self::_E2&_Enum&A&B::bar}(){() → core::int}, "bar");
+  self::expectThrows(#C11.{self::_E3&_Enum&M::callOnAssignment} = #C14);
+  self::expectThrows(#C12.{self::_E3&_Enum&M::callOnAssignment} = #C14);
+}
+
+constants  {
+  #C1 = 0
+  #C2 = "one"
+  #C3 = self::E1 {index:#C1, _name:#C2}
+  #C4 = 1
+  #C5 = "two"
+  #C6 = self::E1 {index:#C4, _name:#C5}
+  #C7 = <self::E1*>[#C3, #C6]
+  #C8 = self::E2 {index:#C1, _name:#C2}
+  #C9 = self::E2 {index:#C4, _name:#C5}
+  #C10 = <self::E2*>[#C8, #C9]
+  #C11 = self::E3 {index:#C1, _name:#C2}
+  #C12 = self::E3 {index:#C4, _name:#C5}
+  #C13 = <self::E3*>[#C11, #C12]
+  #C14 = static-tearoff self::throwOnCall
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///simple_mixins.dart:
+- E1. (from org-dartlang-testcase:///simple_mixins.dart:19:6)
+- _E1&_Enum&A. (from org-dartlang-testcase:///simple_mixins.dart:19:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:76:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- E2. (from org-dartlang-testcase:///simple_mixins.dart:21:6)
+- _E2&_Enum&A&B. (from org-dartlang-testcase:///simple_mixins.dart:21:6)
+- _E2&_Enum&A. (from org-dartlang-testcase:///simple_mixins.dart:21:6)
+- E3. (from org-dartlang-testcase:///simple_mixins.dart:23:6)
+- _E3&_Enum&M. (from org-dartlang-testcase:///simple_mixins.dart:23:6)
diff --git a/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.weak.outline.expect b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.weak.outline.expect
new file mode 100644
index 0000000..abd958f
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.weak.outline.expect
@@ -0,0 +1,96 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    ;
+  get foo() → core::String
+    ;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    ;
+  method bar() → core::int
+    ;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/  {
+  set callOnAssignment(() → void f) → void
+    ;
+}
+abstract class _E1&_Enum&A = core::_Enum with self::A /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E1&_Enum&A
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get foo() → core::String
+    return super.{self::A::foo};
+}
+class E1 extends self::_E1&_Enum&A /*isEnum*/  {
+  static const field core::List<self::E1> values = const <self::E1>[self::E1::one, self::E1::two];
+  static const field self::E1 one = const self::E1::•(0, "one");
+  static const field self::E1 two = const self::E1::•(1, "two");
+  const constructor •(core::int index, core::String name) → self::E1
+    ;
+  method toString() → core::String
+    ;
+}
+abstract class _E2&_Enum&A = core::_Enum with self::A /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub get foo() → core::String
+    return super.{self::A::foo};
+}
+abstract class _E2&_Enum&A&B = self::_E2&_Enum&A with self::B /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A&B
+    : super self::_E2&_Enum&A::•(index, _name)
+    ;
+  mixin-super-stub method bar() → core::int
+    return super.{self::B::bar}();
+}
+class E2 extends self::_E2&_Enum&A&B /*isEnum*/  {
+  static const field core::List<self::E2> values = const <self::E2>[self::E2::one, self::E2::two];
+  static const field self::E2 one = const self::E2::•(0, "one");
+  static const field self::E2 two = const self::E2::•(1, "two");
+  const constructor •(core::int index, core::String name) → self::E2
+    ;
+  method toString() → core::String
+    ;
+}
+abstract class _E3&_Enum&M = core::_Enum with self::M /*isAnonymousMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E3&_Enum&M
+    : super core::_Enum::•(index, _name)
+    ;
+  mixin-super-stub set callOnAssignment(() → void f) → void
+    return super.{self::M::callOnAssignment} = f;
+}
+class E3 extends self::_E3&_Enum&M /*isEnum*/  {
+  static const field core::List<self::E3> values = const <self::E3>[self::E3::one, self::E3::two];
+  static const field self::E3 one = const self::E3::•(0, "one");
+  static const field self::E3 two = const self::E3::•(1, "two");
+  const constructor •(core::int index, core::String name) → self::E3
+    ;
+  method toString() → core::String
+    ;
+}
+static method expectEquals(dynamic x, dynamic y) → dynamic
+  ;
+static method expectThrows(() → void f) → dynamic
+  ;
+static method throwOnCall() → void
+  ;
+static method main() → dynamic
+  ;
+
+
+Extra constant evaluation status:
+Evaluated: ListLiteral @ org-dartlang-testcase:///simple_mixins.dart:19:6 -> ListConstant(const <E1*>[const E1{}, const E1{}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///simple_mixins.dart:19:18 -> InstanceConstant(const E1{})
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///simple_mixins.dart:19:23 -> InstanceConstant(const E1{})
+Evaluated: ListLiteral @ org-dartlang-testcase:///simple_mixins.dart:21:6 -> ListConstant(const <E2*>[const E2{}, const E2{}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///simple_mixins.dart:21:21 -> InstanceConstant(const E2{})
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///simple_mixins.dart:21:26 -> InstanceConstant(const E2{})
+Evaluated: ListLiteral @ org-dartlang-testcase:///simple_mixins.dart:23:6 -> ListConstant(const <E3*>[const E3{}, const E3{}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///simple_mixins.dart:23:18 -> InstanceConstant(const E3{})
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///simple_mixins.dart:23:23 -> InstanceConstant(const E3{})
+Extra constant evaluation: evaluated: 22, effectively constant: 9
diff --git a/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.weak.transformed.expect b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.weak.transformed.expect
new file mode 100644
index 0000000..af40a65
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/simple_mixins.dart.weak.transformed.expect
@@ -0,0 +1,138 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  get foo() → core::String
+    return "foo";
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  method bar() → core::int
+    return 42;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/  {
+  set callOnAssignment(() → void f) → void {
+    f(){() → void};
+  }
+}
+abstract class _E1&_Enum&A extends core::_Enum implements self::A /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E1&_Enum&A
+    : super core::_Enum::•(index, _name)
+    ;
+  get foo() → core::String
+    return "foo";
+}
+class E1 extends self::_E1&_Enum&A /*isEnum*/  {
+  static const field core::List<self::E1> values = #C7;
+  static const field self::E1 one = #C3;
+  static const field self::E1 two = #C6;
+  const constructor •(core::int index, core::String name) → self::E1
+    : super self::_E1&_Enum&A::•(index, name)
+    ;
+  method toString() → core::String
+    ;
+}
+abstract class _E2&_Enum&A extends core::_Enum implements self::A /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A
+    : super core::_Enum::•(index, _name)
+    ;
+  get foo() → core::String
+    return "foo";
+}
+abstract class _E2&_Enum&A&B extends self::_E2&_Enum&A implements self::B /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E2&_Enum&A&B
+    : super self::_E2&_Enum&A::•(index, _name)
+    ;
+  method bar() → core::int
+    return 42;
+}
+class E2 extends self::_E2&_Enum&A&B /*isEnum*/  {
+  static const field core::List<self::E2> values = #C10;
+  static const field self::E2 one = #C8;
+  static const field self::E2 two = #C9;
+  const constructor •(core::int index, core::String name) → self::E2
+    : super self::_E2&_Enum&A&B::•(index, name)
+    ;
+  method toString() → core::String
+    ;
+}
+abstract class _E3&_Enum&M extends core::_Enum implements self::M /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+  const synthetic constructor •(core::int index, core::String _name) → self::_E3&_Enum&M
+    : super core::_Enum::•(index, _name)
+    ;
+  set callOnAssignment(() → void f) → void {
+    f(){() → void};
+  }
+}
+class E3 extends self::_E3&_Enum&M /*isEnum*/  {
+  static const field core::List<self::E3> values = #C13;
+  static const field self::E3 one = #C11;
+  static const field self::E3 two = #C12;
+  const constructor •(core::int index, core::String name) → self::E3
+    : super self::_E3&_Enum&M::•(index, name)
+    ;
+  method toString() → core::String
+    ;
+}
+static method expectEquals(dynamic x, dynamic y) → dynamic {
+  if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
+    throw "Expected '${x}' and '${y}' to be equal.";
+  }
+}
+static method expectThrows(() → void f) → dynamic {
+  try {
+    f(){() → void};
+    throw "Expected function to throw.";
+  }
+  on core::Object catch(final core::Object e) {
+  }
+}
+static method throwOnCall() → void {
+  throw 42;
+}
+static method main() → dynamic {
+  self::expectEquals(#C3.{self::_E1&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C6.{self::_E1&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C8.{self::_E2&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C9.{self::_E2&_Enum&A::foo}{core::String}, "foo");
+  self::expectEquals(#C8.{self::_E2&_Enum&A&B::bar}(){() → core::int}, "bar");
+  self::expectEquals(#C9.{self::_E2&_Enum&A&B::bar}(){() → core::int}, "bar");
+  self::expectThrows(#C11.{self::_E3&_Enum&M::callOnAssignment} = #C14);
+  self::expectThrows(#C12.{self::_E3&_Enum&M::callOnAssignment} = #C14);
+}
+
+constants  {
+  #C1 = 0
+  #C2 = "one"
+  #C3 = self::E1 {index:#C1, _name:#C2}
+  #C4 = 1
+  #C5 = "two"
+  #C6 = self::E1 {index:#C4, _name:#C5}
+  #C7 = <self::E1*>[#C3, #C6]
+  #C8 = self::E2 {index:#C1, _name:#C2}
+  #C9 = self::E2 {index:#C4, _name:#C5}
+  #C10 = <self::E2*>[#C8, #C9]
+  #C11 = self::E3 {index:#C1, _name:#C2}
+  #C12 = self::E3 {index:#C4, _name:#C5}
+  #C13 = <self::E3*>[#C11, #C12]
+  #C14 = static-tearoff self::throwOnCall
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///simple_mixins.dart:
+- E1. (from org-dartlang-testcase:///simple_mixins.dart:19:6)
+- _E1&_Enum&A. (from org-dartlang-testcase:///simple_mixins.dart:19:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:76:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- E2. (from org-dartlang-testcase:///simple_mixins.dart:21:6)
+- _E2&_Enum&A&B. (from org-dartlang-testcase:///simple_mixins.dart:21:6)
+- _E2&_Enum&A. (from org-dartlang-testcase:///simple_mixins.dart:21:6)
+- E3. (from org-dartlang-testcase:///simple_mixins.dart:23:6)
+- _E3&_Enum&M. (from org-dartlang-testcase:///simple_mixins.dart:23:6)
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index 2aef19d..f57bbdf 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -15,6 +15,7 @@
 
 constructor_tearoffs/call_instantiation: TypeCheckError
 constructor_tearoffs/lowering/invalid_redirect: VerificationError
+enhanced_enums/simple_mixins: RuntimeError
 extension_types/access_setter_as_getter: ExpectationFileMismatchSerialized # Expected.
 extension_types/call_not_get: ExpectationFileMismatchSerialized # Expected.
 extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index b66d7f8..5a838fa 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -8,6 +8,7 @@
 
 constructor_tearoffs/call_instantiation: TypeCheckError
 constructor_tearoffs/lowering/invalid_redirect: VerificationError
+enhanced_enums/simple_mixins: RuntimeError
 extension_types/access_setter_as_getter: ExpectationFileMismatchSerialized # Expected.
 extension_types/call_not_get: ExpectationFileMismatchSerialized # Expected.
 extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index 6736b08..0228fca 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -35,6 +35,7 @@
 enhanced_enums/qualified_names_with_no_type_arguments: FormatterCrash
 enhanced_enums/redirecting_initializers: FormatterCrash
 enhanced_enums/simple_fields: FormatterCrash
+enhanced_enums/simple_mixins: FormatterCrash
 extension_types/basic_show: FormatterCrash
 extension_types/call_not_get: FormatterCrash
 extension_types/keyword_in_show_hide_element: FormatterCrash
diff --git a/pkg/front_end/testcases/weak.status b/pkg/front_end/testcases/weak.status
index 8898c1a..f75594a 100644
--- a/pkg/front_end/testcases/weak.status
+++ b/pkg/front_end/testcases/weak.status
@@ -22,6 +22,7 @@
 
 constructor_tearoffs/call_instantiation: TypeCheckError
 constructor_tearoffs/lowering/invalid_redirect: VerificationError
+enhanced_enums/simple_mixins: RuntimeError
 extension_types/access_setter_as_getter: ExpectationFileMismatchSerialized # Expected.
 extension_types/call_not_get: ExpectationFileMismatchSerialized # Expected.
 extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.