[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.