Version 2.17.0-149.0.dev

Merge commit 'e6ff207cf82aedbfeaa4e29df7ede0d1a55cbebd' into 'dev'
diff --git a/DEPS b/DEPS
index 2c99002..7e3aaea 100644
--- a/DEPS
+++ b/DEPS
@@ -93,7 +93,7 @@
   "collection_rev": "a4c941ab94044d118b2086a3f261c30377604127",
   "convert_rev": "e063fdca4bebffecbb5e6aa5525995120982d9ce",
   "crypto_rev": "b5024e4de2b1c474dd558bef593ddbf0bfade152",
-  "csslib_rev": "f746368a0a53cf8f68fd71b218239034e88841d5",
+  "csslib_rev": "518761b166974537f334dbf264e7f56cb157a96a",
 
   # Note: Updates to dart_style have to be coordinated with the infrastructure
   # team so that the internal formatter `tools/sdks/dart-sdk/bin/dart format`
@@ -109,7 +109,7 @@
   # For more details, see https://github.com/dart-lang/sdk/issues/30164
   "dart_style_rev": "6f894c0ca33686122be9085f06e5b9bf6ad55262",
 
-  "dartdoc_rev" : "b3927dd89d6ff9c78dc88ab2901e63b6a3bf29b7",
+  "dartdoc_rev" : "a39f378f8100b907e6285ac825967d764fd664ad",
   "devtools_rev" : "b9f2039239cc72ac8b26f8a5fe46123f34d53ce1",
   "ffi_rev": "4dd32429880a57b64edaf54c9d5af8a9fa9a4ffb",
   "fixnum_rev": "848341f061359ef7ddc0cad472c2ecbb036b28ac",
diff --git a/pkg/analysis_server/lib/src/computer/computer_overrides.dart b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
index 92f68d0..41e8088 100644
--- a/pkg/analysis_server/lib/src/computer/computer_overrides.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
@@ -27,23 +27,9 @@
   List<proto.Override> compute() {
     for (var unitMember in _unit.declarations) {
       if (unitMember is ClassOrMixinDeclaration) {
-        for (var classMember in unitMember.members) {
-          if (classMember is MethodDeclaration) {
-            if (classMember.isStatic) {
-              continue;
-            }
-            _addOverride(classMember.name);
-          }
-          if (classMember is FieldDeclaration) {
-            if (classMember.isStatic) {
-              continue;
-            }
-            List<VariableDeclaration> fields = classMember.fields.variables;
-            for (var field in fields) {
-              _addOverride(field.name);
-            }
-          }
-        }
+        _classMembers(unitMember.members);
+      } else if (unitMember is EnumDeclaration) {
+        _classMembers(unitMember.members);
       }
     }
     return _overrides;
@@ -73,6 +59,26 @@
       }
     }
   }
+
+  void _classMembers(List<ClassMember> members) {
+    for (var classMember in members) {
+      if (classMember is MethodDeclaration) {
+        if (classMember.isStatic) {
+          continue;
+        }
+        _addOverride(classMember.name);
+      }
+      if (classMember is FieldDeclaration) {
+        if (classMember.isStatic) {
+          continue;
+        }
+        List<VariableDeclaration> fields = classMember.fields.variables;
+        for (var field in fields) {
+          _addOverride(field.name);
+        }
+      }
+    }
+  }
 }
 
 /// The container with elements that a class member overrides.
@@ -92,26 +98,6 @@
 }
 
 class _OverriddenElementsFinder {
-  static const List<ElementKind> FIELD_KINDS = <ElementKind>[
-    ElementKind.FIELD,
-    ElementKind.GETTER,
-    ElementKind.SETTER
-  ];
-
-  static const List<ElementKind> GETTER_KINDS = <ElementKind>[
-    ElementKind.FIELD,
-    ElementKind.GETTER
-  ];
-
-  static const List<ElementKind> METHOD_KINDS = <ElementKind>[
-    ElementKind.METHOD
-  ];
-
-  static const List<ElementKind> SETTER_KINDS = <ElementKind>[
-    ElementKind.FIELD,
-    ElementKind.SETTER
-  ];
-
   Element _seed;
   LibraryElement _library;
   ClassElement _class;
@@ -127,12 +113,19 @@
     var library = class_.library;
     var name = seed.displayName;
     List<ElementKind> kinds;
-    if (seed is MethodElement) {
-      kinds = METHOD_KINDS;
+    if (seed is FieldElement) {
+      kinds = [
+        ElementKind.GETTER,
+        if (!seed.isFinal) ElementKind.SETTER,
+      ];
+    } else if (seed is MethodElement) {
+      kinds = const [ElementKind.METHOD];
     } else if (seed is PropertyAccessorElement) {
-      kinds = seed.isGetter ? GETTER_KINDS : SETTER_KINDS;
+      kinds = seed.isGetter
+          ? const [ElementKind.GETTER]
+          : const [ElementKind.SETTER];
     } else {
-      kinds = FIELD_KINDS;
+      kinds = const [];
     }
     return _OverriddenElementsFinder._(seed, library, class_, name, kinds);
   }
diff --git a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
index 4e42510..01507f9 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
@@ -18,10 +18,13 @@
   ImplementedComputer(this.searchEngine, this.unitElement);
 
   Future<void> compute() async {
-    for (var element in unitElement.mixins) {
+    for (var element in unitElement.classes) {
       await _computeForClassElement(element);
     }
-    for (var element in unitElement.classes) {
+    for (var element in unitElement.enums) {
+      await _computeForClassElement(element);
+    }
+    for (var element in unitElement.mixins) {
       await _computeForClassElement(element);
     }
   }
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/remove_leading_underscore.dart b/pkg/analysis_server/lib/src/services/correction/dart/remove_leading_underscore.dart
new file mode 100644
index 0000000..75e7dd0a
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/remove_leading_underscore.dart
@@ -0,0 +1,79 @@
+// 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.
+
+import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/correction/util.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:analyzer_plugin/utilities/range_factory.dart';
+
+class RemoveLeadingUnderscore extends CorrectionProducer {
+  @override
+  bool get canBeAppliedInBulk => true;
+
+  @override
+  bool get canBeAppliedToFile => true;
+
+  @override
+  FixKind get fixKind => DartFixKind.REMOVE_LEADING_UNDERSCORE;
+
+  @override
+  FixKind get multiFixKind => DartFixKind.REMOVE_LEADING_UNDERSCORE_MULTI;
+
+  @override
+  Future<void> compute(ChangeBuilder builder) async {
+    var identifier = node;
+    if (identifier is! SimpleIdentifier) {
+      return;
+    }
+
+    var name = identifier.name;
+    if (name.length < 2) {
+      return;
+    }
+
+    var newName = name.substring(1);
+
+    // Find references to the identifier.
+    List<SimpleIdentifier>? references;
+    var element = identifier.staticElement;
+    if (element is LocalVariableElement) {
+      var root = node.thisOrAncestorOfType<Block>();
+      if (root != null) {
+        references = findLocalElementReferences(root, element);
+      }
+    } else if (element is ParameterElement) {
+      if (!element.isNamed) {
+        print(node.parent.runtimeType);
+        print(node.parent?.parent.runtimeType);
+        print(node.parent?.parent?.parent.runtimeType);
+        var root = node
+            .thisOrAncestorMatching((node) =>
+                node.parent is FunctionDeclaration ||
+                node.parent is MethodDeclaration)
+            ?.parent;
+        if (root != null) {
+          references = findLocalElementReferences(root, element);
+        }
+      }
+    }
+    if (references == null) {
+      return;
+    }
+
+    // Compute the change.
+    var references_final = references;
+    await builder.addDartFileEdit(file, (builder) {
+      for (var reference in references_final) {
+        builder.addSimpleReplacement(range.node(reference), newName);
+      }
+    });
+  }
+
+  /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
+  static RemoveLeadingUnderscore newInstance() => RemoveLeadingUnderscore();
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 874bbdb..819a2a7 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -951,6 +951,16 @@
     DartFixKindPriority.IN_FILE,
     'Remove unnecessary interpolation braces everywhere in file',
   );
+  static const REMOVE_LEADING_UNDERSCORE = FixKind(
+    'dart.fix.remove.leadingUnderscore',
+    DartFixKindPriority.DEFAULT,
+    'Remove leading underscore',
+  );
+  static const REMOVE_LEADING_UNDERSCORE_MULTI = FixKind(
+    'dart.fix.remove.leadingUnderscore.multi',
+    DartFixKindPriority.IN_FILE,
+    'Remove leading underscores in file',
+  );
   static const REMOVE_METHOD_DECLARATION = FixKind(
     'dart.fix.remove.methodDeclaration',
     DartFixKindPriority.DEFAULT,
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 9258b2f..901695f 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -118,6 +118,7 @@
 import 'package:analysis_server/src/services/correction/dart/remove_if_null_operator.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_initializer.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_interpolation_braces.dart';
+import 'package:analysis_server/src/services/correction/dart/remove_leading_underscore.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_method_declaration.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_name_from_combinator.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_non_null_assertion.dart';
@@ -452,6 +453,9 @@
     LintNames.no_duplicate_case_values: [
       RemoveDuplicateCase.newInstance,
     ],
+    LintNames.no_leading_underscores_for_local_identifiers: [
+      RemoveLeadingUnderscore.newInstance,
+    ],
     LintNames.non_constant_identifier_names: [
       RenameToCamelCase.newInstance,
     ],
diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
index 123600d..986a5a4 100644
--- a/pkg/analysis_server/lib/src/services/linter/lint_names.dart
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -59,6 +59,8 @@
   static const String leading_newlines_in_multiline_strings =
       'leading_newlines_in_multiline_strings';
   static const String no_duplicate_case_values = 'no_duplicate_case_values';
+  static const String no_leading_underscores_for_local_identifiers =
+      'no_leading_underscores_for_local_identifiers';
   static const String non_constant_identifier_names =
       'non_constant_identifier_names';
   static const String null_closures = 'null_closures';
diff --git a/pkg/analysis_server/test/analysis/notification_implemented_test.dart b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
index c0deb4e..a9db25d 100644
--- a/pkg/analysis_server/test/analysis/notification_implemented_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
@@ -150,7 +150,7 @@
     assertHasImplementedClass('A {');
   }
 
-  Future<void> test_class_implemented() async {
+  Future<void> test_class_implementedBy_class() async {
     addTestFile('''
 class A {}
 class B implements A {}
@@ -159,7 +159,67 @@
     assertHasImplementedClass('A {');
   }
 
-  Future<void> test_class_inMixin() async {
+  Future<void> test_class_implementedBy_enum() async {
+    addTestFile('''
+class A {}
+
+enum E implements A {
+  v
+}
+''');
+    await prepareImplementedElements();
+    assertHasImplementedClass('A {');
+  }
+
+  Future<void> test_class_implementedBy_enum_getterByGetter() async {
+    addTestFile('''
+class A {
+  int get foo => 0; // A
+}
+
+enum E implements A {
+  v;
+  int get foo => 0; // E
+}
+''');
+    await prepareImplementedElements();
+    assertHasImplementedMember('foo => 0; // A');
+    assertNoImplementedMember('foo => 0; // E');
+  }
+
+  Future<void> test_class_implementedBy_enum_methodByMethod() async {
+    addTestFile('''
+class A {
+  void foo() {} // A
+}
+
+enum E implements A {
+  v;
+  void foo() {} // E
+}
+''');
+    await prepareImplementedElements();
+    assertHasImplementedMember('foo() {} // A');
+    assertNoImplementedMember('foo() {} // E');
+  }
+
+  Future<void> test_class_implementedBy_enum_setterBySetter() async {
+    addTestFile('''
+class A {
+  set foo(int _) {} // A
+}
+
+enum E implements A {
+  v;
+  set foo(int _) {} // E
+}
+''');
+    await prepareImplementedElements();
+    assertHasImplementedMember('foo(int _) {} // A');
+    assertNoImplementedMember('foo(int _) {} // E');
+  }
+
+  Future<void> test_class_implementedBy_mixin() async {
     addTestFile('''
 class A {} // ref
 class B {} // ref
@@ -174,7 +234,7 @@
     assertHasImplementedClass('D {} // ref');
   }
 
-  Future<void> test_class_mixed() async {
+  Future<void> test_class_mixedBy_class() async {
     addTestFile('''
 class A {}
 class B = Object with A;
@@ -183,6 +243,33 @@
     assertHasImplementedClass('A {');
   }
 
+  Future<void> test_class_mixedBy_enum() async {
+    addTestFile('''
+mixin M {}
+enum E with M {
+  v
+}
+''');
+    await prepareImplementedElements();
+    assertHasImplementedClass('M {}');
+  }
+
+  Future<void> test_class_mixedBy_enum_methodByMethod() async {
+    addTestFile('''
+class M {
+  void foo() {} // M
+}
+
+enum E with M {
+  v;
+  void foo() {} // E
+}
+''');
+    await prepareImplementedElements();
+    assertHasImplementedMember('foo() {} // M');
+    assertNoImplementedMember('foo() {} // E');
+  }
+
   Future<void> test_field_withField() async {
     addTestFile('''
 class A {
diff --git a/pkg/analysis_server/test/analysis/notification_overrides_test.dart b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
index bc48633..3ce1928 100644
--- a/pkg/analysis_server/test/analysis/notification_overrides_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
@@ -142,7 +142,7 @@
     assertHasInterfaceMember('m() {} // in A');
   }
 
-  Future<void> test_BAD_fieldByMethod() async {
+  Future<void> test_class_BAD_fieldByMethod() async {
     addTestFile('''
 class A {
   int fff; // in A
@@ -155,7 +155,7 @@
     assertNoOverride('fff() {} // in B');
   }
 
-  Future<void> test_BAD_getterByMethod() async {
+  Future<void> test_class_BAD_getterByMethod() async {
     addTestFile('''
 class A {
   get fff => null;
@@ -168,7 +168,7 @@
     assertNoOverride('fff() {}');
   }
 
-  Future<void> test_BAD_getterBySetter() async {
+  Future<void> test_class_BAD_getterBySetter() async {
     addTestFile('''
 class A {
   get fff => null;
@@ -181,7 +181,7 @@
     assertNoOverride('fff(x) {}');
   }
 
-  Future<void> test_BAD_methodByField() async {
+  Future<void> test_class_BAD_methodByField() async {
     addTestFile('''
 class A {
   fff() {} // in A
@@ -194,7 +194,7 @@
     assertNoOverride('fff; // in B');
   }
 
-  Future<void> test_BAD_methodByGetter() async {
+  Future<void> test_class_BAD_methodByGetter() async {
     addTestFile('''
 class A {
   fff() {}
@@ -207,7 +207,7 @@
     assertNoOverride('fff => null');
   }
 
-  Future<void> test_BAD_methodBySetter() async {
+  Future<void> test_class_BAD_methodBySetter() async {
     addTestFile('''
 class A {
   fff(x) {} // A
@@ -220,7 +220,7 @@
     assertNoOverride('fff(x) {} // B');
   }
 
-  Future<void> test_BAD_privateByPrivate_inDifferentLib() async {
+  Future<void> test_class_BAD_privateByPrivate_inDifferentLib() async {
     newFile(join(testFolder, 'lib.dart'), content: r'''
 class A {
   void _m() {}
@@ -236,7 +236,7 @@
     assertNoOverride('_m() {} // in B');
   }
 
-  Future<void> test_BAD_setterByGetter() async {
+  Future<void> test_class_BAD_setterByGetter() async {
     addTestFile('''
 class A {
   set fff(x) {}
@@ -249,7 +249,7 @@
     assertNoOverride('fff => null;');
   }
 
-  Future<void> test_BAD_setterByMethod() async {
+  Future<void> test_class_BAD_setterByMethod() async {
     addTestFile('''
 class A {
   set fff(x) {} // A
@@ -262,7 +262,7 @@
     assertNoOverride('fff(x) {} // B');
   }
 
-  Future<void> test_definedInInterface_ofInterface() async {
+  Future<void> test_class_definedInInterface_ofInterface() async {
     addTestFile('''
 class A {
   m() {} // in A
@@ -278,7 +278,7 @@
     assertHasInterfaceMember('m() {} // in A');
   }
 
-  Future<void> test_definedInInterface_ofSuper() async {
+  Future<void> test_class_definedInInterface_ofSuper() async {
     addTestFile('''
 class A {
   m() {} // in A
@@ -294,39 +294,7 @@
     assertHasInterfaceMember('m() {} // in A');
   }
 
-  Future<void> test_inMixin_interface_method_direct_single() async {
-    addTestFile('''
-class A {
-  m() {} // in A
-}
-
-mixin M implements A {
-  m() {} // in M
-}
-''');
-    await prepareOverrides();
-    assertHasOverride('m() {} // in M');
-    assertNoSuperMember();
-    assertHasInterfaceMember('m() {} // in A');
-  }
-
-  Future<void> test_inMixin_superclassConstraint_method_direct() async {
-    addTestFile('''
-class A {
-  m() {} // in A
-}
-
-mixin M on A {
-  m() {} // in M
-}
-''');
-    await prepareOverrides();
-    assertHasOverride('m() {} // in M');
-    assertHasSuperElement('m() {} // in A');
-    assertNoInterfaceMembers();
-  }
-
-  Future<void> test_interface_method_direct_multiple() async {
+  Future<void> test_class_interface_method_direct_multiple() async {
     addTestFile('''
 class IA {
   m() {} // in IA
@@ -345,7 +313,7 @@
     assertHasInterfaceMember('m() {} // in IB');
   }
 
-  Future<void> test_interface_method_direct_single() async {
+  Future<void> test_class_interface_method_direct_single() async {
     addTestFile('''
 class A {
   m() {} // in A
@@ -360,7 +328,7 @@
     assertHasInterfaceMember('m() {} // in A');
   }
 
-  Future<void> test_interface_method_indirect_single() async {
+  Future<void> test_class_interface_method_indirect_single() async {
     addTestFile('''
 class A {
   m() {} // in A
@@ -377,7 +345,7 @@
     assertHasInterfaceMember('m() {} // in A');
   }
 
-  Future<void> test_interface_stopWhenFound() async {
+  Future<void> test_class_interface_stopWhenFound() async {
     addTestFile('''
 class A {
   m() {} // in A
@@ -395,7 +363,7 @@
     assertHasInterfaceMember('m() {} // in B');
   }
 
-  Future<void> test_mix_sameMethod() async {
+  Future<void> test_class_mix_sameMethod() async {
     addTestFile('''
 class A {
   m() {} // in A
@@ -412,7 +380,7 @@
     assertNoInterfaceMembers();
   }
 
-  Future<void> test_mix_sameMethod_Object_hashCode() async {
+  Future<void> test_class_mix_sameMethod_Object_hashCode() async {
     addTestFile('''
 class A {}
 abstract class B {}
@@ -426,6 +394,536 @@
     expect(overrideObject.interfaceMembers, isNull);
   }
 
+  Future<void> test_class_staticMembers() async {
+    addTestFile('''
+class A {
+  static int F = 0;
+  static void M() {}
+  static int get G => 0;
+  static void set S(int v) {}
+}
+class B extends A {
+  static int F = 0;
+  static void M() {}
+  static int get G => 0;
+  static void set S(int v) {}
+}
+''');
+    await prepareOverrides();
+    expect(overridesList, isEmpty);
+  }
+
+  Future<void> test_class_super_fieldByField() async {
+    addTestFile('''
+class A {
+  int fff; // in A
+}
+class B extends A {
+  int fff; // in B
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('fff; // in B');
+    assertHasSuperElement('fff; // in A');
+    assertNoInterfaceMembers();
+  }
+
+  Future<void> test_class_super_fieldByGetter() async {
+    addTestFile('''
+class A {
+  int fff; // in A
+}
+class B extends A {
+  get fff => 0; // in B
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('fff => 0; // in B');
+    assertHasSuperElement('fff; // in A');
+    assertNoInterfaceMembers();
+  }
+
+  Future<void> test_class_super_fieldBySetter() async {
+    addTestFile('''
+class A {
+  int fff; // in A
+}
+class B extends A {
+  set fff(x) {} // in B
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('fff(x) {} // in B');
+    assertHasSuperElement('fff; // in A');
+    assertNoInterfaceMembers();
+  }
+
+  Future<void> test_class_super_getterByField() async {
+    addTestFile('''
+class A {
+  get fff => 0; // in A
+  set fff(x) {} // in A
+}
+class B extends A {
+  int fff; // in B
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('fff; // in B');
+    assertHasSuperElement('fff => 0; // in A');
+    assertNoInterfaceMembers();
+  }
+
+  Future<void> test_class_super_getterByGetter() async {
+    addTestFile('''
+class A {
+  get fff => 0; // in A
+}
+class B extends A {
+  get fff => 0; // in B
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('fff => 0; // in B');
+    assertHasSuperElement('fff => 0; // in A');
+    assertNoInterfaceMembers();
+  }
+
+  Future<void> test_class_super_method_direct() async {
+    addTestFile('''
+class A {
+  m() {} // in A
+}
+class B extends A {
+  m() {} // in B
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('m() {} // in B');
+    assertHasSuperElement('m() {} // in A');
+    assertNoInterfaceMembers();
+  }
+
+  Future<void> test_class_super_method_indirect() async {
+    addTestFile('''
+class A {
+  m() {} // in A
+}
+class B extends A {
+}
+class C extends B {
+  m() {} // in C
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('m() {} // in C');
+    assertHasSuperElement('m() {} // in A');
+    assertNoInterfaceMembers();
+  }
+
+  Future<void> test_class_super_method_privateByPrivate() async {
+    addTestFile('''
+class A {
+  _m() {} // in A
+}
+class B extends A {
+  _m() {} // in B
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('_m() {} // in B');
+    assertHasSuperElement('_m() {} // in A');
+    assertNoInterfaceMembers();
+  }
+
+  Future<void> test_class_super_method_superTypeCycle() async {
+    addTestFile('''
+class A extends B {
+  m() {} // in A
+}
+class B extends A {
+  m() {} // in B
+}
+''');
+    await prepareOverrides();
+    // must finish
+  }
+
+  Future<void> test_class_super_setterBySetter() async {
+    addTestFile('''
+class A {
+  set fff(x) {} // in A
+}
+class B extends A {
+  set fff(x) {} // in B
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('fff(x) {} // in B');
+    assertHasSuperElement('fff(x) {} // in A');
+    assertNoInterfaceMembers();
+  }
+
+  Future<void> test_enum_interface_getterByGetter() async {
+    addTestFile('''
+class A {
+  int get foo => 0; // A
+}
+
+enum E implements A {
+  v;
+  int get foo => 0; // E
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('foo => 0; // E');
+    assertNoSuperMember();
+    assertHasInterfaceMember('foo => 0; // A');
+  }
+
+  Future<void> test_enum_interface_methodByMethod() async {
+    addTestFile('''
+class A {
+  void foo() {} // A
+}
+
+enum E implements A {
+  v;
+  void foo() {} // E
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('foo() {} // E');
+    assertNoSuperMember();
+    assertHasInterfaceMember('foo() {} // A');
+  }
+
+  Future<void> test_enum_interface_methodByMethod2() async {
+    addTestFile('''
+class A {
+  void foo() {} // A
+}
+
+class B {
+  void foo() {} // B
+}
+
+enum E implements A, B {
+  v;
+  void foo() {} // E
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('foo() {} // E');
+    assertNoSuperMember();
+    assertHasInterfaceMember('foo() {} // A');
+    assertHasInterfaceMember('foo() {} // B');
+  }
+
+  Future<void> test_enum_interface_methodByMethod_indirect() async {
+    addTestFile('''
+abstract class A {
+  void foo(); // A
+}
+
+abstract class B implements A {}
+
+enum E implements B {
+  v;
+  void foo() {} // E
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('foo() {} // E');
+    assertNoSuperMember();
+    assertHasInterfaceMember('foo(); // A');
+  }
+
+  Future<void> test_enum_interface_setterBySetter() async {
+    addTestFile('''
+class A {
+  set foo(int _) {} // A
+}
+
+enum E implements A {
+  v;
+  set foo(int _) {} // E
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('foo(int _) {} // E');
+    assertNoSuperMember();
+    assertHasInterfaceMember('foo(int _) {} // A');
+  }
+
+  Future<void> test_enum_super_fieldByField() async {
+    addTestFile('''
+mixin M {
+  final int foo = 0; // M
+}
+
+enum E with M {
+  v;
+  final int foo = 0; // E
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('foo = 0; // E');
+    assertHasSuperElement('foo = 0; // M');
+    assertNoInterfaceMembers();
+  }
+
+  Future<void> test_enum_super_fieldByGetter() async {
+    addTestFile('''
+mixin M {
+  final int foo = 0; // M
+}
+
+enum E with M {
+  v;
+  int get foo => 0; // E
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('foo => 0; // E');
+    assertHasSuperElement('foo = 0; // M');
+    assertNoInterfaceMembers();
+  }
+
+  Future<void> test_enum_super_fieldByMethod() async {
+    addTestFile('''
+mixin M {
+  final int foo = 0; // M
+}
+
+enum E with M {
+  v;
+  void foo() {} // E
+}
+''');
+    await prepareOverrides();
+    assertNoOverride('foo() {} // E');
+  }
+
+  Future<void> test_enum_super_fieldBySetter() async {
+    addTestFile('''
+mixin M {
+  final int foo = 0; // M
+}
+
+enum E with M {
+  v;
+  set foo(int _) {} // E
+}
+''');
+    await prepareOverrides();
+    assertNoOverride('foo(int _) {} // E');
+  }
+
+  Future<void> test_enum_super_getterByField() async {
+    addTestFile('''
+mixin M {
+  int get foo => 0; // M
+}
+
+enum E with M {
+  v;
+  final int foo = 0; // E
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('foo = 0; // E');
+    assertHasSuperElement('foo => 0; // M');
+    assertNoInterfaceMembers();
+  }
+
+  Future<void> test_enum_super_getterByGetter() async {
+    addTestFile('''
+mixin M {
+  int get foo => 0; // M
+}
+
+enum E with M {
+  v;
+  int get foo => 0; // E
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('foo => 0; // E');
+    assertHasSuperElement('foo => 0; // M');
+    assertNoInterfaceMembers();
+  }
+
+  Future<void> test_enum_super_getterByMethod() async {
+    addTestFile('''
+mixin M {
+  int get foo => 0; // M
+}
+
+enum E with M {
+  v;
+  void foo() {} // E
+}
+''');
+    await prepareOverrides();
+    assertNoOverride('foo() {} // E');
+  }
+
+  Future<void> test_enum_super_getterBySetter() async {
+    addTestFile('''
+mixin M {
+  int get foo => 0; // M
+}
+
+enum E with M {
+  v;
+  set foo(int _) {} // E
+}
+''');
+    await prepareOverrides();
+    assertNoOverride('foo(int _) {} // E');
+  }
+
+  Future<void> test_enum_super_methodByField() async {
+    addTestFile('''
+mixin M {
+  void foo() {} // M
+}
+
+enum E with M {
+  v;
+  final int foo = 0; // E
+}
+''');
+    await prepareOverrides();
+    assertNoOverride('foo = 0; // E');
+  }
+
+  Future<void> test_enum_super_methodByGetter() async {
+    addTestFile('''
+mixin M {
+  void foo() {} // M
+}
+
+enum E with M {
+  v;
+  int get foo => 0; // E
+}
+''');
+    await prepareOverrides();
+    assertNoOverride('foo => 0; // E');
+  }
+
+  Future<void> test_enum_super_methodByMethod() async {
+    addTestFile('''
+mixin M {
+  void foo() {} // M
+}
+
+enum E with M {
+  v;
+  void foo() {} // E
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('foo() {} // E');
+    assertHasSuperElement('foo() {} // M');
+    assertNoInterfaceMembers();
+  }
+
+  Future<void> test_enum_super_methodBySetter() async {
+    addTestFile('''
+mixin M {
+  void foo() {} // M
+}
+
+enum E with M {
+  v;
+  set foo(int _) {} // E
+}
+''');
+    await prepareOverrides();
+    assertNoOverride('foo(int _) {} // E');
+  }
+
+  Future<void> test_enum_super_setterByField() async {
+    addTestFile('''
+mixin M {
+  set foo(int _) {} // M
+}
+
+enum E with M {
+  v;
+  final int foo = 0; // E
+}
+''');
+    await prepareOverrides();
+    assertNoOverride('foo = 0; // E');
+  }
+
+  Future<void> test_enum_super_setterByGetter() async {
+    addTestFile('''
+mixin M {
+  set foo(int _) {} // M
+}
+
+enum E with M {
+  v;
+  int get foo => 0; // E
+}
+''');
+    await prepareOverrides();
+    assertNoOverride('foo => 0; // E');
+  }
+
+  Future<void> test_enum_super_setterByMethod() async {
+    addTestFile('''
+mixin M {
+  set foo(int _) {} // M
+}
+
+enum E with M {
+  v;
+  void foo() {} // E
+}
+''');
+    await prepareOverrides();
+    assertNoOverride('foo() {} // E');
+  }
+
+  Future<void> test_enum_super_setterBySetter() async {
+    addTestFile('''
+mixin M {
+  set foo(int _) {} // M
+}
+
+enum E with M {
+  v;
+  set foo(int _) {} // E
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('foo(int _) {} // E');
+    assertHasSuperElement('foo(int _) {} // M');
+    assertNoInterfaceMembers();
+  }
+
+  Future<void> test_mixin_interface_method_direct_single() async {
+    addTestFile('''
+class A {
+  m() {} // in A
+}
+
+mixin M implements A {
+  m() {} // in M
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('m() {} // in M');
+    assertNoSuperMember();
+    assertHasInterfaceMember('m() {} // in A');
+  }
+
   Future<void> test_mixin_method_direct() async {
     addTestFile('''
 class A {
@@ -475,173 +973,19 @@
     assertNoInterfaceMembers();
   }
 
-  Future<void> test_staticMembers() async {
-    addTestFile('''
-class A {
-  static int F = 0;
-  static void M() {}
-  static int get G => 0;
-  static void set S(int v) {}
-}
-class B extends A {
-  static int F = 0;
-  static void M() {}
-  static int get G => 0;
-  static void set S(int v) {}
-}
-''');
-    await prepareOverrides();
-    expect(overridesList, isEmpty);
-  }
-
-  Future<void> test_super_fieldByField() async {
-    addTestFile('''
-class A {
-  int fff; // in A
-}
-class B extends A {
-  int fff; // in B
-}
-''');
-    await prepareOverrides();
-    assertHasOverride('fff; // in B');
-    assertHasSuperElement('fff; // in A');
-    assertNoInterfaceMembers();
-  }
-
-  Future<void> test_super_fieldByGetter() async {
-    addTestFile('''
-class A {
-  int fff; // in A
-}
-class B extends A {
-  get fff => 0; // in B
-}
-''');
-    await prepareOverrides();
-    assertHasOverride('fff => 0; // in B');
-    assertHasSuperElement('fff; // in A');
-    assertNoInterfaceMembers();
-  }
-
-  Future<void> test_super_fieldBySetter() async {
-    addTestFile('''
-class A {
-  int fff; // in A
-}
-class B extends A {
-  set fff(x) {} // in B
-}
-''');
-    await prepareOverrides();
-    assertHasOverride('fff(x) {} // in B');
-    assertHasSuperElement('fff; // in A');
-    assertNoInterfaceMembers();
-  }
-
-  Future<void> test_super_getterByField() async {
-    addTestFile('''
-class A {
-  get fff => 0; // in A
-  set fff(x) {} // in A
-}
-class B extends A {
-  int fff; // in B
-}
-''');
-    await prepareOverrides();
-    assertHasOverride('fff; // in B');
-    assertHasSuperElement('fff => 0; // in A');
-    assertNoInterfaceMembers();
-  }
-
-  Future<void> test_super_getterByGetter() async {
-    addTestFile('''
-class A {
-  get fff => 0; // in A
-}
-class B extends A {
-  get fff => 0; // in B
-}
-''');
-    await prepareOverrides();
-    assertHasOverride('fff => 0; // in B');
-    assertHasSuperElement('fff => 0; // in A');
-    assertNoInterfaceMembers();
-  }
-
-  Future<void> test_super_method_direct() async {
+  Future<void> test_mixin_superclassConstraint_method_direct() async {
     addTestFile('''
 class A {
   m() {} // in A
 }
-class B extends A {
-  m() {} // in B
+
+mixin M on A {
+  m() {} // in M
 }
 ''');
     await prepareOverrides();
-    assertHasOverride('m() {} // in B');
+    assertHasOverride('m() {} // in M');
     assertHasSuperElement('m() {} // in A');
     assertNoInterfaceMembers();
   }
-
-  Future<void> test_super_method_indirect() async {
-    addTestFile('''
-class A {
-  m() {} // in A
-}
-class B extends A {
-}
-class C extends B {
-  m() {} // in C
-}
-''');
-    await prepareOverrides();
-    assertHasOverride('m() {} // in C');
-    assertHasSuperElement('m() {} // in A');
-    assertNoInterfaceMembers();
-  }
-
-  Future<void> test_super_method_privateByPrivate() async {
-    addTestFile('''
-class A {
-  _m() {} // in A
-}
-class B extends A {
-  _m() {} // in B
-}
-''');
-    await prepareOverrides();
-    assertHasOverride('_m() {} // in B');
-    assertHasSuperElement('_m() {} // in A');
-    assertNoInterfaceMembers();
-  }
-
-  Future<void> test_super_method_superTypeCycle() async {
-    addTestFile('''
-class A extends B {
-  m() {} // in A
-}
-class B extends A {
-  m() {} // in B
-}
-''');
-    await prepareOverrides();
-    // must finish
-  }
-
-  Future<void> test_super_setterBySetter() async {
-    addTestFile('''
-class A {
-  set fff(x) {} // in A
-}
-class B extends A {
-  set fff(x) {} // in B
-}
-''');
-    await prepareOverrides();
-    assertHasOverride('fff(x) {} // in B');
-    assertHasSuperElement('fff(x) {} // in A');
-    assertNoInterfaceMembers();
-  }
 }
diff --git a/pkg/analysis_server/test/services/search/search_engine_test.dart b/pkg/analysis_server/test/services/search/search_engine_test.dart
index 30fa39f..0097edb 100644
--- a/pkg/analysis_server/test/services/search/search_engine_test.dart
+++ b/pkg/analysis_server/test/services/search/search_engine_test.dart
@@ -61,7 +61,7 @@
     return SearchEngineImpl(allDrivers);
   }
 
-  Future<void> test_membersOfSubtypes_hasMembers() async {
+  Future<void> test_membersOfSubtypes_classByClass_hasMembers() async {
     newFile('$testPackageLibPath/a.dart', content: '''
 class A {
   void a() {}
@@ -91,6 +91,40 @@
     expect(members, unorderedEquals(['a', 'b']));
   }
 
+  Future<void> test_membersOfSubtypes_enum_implements_hasMembers() async {
+    await resolveTestCode('''
+class A {
+  void foo() {}
+}
+
+enum E implements A {
+  v;
+  void foo() {}
+}
+''');
+
+    var A = findElement.class_('A');
+    var members = await searchEngine.membersOfSubtypes(A);
+    expect(members, unorderedEquals(['foo']));
+  }
+
+  Future<void> test_membersOfSubtypes_enum_with_hasMembers() async {
+    await resolveTestCode('''
+mixin M {
+  void foo() {}
+}
+
+enum E with M {
+  v;
+  void foo() {}
+}
+''');
+
+    var M = findElement.mixin('M');
+    var members = await searchEngine.membersOfSubtypes(M);
+    expect(members, unorderedEquals(['foo']));
+  }
+
   Future<void> test_membersOfSubtypes_noMembers() async {
     newFile('$testPackageLibPath/a.dart', content: '''
 class A {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_leading_underscore_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_leading_underscore_test.dart
new file mode 100644
index 0000000..adf0a5a
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_leading_underscore_test.dart
@@ -0,0 +1,137 @@
+// 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.
+
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(RemoveLeadingUnderscoreBulkTest);
+    defineReflectiveTests(RemoveLeadingUnderscoreTest);
+  });
+}
+
+@reflectiveTest
+class RemoveLeadingUnderscoreBulkTest extends BulkFixProcessorTest {
+  @override
+  String get lintCode => LintNames.no_leading_underscores_for_local_identifiers;
+
+  Future<void> test_singleFile() async {
+    await resolveTestCode('''
+main() {
+  int _foo = 42;
+  print(_foo);
+  [0, 1, 2].forEach((_bar) {
+    print(_bar);
+  });
+}
+''');
+    await assertHasFix('''
+main() {
+  int foo = 42;
+  print(foo);
+  [0, 1, 2].forEach((bar) {
+    print(bar);
+  });
+}
+''');
+  }
+}
+
+@reflectiveTest
+class RemoveLeadingUnderscoreTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.REMOVE_LEADING_UNDERSCORE;
+
+  @override
+  String get lintCode => LintNames.no_leading_underscores_for_local_identifiers;
+
+  Future<void> test_localVariable() async {
+    await resolveTestCode('''
+void f() {
+  var _foo = 1;
+  print(_foo);
+}
+''');
+    await assertHasFix('''
+void f() {
+  var foo = 1;
+  print(foo);
+}
+''');
+  }
+
+  Future<void> test_parameter_closure() async {
+    await resolveTestCode('''
+void f() {
+  [0, 1, 2].forEach((_foo) {
+    print(_foo);
+  });
+}
+''');
+    await assertHasFix('''
+void f() {
+  [0, 1, 2].forEach((foo) {
+    print(foo);
+  });
+}
+''');
+  }
+
+  Future<void> test_parameter_function() async {
+    await resolveTestCode('''
+void f(int _foo) {
+  print(_foo);
+}
+''');
+    await assertHasFix('''
+void f(int foo) {
+  print(foo);
+}
+''');
+  }
+
+  Future<void> test_parameter_method() async {
+    await resolveTestCode('''
+class A {
+  void f(int _foo) {
+    print(_foo);
+  }
+}
+''');
+    await assertHasFix('''
+class A {
+  void f(int foo) {
+    print(foo);
+  }
+}
+''');
+  }
+
+  Future<void> test_parameter_optionalNamed() async {
+    await resolveTestCode('''
+void f({int? _foo}) {
+  print(_foo);
+}
+''');
+    await assertNoFix();
+  }
+
+  Future<void> test_parameter_optionalPositional() async {
+    await resolveTestCode('''
+void f([int? _foo]) {
+  print(_foo);
+}
+''');
+    await assertHasFix('''
+void f([int? foo]) {
+  print(foo);
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index c61f1a5..c1d46b5 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -144,6 +144,7 @@
 import 'remove_if_null_operator_test.dart' as remove_if_null_operator;
 import 'remove_initializer_test.dart' as remove_initializer;
 import 'remove_interpolation_braces_test.dart' as remove_interpolation_braces;
+import 'remove_leading_underscore_test.dart' as remove_leading_underscore;
 import 'remove_method_declaration_test.dart' as remove_method_declaration;
 import 'remove_name_from_combinator_test.dart' as remove_name_from_combinator;
 import 'remove_non_null_assertion_test.dart' as remove_non_null_assertion_test;
@@ -346,6 +347,7 @@
     remove_if_null_operator.main();
     remove_initializer.main();
     remove_interpolation_braces.main();
+    remove_leading_underscore.main();
     remove_method_declaration.main();
     remove_name_from_combinator.main();
     remove_non_null_assertion_test.main();
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index a79fe72..84644e4 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -82,7 +82,7 @@
 /// TODO(scheglov) Clean up the list of implicitly analyzed files.
 class AnalysisDriver implements AnalysisDriverGeneric {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 208;
+  static const int DATA_VERSION = 209;
 
   /// The number of exception contexts allowed to write. Once this field is
   /// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/dart/analysis/index.dart b/pkg/analyzer/lib/src/dart/analysis/index.dart
index ba8cdd5..74c3887 100644
--- a/pkg/analyzer/lib/src/dart/analysis/index.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/index.dart
@@ -672,6 +672,20 @@
   }
 
   @override
+  void visitEnumDeclaration(EnumDeclaration node) {
+    _addSubtype(
+      node.name.name,
+      withClause: node.withClause,
+      implementsClause: node.implementsClause,
+      memberNodes: node.members,
+    );
+
+    var declaredElement = node.declaredElement!;
+    recordIsAncestorOf(declaredElement);
+    super.visitEnumDeclaration(node);
+  }
+
+  @override
   void visitExportDirective(ExportDirective node) {
     ExportElement? element = node.element;
     recordUriReference(element?.exportedLibrary, node.uri);
diff --git a/pkg/analyzer/lib/src/dart/analysis/referenced_names.dart b/pkg/analyzer/lib/src/dart/analysis/referenced_names.dart
index 073d6f6..0cc56cb 100644
--- a/pkg/analyzer/lib/src/dart/analysis/referenced_names.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/referenced_names.dart
@@ -41,6 +41,9 @@
       _addSubtypedName(declaration.superclass);
       _addSubtypedNames(declaration.withClause.mixinTypes);
       _addSubtypedNames(declaration.implementsClause?.interfaces);
+    } else if (declaration is EnumDeclaration) {
+      _addSubtypedNames(declaration.withClause?.mixinTypes);
+      _addSubtypedNames(declaration.implementsClause?.interfaces);
     } else if (declaration is MixinDeclaration) {
       _addSubtypedNames(declaration.onClause?.superclassConstraints);
       _addSubtypedNames(declaration.implementsClause?.interfaces);
diff --git a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
index 53650c1..3cc2617 100644
--- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -473,7 +473,7 @@
     );
   }
 
-  test_getFilesSubtypingName() {
+  test_getFilesSubtypingName_class() {
     String a = convertPath('/a.dart');
     String b = convertPath('/b.dart');
 
@@ -510,6 +510,75 @@
     );
   }
 
+  test_getFilesSubtypingName_enum_implements() {
+    String a = convertPath('/a.dart');
+    String b = convertPath('/b.dart');
+
+    newFile(a, content: r'''
+class A {}
+enum E1 implements A {
+  v
+}
+''');
+    newFile(b, content: r'''
+class A {}
+enum E2 implements A {
+  v
+}
+''');
+
+    FileState aFile = fileSystemState.getFileForPath(a);
+    FileState bFile = fileSystemState.getFileForPath(b);
+
+    expect(
+      fileSystemState.getFilesSubtypingName('A'),
+      unorderedEquals([aFile, bFile]),
+    );
+
+    // Change b.dart so that it does not subtype A.
+    newFile(b, content: r'''
+class C {}
+enum E2 implements C {
+  v
+}
+''');
+    bFile.refresh();
+    expect(
+      fileSystemState.getFilesSubtypingName('A'),
+      unorderedEquals([aFile]),
+    );
+    expect(
+      fileSystemState.getFilesSubtypingName('C'),
+      unorderedEquals([bFile]),
+    );
+  }
+
+  test_getFilesSubtypingName_enum_with() {
+    String a = convertPath('/a.dart');
+    String b = convertPath('/b.dart');
+
+    newFile(a, content: r'''
+mixin M {}
+enum E1 with M {
+  v
+}
+''');
+    newFile(b, content: r'''
+mixin M {}
+enum E2 with M {
+  v
+}
+''');
+
+    FileState aFile = fileSystemState.getFileForPath(a);
+    FileState bFile = fileSystemState.getFileForPath(b);
+
+    expect(
+      fileSystemState.getFilesSubtypingName('M'),
+      unorderedEquals([aFile, bFile]),
+    );
+  }
+
   test_hasUri() {
     Uri uri = Uri.parse('package:aaa/foo.dart');
     String templatePath = convertPath('/aaa/lib/foo.dart');
diff --git a/pkg/analyzer/test/src/dart/analysis/index_test.dart b/pkg/analyzer/test/src/dart/analysis/index_test.dart
index 568de01..4c31935 100644
--- a/pkg/analyzer/test/src/dart/analysis/index_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/index_test.dart
@@ -1747,6 +1747,36 @@
     expect(index.subtypes, isEmpty);
   }
 
+  test_subtypes_enum_implements() async {
+    String libP = 'package:test/test.dart;package:test/test.dart';
+    await _indexTestUnit('''
+class A {}
+
+enum E implements A {
+  v;
+  void foo() {}
+}
+''');
+
+    expect(index.subtypes, hasLength(1));
+    _assertSubtype(0, '$libP;A', 'E', ['foo']);
+  }
+
+  test_subtypes_enum_with() async {
+    String libP = 'package:test/test.dart;package:test/test.dart';
+    await _indexTestUnit('''
+mixin M {}
+
+enum E with M {
+  v;
+  void foo() {}
+}
+''');
+
+    expect(index.subtypes, hasLength(1));
+    _assertSubtype(0, '$libP;M', 'E', ['foo']);
+  }
+
   test_subtypes_mixinDeclaration() async {
     String libP = 'package:test/lib.dart;package:test/lib.dart';
     newFile('$testPackageLibPath/lib.dart', content: '''
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
index 3410fd2..6c5e71d 100644
--- a/pkg/analyzer/test/src/dart/analysis/search_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/search_test.dart
@@ -2287,7 +2287,7 @@
     await _verifyReferences(element, expected);
   }
 
-  test_subtypes() async {
+  test_subtypes_class() async {
     await resolveTestCode('''
 class A {}
 
@@ -2342,7 +2342,7 @@
     }
   }
 
-  test_subtypes_discover() async {
+  test_subtypes_class_discover() async {
     var aaaPackageRootPath = '$packagesRootPath/aaa';
     var bbbPackageRootPath = '$packagesRootPath/bbb';
 
@@ -2412,7 +2412,7 @@
     expect(b.members, ['method1']);
   }
 
-  test_subTypes_discover() async {
+  test_subTypes_class_discover() async {
     var aaaPackageRootPath = '$packagesRootPath/aaa';
     var bbbPackageRootPath = '$packagesRootPath/bbb';
     var cccPackageRootPath = '$packagesRootPath/ccc';
@@ -2453,7 +2453,7 @@
     assertHasResult(cccFilePath, 'C', not: true);
   }
 
-  test_subtypes_files() async {
+  test_subtypes_class_files() async {
     String pathB = convertPath('$testPackageLibPath/b.dart');
     String pathC = convertPath('$testPackageLibPath/c.dart');
     newFile(pathB, content: r'''
@@ -2482,6 +2482,59 @@
     expect(c.id, endsWith('c.dart;C'));
   }
 
+  test_subtypes_class_partWithoutLibrary() async {
+    await resolveTestCode('''
+part of lib;
+
+class A {}
+class B extends A {}
+''');
+    var a = findElement.class_('A');
+
+    List<SubtypeResult> subtypes =
+        await driver.search.subtypes(SearchedFiles(), type: a);
+    expect(subtypes, hasLength(1));
+
+    SubtypeResult b = subtypes.singleWhere((r) => r.name == 'B');
+    expect(b.libraryUri, testUriStr);
+    expect(b.id, '$testUriStr;$testUriStr;B');
+  }
+
+  test_subtypes_enum() async {
+    await resolveTestCode('''
+class A {}
+
+enum E1 implements A {
+  v;
+  void methodE1() {}
+}
+
+enum E2 with A {
+  v;
+  void methodE2() {}
+}
+
+class B {}
+''');
+
+    var subtypes = await driver.search.subtypes(
+      SearchedFiles(),
+      type: findElement.class_('A'),
+    );
+    expect(subtypes, hasLength(2));
+
+    var resultE1 = subtypes.singleWhere((r) => r.name == 'E1');
+    var resultE2 = subtypes.singleWhere((r) => r.name == 'E2');
+
+    expect(resultE1.libraryUri, testUriStr);
+    expect(resultE1.id, '$testUriStr;$testUriStr;E1');
+    expect(resultE1.members, ['methodE1']);
+
+    expect(resultE2.libraryUri, testUriStr);
+    expect(resultE2.id, '$testUriStr;$testUriStr;E2');
+    expect(resultE2.members, ['methodE2']);
+  }
+
   test_subtypes_mixin_superclassConstraints() async {
     await resolveTestCode('''
 class A {
@@ -2521,24 +2574,6 @@
     }
   }
 
-  test_subtypes_partWithoutLibrary() async {
-    await resolveTestCode('''
-part of lib;
-
-class A {}
-class B extends A {}
-''');
-    var a = findElement.class_('A');
-
-    List<SubtypeResult> subtypes =
-        await driver.search.subtypes(SearchedFiles(), type: a);
-    expect(subtypes, hasLength(1));
-
-    SubtypeResult b = subtypes.singleWhere((r) => r.name == 'B');
-    expect(b.libraryUri, testUriStr);
-    expect(b.id, '$testUriStr;$testUriStr;B');
-  }
-
   test_topLevelElements() async {
     await resolveTestCode('''
 class A {} // A
diff --git a/pkg/dart2wasm/bin/run_wasm.js b/pkg/dart2wasm/bin/run_wasm.js
index 08a6d92..7e962a0 100644
--- a/pkg/dart2wasm/bin/run_wasm.js
+++ b/pkg/dart2wasm/bin/run_wasm.js
@@ -46,6 +46,19 @@
         setTimeout(function() {
             inst.exports.$call0(closure);
         }, milliseconds);
+    },
+    getCurrentStackTrace: function() {
+        // [Error] should be supported in most browsers.
+        // A possible future optimization we could do is to just save the
+        // `Error` object here, and stringify the stack trace when it is
+        // actually used.
+        let stackString = new Error().stack.toString();
+
+        // We remove the last three lines of the stack trace to prevent including
+        // `Error`, `getCurrentStackTrace`, and `StackTrace.current` in the
+        // stack trace.
+        let userStackString = stackString.split('\n').slice(3).join('\n');
+        return stringToDartString(userStackString);
     }
 };
 
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index d4ef423..5ae0b2a 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -49,6 +49,7 @@
   w.Local? preciseThisLocal;
   final Map<TypeParameter, w.Local> typeLocals = {};
   final List<Statement> finalizers = [];
+  final List<w.Label> tryLabels = [];
   final Map<LabeledStatement, w.Label> labels = {};
   final Map<SwitchCase, w.Label> switchLabels = {};
 
@@ -537,8 +538,86 @@
 
   @override
   void visitTryCatch(TryCatch node) {
-    // TODO(joshualitt): Include catches
+    // It is not valid dart to have a try without a catch.
+    assert(node.catches.isNotEmpty);
+
+    // We lower a [TryCatch] to a wasm try block. If there are any [Catch]
+    // nodes, we generate a single wasm catch instruction, and dispatch at
+    // runtime based on the type of the caught exception.
+    w.Label try_ = b.try_();
     node.body.accept(this);
+    b.br(try_);
+
+    // Insert a catch instruction which will catch any thrown Dart
+    // exceptions.
+    // Note: We must wait to add the try block to the [tryLabels] stack until
+    // after we have visited the body of the try. This is to handle the case of
+    // a rethrow nested within a try nested within a catch, that is we need the
+    // rethrow to target the last try block with a catch.
+    tryLabels.add(try_);
+    b.catch_(translator.exceptionTag);
+
+    // Stash the original exception in a local so we can push it back onto the
+    // stack after each type test. Also, store the stack trace in a local.
+    w.RefType stackTrace = translator.stackTraceInfo.nonNullableType;
+    w.Local thrownStackTrace = addLocal(stackTrace);
+    b.local_set(thrownStackTrace);
+
+    w.RefType exception = translator.topInfo.nonNullableType;
+    w.Local thrownException = addLocal(exception);
+    b.local_set(thrownException);
+
+    // For each catch node:
+    //   1) Create a block for the catch.
+    //   2) Push the caught exception onto the stack.
+    //   3) Add a type test based on the guard of the catch.
+    //   4) If the test fails, we jump to the next catch. Otherwise, we
+    //      execute the body of the catch.
+    for (Catch catch_ in node.catches) {
+      w.Label catchBlock = b.block();
+      DartType guard = catch_.guard;
+
+      // Only emit the type test if the guard is not [Object].
+      if (guard != translator.coreTypes.objectNonNullableRawType) {
+        b.local_get(thrownException);
+        emitTypeTest(
+            guard, translator.coreTypes.objectNonNullableRawType, node);
+        b.i32_eqz();
+        b.br_if(catchBlock);
+      }
+
+      // If there is an exception declaration, create a local corresponding to
+      // the catch's exception [VariableDeclaration] node.
+      VariableDeclaration? exceptionDeclaration = catch_.exception;
+      if (exceptionDeclaration != null) {
+        w.Local guardedException = addLocal(exception);
+        locals[exceptionDeclaration] = guardedException;
+        b.local_get(thrownException);
+        b.local_set(guardedException);
+      }
+
+      // If there is a stack trace declaration, then create a local
+      // corresponding to the catch's stack trace [VariableDeclaration] node.
+      VariableDeclaration? stackTraceDeclaration = catch_.stackTrace;
+      if (stackTraceDeclaration != null) {
+        w.Local guardedStackTrace = addLocal(stackTrace);
+        locals[stackTraceDeclaration] = guardedStackTrace;
+        b.local_get(thrownStackTrace);
+        b.local_set(guardedStackTrace);
+      }
+      catch_.body.accept(this);
+
+      // Jump out of the try entirely if we enter any catch block.
+      b.br(try_);
+      b.end(); // end catchBlock.
+    }
+
+    // We insert a rethrow just before the end of the try block to handle the
+    // case where none of the catch blocks catch the type of the thrown
+    // exception.
+    b.rethrow_(try_);
+    tryLabels.removeLast();
+    b.end(); // end try_.
   }
 
   @override
@@ -1639,13 +1718,18 @@
 
   @override
   w.ValueType visitThrow(Throw node, w.ValueType expectedType) {
-    wrap(node.expression, translator.topInfo.nullableType);
-    // TODO(joshualitt): Throw exception
-    b.comment(node.toStringInternal());
-    b.drop();
-    b.block(const [], [if (expectedType != voidMarker) expectedType]);
-    b.unreachable();
-    b.end();
+    wrap(node.expression, translator.topInfo.nonNullableType);
+    _call(translator.stackTraceCurrent.reference);
+
+    // At this point, we have the exception and the current stack trace on the
+    // stack, so just throw them using the exception tag.
+    b.throw_(translator.exceptionTag);
+    return expectedType;
+  }
+
+  @override
+  w.ValueType visitRethrow(Rethrow node, w.ValueType expectedType) {
+    b.rethrow_(tryLabels.last);
     return expectedType;
   }
 
diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart
index 7a33ce4..36a4b0d 100644
--- a/pkg/dart2wasm/lib/translator.dart
+++ b/pkg/dart2wasm/lib/translator.dart
@@ -85,6 +85,8 @@
   late final Class typedListClass;
   late final Class typedListViewClass;
   late final Class byteDataViewClass;
+  late final Class stackTraceClass;
+  late final Procedure stackTraceCurrent;
   late final Procedure stringEquals;
   late final Procedure stringInterpolate;
   late final Procedure mapFactory;
@@ -110,6 +112,7 @@
   late final w.Module m;
   late final w.DefinedFunction initFunction;
   late final w.ValueType voidMarker;
+  late final w.Tag exceptionTag = createExceptionTag();
 
   // Caches for when identical source constructs need a common representation.
   final Map<w.StorageType, w.ArrayType> arrayTypeCache = {};
@@ -121,6 +124,7 @@
 
   ClassInfo get topInfo => classes[0];
   ClassInfo get objectInfo => classInfo[coreTypes.objectClass]!;
+  ClassInfo get stackTraceInfo => classInfo[stackTraceClass]!;
 
   Translator(this.component, this.coreTypes, this.typeEnvironment, this.options)
       : libraries = component.libraries,
@@ -172,10 +176,13 @@
     oneByteStringClass = lookupCore("_OneByteString");
     twoByteStringClass = lookupCore("_TwoByteString");
     typeClass = lookupCore("_Type");
+    stackTraceClass = lookupCore("StackTrace");
     typedListBaseClass = lookupTypedData("_TypedListBase");
     typedListClass = lookupTypedData("_TypedList");
     typedListViewClass = lookupTypedData("_TypedListView");
     byteDataViewClass = lookupTypedData("_ByteDataView");
+    stackTraceCurrent =
+        stackTraceClass.procedures.firstWhere((p) => p.name.text == "current");
     stringEquals =
         stringBaseClass.procedures.firstWhere((p) => p.name.text == "==");
     stringInterpolate = stringBaseClass.procedures
@@ -340,6 +347,17 @@
             : coreTypes.objectClass;
   }
 
+  /// Creates a [Tag] for a void [FunctionType] with two parameters,
+  /// a [topInfo.nonNullableType] parameter to hold an exception, and a
+  /// [stackTraceInfo.nonNullableType] to hold a stack trace. This single
+  /// exception tag is used to throw and catch all Dart exceptions.
+  w.Tag createExceptionTag() {
+    w.FunctionType functionType = m.addFunctionType(
+        [topInfo.nonNullableType, stackTraceInfo.nonNullableType], const []);
+    w.Tag tag = m.addTag(functionType);
+    return tag;
+  }
+
   w.ValueType translateType(DartType type) {
     w.StorageType wasmType = translateStorageType(type);
     if (wasmType is w.ValueType) return wasmType;
diff --git a/pkg/dartdev/lib/src/commands/doc.dart b/pkg/dartdev/lib/src/commands/doc.dart
index 9a9c4a2..fb9d38a 100644
--- a/pkg/dartdev/lib/src/commands/doc.dart
+++ b/pkg/dartdev/lib/src/commands/doc.dart
@@ -90,7 +90,7 @@
       if (verbose) ...['--verbose-warnings', '--show-stats'],
     ]);
 
-    final config = await parseOptions(pubPackageMetaProvider, options);
+    final config = parseOptions(pubPackageMetaProvider, options);
     if (config == null) {
       // There was an error while parsing options.
       return 2;
@@ -105,7 +105,7 @@
         config, pubPackageMetaProvider, packageConfigProvider);
     final dartdoc = config.generateDocs
         ? await Dartdoc.fromContext(config, packageBuilder)
-        : await Dartdoc.withEmptyGenerator(config, packageBuilder);
+        : Dartdoc.withEmptyGenerator(config, packageBuilder);
     dartdoc.executeGuarded();
     return 0;
   }
diff --git a/pkg/dartdev/lib/src/templates/server_shelf.dart b/pkg/dartdev/lib/src/templates/server_shelf.dart
index 2292d39..023ffea 100644
--- a/pkg/dartdev/lib/src/templates/server_shelf.dart
+++ b/pkg/dartdev/lib/src/templates/server_shelf.dart
@@ -11,7 +11,7 @@
       : super(
           'server-shelf',
           'Server app',
-          'A server app using `package:shelf`',
+          'A server app using package:shelf.',
           categories: const ['dart', 'server'],
         ) {
     addFile('.gitignore', common.gitignore);
@@ -127,7 +127,7 @@
 }
 
 Response _echoHandler(Request request) {
-  final message = params(request, 'message');
+  final message = request.params['message'];
   return Response.ok('$message\n');
 }
 
diff --git a/pkg/dartdev/test/commands/create_integration_test.dart b/pkg/dartdev/test/commands/create_integration_test.dart
index 92e981a..19f93d8 100644
--- a/pkg/dartdev/test/commands/create_integration_test.dart
+++ b/pkg/dartdev/test/commands/create_integration_test.dart
@@ -2,9 +2,13 @@
 // 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.
 
+import 'dart:async';
+import 'dart:convert';
 import 'dart:io';
 
 import 'package:dartdev/src/commands/create.dart';
+import 'package:dartdev/src/templates.dart';
+import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 
 import '../utils.dart';
@@ -14,42 +18,134 @@
 }
 
 void defineCreateTests() {
-  TestProject? p;
+  TestProject? proj;
 
-  setUp(() => p = null);
+  setUp(() => proj = null);
 
-  tearDown(() async => await p?.dispose());
+  tearDown(() async => await proj?.dispose());
 
   // Create tests for each template.
   for (String templateId
       in CreateCommand.legalTemplateIds(includeDeprecated: true)) {
     test(templateId, () async {
-      p = project();
+      const projectName = 'template_project';
+      proj = project();
+      final p = proj!;
+      final templateGenerator = getGenerator(templateId)!;
 
-      ProcessResult createResult = await p!.run([
+      ProcessResult createResult = await p.run([
         'create',
         '--force',
         '--template',
         templateId,
-        'template_project',
+        projectName,
       ]);
       expect(createResult.exitCode, 0, reason: createResult.stderr);
 
       // Validate that the project analyzes cleanly.
-      // TODO: Should we use --fatal-infos here?
-      ProcessResult analyzeResult =
-          await p!.run(['analyze'], workingDir: p!.dir.path);
+      ProcessResult analyzeResult = await p.run(
+        ['analyze', '--fatal-infos', projectName],
+        workingDir: p.dir.path,
+      );
       expect(analyzeResult.exitCode, 0, reason: analyzeResult.stdout);
 
       // Validate that the code is well formatted.
-      ProcessResult formatResult = await p!.run([
+      ProcessResult formatResult = await p.run([
         'format',
         '--output',
         'none',
         '--set-exit-if-changed',
-        'template_project',
+        projectName,
       ]);
       expect(formatResult.exitCode, 0, reason: formatResult.stdout);
+
+      // Process the execution instructions provided by the template.
+      final runCommands = templateGenerator
+          .getInstallInstructions(
+            projectName,
+            scriptPath: projectName,
+          )
+          .split('\n')
+          // Remove directory change instructions.
+          .sublist(1)
+          .map((command) => command.trim())
+          .map((command) {
+        final commandParts = command.split(' ');
+        if (command.startsWith('dart ')) {
+          return commandParts.sublist(1);
+        }
+        return commandParts;
+      }).toList();
+
+      final isServerTemplate = templateGenerator.categories.contains('server');
+      final isWebTemplate = templateGenerator.categories.contains('web');
+      final workingDir = path.join(p.dirPath, projectName);
+
+      // Execute the templates run instructions.
+      for (int i = 0; i < runCommands.length; ++i) {
+        // The last command is always the command to execute the code generated
+        // by the template.
+        final isLastCommand = i == runCommands.length - 1;
+        final command = runCommands[i];
+        Process process;
+
+        if (isLastCommand && isWebTemplate) {
+          // The web template uses `webdev` to execute, not `dart`, so don't
+          // run the test through the project utility method.
+          process = await Process.start(
+              path.join(
+                p.pubCacheBinPath,
+                Platform.isWindows ? '${command.first}.bat' : command.first,
+              ),
+              command.sublist(1),
+              workingDirectory: workingDir,
+              environment: {
+                'PUB_CACHE': p.pubCachePath,
+                'PATH': path.dirname(Platform.resolvedExecutable) +
+                    (Platform.isWindows ? ';' : ':') +
+                    Platform.environment['PATH']!,
+              });
+        } else {
+          process = await p.start(
+            command,
+            workingDir: workingDir,
+          );
+        }
+
+        if (isLastCommand && (isServerTemplate || isWebTemplate)) {
+          final completer = Completer<void>();
+          late StreamSubscription stdoutSub;
+          late StreamSubscription stderrSub;
+          // Listen for well-known output from specific templates to determine
+          // if they've executed correctly. These templates won't exit on their
+          // own, so we'll need to terminate the process once we've verified it
+          // runs correctly.
+          stdoutSub = process.stdout.transform(utf8.decoder).listen((e) {
+            print('stdout: $e');
+            if ((isServerTemplate && e.contains('Server listening on port')) ||
+                (isWebTemplate && e.contains('Succeeded after'))) {
+              stderrSub.cancel();
+              stdoutSub.cancel();
+              process.kill();
+              completer.complete();
+            }
+          });
+          stderrSub = process.stderr
+              .transform(utf8.decoder)
+              .listen((e) => print('stderr: $e'));
+          await completer.future;
+
+          // Since we had to terminate the process manually, we aren't certain
+          // as to what the exit code will be on all platforms (should be -15
+          // for POSIX systems), so we'll just wait for the process to exit
+          // here.
+          await process.exitCode;
+        } else {
+          // If the sample should exit on its own, it should always result in
+          // an exit code of 0.
+          expect(await process.exitCode, 0);
+        }
+      }
     });
   }
 }
diff --git a/pkg/dartdev/test/utils.dart b/pkg/dartdev/test/utils.dart
index 145d519..996b98b 100644
--- a/pkg/dartdev/test/utils.dart
+++ b/pkg/dartdev/test/utils.dart
@@ -45,6 +45,10 @@
 
   String get dirPath => dir.path;
 
+  String get pubCachePath => path.join(dirPath, 'pub_cache');
+
+  String get pubCacheBinPath => path.join(pubCachePath, 'bin');
+
   String get mainPath => path.join(dirPath, relativeFilePath);
 
   final String name;
@@ -129,7 +133,10 @@
           ...arguments,
         ],
         workingDirectory: workingDir ?? dir.path,
-        environment: {if (logAnalytics) '_DARTDEV_LOG_ANALYTICS': 'true'});
+        environment: {
+          if (logAnalytics) '_DARTDEV_LOG_ANALYTICS': 'true',
+          'PUB_CACHE': pubCachePath,
+        });
     final proc = _process!;
     final stdoutContents = proc.stdout.transform(utf8.decoder).join();
     final stderrContents = proc.stderr.transform(utf8.decoder).join();
@@ -153,7 +160,10 @@
           ...arguments,
         ],
         workingDirectory: workingDir ?? dir.path,
-        environment: {if (logAnalytics) '_DARTDEV_LOG_ANALYTICS': 'true'})
+        environment: {
+          if (logAnalytics) '_DARTDEV_LOG_ANALYTICS': 'true',
+          'PUB_CACHE': pubCachePath,
+        })
       ..then((p) => _process = p);
   }
 
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart
index 0e9f780..7db89ce 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_shared.dart
@@ -315,6 +315,7 @@
               'Symbol(C.field): 42, Symbol(_field): 0}');
     });
   });
+
   group('Named arguments anywhere', () {
     var source = r'''
       String topLevelMethod(int param1, String param2,
@@ -390,6 +391,155 @@
           expectedResult: '1, two, 3, four');
     });
   });
+
+  group('Enums', () {
+    var source = r'''
+      enum E {id1, id2, id3}
+
+      enum E2 {id1, id2, id3}
+
+      main() {
+        var e = E.id2;
+        // Breakpoint: bp
+        print('hello world');
+      }
+        ''';
+
+    setUpAll(() async {
+      await driver.initSource(setup, source);
+    });
+
+    tearDownAll(() async {
+      await driver.cleanupTest();
+    });
+
+    test('evaluate to the correct string', () async {
+      await driver.check(
+          breakpointId: 'bp',
+          expression: 'E.id2.toString()',
+          expectedResult: 'E.id2');
+    });
+    test('evaluate to the correct index', () async {
+      await driver.check(
+          breakpointId: 'bp', expression: 'E.id3.index', expectedResult: '2');
+    });
+    test('compare properly against themselves', () async {
+      await driver.check(
+          breakpointId: 'bp',
+          expression: 'e == E.id2 && E.id2 == E.id2',
+          expectedResult: 'true');
+    });
+    test('compare properly against other enums', () async {
+      await driver.check(
+          breakpointId: 'bp',
+          expression: 'e != E2.id2 && E.id2 != E2.id2',
+          expectedResult: 'true');
+    });
+  });
+
+  group('Enhanced enums', () {
+    var source = r'''
+      enum E<T> with M {
+        id_int<int>(0),
+        id_bool<bool>(true),
+        id_string<String>('hello world', n: 13);
+
+        final T field;
+        final num n;
+        static const constStaticField = id_string;
+
+        const E(T arg0, {num? n}) : this.field = arg0, this.n = n ?? 42;
+
+        T get fieldGetter => field;
+        num instanceMethod() => n;
+      }
+
+      enum E2 with M {
+        v1, v2, id_string;
+        int get index => 10;
+      }
+
+      mixin M on Enum {
+        int mixinMethod() => index * 100;
+      }
+
+      main() {
+        var e = E.id_string;
+        // Breakpoint: bp
+        print('hello world');
+      }
+        ''';
+
+    setUpAll(() async {
+      await driver
+          .initSource(setup, source, experiments: {'enhanced-enums': true});
+    });
+
+    tearDownAll(() async {
+      await driver.cleanupTest();
+    });
+
+    test('evaluate to the correct string', () async {
+      await driver.check(
+          breakpointId: 'bp',
+          expression: 'E.id_string.toString()',
+          expectedResult: 'E.id_string');
+    });
+    test('evaluate to the correct index', () async {
+      await driver.check(
+          breakpointId: 'bp',
+          expression: 'E.id_string.index',
+          expectedResult: '2');
+    });
+    test('compare properly against themselves', () async {
+      await driver.check(
+          breakpointId: 'bp',
+          expression: 'e == E.id_string && E.id_string == E.id_string',
+          expectedResult: 'true');
+    });
+    test('compare properly against other enums', () async {
+      await driver.check(
+          breakpointId: 'bp',
+          expression: 'e != E2.id_string && E.id_string != E2.id_string',
+          expectedResult: 'true');
+    });
+    test('with instance methods', () async {
+      await driver.check(
+          breakpointId: 'bp',
+          expression: 'E.id_bool.instanceMethod()',
+          expectedResult: '42');
+    });
+    test('with instance methods from local instance', () async {
+      await driver.check(
+          breakpointId: 'bp',
+          expression: 'e.instanceMethod()',
+          expectedResult: '13');
+    });
+    test('with getters', () async {
+      await driver.check(
+          breakpointId: 'bp',
+          expression: 'E.id_int.fieldGetter',
+          expectedResult: '0');
+    });
+    test('with getters from local instance', () async {
+      await driver.check(
+          breakpointId: 'bp',
+          expression: 'e.fieldGetter',
+          expectedResult: 'hello world');
+    });
+    test('with mixin calls', () async {
+      await driver.check(
+          breakpointId: 'bp',
+          expression: 'E.id_string.mixinMethod()',
+          expectedResult: '200');
+    });
+    test('with mixin calls through overridden indices', () async {
+      await driver.check(
+          breakpointId: 'bp',
+          expression: 'E2.v2.mixinMethod()',
+          expectedResult: '1000');
+    });
+  });
 }
 
 /// Shared tests that are valid in legacy (before 2.12) and are agnostic to
diff --git a/pkg/front_end/lib/src/api_prototype/compiler_options.dart b/pkg/front_end/lib/src/api_prototype/compiler_options.dart
index 5a6fc48..3bd1f30 100644
--- a/pkg/front_end/lib/src/api_prototype/compiler_options.dart
+++ b/pkg/front_end/lib/src/api_prototype/compiler_options.dart
@@ -19,6 +19,7 @@
 import '../base/nnbd_mode.dart';
 
 import '../fasta/kernel/macro.dart';
+import '../macro_serializer.dart';
 import 'experimental_flags.dart'
     show
         AllowedExperimentalFlags,
@@ -137,7 +138,7 @@
   /// by the macro executor provided by [macroExecutorProvider].
   ///
   /// This is part of the experimental macro feature.
-  Future<Uri> Function(Component)? macroSerializer;
+  MacroSerializer? macroSerializer;
 
   /// Whether to generate code for the SDK.
   ///
diff --git a/pkg/front_end/lib/src/isolate_macro_serializer.dart b/pkg/front_end/lib/src/isolate_macro_serializer.dart
new file mode 100644
index 0000000..ef98905
--- /dev/null
+++ b/pkg/front_end/lib/src/isolate_macro_serializer.dart
@@ -0,0 +1,33 @@
+// 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.
+
+import 'dart:isolate';
+
+import 'package:kernel/kernel.dart';
+import 'macro_serializer.dart';
+
+/// [MacroSerializer] that uses blobs registered with the current [Isolate] to
+/// give access to precompiled macro [Component]s.
+///
+/// This can only be used with the [Isolate]-based macro executor.
+class IsolateMacroSerializer implements MacroSerializer {
+  final List<Uri> _createdUris = [];
+
+  @override
+  Future<void> close() {
+    for (Uri uri in _createdUris) {
+      (Isolate.current as dynamic).unregisterKernelBlobUri(uri);
+    }
+    _createdUris.clear();
+    return new Future.value();
+  }
+
+  @override
+  Future<Uri> createUriForComponent(Component component) {
+    Uri uri = (Isolate.current as dynamic)
+        .createUriForKernelBlob(writeComponentToBytes(component));
+    _createdUris.add(uri);
+    return new Future.value(uri);
+  }
+}
diff --git a/pkg/front_end/lib/src/kernel_generator_impl.dart b/pkg/front_end/lib/src/kernel_generator_impl.dart
index 8801b72..dc552e1 100644
--- a/pkg/front_end/lib/src/kernel_generator_impl.dart
+++ b/pkg/front_end/lib/src/kernel_generator_impl.dart
@@ -303,8 +303,8 @@
   precompilationOptions..fileSystem = new HybridFileSystem(fs);
   CompilerResult? compilerResult =
       await kernelForProgramInternal(uri, precompilationOptions);
-  Uri precompiledUri =
-      await options.macroSerializer!(compilerResult!.component!);
+  Uri precompiledUri = await options.macroSerializer!
+      .createUriForComponent(compilerResult!.component!);
   Map<MacroClass, Uri> precompiledMacroUris =
       options.precompiledMacroUris ??= {};
   neededPrecompilations.macroDeclarations
diff --git a/pkg/front_end/lib/src/macro_serializer.dart b/pkg/front_end/lib/src/macro_serializer.dart
new file mode 100644
index 0000000..a8e7ba7
--- /dev/null
+++ b/pkg/front_end/lib/src/macro_serializer.dart
@@ -0,0 +1,18 @@
+// 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.
+
+import 'package:kernel/ast.dart';
+
+/// Interface for supporting serialization of [Component]s for macro
+/// precompilation.
+abstract class MacroSerializer {
+  /// Returns a [Uri] that can be accessed by the macro executor.
+  Future<Uri> createUriForComponent(Component component);
+
+  /// Releases all resources of this serializer.
+  ///
+  /// This must be called when the [Uri]s created by [createUriForComponent]
+  /// are no longer needed.
+  Future<void> close();
+}
diff --git a/pkg/front_end/lib/src/temp_dir_macro_serializer.dart b/pkg/front_end/lib/src/temp_dir_macro_serializer.dart
new file mode 100644
index 0000000..c1630c8
--- /dev/null
+++ b/pkg/front_end/lib/src/temp_dir_macro_serializer.dart
@@ -0,0 +1,43 @@
+// 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.
+
+import 'dart:io';
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/kernel.dart';
+
+import 'fasta/kernel/utils.dart';
+import 'macro_serializer.dart';
+
+/// [MacroSerializer] that uses .dill files stored in a temporary directory to
+/// provided [Uri]s for precompiled macro [Component]s.
+///
+/// This can be used other with the isolate and process based macro executors.
+class TempDirMacroSerializer implements MacroSerializer {
+  final String? name;
+  Directory? tempDirectory;
+  int precompiledCount = 0;
+
+  TempDirMacroSerializer([this.name]);
+
+  Future<Directory> _ensureDirectory() async {
+    return tempDirectory ??= await Directory.systemTemp.createTemp(name);
+  }
+
+  @override
+  Future<Uri> createUriForComponent(Component component) async {
+    Directory directory = await _ensureDirectory();
+    Uri uri =
+        directory.absolute.uri.resolve('macros${precompiledCount++}.dill');
+    await writeComponentToFile(component, uri);
+    return uri;
+  }
+
+  @override
+  Future<void> close() async {
+    try {
+      await tempDirectory?.delete(recursive: true);
+    } catch (_) {}
+  }
+}
diff --git a/pkg/front_end/test/macro_api_test.dart b/pkg/front_end/test/macro_api_test.dart
index c096d36..70c3503 100644
--- a/pkg/front_end/test/macro_api_test.dart
+++ b/pkg/front_end/test/macro_api_test.dart
@@ -2,29 +2,26 @@
 // 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.
 
-import 'dart:io' show Directory, Platform;
+import 'dart:io' show Platform;
 
-import 'package:_fe_analyzer_shared/src/macros/executor/serialization.dart';
 import 'package:_fe_analyzer_shared/src/macros/executor/isolated_executor.dart'
     as isolatedExecutor;
+import 'package:_fe_analyzer_shared/src/macros/executor/serialization.dart';
 import 'package:expect/expect.dart';
 import 'package:front_end/src/api_prototype/experimental_flags.dart';
 import 'package:front_end/src/api_prototype/front_end.dart';
 import 'package:front_end/src/compute_platform_binaries_location.dart';
 import 'package:front_end/src/fasta/kernel/macro.dart';
-import 'package:front_end/src/fasta/kernel/utils.dart';
+import 'package:front_end/src/isolate_macro_serializer.dart';
+import 'package:front_end/src/macro_serializer.dart';
 import 'package:front_end/src/testing/id_testing_helper.dart';
-import 'package:kernel/ast.dart' hide Arguments;
-import 'package:kernel/kernel.dart';
 import 'package:kernel/target/targets.dart';
 import 'package:vm/target/vm.dart';
 
 Future<void> main(List<String> args) async {
   enableMacros = true;
 
-  Directory tempDirectory =
-      await Directory.systemTemp.createTemp('macro_api_test');
-  int precompiledCount = 0;
+  MacroSerializer macroSerializer = new IsolateMacroSerializer();
   try {
     CompilerOptions options = new CompilerOptions();
     options.sdkRoot = computePlatformBinariesLocation();
@@ -37,12 +34,7 @@
     };
     options.precompiledMacroUris = {};
     options.target = options.macroTarget = new VmTarget(new TargetFlags());
-    options.macroSerializer = (Component component) async {
-      Uri uri = tempDirectory.absolute.uri
-          .resolve('macros${precompiledCount++}.dill');
-      await writeComponentToFile(component, uri);
-      return uri;
-    };
+    options.macroSerializer = macroSerializer;
 
     InternalCompilerResult result = await kernelForProgramInternal(
         Platform.script.resolve(
@@ -51,6 +43,6 @@
         retainDataForTesting: true) as InternalCompilerResult;
     Expect.isFalse(result.kernelTargetForTesting!.loader.hasSeenError);
   } finally {
-    await tempDirectory.delete(recursive: true);
+    await macroSerializer.close();
   }
 }
diff --git a/pkg/front_end/test/macro_application/macro_application_test.dart b/pkg/front_end/test/macro_application/macro_application_test.dart
index 4974822..3b988bb 100644
--- a/pkg/front_end/test/macro_application/macro_application_test.dart
+++ b/pkg/front_end/test/macro_application/macro_application_test.dart
@@ -17,9 +17,10 @@
 import 'package:front_end/src/fasta/builder/field_builder.dart';
 import 'package:front_end/src/fasta/builder/member_builder.dart';
 import 'package:front_end/src/fasta/kernel/macro.dart';
-import 'package:front_end/src/fasta/kernel/utils.dart';
 import 'package:front_end/src/fasta/source/source_class_builder.dart';
 import 'package:front_end/src/fasta/source/source_library_builder.dart';
+import 'package:front_end/src/macro_serializer.dart';
+import 'package:front_end/src/temp_dir_macro_serializer.dart';
 import 'package:front_end/src/testing/compiler_common.dart';
 import 'package:front_end/src/testing/id_extractor.dart';
 import 'package:front_end/src/testing/id_testing_helper.dart';
@@ -36,8 +37,8 @@
   bool generateExpectations = args.contains('-g');
   enableMacros = true;
 
-  Directory tempDirectory =
-      await Directory.systemTemp.createTemp('macro_application');
+  MacroSerializer macroSerializer =
+      new TempDirMacroSerializer('macro_application');
   try {
     Directory dataDir =
         new Directory.fromUri(Platform.script.resolve('data/tests'));
@@ -46,23 +47,22 @@
         createUriForFileName: createUriForFileName,
         onFailure: onFailure,
         runTest: runTestFor(const MacroDataComputer(), [
-          new MacroTestConfig(dataDir, tempDirectory,
+          new MacroTestConfig(dataDir, macroSerializer,
               generateExpectations: generateExpectations)
         ]),
         preserveWhitespaceInAnnotations: true);
   } finally {
-    await tempDirectory.delete(recursive: true);
+    await macroSerializer.close();
   }
 }
 
 class MacroTestConfig extends TestConfig {
   final Directory dataDir;
-  final Directory tempDirectory;
+  final MacroSerializer macroSerializer;
   final bool generateExpectations;
-  int precompiledCount = 0;
   final Map<MacroClass, Uri> precompiledMacroUris = {};
 
-  MacroTestConfig(this.dataDir, this.tempDirectory,
+  MacroTestConfig(this.dataDir, this.macroSerializer,
       {required this.generateExpectations})
       : super(cfeMarker, 'cfe',
             explicitExperimentalFlags: {ExperimentalFlag.macros: true},
@@ -76,12 +76,7 @@
     };
     options.precompiledMacroUris = precompiledMacroUris;
     options.macroTarget = new VmTarget(new TargetFlags());
-    options.macroSerializer = (Component component) async {
-      Uri uri = tempDirectory.absolute.uri
-          .resolve('macros${precompiledCount++}.dill');
-      await writeComponentToFile(component, uri);
-      return uri;
-    };
+    options.macroSerializer = macroSerializer;
   }
 
   @override
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index e4445e6..cc0957e 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -123,6 +123,7 @@
 bk
 blindly
 blob
+blobs
 blocking
 bmp
 bn
@@ -1393,6 +1394,7 @@
 unpleasant
 unqualified
 unreachable
+unregister
 unseen
 unset
 unshadowed
diff --git a/pkg/kernel/lib/kernel.dart b/pkg/kernel/lib/kernel.dart
index 9433890..e5787d9 100644
--- a/pkg/kernel/lib/kernel.dart
+++ b/pkg/kernel/lib/kernel.dart
@@ -13,6 +13,8 @@
 ///
 library kernel;
 
+import 'dart:typed_data';
+
 import 'ast.dart';
 import 'binary/ast_to_binary.dart';
 import 'binary/ast_from_binary.dart';
@@ -61,7 +63,7 @@
   return future;
 }
 
-List<int> writeComponentToBytes(Component component) {
+Uint8List writeComponentToBytes(Component component) {
   BytesSink sink = new BytesSink();
   new BinaryPrinter(sink).writeComponentFile(component);
   return sink.builder.toBytes();
diff --git a/pkg/wasm_builder/lib/src/instructions.dart b/pkg/wasm_builder/lib/src/instructions.dart
index 24a9556..10df25a 100644
--- a/pkg/wasm_builder/lib/src/instructions.dart
+++ b/pkg/wasm_builder/lib/src/instructions.dart
@@ -72,6 +72,15 @@
   List<ValueType> get targetTypes => outputs;
 }
 
+class Try extends Label {
+  bool hasCatch = false;
+
+  Try(List<ValueType> inputs, List<ValueType> outputs)
+      : super._(inputs, outputs);
+
+  List<ValueType> get targetTypes => outputs;
+}
+
 /// A sequence of Wasm instructions.
 ///
 /// Instructions can be added to the sequence by calling the corresponding
@@ -350,6 +359,42 @@
     writeByte(0x05);
   }
 
+  /// Emit a `try` instruction.
+  Label try_(
+      [List<ValueType> inputs = const [], List<ValueType> outputs = const []]) {
+    return _beginBlock(0x06, Try(inputs, outputs), trace: const ['try']);
+  }
+
+  /// Emit a `catch` instruction.
+  void catch_(Tag tag) {
+    assert(_topOfLabelStack is Try ||
+        _reportError("Unexpected 'catch' (not in 'try' block"));
+    final Try try_ = _topOfLabelStack as Try;
+    assert(_verifyEndOfBlock(tag.type.inputs,
+        trace: ['catch', tag], reachableAfter: try_.reachable, reindent: true));
+    try_.hasCatch = true;
+    _reachable = try_.reachable;
+    writeByte(0x07);
+    _writeTag(tag);
+  }
+
+  /// Emit a `throw` instruction.
+  void throw_(Tag tag) {
+    assert(_verifyTypes(tag.type.inputs, const [], trace: ['throw', tag]));
+    _reachable = false;
+    writeByte(0x08);
+    writeUnsigned(tag.index);
+  }
+
+  /// Emit a `rethrow` instruction.
+  void rethrow_(Label label) {
+    assert(label is Try && label.hasCatch);
+    assert(_verifyTypes(const [], const [], trace: ['rethrow', label]));
+    _reachable = false;
+    writeByte(0x09);
+    _writeLabel(label);
+  }
+
   /// Emit an `end` instruction.
   void end() {
     assert(_verifyEndOfBlock(_topOfLabelStack.outputs,
@@ -371,6 +416,10 @@
     writeUnsigned(_labelIndex(label));
   }
 
+  void _writeTag(Tag tag) {
+    writeUnsigned(tag.index);
+  }
+
   /// Emit a `br` instruction.
   void br(Label label) {
     assert(_verifyTypes(const [], const [],
diff --git a/pkg/wasm_builder/lib/src/module.dart b/pkg/wasm_builder/lib/src/module.dart
index 95ad8df..e015acf 100644
--- a/pkg/wasm_builder/lib/src/module.dart
+++ b/pkg/wasm_builder/lib/src/module.dart
@@ -20,6 +20,7 @@
   final List<BaseFunction> functions = [];
   final List<Table> tables = [];
   final List<Memory> memories = [];
+  final List<Tag> tags = [];
   final List<DataSegment> dataSegments = [];
   final List<Global> globals = [];
   final List<Export> exports = [];
@@ -124,6 +125,13 @@
     return memory;
   }
 
+  /// Add a new tag to the module.
+  Tag addTag(FunctionType type) {
+    final tag = Tag(tags.length, type);
+    tags.add(tag);
+    return tag;
+  }
+
   /// Add a new data segment to the module.
   ///
   /// Either [memory] and [offset] must be both specified or both omitted. If
@@ -213,6 +221,7 @@
     FunctionSection(this).serialize(this);
     TableSection(this).serialize(this);
     MemorySection(this).serialize(this);
+    TagSection(this).serialize(this);
     if (dataReferencedFromGlobalInitializer) {
       DataCountSection(this).serialize(this);
     }
@@ -392,6 +401,23 @@
   }
 }
 
+/// A tag in a module.
+class Tag implements Serializable {
+  final int index;
+  final FunctionType type;
+
+  Tag(this.index, this.type);
+
+  @override
+  void serialize(Serializer s) {
+    // 0 byte for exception.
+    s.writeByte(0x00);
+    s.write(type);
+  }
+
+  String toString() => "#$index";
+}
+
 /// A data segment in a module.
 class DataSegment implements Serializable {
   final int index;
@@ -642,6 +668,21 @@
   }
 }
 
+class TagSection extends Section {
+  TagSection(Module module) : super(module);
+
+  @override
+  int get id => 13;
+
+  @override
+  bool get isNotEmpty => module.tags.isNotEmpty;
+
+  @override
+  void serializeContents() {
+    writeList(module.tags);
+  }
+}
+
 class GlobalSection extends Section {
   GlobalSection(Module module) : super(module);
 
diff --git a/pkg/wasm_builder/lib/wasm_builder.dart b/pkg/wasm_builder/lib/wasm_builder.dart
index 8bf1b98..7dfeb68 100644
--- a/pkg/wasm_builder/lib/wasm_builder.dart
+++ b/pkg/wasm_builder/lib/wasm_builder.dart
@@ -14,7 +14,8 @@
         Local,
         Memory,
         Module,
-        Table;
+        Table,
+        Tag;
 export 'src/types.dart'
     show
         ArrayType,
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index f573579..3d2a0f0 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -658,7 +658,8 @@
     auto initialize_callback = Isolate::InitializeCallback();
     if (initialize_callback == nullptr) {
       FailedSpawn(
-          "Lightweight isolate spawn is not supported by this Dart embedder\n");
+          "Lightweight isolate spawn is not supported by this Dart embedder\n",
+          /*has_current_isolate=*/false);
       return;
     }
 
diff --git a/runtime/tests/vm/dart/regress_flutter98967_test.dart b/runtime/tests/vm/dart/regress_flutter98967_test.dart
new file mode 100644
index 0000000..97feb2d
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_flutter98967_test.dart
@@ -0,0 +1,53 @@
+// 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.
+
+// Regression test for https://github.com/flutter/flutter/issues/98967.
+// Verifies that compiler doesn't generate wrong code for comparison of ints
+// due to a late change in the representation of EqualityCompare inputs.
+
+import 'package:expect/expect.dart';
+
+class C {
+  int? val;
+
+  @pragma('vm:never-inline')
+  void testImpl(bool Function(int) compare) {
+    for (var i = 0; i < 2; i++) {
+      Expect.equals(false, compare(i));
+      val = i;
+      Expect.equals(true, compare(i));
+    }
+
+    final mint0 = int.parse("7fffffffffffffff", radix: 16);
+    final mint1 = int.parse("7fffffffffffffff", radix: 16);
+    if (mint0 != mint1) throw 'This is the same mint value';
+
+    Expect.equals(false, compare(mint0));
+    val = mint0;
+    Expect.equals(true, compare(mint0));
+    Expect.equals(true, compare(mint1),
+        'expected two different mints with the same value compare equal');
+  }
+
+  @pragma('vm:never-inline')
+  static void blackhole(void Function() f) {
+    f();
+  }
+
+  void test() {
+    return testImpl((v) {
+      // Note: need multiple context levels in the chain to delay
+      // optimizer forwarding load of [val] and subsequently
+      // clearing null_aware flag on the equality comparison.
+      // Hence the closure capturing [v] below.
+      final result = val != null ? val == v : false;
+      blackhole(() => v);
+      return result;
+    });
+  }
+}
+
+void main() {
+  C().test();
+}
diff --git a/runtime/tests/vm/dart/spawn_uri_from_kernel_blob_test.dart b/runtime/tests/vm/dart/spawn_uri_from_kernel_blob_test.dart
index c9c2ae6..72c8793e 100644
--- a/runtime/tests/vm/dart/spawn_uri_from_kernel_blob_test.dart
+++ b/runtime/tests/vm/dart/spawn_uri_from_kernel_blob_test.dart
@@ -8,7 +8,6 @@
 
 import 'dart:io' show Platform;
 import 'dart:isolate' show Isolate, ReceivePort;
-import 'dart:typed_data' show Uint8List;
 
 import "package:expect/expect.dart";
 import 'package:front_end/src/api_unstable/vm.dart'
@@ -33,7 +32,7 @@
     };
   final Component component =
       (await kernelForProgram(sourceUri, options))!.component!;
-  final kernelBlob = writeComponentToBytes(component) as Uint8List;
+  final kernelBlob = writeComponentToBytes(component);
 
   final kernelBlobUri =
       (Isolate.current as dynamic).createUriForKernelBlob(kernelBlob);
diff --git a/runtime/vm/compiler/backend/flow_graph.h b/runtime/vm/compiler/backend/flow_graph.h
index 2c82c13..93c832a 100644
--- a/runtime/vm/compiler/backend/flow_graph.h
+++ b/runtime/vm/compiler/backend/flow_graph.h
@@ -397,6 +397,17 @@
   // after this point.
   void disallow_licm() { licm_allowed_ = false; }
 
+  // Returns true if mismatch in input/output representations is allowed.
+  bool unmatched_representations_allowed() const {
+    return unmatched_representations_allowed_;
+  }
+
+  // After the last SelectRepresentations pass all further transformations
+  // should maintain matching input/output representations.
+  void disallow_unmatched_representations() {
+    unmatched_representations_allowed_ = false;
+  }
+
   PrologueInfo prologue_info() const { return prologue_info_; }
 
   // Computes the loop hierarchy of the flow graph on demand.
@@ -623,6 +634,7 @@
   ConstantInstr* constant_dead_;
 
   bool licm_allowed_;
+  bool unmatched_representations_allowed_ = true;
 
   const PrologueInfo prologue_info_;
 
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 8991d8d..256e184 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -3460,7 +3460,11 @@
       flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue);
       return replacement;
     } else {
-      if (!left_type->is_nullable() && !right_type->is_nullable()) {
+      // Null-aware EqualityCompare takes boxed inputs, so make sure
+      // unmatched representations are still allowed when converting
+      // EqualityCompare to the unboxed instruction.
+      if (!left_type->is_nullable() && !right_type->is_nullable() &&
+          flow_graph->unmatched_representations_allowed()) {
         set_null_aware(false);
       }
     }
diff --git a/runtime/vm/compiler/backend/il_test.cc b/runtime/vm/compiler/backend/il_test.cc
index 30502a4..d29658c 100644
--- a/runtime/vm/compiler/backend/il_test.cc
+++ b/runtime/vm/compiler/backend/il_test.cc
@@ -390,6 +390,49 @@
   }
 }
 
+static void TestNullAwareEqualityCompareCanonicalization(
+    Thread* thread,
+    bool allow_representation_change) {
+  using compiler::BlockBuilder;
+
+  CompilerState S(thread, /*is_aot=*/true, /*is_optimizing=*/true);
+
+  FlowGraphBuilderHelper H;
+
+  auto normal_entry = H.flow_graph()->graph_entry()->normal_entry();
+
+  EqualityCompareInstr* compare = nullptr;
+  {
+    BlockBuilder builder(H.flow_graph(), normal_entry);
+    Definition* v0 =
+        builder.AddParameter(0, 0, /*with_frame=*/true, kUnboxedInt64);
+    Definition* v1 =
+        builder.AddParameter(1, 1, /*with_frame=*/true, kUnboxedInt64);
+    Definition* box0 = builder.AddDefinition(new BoxInt64Instr(new Value(v0)));
+    Definition* box1 = builder.AddDefinition(new BoxInt64Instr(new Value(v1)));
+
+    compare = builder.AddDefinition(new EqualityCompareInstr(
+        InstructionSource(), Token::kEQ, new Value(box0), new Value(box1),
+        kMintCid, S.GetNextDeoptId(), /*null_aware=*/true));
+    builder.AddReturn(new Value(compare));
+  }
+
+  H.FinishGraph();
+
+  if (!allow_representation_change) {
+    H.flow_graph()->disallow_unmatched_representations();
+  }
+
+  H.flow_graph()->Canonicalize();
+
+  EXPECT(compare->is_null_aware() == !allow_representation_change);
+}
+
+ISOLATE_UNIT_TEST_CASE(IL_Canonicalize_EqualityCompare) {
+  TestNullAwareEqualityCompareCanonicalization(thread, true);
+  TestNullAwareEqualityCompareCanonicalization(thread, false);
+}
+
 static void WriteCidRangeVectorTo(const CidRangeVector& ranges,
                                   BaseTextBuffer* buffer) {
   if (ranges.is_empty()) {
diff --git a/runtime/vm/compiler/compiler_pass.cc b/runtime/vm/compiler/compiler_pass.cc
index 1faa8d3..33079e7 100644
--- a/runtime/vm/compiler/compiler_pass.cc
+++ b/runtime/vm/compiler/compiler_pass.cc
@@ -309,7 +309,7 @@
   INVOKE_PASS(ConstantPropagation);
   INVOKE_PASS(TypePropagation);
   INVOKE_PASS(WidenSmiToInt32);
-  INVOKE_PASS(SelectRepresentations);
+  INVOKE_PASS(SelectRepresentations_Final);
   INVOKE_PASS(TypePropagation);
   INVOKE_PASS(TryCatchOptimization);
   INVOKE_PASS(EliminateEnvironments);
@@ -380,7 +380,7 @@
   INVOKE_PASS(EliminateDeadPhis);
   INVOKE_PASS(DCE);
   INVOKE_PASS(TypePropagation);
-  INVOKE_PASS(SelectRepresentations);
+  INVOKE_PASS(SelectRepresentations_Final);
   INVOKE_PASS(Canonicalize);
   INVOKE_PASS(UseTableDispatch);
   INVOKE_PASS(EliminateStackOverflowChecks);
@@ -469,6 +469,13 @@
   flow_graph->SelectRepresentations();
 });
 
+COMPILER_PASS(SelectRepresentations_Final, {
+  // Final selection of representations. After this pass
+  // representations of inputs/outputs should match.
+  flow_graph->SelectRepresentations();
+  flow_graph->disallow_unmatched_representations();
+});
+
 COMPILER_PASS(UseTableDispatch, {
   state->call_specializer->ReplaceInstanceCallsWithDispatchTableCalls();
 });
diff --git a/runtime/vm/compiler/compiler_pass.h b/runtime/vm/compiler/compiler_pass.h
index 01a7194..bac28af 100644
--- a/runtime/vm/compiler/compiler_pass.h
+++ b/runtime/vm/compiler/compiler_pass.h
@@ -46,6 +46,7 @@
   V(RangeAnalysis)                                                             \
   V(ReorderBlocks)                                                             \
   V(SelectRepresentations)                                                     \
+  V(SelectRepresentations_Final)                                               \
   V(SetOuterInliningId)                                                        \
   V(TryCatchOptimization)                                                      \
   V(TryOptimizePatterns)                                                       \
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index 48fbd5f..6c7c909 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -1704,21 +1704,23 @@
                                        intptr_t growth_in_pages,
                                        const char* reason) {
   // Save final threshold compared before growing.
-  hard_gc_threshold_in_words_ =
+  intptr_t threshold =
       after.CombinedUsedInWords() + (kOldPageSizeInWords * growth_in_pages);
 
+#if defined(TARGET_ARCH_IA32)
+  // No concurrent marking.
+  soft_gc_threshold_in_words_ = threshold;
+  hard_gc_threshold_in_words_ = threshold;
+#else
   // Start concurrent marking when old-space has less than half of new-space
   // available or less than 5% available.
-#if defined(TARGET_ARCH_IA32)
-  const intptr_t headroom = 0;  // No concurrent marking.
-#else
   // Note that heap_ can be null in some unit tests.
   const intptr_t new_space =
       heap_ == nullptr ? 0 : heap_->new_space()->CapacityInWords();
-  const intptr_t headroom =
-      Utils::Maximum(new_space / 2, hard_gc_threshold_in_words_ / 20);
+  const intptr_t headroom = Utils::Maximum(new_space / 2, threshold / 20);
+  soft_gc_threshold_in_words_ = threshold;
+  hard_gc_threshold_in_words_ = threshold + headroom;
 #endif
-  soft_gc_threshold_in_words_ = hard_gc_threshold_in_words_ - headroom;
 
   // Set a tight idle threshold.
   idle_gc_threshold_in_words_ =
diff --git a/runtime/vm/isolate_test.cc b/runtime/vm/isolate_test.cc
index 2b8afac..0a53fbb 100644
--- a/runtime/vm/isolate_test.cc
+++ b/runtime/vm/isolate_test.cc
@@ -22,11 +22,13 @@
 
 // Test to ensure that an exception is thrown if no isolate creation
 // callback has been set by the embedder when an isolate is spawned.
-TEST_CASE(IsolateSpawn) {
-  const char* kScriptChars =
+void IsolateSpawn(const char* platform_script_value) {
+  const char* kScriptChars = OS::SCreate(
+      nullptr,
       "import 'dart:isolate';\n"
       // Ignores printed lines.
       "var _nullPrintClosure = (String line) {};\n"
+      "var _platformScript = () => Uri.parse(\"%s\");\n"
       "void entry(message) {}\n"
       "void testMain() {\n"
       "  Isolate.spawn(entry, null);\n"
@@ -35,7 +37,8 @@
       "  var rp = RawReceivePort();\n"
       "  rp.sendPort.send(null);\n"
       "  rp.handler = (_) { rp.close(); };\n"
-      "}\n";
+      "}\n",
+      platform_script_value);
 
   Dart_Handle test_lib = TestCase::LoadTestScript(kScriptChars, NULL);
 
@@ -47,9 +50,19 @@
   Dart_Handle internal_lib = Dart_LookupLibrary(url);
   EXPECT_VALID(internal_lib);
   Dart_Handle print = Dart_GetField(test_lib, NewString("_nullPrintClosure"));
+  EXPECT_VALID(print);
   Dart_Handle result =
       Dart_SetField(internal_lib, NewString("_printClosure"), print);
+  EXPECT_VALID(result);
 
+  Dart_Handle platform_script =
+      Dart_GetField(test_lib, NewString("_platformScript"));
+  EXPECT_VALID(platform_script);
+  Dart_Handle vmlibraryhooks_class =
+      Dart_GetClass(internal_lib, NewString("VMLibraryHooks"));
+  EXPECT_VALID(vmlibraryhooks_class);
+  result = Dart_SetField(vmlibraryhooks_class, NewString("platformScript"),
+                         platform_script);
   EXPECT_VALID(result);
 
   // Setup the 'scheduleImmediate' closure.
@@ -72,12 +85,22 @@
   EXPECT_VALID(result);
   // Run until all ports to isolate are closed.
   result = Dart_RunLoop();
-  EXPECT_ERROR(result, "Unsupported operation: Isolate.spawn");
+  EXPECT_ERROR(
+      result,
+      "Lightweight isolate spawn is not supported by this Dart embedder");
   EXPECT(Dart_ErrorHasException(result));
   Dart_Handle exception_result = Dart_ErrorGetException(result);
   EXPECT_VALID(exception_result);
 }
 
+TEST_CASE(IsolateSpawn_FileUri) {
+  IsolateSpawn("file:/a.dart");
+}
+
+TEST_CASE(IsolateSpawn_PackageUri) {
+  IsolateSpawn("package:/a.dart");
+}
+
 class InterruptChecker : public ThreadPool::Task {
  public:
   static const intptr_t kTaskCount;
diff --git a/sdk/lib/_internal/vm/lib/isolate_patch.dart b/sdk/lib/_internal/vm/lib/isolate_patch.dart
index 34df646..4e7b164 100644
--- a/sdk/lib/_internal/vm/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/vm/lib/isolate_patch.dart
@@ -366,7 +366,11 @@
       throw new UnsupportedError("Isolate.spawn");
     }
     if (script.isScheme("package")) {
-      script = await Isolate.resolvePackageUri(script);
+      if (Isolate._packageSupported()) {
+        // resolving script uri is not really neccessary, but can be useful
+        // for better failed-to-lookup-function-in-a-script spawn errors.
+        script = await Isolate.resolvePackageUri(script);
+      }
     }
 
     final RawReceivePort readyPort =
diff --git a/sdk/lib/_internal/wasm/lib/stack_trace_patch.dart b/sdk/lib/_internal/wasm/lib/stack_trace_patch.dart
new file mode 100644
index 0000000..4e43fa0
--- /dev/null
+++ b/sdk/lib/_internal/wasm/lib/stack_trace_patch.dart
@@ -0,0 +1,15 @@
+// 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.
+
+@pragma("wasm:import", "dart2wasm.getCurrentStackTrace")
+external String _getCurrentStackTrace();
+
+@patch
+class StackTrace {
+  @patch
+  @pragma("wasm:entry-point")
+  static StackTrace get current {
+    return _StringStackTrace(_getCurrentStackTrace());
+  }
+}
diff --git a/sdk/lib/libraries.json b/sdk/lib/libraries.json
index 4db66c7..619c1c0 100644
--- a/sdk/lib/libraries.json
+++ b/sdk/lib/libraries.json
@@ -204,6 +204,7 @@
           "_internal/vm/lib/null_patch.dart",
           "_internal/vm/lib/map_patch.dart",
           "_internal/wasm/lib/object_patch.dart",
+          "_internal/wasm/lib/stack_trace_patch.dart",
           "_internal/wasm/lib/string_buffer_patch.dart",
           "_internal/wasm/lib/string_patch.dart",
           "_internal/wasm/lib/type.dart"
diff --git a/sdk/lib/libraries.yaml b/sdk/lib/libraries.yaml
index 1730d5d..055f5e8 100644
--- a/sdk/lib/libraries.yaml
+++ b/sdk/lib/libraries.yaml
@@ -196,6 +196,7 @@
       - _internal/vm/lib/null_patch.dart
       - _internal/vm/lib/map_patch.dart
       - _internal/wasm/lib/object_patch.dart
+      - _internal/wasm/lib/stack_trace_patch.dart
       - _internal/wasm/lib/string_buffer_patch.dart
       - _internal/wasm/lib/string_patch.dart
       - _internal/wasm/lib/type.dart
diff --git a/tools/VERSION b/tools/VERSION
index 4038bc6..827ebec 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 148
+PRERELEASE 149
 PRERELEASE_PATCH 0
\ No newline at end of file