[cfe] Perform inference on enum elements as on other fields

The type inference on enum elements was performed at the outline
expression building phase, which is later than the inference on the
rest of the members. It prevents some type checks from being performed
correctly, for example, a check for the type of the getter induced by
the element and a declared static setter. This CL moves the inference
on enum elements to the same phase as for the rest of the class and
enum members.

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

Change-Id: Iefc5606e6db07df8cd2de101c47d115c2ff8454a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/236000
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
index 792c92f..c0d8fed 100644
--- a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
@@ -5,6 +5,7 @@
 library fasta.implicit_type;
 
 import 'package:_fe_analyzer_shared/src/scanner/token.dart' show Token;
+import 'package:front_end/src/fasta/source/source_enum_builder.dart';
 import 'package:kernel/ast.dart';
 import 'package:kernel/src/assumptions.dart';
 import 'package:kernel/src/legacy_erasure.dart';
@@ -13,6 +14,7 @@
 import '../constant_context.dart';
 import '../fasta_codes.dart';
 import '../problems.dart' show unsupported;
+import '../builder/builder.dart';
 import '../source/source_field_builder.dart';
 import '../type_inference/type_inferrer.dart';
 import '../type_inference/type_schema.dart';
@@ -115,6 +117,7 @@
     }
     isStarted = true;
     DartType? inferredType;
+    Builder? parent = fieldBuilder.parent;
     if (_overriddenFields != null) {
       for (ImplicitFieldType overridden in _overriddenFields!) {
         DartType overriddenType = overridden.inferType();
@@ -128,6 +131,10 @@
         }
       }
       return inferredType!;
+    } else if (parent is SourceEnumBuilder &&
+        parent.elementBuilders.contains(fieldBuilder)) {
+      inferredType = parent.buildElement(
+          parent.library, fieldBuilder, parent.library.loader.coreTypes);
     } else if (initializerToken != null) {
       InterfaceType? enclosingClassThisType = fieldBuilder.classBuilder == null
           ? 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 a177232..0d215bd 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
@@ -8,12 +8,12 @@
 
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart';
+import 'package:kernel/core_types.dart';
 import 'package:kernel/reference_from_index.dart' show IndexedClass;
 
 import '../builder/builder.dart';
 import '../builder/class_builder.dart';
 import '../builder/constructor_reference_builder.dart';
-import '../builder/field_builder.dart';
 import '../builder/formal_parameter_builder.dart';
 import '../builder/library_builder.dart';
 import '../builder/member_builder.dart';
@@ -43,6 +43,7 @@
 import '../kernel/constructor_tearoff_lowering.dart';
 import '../kernel/expression_generator_helper.dart';
 import '../kernel/kernel_helper.dart';
+import '../kernel/implicit_field_type.dart';
 import '../kernel/internal_ast.dart';
 
 import '../modifier.dart' show constMask, hasInitializerMask, staticMask;
@@ -70,8 +71,17 @@
 
   final NamedTypeBuilder listType;
 
+  final NamedTypeBuilder selfType;
+
   DeclaredSourceConstructorBuilder? synthesizedDefaultConstructorBuilder;
 
+  final List<SourceFieldBuilder> elementBuilders;
+
+  final Set<SourceFieldBuilder> _builtElements =
+      new Set<SourceFieldBuilder>.identity();
+
+  final List<DelayedActionPerformer> _delayedActionPerformers = [];
+
   SourceEnumBuilder.internal(
       List<MetadataBuilder>? metadata,
       String name,
@@ -81,11 +91,13 @@
       Scope scope,
       ConstructorScope constructors,
       Class cls,
+      this.elementBuilders,
       this.enumConstantInfos,
       this.intType,
       this.listType,
       this.objectType,
       this.stringType,
+      this.selfType,
       SourceLibraryBuilder parent,
       List<ConstructorReferenceBuilder> constructorReferences,
       int startCharOffset,
@@ -178,6 +190,7 @@
     Map<String, MemberBuilder> members = <String, MemberBuilder>{};
     Map<String, MemberBuilder> setters = <String, MemberBuilder>{};
     Map<String, MemberBuilder> constructors = <String, MemberBuilder>{};
+    List<SourceFieldBuilder> elementBuilders = <SourceFieldBuilder>[];
     NamedTypeBuilder selfType = new NamedTypeBuilder(
         name,
         const NullabilityBuilder.omitted(),
@@ -418,9 +431,9 @@
           setterReference =
               referencesFromIndexed.lookupSetterReference(nameName);
         }
-        FieldBuilder fieldBuilder = new SourceFieldBuilder(
+        SourceFieldBuilder fieldBuilder = new SourceFieldBuilder(
             metadata,
-            selfType,
+            null,
             name,
             constMask | staticMask | hasInitializerMask,
             /* isTopLevel = */ false,
@@ -431,7 +444,11 @@
             fieldReference: fieldReference,
             fieldGetterReference: getterReference,
             fieldSetterReference: setterReference);
+        fieldBuilder.fieldType = new ImplicitFieldType(
+            fieldBuilder, enumConstantInfo.argumentsBeginToken);
+        parent.registerImplicitlyTypedField(fieldBuilder);
         members[name] = fieldBuilder..next = existing;
+        elementBuilders.add(fieldBuilder);
       }
     }
 
@@ -449,11 +466,13 @@
             isModifiable: false),
         constructorScope..local.addAll(constructors),
         cls,
+        elementBuilders,
         enumConstantInfos,
         intType,
         listType,
         objectType,
         stringType,
+        selfType,
         parent,
         constructorReferences,
         startCharOffsetComputed,
@@ -579,6 +598,143 @@
     return super.build(libraryBuilder, coreLibrary);
   }
 
+  DartType buildElement(SourceLibraryBuilder libraryBuilder,
+      SourceFieldBuilder fieldBuilder, CoreTypes coreTypes) {
+    DartType selfType = this.selfType.build(libraryBuilder);
+    Builder? builder = firstMemberNamed(fieldBuilder.name);
+    if (builder == null || !builder.isField) return selfType;
+    fieldBuilder = builder as SourceFieldBuilder;
+    if (!_builtElements.add(fieldBuilder)) return fieldBuilder.fieldType;
+
+    if (enumConstantInfos == null) return selfType;
+
+    String constant = fieldBuilder.name;
+
+    EnumConstantInfo? enumConstantInfo;
+    int elementIndex = 0;
+    for (EnumConstantInfo? info in enumConstantInfos!) {
+      if (info?.name == constant) {
+        enumConstantInfo = info;
+        break;
+      }
+      // Skip the duplicated entries in numbering.
+      if (info?.name != null) {
+        elementIndex++;
+      }
+    }
+    if (enumConstantInfo == null) return selfType;
+
+    DartType inferredFieldType = selfType;
+
+    String constructorName =
+        enumConstantInfo.constructorReferenceBuilder?.suffix ?? "";
+    String fullConstructorNameForErrors =
+        enumConstantInfo.constructorReferenceBuilder?.fullNameForErrors ?? name;
+    int fileOffset = enumConstantInfo.constructorReferenceBuilder?.charOffset ??
+        enumConstantInfo.charOffset;
+    MemberBuilder? constructorBuilder =
+        constructorScope.lookupLocalMember(constructorName);
+
+    ArgumentsImpl arguments;
+    List<Expression> enumSyntheticArguments = <Expression>[
+      new IntLiteral(elementIndex),
+      new StringLiteral(constant),
+    ];
+    List<DartType>? typeArguments;
+    List<TypeBuilder>? typeArgumentBuilders =
+        enumConstantInfo.constructorReferenceBuilder?.typeArguments;
+    if (typeArgumentBuilders != null) {
+      typeArguments = <DartType>[];
+      for (TypeBuilder typeBuilder in typeArgumentBuilders) {
+        typeArguments.add(typeBuilder.build(library));
+      }
+    }
+    if (libraryBuilder.enableEnhancedEnumsInLibrary) {
+      // We need to create a BodyBuilder to solve the following: 1) if
+      // the arguments token is provided, we'll use the BodyBuilder to
+      // parse them and perform inference, 2) if the type arguments
+      // aren't provided, but required, we'll use it to infer them, and
+      // 3) in case of erroneous code the constructor invocation should
+      // be built via a body builder to detect potential errors.
+      BodyBuilder bodyBuilder = library.loader
+          .createBodyBuilderForOutlineExpression(
+              library, this, this, scope, fileUri);
+      bodyBuilder.constantContext = ConstantContext.inferred;
+
+      if (enumConstantInfo.argumentsBeginToken != null) {
+        arguments =
+            bodyBuilder.parseArguments(enumConstantInfo.argumentsBeginToken!);
+        bodyBuilder.performBacklogComputations(_delayedActionPerformers);
+
+        arguments.positional.insertAll(0, enumSyntheticArguments);
+        arguments.argumentsOriginalOrder?.insertAll(0, enumSyntheticArguments);
+      } else {
+        arguments = new ArgumentsImpl(enumSyntheticArguments);
+      }
+      if (typeArguments != null) {
+        ArgumentsImpl.setNonInferrableArgumentTypes(arguments, typeArguments);
+      } else if (cls.typeParameters.isNotEmpty) {
+        arguments.types.addAll(new List<DartType>.filled(
+            cls.typeParameters.length, const UnknownType()));
+      }
+      setParents(enumSyntheticArguments, arguments);
+      if (constructorBuilder == null ||
+          constructorBuilder is! SourceConstructorBuilder) {
+        if (!fieldBuilder.hasBodyBeenBuilt) {
+          fieldBuilder.buildBody(
+              coreTypes,
+              bodyBuilder.buildUnresolvedError(new NullLiteral(),
+                  fullConstructorNameForErrors, arguments, fileOffset,
+                  kind: UnresolvedKind.Constructor));
+        }
+      } else {
+        Expression initializer = bodyBuilder.buildStaticInvocation(
+            constructorBuilder.constructor, arguments,
+            constness: Constness.explicitConst,
+            charOffset: fieldBuilder.charOffset);
+        ExpressionInferenceResult inferenceResult = bodyBuilder.typeInferrer
+            .inferFieldInitializer(
+                bodyBuilder, const UnknownType(), initializer);
+        initializer = inferenceResult.expression;
+        inferredFieldType = inferenceResult.inferredType;
+        if (!fieldBuilder.hasBodyBeenBuilt) {
+          fieldBuilder.buildBody(coreTypes, initializer);
+        }
+      }
+    } else {
+      arguments = new ArgumentsImpl(enumSyntheticArguments);
+      setParents(enumSyntheticArguments, arguments);
+      if (constructorBuilder == null ||
+          constructorBuilder is! SourceConstructorBuilder ||
+          !constructorBuilder.isConst) {
+        // This can only occur if there enhanced enum features are used
+        // when they are not enabled.
+        assert(libraryBuilder.loader.hasSeenError);
+        String text = libraryBuilder.loader.target.context
+            .format(
+                templateConstructorNotFound
+                    .withArguments(fullConstructorNameForErrors)
+                    .withLocation(fieldBuilder.fileUri, fileOffset, noLength),
+                Severity.error)
+            .plain;
+        if (!fieldBuilder.hasBodyBeenBuilt) {
+          fieldBuilder.buildBody(
+              coreTypes, new InvalidExpression(text)..fileOffset = charOffset);
+        }
+      } else {
+        Expression initializer = new ConstructorInvocation(
+            constructorBuilder.constructor, arguments,
+            isConst: true)
+          ..fileOffset = fieldBuilder.charOffset;
+        if (!fieldBuilder.hasBodyBeenBuilt) {
+          fieldBuilder.buildBody(coreTypes, initializer);
+        }
+      }
+    }
+
+    return inferredFieldType;
+  }
+
   @override
   void buildOutlineExpressions(
       SourceLibraryBuilder libraryBuilder,
@@ -604,123 +760,13 @@
         classHierarchy.coreTypes,
         new ListLiteral(values,
             typeArgument: rawType(library.nonNullable), isConst: true));
-    int index = 0;
-    if (enumConstantInfos != null) {
-      for (EnumConstantInfo? enumConstantInfo in enumConstantInfos!) {
-        if (enumConstantInfo != null) {
-          String constant = enumConstantInfo.name;
-          Builder declaration = firstMemberNamed(constant)!;
-          SourceFieldBuilder field;
-          if (declaration.isField) {
-            field = declaration as SourceFieldBuilder;
-          } else {
-            continue;
-          }
 
-          String constructorName =
-              enumConstantInfo.constructorReferenceBuilder?.suffix ?? "";
-          String fullConstructorNameForErrors =
-              enumConstantInfo.constructorReferenceBuilder?.fullNameForErrors ??
-                  name;
-          int fileOffset =
-              enumConstantInfo.constructorReferenceBuilder?.charOffset ??
-                  enumConstantInfo.charOffset;
-          MemberBuilder? constructorBuilder =
-              constructorScope.lookupLocalMember(constructorName);
-
-          ArgumentsImpl arguments;
-          List<Expression> enumSyntheticArguments = <Expression>[
-            new IntLiteral(index++),
-            new StringLiteral(constant),
-          ];
-          List<DartType>? typeArguments;
-          List<TypeBuilder>? typeArgumentBuilders =
-              enumConstantInfo.constructorReferenceBuilder?.typeArguments;
-          if (typeArgumentBuilders != null) {
-            typeArguments = <DartType>[];
-            for (TypeBuilder typeBuilder in typeArgumentBuilders) {
-              typeArguments.add(typeBuilder.build(library));
-            }
-          }
-          if (libraryBuilder.enableEnhancedEnumsInLibrary) {
-            // We need to create a BodyBuilder to solve the following: 1) if
-            // the arguments token is provided, we'll use the BodyBuilder to
-            // parse them and perform inference, 2) if the type arguments
-            // aren't provided, but required, we'll use it to infer them, and
-            // 3) in case of erroneous code the constructor invocation should
-            // be built via a body builder to detect potential errors.
-            BodyBuilder bodyBuilder = library.loader
-                .createBodyBuilderForOutlineExpression(
-                    library, this, this, scope, fileUri);
-            bodyBuilder.constantContext = ConstantContext.inferred;
-
-            if (enumConstantInfo.argumentsBeginToken != null) {
-              arguments = bodyBuilder
-                  .parseArguments(enumConstantInfo.argumentsBeginToken!);
-              bodyBuilder.performBacklogComputations(delayedActionPerformers);
-
-              arguments.positional.insertAll(0, enumSyntheticArguments);
-              arguments.argumentsOriginalOrder
-                  ?.insertAll(0, enumSyntheticArguments);
-            } else {
-              arguments = new ArgumentsImpl(enumSyntheticArguments);
-            }
-            if (typeArguments != null) {
-              ArgumentsImpl.setNonInferrableArgumentTypes(
-                  arguments, typeArguments);
-            } else if (cls.typeParameters.isNotEmpty) {
-              arguments.types.addAll(new List<DartType>.filled(
-                  cls.typeParameters.length, const UnknownType()));
-            }
-            setParents(enumSyntheticArguments, arguments);
-            if (constructorBuilder == null ||
-                constructorBuilder is! SourceConstructorBuilder) {
-              field.buildBody(
-                  classHierarchy.coreTypes,
-                  bodyBuilder.buildUnresolvedError(new NullLiteral(),
-                      fullConstructorNameForErrors, arguments, fileOffset,
-                      kind: UnresolvedKind.Constructor));
-            } else {
-              Expression initializer = bodyBuilder.buildStaticInvocation(
-                  constructorBuilder.constructor, arguments,
-                  constness: Constness.explicitConst,
-                  charOffset: field.charOffset);
-              ExpressionInferenceResult inferenceResult =
-                  bodyBuilder.typeInferrer.inferFieldInitializer(
-                      bodyBuilder, const UnknownType(), initializer);
-              initializer = inferenceResult.expression;
-              field.fieldType = inferenceResult.inferredType;
-              field.buildBody(classHierarchy.coreTypes, initializer);
-            }
-          } else {
-            arguments = new ArgumentsImpl(enumSyntheticArguments);
-            setParents(enumSyntheticArguments, arguments);
-            if (constructorBuilder == null ||
-                constructorBuilder is! SourceConstructorBuilder ||
-                !constructorBuilder.isConst) {
-              // This can only occur if there enhanced enum features are used
-              // when they are not enabled.
-              assert(libraryBuilder.loader.hasSeenError);
-              String text = libraryBuilder.loader.target.context
-                  .format(
-                      templateConstructorNotFound
-                          .withArguments(fullConstructorNameForErrors)
-                          .withLocation(field.fileUri, fileOffset, noLength),
-                      Severity.error)
-                  .plain;
-              field.buildBody(classHierarchy.coreTypes,
-                  new InvalidExpression(text)..fileOffset = charOffset);
-            } else {
-              Expression initializer = new ConstructorInvocation(
-                  constructorBuilder.constructor, arguments,
-                  isConst: true)
-                ..fileOffset = field.charOffset;
-              field.buildBody(classHierarchy.coreTypes, initializer);
-            }
-          }
-        }
-      }
+    for (SourceFieldBuilder elementBuilder in elementBuilders) {
+      elementBuilder.fieldType = buildElement(
+          libraryBuilder, elementBuilder, classHierarchy.coreTypes);
     }
+    delayedActionPerformers.addAll(_delayedActionPerformers);
+    _delayedActionPerformers.clear();
 
     SourceProcedureBuilder toStringBuilder =
         firstMemberNamed("toString") as SourceProcedureBuilder;
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index e442d51..6928e1f 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -2022,6 +2022,7 @@
 nullable
 num
 number
+numbering
 numbers
 numeric
 object
diff --git a/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart
new file mode 100644
index 0000000..5ab89b1
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart
@@ -0,0 +1,13 @@
+// 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.
+
+enum E<T> {
+  element<int>(),
+  element2<int>();
+
+  static void set element(E<int> val) {} // Ok.
+  static void set element2(E<String> val) {} // Error.
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.strong.expect b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.strong.expect
new file mode 100644
index 0000000..e34c005
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.strong.expect
@@ -0,0 +1,45 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart:7:3: Error: The type 'E<int>' of the getter 'E.element2' is not a subtype of the type 'E<String>' of the setter 'E.element2'.
+//  - 'E' is from 'pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart'.
+//   element2<int>();
+//   ^^^^^^^^
+// pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart:10:19: Context: This is the declaration of the setter 'E.element2'.
+//   static void set element2(E<String> val) {} // Error.
+//                   ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class E<T extends core::Object? = dynamic> extends core::_Enum /*isEnum*/  {
+  static const field core::List<self::E<dynamic>> values = #C7;
+  static const field self::E<core::int> element = #C3;
+  static const field self::E<core::int> element2 = #C6;
+  const constructor •(core::int index, core::String name) → self::E<self::E::T%>
+    : super core::_Enum::•(index, name)
+    ;
+  method toString() → core::String
+    return "E.${this.{core::_Enum::_name}{core::String}}";
+  static set element(self::E<core::int> val) → void {}
+  static set element2(self::E<core::String> val) → void {}
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = 0
+  #C2 = "element"
+  #C3 = self::E<core::int> {index:#C1, _name:#C2}
+  #C4 = 1
+  #C5 = "element2"
+  #C6 = self::E<core::int> {index:#C4, _name:#C5}
+  #C7 = <self::E<dynamic>>[#C3, #C6]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///setter_getter_type_check.dart:
+- E. (from org-dartlang-testcase:///setter_getter_type_check.dart:5:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.strong.transformed.expect b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.strong.transformed.expect
new file mode 100644
index 0000000..e34c005
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.strong.transformed.expect
@@ -0,0 +1,45 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart:7:3: Error: The type 'E<int>' of the getter 'E.element2' is not a subtype of the type 'E<String>' of the setter 'E.element2'.
+//  - 'E' is from 'pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart'.
+//   element2<int>();
+//   ^^^^^^^^
+// pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart:10:19: Context: This is the declaration of the setter 'E.element2'.
+//   static void set element2(E<String> val) {} // Error.
+//                   ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class E<T extends core::Object? = dynamic> extends core::_Enum /*isEnum*/  {
+  static const field core::List<self::E<dynamic>> values = #C7;
+  static const field self::E<core::int> element = #C3;
+  static const field self::E<core::int> element2 = #C6;
+  const constructor •(core::int index, core::String name) → self::E<self::E::T%>
+    : super core::_Enum::•(index, name)
+    ;
+  method toString() → core::String
+    return "E.${this.{core::_Enum::_name}{core::String}}";
+  static set element(self::E<core::int> val) → void {}
+  static set element2(self::E<core::String> val) → void {}
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = 0
+  #C2 = "element"
+  #C3 = self::E<core::int> {index:#C1, _name:#C2}
+  #C4 = 1
+  #C5 = "element2"
+  #C6 = self::E<core::int> {index:#C4, _name:#C5}
+  #C7 = <self::E<dynamic>>[#C3, #C6]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///setter_getter_type_check.dart:
+- E. (from org-dartlang-testcase:///setter_getter_type_check.dart:5:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.textual_outline.expect b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.textual_outline.expect
new file mode 100644
index 0000000..43a8af8
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.textual_outline.expect
@@ -0,0 +1,9 @@
+enum E<T> {
+  element<int>(),
+  element2<int>();
+
+  static void set element(E<int> val) {}
+  static void set element2(E<String> val) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..43a8af8
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.textual_outline_modelled.expect
@@ -0,0 +1,9 @@
+enum E<T> {
+  element<int>(),
+  element2<int>();
+
+  static void set element(E<int> val) {}
+  static void set element2(E<String> val) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.weak.expect b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.weak.expect
new file mode 100644
index 0000000..117fd4f
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.weak.expect
@@ -0,0 +1,45 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart:7:3: Error: The type 'E<int>' of the getter 'E.element2' is not a subtype of the type 'E<String>' of the setter 'E.element2'.
+//  - 'E' is from 'pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart'.
+//   element2<int>();
+//   ^^^^^^^^
+// pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart:10:19: Context: This is the declaration of the setter 'E.element2'.
+//   static void set element2(E<String> val) {} // Error.
+//                   ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class E<T extends core::Object? = dynamic> extends core::_Enum /*isEnum*/  {
+  static const field core::List<self::E<dynamic>> values = #C7;
+  static const field self::E<core::int> element = #C3;
+  static const field self::E<core::int> element2 = #C6;
+  const constructor •(core::int index, core::String name) → self::E<self::E::T%>
+    : super core::_Enum::•(index, name)
+    ;
+  method toString() → core::String
+    return "E.${this.{core::_Enum::_name}{core::String}}";
+  static set element(self::E<core::int> val) → void {}
+  static set element2(self::E<core::String> val) → void {}
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = 0
+  #C2 = "element"
+  #C3 = self::E<core::int*> {index:#C1, _name:#C2}
+  #C4 = 1
+  #C5 = "element2"
+  #C6 = self::E<core::int*> {index:#C4, _name:#C5}
+  #C7 = <self::E<dynamic>*>[#C3, #C6]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///setter_getter_type_check.dart:
+- E. (from org-dartlang-testcase:///setter_getter_type_check.dart:5:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.weak.modular.expect b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.weak.modular.expect
new file mode 100644
index 0000000..117fd4f
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.weak.modular.expect
@@ -0,0 +1,45 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart:7:3: Error: The type 'E<int>' of the getter 'E.element2' is not a subtype of the type 'E<String>' of the setter 'E.element2'.
+//  - 'E' is from 'pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart'.
+//   element2<int>();
+//   ^^^^^^^^
+// pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart:10:19: Context: This is the declaration of the setter 'E.element2'.
+//   static void set element2(E<String> val) {} // Error.
+//                   ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class E<T extends core::Object? = dynamic> extends core::_Enum /*isEnum*/  {
+  static const field core::List<self::E<dynamic>> values = #C7;
+  static const field self::E<core::int> element = #C3;
+  static const field self::E<core::int> element2 = #C6;
+  const constructor •(core::int index, core::String name) → self::E<self::E::T%>
+    : super core::_Enum::•(index, name)
+    ;
+  method toString() → core::String
+    return "E.${this.{core::_Enum::_name}{core::String}}";
+  static set element(self::E<core::int> val) → void {}
+  static set element2(self::E<core::String> val) → void {}
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = 0
+  #C2 = "element"
+  #C3 = self::E<core::int*> {index:#C1, _name:#C2}
+  #C4 = 1
+  #C5 = "element2"
+  #C6 = self::E<core::int*> {index:#C4, _name:#C5}
+  #C7 = <self::E<dynamic>*>[#C3, #C6]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///setter_getter_type_check.dart:
+- E. (from org-dartlang-testcase:///setter_getter_type_check.dart:5:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.weak.outline.expect b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.weak.outline.expect
new file mode 100644
index 0000000..adc5a7d
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.weak.outline.expect
@@ -0,0 +1,38 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart:7:3: Error: The type 'E<int>' of the getter 'E.element2' is not a subtype of the type 'E<String>' of the setter 'E.element2'.
+//  - 'E' is from 'pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart'.
+//   element2<int>();
+//   ^^^^^^^^
+// pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart:10:19: Context: This is the declaration of the setter 'E.element2'.
+//   static void set element2(E<String> val) {} // Error.
+//                   ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class E<T extends core::Object? = dynamic> extends core::_Enum /*isEnum*/  {
+  static const field core::List<self::E<dynamic>> values = const <self::E<dynamic>>[self::E::element, self::E::element2];
+  static const field self::E<core::int> element = const self::E::•<core::int>(0, "element");
+  static const field self::E<core::int> element2 = const self::E::•<core::int>(1, "element2");
+  const constructor •(core::int index, core::String name) → self::E<self::E::T%>
+    : super core::_Enum::•(index, name)
+    ;
+  method toString() → core::String
+    return "E.${this.{core::_Enum::_name}{core::String}}";
+  static set element(self::E<core::int> val) → void
+    ;
+  static set element2(self::E<core::String> val) → void
+    ;
+}
+static method main() → dynamic
+  ;
+
+
+Extra constant evaluation status:
+Evaluated: ListLiteral @ org-dartlang-testcase:///setter_getter_type_check.dart:5:6 -> ListConstant(const <E<dynamic>*>[const E<int*>{_Enum.index: 0, _Enum._name: "element"}, const E<int*>{_Enum.index: 1, _Enum._name: "element2"}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///setter_getter_type_check.dart:6:3 -> InstanceConstant(const E<int*>{_Enum.index: 0, _Enum._name: "element"})
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///setter_getter_type_check.dart:7:3 -> InstanceConstant(const E<int*>{_Enum.index: 1, _Enum._name: "element2"})
+Extra constant evaluation: evaluated: 8, effectively constant: 3
diff --git a/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.weak.transformed.expect b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.weak.transformed.expect
new file mode 100644
index 0000000..117fd4f
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart.weak.transformed.expect
@@ -0,0 +1,45 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart:7:3: Error: The type 'E<int>' of the getter 'E.element2' is not a subtype of the type 'E<String>' of the setter 'E.element2'.
+//  - 'E' is from 'pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart'.
+//   element2<int>();
+//   ^^^^^^^^
+// pkg/front_end/testcases/enhanced_enums/setter_getter_type_check.dart:10:19: Context: This is the declaration of the setter 'E.element2'.
+//   static void set element2(E<String> val) {} // Error.
+//                   ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class E<T extends core::Object? = dynamic> extends core::_Enum /*isEnum*/  {
+  static const field core::List<self::E<dynamic>> values = #C7;
+  static const field self::E<core::int> element = #C3;
+  static const field self::E<core::int> element2 = #C6;
+  const constructor •(core::int index, core::String name) → self::E<self::E::T%>
+    : super core::_Enum::•(index, name)
+    ;
+  method toString() → core::String
+    return "E.${this.{core::_Enum::_name}{core::String}}";
+  static set element(self::E<core::int> val) → void {}
+  static set element2(self::E<core::String> val) → void {}
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = 0
+  #C2 = "element"
+  #C3 = self::E<core::int*> {index:#C1, _name:#C2}
+  #C4 = 1
+  #C5 = "element2"
+  #C6 = self::E<core::int*> {index:#C4, _name:#C5}
+  #C7 = <self::E<dynamic>*>[#C3, #C6]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///setter_getter_type_check.dart:
+- E. (from org-dartlang-testcase:///setter_getter_type_check.dart:5:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)