[roll] Update third-party dart packages

Roller-URL: https://ci.chromium.org/b/8788661818094425073
Roller-Owners: flutter-on-fuchsia-team@google.com, godofredoc@google.com
CQ-Do-Not-Cancel-Tryjobs: true
Change-Id: Ib667541795fa684605dcb68950dd7cc1e37779fd
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/dart-pkg/+/806548
Commit-Queue: GI Roller <global-integration-roller@fuchsia-infra.iam.gserviceaccount.com>
diff --git a/_fe_analyzer_shared/BUILD.gn b/_fe_analyzer_shared/BUILD.gn
index 0b72536..f1b34d3 100644
--- a/_fe_analyzer_shared/BUILD.gn
+++ b/_fe_analyzer_shared/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by package_importer.py for _fe_analyzer_shared-52.0.0
+# This file is generated by package_importer.py for _fe_analyzer_shared-53.0.0
 
 import("//build/dart/dart_library.gni")
 
@@ -25,7 +25,9 @@
     "src/exhaustiveness/profile.dart",
     "src/exhaustiveness/space.dart",
     "src/exhaustiveness/static_type.dart",
+    "src/exhaustiveness/static_types.dart",
     "src/exhaustiveness/subtract.dart",
+    "src/exhaustiveness/test_helper.dart",
     "src/experiments/errors.dart",
     "src/experiments/flags.dart",
     "src/flow_analysis/factory_type_test_helper.dart",
@@ -86,7 +88,6 @@
     "src/parser/type_info.dart",
     "src/parser/type_info_impl.dart",
     "src/parser/util.dart",
-    "src/parser/value_kind.dart",
     "src/scanner/abstract_scanner.dart",
     "src/scanner/characters.dart",
     "src/scanner/error_token.dart",
@@ -123,9 +124,12 @@
     "src/util/libraries_specification.dart",
     "src/util/link.dart",
     "src/util/link_implementation.dart",
+    "src/util/null_value.dart",
     "src/util/options.dart",
     "src/util/relativize.dart",
     "src/util/resolve_input_uri.dart",
     "src/util/resolve_relative_uri.dart",
+    "src/util/stack_checker.dart",
+    "src/util/value_kind.dart",
   ]
 }
diff --git a/_fe_analyzer_shared/analysis_options_no_lints.yaml b/_fe_analyzer_shared/analysis_options_no_lints.yaml
index 310a360..8aede22 100644
--- a/_fe_analyzer_shared/analysis_options_no_lints.yaml
+++ b/_fe_analyzer_shared/analysis_options_no_lints.yaml
@@ -9,6 +9,7 @@
   exclude:
     - test/constants/data/**
     - test/constants/data_2/**
+    - test/exhaustiveness/data/**
     - test/flow_analysis/assigned_variables/data/**
     - test/flow_analysis/definite_assignment/data/**
     - test/flow_analysis/definite_unassignment/data/**
diff --git a/_fe_analyzer_shared/lib/src/exhaustiveness/exhaustive.dart b/_fe_analyzer_shared/lib/src/exhaustiveness/exhaustive.dart
index 17fbf9f..51d7f56 100644
--- a/_fe_analyzer_shared/lib/src/exhaustiveness/exhaustive.dart
+++ b/_fe_analyzer_shared/lib/src/exhaustiveness/exhaustive.dart
@@ -24,8 +24,9 @@
 /// Returns a string containing any unreachable case or non-exhaustive match
 /// errors. Returns an empty string if all cases are reachable and the cases
 /// are exhaustive.
-String reportErrors(StaticType valueType, List<Space> cases) {
-  List<String> errors = <String>[];
+List<ExhaustivenessError> reportErrors(StaticType valueType, List<Space> cases,
+    [List<Space>? remainingSpaces]) {
+  List<ExhaustivenessError> errors = <ExhaustivenessError>[];
 
   Space remaining = new Space(valueType);
   for (int i = 0; i < cases.length; i++) {
@@ -33,17 +34,45 @@
     if (i > 0) {
       Space previous = new Space.union(cases.sublist(0, i));
       if (subtract(cases[i], previous) == Space.empty) {
-        errors.add('Case #${i + 1} ${cases[i]} is covered by $previous.');
+        errors.add(new UnreachableCaseError(valueType, cases, i, previous));
       }
     }
 
+    remainingSpaces?.add(remaining);
     remaining = subtract(remaining, cases[i]);
   }
+  remainingSpaces?.add(remaining);
 
   if (remaining != Space.empty) {
-    errors.add(
-        '$valueType is not exhaustively matched by ${new Space.union(cases)}.');
+    errors.add(new NonExhaustiveError(valueType, cases, remaining));
   }
 
-  return errors.join('\n');
+  return errors;
+}
+
+class ExhaustivenessError {}
+
+class NonExhaustiveError implements ExhaustivenessError {
+  final StaticType valueType;
+  final List<Space> cases;
+  final Space remaining;
+
+  NonExhaustiveError(this.valueType, this.cases, this.remaining);
+
+  @override
+  String toString() =>
+      '$valueType is not exhaustively matched by ${new Space.union(cases)}.';
+}
+
+class UnreachableCaseError implements ExhaustivenessError {
+  final StaticType valueType;
+  final List<Space> cases;
+  final int index;
+  final Space previous;
+
+  UnreachableCaseError(this.valueType, this.cases, this.index, this.previous);
+
+  @override
+  String toString() =>
+      'Case #${index + 1} ${cases[index]} is covered by $previous.';
 }
diff --git a/_fe_analyzer_shared/lib/src/exhaustiveness/space.dart b/_fe_analyzer_shared/lib/src/exhaustiveness/space.dart
index 19fa478..b962aec 100644
--- a/_fe_analyzer_shared/lib/src/exhaustiveness/space.dart
+++ b/_fe_analyzer_shared/lib/src/exhaustiveness/space.dart
@@ -76,6 +76,9 @@
   /// The space containing everything.
   static final Space top = new Space(StaticType.nullableObject);
 
+  /// The space containing only `null`.
+  static final Space nullSpace = new Space(StaticType.nullType);
+
   factory Space(StaticType type, [Map<String, Space> fields = const {}]) =>
       new ExtractSpace._(type, fields);
 
diff --git a/_fe_analyzer_shared/lib/src/exhaustiveness/static_types.dart b/_fe_analyzer_shared/lib/src/exhaustiveness/static_types.dart
new file mode 100644
index 0000000..04a9dd3
--- /dev/null
+++ b/_fe_analyzer_shared/lib/src/exhaustiveness/static_types.dart
@@ -0,0 +1,452 @@
+// 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:_fe_analyzer_shared/src/exhaustiveness/static_type.dart';
+
+/// Interface implemented by analyze/CFE to support type operations need for the
+/// shared [StaticType]s.
+abstract class TypeOperations<Type extends Object> {
+  /// Returns the type for `Object`.
+  Type get nullableObjectType;
+
+  /// Returns `true` if [s] is a subtype of [t].
+  bool isSubtypeOf(Type s, Type t);
+
+  /// Returns `true` if [type] is a potentially nullable type.
+  bool isNullable(Type type);
+
+  /// Returns the non-nullable type corresponding to [type]. For instance
+  /// `Foo` for `Foo?`. If [type] is already non-nullable, it itself is
+  /// returned.
+  Type getNonNullable(Type type);
+
+  /// Returns `true` if [type] is the `Null` type.
+  bool isNullType(Type type);
+
+  /// Returns `true` if [type] is the `Never` type.
+  bool isNeverType(Type type);
+
+  /// Returns `true` if [type] is the `Object?` type.
+  bool isNullableObject(Type type);
+
+  /// Returns `true` if [type] is the `Object` type.
+  bool isNonNullableObject(Type type);
+
+  /// Returns `true` if [type] is the `bool` type.
+  bool isBoolType(Type type);
+
+  /// Returns the `bool` type.
+  Type get boolType;
+
+  /// Returns a map of the field names and corresponding types available on
+  /// [type]. For an interface type, these are the fields and getters, and for
+  /// record types these are the record fields.
+  Map<String, Type> getFieldTypes(Type type);
+
+  /// Returns a human-readable representation of the [type].
+  String typeToString(Type type);
+}
+
+/// Interface implemented by analyzer/CFE to support [StaticType]s for enums.
+abstract class EnumOperations<Type extends Object, EnumClass extends Object,
+    EnumElement extends Object, EnumElementValue extends Object> {
+  /// Returns the enum class declaration for the [type] or `null` if
+  /// [type] is not an enum type.
+  EnumClass? getEnumClass(Type type);
+
+  /// Returns the enum elements defined by [enumClass].
+  Iterable<EnumElement> getEnumElements(EnumClass enumClass);
+
+  /// Returns the value defined by the [enumElement]. The encoding is specific
+  /// the implementation of this interface but must ensure constant value
+  /// identity.
+  EnumElementValue getEnumElementValue(EnumElement enumElement);
+
+  /// Returns the declared name of the [enumElement].
+  String getEnumElementName(EnumElement enumElement);
+
+  /// Returns the static type of the [enumElement].
+  Type getEnumElementType(EnumElement enumElement);
+}
+
+/// Interface implemented by analyzer/CFE to support [StaticType]s for sealed
+/// classes.
+abstract class SealedClassOperations<Type extends Object,
+    Class extends Object> {
+  /// Returns the sealed class declaration for [type] or `null` if [type] is not
+  /// a sealed class type.
+  Class? getSealedClass(Type type);
+
+  /// Returns the direct subclasses of [sealedClass] that either extend,
+  /// implement or mix it in.
+  List<Class> getDirectSubclasses(Class sealedClass);
+
+  /// Returns the instance of [subClass] that implements [sealedClassType].
+  ///
+  /// `null` might be returned if [subClass] cannot implement [sealedClassType].
+  /// For instance
+  ///
+  ///     sealed class A<T> {}
+  ///     class B<T> extends A<T> {}
+  ///     class C extends A<int> {}
+  ///
+  /// here `C` has no implementation of `A<String>`.
+  ///
+  /// It is assumed that `TypeOperations.isSealedClass` is `true` for
+  /// [sealedClassType] and that [subClass] is in `getDirectSubclasses` for
+  /// `getSealedClass` of [sealedClassType].
+  ///
+  // TODO(johnniwinther): What should this return for generic types?
+  Type? getSubclassAsInstanceOf(Class subClass, Type sealedClassType);
+}
+
+/// Interface for looking up fields and their corresponding [StaticType]s of
+/// a given type.
+abstract class FieldLookup<Type extends Object> {
+  /// Returns a map of the field names and corresponding [StaticType]s available
+  /// on [type]. For an interface type, these are the fields and getters, and
+  /// for record types these are the record fields.
+  Map<String, StaticType> getFieldTypes(Type type);
+}
+
+/// Cache used for computing [StaticType]s used for exhaustiveness checking.
+///
+/// This implementation is shared between analyzer and CFE, and implemented
+/// using the analyzer/CFE implementations of [TypeOperations],
+/// [EnumOperations], and [SealedClassOperations].
+class ExhaustivenessCache<
+    Type extends Object,
+    Class extends Object,
+    EnumClass extends Object,
+    EnumElement extends Object,
+    EnumElementValue extends Object> implements FieldLookup<Type> {
+  final TypeOperations<Type> _typeOperations;
+  final EnumOperations<Type, EnumClass, EnumElement, EnumElementValue>
+      enumOperations;
+  final SealedClassOperations<Type, Class> _sealedClassOperations;
+
+  /// Cache for [EnumInfo] for enum classes.
+  Map<EnumClass, EnumInfo<Type, EnumClass, EnumElement, EnumElementValue>>
+      _enumInfo = {};
+
+  /// Cache for [SealedClassInfo] for sealed classes.
+  Map<Class, SealedClassInfo<Type, Class>> _sealedClassInfo = {};
+
+  /// Cache for [UniqueStaticType]s.
+  Map<Object, StaticType> _uniqueTypeMap = {};
+
+  /// Cache for the [StaticType] for `bool`.
+  late BoolStaticType _boolStaticType =
+      new BoolStaticType(_typeOperations, this, _typeOperations.boolType);
+
+  /// Cache for [StaticType]s for fields available on a [Type].
+  Map<Type, Map<String, StaticType>> _fieldCache = {};
+
+  ExhaustivenessCache(
+      this._typeOperations, this.enumOperations, this._sealedClassOperations);
+
+  /// Returns the [EnumInfo] for [enumClass].
+  EnumInfo<Type, EnumClass, EnumElement, EnumElementValue> _getEnumInfo(
+      EnumClass enumClass) {
+    return _enumInfo[enumClass] ??=
+        new EnumInfo(_typeOperations, this, enumOperations, enumClass);
+  }
+
+  /// Returns the [SealedClassInfo] for [sealedClass].
+  SealedClassInfo<Type, Class> _getSealedClassInfo(Class sealedClass) {
+    return _sealedClassInfo[sealedClass] ??=
+        new SealedClassInfo(_sealedClassOperations, sealedClass);
+  }
+
+  /// Returns the [StaticType] for the boolean [value].
+  StaticType getBoolValueStaticType(bool value) {
+    return value ? _boolStaticType.trueType : _boolStaticType.falseType;
+  }
+
+  /// Returns the [StaticType]  for [type].
+  StaticType getStaticType(Type type) {
+    if (_typeOperations.isNeverType(type)) {
+      return StaticType.neverType;
+    } else if (_typeOperations.isNullType(type)) {
+      return StaticType.nullType;
+    } else if (_typeOperations.isNonNullableObject(type)) {
+      return StaticType.nonNullableObject;
+    } else if (_typeOperations.isNullableObject(type)) {
+      return StaticType.nullableObject;
+    }
+
+    StaticType staticType;
+    Type nonNullable = _typeOperations.getNonNullable(type);
+    if (_typeOperations.isBoolType(nonNullable)) {
+      staticType = _boolStaticType;
+    } else {
+      EnumClass? enumClass = enumOperations.getEnumClass(nonNullable);
+      if (enumClass != null) {
+        staticType = new EnumStaticType(
+            _typeOperations, this, nonNullable, _getEnumInfo(enumClass));
+      } else {
+        Class? sealedClass = _sealedClassOperations.getSealedClass(nonNullable);
+        if (sealedClass != null) {
+          staticType = new SealedClassStaticType(
+              _typeOperations,
+              this,
+              nonNullable,
+              this,
+              _sealedClassOperations,
+              _getSealedClassInfo(sealedClass));
+        } else {
+          staticType =
+              new TypeBasedStaticType(_typeOperations, this, nonNullable);
+        }
+      }
+    }
+    if (_typeOperations.isNullable(type)) {
+      staticType = staticType.nullable;
+    }
+    return staticType;
+  }
+
+  /// Returns the [StaticType] for the [enumElementValue] declared by
+  /// [enumClass].
+  StaticType getEnumElementStaticType(
+      EnumClass enumClass, EnumElementValue enumElementValue) {
+    return _getEnumInfo(enumClass).getEnumElement(enumElementValue);
+  }
+
+  /// Creates a new unique [StaticType].
+  StaticType getUnknownStaticType() {
+    return getUniqueStaticType(
+        _typeOperations.nullableObjectType, new Object(), '?');
+  }
+
+  /// Returns a [StaticType] of the given [type] with the given
+  /// [textualRepresentation] that unique identifies the [uniqueValue].
+  ///
+  /// This is used for constants that are neither bool nor enum values.
+  StaticType getUniqueStaticType(
+      Type type, Object uniqueValue, String textualRepresentation) {
+    Type nonNullable = _typeOperations.getNonNullable(type);
+    StaticType staticType = _uniqueTypeMap[uniqueValue] ??=
+        new UniqueStaticType(_typeOperations, this, nonNullable, uniqueValue,
+            textualRepresentation);
+    if (_typeOperations.isNullable(type)) {
+      staticType = staticType.nullable;
+    }
+    return staticType;
+  }
+
+  @override
+  Map<String, StaticType> getFieldTypes(Type type) {
+    Map<String, StaticType>? fields = _fieldCache[type];
+    if (fields == null) {
+      _fieldCache[type] = fields = {};
+      for (MapEntry<String, Type> entry
+          in _typeOperations.getFieldTypes(type).entries) {
+        fields[entry.key] = getStaticType(entry.value);
+      }
+    }
+    return fields;
+  }
+}
+
+/// [EnumInfo] stores information to compute the static type for and the type
+/// of and enum class and its enum elements.
+class EnumInfo<Type extends Object, EnumClass extends Object,
+    EnumElement extends Object, EnumElementValue extends Object> {
+  final TypeOperations<Type> _typeOperations;
+  final FieldLookup<Type> _fieldLookup;
+  final EnumOperations<Type, EnumClass, EnumElement, EnumElementValue>
+      _enumOperations;
+  final EnumClass _enumClass;
+  Map<EnumElementValue, EnumElementStaticType<Type, EnumElement>>?
+      _enumElements;
+
+  EnumInfo(this._typeOperations, this._fieldLookup, this._enumOperations,
+      this._enumClass);
+
+  /// Returns a map of the enum elements and their corresponding [StaticType]s
+  /// declared by [_enumClass].
+  Map<EnumElementValue, EnumElementStaticType<Type, EnumElement>>
+      get enumElements => _enumElements ??= _createEnumElements();
+
+  /// Returns the [StaticType] corresponding to [enumElementValue].
+  EnumElementStaticType<Type, EnumElement> getEnumElement(
+      EnumElementValue enumElementValue) {
+    return enumElements[enumElementValue]!;
+  }
+
+  Map<EnumElementValue, EnumElementStaticType<Type, EnumElement>>
+      _createEnumElements() {
+    Map<EnumElementValue, EnumElementStaticType<Type, EnumElement>> elements =
+        {};
+    for (EnumElement element in _enumOperations.getEnumElements(_enumClass)) {
+      EnumElementValue value = _enumOperations.getEnumElementValue(element);
+      elements[value] = new EnumElementStaticType<Type, EnumElement>(
+          _typeOperations,
+          _fieldLookup,
+          _enumOperations.getEnumElementType(element),
+          element,
+          _enumOperations.getEnumElementName(element));
+    }
+    return elements;
+  }
+}
+
+/// [SealedClassInfo] stores information to compute the static type for a
+/// sealed class.
+class SealedClassInfo<Type extends Object, Class extends Object> {
+  final SealedClassOperations<Type, Class> _sealedClassOperations;
+  final Class _sealedClass;
+  List<Class>? _subClasses;
+
+  SealedClassInfo(this._sealedClassOperations, this._sealedClass);
+
+  /// Returns the classes that directly extends, implements or mix in
+  /// [_sealedClass].
+  Iterable<Class> get subClasses =>
+      _subClasses ??= _sealedClassOperations.getDirectSubclasses(_sealedClass);
+}
+
+/// [StaticType] based on a non-nullable [Type].
+///
+/// All [StaticType] implementation in this library are based on [Type] through
+/// this class. Additionally, the `static_type.dart` library has fixed
+/// [StaticType] implementations for `Object`, `Null`, `Never` and nullable
+/// types.
+class TypeBasedStaticType<Type extends Object> extends NonNullableStaticType {
+  final TypeOperations<Type> _typeOperations;
+  final FieldLookup<Type> _fieldLookup;
+  final Type _type;
+
+  TypeBasedStaticType(this._typeOperations, this._fieldLookup, this._type);
+
+  @override
+  Map<String, StaticType> get fields => _fieldLookup.getFieldTypes(_type);
+
+  /// Returns a non-null value for static types that are unique subtypes of
+  /// the [_type]. For instance individual elements of an enum.
+  Object? get identity => null;
+
+  @override
+  bool isSubtypeOfInternal(StaticType other) {
+    return other is TypeBasedStaticType<Type> &&
+        (other.identity == null || identical(identity, other.identity)) &&
+        _typeOperations.isSubtypeOf(_type, other._type);
+  }
+
+  @override
+  bool get isSealed => false;
+
+  @override
+  String get name => _typeOperations.typeToString(_type);
+}
+
+/// [StaticType] for an instantiation of an enum that support access to the
+/// enum values that populate its type through the [subtypes] property.
+class EnumStaticType<Type extends Object, EnumElement extends Object>
+    extends TypeBasedStaticType<Type> {
+  final EnumInfo<Type, Object, EnumElement, Object> _enumInfo;
+  List<EnumElementStaticType<Type, EnumElement>>? _enumElements;
+
+  EnumStaticType(
+      super.typeOperations, super.fieldLookup, super.type, this._enumInfo);
+
+  @override
+  bool get isSealed => true;
+
+  @override
+  Iterable<StaticType> get subtypes => enumElements;
+
+  List<EnumElementStaticType<Type, EnumElement>> get enumElements =>
+      _enumElements ??= _createEnumElements();
+
+  List<EnumElementStaticType<Type, EnumElement>> _createEnumElements() {
+    List<EnumElementStaticType<Type, EnumElement>> elements = [];
+    for (EnumElementStaticType<Type, EnumElement> enumElement
+        in _enumInfo.enumElements.values) {
+      if (_typeOperations.isSubtypeOf(enumElement._type, _type)) {
+        elements.add(enumElement);
+      }
+    }
+    return elements;
+  }
+}
+
+/// [StaticType] for a single enum element.
+///
+/// In the [StaticType] model, individual enum elements are represented as
+/// unique subtypes of the enum type, modelled using [EnumStaticType].
+class EnumElementStaticType<Type extends Object, EnumElement extends Object>
+    extends TypeBasedStaticType<Type> {
+  final EnumElement enumElement;
+
+  @override
+  final String name;
+
+  EnumElementStaticType(super.typeOperations, super.fieldLookup, super.type,
+      this.enumElement, this.name);
+
+  @override
+  Object? get identity => enumElement;
+}
+
+/// [StaticType] for a sealed class type.
+class SealedClassStaticType<Type extends Object, Class extends Object>
+    extends TypeBasedStaticType<Type> {
+  final ExhaustivenessCache<Type, dynamic, dynamic, dynamic, Class> _cache;
+  final SealedClassOperations<Type, Class> _sealedClassOperations;
+  final SealedClassInfo<Type, Class> _sealedInfo;
+  Iterable<StaticType>? _subtypes;
+
+  SealedClassStaticType(super.typeOperations, super.fieldLookup, super.type,
+      this._cache, this._sealedClassOperations, this._sealedInfo);
+
+  @override
+  bool get isSealed => true;
+
+  @override
+  Iterable<StaticType> get subtypes => _subtypes ??= _createSubtypes();
+
+  List<StaticType> _createSubtypes() {
+    List<StaticType> subtypes = [];
+    for (Class subClass in _sealedInfo.subClasses) {
+      Type? subtype =
+          _sealedClassOperations.getSubclassAsInstanceOf(subClass, _type);
+      if (subtype != null) {
+        assert(_typeOperations.isSubtypeOf(subtype, _type));
+        subtypes.add(_cache.getStaticType(subtype));
+      }
+    }
+    return subtypes;
+  }
+}
+
+/// [StaticType] for an object uniquely defined by its [identity].
+class UniqueStaticType<Type extends Object> extends TypeBasedStaticType<Type> {
+  @override
+  final Object identity;
+
+  @override
+  final String name;
+
+  UniqueStaticType(super.typeOperations, super.fieldLookup, super.type,
+      this.identity, this.name);
+}
+
+/// [StaticType] for the `bool` type.
+class BoolStaticType<Type extends Object> extends TypeBasedStaticType<Type> {
+  BoolStaticType(super.typeOperations, super.fieldLookup, super.type);
+
+  @override
+  bool get isSealed => true;
+
+  late StaticType trueType =
+      new UniqueStaticType(_typeOperations, _fieldLookup, _type, true, 'true');
+
+  late StaticType falseType = new UniqueStaticType(
+      _typeOperations, _fieldLookup, _type, false, 'false');
+
+  @override
+  Iterable<StaticType> get subtypes => [trueType, falseType];
+}
diff --git a/_fe_analyzer_shared/lib/src/exhaustiveness/subtract.dart b/_fe_analyzer_shared/lib/src/exhaustiveness/subtract.dart
index 85e5631..c69677f 100644
--- a/_fe_analyzer_shared/lib/src/exhaustiveness/subtract.dart
+++ b/_fe_analyzer_shared/lib/src/exhaustiveness/subtract.dart
@@ -30,6 +30,9 @@
     }.toList();
   }
 
+  if (left == StaticType.neverType) {
+    return const [];
+  }
   return [left];
 }
 
@@ -113,6 +116,10 @@
     // If the right space matches on a field that the left doesn't have, infer
     // it from the static type of the field. That contains the same set of
     // values as having no field at all.
+    // TODO(johnniwinther): Enable this assertion when unit tests handle record
+    // types correctly.
+    //assert(type.fields.containsKey(name),
+    // "Field '$name' not found in $type.");
     leftFields[name] = left.fields[name] ?? new Space(type.fields[name]!);
 
     // If the left matches on a field that the right doesn't have, infer top
diff --git a/_fe_analyzer_shared/lib/src/exhaustiveness/test_helper.dart b/_fe_analyzer_shared/lib/src/exhaustiveness/test_helper.dart
new file mode 100644
index 0000000..d4c54a4
--- /dev/null
+++ b/_fe_analyzer_shared/lib/src/exhaustiveness/test_helper.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'space.dart';
+import 'static_type.dart';
+
+/// Tags used for id-testing of exhaustiveness.
+class Tags {
+  static const String scrutineeType = 'type';
+  static const String scrutineeFields = 'fields';
+  static const String space = 'space';
+  static const String subtypes = 'subtypes';
+  static const String remaining = 'remaining';
+}
+
+/// Returns a textual representation for [space] used for testing.
+String spaceToText(Space space) => space.toString();
+
+/// Returns a textual representation for [fields] used for testing.
+String fieldsToText(Map<String, StaticType> fields) {
+  // TODO(johnniwinther): Enforce that field maps are always sorted.
+  List<String> sortedNames = fields.keys.toList()..sort();
+  StringBuffer sb = new StringBuffer();
+  String comma = '';
+  sb.write('{');
+  for (String name in sortedNames) {
+    if (name.startsWith('_')) {
+      // Avoid implementation specific fields, like `Object._identityHashCode`
+      // and `Enum._name`.
+      // TODO(johnniwinther): Support private fields in the test code.
+      continue;
+    }
+    sb.write(comma);
+    sb.write(name);
+    sb.write(':');
+    sb.write(staticTypeToText(fields[name]!));
+    comma = ',';
+  }
+  sb.write('}');
+  return sb.toString();
+}
+
+/// Returns a textual representation for [type] used for testing.
+String staticTypeToText(StaticType type) => type.toString();
+
+/// Returns a textual representation of the subtypes of [type] used for testing.
+String? subtypesToText(StaticType type) {
+  List<StaticType> subtypes = type.subtypes.toList();
+  if (subtypes.isEmpty) return null;
+  // TODO(johnniwinther): Sort subtypes.
+  StringBuffer sb = new StringBuffer();
+  String comma = '';
+  sb.write('{');
+  for (StaticType subtype in subtypes) {
+    sb.write(comma);
+    sb.write(staticTypeToText(subtype));
+    comma = ',';
+  }
+  sb.write('}');
+  return sb.toString();
+}
diff --git a/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index 8435b32..27722d9 100644
--- a/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -157,6 +157,28 @@
   /// See [assert_begin] for more information.
   void assert_end();
 
+  /// Call this method after visiting a reference to a variable inside a pattern
+  /// assignment.  [node] is the pattern, [variable] is the referenced variable,
+  /// and [writtenType] is the type that's written to that variable by the
+  /// assignment.
+  void assignedVariablePattern(Node node, Variable variable, Type writtenType);
+
+  /// Call this method when the temporary variable holding the result of a
+  /// pattern match is assigned to a user-accessible variable.  (Depending on
+  /// the client's model, this might happen right after a variable pattern is
+  /// matched, or later, after one or more logical-or patterns have been
+  /// handled).
+  ///
+  /// [promotionKey] is the promotion key used by flow analysis to represent the
+  /// temporary variable holding the result of the pattern match, and [variable]
+  /// is the user-accessible variable that the value is being assigned to.
+  ///
+  /// Returns the promotion key used by flow analysis to represent [variable].
+  /// This may be used in future calls to [assignMatchedPatternVariable] to
+  /// handle nested logical-ors, or logical-ors nested within switch cases that
+  /// share a body.
+  void assignMatchedPatternVariable(Variable variable, int promotionKey);
+
   /// Call this method when visiting a boolean literal expression.
   void booleanLiteral(Expression expression, bool value);
 
@@ -178,22 +200,67 @@
   /// [conditionalExpression] should be the entire conditional expression.
   void conditional_thenBegin(Expression condition, Node conditionalExpression);
 
-  void constantPattern_end(Expression expression);
+  /// Call this method after processing a constant pattern.  [expression] should
+  /// be the pattern's constant expression, and [type] should be its static
+  /// type.
+  ///
+  /// If [patternsEnabled] is `true`, pattern support is enabled and this is an
+  /// ordinary constant pattern.  if [patternsEnabled] is `false`, pattern
+  /// support is disabled and this constant pattern is one of the cases of a
+  /// legacy switch statement.
+  void constantPattern_end(Expression expression, Type type,
+      {required bool patternsEnabled});
+
+  /// Copy promotion data associated with one promotion key to another.  This
+  /// is used after analyzing a branch of a logical-or pattern, to move the
+  /// promotion data associated with the result of a pattern match on the left
+  /// hand and right hand sides of the logical-or into a common promotion key,
+  /// so that promotions will be properly unified when the control flow paths
+  /// are joined.
+  void copyPromotionData({required int sourceKey, required int destinationKey});
 
   /// Register a declaration of the [variable] in the current state.
   /// Should also be called for function parameters.
   ///
+  /// [staticType] should be the static type of the variable (after type
+  /// inference).
+  ///
   /// A local variable is [initialized] if its declaration has an initializer.
   /// A function parameter is always initialized, so [initialized] is `true`.
-  void declare(Variable variable, bool initialized);
+  ///
+  /// In debug builds, an assertion will normally verify that no variable gets
+  /// declared more than once.  This assertion may be disabled by passing `true`
+  /// to [skipDuplicateCheck].
+  ///
+  /// TODO(paulberry): try to remove all uses of skipDuplicateCheck
+  void declare(Variable variable, Type staticType,
+      {required bool initialized, bool skipDuplicateCheck = false});
 
   /// Call this method after visiting a variable pattern in a non-assignment
   /// context (or a wildcard pattern).
   ///
   /// [matchedType] should be the static type of the value being matched.
   /// [staticType] should be the static type of the variable pattern itself.
-  void declaredVariablePattern(
-      {required Type matchedType, required Type staticType});
+  /// [initializerExpression] should be the initializer expression being matched
+  /// (or `null` if there is no expression being matched to this variable).
+  /// [isFinal] indicates whether the variable is final, and [isImplicitlyTyped]
+  /// indicates whether the variable has an explicit type annotation.
+  ///
+  /// Although pattern variables in Dart cannot be late, the client is allowed
+  /// to model a traditional (non-patterned) variable declaration statement
+  /// using the same flow analysis machinery as it uses for pattern variable
+  /// declaration statements; when it does so, it may use [isLate] to indicate
+  /// whether the variable in question is a `late` variable.
+  ///
+  /// Returns the promotion key used by flow analysis to track the temporary
+  /// variable that holds the matched value.
+  int declaredVariablePattern(
+      {required Type matchedType,
+      required Type staticType,
+      Expression? initializerExpression,
+      bool isFinal = false,
+      bool isLate = false,
+      required bool isImplicitlyTyped});
 
   /// Call this method before visiting the body of a "do-while" statement.
   /// [doStatement] should be the same node that was passed to
@@ -227,6 +294,13 @@
       EqualityInfo<Type>? leftOperandInfo, EqualityInfo<Type>? rightOperandInfo,
       {bool notEqual = false});
 
+  /// Call this method after processing a relational pattern that uses an
+  /// equality operator (either `==` or `!=`).  [operand] should be the operand
+  /// to the right of the operator, [operandType] should be its static type, and
+  /// [notEqual] should be `true` iff the operator was `!=`.
+  void equalityRelationalPattern_end(Expression operand, Type operandType,
+      {bool notEqual = false});
+
   /// Retrieves the [ExpressionInfo] associated with [target], if known.  Will
   /// return `null` if (a) no info is associated with [target], or (b) another
   /// expression with info has been visited more recently than [target].  For
@@ -339,11 +413,19 @@
 
   /// Call this method when visiting a break statement.  [target] should be the
   /// statement targeted by the break.
-  void handleBreak(Statement target);
+  ///
+  /// To facilitate error recovery, [target] is allowed to be `null`; if this
+  /// happens, the break statement is analyzed as though it's an unconditional
+  /// branch to nowhere (i.e. similar to a `return` or `throw`).
+  void handleBreak(Statement? target);
 
   /// Call this method when visiting a continue statement.  [target] should be
   /// the statement targeted by the continue.
-  void handleContinue(Statement target);
+  ///
+  /// To facilitate error recovery, [target] is allowed to be `null`; if this
+  /// happens, the continue statement is analyzed as though it's an
+  /// unconditional branch to nowhere (i.e. similar to a `return` or `throw`).
+  void handleContinue(Statement? target);
 
   /// Register the fact that the current state definitely exists, e.g. returns
   /// from the body, throws an exception, etc.
@@ -512,6 +594,10 @@
   /// Call this method after visiting a logical-or (`||`) pattern.
   void logicalOrPattern_end();
 
+  /// Call this method after processing a relational pattern that uses a
+  /// non-equality operator (any operator other than `==` or `!=`).
+  void nonEqualityRelationalPattern_end();
+
   /// Call this method just after visiting a non-null assertion (`x!`)
   /// expression.
   void nonNullAssert_end(Expression operand);
@@ -536,6 +622,15 @@
   /// not be called until after processing the method call to `z(x)`.
   void nullAwareAccess_rightBegin(Expression? target, Type targetType);
 
+  /// Call this method before visiting the subpattern of a null-check or a
+  /// null-assert pattern. [isAssert] indicates whether the pattern is a
+  /// null-check or a null-assert pattern.
+  bool nullCheckOrAssertPattern_begin({required bool isAssert});
+
+  /// Call this method after visiting the subpattern of a null-check or a
+  /// null-assert pattern.
+  void nullCheckOrAssertPattern_end();
+
   /// Call this method when encountering an expression that is a `null` literal.
   void nullLiteral(Expression expression);
 
@@ -555,6 +650,16 @@
   /// Call this method after visiting a pattern assignment expression.
   void patternAssignment_end();
 
+  /// Call this method just after visiting the expression (which usually
+  /// implements `Iterable`, but can also be `dynamic`), and before visiting
+  /// the pattern or body.
+  ///
+  /// [elementType] is the element type of the `Iterable`, or `dynamic`.
+  void patternForIn_afterExpression(Type elementType);
+
+  /// Call this method after visiting the body.
+  void patternForIn_end();
+
   /// Call this method just after visiting the initializer of a pattern variable
   /// declaration, and before visiting the pattern.
   ///
@@ -597,6 +702,33 @@
   /// is currently promoted.  Otherwise returns `null`.
   Type? promotedType(Variable variable);
 
+  /// Call this method when visiting a pattern whose semantics constrain the
+  /// type of the matched value.  This could be due to a required type of a
+  /// declared variable pattern, list pattern, map pattern, record pattern,
+  /// object pattern, or wildcard pattern, or it could be due to the
+  /// demonstrated type of a record pattern.
+  ///
+  /// [matchedType] should be the matched value type, and [knownType] should
+  /// be the type that the matched value is now known to satisfy.
+  ///
+  /// If [matchFailsIfWrongType] is `true` (the default), flow analysis models
+  /// the usual semantics of a type test in a pattern: if the matched value
+  /// fails to have the type [knownType], the pattern will fail to match.
+  /// If it is `false`, it models the semantics where the no match failure can
+  /// occur (either because the matched value is known, due to other invariants
+  /// to have the type [knownType], or because a type test failure would result
+  /// in an exception being thrown).
+  ///
+  /// If [matchMayFailEvenIfCorrectType] is `true`, flow analysis would always
+  /// update the unmatched value.
+  ///
+  /// Returns `true` if [matchedType] is a subtype of [knownType].
+  bool promoteForPattern(
+      {required Type matchedType,
+      required Type knownType,
+      bool matchFailsIfWrongType = true,
+      bool matchMayFailEvenIfCorrectType = false});
+
   /// Call this method just after visiting a property get expression.
   /// [wholeExpression] should be the whole property get, [target] should be the
   /// expression to the left hand side of the `.`, and [propertyName] should be
@@ -627,14 +759,9 @@
   /// [matchedType] is the type that should be used to type check the
   /// subpattern.
   ///
-  /// If [isDistinctValue] is `true`, that indicates that the subpattern will be
-  /// matched against a different value than the outer pattern (this happens,
-  /// for example, when examining the subpatterns of a list, map, or object
-  /// pattern).  If [isDistinctValue] is `false`, that indicates that the
-  /// subpattern will be matched against the same value as the outer pattern
-  /// (and thus, promotions should transfer between the subpattern and the outer
-  /// pattern).
-  void pushSubpattern(Type matchedType, {required bool isDistinctValue});
+  /// Flow analysis makes no assumptions about the relation between the matched
+  /// value for the outer pattern and the subpattern.
+  void pushSubpattern(Type matchedType);
 
   /// Retrieves the SSA node associated with [variable], or `null` if [variable]
   /// is not associated with an SSA node because it is write captured.  For
@@ -644,7 +771,10 @@
 
   /// Call this method just after visiting a `case` or `default` body.  See
   /// [switchStatement_expressionEnd] for details.
-  void switchStatement_afterCase();
+  ///
+  /// This method returns a boolean indicating whether the end of the case body
+  /// is "locally reachable" (i.e. reachable from its start).
+  bool switchStatement_afterCase();
 
   /// Call this method just before visiting a `case` or `default` clause.  See
   /// [switchStatement_expressionEnd] for details.
@@ -966,6 +1096,18 @@
   }
 
   @override
+  void assignedVariablePattern(Node node, Variable variable, Type writtenType) {
+    _wrap('assignedVariablePattern($node, $variable, $writtenType)',
+        () => _wrapped.assignedVariablePattern(node, variable, writtenType));
+  }
+
+  @override
+  void assignMatchedPatternVariable(Variable variable, int promotionKey) {
+    _wrap('assignMatchedPatternVariable($variable, $promotionKey)',
+        () => _wrapped.assignMatchedPatternVariable(variable, promotionKey));
+  }
+
+  @override
   void booleanLiteral(Expression expression, bool value) {
     _wrap('booleanLiteral($expression, $value)',
         () => _wrapped.booleanLiteral(expression, value));
@@ -997,25 +1139,57 @@
   }
 
   @override
-  void constantPattern_end(Expression expression) {
-    _wrap('constantPattern_end($expression)',
-        () => _wrapped.constantPattern_end(expression));
-  }
-
-  @override
-  void declare(Variable variable, bool initialized) {
-    _wrap('declare($variable, $initialized)',
-        () => _wrapped.declare(variable, initialized));
-  }
-
-  @override
-  void declaredVariablePattern(
-      {required Type matchedType, required Type staticType}) {
+  void constantPattern_end(Expression expression, Type type,
+      {required bool patternsEnabled}) {
     _wrap(
+        'constantPattern_end($expression, $type, '
+        'patternsEnabled: $patternsEnabled)',
+        () => _wrapped.constantPattern_end(expression, type,
+            patternsEnabled: patternsEnabled));
+  }
+
+  @override
+  void copyPromotionData(
+      {required int sourceKey, required int destinationKey}) {
+    _wrap(
+        'copyPromotionData(sourceKey: $sourceKey, '
+        'destinationKey: $destinationKey)',
+        () => _wrapped.copyPromotionData(
+            sourceKey: sourceKey, destinationKey: destinationKey));
+  }
+
+  @override
+  void declare(Variable variable, Type staticType,
+      {required bool initialized, bool skipDuplicateCheck = false}) {
+    _wrap(
+        'declare($variable, $staticType, '
+        'initialized: $initialized, skipDuplicateCheck: $skipDuplicateCheck)',
+        () => _wrapped.declare(variable, staticType,
+            initialized: initialized, skipDuplicateCheck: skipDuplicateCheck));
+  }
+
+  @override
+  int declaredVariablePattern(
+      {required Type matchedType,
+      required Type staticType,
+      Expression? initializerExpression,
+      bool isFinal = false,
+      bool isLate = false,
+      required bool isImplicitlyTyped}) {
+    return _wrap(
         'declaredVariablePattern(matchedType: $matchedType, '
-        'staticType: $staticType)',
+        'staticType: $staticType, '
+        'initializerExpression: $initializerExpression, isFinal: $isFinal, '
+        'isLate: $isLate, isImplicitlyTyped: $isImplicitlyTyped)',
         () => _wrapped.declaredVariablePattern(
-            matchedType: matchedType, staticType: staticType));
+            matchedType: matchedType,
+            staticType: staticType,
+            initializerExpression: initializerExpression,
+            isFinal: isFinal,
+            isLate: isLate,
+            isImplicitlyTyped: isImplicitlyTyped),
+        isQuery: true,
+        isPure: false);
   }
 
   @override
@@ -1055,6 +1229,16 @@
   }
 
   @override
+  void equalityRelationalPattern_end(Expression operand, Type operandType,
+      {bool notEqual = false}) {
+    _wrap(
+        'equalityRelationalPattern_end($operand, $operandType, '
+        'notEqual: $notEqual)',
+        () => _wrapped.equalityRelationalPattern_end(operand, operandType,
+            notEqual: notEqual));
+  }
+
+  @override
   ExpressionInfo<Type>? expressionInfoForTesting(Expression target) {
     return _wrap('expressionInfoForTesting($target)',
         () => _wrapped.expressionInfoForTesting(target),
@@ -1126,12 +1310,12 @@
   }
 
   @override
-  void handleBreak(Statement target) {
+  void handleBreak(Statement? target) {
     _wrap('handleBreak($target)', () => _wrapped.handleBreak(target));
   }
 
   @override
-  void handleContinue(Statement target) {
+  void handleContinue(Statement? target) {
     _wrap('handleContinue($target)', () => _wrapped.handleContinue(target));
   }
 
@@ -1306,6 +1490,12 @@
   }
 
   @override
+  void nonEqualityRelationalPattern_end() {
+    _wrap('nonEqualityRelationalPattern_end()',
+        () => _wrapped.nonEqualityRelationalPattern_end());
+  }
+
+  @override
   void nonNullAssert_end(Expression operand) {
     return _wrap('nonNullAssert_end($operand)',
         () => _wrapped.nonNullAssert_end(operand));
@@ -1323,6 +1513,19 @@
   }
 
   @override
+  bool nullCheckOrAssertPattern_begin({required bool isAssert}) {
+    return _wrap('nullCheckOrAssertPattern_begin(isAssert: $isAssert)',
+        () => _wrapped.nullCheckOrAssertPattern_begin(isAssert: isAssert),
+        isQuery: true, isPure: false);
+  }
+
+  @override
+  void nullCheckOrAssertPattern_end() {
+    _wrap('nullCheckOrAssertPattern_end()',
+        () => _wrapped.nullCheckOrAssertPattern_end());
+  }
+
+  @override
   void nullLiteral(Expression expression) {
     _wrap('nullLiteral($expression)', () => _wrapped.nullLiteral(expression));
   }
@@ -1348,6 +1551,19 @@
   }
 
   @override
+  void patternForIn_afterExpression(Type elementType) {
+    _wrap(
+      'patternForIn_afterExpression($elementType)',
+      () => _wrapped.patternForIn_afterExpression(elementType),
+    );
+  }
+
+  @override
+  void patternForIn_end() {
+    _wrap('patternForIn_end()', () => _wrapped.patternForIn_end());
+  }
+
+  @override
   void patternVariableDeclaration_afterInitializer(
       Expression initializer, Type initializerType) {
     _wrap(
@@ -1387,6 +1603,26 @@
   }
 
   @override
+  bool promoteForPattern(
+      {required Type matchedType,
+      required Type knownType,
+      bool matchFailsIfWrongType = true,
+      bool matchMayFailEvenIfCorrectType = false}) {
+    return _wrap(
+        'patternRequiredType(matchedType: $matchedType, '
+        'requiredType: $knownType, '
+        'matchFailsIfWrongType: $matchFailsIfWrongType, '
+        'matchMayFailEvenIfCorrectType: $matchMayFailEvenIfCorrectType)',
+        () => _wrapped.promoteForPattern(
+            matchedType: matchedType,
+            knownType: knownType,
+            matchFailsIfWrongType: matchFailsIfWrongType,
+            matchMayFailEvenIfCorrectType: matchMayFailEvenIfCorrectType),
+        isQuery: true,
+        isPure: false);
+  }
+
+  @override
   Type? propertyGet(Expression? wholeExpression, Expression target,
       String propertyName, Object? propertyMember, Type staticType) {
     return _wrap(
@@ -1399,11 +1635,9 @@
   }
 
   @override
-  void pushSubpattern(Type matchedType, {required bool isDistinctValue}) {
-    _wrap(
-        'pushSubpattern($matchedType, isDistinctValue: $isDistinctValue)',
-        () => _wrapped.pushSubpattern(matchedType,
-            isDistinctValue: isDistinctValue));
+  void pushSubpattern(Type matchedType) {
+    _wrap('pushSubpattern($matchedType)',
+        () => _wrapped.pushSubpattern(matchedType));
   }
 
   @override
@@ -1414,9 +1648,10 @@
   }
 
   @override
-  void switchStatement_afterCase() {
-    _wrap('switchStatement_afterCase()',
-        () => _wrapped.switchStatement_afterCase());
+  bool switchStatement_afterCase() {
+    return _wrap('switchStatement_afterCase()',
+        () => _wrapped.switchStatement_afterCase(),
+        isPure: false, isQuery: true);
   }
 
   @override
@@ -2129,18 +2364,19 @@
   FlowModel<Type> write<Variable extends Object>(
       FlowModelHelper<Type> helper,
       NonPromotionReason? nonPromotionReason,
-      Variable variable,
       int variableKey,
       Type writtenType,
       SsaNode<Type> newSsaNode,
       Operations<Variable, Type> operations,
-      {bool promoteToTypeOfInterest = true}) {
+      {bool promoteToTypeOfInterest = true,
+      required Type unpromotedType}) {
     FlowModel<Type>? newModel;
     VariableModel<Type>? infoForVar = variableInfo[variableKey];
     if (infoForVar != null) {
-      VariableModel<Type> newInfoForVar = infoForVar.write(nonPromotionReason,
-          variable, variableKey, writtenType, operations, newSsaNode,
-          promoteToTypeOfInterest: promoteToTypeOfInterest);
+      VariableModel<Type> newInfoForVar = infoForVar.write(
+          nonPromotionReason, variableKey, writtenType, operations, newSsaNode,
+          promoteToTypeOfInterest: promoteToTypeOfInterest,
+          unpromotedType: unpromotedType);
       if (!identical(newInfoForVar, infoForVar)) {
         newModel = _updateVariableInfo(variableKey, newInfoForVar);
       }
@@ -2814,12 +3050,12 @@
   /// reason for any potential demotion.
   VariableModel<Type> write<Variable extends Object>(
       NonPromotionReason? nonPromotionReason,
-      Variable variable,
       int variableKey,
       Type writtenType,
       Operations<Variable, Type> operations,
       SsaNode<Type> newSsaNode,
-      {required bool promoteToTypeOfInterest}) {
+      {required bool promoteToTypeOfInterest,
+      required Type unpromotedType}) {
     if (writeCaptured) {
       return new VariableModel<Type>(
           promotedTypes: promotedTypes,
@@ -2833,10 +3069,9 @@
         _demoteViaAssignment(writtenType, operations, nonPromotionReason);
     List<Type>? newPromotedTypes = demotionResult.promotedTypes;
 
-    Type declaredType = operations.variableType(variable);
     if (promoteToTypeOfInterest) {
       newPromotedTypes = _tryPromoteToTypeOfInterest(
-          operations, declaredType, newPromotedTypes, writtenType);
+          operations, unpromotedType, newPromotedTypes, writtenType);
     }
     // TODO(paulberry): remove demotions from demotionResult.nonPromotionHistory
     // that are no longer in effect due to re-promotion.
@@ -2917,6 +3152,18 @@
     return new _DemotionResult<Type>(newPromotedTypes, newNonPromotionHistory);
   }
 
+  /// Returns a variable model that is the same as this one, but with the
+  /// variable definitely assigned.
+  VariableModel<Type> _setAssigned() => assigned
+      ? this
+      : new VariableModel(
+          promotedTypes: promotedTypes,
+          tested: tested,
+          assigned: true,
+          unassigned: false,
+          ssaNode: ssaNode ?? new SsaNode(null),
+          nonPromotionHistory: nonPromotionHistory);
+
   /// Determines whether a variable with the given [promotedTypes] should be
   /// promoted to [writtenType] based on types of interest.  If it should,
   /// returns an updated promotion chain; otherwise returns [promotedTypes]
@@ -3343,6 +3590,36 @@
   _DemotionResult(this.promotedTypes, this.nonPromotionHistory);
 }
 
+/// Specialization of [_EqualityCheckResult] used as the return value for
+/// [_FlowAnalysisImpl._equalityCheck] when exactly one of the two operands is a
+/// `null` literal (and therefore the equality test is testing whether the other
+/// operand is `null`).
+///
+/// Note that if both operands are `null`, then [_GuaranteedEqual] will be
+/// returned instead.
+class _EqualityCheckIsNullCheck<Type extends Object>
+    extends _EqualityCheckResult {
+  /// If the operand that is being null-tested is something that can undergo
+  /// type promotion, the object recording its promotion key, type information,
+  /// etc.  Otherwise, `null`.
+  final ReferenceWithType<Type>? reference;
+
+  /// If `true` the operand that's being null-tested corresponds to
+  /// [_FlowAnalysisImpl._equalityCheck]'s `rightOperandInfo` argument; if
+  /// `false`, it corresponds to [_FlowAnalysisImpl._equalityCheck]'s
+  /// `leftOperandInfo` argument.
+  final bool isReferenceOnRight;
+
+  _EqualityCheckIsNullCheck(this.reference, {required this.isReferenceOnRight})
+      : super._();
+}
+
+/// Result of performing equality check.  This class is used as the return value
+/// for [_FlowAnalysisImpl._equalityCheck].
+abstract class _EqualityCheckResult {
+  const _EqualityCheckResult._();
+}
+
 class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
         Expression extends Object, Variable extends Object, Type extends Object>
     implements
@@ -3369,8 +3646,8 @@
   FlowModel<Type>? _unmatched;
 
   /// If a pattern is being analyzed, and the scrutinee is something that might
-  /// be type promoted as a consequence of the pattern match, reference to the
-  /// scrutinee.  Otherwise `null`.
+  /// be relevant to type promotion as a consequence of the pattern match,
+  /// [ReferenceWithType] object referring to the scrutinee.  Otherwise `null`.
   ReferenceWithType<Type>? _scrutineeReference;
 
   /// If a pattern is being analyzed, and the scrutinee is something that might
@@ -3394,11 +3671,6 @@
   ///     }
   SsaNode<Type>? _scrutineeSsaNode;
 
-  /// If a pattern is being analyzed, the static type of the scrutinee
-  /// expression, otherwise`null`.  This determines the initial matched value
-  /// type.
-  Type? _scrutineeType;
-
   /// The most recently visited expression for which an [ExpressionInfo] object
   /// exists, or `null` if no expression has been visited that has a
   /// corresponding [ExpressionInfo] object.
@@ -3428,18 +3700,24 @@
   @override
   final PromotionKeyStore<Variable> promotionKeyStore;
 
+  /// For debugging only: the set of [Variable]s that have been passed to
+  /// [declare] so far.  This is used to detect unnecessary calls to [declare].
+  final Set<Variable> _debugDeclaredVariables = {};
+
   _FlowAnalysisImpl(this.operations, this._assignedVariables,
       {required this.respectImplicitlyTypedVarInitializers})
       : promotionKeyStore = _assignedVariables.promotionKeyStore {
     if (!_assignedVariables.isFinished) {
       _assignedVariables.finish();
     }
-    AssignedVariablesNodeInfo anywhere = _assignedVariables.anywhere;
-    Set<int> implicitlyDeclaredVars = {...anywhere.read, ...anywhere.written};
-    implicitlyDeclaredVars.removeAll(anywhere.declared);
-    for (int variableKey in implicitlyDeclaredVars) {
-      _current = _current.declare(variableKey, true);
-    }
+    assert(() {
+      AssignedVariablesNodeInfo anywhere = _assignedVariables.anywhere;
+      Set<int> implicitlyDeclaredVars = {...anywhere.read, ...anywhere.written};
+      implicitlyDeclaredVars.removeAll(anywhere.declared);
+      assert(implicitlyDeclaredVars.isEmpty,
+          'All variables should be declared somewhere');
+      return true;
+    }());
   }
 
   @override
@@ -3477,6 +3755,26 @@
   }
 
   @override
+  void assignedVariablePattern(Node node, Variable variable, Type writtenType) {
+    _PatternContext<Type> context = _stack.last as _PatternContext<Type>;
+    _write(node, variable, writtenType, context._matchedValueInfo);
+  }
+
+  @override
+  void assignMatchedPatternVariable(Variable variable, int promotionKey) {
+    int mergedKey = promotionKeyStore.keyForVariable(variable);
+    VariableModel<Type> info = _current.infoFor(promotionKey);
+    // Normally flow analysis is responsible for tracking whether variables are
+    // definitely assigned; however for variables appearing in patterns we
+    // have other logic to make sure that a value is definitely assigned (e.g.
+    // the rule that a variable appearing on one side of an `||` must also
+    // appear on the other side).  So to avoid reporting redundant errors, we
+    // pretend that the variable is definitely assigned, even if it isn't.
+    info = info._setAssigned();
+    _current = _current._updateVariableInfo(mergedKey, info);
+  }
+
+  @override
   void booleanLiteral(Expression expression, bool value) {
     FlowModel<Type> unreachable = _current.setUnreachable();
     _storeExpressionInfo(
@@ -3524,51 +3822,60 @@
   }
 
   @override
-  void constantPattern_end(Expression expression) {
-    // As a temporary measure, just assume the pattern might or might not match.
-    // This avoids some bogus "unreachable code" warnings in analyzer tests.
-    // TODO(paulberry): replace this with an implementation that does similar
-    // promotion to `==` operations.
-    _unmatched = _join(_unmatched!, _current);
+  void constantPattern_end(Expression expression, Type type,
+      {required bool patternsEnabled}) {
+    assert(_stack.last is _PatternContext<Type>);
+    if (patternsEnabled) {
+      _handleEqualityCheckPattern(expression, type, notEqual: false);
+    } else {
+      // Before pattern support was added to Dart, flow analysis didn't do any
+      // promotion based on the constants in individual case clauses.  Also, it
+      // assumed that all case clauses were equally reachable.  So, when
+      // analyzing legacy code that targets a language version before patterns
+      // were supported, we need to mimic that old behavior.  The easiest way to
+      // do that is to simply assume that the pattern might or might not match,
+      // regardless of the constant expression.
+      _unmatched = _join(_unmatched!, _current);
+    }
   }
 
   @override
-  void declare(Variable variable, bool initialized) {
+  void copyPromotionData(
+      {required int sourceKey, required int destinationKey}) {
+    _current = _current._updateVariableInfo(
+        destinationKey, _current.infoFor(sourceKey));
+  }
+
+  @override
+  void declare(Variable variable, Type staticType,
+      {required bool initialized, bool skipDuplicateCheck = false}) {
+    assert(
+        operations.isSameType(staticType, operations.variableType(variable)));
+    assert(_debugDeclaredVariables.add(variable) || skipDuplicateCheck,
+        'Variable $variable already declared');
     _current = _current.declare(
         promotionKeyStore.keyForVariable(variable), initialized);
   }
 
   @override
-  void declaredVariablePattern(
-      {required Type matchedType, required Type staticType}) {
+  int declaredVariablePattern(
+      {required Type matchedType,
+      required Type staticType,
+      Expression? initializerExpression,
+      bool isFinal = false,
+      bool isLate = false,
+      required bool isImplicitlyTyped}) {
     _PatternContext<Type> context = _stack.last as _PatternContext<Type>;
-    ReferenceWithType<Type> matchedValueReference =
-        context._matchedValueReference;
-    bool coversMatchedType =
-        typeOperations.isSubtypeOf(matchedType, staticType);
-    // Promote the synthetic cache variable the pattern is being matched
-    // against.
-    ExpressionInfo<Type> promotionInfo = _current.tryPromoteForTypeCheck(
-        this, matchedValueReference, staticType);
-    FlowModel<Type> ifTrue = promotionInfo.ifTrue;
-    FlowModel<Type> ifFalse = promotionInfo.ifFalse;
-    ReferenceWithType<Type>? scrutineeReference = _scrutineeReference;
-    // If there's a scrutinee, and its value is known to be the same as that of
-    // the synthetic cache variable, promote it too.
-    if (scrutineeReference != null &&
-        _current.infoFor(matchedValueReference.promotionKey).ssaNode ==
-            _scrutineeSsaNode) {
-      ifTrue = ifTrue
-          .tryPromoteForTypeCheck(this, scrutineeReference, staticType)
-          .ifTrue;
-      ifFalse = ifFalse
-          .tryPromoteForTypeCheck(this, scrutineeReference, staticType)
-          .ifFalse;
-    }
-    _current = ifTrue;
-    if (!coversMatchedType) {
-      _unmatched = _join(_unmatched!, ifFalse);
-    }
+    // Choose a fresh promotion key to represent the temporary variable that
+    // stores the matched value, and mark it as initialized.
+    int promotionKey = promotionKeyStore.makeTemporaryKey();
+    _current = _current.declare(promotionKey, true);
+    _initialize(promotionKey, matchedType, context._matchedValueInfo,
+        isFinal: isFinal,
+        isLate: isLate,
+        isImplicitlyTyped: isImplicitlyTyped,
+        unpromotedType: staticType);
+    return promotionKey;
   }
 
   @override
@@ -3599,8 +3906,7 @@
 
   @override
   EqualityInfo<Type> equalityOperand_end(Expression operand, Type type) =>
-      new EqualityInfo<Type>._(
-          _getExpressionInfo(operand), type, _getExpressionReference(operand));
+      _computeEqualityInfo(operand, type);
 
   @override
   void equalityOperation_end(Expression wholeExpression,
@@ -3611,41 +3917,47 @@
     // information about legacy operands.  But since we are currently in full
     // (post null safety) flow analysis logic, we can safely assume that they
     // are not null.
-    ReferenceWithType<Type>? lhsReference = leftOperandInfo!._reference;
-    ReferenceWithType<Type>? rhsReference = rightOperandInfo!._reference;
-    TypeClassification leftOperandTypeClassification =
-        operations.classifyType(leftOperandInfo._type);
-    TypeClassification rightOperandTypeClassification =
-        operations.classifyType(rightOperandInfo._type);
-    if (leftOperandTypeClassification == TypeClassification.nullOrEquivalent &&
-        rightOperandTypeClassification == TypeClassification.nullOrEquivalent) {
+    _EqualityCheckResult equalityCheckResult =
+        _equalityCheck(leftOperandInfo!, rightOperandInfo!);
+    if (equalityCheckResult is _GuaranteedEqual) {
+      // Both operands are known by flow analysis to compare equal, so the whole
+      // expression behaves equivalently to a boolean (either `true` or `false`
+      // depending whether the check uses the `!=` operator).
       booleanLiteral(wholeExpression, !notEqual);
-    } else if ((leftOperandTypeClassification ==
-                TypeClassification.nullOrEquivalent &&
-            rightOperandTypeClassification == TypeClassification.nonNullable) ||
-        (rightOperandTypeClassification ==
-                TypeClassification.nullOrEquivalent &&
-            leftOperandTypeClassification == TypeClassification.nonNullable)) {
-      // In strong mode the test is guaranteed to produce a "not equal" result,
-      // but weak mode it might produce an "equal" result.  We don't want flow
-      // analysis behavior to depend on mode, so we conservatively assume that
-      // either result is possible.
-    } else if (leftOperandInfo._expressionInfo is _NullInfo<Type> &&
-        rhsReference != null) {
+    } else if (equalityCheckResult is _EqualityCheckIsNullCheck<Type>) {
+      ReferenceWithType<Type>? reference = equalityCheckResult.reference;
+      if (reference == null) {
+        // One side of the equality check is `null`, but the other side is not a
+        // promotable reference.  So there's no promotion to do.
+        return;
+      }
+      // The equality check is a null check of something potentially promotable
+      // (e.g. a local variable).  Record the necessary information so that if
+      // this null check winds up being used for a conditional branch, the
+      // variable's will be promoted on the appropriate code path.
       ExpressionInfo<Type> equalityInfo =
-          _current.tryMarkNonNullable(this, rhsReference);
+          _current.tryMarkNonNullable(this, reference);
       _storeExpressionInfo(
           wholeExpression, notEqual ? equalityInfo : equalityInfo.invert());
-    } else if (rightOperandInfo._expressionInfo is _NullInfo<Type> &&
-        lhsReference != null) {
-      ExpressionInfo<Type> equalityInfo =
-          _current.tryMarkNonNullable(this, lhsReference);
-      _storeExpressionInfo(
-          wholeExpression, notEqual ? equalityInfo : equalityInfo.invert());
+    } else {
+      assert(equalityCheckResult is _NoEqualityInformation);
+      // Since flow analysis can't garner any information from this equality
+      // check, nothing needs to be done; by not calling `_storeExpressionInfo`,
+      // we ensure that if `_getExpressionInfo` is later called on this
+      // expression, `null` will be returned.  That means that if this
+      // expression winds up being used for a conditional branch, flow analysis
+      // will consider both code paths reachable and won't perform any
+      // promotions on either path.
     }
   }
 
   @override
+  void equalityRelationalPattern_end(Expression operand, Type operandType,
+      {bool notEqual = false}) {
+    _handleEqualityCheckPattern(operand, operandType, notEqual: notEqual);
+  }
+
+  @override
   ExpressionInfo<Type>? expressionInfoForTesting(Expression target) =>
       identical(target, _expressionWithInfo) ? _expressionInfo : null;
 
@@ -3656,7 +3968,6 @@
     assert(_unmatched == null);
     assert(_scrutineeReference == null);
     assert(_scrutineeSsaNode == null);
-    assert(_scrutineeType == null);
   }
 
   @override
@@ -3749,14 +4060,14 @@
   Type getMatchedValueType() {
     _PatternContext<Type> context = _stack.last as _PatternContext<Type>;
     return _current
-            .infoFor(context._matchedValueReference.promotionKey)
+            .infoFor(context._matchedValuePromotionKey)
             .promotedTypes
             ?.last ??
-        context._matchedValueType;
+        context._matchedValueUnpromotedType;
   }
 
   @override
-  void handleBreak(Statement target) {
+  void handleBreak(Statement? target) {
     _BranchTargetContext<Type>? context = _statementToContext[target];
     if (context != null) {
       context._breakModel =
@@ -3766,7 +4077,7 @@
   }
 
   @override
-  void handleContinue(Statement target) {
+  void handleContinue(Statement? target) {
     _BranchTargetContext<Type>? context = _statementToContext[target];
     if (context != null) {
       context._continueModel = _join(
@@ -3789,8 +4100,7 @@
     // Note that we don't need to take any action to handle
     // `before(E1) = matched(P)`, because we store both the "matched" state for
     // patterns and the "before" state for expressions in `_current`.
-    _pushScrutinee(_getExpressionReference(scrutinee), scrutineeType);
-    _pushPattern();
+    _pushPattern(_pushScrutinee(scrutinee, scrutineeType));
   }
 
   @override
@@ -3889,30 +4199,14 @@
       {required bool isFinal,
       required bool isLate,
       required bool isImplicitlyTyped}) {
+    Type unpromotedType = operations.variableType(variable);
     int variableKey = promotionKeyStore.keyForVariable(variable);
-    ExpressionInfo<Type>? expressionInfo;
-    if (isLate) {
-      // Don't get expression info for late variables, since we don't know when
-      // they'll be initialized.
-    } else if (isImplicitlyTyped && !respectImplicitlyTypedVarInitializers) {
-      // If the language version is too old, SSA analysis has to ignore
-      // initializer expressions for implicitly typed variables, in order to
-      // preserve the buggy behavior of
-      // https://github.com/dart-lang/language/issues/1785.
-    } else if (initializerExpression != null) {
-      expressionInfo = _getExpressionInfo(initializerExpression);
-    }
-    SsaNode<Type> newSsaNode = new SsaNode<Type>(
-        expressionInfo is _TrivialExpressionInfo ? null : expressionInfo);
-    _current = _current.write(
-        this, null, variable, variableKey, matchedType, newSsaNode, operations,
-        promoteToTypeOfInterest: !isImplicitlyTyped && !isFinal);
-    if (isImplicitlyTyped && operations.isTypeParameterType(matchedType)) {
-      _current = _current
-          .tryPromoteForTypeCheck(
-              this, _variableReference(variable, variableKey), matchedType)
-          .ifTrue;
-    }
+    _initialize(
+        variableKey, matchedType, _getExpressionInfo(initializerExpression),
+        isFinal: isFinal,
+        isLate: isLate,
+        isImplicitlyTyped: isImplicitlyTyped,
+        unpromotedType: unpromotedType);
   }
 
   @override
@@ -4046,8 +4340,11 @@
   void logicalOrPattern_begin() {
     _PatternContext<Type> context = _stack.last as _PatternContext<Type>;
     // Save the pieces of the current flow state that will be needed later.
-    _stack.add(new _OrPatternContext<Type>(context._matchedValueReference,
-        context._matchedValueType, _unmatched!));
+    _stack.add(new _OrPatternContext<Type>(
+        context._matchedValueInfo,
+        context._matchedValuePromotionKey,
+        context._matchedValueUnpromotedType,
+        _unmatched!));
     // Initialize `_unmatched` to a fresh unreachable flow state, so that after
     // we visit the left hand side, `_unmatched` will represent the flow state
     // if the left hand side failed to match.
@@ -4064,6 +4361,14 @@
   }
 
   @override
+  void nonEqualityRelationalPattern_end() {
+    // Flow analysis has no way of knowing whether the operator will return
+    // `true` or `false`, so just assume the worst case--both cases are
+    // reachable and no promotions can be done in either case.
+    _unmatched = _join(_unmatched!, _current);
+  }
+
+  @override
   void nonNullAssert_end(Expression operand) {
     ReferenceWithType<Type>? operandReference =
         _getExpressionReference(operand);
@@ -4094,6 +4399,32 @@
   }
 
   @override
+  bool nullCheckOrAssertPattern_begin({required bool isAssert}) {
+    if (!isAssert) {
+      // Account for the possibility that the pattern might not match.  Note
+      // that it's tempting to skip this step if matchedValueType is
+      // non-nullable (based on the reasoning that a non-null value is
+      // guaranteed to satisfy a null check), but in weak mode that's not sound,
+      // because in weak mode even non-nullable values might be null.  We don't
+      // want flow analysis behavior to depend on mode, so we conservatively
+      // assume the pattern might not match regardless of matchedValueType.
+      _unmatched = _join(_unmatched, _current);
+    }
+    FlowModel<Type>? ifNotNull = _nullCheckPattern();
+    if (ifNotNull != null) {
+      _current = ifNotNull;
+    }
+    // Note: we don't need to push a new pattern context for the subpattern,
+    // because (a) the subpattern matches the same value as the outer pattern,
+    // and (b) promotion of the synthetic cache variable takes care of
+    // establishing the correct matched value type.
+    return ifNotNull == null;
+  }
+
+  @override
+  void nullCheckOrAssertPattern_end() {}
+
+  @override
   void nullLiteral(Expression expression) {
     _storeExpressionInfo(expression, new _NullInfo(_current));
   }
@@ -4106,8 +4437,7 @@
 
   @override
   void patternAssignment_afterRhs(Expression rhs, Type rhsType) {
-    _pushScrutinee(_getExpressionReference(rhs), rhsType);
-    _pushPattern();
+    _pushPattern(_pushScrutinee(rhs, rhsType));
   }
 
   @override
@@ -4117,10 +4447,20 @@
   }
 
   @override
+  void patternForIn_afterExpression(Type elementType) {
+    _pushPattern(_pushScrutinee(null, elementType));
+  }
+
+  @override
+  void patternForIn_end() {
+    _popPattern(null);
+    _popScrutinee();
+  }
+
+  @override
   void patternVariableDeclaration_afterInitializer(
       Expression initializer, Type initializerType) {
-    _pushScrutinee(_getExpressionReference(initializer), initializerType);
-    _pushPattern();
+    _pushPattern(_pushScrutinee(initializer, initializerType));
   }
 
   @override
@@ -4151,6 +4491,43 @@
   }
 
   @override
+  bool promoteForPattern(
+      {required Type matchedType,
+      required Type knownType,
+      bool matchFailsIfWrongType = true,
+      bool matchMayFailEvenIfCorrectType = false}) {
+    _PatternContext<Type> context = _stack.last as _PatternContext<Type>;
+    ReferenceWithType<Type> matchedValueReference =
+        context.createReference(matchedType);
+    bool coversMatchedType = operations.isSubtypeOf(matchedType, knownType);
+    // Promote the synthetic cache variable the pattern is being matched
+    // against.
+    ExpressionInfo<Type> promotionInfo =
+        _current.tryPromoteForTypeCheck(this, matchedValueReference, knownType);
+    FlowModel<Type> ifTrue = promotionInfo.ifTrue;
+    FlowModel<Type> ifFalse = promotionInfo.ifFalse;
+    ReferenceWithType<Type>? scrutineeReference = _scrutineeReference;
+    // If there's a scrutinee, and its value is known to be the same as that of
+    // the synthetic cache variable, promote it too.
+    if (scrutineeReference != null &&
+        _current.infoFor(matchedValueReference.promotionKey).ssaNode ==
+            _current.infoFor(scrutineeReference.promotionKey).ssaNode) {
+      ifTrue = ifTrue
+          .tryPromoteForTypeCheck(this, scrutineeReference, knownType)
+          .ifTrue;
+      ifFalse = ifFalse
+          .tryPromoteForTypeCheck(this, scrutineeReference, knownType)
+          .ifFalse;
+    }
+    _current = ifTrue;
+    if (matchMayFailEvenIfCorrectType ||
+        (matchFailsIfWrongType && !coversMatchedType)) {
+      _unmatched = _join(_unmatched!, coversMatchedType ? ifTrue : ifFalse);
+    }
+    return coversMatchedType;
+  }
+
+  @override
   Type? propertyGet(Expression? wholeExpression, Expression target,
       String propertyName, Object? propertyMember, Type staticType) {
     return _handleProperty(
@@ -4158,14 +4535,11 @@
   }
 
   @override
-  void pushSubpattern(Type matchedType, {required bool isDistinctValue}) {
-    _PatternContext<Type> context = _stack.last as _PatternContext<Type>;
+  void pushSubpattern(Type matchedType) {
+    assert(_stack.last is _PatternContext<Type>);
     assert(_unmatched != null);
     _stack.add(new _PatternContext<Type>(
-        isDistinctValue
-            ? _makeTemporaryReference(new SsaNode<Type>(null), matchedType)
-            : context._matchedValueReference,
-        matchedType));
+        null, _makeTemporaryReference(new SsaNode<Type>(null)), matchedType));
   }
 
   @override
@@ -4173,24 +4547,30 @@
       .variableInfo[promotionKeyStore.keyForVariable(variable)]?.ssaNode;
 
   @override
-  void switchStatement_afterCase() {
+  bool switchStatement_afterCase() {
     _SwitchStatementContext<Type> context =
         _stack.last as _SwitchStatementContext<Type>;
-    context._breakModel = _join(context._breakModel, _current);
+    bool isLocallyReachable = _current.reachable.locallyReachable;
+    _current = _current.unsplit();
+    if (isLocallyReachable) {
+      context._breakModel = _join(context._breakModel, _current);
+    }
+    return isLocallyReachable;
   }
 
   @override
   void switchStatement_beginAlternative() {
-    assert(_stack.last is _SwitchAlternativesContext<Type>);
-    _pushPattern();
+    _SwitchAlternativesContext<Type> context =
+        _stack.last as _SwitchAlternativesContext<Type>;
+    _current = context._switchStatementContext._unmatched;
+    _pushPattern(context._switchStatementContext._matchedValueInfo);
   }
 
   @override
   void switchStatement_beginAlternatives() {
     _SwitchStatementContext<Type> context =
         _stack.last as _SwitchStatementContext<Type>;
-    _current = context._previous.split();
-    _stack.add(new _SwitchAlternativesContext<Type>(_current));
+    _stack.add(new _SwitchAlternativesContext<Type>(context));
   }
 
   @override
@@ -4219,13 +4599,14 @@
 
   @override
   void switchStatement_endAlternative(Expression? guard) {
-    // TODO(paulberry): make use of `unmatched`
-    // ignore: unused_local_variable
     FlowModel<Type> unmatched = _popPattern(guard);
     _SwitchAlternativesContext<Type> context =
         _stack.last as _SwitchAlternativesContext<Type>;
+    // Future alternatives will be analyzed under the assumption that this
+    // alternative didn't match.  This models the fact that a switch statement
+    // behaves like a chain of if/else tests.
+    context._switchStatementContext._unmatched = unmatched;
     context._combinedModel = _join(context._combinedModel, _current);
-    _current = context._previous;
   }
 
   @override
@@ -4233,29 +4614,29 @@
       {required bool hasLabels}) {
     _SwitchAlternativesContext<Type> alternativesContext =
         _stack.removeLast() as _SwitchAlternativesContext<Type>;
-    _SimpleStatementContext<Type> switchContext =
-        _stack.last as _SimpleStatementContext<Type>;
+    _SwitchStatementContext<Type> switchContext =
+        _stack.last as _SwitchStatementContext<Type>;
     if (hasLabels) {
       AssignedVariablesNodeInfo info = _assignedVariables.getInfoForNode(node!);
       _current = switchContext._previous
           .conservativeJoin(this, info.written, info.captured);
     } else {
-      _current =
-          (alternativesContext._combinedModel ?? alternativesContext._previous)
-              .unsplit();
+      _current = alternativesContext._combinedModel ?? switchContext._unmatched;
     }
-    // TODO(paulberry): consider doing a split here if unreachable, and a join
-    // later, so that one case matching everything won't prevent promotion in
-    // cases that follow
+    // Do a control flow split so that in switchStatement_afterCase, we'll be
+    // able to tell whether the end of the case body was reachable from its
+    // start.
+    _current = _current.split();
   }
 
   @override
   void switchStatement_expressionEnd(
       Statement? switchStatement, Expression scrutinee, Type scrutineeType) {
-    _pushScrutinee(_getExpressionReference(scrutinee), scrutineeType);
+    EqualityInfo<Type> matchedValueInfo =
+        _pushScrutinee(scrutinee, scrutineeType);
     _current = _current.split();
     _SwitchStatementContext<Type> context = new _SwitchStatementContext<Type>(
-        _current.reachable.parent!, _current, scrutineeType);
+        _current.reachable.parent!, _current, matchedValueInfo);
     _stack.add(context);
     if (switchStatement != null) {
       _statementToContext[switchStatement] = context;
@@ -4350,11 +4731,12 @@
 
   @override
   Type? variableRead(Expression expression, Variable variable) {
+    Type unpromotedType = operations.variableType(variable);
     int variableKey = promotionKeyStore.keyForVariable(variable);
     VariableModel<Type> variableModel = _current._getInfo(variableKey);
     Type? promotedType = variableModel.promotedTypes?.last;
     _storeExpressionReference(
-        expression, _variableReference(variable, variableKey));
+        expression, _variableReference(variableKey, unpromotedType));
     ExpressionInfo<Type>? expressionInfo = variableModel.ssaNode?.expressionInfo
         ?.rebaseForward(operations, _current);
     if (expressionInfo != null) {
@@ -4419,32 +4801,79 @@
   @override
   void write(Node node, Variable variable, Type writtenType,
       Expression? writtenExpression) {
-    int variableKey = promotionKeyStore.keyForVariable(variable);
-    ExpressionInfo<Type>? expressionInfo = writtenExpression == null
-        ? null
-        : _getExpressionInfo(writtenExpression);
-    SsaNode<Type> newSsaNode = new SsaNode<Type>(
-        expressionInfo is _TrivialExpressionInfo ? null : expressionInfo);
-    _current = _current.write(
-        this,
-        new DemoteViaExplicitWrite<Variable>(variable, node),
-        variable,
-        variableKey,
-        writtenType,
-        newSsaNode,
-        operations);
+    _write(node, variable, writtenType, _getExpressionInfo(writtenExpression));
   }
 
+  /// Computes an [EqualityInfo] object to describe the expression [expression],
+  /// having static type [type].
+  EqualityInfo<Type> _computeEqualityInfo(Expression expression, Type type) =>
+      new EqualityInfo<Type>._(_getExpressionInfo(expression), type,
+          _getExpressionReference(expression));
+
   @override
   void _dumpState() {
     print('  current: $_current');
-    print('  expressionWithInfo: $_expressionWithInfo');
-    print('  expressionInfo: $_expressionInfo');
-    print('  expressionWithReference: $_expressionWithReference');
-    print('  expressionReference: $_expressionReference');
-    print('  stack:');
-    for (_FlowContext stackEntry in _stack.reversed) {
-      print('    $stackEntry');
+    if (_unmatched != null) {
+      print('  unmatched: $_unmatched');
+    }
+    if (_scrutineeReference != null) {
+      print('  scrutineeReference: $_scrutineeReference');
+    }
+    if (_scrutineeSsaNode != null) {
+      print('  scrutineeSsaNode: $_scrutineeSsaNode');
+    }
+    if (_expressionWithInfo != null) {
+      print('  expressionWithInfo: $_expressionWithInfo');
+    }
+    if (_expressionInfo != null) {
+      print('  expressionInfo: $_expressionInfo');
+    }
+    if (_expressionWithReference != null) {
+      print('  expressionWithReference: $_expressionWithReference');
+    }
+    if (_expressionReference != null) {
+      print('  expressionReference: $_expressionReference');
+    }
+    if (_stack.isNotEmpty) {
+      print('  stack:');
+      for (_FlowContext stackEntry in _stack.reversed) {
+        print('    $stackEntry');
+      }
+    }
+  }
+
+  /// Analyzes an equality check between the operands described by
+  /// [leftOperandInfo] and [rightOperandInfo].
+  _EqualityCheckResult _equalityCheck(
+      EqualityInfo<Type> leftOperandInfo, EqualityInfo<Type> rightOperandInfo) {
+    ReferenceWithType<Type>? lhsReference = leftOperandInfo._reference;
+    ReferenceWithType<Type>? rhsReference = rightOperandInfo._reference;
+    TypeClassification leftOperandTypeClassification =
+        operations.classifyType(leftOperandInfo._type);
+    TypeClassification rightOperandTypeClassification =
+        operations.classifyType(rightOperandInfo._type);
+    if (leftOperandTypeClassification == TypeClassification.nullOrEquivalent &&
+        rightOperandTypeClassification == TypeClassification.nullOrEquivalent) {
+      return const _GuaranteedEqual();
+    } else if ((leftOperandTypeClassification ==
+                TypeClassification.nullOrEquivalent &&
+            rightOperandTypeClassification == TypeClassification.nonNullable) ||
+        (rightOperandTypeClassification ==
+                TypeClassification.nullOrEquivalent &&
+            leftOperandTypeClassification == TypeClassification.nonNullable)) {
+      // In strong mode the test is guaranteed to produce a "not equal" result,
+      // but weak mode it might produce an "equal" result.  We don't want flow
+      // analysis behavior to depend on mode, so we conservatively assume that
+      // either result is possible.
+      return const _NoEqualityInformation();
+    } else if (leftOperandInfo._expressionInfo is _NullInfo<Type>) {
+      return new _EqualityCheckIsNullCheck(rhsReference,
+          isReferenceOnRight: true);
+    } else if (rightOperandInfo._expressionInfo is _NullInfo<Type>) {
+      return new _EqualityCheckIsNullCheck(lhsReference,
+          isReferenceOnRight: false);
+    } else {
+      return const _NoEqualityInformation();
     }
   }
 
@@ -4533,6 +4962,84 @@
     return () => {};
   }
 
+  /// Common code for handling patterns that perform an equality check.
+  /// [operand] is the expression that the matched value is being compared to,
+  /// and [operandType] is its type.
+  ///
+  /// If [notEqual] is `true`, the pattern matches if the matched value is *not*
+  /// equal to the operand; otherwise, it matches if the matched value is
+  /// *equal* to the operand.
+  void _handleEqualityCheckPattern(Expression operand, Type operandType,
+      {required bool notEqual}) {
+    _PatternContext<Type> context = _stack.last as _PatternContext<Type>;
+    _EqualityCheckResult equalityCheckResult = _equalityCheck(
+        new EqualityInfo._(context._matchedValueInfo, getMatchedValueType(),
+            context.createReference(getMatchedValueType())),
+        equalityOperand_end(operand, operandType));
+    if (equalityCheckResult is _NoEqualityInformation) {
+      // We have no information so we have to assume the pattern might or
+      // might not match.
+      _unmatched = _join(_unmatched!, _current);
+    } else if (equalityCheckResult is _EqualityCheckIsNullCheck<Type>) {
+      FlowModel<Type>? ifNotNull;
+      if (!equalityCheckResult.isReferenceOnRight) {
+        // The `null` literal is on the right hand side of the implicit
+        // equality check, meaning it is the constant value.  So the user is
+        // doing something like this:
+        //
+        //     if (v case == null) { ... }
+        //
+        // So we want to promote the type of `v` in the case where the
+        // constant pattern *didn't* match.
+        ifNotNull = _nullCheckPattern();
+        if (ifNotNull == null) {
+          // `_nullCheckPattern` returns `null` in the case where the matched
+          // value type is non-nullable.  In fully sound programs, this would
+          // mean that the pattern cannot possibly match.  However, in mixed
+          // mode programs it might match due to unsoundness.  Since we don't
+          // want type inference results to change when a program becomes
+          // fully sound, we have to assume that we're in mixed mode, and thus
+          // the pattern might match.
+          ifNotNull = _current;
+        }
+      } else {
+        // The `null` literal is on the left hand side of the implicit
+        // equality check, meaning it is the scrutinee.  So the user is doing
+        // something silly like this:
+        //
+        //     if (null case == c) { ... }
+        //
+        // (where `c` is some constant).  There's no variable to promote.
+        //
+        // Since flow analysis can't make use of the results of constant
+        // evaluation, we can't really assume anything; as far as we know, the
+        // pattern might or might not match.
+        ifNotNull = _current;
+      }
+      if (notEqual) {
+        _unmatched = _join(_unmatched!, _current);
+        _current = ifNotNull;
+      } else {
+        _unmatched = _join(_unmatched!, ifNotNull);
+      }
+    } else {
+      assert(equalityCheckResult is _GuaranteedEqual);
+      if (notEqual) {
+        // Both operands are known by flow analysis to compare equal, so the
+        // constant pattern is guaranteed *not* to match.
+        _unmatched = _join(_unmatched!, _current);
+        _current = _current.setUnreachable();
+      } else {
+        // Both operands are known by flow analysis to compare equal, so the
+        // constant pattern is guaranteed to match.  Since our approach to
+        // handling patterns in flow analysis uses "implicit and" semantics
+        // (initially assuming that the pattern always matches, and then
+        // updating the `_current` and `_unmatched` states to reflect what
+        // values the pattern rejects), we don't have to do any updates.
+      }
+    }
+  }
+
   Type? _handleProperty(Expression? wholeExpression, Expression? target,
       String propertyName, Object? propertyMember, Type staticType) {
     int targetKey;
@@ -4575,16 +5082,46 @@
     return promotedType;
   }
 
+  void _initialize(
+      int promotionKey, Type matchedType, ExpressionInfo<Type>? expressionInfo,
+      {required bool isFinal,
+      required bool isLate,
+      required bool isImplicitlyTyped,
+      required Type unpromotedType}) {
+    if (isLate) {
+      // Don't use expression info for late variables, since we don't know when
+      // they'll be initialized.
+      expressionInfo = null;
+    } else if (isImplicitlyTyped && !respectImplicitlyTypedVarInitializers) {
+      // If the language version is too old, SSA analysis has to ignore
+      // initializer expressions for implicitly typed variables, in order to
+      // preserve the buggy behavior of
+      // https://github.com/dart-lang/language/issues/1785.
+      expressionInfo = null;
+    }
+    SsaNode<Type> newSsaNode = new SsaNode<Type>(
+        expressionInfo is _TrivialExpressionInfo ? null : expressionInfo);
+    _current = _current.write(
+        this, null, promotionKey, matchedType, newSsaNode, operations,
+        promoteToTypeOfInterest: !isImplicitlyTyped && !isFinal,
+        unpromotedType: unpromotedType);
+    if (isImplicitlyTyped && operations.isTypeParameterType(matchedType)) {
+      _current = _current
+          .tryPromoteForTypeCheck(this,
+              _variableReference(promotionKey, unpromotedType), matchedType)
+          .ifTrue;
+    }
+  }
+
   FlowModel<Type> _join(FlowModel<Type>? first, FlowModel<Type>? second) =>
       FlowModel.join(operations, first, second, _current._emptyVariableMap);
 
-  /// Creates a [ReferenceWithType] representing a temporary variable that
-  /// doesn't correspond to any variable in the user's source code.  This is
-  /// used by flow analysis to model the synthetic variables used during pattern
-  /// matching to cache the values that the pattern, and its subpattterns, are
+  /// Creates a promotion key representing a temporary variable that doesn't
+  /// correspond to any variable in the user's source code.  This is used by
+  /// flow analysis to model the synthetic variables used during pattern
+  /// matching to cache the values that the pattern, and its subpatterns, are
   /// being matched against.
-  ReferenceWithType<Type> _makeTemporaryReference(
-      SsaNode<Type>? ssaNode, Type matchedType) {
+  int _makeTemporaryReference(SsaNode<Type>? ssaNode) {
     int promotionKey = promotionKeyStore.makeTemporaryKey();
     _current = _current._updateVariableInfo(
         promotionKey,
@@ -4594,18 +5131,52 @@
             assigned: true,
             unassigned: false,
             ssaNode: ssaNode));
-    return new ReferenceWithType<Type>(promotionKey, matchedType,
-        isPromotable: true, isThisOrSuper: false);
+    return promotionKey;
   }
 
   FlowModel<Type> _merge(FlowModel<Type> first, FlowModel<Type>? second) =>
       FlowModel.merge(operations, first, second, _current._emptyVariableMap);
 
+  /// Computes an updated flow model representing the result of a null check
+  /// performed by a pattern.  The returned flow model represents what is known
+  /// about the program state if the matched value is determined to be not equal
+  /// to `null`.
+  ///
+  /// If the matched value's type is non-nullable, then `null` is returned.
+  FlowModel<Type>? _nullCheckPattern() {
+    _PatternContext<Type> context = _stack.last as _PatternContext<Type>;
+    Type matchedValueType = getMatchedValueType();
+    ReferenceWithType<Type> matchedValueReference =
+        context.createReference(matchedValueType);
+    // Promote
+    TypeClassification typeClassification =
+        operations.classifyType(matchedValueType);
+    if (typeClassification == TypeClassification.nonNullable) {
+      return null;
+    } else {
+      FlowModel<Type>? ifNotNull =
+          _current.tryMarkNonNullable(this, matchedValueReference).ifTrue;
+      ReferenceWithType<Type>? scrutineeReference = _scrutineeReference;
+      // If there's a scrutinee, and its value is known to be the same as that
+      // of the synthetic cache variable, promote it too.
+      if (scrutineeReference != null &&
+          _current.infoFor(matchedValueReference.promotionKey).ssaNode ==
+              _current.infoFor(scrutineeReference.promotionKey).ssaNode) {
+        ifNotNull =
+            ifNotNull.tryMarkNonNullable(this, scrutineeReference).ifTrue;
+      }
+      if (typeClassification == TypeClassification.nullOrEquivalent) {
+        ifNotNull = ifNotNull.setUnreachable();
+      }
+      return ifNotNull;
+    }
+  }
+
   FlowModel<Type> _popPattern(Expression? guard) {
-    _FlowContext context = _stack.removeLast();
-    assert(context is _TopPatternContext<Type>);
+    _TopPatternContext<Type> context =
+        _stack.removeLast() as _TopPatternContext<Type>;
     FlowModel<Type> unmatched = _unmatched!;
-    _unmatched = null;
+    _unmatched = context._previousUnmatched;
     if (guard != null) {
       ExpressionInfo<Type> guardInfo = _expressionEnd(guard);
       _current = guardInfo.ifTrue;
@@ -4619,28 +5190,46 @@
         _stack.removeLast() as _ScrutineeContext<Type>;
     _scrutineeReference = context.previousScrutineeReference;
     _scrutineeSsaNode = context.previousScrutineeSsaNode;
-    _scrutineeType = context.previousScrutineeType;
   }
 
-  void _pushPattern() {
-    assert(_unmatched == null);
-    _unmatched = _current.setUnreachable();
+  /// Updates the [_stack] to reflect the fact that flow analysis is entering
+  /// into a pattern or subpattern match.  [matchedValueInfo] should be the
+  /// [EqualityInfo] representing the value being matched.
+  void _pushPattern(EqualityInfo<Type> matchedValueInfo) {
     _stack.add(new _TopPatternContext<Type>(
-        _makeTemporaryReference(_scrutineeSsaNode, _scrutineeType!),
-        _scrutineeType!));
+        matchedValueInfo._expressionInfo,
+        matchedValueInfo._reference!.promotionKey,
+        matchedValueInfo._type,
+        _unmatched));
+    _unmatched = _current.setUnreachable();
   }
 
-  void _pushScrutinee(
-      ReferenceWithType<Type>? scrutineeReference, Type scrutineeType) {
+  /// Updates the [_stack] to reflect the fact that flow analysis is entering
+  /// into a construct that performs pattern matching.  [scrutinee] should be
+  /// the expression that is being matched (or `null` if there is no expression
+  /// that's being matched directly, as happens when in `for-in` loops).
+  /// [scrutineeType] should be the static type of the scrutinee.
+  ///
+  /// The returned value is the [EqualityInfo] representing the value being
+  /// matched.  It should be passed to [_pushPattern].
+  EqualityInfo<Type> _pushScrutinee(Expression? scrutinee, Type scrutineeType) {
+    EqualityInfo<Type>? scrutineeInfo = scrutinee == null
+        ? null
+        : _computeEqualityInfo(scrutinee, scrutineeType);
     _stack.add(new _ScrutineeContext<Type>(
         previousScrutineeReference: _scrutineeReference,
-        previousScrutineeSsaNode: _scrutineeSsaNode,
-        previousScrutineeType: _scrutineeType));
+        previousScrutineeSsaNode: _scrutineeSsaNode));
+    ReferenceWithType<Type>? scrutineeReference = scrutineeInfo?._reference;
     _scrutineeReference = scrutineeReference;
     _scrutineeSsaNode = scrutineeReference == null
         ? new SsaNode<Type>(null)
         : _current.infoFor(scrutineeReference.promotionKey).ssaNode;
-    _scrutineeType = scrutineeType;
+    return new EqualityInfo._(
+        scrutineeInfo?._expressionInfo,
+        scrutineeType,
+        new ReferenceWithType(
+            _makeTemporaryReference(_scrutineeSsaNode), scrutineeType,
+            isPromotable: true, isThisOrSuper: false));
   }
 
   /// Associates [expression], which should be the most recently visited
@@ -4667,10 +5256,28 @@
           isPromotable: false, isThisOrSuper: true);
 
   ReferenceWithType<Type> _variableReference(
-          Variable variable, int variableKey) =>
+          int variableKey, Type unpromotedType) =>
       new ReferenceWithType<Type>(variableKey,
-          promotedType(variable) ?? operations.variableType(variable),
+          _current.infoFor(variableKey).promotedTypes?.last ?? unpromotedType,
           isPromotable: true, isThisOrSuper: false);
+
+  /// Common logic for handling writes to variables, whether they occur as part
+  /// of an ordinary assignment or a pattern assignment.
+  void _write(Node node, Variable variable, Type writtenType,
+      ExpressionInfo<Type>? expressionInfo) {
+    Type unpromotedType = operations.variableType(variable);
+    int variableKey = promotionKeyStore.keyForVariable(variable);
+    SsaNode<Type> newSsaNode = new SsaNode<Type>(
+        expressionInfo is _TrivialExpressionInfo ? null : expressionInfo);
+    _current = _current.write(
+        this,
+        new DemoteViaExplicitWrite<Variable>(variable, node),
+        variableKey,
+        writtenType,
+        newSsaNode,
+        operations,
+        unpromotedType: unpromotedType);
+  }
 }
 
 /// Base class for objects representing constructs in the Dart programming
@@ -4722,6 +5329,15 @@
   String get _debugType => '_FunctionExpressionContext';
 }
 
+/// Specialization of [_EqualityCheckResult] used as the return value for
+/// [_FlowAnalysisImpl._equalityCheck] when it is determined that the two
+/// operands are guaranteed to be equal to one another, so the code path that
+/// results from a not-equal result should be marked as unreachable.  (This
+/// happens if both operands have type `Null`).
+class _GuaranteedEqual extends _EqualityCheckResult {
+  const _GuaranteedEqual() : super._();
+}
+
 /// [_FlowContext] representing an `if` statement.
 class _IfContext<Type extends Object> extends _BranchContext<Type> {
   /// Flow model associated with the state of program execution after the `if`
@@ -4859,6 +5475,12 @@
   void assert_end() {}
 
   @override
+  assignedVariablePattern(Node node, Variable variable, Type writtenType) {}
+
+  @override
+  void assignMatchedPatternVariable(Variable variable, int promotionKey) {}
+
+  @override
   void booleanLiteral(Expression expression, bool value) {}
 
   @override
@@ -4879,14 +5501,26 @@
   }
 
   @override
-  void constantPattern_end(Expression expression) {}
+  void constantPattern_end(Expression expression, Type type,
+      {required bool patternsEnabled}) {}
 
   @override
-  void declare(Variable variable, bool initialized) {}
+  void copyPromotionData(
+      {required int sourceKey, required int destinationKey}) {}
 
   @override
-  void declaredVariablePattern(
-      {required Type matchedType, required Type staticType}) {}
+  void declare(Variable variable, Type staticType,
+      {required bool initialized, bool skipDuplicateCheck = false}) {}
+
+  @override
+  int declaredVariablePattern(
+          {required Type matchedType,
+          required Type staticType,
+          Expression? initializerExpression,
+          bool isFinal = false,
+          bool isLate = false,
+          required bool isImplicitlyTyped}) =>
+      0;
 
   @override
   void doStatement_bodyBegin(Statement doStatement) {}
@@ -4907,6 +5541,10 @@
       {bool notEqual = false}) {}
 
   @override
+  void equalityRelationalPattern_end(Expression operand, Type operandType,
+      {bool notEqual = false}) {}
+
+  @override
   ExpressionInfo<Type>? expressionInfoForTesting(Expression target) {
     throw new StateError(
         'expressionInfoForTesting requires null-aware flow analysis');
@@ -4959,10 +5597,10 @@
   }
 
   @override
-  void handleBreak(Statement target) {}
+  void handleBreak(Statement? target) {}
 
   @override
-  void handleContinue(Statement target) {}
+  void handleContinue(Statement? target) {}
 
   @override
   void handleExit() {}
@@ -5159,6 +5797,9 @@
   void logicalOrPattern_end() {}
 
   @override
+  void nonEqualityRelationalPattern_end() {}
+
+  @override
   void nonNullAssert_end(Expression operand) {}
 
   @override
@@ -5168,6 +5809,12 @@
   void nullAwareAccess_rightBegin(Expression? target, Type targetType) {}
 
   @override
+  bool nullCheckOrAssertPattern_begin({required bool isAssert}) => false;
+
+  @override
+  void nullCheckOrAssertPattern_end() {}
+
+  @override
   void nullLiteral(Expression expression) {}
 
   @override
@@ -5183,6 +5830,12 @@
   void patternAssignment_end() {}
 
   @override
+  void patternForIn_afterExpression(Type elementType) {}
+
+  @override
+  void patternForIn_end() {}
+
+  @override
   void patternVariableDeclaration_afterInitializer(
       Expression initializer, Type initializerType) {}
 
@@ -5204,12 +5857,20 @@
   }
 
   @override
+  bool promoteForPattern(
+          {required Type matchedType,
+          required Type knownType,
+          bool matchFailsIfWrongType = true,
+          bool matchMayFailEvenIfCorrectType = false}) =>
+      false;
+
+  @override
   Type? propertyGet(Expression? wholeExpression, Expression target,
           String propertyName, Object? propertyMember, Type staticType) =>
       null;
 
   @override
-  void pushSubpattern(Type matchedType, {required bool isDistinctValue}) {}
+  void pushSubpattern(Type matchedType) {}
 
   @override
   SsaNode<Type>? ssaNodeForTesting(Variable variable) {
@@ -5217,7 +5878,7 @@
   }
 
   @override
-  void switchStatement_afterCase() {}
+  bool switchStatement_afterCase() => true;
 
   @override
   void switchStatement_beginAlternative() {}
@@ -5398,6 +6059,15 @@
   String toString() => 'LegacyVariableReadInfo($_variable, $_shownTypes)';
 }
 
+/// Specialization of [_EqualityCheckResult] used as the return value for
+/// [_FlowAnalysisImpl._equalityCheck] when no particular conclusion can be
+/// drawn about the outcome of the outcome of the equality check.  In other
+/// words, regardless of whether the equality check matches or not, the
+/// resulting code path is reachable and no promotions can be done.
+class _NoEqualityInformation extends _EqualityCheckResult {
+  const _NoEqualityInformation() : super._();
+}
+
 /// [_FlowContext] representing a null aware access (`?.`).
 class _NullAwareAccessContext<Type extends Object>
     extends _SimpleContext<Type> {
@@ -5446,8 +6116,8 @@
   /// side matched.
   FlowModel<Type>? _lhsMatched;
 
-  _OrPatternContext(super.matchedValueReference, super.matchedValueType,
-      this._previousUnmatched);
+  _OrPatternContext(super.matchedValueInfo, super.matchedValuePromotionKey,
+      super.matchedValueUnpromotedType, this._previousUnmatched);
 
   @override
   Map<String, Object?> get _debugFields => super._debugFields
@@ -5460,21 +6130,31 @@
 
 /// [_FlowContext] representing a pattern.
 class _PatternContext<Type extends Object> extends _FlowContext {
-  /// Reference for the value being matched.
-  final ReferenceWithType<Type> _matchedValueReference;
+  /// [ExpressionInfo] for the value being matched.
+  final ExpressionInfo<Type>? _matchedValueInfo;
 
-  /// The matched value type that should be used to type analyze the pattern.
-  final Type _matchedValueType;
+  /// Promotion key for the value being matched.
+  final int _matchedValuePromotionKey;
 
-  _PatternContext(this._matchedValueReference, this._matchedValueType);
+  /// The type of the matched value, before any type promotion.
+  final Type _matchedValueUnpromotedType;
+
+  _PatternContext(this._matchedValueInfo, this._matchedValuePromotionKey,
+      this._matchedValueUnpromotedType);
 
   @override
   Map<String, Object?> get _debugFields => super._debugFields
-    ..['matchedValueReference'] = _matchedValueReference
-    ..['matchedValueType'] = _matchedValueType;
+    ..['matchedValueInfo'] = _matchedValueInfo
+    ..['matchedValuePromotionKey'] = _matchedValuePromotionKey
+    ..['matchedValueUnpromotedType'] = _matchedValueUnpromotedType;
 
   @override
   String get _debugType => '_PatternContext';
+
+  /// Creates a reference to the matched value having type [matchedType].
+  ReferenceWithType<Type> createReference(Type matchedType) =>
+      new ReferenceWithType(_matchedValuePromotionKey, matchedType,
+          isPromotable: true, isThisOrSuper: false);
 }
 
 /// [ReferenceWithType] object representing a property get.
@@ -5506,18 +6186,14 @@
 
   final SsaNode<Type>? previousScrutineeSsaNode;
 
-  final Type? previousScrutineeType;
-
   _ScrutineeContext(
       {required this.previousScrutineeReference,
-      required this.previousScrutineeSsaNode,
-      required this.previousScrutineeType});
+      required this.previousScrutineeSsaNode});
 
   @override
   Map<String, Object?> get _debugFields => super._debugFields
     ..['previousScrutineeReference'] = previousScrutineeReference
-    ..['previousScrutineeSsaNode'] = previousScrutineeSsaNode
-    ..['previousScrutineeType'] = previousScrutineeType;
+    ..['previousScrutineeSsaNode'] = previousScrutineeSsaNode;
 
   @override
   String get _debugType => '_ScrutineeContext';
@@ -5561,16 +6237,16 @@
 }
 
 class _SwitchAlternativesContext<Type extends Object> extends _FlowContext {
-  final FlowModel<Type> _previous;
+  /// The enclosing [_SwitchStatementContext].
+  final _SwitchStatementContext<Type> _switchStatementContext;
 
   FlowModel<Type>? _combinedModel;
 
-  _SwitchAlternativesContext(this._previous);
+  _SwitchAlternativesContext(this._switchStatementContext);
 
   @override
-  Map<String, Object?> get _debugFields => super._debugFields
-    ..['previous'] = _previous
-    ..['combinedModel'] = _combinedModel;
+  Map<String, Object?> get _debugFields =>
+      super._debugFields..['combinedModel'] = _combinedModel;
 
   @override
   String get _debugType => '_SwitchAlternativesContext';
@@ -5579,15 +6255,22 @@
 /// [_FlowContext] representing a switch statement.
 class _SwitchStatementContext<Type extends Object>
     extends _SimpleStatementContext<Type> {
-  /// The static type of the value being matched.
-  final Type _scrutineeType;
+  /// [EqualityInfo] for the value being matched.
+  final EqualityInfo<Type> _matchedValueInfo;
+
+  /// Flow state for the code path where no switch cases have matched yet.  If
+  /// we think of a switch statement as syntactic sugar for a chain of if-else
+  /// statements, this is the flow state on entry to the next `if`.
+  FlowModel<Type> _unmatched;
 
   _SwitchStatementContext(
-      super.checkpoint, super._previous, this._scrutineeType);
+      super.checkpoint, super._previous, this._matchedValueInfo)
+      : _unmatched = _previous;
 
   @override
-  Map<String, Object?> get _debugFields =>
-      super._debugFields..['scrutineeType'] = _scrutineeType;
+  Map<String, Object?> get _debugFields => super._debugFields
+    ..['matchedValueInfo'] = _matchedValueInfo
+    ..['unmatched'] = _unmatched;
 
   @override
   String get _debugType => '_SwitchStatementContext';
@@ -5595,7 +6278,14 @@
 
 /// [_FlowContext] representing the top level of a pattern syntax tree.
 class _TopPatternContext<Type extends Object> extends _PatternContext<Type> {
-  _TopPatternContext(super._matchedValueReference, super.matchedValueType);
+  final FlowModel<Type>? _previousUnmatched;
+
+  _TopPatternContext(super._matchedValueInfo, super._matchedValuePromotionKey,
+      super._matchedValueUnpromotedType, this._previousUnmatched);
+
+  @override
+  Map<String, Object?> get _debugFields =>
+      super._debugFields..['previousUnmatched'] = _previousUnmatched;
 
   @override
   String get _debugType => '_TopPatternContext';
diff --git a/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index f80348f..a6943bf 100644
--- a/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -343,6 +343,60 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
     Message Function(
+        String
+            name)> templateBaseClassImplementedOutsideOfLibrary = const Template<
+        Message Function(String name)>(
+    problemMessageTemplate:
+        r"""The class '#name' can't be implemented outside of its library because it's a base class.""",
+    withArguments: _withArgumentsBaseClassImplementedOutsideOfLibrary);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+    codeBaseClassImplementedOutsideOfLibrary =
+    const Code<Message Function(String name)>(
+        "BaseClassImplementedOutsideOfLibrary",
+        analyzerCodes: <String>["BASE_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsBaseClassImplementedOutsideOfLibrary(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeBaseClassImplementedOutsideOfLibrary,
+      problemMessage:
+          """The class '${name}' can't be implemented outside of its library because it's a base class.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        String
+            name)> templateBaseMixinImplementedOutsideOfLibrary = const Template<
+        Message Function(String name)>(
+    problemMessageTemplate:
+        r"""The mixin '#name' can't be implemented outside of its library because it's a base mixin.""",
+    withArguments: _withArgumentsBaseMixinImplementedOutsideOfLibrary);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+    codeBaseMixinImplementedOutsideOfLibrary =
+    const Code<Message Function(String name)>(
+        "BaseMixinImplementedOutsideOfLibrary",
+        analyzerCodes: <String>["BASE_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsBaseMixinImplementedOutsideOfLibrary(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeBaseMixinImplementedOutsideOfLibrary,
+      problemMessage:
+          """The mixin '${name}' can't be implemented outside of its library because it's a base mixin.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
         String string,
         String
             string2)> templateBinaryOperatorWrittenOut = const Template<
@@ -906,23 +960,25 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<Message Function(String name)> templateCantUseClassAsMixin =
-    const Template<Message Function(String name)>(
-        problemMessageTemplate: r"""Class '#name' can't be used as a mixin.""",
-        withArguments: _withArgumentsCantUseClassAsMixin);
+const Template<
+    Message Function(String name)> templateCantUseClassAsMixin = const Template<
+        Message Function(String name)>(
+    problemMessageTemplate:
+        r"""The class '#name' can't be used as a mixin because it isn't a mixin class nor a mixin.""",
+    withArguments: _withArgumentsCantUseClassAsMixin);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeCantUseClassAsMixin =
-    const Code<Message Function(String name)>(
-  "CantUseClassAsMixin",
-);
+    const Code<Message Function(String name)>("CantUseClassAsMixin",
+        analyzerCodes: <String>["CLASS_USED_AS_MIXIN"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsCantUseClassAsMixin(String name) {
   if (name.isEmpty) throw 'No name provided';
   name = demangleMixinApplicationName(name);
   return new Message(codeCantUseClassAsMixin,
-      problemMessage: """Class '${name}' can't be used as a mixin.""",
+      problemMessage:
+          """The class '${name}' can't be used as a mixin because it isn't a mixin class nor a mixin.""",
       arguments: {'name': name});
 }
 
@@ -1981,6 +2037,16 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeContinueLabelInvalid = messageContinueLabelInvalid;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageContinueLabelInvalid = const MessageCode(
+    "ContinueLabelInvalid",
+    analyzerCodes: <String>["CONTINUE_LABEL_INVALID"],
+    problemMessage:
+        r"""A 'continue' label must be on a loop or a switch member.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeContinueOutsideOfLoop = messageContinueOutsideOfLoop;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2462,6 +2528,43 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String name)>
+    templateDuplicatePatternAssignmentVariable =
+    const Template<Message Function(String name)>(
+        problemMessageTemplate:
+            r"""The variable '#name' is already assigned in this pattern.""",
+        correctionMessageTemplate: r"""Try renaming the variable.""",
+        withArguments: _withArgumentsDuplicatePatternAssignmentVariable);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+    codeDuplicatePatternAssignmentVariable =
+    const Code<Message Function(String name)>(
+        "DuplicatePatternAssignmentVariable",
+        analyzerCodes: <String>["DUPLICATE_PATTERN_ASSIGNMENT_VARIABLE"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsDuplicatePatternAssignmentVariable(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeDuplicatePatternAssignmentVariable,
+      problemMessage:
+          """The variable '${name}' is already assigned in this pattern.""",
+      correctionMessage: """Try renaming the variable.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeDuplicatePatternAssignmentVariableContext =
+    messageDuplicatePatternAssignmentVariableContext;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageDuplicatePatternAssignmentVariableContext =
+    const MessageCode("DuplicatePatternAssignmentVariableContext",
+        severity: Severity.context,
+        problemMessage: r"""The first assigned variable pattern.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeDuplicatePrefix = messageDuplicatePrefix;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2472,6 +2575,63 @@
     correctionMessage: r"""Try removing all but one prefix.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String name)>
+    templateDuplicateRecordPatternField =
+    const Template<Message Function(String name)>(
+        problemMessageTemplate:
+            r"""The field '#name' is already matched in this pattern.""",
+        correctionMessageTemplate: r"""Try removing the duplicate field.""",
+        withArguments: _withArgumentsDuplicateRecordPatternField);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)> codeDuplicateRecordPatternField =
+    const Code<Message Function(String name)>("DuplicateRecordPatternField",
+        analyzerCodes: <String>["DUPLICATE_RECORD_PATTERN_FIELD"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsDuplicateRecordPatternField(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeDuplicateRecordPatternField,
+      problemMessage:
+          """The field '${name}' is already matched in this pattern.""",
+      correctionMessage: """Try removing the duplicate field.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeDuplicateRecordPatternFieldContext =
+    messageDuplicateRecordPatternFieldContext;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageDuplicateRecordPatternFieldContext = const MessageCode(
+    "DuplicateRecordPatternFieldContext",
+    severity: Severity.context,
+    problemMessage: r"""The first field.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeDuplicateRestElementInPattern =
+    messageDuplicateRestElementInPattern;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageDuplicateRestElementInPattern = const MessageCode(
+    "DuplicateRestElementInPattern",
+    analyzerCodes: <String>["DUPLICATE_REST_ELEMENT_IN_PATTERN"],
+    problemMessage:
+        r"""At most one rest element is allowed in a list or map pattern.""",
+    correctionMessage: r"""Try removing the duplicate rest element.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeDuplicateRestElementInPatternContext =
+    messageDuplicateRestElementInPatternContext;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageDuplicateRestElementInPatternContext =
+    const MessageCode("DuplicateRestElementInPatternContext",
+        severity: Severity.context,
+        problemMessage: r"""The first rest element.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(String name)> templateDuplicatedDeclaration =
     const Template<Message Function(String name)>(
         problemMessageTemplate:
@@ -4616,7 +4776,7 @@
     Message Function(String name)> templateFfiFieldNull = const Template<
         Message Function(String name)>(
     problemMessageTemplate:
-        r"""Field '#name' cannot have type 'Null', it must be `int`, `double`, `Pointer`, or a subtype of `Struct` or `Union`.""",
+        r"""Field '#name' cannot be nullable or have type 'Null', it must be `int`, `double`, `Pointer`, or a subtype of `Struct` or `Union`.""",
     withArguments: _withArgumentsFfiFieldNull);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -4631,7 +4791,7 @@
   name = demangleMixinApplicationName(name);
   return new Message(codeFfiFieldNull,
       problemMessage:
-          """Field '${name}' cannot have type 'Null', it must be `int`, `double`, `Pointer`, or a subtype of `Struct` or `Union`.""",
+          """Field '${name}' cannot be nullable or have type 'Null', it must be `int`, `double`, `Pointer`, or a subtype of `Struct` or `Union`.""",
       arguments: {'name': name});
 }
 
@@ -5000,6 +5160,60 @@
 const Template<
     Message Function(
         String
+            name)> templateFinalClassExtendedOutsideOfLibrary = const Template<
+        Message Function(String name)>(
+    problemMessageTemplate:
+        r"""The class '#name' can't be extended outside of its library because it's a final class.""",
+    withArguments: _withArgumentsFinalClassExtendedOutsideOfLibrary);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+    codeFinalClassExtendedOutsideOfLibrary =
+    const Code<Message Function(String name)>(
+        "FinalClassExtendedOutsideOfLibrary",
+        analyzerCodes: <String>["FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFinalClassExtendedOutsideOfLibrary(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeFinalClassExtendedOutsideOfLibrary,
+      problemMessage:
+          """The class '${name}' can't be extended outside of its library because it's a final class.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        String
+            name)> templateFinalClassImplementedOutsideOfLibrary = const Template<
+        Message Function(String name)>(
+    problemMessageTemplate:
+        r"""The class '#name' can't be implemented outside of its library because it's a final class.""",
+    withArguments: _withArgumentsFinalClassImplementedOutsideOfLibrary);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+    codeFinalClassImplementedOutsideOfLibrary =
+    const Code<Message Function(String name)>(
+        "FinalClassImplementedOutsideOfLibrary",
+        analyzerCodes: <String>["FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFinalClassImplementedOutsideOfLibrary(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeFinalClassImplementedOutsideOfLibrary,
+      problemMessage:
+          """The class '${name}' can't be implemented outside of its library because it's a final class.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        String
             name)> templateFinalFieldNotInitialized = const Template<
         Message Function(String name)>(
     problemMessageTemplate: r"""Final field '#name' is not initialized.""",
@@ -5086,6 +5300,60 @@
 const Template<
     Message Function(
         String
+            name)> templateFinalMixinImplementedOutsideOfLibrary = const Template<
+        Message Function(String name)>(
+    problemMessageTemplate:
+        r"""The mixin '#name' can't be implemented outside of its library because it's a final mixin.""",
+    withArguments: _withArgumentsFinalMixinImplementedOutsideOfLibrary);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+    codeFinalMixinImplementedOutsideOfLibrary =
+    const Code<Message Function(String name)>(
+        "FinalMixinImplementedOutsideOfLibrary",
+        analyzerCodes: <String>["FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFinalMixinImplementedOutsideOfLibrary(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeFinalMixinImplementedOutsideOfLibrary,
+      problemMessage:
+          """The mixin '${name}' can't be implemented outside of its library because it's a final mixin.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        String
+            name)> templateFinalMixinMixedInOutsideOfLibrary = const Template<
+        Message Function(String name)>(
+    problemMessageTemplate:
+        r"""The mixin '#name' can't be mixed-in outside of its library because it's a final mixin.""",
+    withArguments: _withArgumentsFinalMixinMixedInOutsideOfLibrary);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+    codeFinalMixinMixedInOutsideOfLibrary =
+    const Code<Message Function(String name)>(
+        "FinalMixinMixedInOutsideOfLibrary",
+        analyzerCodes: <String>["FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFinalMixinMixedInOutsideOfLibrary(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeFinalMixinMixedInOutsideOfLibrary,
+      problemMessage:
+          """The mixin '${name}' can't be mixed-in outside of its library because it's a final mixin.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        String
             name)> templateFinalNotAssignedError = const Template<
         Message Function(String name)>(
     problemMessageTemplate:
@@ -6124,6 +6392,60 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        String
+            name)> templateInterfaceClassExtendedOutsideOfLibrary = const Template<
+        Message Function(String name)>(
+    problemMessageTemplate:
+        r"""The class '#name' can't be extended outside of its library because it's an interface class.""",
+    withArguments: _withArgumentsInterfaceClassExtendedOutsideOfLibrary);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+    codeInterfaceClassExtendedOutsideOfLibrary =
+    const Code<Message Function(String name)>(
+        "InterfaceClassExtendedOutsideOfLibrary",
+        analyzerCodes: <String>["INTERFACE_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsInterfaceClassExtendedOutsideOfLibrary(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeInterfaceClassExtendedOutsideOfLibrary,
+      problemMessage:
+          """The class '${name}' can't be extended outside of its library because it's an interface class.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        String
+            name)> templateInterfaceMixinMixedInOutsideOfLibrary = const Template<
+        Message Function(String name)>(
+    problemMessageTemplate:
+        r"""The mixin '#name' can't be mixed-in outside of its library because it's an interface mixin.""",
+    withArguments: _withArgumentsInterfaceMixinMixedInOutsideOfLibrary);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+    codeInterfaceMixinMixedInOutsideOfLibrary =
+    const Code<Message Function(String name)>(
+        "InterfaceMixinMixedInOutsideOfLibrary",
+        analyzerCodes: <String>["INTERFACE_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsInterfaceMixinMixedInOutsideOfLibrary(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeInterfaceMixinMixedInOutsideOfLibrary,
+      problemMessage:
+          """The mixin '${name}' can't be mixed-in outside of its library because it's an interface mixin.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeInternalProblemAlreadyInitialized =
     messageInternalProblemAlreadyInitialized;
 
@@ -6604,6 +6926,81 @@
         r"""The escape sequence starting with '\u' isn't a valid code point.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeInvalidConstantPatternDuplicateConst =
+    messageInvalidConstantPatternDuplicateConst;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageInvalidConstantPatternDuplicateConst =
+    const MessageCode("InvalidConstantPatternDuplicateConst",
+        index: 137,
+        problemMessage:
+            r"""Duplicate 'const' keyword in constant expression.""",
+        correctionMessage: r"""Try removing one of the 'const' keywords.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeInvalidConstantPatternEmptyRecordLiteral =
+    messageInvalidConstantPatternEmptyRecordLiteral;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageInvalidConstantPatternEmptyRecordLiteral =
+    const MessageCode("InvalidConstantPatternEmptyRecordLiteral",
+        index: 138,
+        problemMessage:
+            r"""The empty record literal is not supported as a constant pattern.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeInvalidConstantPatternGeneric =
+    messageInvalidConstantPatternGeneric;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageInvalidConstantPatternGeneric = const MessageCode(
+    "InvalidConstantPatternGeneric",
+    index: 139,
+    problemMessage:
+        r"""This expression is not supported as a constant pattern.""",
+    correctionMessage: r"""Try wrapping the expression in 'const ( ... )'.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeInvalidConstantPatternNegation =
+    messageInvalidConstantPatternNegation;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageInvalidConstantPatternNegation = const MessageCode(
+    "InvalidConstantPatternNegation",
+    index: 135,
+    problemMessage:
+        r"""Only negation of a numeric literal is supported as a constant pattern.""",
+    correctionMessage: r"""Try wrapping the expression in 'const ( ... )'.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        String
+            name)> templateInvalidConstantPatternUnary = const Template<
+        Message Function(String name)>(
+    problemMessageTemplate:
+        r"""The unary operator #name is not supported as a constant pattern.""",
+    correctionMessageTemplate:
+        r"""Try wrapping the expression in 'const ( ... )'.""",
+    withArguments: _withArgumentsInvalidConstantPatternUnary);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)> codeInvalidConstantPatternUnary =
+    const Code<Message Function(String name)>("InvalidConstantPatternUnary",
+        index: 136);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsInvalidConstantPatternUnary(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeInvalidConstantPatternUnary,
+      problemMessage:
+          """The unary operator ${name} is not supported as a constant pattern.""",
+      correctionMessage: """Try wrapping the expression in 'const ( ... )'.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(String name)> templateInvalidContinueTarget =
     const Template<Message Function(String name)>(
         problemMessageTemplate: r"""Can't continue at '#name'.""",
@@ -7434,6 +7831,18 @@
     correctionMessage: r"""Try replacing this with a normal method.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeJsInteropStaticInteropAnonymousFactoryTearoff =
+    messageJsInteropStaticInteropAnonymousFactoryTearoff;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageJsInteropStaticInteropAnonymousFactoryTearoff =
+    const MessageCode("JsInteropStaticInteropAnonymousFactoryTearoff",
+        problemMessage:
+            r"""Factories of `@anonymous` `@staticInterop` classes can not be torn off.""",
+        correctionMessage:
+            r"""Declare a closure that forwards to this factory instead.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null>
     codeJsInteropStaticInteropExternalExtensionMembersWithTypeParameters =
     messageJsInteropStaticInteropExternalExtensionMembersWithTypeParameters;
@@ -7893,6 +8302,16 @@
     problemMessage: r"""List literal requires exactly one type argument.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeListPatternTooManyTypeArguments =
+    messageListPatternTooManyTypeArguments;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageListPatternTooManyTypeArguments = const MessageCode(
+    "ListPatternTooManyTypeArguments",
+    analyzerCodes: <String>["EXPECTED_ONE_LIST_PATTERN_TYPE_ARGUMENTS"],
+    problemMessage: r"""A list pattern requires exactly one type argument.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(String string, Token token)>
     templateLiteralWithClass =
     const Template<Message Function(String string, Token token)>(
@@ -8063,6 +8482,16 @@
     problemMessage: r"""A map literal requires exactly two type arguments.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeMapPatternTypeArgumentMismatch =
+    messageMapPatternTypeArgumentMismatch;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageMapPatternTypeArgumentMismatch = const MessageCode(
+    "MapPatternTypeArgumentMismatch",
+    analyzerCodes: <String>["EXPECTED_TWO_MAP_PATTERN_TYPE_ARGUMENTS"],
+    problemMessage: r"""A map pattern requires exactly two type arguments.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(String name)> templateMemberNotFound =
     const Template<Message Function(String name)>(
         problemMessageTemplate: r"""Member not found: '#name'.""",
@@ -8095,6 +8524,19 @@
     correctionMessage: r"""Try renaming the member.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeMetadataSpaceBeforeParenthesis =
+    messageMetadataSpaceBeforeParenthesis;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageMetadataSpaceBeforeParenthesis = const MessageCode(
+    "MetadataSpaceBeforeParenthesis",
+    index: 134,
+    problemMessage:
+        r"""Annotations can't have spaces or comments before the parenthesis.""",
+    correctionMessage:
+        r"""Remove any spaces or comments before the parenthesis.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeMetadataTypeArguments = messageMetadataTypeArguments;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -8376,6 +8818,34 @@
 const Template<
     Message Function(
         String
+            name)> templateMissingVariablePattern = const Template<
+        Message Function(String name)>(
+    problemMessageTemplate:
+        r"""Variable pattern '#name' is missing in this branch of the logical-or pattern.""",
+    correctionMessageTemplate:
+        r"""Try declaring this variable pattern in the branch.""",
+    withArguments: _withArgumentsMissingVariablePattern);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)> codeMissingVariablePattern =
+    const Code<Message Function(String name)>("MissingVariablePattern",
+        analyzerCodes: <String>["MISSING_VARIABLE_PATTERN"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsMissingVariablePattern(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeMissingVariablePattern,
+      problemMessage:
+          """Variable pattern '${name}' is missing in this branch of the logical-or pattern.""",
+      correctionMessage: """Try declaring this variable pattern in the branch.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        String
             name)> templateMixinApplicationNoConcreteGetter = const Template<
         Message Function(String name)>(
     problemMessageTemplate:
@@ -9113,6 +9583,16 @@
     problemMessage: r"""This is the existing member.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeNonBoolCondition = messageNonBoolCondition;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageNonBoolCondition = const MessageCode(
+    "NonBoolCondition",
+    analyzerCodes: <String>["NON_BOOL_CONDITION"],
+    problemMessage: r"""Conditions must have a static type of 'bool'.""",
+    correctionMessage: r"""Try changing the condition.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeNonConstConstructor = messageNonConstConstructor;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -10317,6 +10797,49 @@
     correctionMessage: r"""Try adding 'external' to the origin declaration.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        String
+            name)> templatePatternAssignmentDeclaresVariable = const Template<
+        Message Function(String name)>(
+    problemMessageTemplate:
+        r"""Variable '#name' can't be declared in a pattern assignment.""",
+    correctionMessageTemplate:
+        r"""Try using a preexisting variable or changing the assignment to a pattern variable declaration.""",
+    withArguments: _withArgumentsPatternAssignmentDeclaresVariable);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+    codePatternAssignmentDeclaresVariable =
+    const Code<Message Function(String name)>(
+  "PatternAssignmentDeclaresVariable",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsPatternAssignmentDeclaresVariable(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codePatternAssignmentDeclaresVariable,
+      problemMessage:
+          """Variable '${name}' can't be declared in a pattern assignment.""",
+      correctionMessage:
+          """Try using a preexisting variable or changing the assignment to a pattern variable declaration.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codePatternAssignmentNotLocalVariable =
+    messagePatternAssignmentNotLocalVariable;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messagePatternAssignmentNotLocalVariable = const MessageCode(
+    "PatternAssignmentNotLocalVariable",
+    analyzerCodes: <String>["PATTERN_ASSIGNMENT_NOT_LOCAL_VARIABLE"],
+    problemMessage:
+        r"""Only local variables or formal parameters can be used in pattern assignments.""",
+    correctionMessage: r"""Try assigning to a local variable.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codePlatformPrivateLibraryAccess =
     messagePlatformPrivateLibraryAccess;
 
@@ -10519,6 +11042,19 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeRefutablePatternInIrrefutableContext =
+    messageRefutablePatternInIrrefutableContext;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageRefutablePatternInIrrefutableContext = const MessageCode(
+    "RefutablePatternInIrrefutableContext",
+    analyzerCodes: <String>["REFUTABLE_PATTERN_IN_IRREFUTABLE_CONTEXT"],
+    problemMessage:
+        r"""Refutable patterns can't be used in an irrefutable context.""",
+    correctionMessage:
+        r"""Try using an if-case, a 'switch' statement, or a 'switch' expression instead.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(String name)>
     templateRequiredNamedParameterHasDefaultValueError =
     const Template<Message Function(String name)>(
@@ -10557,6 +11093,28 @@
         r"""Try removing the default value or making the parameter optional.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeRestElementWithSubpatternInMapPattern =
+    messageRestElementWithSubpatternInMapPattern;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageRestElementWithSubpatternInMapPattern =
+    const MessageCode("RestElementWithSubpatternInMapPattern",
+        analyzerCodes: <String>["REST_ELEMENT_WITH_SUBPATTERN_IN_MAP_PATTERN"],
+        problemMessage:
+            r"""A rest element in a map pattern can't have a subpattern.""",
+        correctionMessage: r"""Try removing the subpattern.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeRestPatternNotLastInMapPattern =
+    messageRestPatternNotLastInMapPattern;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageRestPatternNotLastInMapPattern = const MessageCode(
+    "RestPatternNotLastInMapPattern",
+    problemMessage:
+        r"""The '...' pattern can appear only at the end in map patterns.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeRethrowNotCatch = messageRethrowNotCatch;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -10687,7 +11245,7 @@
             name)> templateSealedClassSubtypeOutsideOfLibrary = const Template<
         Message Function(String name)>(
     problemMessageTemplate:
-        r"""Sealed class '#name' can't be extended, implemented, or mixed in outside of its library.""",
+        r"""The class '#name' can't be extended, implemented, or mixed in outside of its library because it's a sealed class.""",
     withArguments: _withArgumentsSealedClassSubtypeOutsideOfLibrary);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -10703,7 +11261,7 @@
   name = demangleMixinApplicationName(name);
   return new Message(codeSealedClassSubtypeOutsideOfLibrary,
       problemMessage:
-          """Sealed class '${name}' can't be extended, implemented, or mixed in outside of its library.""",
+          """The class '${name}' can't be extended, implemented, or mixed in outside of its library because it's a sealed class.""",
       arguments: {'name': name});
 }
 
@@ -10714,7 +11272,7 @@
             name)> templateSealedMixinSubtypeOutsideOfLibrary = const Template<
         Message Function(String name)>(
     problemMessageTemplate:
-        r"""Sealed mixin '#name' can't be mixed in outside of its library.""",
+        r"""The mixin '#name' can't be mixed in outside of its library because it's a sealed mixin.""",
     withArguments: _withArgumentsSealedMixinSubtypeOutsideOfLibrary);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -10730,7 +11288,7 @@
   name = demangleMixinApplicationName(name);
   return new Message(codeSealedMixinSubtypeOutsideOfLibrary,
       problemMessage:
-          """Sealed mixin '${name}' can't be mixed in outside of its library.""",
+          """The mixin '${name}' can't be mixed in outside of its library because it's a sealed mixin.""",
       arguments: {'name': name});
 }
 
@@ -12043,6 +12601,55 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeUnnamedObjectPatternField =
+    messageUnnamedObjectPatternField;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageUnnamedObjectPatternField = const MessageCode(
+    "UnnamedObjectPatternField",
+    problemMessage: r"""A pattern field in an object pattern must be named.""",
+    correctionMessage:
+        r"""Try adding a pattern name or ':' before the pattern.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeUnnecessaryNullAssertPattern =
+    messageUnnecessaryNullAssertPattern;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageUnnecessaryNullAssertPattern = const MessageCode(
+    "UnnecessaryNullAssertPattern",
+    analyzerCodes: <String>["UNNECESSARY_NULL_ASSERT_PATTERN"],
+    severity: Severity.warning,
+    problemMessage:
+        r"""The null-assert pattern will have no effect because the matched type isn't nullable.""",
+    correctionMessage:
+        r"""Try replacing the null-assert pattern with its nested pattern.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeUnnecessaryNullCheckPattern =
+    messageUnnecessaryNullCheckPattern;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageUnnecessaryNullCheckPattern = const MessageCode(
+    "UnnecessaryNullCheckPattern",
+    analyzerCodes: <String>["UNNECESSARY_NULL_CHECK_PATTERN"],
+    severity: Severity.warning,
+    problemMessage:
+        r"""The null-check pattern will have no effect because the matched type isn't nullable.""",
+    correctionMessage:
+        r"""Try replacing the null-check pattern with its nested pattern.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeUnreachableSwitchCase = messageUnreachableSwitchCase;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageUnreachableSwitchCase = const MessageCode(
+    "UnreachableSwitchCase",
+    analyzerCodes: <String>["UNREACHABLE_SWITCH_CASE"],
+    severity: Severity.warning,
+    problemMessage: r"""This case is covered by the previous cases.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
     Message Function(
         String name,
@@ -12281,6 +12888,31 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String name)>
+    templateVariablePatternTypeMismatchInSwitchHeads =
+    const Template<Message Function(String name)>(
+        problemMessageTemplate:
+            r"""Variable pattern '#name' doesn't have the same type in all cases.""",
+        withArguments: _withArgumentsVariablePatternTypeMismatchInSwitchHeads);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+    codeVariablePatternTypeMismatchInSwitchHeads =
+    const Code<Message Function(String name)>(
+  "VariablePatternTypeMismatchInSwitchHeads",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsVariablePatternTypeMismatchInSwitchHeads(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeVariablePatternTypeMismatchInSwitchHeads,
+      problemMessage:
+          """Variable pattern '${name}' doesn't have the same type in all cases.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeVerificationErrorOriginContext =
     messageVerificationErrorOriginContext;
 
@@ -12329,7 +12961,7 @@
     problemMessageTemplate:
         r"""The integer literal #string can't be represented exactly in JavaScript.""",
     correctionMessageTemplate:
-        r"""Try changing the literal to something that can be represented in Javascript. In Javascript #string2 is the nearest value that can be represented exactly.""",
+        r"""Try changing the literal to something that can be represented in JavaScript. In JavaScript #string2 is the nearest value that can be represented exactly.""",
     withArguments: _withArgumentsWebLiteralCannotBeRepresentedExactly);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -12347,7 +12979,7 @@
   return new Message(codeWebLiteralCannotBeRepresentedExactly,
       problemMessage:
           """The integer literal ${string} can't be represented exactly in JavaScript.""",
-      correctionMessage: """Try changing the literal to something that can be represented in Javascript. In Javascript ${string2} is the nearest value that can be represented exactly.""",
+      correctionMessage: """Try changing the literal to something that can be represented in JavaScript. In JavaScript ${string2} is the nearest value that can be represented exactly.""",
       arguments: {'string': string, 'string2': string2});
 }
 
diff --git a/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart b/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
index 5a0aa9d..b45c6a9 100644
--- a/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
+++ b/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
@@ -73,11 +73,24 @@
       Token? macroToken,
       Token? inlineToken,
       Token? sealedToken,
+      Token? baseToken,
+      Token? interfaceToken,
+      Token? finalToken,
       Token? augmentToken,
       Token? mixinToken,
       Token name) {
-    listener?.beginClassDeclaration(begin, abstractToken, macroToken,
-        inlineToken, sealedToken, augmentToken, mixinToken, name);
+    listener?.beginClassDeclaration(
+        begin,
+        abstractToken,
+        macroToken,
+        inlineToken,
+        sealedToken,
+        baseToken,
+        interfaceToken,
+        finalToken,
+        augmentToken,
+        mixinToken,
+        name);
   }
 
   @override
@@ -387,9 +400,15 @@
 
   @override
   void beginMixinDeclaration(
-      Token? augmentToken, Token? sealedToken, Token mixinKeyword, Token name) {
-    listener?.beginMixinDeclaration(
-        augmentToken, sealedToken, mixinKeyword, name);
+      Token? augmentToken,
+      Token? sealedToken,
+      Token? baseToken,
+      Token? interfaceToken,
+      Token? finalToken,
+      Token mixinKeyword,
+      Token name) {
+    listener?.beginMixinDeclaration(augmentToken, sealedToken, baseToken,
+        interfaceToken, finalToken, mixinKeyword, name);
   }
 
   @override
@@ -404,11 +423,24 @@
       Token? macroToken,
       Token? inlineToken,
       Token? sealedToken,
+      Token? baseToken,
+      Token? interfaceToken,
+      Token? finalToken,
       Token? augmentToken,
       Token? mixinToken,
       Token name) {
-    listener?.beginNamedMixinApplication(begin, abstractToken, macroToken,
-        inlineToken, sealedToken, augmentToken, mixinToken, name);
+    listener?.beginNamedMixinApplication(
+        begin,
+        abstractToken,
+        macroToken,
+        inlineToken,
+        sealedToken,
+        baseToken,
+        interfaceToken,
+        finalToken,
+        augmentToken,
+        mixinToken,
+        name);
   }
 
   @override
@@ -1837,6 +1869,11 @@
   }
 
   @override
+  void beginSwitchCaseWhenClause(Token when) {
+    listener?.beginSwitchCaseWhenClause(when);
+  }
+
+  @override
   void endRecordLiteral(Token token, int count, Token? constKeyword) {
     listener?.endRecordLiteral(token, count, constKeyword);
   }
@@ -1857,13 +1894,23 @@
   }
 
   @override
+  void endSwitchCaseWhenClause(Token token) {
+    listener?.endSwitchCaseWhenClause(token);
+  }
+
+  @override
   void handleParenthesizedPattern(Token token) {
     listener?.handleParenthesizedPattern(token);
   }
 
   @override
-  void handleConstantPattern(Token? constKeyword) {
-    listener?.handleConstantPattern(constKeyword);
+  void beginConstantPattern(Token? constKeyword) {
+    listener?.beginConstantPattern(constKeyword);
+  }
+
+  @override
+  void endConstantPattern(Token? constKeyword) {
+    listener?.endConstantPattern(constKeyword);
   }
 
   @override
@@ -1942,6 +1989,16 @@
   }
 
   @override
+  void handleSwitchCaseNoWhenClause(Token token) {
+    listener?.handleSwitchCaseNoWhenClause(token);
+  }
+
+  @override
+  void handleSwitchExpressionCasePattern(Token token) {
+    listener?.handleSwitchExpressionCasePattern(token);
+  }
+
+  @override
   void handleSymbolVoid(Token token) {
     listener?.handleSymbolVoid(token);
   }
diff --git a/_fe_analyzer_shared/lib/src/parser/listener.dart b/_fe_analyzer_shared/lib/src/parser/listener.dart
index f570f57..d21ca1b 100644
--- a/_fe_analyzer_shared/lib/src/parser/listener.dart
+++ b/_fe_analyzer_shared/lib/src/parser/listener.dart
@@ -139,6 +139,9 @@
       Token? macroToken,
       Token? inlineToken,
       Token? sealedToken,
+      Token? baseToken,
+      Token? interfaceToken,
+      Token? finalToken,
       Token? augmentToken,
       Token? mixinToken,
       Token name) {}
@@ -200,8 +203,14 @@
   }
 
   /// Handle the beginning of a mixin declaration.
-  void beginMixinDeclaration(Token? augmentToken, Token? sealedToken,
-      Token mixinKeyword, Token name) {}
+  void beginMixinDeclaration(
+      Token? augmentToken,
+      Token? sealedToken,
+      Token? baseToken,
+      Token? interfaceToken,
+      Token? finalToken,
+      Token mixinKeyword,
+      Token name) {}
 
   /// Handle an on clause in a mixin declaration. Substructures:
   /// - implemented types
@@ -648,7 +657,7 @@
   }
 
   /// Handle the beginning of a named function expression which isn't legal
-  /// syntax in Dart.  Useful for recovering from Javascript code being pasted
+  /// syntax in Dart.  Useful for recovering from JavaScript code being pasted
   /// into a Dart program, as it will interpret `function foo() {}` as a named
   /// function expression with return type `function` and name `foo`.
   ///
@@ -657,7 +666,7 @@
   void beginNamedFunctionExpression(Token token) {}
 
   /// A named function expression which isn't legal syntax in Dart.
-  /// Useful for recovering from Javascript code being pasted into a Dart
+  /// Useful for recovering from JavaScript code being pasted into a Dart
   /// program, as it will interpret `function foo() {}` as a named function
   /// expression with return type `function` and name `foo`.
   ///
@@ -785,6 +794,9 @@
       Token? macroToken,
       Token? inlineToken,
       Token? sealedToken,
+      Token? baseToken,
+      Token? interfaceToken,
+      Token? finalToken,
       Token? augmentToken,
       Token? mixinToken,
       Token name) {}
@@ -1874,6 +1886,15 @@
     logEvent("Operator");
   }
 
+  /// Invoked when a pattern switch case doesn't have the 'when' clause
+  void handleSwitchCaseNoWhenClause(Token token) {
+    logEvent("SwitchCaseNoWhenClause");
+  }
+
+  void handleSwitchExpressionCasePattern(Token token) {
+    logEvent("SwitchExpressionCasePattern");
+  }
+
   void handleSymbolVoid(Token token) {
     logEvent("SymbolVoid");
   }
@@ -1907,6 +1928,11 @@
   /// either [endParenthesizedExpression] or [endRecordLiteral].
   void beginParenthesizedExpressionOrRecordLiteral(Token token) {}
 
+  /// Starts a guard expression in a switch case, after the 'when' keyword
+  void beginSwitchCaseWhenClause(Token when) {
+    logEvent("SwitchCaseWhenClause");
+  }
+
   /// Ends a record literal with [count] entries.
   void endRecordLiteral(Token token, int count, Token? constKeyword) {
     logEvent("RecordLiteral");
@@ -1930,6 +1956,11 @@
     logEvent("ParenthesizedExpression");
   }
 
+  /// Starts a guard expression in a switch case, after the 'when' keyword
+  void endSwitchCaseWhenClause(Token token) {
+    logEvent("SwitchCaseWhenClause");
+  }
+
   /// Called after the parser has consumed a parenthesized pattern, consisting
   /// of a `(`, a pattern, and a `)`.
   void handleParenthesizedPattern(Token token) {
@@ -1944,8 +1975,23 @@
   /// pattern or the constant expression.  This ambiguity is resolved in favor
   /// of associating the `const` keyword with the constant pattern.  So for
   /// example, in `case const []` the `const` keyword is passed to
-  /// [handleConstantPattern] rather than [handleLiteralList].
-  void handleConstantPattern(Token? constKeyword) {
+  /// [beginConstantPattern] and [endConstantPattern] rather than
+  /// [handleLiteralList].
+  void beginConstantPattern(Token? constKeyword) {
+    logEvent("ConstantPattern");
+  }
+
+  /// Called after the parser has consumed a constant pattern, consisting of an
+  /// optional `const` and an expression.
+  ///
+  /// Note that some expressions can legally begin with `const`, so there is
+  /// ambiguity as to whether to associate the `const` keyword with the constant
+  /// pattern or the constant expression.  This ambiguity is resolved in favor
+  /// of associating the `const` keyword with the constant pattern.  So for
+  /// example, in `case const []` the `const` keyword is passed to
+  /// [beginConstantPattern] and [endConstantPattern] rather than
+  /// [handleLiteralList].
+  void endConstantPattern(Token? constKeyword) {
     logEvent("ConstantPattern");
   }
 
diff --git a/_fe_analyzer_shared/lib/src/parser/literal_entry_info_impl.dart b/_fe_analyzer_shared/lib/src/parser/literal_entry_info_impl.dart
index 791b8e1..02621b4 100644
--- a/_fe_analyzer_shared/lib/src/parser/literal_entry_info_impl.dart
+++ b/_fe_analyzer_shared/lib/src/parser/literal_entry_info_impl.dart
@@ -50,8 +50,8 @@
         // Process `for ( pattern in expression )`
         assert(optional('in', token.next!));
         _inStyle = true;
-        return parser.parseForInLoopPartsRest(
-            token, awaitToken, forToken, patternKeyword, null);
+        return parser.parseForInLoopPartsRest(token, awaitToken, forToken,
+            patternKeyword, /* identifier = */ null);
       }
     }
     Token identifier = token.next!;
@@ -61,7 +61,7 @@
       // Process `for ( ... in ... )`
       _inStyle = true;
       token = parser.parseForInLoopPartsRest(
-          token, awaitToken, forToken, null, identifier);
+          token, awaitToken, forToken, /* patternKeyword = */ null, identifier);
     } else {
       // Process `for ( ... ; ... ; ... )`
       _inStyle = false;
diff --git a/_fe_analyzer_shared/lib/src/parser/modifier_context.dart b/_fe_analyzer_shared/lib/src/parser/modifier_context.dart
index 96b2711..814e125 100644
--- a/_fe_analyzer_shared/lib/src/parser/modifier_context.dart
+++ b/_fe_analyzer_shared/lib/src/parser/modifier_context.dart
@@ -128,7 +128,6 @@
       reportTopLevelModifierError(externalToken!, keyword);
     }
     reportExtraneousModifier(covariantToken);
-    reportExtraneousModifier(finalToken);
     reportExtraneousModifier(lateToken);
     reportExtraneousModifier(requiredToken);
     reportExtraneousModifier(staticToken);
@@ -160,7 +159,6 @@
     reportTopLevelModifierError(externalToken, keyword);
     reportExtraneousModifier(abstractToken);
     reportExtraneousModifier(covariantToken);
-    reportExtraneousModifier(finalToken);
     reportExtraneousModifier(lateToken);
     reportExtraneousModifier(requiredToken);
     reportExtraneousModifier(staticToken);
diff --git a/_fe_analyzer_shared/lib/src/parser/parser.dart b/_fe_analyzer_shared/lib/src/parser/parser.dart
index 72c8899..3ed93de 100644
--- a/_fe_analyzer_shared/lib/src/parser/parser.dart
+++ b/_fe_analyzer_shared/lib/src/parser/parser.dart
@@ -35,7 +35,7 @@
 
 export 'member_kind.dart' show MemberKind;
 
-export 'parser_impl.dart' show Parser;
+export 'parser_impl.dart' show ConstantPatternContext, Parser;
 
 export 'parser_error.dart' show ParserError;
 
diff --git a/_fe_analyzer_shared/lib/src/parser/parser_impl.dart b/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
index 578f0cd..7ca1b52 100644
--- a/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
+++ b/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
@@ -526,6 +526,8 @@
           /* macroToken = */ null,
           /* inlineToken = */ null,
           /* sealedToken = */ null,
+          /* baseToken = */ null,
+          /* interfaceToken = */ null,
           directiveState);
     }
     Token start = token;
@@ -533,10 +535,14 @@
     if (next.isModifier) {
       if (optional('var', next) ||
           optional('late', next) ||
-          ((optional('const', next) || optional('final', next)) &&
-              // Ignore `const class` and `final class` so that it is reported
-              // below as an invalid modifier on a class.
-              !optional('class', next.next!))) {
+          (optional('final', next) &&
+              (!optional('class', next.next!) &&
+                  !optional('mixin', next.next!))) ||
+          // Ignore using 'final' as a modifier for a class or a mixin, but
+          // allow in other contexts.
+          (optional('const', next) && !optional('class', next.next!))) {
+        // Ignore `const class` so that it is reported below as an invalid
+        // modifier on a class.
         directiveState?.checkDeclaration();
         return parseTopLevelMemberImpl(token);
       }
@@ -548,6 +554,8 @@
     Token? macroToken;
     Token? inlineToken;
     Token? sealedToken;
+    Token? baseToken;
+    Token? interfaceToken;
     if (next.isIdentifier &&
         next.lexeme == 'inline' &&
         optional('class', next.next!)) {
@@ -569,6 +577,17 @@
         start = next;
         next = next.next!.next!;
       }
+    } else if (next.isIdentifier && next.lexeme == 'base') {
+      baseToken = next;
+      if (optional('class', next.next!) || optional('mixin', next.next!)) {
+        next = next.next!;
+      }
+    } else if (next.isIdentifier && next.lexeme == 'interface') {
+      interfaceToken = next;
+      if (optional('class', next.next!) || optional('mixin', next.next!)) {
+        next = next.next!;
+      }
+      // TODO(kallentu): Handle incorrect ordering of modifiers.
     }
     if (next.isTopLevelKeyword) {
       return parseTopLevelKeywordDeclaration(
@@ -577,6 +596,8 @@
           /* macroToken = */ macroToken,
           /* inlineToken = */ inlineToken,
           /* sealedToken = */ sealedToken,
+          /* baseToken = */ baseToken,
+          /* interfaceToken = */ interfaceToken,
           directiveState);
     } else if (next.isKeywordOrIdentifier) {
       // TODO(danrubel): improve parseTopLevelMember
@@ -615,12 +636,22 @@
       Token? macroToken,
       Token? inlineToken,
       Token? sealedToken,
+      Token? baseToken,
+      Token? interfaceToken,
       DirectiveContext? directiveState) {
     assert(keyword.isTopLevelKeyword);
     final String? value = keyword.stringValue;
     if (identical(value, 'class')) {
-      return _handleModifiersForClassDeclaration(start, keyword, macroToken,
-          inlineToken, sealedToken, null, directiveState);
+      return _handleModifiersForClassDeclaration(
+          start,
+          keyword,
+          macroToken,
+          inlineToken,
+          sealedToken,
+          baseToken,
+          interfaceToken,
+          /* mixinToken = */ null,
+          directiveState);
     } else if (identical(value, 'enum')) {
       directiveState?.checkDeclaration();
       ModifierContext context = new ModifierContext(this);
@@ -679,12 +710,23 @@
           return parseTypedef(keyword);
         } else if (identical(value, 'mixin')) {
           if (identical(nextValue, 'class')) {
-            return _handleModifiersForClassDeclaration(start, keyword.next!,
-                macroToken, inlineToken, sealedToken, keyword, directiveState);
+            // TODO(kallentu): Error handling for any class modifier here other
+            // than base. Only base mixin classes are allowed.
+            return _handleModifiersForClassDeclaration(
+                start,
+                keyword.next!,
+                macroToken,
+                inlineToken,
+                sealedToken,
+                baseToken,
+                /* interfaceToken = */ null,
+                keyword,
+                directiveState);
           }
           context.parseMixinModifiers(start, keyword);
           directiveState?.checkDeclaration();
-          return parseMixin(context.augmentToken, sealedToken, keyword);
+          return parseMixin(context.augmentToken, sealedToken, baseToken,
+              interfaceToken, context.finalToken, keyword);
         } else if (identical(value, 'extension')) {
           context.parseTopLevelKeywordModifiers(start, keyword);
           directiveState?.checkDeclaration();
@@ -715,6 +757,8 @@
       Token? macroToken,
       Token? inlineToken,
       Token? sealedToken,
+      Token? baseToken,
+      Token? interfaceToken,
       Token? mixinToken,
       DirectiveContext? directiveState) {
     directiveState?.checkDeclaration();
@@ -724,10 +768,17 @@
     } else {
       context.parseClassModifiers(start, classKeyword);
     }
-    Token? abstractToken = context.abstractToken;
-    Token? augmentToken = context.augmentToken;
-    return parseClassOrNamedMixinApplication(abstractToken, macroToken,
-        inlineToken, sealedToken, augmentToken, mixinToken, classKeyword);
+    return parseClassOrNamedMixinApplication(
+        context.abstractToken,
+        macroToken,
+        inlineToken,
+        sealedToken,
+        baseToken,
+        interfaceToken,
+        context.finalToken,
+        context.augmentToken,
+        mixinToken,
+        classKeyword);
   }
 
   bool _isIdentifierOrQuestionIdentifier(Token token) {
@@ -1234,7 +1285,7 @@
       reportRecoverableError(
           token, codes.messageMetadataTypeArgumentsUninstantiated);
     }
-    token = parseArgumentsOptMetadata(token);
+    token = parseArgumentsOptMetadata(token, hasTypeArguments);
     listener.endMetadata(atToken, period, token.next!);
     return token;
   }
@@ -1328,7 +1379,7 @@
             bool recover = false;
             if (optional(';', endGroup.next!)) {
               // Missing parenthesis. Insert them.
-              // Turn "<whatever>;" in to "<whatever>();"
+              // Turn "<whatever>;" into "<whatever>();"
               // Insert missing 'Function' below.
               reportRecoverableError(endGroup,
                   missingParameterMessage(MemberKind.FunctionTypeAlias));
@@ -1894,9 +1945,6 @@
       next = token.next!;
     }
 
-    final bool isNamedParameter =
-        parameterKind == FormalParameterKind.optionalNamed;
-
     Token? thisKeyword;
     Token? superKeyword;
     Token? periodAfterThisOrSuper;
@@ -2006,6 +2054,7 @@
     if (periodAfterThisOrSuper != null) {
       token = periodAfterThisOrSuper;
     }
+    final bool isNamedParameter = parameterKind.isNamed;
     next = token.next!;
     if (inFunctionType &&
         !isNamedParameter &&
@@ -2486,6 +2535,9 @@
       Token? macroToken,
       Token? inlineToken,
       Token? sealedToken,
+      Token? baseToken,
+      Token? interfaceToken,
+      Token? finalToken,
       Token? augmentToken,
       Token? mixinToken,
       Token classKeyword) {
@@ -2501,12 +2553,32 @@
       reportRecoverableError(sealedToken, codes.messageAbstractSealedClass);
     }
     if (optional('=', token.next!)) {
-      listener.beginNamedMixinApplication(begin, abstractToken, macroToken,
-          inlineToken, sealedToken, augmentToken, mixinToken, name);
+      listener.beginNamedMixinApplication(
+          begin,
+          abstractToken,
+          macroToken,
+          inlineToken,
+          sealedToken,
+          baseToken,
+          interfaceToken,
+          finalToken,
+          augmentToken,
+          mixinToken,
+          name);
       return parseNamedMixinApplication(token, begin, classKeyword);
     } else {
-      listener.beginClassDeclaration(begin, abstractToken, macroToken,
-          inlineToken, sealedToken, augmentToken, mixinToken, name);
+      listener.beginClassDeclaration(
+          begin,
+          abstractToken,
+          macroToken,
+          inlineToken,
+          sealedToken,
+          baseToken,
+          interfaceToken,
+          finalToken,
+          augmentToken,
+          mixinToken,
+          name);
       return parseClass(token, begin, classKeyword, name.lexeme);
     }
   }
@@ -2720,13 +2792,15 @@
   ///
   /// ```
   /// mixinDeclaration:
-  ///   metadata? 'augment'? 'sealed'? 'mixin' [SimpleIdentifier]
+  ///   metadata? 'augment'? mixinModifiers? 'mixin' [SimpleIdentifier]
   ///        [TypeParameterList]? [OnClause]? [ImplementsClause]?
   ///        '{' [ClassMember]* '}'
   /// ;
+  ///
+  /// mixinModifiers: 'sealed' | 'base' | 'interface' | 'final'
   /// ```
-  Token parseMixin(
-      Token? augmentToken, Token? sealedToken, Token mixinKeyword) {
+  Token parseMixin(Token? augmentToken, Token? sealedToken, Token? baseToken,
+      Token? interfaceToken, Token? finalToken, Token mixinKeyword) {
     assert(optional('mixin', mixinKeyword));
     listener.beginClassOrMixinOrNamedMixinApplicationPrelude(mixinKeyword);
     Token name = ensureIdentifier(
@@ -2734,8 +2808,8 @@
     Token headerStart = computeTypeParamOrArg(
             name, /* inDeclaration = */ true, /* allowsVariance = */ true)
         .parseVariables(name, this);
-    listener.beginMixinDeclaration(
-        augmentToken, sealedToken, mixinKeyword, name);
+    listener.beginMixinDeclaration(augmentToken, sealedToken, baseToken,
+        interfaceToken, finalToken, mixinKeyword, name);
     Token token = parseMixinHeaderOpt(headerStart, mixinKeyword);
     if (!optional('{', token.next!)) {
       // Recovery
@@ -4922,7 +4996,7 @@
   ///
   /// If [isFunctionExpression] is true, this method parses the rest of named
   /// function expression which isn't legal syntax in Dart.  Useful for
-  /// recovering from Javascript code being pasted into a Dart program, as it
+  /// recovering from JavaScript code being pasted into a Dart program, as it
   /// will interpret `function foo() {}` as a named function expression with
   /// return type `function` and name `foo`.
   ///
@@ -5490,8 +5564,8 @@
       } else {
         token = optional('throw', token.next!)
             ? parseThrowExpression(token, /* allowCascades = */ true)
-            : parsePrecedenceExpression(
-                token, ASSIGNMENT_PRECEDENCE, /* allowCascades = */ true);
+            : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE,
+                /* allowCascades = */ true, ConstantPatternContext.none);
       }
     }
     expressionDepth--;
@@ -5501,8 +5575,8 @@
   Token parseExpressionWithoutCascade(Token token) {
     return optional('throw', token.next!)
         ? parseThrowExpression(token, /* allowCascades = */ false)
-        : parsePrecedenceExpression(
-            token, ASSIGNMENT_PRECEDENCE, /* allowCascades = */ false);
+        : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE,
+            /* allowCascades = */ false, ConstantPatternContext.none);
   }
 
   bool canParseAsConditional(Token question) {
@@ -5546,34 +5620,44 @@
     return token;
   }
 
-  Token parsePrecedenceExpression(
-      Token token, int precedence, bool allowCascades) {
+  Token parsePrecedenceExpression(Token token, int precedence,
+      bool allowCascades, ConstantPatternContext constantPatternContext) {
     assert(precedence >= 1);
     assert(precedence <= SELECTOR_PRECEDENCE);
-    token = parseUnaryExpression(token, allowCascades);
+    token = parseUnaryExpression(token, allowCascades, constantPatternContext);
     Token bangToken = token;
     if (optional('!', token.next!)) {
       bangToken = token.next!;
     }
     TypeParamOrArgInfo typeArg = computeMethodTypeArguments(bangToken);
     if (typeArg != noTypeParamOrArg) {
-      // For example a(b)<T>(c), where token is before '<'.
       if (optional('!', bangToken)) {
+        // For example `e!<int>()`, where [token] is before '<'.
         listener.handleNonNullAssertExpression(bangToken);
       }
       token = typeArg.parseArguments(bangToken, this);
       if (!optional('(', token.next!)) {
+        // For example `e<a, b>;`, where [token] is before ';' or
+        // `C<int>.new`, where [token] is before '.'.
+        if (constantPatternContext != ConstantPatternContext.none) {
+          reportRecoverableError(
+              bangToken.next!, codes.messageInvalidConstantPatternGeneric);
+        }
         listener.handleTypeArgumentApplication(bangToken.next!);
         typeArg = noTypeParamOrArg;
       }
     }
 
     return _parsePrecedenceExpressionLoop(
-        precedence, allowCascades, typeArg, token);
+        precedence, allowCascades, typeArg, token, constantPatternContext);
   }
 
-  Token _parsePrecedenceExpressionLoop(int precedence, bool allowCascades,
-      TypeParamOrArgInfo typeArg, Token token) {
+  Token _parsePrecedenceExpressionLoop(
+      int precedence,
+      bool allowCascades,
+      TypeParamOrArgInfo typeArg,
+      Token token,
+      ConstantPatternContext constantPatternContext) {
     Token next = token.next!;
     TokenType type = next.type;
     int tokenLevel = _computePrecedence(next, forPattern: false);
@@ -5609,7 +5693,8 @@
           }
           token = optional('throw', next.next!)
               ? parseThrowExpression(next, /* allowCascades = */ false)
-              : parsePrecedenceExpression(next, level, allowCascades);
+              : parsePrecedenceExpression(
+                  next, level, allowCascades, ConstantPatternContext.none);
           listener.handleAssignmentExpression(operator);
         } else if (identical(tokenLevel, POSTFIX_PRECEDENCE)) {
           if ((identical(type, TokenType.PLUS_PLUS)) ||
@@ -5629,7 +5714,9 @@
             // unary expression isn't legal after a period, so we call
             // [parsePrimary] instead.
             token = parsePrimary(
-                token.next!, IdentifierContext.expressionContinuation);
+                token.next!,
+                IdentifierContext.expressionContinuation,
+                ConstantPatternContext.none);
             listener.handleEndingBinaryExpression(operator);
 
             Token bangToken = token;
@@ -5644,6 +5731,10 @@
               }
               token = typeArg.parseArguments(bangToken, this);
               if (!optional('(', token.next!)) {
+                if (constantPatternContext != ConstantPatternContext.none) {
+                  reportRecoverableError(bangToken.next!,
+                      codes.messageInvalidConstantPatternGeneric);
+                }
                 listener.handleTypeArgumentApplication(bangToken.next!);
                 typeArg = noTypeParamOrArg;
               }
@@ -5703,8 +5794,8 @@
           listener.beginBinaryExpression(next);
           // Left associative, so we recurse at the next higher
           // precedence level.
-          token =
-              parsePrecedenceExpression(token.next!, level + 1, allowCascades);
+          token = parsePrecedenceExpression(token.next!, level + 1,
+              allowCascades, ConstantPatternContext.none);
           listener.endBinaryExpression(operator);
         }
         next = token.next!;
@@ -5728,8 +5819,8 @@
       // Attempt recovery
       if (_attemptPrecedenceLevelRecovery(
           token, precedence, /* currentLevel = */ -1, allowCascades, typeArg)) {
-        return _parsePrecedenceExpressionLoop(
-            precedence, allowCascades, typeArg, token);
+        return _parsePrecedenceExpressionLoop(precedence, allowCascades,
+            typeArg, token, ConstantPatternContext.none);
       }
     }
     return token;
@@ -5773,8 +5864,8 @@
       cachedRewriter = undoableTokenStreamRewriter;
       rewriter.replaceNextTokenWithSyntheticToken(token, replacement);
       bool acceptRecovery = false;
-      Token afterExpression = _parsePrecedenceExpressionLoop(
-          precedence, allowCascades, typeArg, token);
+      Token afterExpression = _parsePrecedenceExpressionLoop(precedence,
+          allowCascades, typeArg, token, ConstantPatternContext.none);
       Token afterExpressionNext = afterExpression.next!;
 
       if (!nullListener.hasErrors &&
@@ -5939,14 +6030,16 @@
     return token;
   }
 
-  Token parseUnaryExpression(Token token, bool allowCascades) {
+  Token parseUnaryExpression(Token token, bool allowCascades,
+      ConstantPatternContext constantPatternContext) {
     String? value = token.next!.stringValue;
     // Prefix:
     if (identical(value, 'await')) {
       if (inPlainSync) {
         if (!looksLikeAwaitExpression(
             token, AwaitOrYieldContext.UnaryExpression)) {
-          return parsePrimary(token, IdentifierContext.expression);
+          return parsePrimary(
+              token, IdentifierContext.expression, ConstantPatternContext.none);
         }
         // Recovery: Looks like an expression preceded by `await`.
         // Fall through and let parseAwaitExpression report the error.
@@ -5960,15 +6053,31 @@
           codes.messageUnsupportedPrefixPlus,
           new SyntheticStringToken(
               TokenType.IDENTIFIER, '', token.next!.offset));
-      return parsePrimary(token, IdentifierContext.expression);
-    } else if ((identical(value, '!')) ||
-        (identical(value, '-')) ||
-        (identical(value, '~'))) {
+      return parsePrimary(
+          token, IdentifierContext.expression, constantPatternContext);
+    } else if ((identical(value, '!')) || (identical(value, '~'))) {
+      Token operator = token.next!;
+      if (constantPatternContext != ConstantPatternContext.none) {
+        reportRecoverableError(operator,
+            codes.templateInvalidConstantPatternUnary.withArguments(value!));
+      }
+      // Right associative, so we recurse at the same precedence
+      // level.
+      token = parsePrecedenceExpression(operator, POSTFIX_PRECEDENCE,
+          allowCascades, ConstantPatternContext.none);
+      listener.handleUnaryPrefixExpression(operator);
+      return token;
+    } else if (identical(value, '-')) {
       Token operator = token.next!;
       // Right associative, so we recurse at the same precedence
       // level.
       token = parsePrecedenceExpression(
-          token.next!, POSTFIX_PRECEDENCE, allowCascades);
+          operator,
+          POSTFIX_PRECEDENCE,
+          allowCascades,
+          constantPatternContext != ConstantPatternContext.none
+              ? ConstantPatternContext.numericLiteralOnly
+              : ConstantPatternContext.none);
       listener.handleUnaryPrefixExpression(operator);
       return token;
     } else if ((identical(value, '++')) || identical(value, '--')) {
@@ -5976,8 +6085,8 @@
       Token operator = token.next!;
       // Right associative, so we recurse at the same precedence
       // level.
-      token = parsePrecedenceExpression(
-          token.next!, POSTFIX_PRECEDENCE, allowCascades);
+      token = parsePrecedenceExpression(operator, POSTFIX_PRECEDENCE,
+          allowCascades, ConstantPatternContext.none);
       listener.handleUnaryPrefixAssignmentExpression(operator);
       return token;
     } else if (useImplicitCreationExpression && token.next!.isIdentifier) {
@@ -6004,7 +6113,8 @@
         }
       }
     }
-    return parsePrimary(token, IdentifierContext.expression);
+    return parsePrimary(
+        token, IdentifierContext.expression, constantPatternContext);
   }
 
   Token parseArgumentOrIndexStar(
@@ -6100,24 +6210,48 @@
     return token;
   }
 
-  Token parsePrimary(Token token, IdentifierContext context) {
+  Token parsePrimary(Token token, IdentifierContext context,
+      ConstantPatternContext constantPatternContext) {
     _tryRewriteNewToIdentifier(token, context);
-    final int kind = token.next!.kind;
+    final Token next = token.next!;
+    final int kind = next.kind;
     if (kind == IDENTIFIER_TOKEN) {
+      if (constantPatternContext == ConstantPatternContext.numericLiteralOnly) {
+        reportRecoverableError(
+            next, codes.messageInvalidConstantPatternNegation);
+      }
       return parseSendOrFunctionLiteral(token, context);
     } else if (kind == INT_TOKEN || kind == HEXADECIMAL_TOKEN) {
       return parseLiteralInt(token);
     } else if (kind == DOUBLE_TOKEN) {
       return parseLiteralDouble(token);
     } else if (kind == STRING_TOKEN) {
+      if (constantPatternContext == ConstantPatternContext.numericLiteralOnly) {
+        reportRecoverableError(
+            next, codes.messageInvalidConstantPatternNegation);
+      }
       return parseLiteralString(token);
     } else if (kind == HASH_TOKEN) {
+      if (constantPatternContext == ConstantPatternContext.numericLiteralOnly) {
+        reportRecoverableError(
+            next, codes.messageInvalidConstantPatternNegation);
+      }
       return parseLiteralSymbol(token);
     } else if (kind == KEYWORD_TOKEN) {
-      final String? value = token.next!.stringValue;
+      final String? value = next.stringValue;
       if (identical(value, "true") || identical(value, "false")) {
+        if (constantPatternContext ==
+            ConstantPatternContext.numericLiteralOnly) {
+          reportRecoverableError(
+              next, codes.messageInvalidConstantPatternNegation);
+        }
         return parseLiteralBool(token);
       } else if (identical(value, "null")) {
+        if (constantPatternContext ==
+            ConstantPatternContext.numericLiteralOnly) {
+          reportRecoverableError(
+              next, codes.messageInvalidConstantPatternNegation);
+        }
         return parseLiteralNull(token);
       } else if (identical(value, "this")) {
         return parseThisExpression(token, context);
@@ -6129,6 +6263,10 @@
       } else if (identical(value, "new")) {
         return parseNewExpression(token);
       } else if (identical(value, "const")) {
+        if (constantPatternContext == ConstantPatternContext.explicit) {
+          reportRecoverableError(
+              next, codes.messageInvalidConstantPatternDuplicateConst);
+        }
         return parseConstExpression(token);
       } else if (identical(value, "void")) {
         return parseSendOrFunctionLiteral(token, context);
@@ -6139,18 +6277,24 @@
         return parseAssert(token, Assert.Expression);
       } else if (allowPatterns && identical(value, "switch")) {
         return parseSwitchExpression(token);
-      } else if (token.next!.isIdentifier) {
+      } else if (next.isIdentifier) {
+        if (constantPatternContext ==
+            ConstantPatternContext.numericLiteralOnly) {
+          reportRecoverableError(
+              next, codes.messageInvalidConstantPatternNegation);
+        }
         return parseSendOrFunctionLiteral(token, context);
       } else if (identical(value, "return")) {
         // Recovery
         token = token.next!;
         reportRecoverableErrorWithToken(token, codes.templateUnexpectedToken);
-        return parsePrimary(token, context);
+        return parsePrimary(token, context, ConstantPatternContext.none);
       } else {
         // Fall through to the recovery code.
       }
     } else if (kind == OPEN_PAREN_TOKEN) {
-      return parseParenthesizedExpressionFunctionLiteralOrRecordLiteral(token);
+      return parseParenthesizedExpressionFunctionLiteralOrRecordLiteral(
+          token, constantPatternContext);
     } else if (kind == OPEN_SQUARE_BRACKET_TOKEN ||
         optional('[]', token.next!)) {
       listener.handleNoTypeArguments(token.next!);
@@ -6170,7 +6314,7 @@
   }
 
   Token parseParenthesizedExpressionFunctionLiteralOrRecordLiteral(
-      Token token) {
+      Token token, ConstantPatternContext constantPatternContext) {
     Token next = token.next!;
     assert(optional('(', next));
 
@@ -6202,7 +6346,7 @@
     bool old = mayParseFunctionExpressions;
     mayParseFunctionExpressions = true;
     token = parseParenthesizedExpressionOrRecordLiteral(
-        token, /* constKeywordForRecord = */ null);
+        token, /* constKeywordForRecord = */ null, constantPatternContext);
     mayParseFunctionExpressions = old;
     return token;
   }
@@ -6230,7 +6374,9 @@
   /// If [constKeywordForRecord] is non-null it is forced to be a record
   /// literal and an error will be issued if there is no trailing comma.
   Token parseParenthesizedExpressionOrRecordLiteral(
-      Token token, Token? constKeywordForRecord) {
+      Token token,
+      Token? constKeywordForRecord,
+      ConstantPatternContext constantPatternContext) {
     Token begin = token.next!;
     assert(optional('(', begin));
     listener.beginParenthesizedExpressionOrRecordLiteral(begin);
@@ -6296,6 +6442,9 @@
       } else if (count == 1 && !wasValidRecord) {
         reportRecoverableError(
             token, codes.messageRecordLiteralOnePositionalFieldNoTrailingComma);
+      } else if (constantPatternContext != ConstantPatternContext.none) {
+        reportRecoverableError(
+            token, codes.messageInvalidConstantPatternEmptyRecordLiteral);
       }
       listener.endRecordLiteral(begin, count, constKeywordForRecord);
     } else {
@@ -6723,7 +6872,8 @@
               identifier,
               codes.templateLiteralWithClassAndNew
                   .withArguments(value.toLowerCase(), identifier));
-          return parsePrimary(identifier, IdentifierContext.expression);
+          return parsePrimary(identifier, IdentifierContext.expression,
+              ConstantPatternContext.none);
         }
       } else if (value == "List" && !optional('.', identifier.next!)) {
         potentialTypeArg = computeTypeParamOrArg(identifier);
@@ -6736,7 +6886,8 @@
               identifier,
               codes.templateLiteralWithClassAndNew
                   .withArguments(value.toLowerCase(), identifier));
-          return parsePrimary(identifier, IdentifierContext.expression);
+          return parsePrimary(identifier, IdentifierContext.expression,
+              ConstantPatternContext.none);
         }
       }
     } else {
@@ -6754,12 +6905,14 @@
             optional('[]', afterToken)) {
           // Recover by ignoring the `new` and parse as a literal map/set/list.
           reportRecoverableError(newKeyword, codes.messageLiteralWithNew);
-          return parsePrimary(newKeyword, IdentifierContext.expression);
+          return parsePrimary(newKeyword, IdentifierContext.expression,
+              ConstantPatternContext.none);
         }
       } else if (value == "{" || value == "[" || value == "[]") {
         // Recover by ignoring the `new` and parse as a literal map/set/list.
         reportRecoverableError(newKeyword, codes.messageLiteralWithNew);
-        return parsePrimary(newKeyword, IdentifierContext.expression);
+        return parsePrimary(newKeyword, IdentifierContext.expression,
+            ConstantPatternContext.none);
       }
     }
 
@@ -6814,7 +6967,8 @@
     if (identical(value, '(')) {
       // Const record literal.
       listener.beginConstLiteral(next);
-      token = parseParenthesizedExpressionOrRecordLiteral(token, constKeyword);
+      token = parseParenthesizedExpressionOrRecordLiteral(
+          token, constKeyword, ConstantPatternContext.none);
       listener.endConstLiteral(token.next!);
       return token;
     }
@@ -7074,7 +7228,7 @@
               identifier,
               codes.templateLiteralWithClass
                   .withArguments(value.toLowerCase(), identifier));
-          return parsePrimary(identifier, context);
+          return parsePrimary(identifier, context, ConstantPatternContext.none);
         }
       } else if (value == "List") {
         potentialTypeArg = computeTypeParamOrArg(identifier);
@@ -7090,7 +7244,7 @@
               identifier,
               codes.templateLiteralWithClass
                   .withArguments(value.toLowerCase(), identifier));
-          return parsePrimary(identifier, context);
+          return parsePrimary(identifier, context, ConstantPatternContext.none);
         }
       }
     }
@@ -7139,13 +7293,39 @@
   /// has to follow the previous token without space.
   /// See also
   /// https://github.com/dart-lang/language/blob/master/accepted/future-releases/records/records-feature-specification.md#ambiguity-with-metadata-annotations
-  Token parseArgumentsOptMetadata(Token token) {
-    Token next = token.next!;
-    if (!optional('(', next) || (token.charEnd != next.charOffset)) {
+  Token parseArgumentsOptMetadata(Token token, bool hasTypeArguments) {
+    final Token next = token.next!;
+    if (!optional('(', next)) {
       listener.handleNoArguments(next);
       return token;
-    } else {
+    } else if (token.charEnd == next.charOffset) {
       return parseArguments(token);
+    } else {
+      // There is a '(', but it's not technically arguments to the metadata.
+      // Decide if we should recover as if it is. This should only be done
+      // if we know that it isn't a record type.
+      if (hasTypeArguments) {
+        // Arguments are required, so parse as arguments anyway.
+        reportRecoverableError(
+            next, codes.messageMetadataSpaceBeforeParenthesis);
+        return parseArguments(token);
+      }
+      final Token startParen = next;
+      final Token endParen = startParen.endGroup!;
+      final Token afterParen = endParen.next!;
+      final String? value = afterParen.stringValue;
+      if (identical(value, 'class') || identical(value, 'enum')) {
+        // The 'class' and 'enum' keywords are reserved keywords and recovery
+        // should be safe. Other keywords aren't reserved and needs more
+        // lookahead to determine if recovery here would be good.
+        //For now we don't.
+        reportRecoverableError(
+            next, codes.messageMetadataSpaceBeforeParenthesis);
+        return parseArguments(token);
+      }
+
+      listener.handleNoArguments(next);
+      return token;
     }
   }
 
@@ -7744,15 +7924,16 @@
       } else {
         // Process `for ( pattern in expression )`
         assert(optional('in', token.next!));
-        return parseForInRest(
-            token, awaitToken, forToken, patternKeyword, null);
+        return parseForInRest(token, awaitToken, forToken, patternKeyword,
+            /* identifier = */ null);
       }
     }
     Token identifier = token.next!;
     token = parseForLoopPartsMid(token, awaitToken, forToken);
     if (optional('in', token.next!) || optional(':', token.next!)) {
       // Process `for ( ... in ... )`
-      return parseForInRest(token, awaitToken, forToken, null, identifier);
+      return parseForInRest(
+          token, awaitToken, forToken, /* patternKeyword = */ null, identifier);
     } else {
       // Process `for ( ... ; ... ; ... )`
       return parseForRest(awaitToken, token, forToken);
@@ -8132,8 +8313,8 @@
     Token awaitToken = token.next!;
     assert(optional('await', awaitToken));
     listener.beginAwaitExpression(awaitToken);
-    token = parsePrecedenceExpression(
-        awaitToken, POSTFIX_PRECEDENCE, allowCascades);
+    token = parsePrecedenceExpression(awaitToken, POSTFIX_PRECEDENCE,
+        allowCascades, ConstantPatternContext.none);
     if (inAsync) {
       listener.endAwaitExpression(awaitToken, token.next!);
     } else {
@@ -8220,16 +8401,11 @@
       Token? onKeyword = null;
       if (identical(value, 'on')) {
         // 'on' type catchPart?
+        // Note https://github.com/dart-lang/language/blob/master/accepted/future-releases/records/records-feature-specification.md#ambiguity-with-on-clauses
+        // "Whenever on appears after a try block or after a preceding on clause
+        // on a try block, we unconditionally parse it as an on clause".
         onKeyword = token;
         TypeInfo typeInfo = computeType(token, /* required = */ true);
-        if (catchCount > 0 && (typeInfo == noType || typeInfo.recovered)) {
-          // Not a valid on-clause and we have enough catch counts to be a valid
-          // try block already.
-          // This could for instance be code like `on([...])` or `on = 42` after
-          // some actual catch/on as that could be a valid method call, local
-          // function, assignment etc.
-          break;
-        }
         listener.beginCatchClause(token);
         didBeginCatchClause = true;
         lastConsumed = typeInfo.ensureTypeNotVoid(token, this);
@@ -8416,7 +8592,11 @@
           Token? when;
           if (optional('when', next)) {
             when = token = next;
+            listener.beginSwitchCaseWhenClause(when);
             token = parseExpression(token);
+            listener.endSwitchCaseWhenClause(token);
+          } else {
+            listener.handleSwitchCaseNoWhenClause(token);
           }
           token = ensureColon(token);
           listener.endCaseExpression(caseKeyword, when, token);
@@ -9384,6 +9564,17 @@
         // variablePattern ::= ( 'var' | 'final' | 'final'? type )? identifier
         return parseVariablePattern(token, patternContext);
       case '(':
+        // "(" could start a record type (which has to be followed by an
+        // identifier though), e.g. `(int, int) foo`.
+        if (next.endGroup!.next!.isIdentifier) {
+          TypeInfo typeInfo = computeVariablePatternType(token);
+          if (typeInfo is ComplexTypeInfo &&
+              typeInfo.isRecordType &&
+              !typeInfo.recovered) {
+            return parseVariablePattern(token, patternContext,
+                typeInfo: typeInfo);
+          }
+        }
         // parenthesizedPattern  ::= '(' pattern ')'
         // recordPattern         ::= '(' patternFields? ')'
         // patternFields         ::= patternField ( ',' patternField )* ','?
@@ -9405,7 +9596,7 @@
       case 'const':
         // constantPattern ::= booleanLiteral
         //                   | nullLiteral
-        //                   | numericLiteral
+        //                   | '-'? numericLiteral
         //                   | stringLiteral
         //                   | identifier
         //                   | qualifiedName
@@ -9414,13 +9605,10 @@
         //                   | 'const' typeArguments? '{' elements? '}'
         //                   | 'const' '(' expression ')'
         Token const_ = next;
-        // TODO(paulberry): report error if this constant is not permitted by
-        // the grammar.  Pay careful attention to making sure that constructs
-        // like `const const Foo()`, `const const []`, and `const const {}`
-        // lead to errors.
-        token = parsePrecedenceExpression(
-            const_, SELECTOR_PRECEDENCE, /* allowCascades = */ false);
-        listener.handleConstantPattern(const_);
+        listener.beginConstantPattern(const_);
+        token = parsePrecedenceExpression(const_, SELECTOR_PRECEDENCE,
+            /* allowCascades = */ false, ConstantPatternContext.explicit);
+        listener.endConstantPattern(const_);
         return token;
     }
     TokenType type = next.type;
@@ -9432,8 +9620,8 @@
       // suggested in https://github.com/dart-lang/language/issues/2501.
       // TODO(paulberry): update this code if necessary when that issue is
       // resolved.
-      token = parsePrecedenceExpression(
-          next, SHIFT_PRECEDENCE, /* allowCascades = */ false);
+      token = parsePrecedenceExpression(next, SHIFT_PRECEDENCE,
+          /* allowCascades = */ false, ConstantPatternContext.none);
       listener.handleRelationalPattern(operator);
       return token;
     }
@@ -9488,11 +9676,10 @@
       // It's not an object pattern so parse it as an expression.
       token = beforeFirstIdentifier;
     }
-    // TODO(paulberry): report error if this constant is not permitted by the
-    // grammar
-    token = parsePrecedenceExpression(
-        token, SELECTOR_PRECEDENCE, /* allowCascades = */ false);
-    listener.handleConstantPattern(/* constKeyword = */ null);
+    listener.beginConstantPattern(/* constKeyword = */ null);
+    token = parsePrecedenceExpression(token, SELECTOR_PRECEDENCE,
+        /* allowCascades = */ false, ConstantPatternContext.implicit);
+    listener.endConstantPattern(/* constKeyword = */ null);
     return token;
   }
 
@@ -9509,10 +9696,11 @@
       Token next = token.next!;
       if (optional('var', next) || optional('final', next)) {
         token = keyword = next;
+        bool nextIsParen = optional("(", token.next!);
         // TODO(paulberry): this accepts `var <type> name` as a variable
         // pattern.  We want to accept that for error recovery, but don't forget
         // to report the appropriate error.
-        typeInfo = computeVariablePatternType(token);
+        typeInfo = computeVariablePatternType(token, nextIsParen);
         token = typeInfo.parseType(token, this);
       } else {
         // Bare identifier pattern
@@ -9643,7 +9831,7 @@
           colon = rewriteAndRecover(
               token,
               codes.templateExpectedButGot.withArguments(':'),
-              new SyntheticToken(TokenType.PERIOD, next.charOffset));
+              new SyntheticToken(TokenType.COLON, next.charOffset));
         }
         token = parsePattern(colon, patternContext);
         listener.handleMapPatternEntry(colon, token.next!);
@@ -9938,6 +10126,7 @@
       while (true) {
         listener.beginSwitchExpressionCase();
         token = parsePattern(token, PatternContext.matching);
+        listener.handleSwitchExpressionCasePattern(token);
         Token? when;
         next = token.next!;
         if (optional('when', next)) {
@@ -10026,3 +10215,40 @@
 
   const PatternContext({required this.isRefutable});
 }
+
+/// Enum describing the different contexts in which a constant pattern is
+/// parsed.
+///
+/// This restricts what expressions are allowed.
+enum ConstantPatternContext {
+  /// A constant pattern is not currently being parsed.
+  none,
+
+  /// A constant pattern without a preceding `const` is being parsed.
+  ///
+  /// For instance `e` in
+  ///
+  ///     if (o case e) {}
+  ///
+  /// Here `e` can be any valid constant pattern, but not for instance
+  /// expressions like `!foo`.
+  implicit,
+
+  /// A constant pattern with a preceding `const` is being parsed.
+  ///
+  /// For instance `e` in
+  ///
+  ///     if (o case const e) {}
+  ///
+  /// Here `e` cannot start with `const`.
+  explicit,
+
+  /// A constant pattern started with a `-` is being parsed.
+  ///
+  /// For instance `e` in
+  ///
+  ///     if (o case -e) {}
+  ///
+  /// Here `e` is only allowed to be a numeric literal.
+  numericLiteralOnly,
+}
diff --git a/_fe_analyzer_shared/lib/src/parser/quote.dart b/_fe_analyzer_shared/lib/src/parser/quote.dart
index d180f412..eac159c 100644
--- a/_fe_analyzer_shared/lib/src/parser/quote.dart
+++ b/_fe_analyzer_shared/lib/src/parser/quote.dart
@@ -4,6 +4,8 @@
 
 library fasta.quote;
 
+import 'package:_fe_analyzer_shared/src/scanner/string_canonicalizer.dart';
+
 import 'package:_fe_analyzer_shared/src/parser/listener.dart'
     show UnescapeErrorListener;
 
@@ -148,32 +150,35 @@
 
 String unescape(String string, Quote quote, Object location,
     UnescapeErrorListener listener) {
+  String result;
   switch (quote) {
     case Quote.Single:
     case Quote.Double:
-      return !string.contains("\\")
+      result = !string.contains("\\")
           ? string
           : unescapeCodeUnits(
               string.codeUnits, /* isRaw = */ false, location, listener);
-
+      break;
     case Quote.MultiLineSingle:
     case Quote.MultiLineDouble:
-      return !string.contains("\\") && !string.contains("\r")
+      result = !string.contains("\\") && !string.contains("\r")
           ? string
           : unescapeCodeUnits(
               string.codeUnits, /* isRaw = */ false, location, listener);
-
+      break;
     case Quote.RawSingle:
     case Quote.RawDouble:
-      return string;
-
+      result = string;
+      break;
     case Quote.RawMultiLineSingle:
     case Quote.RawMultiLineDouble:
-      return !string.contains("\r")
+      result = !string.contains("\r")
           ? string
           : unescapeCodeUnits(
               string.codeUnits, /* isRaw = */ true, location, listener);
+      break;
   }
+  return considerCanonicalizeString(result);
 }
 
 // Note: based on
diff --git a/_fe_analyzer_shared/lib/src/parser/stack_listener.dart b/_fe_analyzer_shared/lib/src/parser/stack_listener.dart
index 32076fb..20d7496 100644
--- a/_fe_analyzer_shared/lib/src/parser/stack_listener.dart
+++ b/_fe_analyzer_shared/lib/src/parser/stack_listener.dart
@@ -17,15 +17,24 @@
 
 import '../scanner/scanner.dart' show Token;
 
+import '../util/stack_checker.dart';
+import '../util/value_kind.dart';
 import 'identifier_context.dart' show IdentifierContext;
 
 import 'parser.dart' show Listener, MemberKind, lengthOfSpan;
 
 import 'quote.dart' show unescapeString;
 
-import 'value_kind.dart';
+import '../util/null_value.dart';
 
-enum NullValue {
+/// Sentinel values used for typed `null` values on a stack.
+///
+/// This is used to avoid mixing `null` values between different kinds. For
+/// instance a stack entry is meant to contain an expression or null, the
+/// `NullValues.Expression` is pushed on the stack instead of `null` and when
+/// popping the entry `NullValues.Expression` is passed show how `null` is
+/// represented.
+enum NullValues implements NullValue<Object> {
   Arguments,
   As,
   AwaitToken,
@@ -78,16 +87,14 @@
   TypeVariable,
   TypeVariables,
   VarFinalOrConstToken,
+  VariableDeclarationList,
   WithClause,
 }
 
-abstract class StackListener extends Listener {
+abstract class StackListener extends Listener with StackChecker {
   static const bool debugStack = false;
   final Stack stack = debugStack ? new DebugStack() : new StackImpl();
 
-  /// Used to report an internal error encountered in the stack listener.
-  Never internalProblem(Message message, int charOffset, Uri uri);
-
   /// Checks that [value] matches the expected [kind].
   ///
   /// Use this in assert statements like
@@ -95,23 +102,8 @@
   ///     assert(checkValue(token, ValueKind.Token, value));
   ///
   /// to document and validate the expected value kind.
-  bool checkValue(Token? token, ValueKind kind, Object value) {
-    if (!kind.check(value)) {
-      String message = 'Unexpected value `${value}` (${value.runtimeType}). '
-          'Expected ${kind}.';
-      if (token != null) {
-        // If offset is available report and internal problem to show the
-        // parsed code in the output.
-        throw internalProblem(
-            new Message(const Code<String>('Internal error'),
-                problemMessage: message),
-            token.charOffset,
-            uri);
-      } else {
-        throw message;
-      }
-    }
-    return true;
+  bool checkValue(Token? token, ValueKind kind, Object? value) {
+    return checkStackValue(uri, token?.charOffset, kind, value);
   }
 
   /// Checks the top of the current stack against [kinds]. If a mismatch is
@@ -125,99 +117,16 @@
   /// to document the expected stack and get earlier errors on unexpected stack
   /// content.
   bool checkState(Token? token, List<ValueKind> kinds) {
-    bool success = true;
-    for (int kindIndex = 0; kindIndex < kinds.length; kindIndex++) {
-      ValueKind kind = kinds[kindIndex];
-      if (kindIndex < stack.length) {
-        Object? value = stack[kindIndex];
-        if (!kind.check(value)) {
-          success = false;
-        }
-      } else {
-        success = false;
-      }
-    }
-    if (!success) {
-      StringBuffer sb = new StringBuffer();
-
-      String safeToString(Object? object) {
-        try {
-          return '$object';
-        } catch (e) {
-          // Judgments fail on toString.
-          return object.runtimeType.toString();
-        }
-      }
-
-      String padLeft(Object object, int length) {
-        String text = safeToString(object);
-        if (text.length < length) {
-          return ' ' * (length - text.length) + text;
-        }
-        return text;
-      }
-
-      String padRight(Object object, int length) {
-        String text = safeToString(object);
-        if (text.length < length) {
-          return text + ' ' * (length - text.length);
-        }
-        return text;
-      }
-
-      // Compute kind/stack frame information for all expected values plus 3 more
-      // stack elements if available.
-      for (int kindIndex = 0; kindIndex < kinds.length + 3; kindIndex++) {
-        if (kindIndex >= stack.length && kindIndex >= kinds.length) {
-          // No more stack elements nor kinds to display.
-          break;
-        }
-        sb.write(padLeft(kindIndex, 4));
-        sb.write(': ');
-        ValueKind? kind;
-        if (kindIndex < kinds.length) {
-          kind = kinds[kindIndex];
-          sb.write(padRight(kind, 60));
-        } else {
-          sb.write(padRight('---', 60));
-        }
-        if (kindIndex < stack.length) {
-          Object? value = stack[kindIndex];
-          if (kind == null || kind.check(value)) {
-            sb.write(' ');
-          } else {
-            sb.write('*');
-          }
-          sb.write(safeToString(value));
-          sb.write(' (${value.runtimeType})');
-        } else {
-          if (kind == null) {
-            sb.write(' ');
-          } else {
-            sb.write('*');
-          }
-          sb.write('---');
-        }
-        sb.writeln();
-      }
-
-      String message = '$runtimeType failure\n$sb';
-      if (token != null) {
-        // If offset is available report and internal problem to show the
-        // parsed code in the output.
-        throw internalProblem(
-            new Message(const Code<String>('Internal error'),
-                problemMessage: message),
-            token.charOffset,
-            uri);
-      } else {
-        throw message;
-      }
-    }
-    return success;
+    return checkStackStateForAssert(uri, token?.charOffset, kinds);
   }
 
   @override
+  int get stackHeight => stack.length;
+
+  @override
+  Object? lookupStack(int index) => stack[index];
+
+  @override
   Uri get uri;
 
   Uri get importUri;
@@ -294,7 +203,7 @@
   @override
   void handleNoName(Token token) {
     debugEvent("NoName");
-    push(NullValue.Identifier);
+    push(NullValues.Identifier);
   }
 
   @override
@@ -368,13 +277,13 @@
   @override
   void handleNoTypeArguments(Token token) {
     debugEvent("NoTypeArguments");
-    push(NullValue.TypeArguments);
+    push(NullValues.TypeArguments);
   }
 
   @override
   void handleNoTypeVariables(Token token) {
     debugEvent("NoTypeVariables");
-    push(NullValue.TypeVariables);
+    push(NullValues.TypeVariables);
   }
 
   @override
@@ -385,25 +294,25 @@
   @override
   void handleNoType(Token lastConsumed) {
     debugEvent("NoType");
-    push(NullValue.TypeBuilder);
+    push(NullValues.TypeBuilder);
   }
 
   @override
   void handleNoFormalParameters(Token token, MemberKind kind) {
     debugEvent("NoFormalParameters");
-    push(NullValue.FormalParameters);
+    push(NullValues.FormalParameters);
   }
 
   @override
   void handleNoArguments(Token token) {
     debugEvent("NoArguments");
-    push(NullValue.Arguments);
+    push(NullValues.Arguments);
   }
 
   @override
   void handleNativeFunctionBody(Token nativeToken, Token semicolon) {
     debugEvent("NativeFunctionBody");
-    push(NullValue.FunctionBody);
+    push(NullValues.FunctionBody);
   }
 
   @override
@@ -419,13 +328,13 @@
   @override
   void handleNoFunctionBody(Token token) {
     debugEvent("NoFunctionBody");
-    push(NullValue.FunctionBody);
+    push(NullValues.FunctionBody);
   }
 
   @override
   void handleNoInitializers() {
     debugEvent("NoInitializers");
-    push(NullValue.Initializers);
+    push(NullValues.Initializers);
   }
 
   @override
diff --git a/_fe_analyzer_shared/lib/src/parser/type_info.dart b/_fe_analyzer_shared/lib/src/parser/type_info.dart
index e326646..1d6efdc 100644
--- a/_fe_analyzer_shared/lib/src/parser/type_info.dart
+++ b/_fe_analyzer_shared/lib/src/parser/type_info.dart
@@ -353,8 +353,8 @@
 /// This is similar to [computeType], but has special logic to account for an
 /// ambiguity that arises in patterns due to the fact that `as` can either be
 /// an identifier or the operator in a castPattern.
-TypeInfo computeVariablePatternType(Token token) {
-  TypeInfo typeInfo = computeType(token, /* required = */ false);
+TypeInfo computeVariablePatternType(Token token, [bool required = false]) {
+  TypeInfo typeInfo = computeType(token, required);
   Token afterType = typeInfo.skipType(token);
   if (!identical(afterType, token)) {
     Token next = afterType.next!;
diff --git a/_fe_analyzer_shared/lib/src/parser/util.dart b/_fe_analyzer_shared/lib/src/parser/util.dart
index 6891278..a3ec081 100644
--- a/_fe_analyzer_shared/lib/src/parser/util.dart
+++ b/_fe_analyzer_shared/lib/src/parser/util.dart
@@ -124,7 +124,7 @@
       next = token.next!;
     }
 
-    // The extra .identifier after arguments in in [parseMetadata].
+    // The extra .identifier after arguments in [parseMetadata].
     if (optional('.', next)) {
       token = next;
       next = token.next!;
diff --git a/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart b/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart
index b98f290..86d87e4 100644
--- a/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart
+++ b/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart
@@ -513,7 +513,7 @@
    * If a begin group token matches [openKind],
    * then discard begin group tokens up to that match and return `true`,
    * otherwise return `false`.
-   * This recovers nicely from from situations like "{[}" and "{foo());}",
+   * This recovers nicely from situations like "{[}" and "{foo());}",
    * but not "foo(() {bar());});"
    */
   bool discardBeginGroupUntil(int openKind) {
@@ -543,7 +543,7 @@
 
     // If the stack does not have any opener of the given type,
     // then return without discarding anything.
-    // This recovers nicely from from situations like "{foo());}".
+    // This recovers nicely from situations like "{foo());}".
     if (groupingStack.isEmpty) {
       groupingStack = originalStack;
       return false;
@@ -613,7 +613,7 @@
     }
 
     // Insert synthetic closers and report errors for any unbalanced openers.
-    // This recovers nicely from from situations like "{[}".
+    // This recovers nicely from situations like "{[}".
     insertSyntheticClosers(originalStack, groupingStack);
     return true;
   }
@@ -621,7 +621,7 @@
   void insertSyntheticClosers(
       Link<BeginToken> originalStack, Link<BeginToken> entryToUse) {
     // Insert synthetic closers and report errors for any unbalanced openers.
-    // This recovers nicely from from situations like "{[}".
+    // This recovers nicely from situations like "{[}".
     while (!identical(originalStack, entryToUse)) {
       // Don't report unmatched errors for <; it is also the less-than operator.
       if (!identical(entryToUse.head.kind, LT_TOKEN)) {
diff --git a/_fe_analyzer_shared/lib/src/scanner/string_canonicalizer.dart b/_fe_analyzer_shared/lib/src/scanner/string_canonicalizer.dart
index 19ea7c6..5c5e337 100644
--- a/_fe_analyzer_shared/lib/src/scanner/string_canonicalizer.dart
+++ b/_fe_analyzer_shared/lib/src/scanner/string_canonicalizer.dart
@@ -6,33 +6,117 @@
 
 import 'dart:convert';
 
-abstract class Node {
-  final String payload;
-  Node? next;
+final _StringCanonicalizer _canonicalizer = new _StringCanonicalizer();
 
-  Node(this.payload, this.next);
+/// Returns [string] or a canonicalized version of it if our heuristics indicate
+/// it may be a good idea to canonicalize it.
+String considerCanonicalizeString(String string) {
+  // It is very unlikely that large strings will appear repeatedly (mostly those
+  // are long comments or literal strings).
+  // To avoid putting those into the cache and requiring pruning again, we
+  // simply return them.
+  if (string.length > 250) return string;
+  return _canonicalizer.canonicalizeString(string);
+}
+
+/// Returns a sub-string of [string] or a canonicalized version of it if our
+/// heuristics indicate it may be a good idea to canonicalize it.
+///
+/// The sub-string is starting at [start] (inclusive) and ends at [end]
+/// (exclusive).
+String considerCanonicalizeSubString(String string, int start, int end) {
+  // It is very unlikely that large strings will appear repeatedly (mostly those
+  // are long comments or literal strings).
+  // To avoid putting those into the cache and requiring pruning again, we
+  // simply return them.
+  if ((end - start) > 250) return string.substring(start, end);
+  return _canonicalizer.canonicalizeSubString(string, start, end);
+}
+
+/// Returns a canonicalized version of [string].
+String canonicalizeString(String string) {
+  return _canonicalizer.canonicalizeString(string);
+}
+
+/// Returns a canonicalized version of a sub-string of [string].
+///
+/// The sub-string is starting at [start] (inclusive) and ends at [end]
+/// (exclusive).
+String canonicalizeSubString(String string, int start, int end) {
+  return _canonicalizer.canonicalizeSubString(string, start, end);
+}
+
+/// Returns a canonicalized version of the UTF-8 decoded string from [bytes].
+///
+/// The string is UTF-8 decoded from [bytes], starting at [start] (inclusive)
+/// and ending at [end] (exclusive).
+///
+/// It may avoid the overhead of UTF-8 decoding if the string is already in the
+/// cache.
+String canonicalizeUtf8SubString(
+    List<int> bytes, int start, int end, bool isAscii) {
+  return _canonicalizer.canonicalizeBytes(bytes, start, end, isAscii);
+}
+
+/// Will clear the string canonicalization cache.
+void clearStringCanonicalizationCache() {
+  _canonicalizer.clear();
+}
+
+/// Will prune the string canonicalization if it's current memory consumption
+/// is estimated to be larger than [allowGrowthTo].
+///
+/// An attempt is made to keep most frequently used strings in the cache while
+/// maintaining the memory limit.
+void pruneStringCanonicalizationCache([int allowGrowthTo = 5 * 1024 * 1024]) {
+  _canonicalizer.pruneTo(allowGrowthTo);
+}
+
+/// Decode UTF-8 without canonicalizing it.
+String decodeString(List<int> bytes, int start, int end, bool isAscii) {
+  return isAscii
+      ? new String.fromCharCodes(bytes, start, end)
+      : const Utf8Decoder(allowMalformed: true).convert(bytes, start, end);
+}
+
+abstract class _Node {
+  final String payload;
+  _Node? next;
+
+  _Node(this.payload, this.next);
 
   int get hash;
 }
 
-class StringNode extends Node {
-  StringNode(super.payload, super.next);
+class _StringNode extends _Node {
+  int usageCount = 1;
+
+  _StringNode(super.payload, super.next);
 
   @override
   int get hash =>
-      StringCanonicalizer.hashString(payload, /* start = */ 0, payload.length);
+      _StringCanonicalizer.hashString(payload, /* start = */ 0, payload.length);
+
+  // On a 64-bit Dart VM the size of
+  //  * [_StringNode] itself is 32 bytes
+  //  * [String] is 16 bytes plus the actual string data.
+  //
+  // It's an estimation that may overestimate (e.g. on 32-bit architectures) or
+  // underestimate (if payload is unicode) - but is reasonably precise for our
+  // purpose.
+  int get estimatedMemoryConsumption => 32 + (16 + payload.length);
 }
 
-class Utf8Node extends Node {
+class _Utf8Node extends _Node {
   final List<int> data;
   final int start;
   final int end;
 
-  Utf8Node(this.data, this.start, this.end, String payload, Node? next)
+  _Utf8Node(this.data, this.start, this.end, String payload, _Node? next)
       : super(payload, next);
 
   @override
-  int get hash => StringCanonicalizer.hashBytes(data, start, end);
+  int get hash => _StringCanonicalizer.hashBytes(data, start, end);
 }
 
 /// A hash table for triples:
@@ -41,7 +125,7 @@
 /// are canonical.
 ///
 /// Gives about 3% speedup on dart2js.
-class StringCanonicalizer {
+class _StringCanonicalizer {
   /// Mask away top bits to keep hash calculation within 32-bit SMI range.
   static const int MASK = 16 * 1024 * 1024 - 1;
 
@@ -53,18 +137,18 @@
   /// Items in a hash table.
   int _count = 0;
 
-  /// The table itself.
-  List<Node?> _nodes = new List<Node?>.filled(INITIAL_SIZE, /* fill = */ null);
+  /// Number of [_StringNode]s in the cache.
+  int _stringCount = 0;
 
-  static String decode(List<int> data, int start, int end, bool asciiOnly) {
-    String s;
-    if (asciiOnly) {
-      s = new String.fromCharCodes(data, start, end);
-    } else {
-      s = const Utf8Decoder(allowMalformed: true).convert(data, start, end);
-    }
-    return s;
-  }
+  /// Number of []s in the cache.
+  int _utf8StringCount = 0;
+
+  /// Memory consumption of [_StringNode]s.
+  int _estimatedStringMemoryConsumption = 0;
+
+  /// The table itself.
+  List<_Node?> _nodes =
+      new List<_Node?>.filled(INITIAL_SIZE, /* fill = */ null);
 
   static int hashBytes(List<int> data, int start, int end) {
     int h = 5381;
@@ -82,15 +166,15 @@
     return h;
   }
 
-  rehash() {
+  void rehash() {
     int newSize = _size * 2;
-    List<Node?> newNodes = new List<Node?>.filled(newSize, /* fill = */ null);
+    List<_Node?> newNodes = new List<_Node?>.filled(newSize, /* fill = */ null);
     for (int i = 0; i < _size; i++) {
-      Node? t = _nodes[i];
+      _Node? t = _nodes[i];
       while (t != null) {
-        Node? n = t.next;
+        _Node? n = t.next;
         int newIndex = t.hash & (newSize - 1);
-        Node? s = newNodes[newIndex];
+        _Node? s = newNodes[newIndex];
         t.next = s;
         newNodes[newIndex] = t;
         t = n;
@@ -100,24 +184,14 @@
     _nodes = newNodes;
   }
 
-  String canonicalize(data, int start, int end, bool asciiOnly) {
-    if (data is String) {
-      if (start == 0 && (end == data.length - 1)) {
-        return canonicalizeString(data);
-      }
-      return canonicalizeSubString(data, start, end);
-    }
-    return canonicalizeBytes(data as List<int>, start, end, asciiOnly);
-  }
-
   String canonicalizeBytes(List<int> data, int start, int end, bool asciiOnly) {
     if (_count > _size) rehash();
     final int index = hashBytes(data, start, end) & (_size - 1);
-    Node? s = _nodes[index];
-    Node? t = s;
+    _Node? s = _nodes[index];
+    _Node? t = s;
     int len = end - start;
     while (t != null) {
-      if (t is Utf8Node) {
+      if (t is _Utf8Node) {
         final List<int> tData = t.data;
         if (t.end - t.start == len) {
           int i = start, j = t.start;
@@ -132,31 +206,25 @@
       }
       t = t.next;
     }
-    String payload = decode(data, start, end, asciiOnly);
-    _nodes[index] = new Utf8Node(data, start, end, payload, s);
-    _count++;
-    return payload;
+    return insertUtf8Node(
+        index, s, data, start, end, decodeString(data, start, end, asciiOnly));
   }
 
   String canonicalizeSubString(String data, int start, int end) {
+    final int len = end - start;
+    if (start == 0 && data.length == len) {
+      return canonicalizeString(data);
+    }
     if (_count > _size) rehash();
     final int index = hashString(data, start, end) & (_size - 1);
-    Node? s = _nodes[index];
-    Node? t = s;
-    int len = end - start;
+    final _Node? s = _nodes[index];
+    _Node? t = s;
     while (t != null) {
-      if (t is StringNode) {
+      if (t is _StringNode) {
         final String tData = t.payload;
-        if (identical(data, tData)) return tData;
-        if (tData.length == len) {
-          int i = start, j = 0;
-          while (i < end && data.codeUnitAt(i) == tData.codeUnitAt(j)) {
-            i++;
-            j++;
-          }
-          if (i == end) {
-            return tData;
-          }
+        if (tData.length == len && data.startsWith(tData, start)) {
+          t.usageCount++;
+          return tData;
         }
       }
       t = t.next;
@@ -168,37 +236,110 @@
     if (_count > _size) rehash();
     final int index =
         hashString(data, /* start = */ 0, data.length) & (_size - 1);
-    Node? s = _nodes[index];
-    Node? t = s;
+    final _Node? s = _nodes[index];
+    _Node? t = s;
     while (t != null) {
-      if (t is StringNode) {
+      if (t is _StringNode) {
         final String tData = t.payload;
-        if (identical(data, tData)) return tData;
-        if (data == tData) return tData;
+        if (identical(data, tData) || data == tData) {
+          t.usageCount++;
+          return tData;
+        }
       }
       t = t.next;
     }
     return insertStringNode(index, s, data);
   }
 
-  String insertStringNode(int index, Node? next, String value) {
-    final StringNode newNode = new StringNode(value, next);
+  String insertStringNode(int index, _Node? next, String value) {
+    final _StringNode newNode = new _StringNode(value, next);
     _nodes[index] = newNode;
     _count++;
+    _stringCount++;
+    _estimatedStringMemoryConsumption += newNode.estimatedMemoryConsumption;
     return value;
   }
 
-  String insertUtf8Node(int index, Node? next, List<int> buffer, int start,
+  String insertUtf8Node(int index, _Node? next, List<int> buffer, int start,
       int end, String value) {
-    final Utf8Node newNode = new Utf8Node(buffer, start, end, value, next);
+    final _Utf8Node newNode = new _Utf8Node(buffer, start, end, value, next);
     _nodes[index] = newNode;
     _count++;
+    _utf8StringCount++;
     return value;
   }
 
-  clear() {
-    _size = INITIAL_SIZE;
-    _nodes = new List<Node?>.filled(_size, /* fill = */ null);
+  void clear() {
+    initializeWithSize(INITIAL_SIZE);
+  }
+
+  void initializeWithSize(int size) {
+    _size = size;
+    _nodes = new List<_Node?>.filled(_size, /* fill = */ null);
     _count = 0;
+    _utf8StringCount = 0;
+    _stringCount = 0;
+    _estimatedStringMemoryConsumption = 0;
+  }
+
+  void pruneTo(int allowGrowthTo) {
+    // If we're already within the limit and there's no [_Utf8Node]s around
+    // (which may hold on to very large Uint8List buffers) we have nothing to
+    // do.
+    if (_estimatedStringMemoryConsumption < allowGrowthTo &&
+        _utf8StringCount == 0) {
+      return;
+    }
+
+    // If there's only [_Utf8Node]s around we'll clear the entire cache.
+    if (_stringCount == 0) {
+      clear();
+      return;
+    }
+
+    // Find all [_StringNode]s, sort them by usage and insert remaining nodes
+    // into a new cache until we've reached half of the [allowGrowthTo] -
+    // leaving some space before we'll have to prune again next time.
+
+    final List<_StringNode> stringNodes = new List<_StringNode>.filled(
+        _stringCount, new _StringNode('dummy', /* next = */ null));
+    int writeIndex = 0;
+    for (int i = 0; i < _nodes.length; ++i) {
+      _Node? node = _nodes[i];
+      while (node != null) {
+        final _Node? nextNode = node.next;
+        if (node is _StringNode) {
+          stringNodes[writeIndex++] = node;
+          node.next = null;
+        }
+        node = nextNode;
+      }
+    }
+    stringNodes.sort((_StringNode a, _StringNode b) {
+      return b.usageCount - a.usageCount;
+    });
+
+    int sum = 0;
+    int lastIndex = 0;
+    for (int i = 0; i < stringNodes.length; ++i) {
+      final _StringNode node = stringNodes[i];
+      sum += node.estimatedMemoryConsumption;
+      if (sum >= (allowGrowthTo ~/ 2) || node.usageCount < 2) {
+        lastIndex = i;
+        break;
+      }
+    }
+
+    final int newSize = (1 << lastIndex.bitLength);
+    initializeWithSize(newSize);
+    for (int i = lastIndex; i >= 0; --i) {
+      final _StringNode newNode = stringNodes[i];
+      final int index = newNode.hash & (_size - 1);
+      newNode.next = _nodes[index];
+      _nodes[index] = newNode;
+      _count++;
+      _stringCount++;
+      _estimatedStringMemoryConsumption += newNode.estimatedMemoryConsumption;
+    }
   }
 }
diff --git a/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart b/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart
index 2cb1c1c..2b89816 100644
--- a/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart
+++ b/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart
@@ -17,6 +17,9 @@
 import 'abstract_scanner.dart'
     show AbstractScanner, LanguageVersionChanged, ScannerConfiguration;
 
+import 'string_canonicalizer.dart'
+    show canonicalizeString, canonicalizeSubString;
+
 import 'token_impl.dart'
     show
         CommentTokenImpl,
@@ -94,9 +97,12 @@
   @override
   analyzer.StringToken createSyntheticSubstringToken(
       TokenType type, int start, bool asciiOnly, String syntheticChars) {
-    String source = string.substring(start, scanOffset);
+    String value = syntheticChars.length == 0
+        ? canonicalizeSubString(string, start, scanOffset)
+        : canonicalizeString(
+            string.substring(start, scanOffset) + syntheticChars);
     return new SyntheticStringToken(
-        type, source + syntheticChars, tokenStart, source.length);
+        type, value, tokenStart, value.length - syntheticChars.length);
   }
 
   @override
diff --git a/_fe_analyzer_shared/lib/src/scanner/token_impl.dart b/_fe_analyzer_shared/lib/src/scanner/token_impl.dart
index 000542c..09ac5ad 100644
--- a/_fe_analyzer_shared/lib/src/scanner/token_impl.dart
+++ b/_fe_analyzer_shared/lib/src/scanner/token_impl.dart
@@ -41,8 +41,7 @@
    */
   StringTokenImpl.fromString(TokenType type, String value, int charOffset,
       {bool canonicalize = false, CommentToken? precedingComments})
-      : valueOrLazySubstring =
-            canonicalize ? canonicalizedString(value) : value,
+      : valueOrLazySubstring = canonicalize ? canonicalizeString(value) : value,
         super(type, charOffset, precedingComments);
 
   /**
@@ -55,8 +54,9 @@
       : super(type, charOffset, precedingComments) {
     int length = end - start;
     if (length <= LAZY_THRESHOLD) {
-      valueOrLazySubstring =
-          canonicalizedSubString(data, start, end, canonicalize);
+      valueOrLazySubstring = canonicalize
+          ? canonicalizeSubString(data, start, end)
+          : data.substring(start, end);
     } else {
       valueOrLazySubstring =
           new _LazySubstring(data, start, length, canonicalize);
@@ -73,7 +73,8 @@
       : super(type, charOffset, precedingComments) {
     int length = end - start;
     if (length <= LAZY_THRESHOLD) {
-      valueOrLazySubstring = decodeUtf8(data, start, end, asciiOnly);
+      valueOrLazySubstring =
+          canonicalizeUtf8SubString(data, start, end, asciiOnly);
     } else {
       valueOrLazySubstring = new _LazySubstring(data, start, length, asciiOnly);
     }
@@ -89,11 +90,14 @@
       int start = valueOrLazySubstring.start;
       int end = start + (valueOrLazySubstring as _LazySubstring).length;
       if (data is String) {
-        valueOrLazySubstring = canonicalizedSubString(
-            data, start, end, valueOrLazySubstring.boolValue);
+        final bool canonicalize = valueOrLazySubstring.boolValue;
+        valueOrLazySubstring = canonicalize
+            ? canonicalizeSubString(data, start, end)
+            : data.substring(start, end);
       } else {
+        final bool isAscii = valueOrLazySubstring.boolValue;
         valueOrLazySubstring =
-            decodeUtf8(data, start, end, valueOrLazySubstring.boolValue);
+            canonicalizeUtf8SubString(data, start, end, isAscii);
       }
       return valueOrLazySubstring;
     }
@@ -105,22 +109,6 @@
   @override
   String toString() => lexeme;
 
-  static final StringCanonicalizer canonicalizer = new StringCanonicalizer();
-
-  static String canonicalizedString(String s) {
-    return canonicalizer.canonicalizeString(s);
-  }
-
-  static String canonicalizedSubString(
-      String s, int start, int end, bool canonicalize) {
-    if (!canonicalize) return s.substring(start, end);
-    return canonicalizer.canonicalizeSubString(s, start, end);
-  }
-
-  static String decodeUtf8(List<int> data, int start, int end, bool asciiOnly) {
-    return canonicalizer.canonicalizeBytes(data, start, end, asciiOnly);
-  }
-
   @override
   String value() => lexeme;
 }
diff --git a/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart b/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart
index f361177..a1dd384 100644
--- a/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart
+++ b/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart
@@ -15,6 +15,9 @@
 import 'abstract_scanner.dart'
     show AbstractScanner, LanguageVersionChanged, ScannerConfiguration;
 
+import 'string_canonicalizer.dart'
+    show canonicalizeUtf8SubString, canonicalizeString, decodeString;
+
 import 'token_impl.dart'
     show
         CommentTokenImpl,
@@ -246,10 +249,12 @@
   @override
   analyzer.StringToken createSyntheticSubstringToken(
       TokenType type, int start, bool asciiOnly, String syntheticChars) {
-    String source =
-        StringTokenImpl.decodeUtf8(bytes, start, byteOffset, asciiOnly);
+    String value = syntheticChars.length == 0
+        ? canonicalizeUtf8SubString(bytes, start, byteOffset, asciiOnly)
+        : canonicalizeString(
+            decodeString(bytes, start, byteOffset, asciiOnly) + syntheticChars);
     return new SyntheticStringToken(
-        type, source + syntheticChars, tokenStart, source.length);
+        type, value, tokenStart, value.length - syntheticChars.length);
   }
 
   @override
diff --git a/_fe_analyzer_shared/lib/src/testing/id_testing.dart b/_fe_analyzer_shared/lib/src/testing/id_testing.dart
index e34d830..2f7b925 100644
--- a/_fe_analyzer_shared/lib/src/testing/id_testing.dart
+++ b/_fe_analyzer_shared/lib/src/testing/id_testing.dart
@@ -708,7 +708,8 @@
     File file = new File.fromUri(dataDir.uri.resolve('marker.options'));
     File script = new File.fromUri(Platform.script);
     if (!file.existsSync()) {
-      throw new ArgumentError("Marker option file '$file' doesn't exist.");
+      throw new ArgumentError(
+          "Marker option file '${file.uri}' doesn't exist.");
     }
 
     Map<String, MarkerTester> markers = {};
@@ -749,7 +750,7 @@
 
   Future<void> runAll(List<String> args) async {
     Set<MarkerTester> testers = markers.values.toSet();
-    bool allOk = true;
+    int errorsCount = 0;
     for (MarkerTester tester in testers) {
       print('================================================================');
       print('Running tester: ${tester.path} ${args.join(' ')}');
@@ -758,11 +759,11 @@
           Platform.resolvedExecutable, [tester.uri.toString(), ...args],
           mode: ProcessStartMode.inheritStdio);
       if (await process.exitCode != 0) {
-        allOk = false;
+        errorsCount++;
       }
     }
-    if (!allOk) {
-      throw "Error(s) occurred.";
+    if (errorsCount != 0) {
+      throw "Error${errorsCount == 1 ? "" : "s"} occurred.";
     }
   }
 }
diff --git a/_fe_analyzer_shared/lib/src/type_inference/promotion_key_store.dart b/_fe_analyzer_shared/lib/src/type_inference/promotion_key_store.dart
index bf99c8b..614d497 100644
--- a/_fe_analyzer_shared/lib/src/type_inference/promotion_key_store.dart
+++ b/_fe_analyzer_shared/lib/src/type_inference/promotion_key_store.dart
@@ -37,7 +37,7 @@
   /// Creates a fresh promotion key that hasn't been used before (and won't be
   /// reused again).  This is used by flow analysis to model the synthetic
   /// variables used during pattern matching to cache the values that the
-  /// pattern, and its subpattterns, are being matched against.
+  /// pattern, and its subpatterns, are being matched against.
   int makeTemporaryKey() => _makeNewKey();
 
   Variable? variableForKey(int variableKey) => _keyToInfo[variableKey].variable;
diff --git a/_fe_analyzer_shared/lib/src/type_inference/type_analysis_result.dart b/_fe_analyzer_shared/lib/src/type_inference/type_analysis_result.dart
index 8f6fd62..c55dd3c 100644
--- a/_fe_analyzer_shared/lib/src/type_inference/type_analysis_result.dart
+++ b/_fe_analyzer_shared/lib/src/type_inference/type_analysis_result.dart
@@ -51,37 +51,44 @@
   /// Indicates whether variables declared in the pattern should be `late`.
   final bool isLate;
 
-  /// The top level pattern in this pattern match.
-  final Node? topPattern;
-
   /// The initializer being assigned to this pattern via a variable declaration
   /// statement, or `null` if this pattern does not occur in a variable
-  /// declaration statement.
-  final Expression? _initializer;
+  /// declaration statement, or this pattern is not the top-level pattern in
+  /// the declaration.
+  final Expression? initializer;
 
   /// The switch scrutinee, or `null` if this pattern does not occur in a switch
-  /// statement or switch expression.
-  final Expression? _switchScrutinee;
+  /// statement or switch expression, or this pattern is not the top-level
+  /// pattern.
+  final Expression? switchScrutinee;
+
+  /// If the match is being done in a pattern assignment, the set of variables
+  /// assigned so far.
+  final Map<Variable, Pattern>? assignedVariables;
+
+  /// For each variable name in the pattern, a list of the variables which might
+  /// capture that variable's value, depending upon which alternative is taken
+  /// in a logical-or pattern.
+  final Map<String, List<Variable>> componentVariables;
+
+  /// For each variable name in the pattern, the promotion key holding the value
+  /// captured by that variable.
+  final Map<String, int> patternVariablePromotionKeys;
+
+  /// If non-null, the warning that should be issued if the pattern is `_`
+  final UnnecessaryWildcardKind? unnecessaryWildcardKind;
 
   MatchContext({
-    Expression? initializer,
+    this.initializer,
     this.irrefutableContext,
     required this.isFinal,
     this.isLate = false,
-    Expression? switchScrutinee,
-    required this.topPattern,
-  })  : _initializer = initializer,
-        _switchScrutinee = switchScrutinee;
-
-  /// If the pattern [pattern] is the [topPattern] and there is a corresponding
-  /// initializer expression, returns it.  Otherwise returns `null`.
-  Expression? getInitializer(Pattern pattern) =>
-      identical(pattern, topPattern) ? _initializer : null;
-
-  /// If the pattern [pattern] is the [topPattern] and there is a corresponding
-  /// switch scrutinee expression, returns it.  Otherwise returns `null`.
-  Expression? getSwitchScrutinee(Node pattern) =>
-      identical(pattern, topPattern) ? _switchScrutinee : null;
+    this.switchScrutinee,
+    this.assignedVariables,
+    required this.componentVariables,
+    required this.patternVariablePromotionKeys,
+    this.unnecessaryWildcardKind,
+  });
 
   /// Returns a modified version of `this`, with [irrefutableContext] set to
   /// `null`.  This is used to suppress cascading errors after reporting
@@ -90,12 +97,61 @@
       irrefutableContext == null
           ? this
           : new MatchContext(
-              initializer: _initializer,
+              initializer: initializer,
               isFinal: isFinal,
               isLate: isLate,
-              switchScrutinee: _switchScrutinee,
-              topPattern: topPattern,
+              switchScrutinee: switchScrutinee,
+              assignedVariables: assignedVariables,
+              componentVariables: componentVariables,
+              patternVariablePromotionKeys: patternVariablePromotionKeys,
             );
+
+  /// Returns a modified version of `this`, with a new value of
+  /// [patternVariablePromotionKeys].
+  MatchContext<Node, Expression, Pattern, Type, Variable> withPromotionKeys(
+          Map<String, int> patternVariablePromotionKeys) =>
+      new MatchContext(
+        initializer: null,
+        irrefutableContext: irrefutableContext,
+        isFinal: isFinal,
+        isLate: isLate,
+        switchScrutinee: null,
+        assignedVariables: assignedVariables,
+        componentVariables: componentVariables,
+        patternVariablePromotionKeys: patternVariablePromotionKeys,
+        unnecessaryWildcardKind: unnecessaryWildcardKind,
+      );
+
+  /// Returns a modified version of `this`, with both [initializer] and
+  /// [switchScrutinee] set to `null` (because this context is not for a
+  /// top-level pattern anymore).
+  MatchContext<Node, Expression, Pattern, Type, Variable>
+      withUnnecessaryWildcardKind(
+          UnnecessaryWildcardKind? unnecessaryWildcardKind) {
+    return new MatchContext(
+      initializer: null,
+      irrefutableContext: irrefutableContext,
+      isFinal: isFinal,
+      isLate: isLate,
+      assignedVariables: assignedVariables,
+      switchScrutinee: null,
+      componentVariables: componentVariables,
+      patternVariablePromotionKeys: patternVariablePromotionKeys,
+      unnecessaryWildcardKind: unnecessaryWildcardKind,
+    );
+  }
+}
+
+/// Container for the result of running type analysis on a pattern assignment.
+class PatternAssignmentAnalysisResult<Type extends Object>
+    extends SimpleTypeAnalysisResult<Type> {
+  /// The type schema of the pattern on the left hand size of the assignment.
+  final Type patternSchema;
+
+  PatternAssignmentAnalysisResult({
+    required this.patternSchema,
+    required super.type,
+  });
 }
 
 /// Container for the result of running type analysis on an expression that does
@@ -144,3 +200,15 @@
     required this.scrutineeType,
   });
 }
+
+/// The location of a wildcard pattern that was found unnecessary.
+///
+/// When a wildcard pattern always matches, and is not required by the
+/// by the location, we can report it as unnecessary. The locations where it
+/// is necessary include list patterns, record patterns, cast patterns, etc.
+enum UnnecessaryWildcardKind {
+  /// The wildcard pattern is the left or the right side of a logical-and
+  /// pattern. Because we found that is always matches, it has no effect,
+  /// and can be removed.
+  logicalAndPatternOperand,
+}
diff --git a/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart b/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart
index 542508f..68656e6 100644
--- a/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart
+++ b/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart
@@ -33,6 +33,15 @@
   });
 }
 
+/// The location where the join of a pattern variable happens.
+enum JoinedPatternVariableLocation {
+  /// A single pattern, from `logical-or` patterns.
+  singlePattern,
+
+  /// A shared `case` scope, when multiple `case`s share the same body.
+  sharedCaseScope,
+}
+
 class MapPatternEntry<Expression extends Object, Pattern extends Object> {
   final Expression key;
   final Pattern value;
@@ -82,15 +91,27 @@
   });
 }
 
+/// Kinds of relational pattern operators that shared analysis needs to
+/// distinguish.
+enum RelationalOperatorKind {
+  /// The operator `==`
+  equals,
+
+  /// The operator `!=`
+  notEquals,
+
+  /// Any relational pattern operator other than `==` or `!=`
+  other,
+}
+
 /// Information about a relational operator.
 class RelationalOperatorResolution<Type extends Object> {
-  /// Is `true` when the operator is `==` or `!=`.
-  final bool isEquality;
+  final RelationalOperatorKind kind;
   final Type parameterType;
   final Type returnType;
 
   RelationalOperatorResolution({
-    required this.isEquality,
+    required this.kind,
     required this.parameterType,
     required this.returnType,
   });
@@ -230,6 +251,9 @@
   TypeAnalyzerErrors<Node, Statement, Expression, Variable, Type, Pattern>?
       get errors;
 
+  /// Returns the type used by the client in the case of errors.
+  Type get errorType;
+
   /// Returns the client's [FlowAnalysis] object.
   FlowAnalysis<Node, Statement, Expression, Variable, Type> get flow;
 
@@ -263,6 +287,20 @@
       MatchContext<Node, Expression, Pattern, Type, Variable> context,
       Pattern node,
       Variable variable) {
+    Map<Variable, Pattern>? assignedVariables = context.assignedVariables;
+    if (assignedVariables != null) {
+      Pattern? original = assignedVariables[variable];
+      if (original == null) {
+        assignedVariables[variable] = node;
+      } else {
+        errors?.duplicateAssignmentPatternVariable(
+          variable: variable,
+          original: original,
+          duplicate: node,
+        );
+      }
+    }
+
     Type variableDeclaredType = operations.variableType(variable);
     Node? irrefutableContext = context.irrefutableContext;
     assert(irrefutableContext != null,
@@ -276,7 +314,9 @@
           matchedType: matchedType,
           requiredType: variableDeclaredType);
     }
-    flow.write(node, variable, matchedType, context.getInitializer(node));
+    flow.promoteForPattern(
+        matchedType: matchedType, knownType: variableDeclaredType);
+    flow.assignedVariablePattern(node, variable, matchedType);
   }
 
   /// Computes the type schema for a variable pattern appearing in an assignment
@@ -284,18 +324,38 @@
   Type analyzeAssignedVariablePatternSchema(Variable variable) =>
       flow.promotedType(variable) ?? operations.variableType(variable);
 
-  /// Analyzes a cast pattern.  [innerPattern] is the sub-pattern] and [type] is
-  /// the type to cast to.
+  /// Analyzes a cast pattern.  [innerPattern] is the sub-pattern] and
+  /// [requiredType] is the type to cast to.
   ///
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (Pattern innerPattern).
-  void analyzeCastPattern(
-      MatchContext<Node, Expression, Pattern, Type, Variable> context,
-      Pattern innerPattern,
-      Type type) {
-    flow.pushSubpattern(type, isDistinctValue: false);
-    dispatchPattern(context, innerPattern);
+  void analyzeCastPattern({
+    required MatchContext<Node, Expression, Pattern, Type, Variable> context,
+    required Pattern pattern,
+    required Pattern innerPattern,
+    required Type requiredType,
+  }) {
+    Type matchedValueType = flow.getMatchedValueType();
+    bool matchedTypeIsSubtypeOfRequired = flow.promoteForPattern(
+        matchedType: matchedValueType,
+        knownType: requiredType,
+        matchFailsIfWrongType: false);
+    if (matchedTypeIsSubtypeOfRequired) {
+      errors?.matchedTypeIsSubtypeOfRequired(
+        pattern: pattern,
+        matchedType: matchedValueType,
+        requiredType: requiredType,
+      );
+    }
+    // Note: although technically the inner pattern match of a cast-pattern
+    // operates on the same value as the cast pattern does, we analyze it as
+    // though it's a different value; this ensures that (a) the matched value
+    // type when matching the inner pattern is precisely the cast type, and (b)
+    // promotions triggered by the inner pattern have no effect outside the
+    // cast.
+    flow.pushSubpattern(requiredType);
+    dispatchPattern(context.withUnnecessaryWildcardKind(null), innerPattern);
     // Stack: (Pattern)
     flow.popSubpattern();
   }
@@ -311,8 +371,10 @@
   ///
   /// See [dispatchPattern] for the meaning of [context].
   ///
+  /// Returns the static type of [expression].
+  ///
   /// Stack effect: pushes (Expression).
-  void analyzeConstantPattern(
+  Type analyzeConstantPattern(
       MatchContext<Node, Expression, Pattern, Type, Variable> context,
       Node node,
       Expression expression) {
@@ -324,26 +386,28 @@
       errors?.refutablePatternInIrrefutableContext(node, irrefutableContext);
     }
     Type matchedType = flow.getMatchedValueType();
-    Type staticType = analyzeExpression(expression, matchedType);
-    flow.constantPattern_end(expression);
+    Type expressionType = analyzeExpression(expression, matchedType);
+    flow.constantPattern_end(expression, expressionType,
+        patternsEnabled: options.patternsEnabled);
     // Stack: (Expression)
     if (errors != null && !options.patternsEnabled) {
-      Expression? switchScrutinee = context.getSwitchScrutinee(node);
+      Expression? switchScrutinee = context.switchScrutinee;
       if (switchScrutinee != null) {
         bool nullSafetyEnabled = options.nullSafetyEnabled;
         bool matches = nullSafetyEnabled
-            ? operations.isSubtypeOf(staticType, matchedType)
-            : operations.isAssignableTo(staticType, matchedType);
+            ? operations.isSubtypeOf(expressionType, matchedType)
+            : operations.isAssignableTo(expressionType, matchedType);
         if (!matches) {
           errors.caseExpressionTypeMismatch(
               caseExpression: expression,
               scrutinee: switchScrutinee,
-              caseExpressionType: staticType,
+              caseExpressionType: expressionType,
               scrutineeType: matchedType,
               nullSafetyEnabled: nullSafetyEnabled);
         }
       }
     }
+    return expressionType;
   }
 
   /// Computes the type schema for a constant pattern.
@@ -357,24 +421,23 @@
     return unknownType;
   }
 
-  /// Analyzes a variable pattern in a non-assignment context (or a wildcard
-  /// pattern).  [node] is the pattern itself, [variable] is the variable,
-  /// [declaredType] is the explicitly declared type (if present), and [isFinal]
-  /// indicates whether the variable is final.
+  /// Analyzes a variable pattern in a non-assignment context.  [node] is the
+  /// pattern itself, [variable] is the variable, [declaredType] is the
+  /// explicitly declared type (if present).  [variableName] is the name of the
+  /// variable; this is used to match up corresponding variables in the
+  /// different branches of logical-or patterns, as well as different switch
+  /// cases that share a body.
   ///
   /// See [dispatchPattern] for the meaning of [context].
   ///
-  /// If this is a wildcard pattern (it doesn't bind any variable), [variable]
-  /// should be `null`.
-  ///
   /// Returns the static type of the variable (possibly inferred).
   ///
   /// Stack effect: none.
   Type analyzeDeclaredVariablePattern(
     MatchContext<Node, Expression, Pattern, Type, Variable> context,
     Pattern node,
-    Variable? variable,
-    String? name,
+    Variable variable,
+    String variableName,
     Type? declaredType,
   ) {
     Type matchedType = flow.getMatchedValueType();
@@ -389,22 +452,20 @@
           matchedType: matchedType,
           requiredType: staticType);
     }
-    flow.declaredVariablePattern(
-        matchedType: matchedType, staticType: staticType);
+    flow.promoteForPattern(matchedType: matchedType, knownType: staticType);
     bool isImplicitlyTyped = declaredType == null;
-    if (variable != null) {
-      if (name == null) {
-        throw new StateError(
-            'When the variable is not null, the name must also be not null');
-      }
-      flow.declare(variable, false);
-      setVariableType(variable, staticType);
-      // TODO(paulberry): are we handling _isFinal correctly?
-      flow.initialize(variable, matchedType, context.getInitializer(node),
-          isFinal: context.isFinal || isVariableFinal(variable),
-          isLate: context.isLate,
-          isImplicitlyTyped: isImplicitlyTyped);
-    }
+    // TODO(paulberry): are we handling _isFinal correctly?
+    int promotionKey = context.patternVariablePromotionKeys[variableName] =
+        flow.declaredVariablePattern(
+            matchedType: matchedType,
+            staticType: staticType,
+            initializerExpression: context.initializer,
+            isFinal: context.isFinal || isVariableFinal(variable),
+            isLate: context.isLate,
+            isImplicitlyTyped: isImplicitlyTyped);
+    setVariableType(variable, staticType);
+    (context.componentVariables[variableName] ??= []).add(variable);
+    flow.assignMatchedPatternVariable(variable, promotionKey);
     return staticType;
   }
 
@@ -443,6 +504,10 @@
   /// the expression, [pattern] for the pattern to match, [ifTrue] for the
   /// "then" branch, and [ifFalse] for the "else" branch (if present).
   ///
+  /// [variables] should be a map from variable name to the variable the client
+  /// wishes to use to represent that variable.  This is used to join together
+  /// variables that appear in different branches of logical-or patterns.
+  ///
   /// Stack effect: pushes (Expression scrutinee, Pattern, Expression guard,
   /// CollectionElement ifTrue, CollectionElement ifFalse).  If there is no
   /// `else` clause, the representation for `ifFalse` will be pushed by
@@ -452,6 +517,7 @@
     required Node node,
     required Expression expression,
     required Pattern pattern,
+    required Map<String, Variable> variables,
     required Expression? guard,
     required Node ifTrue,
     required Node? ifFalse,
@@ -462,12 +528,21 @@
     Type initializerType = analyzeExpression(expression, unknownType);
     flow.ifCaseStatement_afterExpression(expression, initializerType);
     // Stack: (Expression)
+    Map<String, List<Variable>> componentVariables = {};
+    Map<String, int> patternVariablePromotionKeys = {};
     // TODO(paulberry): rework handling of isFinal
     dispatchPattern(
-        new MatchContext<Node, Expression, Pattern, Type, Variable>(
-            isFinal: false, topPattern: pattern),
-        pattern);
+      new MatchContext<Node, Expression, Pattern, Type, Variable>(
+        isFinal: false,
+        componentVariables: componentVariables,
+        patternVariablePromotionKeys: patternVariablePromotionKeys,
+      ),
+      pattern,
+    );
     // Stack: (Expression, Pattern)
+    _finishJoinedPatternVariables(
+        variables, componentVariables, patternVariablePromotionKeys,
+        location: JoinedPatternVariableLocation.singlePattern);
     if (guard != null) {
       _checkGuardType(guard, analyzeExpression(guard, boolType));
     } else {
@@ -506,28 +581,26 @@
     Type initializerType = analyzeExpression(expression, unknownType);
     flow.ifCaseStatement_afterExpression(expression, initializerType);
     // Stack: (Expression)
+    Map<String, List<Variable>> componentVariables = {};
+    Map<String, int> patternVariablePromotionKeys = {};
     // TODO(paulberry): rework handling of isFinal
     dispatchPattern(
       new MatchContext<Node, Expression, Pattern, Type, Variable>(
         isFinal: false,
-        topPattern: pattern,
+        componentVariables: componentVariables,
+        patternVariablePromotionKeys: patternVariablePromotionKeys,
       ),
       pattern,
     );
 
-    _finishJoinedVariables(
+    _finishJoinedPatternVariables(
       variables,
-      reportErrors: true,
+      componentVariables,
+      patternVariablePromotionKeys,
+      location: JoinedPatternVariableLocation.singlePattern,
     );
 
-    for (Variable variable in variables.values) {
-      flow.declare(variable, true);
-    }
-
-    handle_ifCaseStatement_afterPattern(
-      node: node,
-      variables: variables.values,
-    );
+    handle_ifCaseStatement_afterPattern(node: node);
     // Stack: (Expression, Pattern)
     if (guard != null) {
       _checkGuardType(guard, analyzeExpression(guard, boolType));
@@ -625,25 +698,39 @@
         valueType = objectQuestionType;
       }
     }
+    Type requiredType = listType(valueType);
+    flow.promoteForPattern(
+        matchedType: matchedType,
+        knownType: requiredType,
+        matchMayFailEvenIfCorrectType: true);
     // Stack: ()
+    Node? previousRestPattern;
     for (Node element in elements) {
       if (isRestPatternElement(element)) {
+        if (previousRestPattern != null) {
+          errors?.duplicateRestPattern(
+            mapOrListPattern: node,
+            original: previousRestPattern,
+            duplicate: element,
+          );
+        }
+        previousRestPattern = element;
         Pattern? subPattern = getRestPatternElementPattern(element);
         if (subPattern != null) {
-          Type subPatternMatchedType = listType(valueType);
-          flow.pushSubpattern(subPatternMatchedType, isDistinctValue: true);
-          dispatchPattern(context, subPattern);
+          Type subPatternMatchedType = requiredType;
+          flow.pushSubpattern(subPatternMatchedType);
+          dispatchPattern(
+              context.withUnnecessaryWildcardKind(null), subPattern);
           flow.popSubpattern();
         }
         handleListPatternRestElement(node, element);
       } else {
-        flow.pushSubpattern(valueType, isDistinctValue: true);
-        dispatchPattern(context, element);
+        flow.pushSubpattern(valueType);
+        dispatchPattern(context.withUnnecessaryWildcardKind(null), element);
         flow.popSubpattern();
       }
     }
     // Stack: (n * Pattern) where n = elements.length
-    Type requiredType = listType(valueType);
     Node? irrefutableContext = context.irrefutableContext;
     if (irrefutableContext != null &&
         !operations.isAssignableTo(matchedType, requiredType)) {
@@ -709,9 +796,19 @@
       Node lhs,
       Node rhs) {
     // Stack: ()
-    dispatchPattern(context, lhs);
+    dispatchPattern(
+      context.withUnnecessaryWildcardKind(
+        UnnecessaryWildcardKind.logicalAndPatternOperand,
+      ),
+      lhs,
+    );
     // Stack: (Pattern left)
-    dispatchPattern(context, rhs);
+    dispatchPattern(
+      context.withUnnecessaryWildcardKind(
+        UnnecessaryWildcardKind.logicalAndPatternOperand,
+      ),
+      rhs,
+    );
     // Stack: (Pattern left, Pattern right)
   }
 
@@ -743,11 +840,55 @@
     }
     // Stack: ()
     flow.logicalOrPattern_begin();
-    dispatchPattern(context, lhs);
+    Map<String, int> leftPromotionKeys = {};
+    dispatchPattern(
+      context
+          .withPromotionKeys(leftPromotionKeys)
+          .withUnnecessaryWildcardKind(null),
+      lhs,
+    );
     // Stack: (Pattern left)
+    // We'll use the promotion keys allocated during processing of the LHS as
+    // the merged keys.
+    for (MapEntry<String, int> entry in leftPromotionKeys.entries) {
+      String variableName = entry.key;
+      int promotionKey = entry.value;
+      assert(!context.patternVariablePromotionKeys.containsKey(variableName));
+      context.patternVariablePromotionKeys[variableName] = promotionKey;
+    }
     flow.logicalOrPattern_afterLhs();
-    dispatchPattern(context, rhs);
+    handle_logicalOrPattern_afterLhs(node);
+    Map<String, int> rightPromotionKeys = {};
+    dispatchPattern(
+      context
+          .withPromotionKeys(rightPromotionKeys)
+          .withUnnecessaryWildcardKind(null),
+      rhs,
+    );
     // Stack: (Pattern left, Pattern right)
+    for (MapEntry<String, int> entry in rightPromotionKeys.entries) {
+      String variableName = entry.key;
+      int rightPromotionKey = entry.value;
+      int? mergedPromotionKey = leftPromotionKeys[variableName];
+      if (mergedPromotionKey == null) {
+        // No matching variable on the LHS.  This is an error condition (which
+        // has already been reported by VariableBinder).  For error recovery,
+        // we still need to add the variable to
+        // context.patternVariablePromotionKeys so that later analysis still
+        // accounts for the presence of this variable.  So we just use the
+        // promotion key from the RHS as the merged key.
+        mergedPromotionKey = rightPromotionKey;
+        assert(!context.patternVariablePromotionKeys.containsKey(variableName));
+        context.patternVariablePromotionKeys[variableName] = mergedPromotionKey;
+      } else {
+        // Copy the promotion data over to the merged key.
+        flow.copyPromotionData(
+            sourceKey: rightPromotionKey, destinationKey: mergedPromotionKey);
+      }
+    }
+    // Since the promotion data is now all stored in the merged keys in both
+    // flow control branches, the normal join process will combine promotions
+    // accordingly.
     flow.logicalOrPattern_end();
   }
 
@@ -800,32 +941,65 @@
         keyContext = unknownType;
       }
     }
+    Type requiredType = mapType(
+      keyType: keyType,
+      valueType: valueType,
+    );
+    flow.promoteForPattern(
+        matchedType: matchedType,
+        knownType: requiredType,
+        matchMayFailEvenIfCorrectType: true);
     // Stack: ()
+
+    bool hasDuplicateRestPatternReported = false;
+    Node? previousRestPattern;
     for (Node element in elements) {
+      if (isRestPatternElement(element)) {
+        if (previousRestPattern != null) {
+          errors?.duplicateRestPattern(
+            mapOrListPattern: node,
+            original: previousRestPattern,
+            duplicate: element,
+          );
+          hasDuplicateRestPatternReported = true;
+        }
+        previousRestPattern = element;
+      }
+    }
+
+    for (int i = 0; i < elements.length; i++) {
+      Node element = elements[i];
       MapPatternEntry<Expression, Pattern>? entry = getMapPatternEntry(element);
       if (entry != null) {
         analyzeExpression(entry.key, keyContext);
-        flow.pushSubpattern(valueType, isDistinctValue: true);
-        dispatchPattern(context, entry.value);
+        flow.pushSubpattern(valueType);
+        dispatchPattern(
+          context.withUnnecessaryWildcardKind(null),
+          entry.value,
+        );
         handleMapPatternEntry(node, element);
         flow.popSubpattern();
       } else {
         assert(isRestPatternElement(element));
+        if (!hasDuplicateRestPatternReported) {
+          if (i != elements.length - 1) {
+            errors?.restPatternNotLastInMap(node, element);
+          }
+        }
         Pattern? subPattern = getRestPatternElementPattern(element);
         if (subPattern != null) {
           errors?.restPatternWithSubPatternInMap(node, element);
-          flow.pushSubpattern(dynamicType, isDistinctValue: true);
-          dispatchPattern(context, subPattern);
+          flow.pushSubpattern(dynamicType);
+          dispatchPattern(
+            context.withUnnecessaryWildcardKind(null),
+            subPattern,
+          );
           flow.popSubpattern();
         }
         handleMapPatternRestElement(node, element);
       }
     }
     // Stack: (n * MapPatternElement) where n = elements.length
-    Type requiredType = mapType(
-      keyType: keyType,
-      valueType: valueType,
-    );
     Node? irrefutableContext = context.irrefutableContext;
     if (irrefutableContext != null &&
         !operations.isAssignableTo(matchedType, requiredType)) {
@@ -882,22 +1056,29 @@
   /// Stack effect: pushes (Pattern innerPattern).
   void analyzeNullCheckOrAssertPattern(
       MatchContext<Node, Expression, Pattern, Type, Variable> context,
-      Node node,
+      Pattern node,
       Pattern innerPattern,
       {required bool isAssert}) {
     // Stack: ()
-    Type matchedType = flow.getMatchedValueType();
-    Type innerMatchedType = operations.promoteToNonNull(matchedType);
     Node? irrefutableContext = context.irrefutableContext;
+    bool matchedTypeIsStrictlyNonNullable =
+        flow.nullCheckOrAssertPattern_begin(isAssert: isAssert);
     if (irrefutableContext != null && !isAssert) {
       errors?.refutablePatternInIrrefutableContext(node, irrefutableContext);
       // Avoid cascading errors
       context = context.makeRefutable();
+    } else if (matchedTypeIsStrictlyNonNullable) {
+      errors?.matchedTypeIsStrictlyNonNullable(
+        pattern: node,
+        matchedType: flow.getMatchedValueType(),
+      );
     }
-    flow.pushSubpattern(innerMatchedType, isDistinctValue: false);
-    dispatchPattern(context, innerPattern);
+    dispatchPattern(
+      context.withUnnecessaryWildcardKind(null),
+      innerPattern,
+    );
     // Stack: (Pattern)
-    flow.popSubpattern();
+    flow.nullCheckOrAssertPattern_end();
   }
 
   /// Computes the type schema for a null-check or null-assert pattern.
@@ -931,13 +1112,14 @@
     Pattern node, {
     required List<RecordPatternField<Node, Pattern>> fields,
   }) {
-    _reportDuplicateRecordPatternFields(fields);
+    _reportDuplicateRecordPatternFields(node, fields);
 
     Type matchedType = flow.getMatchedValueType();
     Type requiredType = downwardInferObjectPatternRequiredType(
       matchedType: matchedType,
       pattern: node,
     );
+    flow.promoteForPattern(matchedType: matchedType, knownType: requiredType);
 
     // If the required type is `dynamic` or `Never`, then every getter is
     // treated as having the same type.
@@ -965,8 +1147,11 @@
             receiverType: requiredType,
             field: field,
           );
-      flow.pushSubpattern(propertyType, isDistinctValue: true);
-      dispatchPattern(context, field.pattern);
+      flow.pushSubpattern(propertyType);
+      dispatchPattern(
+        context.withUnnecessaryWildcardKind(null),
+        field.pattern,
+      );
       flow.popSubpattern();
     }
     // Stack: (n * Pattern) where n = fields.length
@@ -988,28 +1173,101 @@
   /// the pattern, and [rhs] for the right hand side.
   ///
   /// Stack effect: pushes (Expression, Pattern).
-  ExpressionTypeAnalysisResult<Type> analyzePatternAssignment(
+  PatternAssignmentAnalysisResult<Type> analyzePatternAssignment(
       Expression node, Pattern pattern, Expression rhs) {
     // Stack: ()
-    Type rhsType = analyzeExpression(rhs, dispatchPatternSchema(pattern));
+    Type patternSchema = dispatchPatternSchema(pattern);
+    Type rhsType = analyzeExpression(rhs, patternSchema);
     // Stack: (Expression)
     flow.patternAssignment_afterRhs(rhs, rhsType);
+    Map<String, List<Variable>> componentVariables = {};
+    Map<String, int> patternVariablePromotionKeys = {};
     dispatchPattern(
       new MatchContext<Node, Expression, Pattern, Type, Variable>(
         isFinal: false,
         initializer: rhs,
         irrefutableContext: node,
-        topPattern: pattern,
+        assignedVariables: <Variable, Pattern>{},
+        componentVariables: componentVariables,
+        patternVariablePromotionKeys: patternVariablePromotionKeys,
       ),
       pattern,
     );
+    if (componentVariables.isNotEmpty) {
+      // Declared pattern variables should never appear in a pattern assignment
+      // so this should never happen.
+      errors?.assertInErrorRecovery();
+    }
     flow.patternAssignment_end();
     // Stack: (Expression, Pattern)
-    return new SimpleTypeAnalysisResult<Type>(type: rhsType);
+    return new PatternAssignmentAnalysisResult<Type>(
+      patternSchema: patternSchema,
+      type: rhsType,
+    );
   }
 
-  /// Analyzes a patternVariableDeclaration statement of the form
-  /// `var pattern = initializer;` or `final pattern = initializer;.
+  /// Analyzes a `pattern-for-in` statement or element.
+  ///
+  /// Statement:
+  /// `for (<keyword> <pattern> in <expression>) <statement>`
+  ///
+  /// Element:
+  /// `for (<keyword> <pattern> in <expression>) <body>`
+  ///
+  /// Stack effect: pushes (Expression, Pattern).
+  void analyzePatternForIn({
+    required Node node,
+    required bool hasAwait,
+    required Pattern pattern,
+    required Expression expression,
+    required void Function() dispatchBody,
+  }) {
+    // Stack: ()
+    Type patternTypeSchema = dispatchPatternSchema(pattern);
+    Type expressionTypeSchema = hasAwait
+        ? streamType(patternTypeSchema)
+        : iterableType(patternTypeSchema);
+    Type expressionType = analyzeExpression(expression, expressionTypeSchema);
+    // Stack: (Expression)
+
+    Type? elementType = hasAwait
+        ? operations.matchStreamType(expressionType)
+        : operations.matchIterableType(expressionType);
+    if (elementType == null) {
+      if (operations.isDynamic(expressionType)) {
+        elementType = dynamicType;
+      } else {
+        errors?.patternForInExpressionIsNotIterable(
+          node: node,
+          expression: expression,
+          expressionType: expressionType,
+        );
+        elementType = dynamicType;
+      }
+    }
+    flow.patternForIn_afterExpression(elementType);
+
+    Map<String, List<Variable>> componentVariables = {};
+    Map<String, int> patternVariablePromotionKeys = {};
+    dispatchPattern(
+      new MatchContext<Node, Expression, Pattern, Type, Variable>(
+        isFinal: false,
+        irrefutableContext: node,
+        componentVariables: componentVariables,
+        patternVariablePromotionKeys: patternVariablePromotionKeys,
+      ),
+      pattern,
+    );
+    // Stack: (Expression, Pattern)
+
+    flow.forEach_bodyBegin(node);
+    dispatchBody();
+    flow.forEach_end();
+    flow.patternForIn_end();
+  }
+
+  /// Analyzes a patternVariableDeclaration node of the form
+  /// `var pattern = initializer` or `final pattern = initializer`.
   ///
   /// [node] should be the AST node for the entire declaration, [pattern] for
   /// the pattern, and [initializer] for the initializer.  [isFinal] and
@@ -1020,8 +1278,10 @@
   /// variable pattern; [TypeAnalyzerErrors.patternDoesNotAllowLate] will be
   /// reported if any other kind of pattern is used.
   ///
+  /// Returns the type schema of the [pattern].
+  ///
   /// Stack effect: pushes (Expression, Pattern).
-  void analyzePatternVariableDeclarationStatement(
+  Type analyzePatternVariableDeclaration(
       Node node, Pattern pattern, Expression initializer,
       {required bool isFinal, required bool isLate}) {
     // Stack: ()
@@ -1031,26 +1291,33 @@
     if (isLate) {
       flow.lateInitializer_begin(node);
     }
-    Type initializerType =
-        analyzeExpression(initializer, dispatchPatternSchema(pattern));
+    Type patternSchema = dispatchPatternSchema(pattern);
+    Type initializerType = analyzeExpression(initializer, patternSchema);
     // Stack: (Expression)
     if (isLate) {
       flow.lateInitializer_end();
     }
     flow.patternVariableDeclaration_afterInitializer(
         initializer, initializerType);
+    Map<String, List<Variable>> componentVariables = {};
+    Map<String, int> patternVariablePromotionKeys = {};
     dispatchPattern(
       new MatchContext<Node, Expression, Pattern, Type, Variable>(
         isFinal: isFinal,
         isLate: isLate,
         initializer: initializer,
         irrefutableContext: node,
-        topPattern: pattern,
+        componentVariables: componentVariables,
+        patternVariablePromotionKeys: patternVariablePromotionKeys,
       ),
       pattern,
     );
+    _finishJoinedPatternVariables(
+        {}, componentVariables, patternVariablePromotionKeys,
+        location: JoinedPatternVariableLocation.singlePattern);
     flow.patternVariableDeclaration_end();
     // Stack: (Expression, Pattern)
+    return patternSchema;
   }
 
   /// Analyzes a record pattern.  [node] is the pattern itself, and [fields]
@@ -1064,12 +1331,24 @@
     Pattern node, {
     required List<RecordPatternField<Node, Pattern>> fields,
   }) {
+    List<Type> demonstratedPositionalTypes = [];
+    List<NamedType<Type>> demonstratedNamedTypes = [];
     void dispatchField(
       RecordPatternField<Node, Pattern> field,
       Type matchedType,
     ) {
-      flow.pushSubpattern(matchedType, isDistinctValue: true);
-      dispatchPattern(context, field.pattern);
+      flow.pushSubpattern(matchedType);
+      dispatchPattern(
+        context.withUnnecessaryWildcardKind(null),
+        field.pattern,
+      );
+      Type demonstratedType = flow.getMatchedValueType();
+      String? name = field.name;
+      if (name == null) {
+        demonstratedPositionalTypes.add(demonstratedType);
+      } else {
+        demonstratedNamedTypes.add(new NamedType(name, demonstratedType));
+      }
       flow.popSubpattern();
     }
 
@@ -1079,7 +1358,7 @@
       }
     }
 
-    _reportDuplicateRecordPatternFields(fields);
+    _reportDuplicateRecordPatternFields(node, fields);
 
     // Build the required type.
     int requiredTypePositionalCount = 0;
@@ -1101,9 +1380,10 @@
       ),
       named: requiredTypeNamedTypes,
     );
+    Type matchedType = flow.getMatchedValueType();
+    flow.promoteForPattern(matchedType: matchedType, knownType: requiredType);
 
     // Stack: ()
-    Type matchedType = flow.getMatchedValueType();
     RecordType<Type>? matchedRecordType = asRecordType(matchedType);
     if (matchedRecordType != null) {
       List<Type>? fieldTypes = _matchRecordTypeShape(fields, matchedRecordType);
@@ -1132,6 +1412,13 @@
         requiredType: requiredType,
       );
     }
+
+    Type demonstratedType = recordType(
+        positional: demonstratedPositionalTypes, named: demonstratedNamedTypes);
+    flow.promoteForPattern(
+        matchedType: matchedType,
+        knownType: demonstratedType,
+        matchFailsIfWrongType: false);
     return requiredType;
   }
 
@@ -1162,10 +1449,12 @@
   /// This method will invoke [resolveRelationalPatternOperator] to obtain
   /// information about the operator.
   ///
+  /// Returns the type of the [operand].
+  ///
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (Expression).
-  void analyzeRelationalPattern(
+  Type analyzeRelationalPattern(
       MatchContext<Node, Expression, Pattern, Type, Variable> context,
       Pattern node,
       Expression operand) {
@@ -1181,11 +1470,27 @@
         resolveRelationalPatternOperator(node, matchedValueType);
     Type operandContext = operator?.parameterType ?? unknownType;
     Type operandType = analyzeExpression(operand, operandContext);
+    bool isEquality;
+    switch (operator?.kind) {
+      case RelationalOperatorKind.equals:
+        isEquality = true;
+        flow.equalityRelationalPattern_end(operand, operandType,
+            notEqual: false);
+        break;
+      case RelationalOperatorKind.notEquals:
+        isEquality = true;
+        flow.equalityRelationalPattern_end(operand, operandType,
+            notEqual: true);
+        break;
+      default:
+        isEquality = false;
+        flow.nonEqualityRelationalPattern_end();
+        break;
+    }
     // Stack: (Expression)
     if (errors != null && operator != null) {
-      Type argumentType = operator.isEquality
-          ? operations.promoteToNonNull(operandType)
-          : operandType;
+      Type argumentType =
+          isEquality ? operations.promoteToNonNull(operandType) : operandType;
       if (!operations.isAssignableTo(argumentType, operator.parameterType)) {
         errors.argumentTypeNotAssignable(
           argument: operand,
@@ -1195,11 +1500,14 @@
       }
       if (!operations.isAssignableTo(operator.returnType, boolType)) {
         errors.relationalPatternOperatorReturnTypeNotAssignableToBool(
-          node: node,
+          pattern: node,
           returnType: operator.returnType,
         );
       }
     }
+    // TODO(johnniwinther): This doesn't scale. We probably need to pass more
+    // information, for instance whether this was an erroneous case.
+    return operandType;
   }
 
   /// Computes the type schema for a relational pattern.
@@ -1231,20 +1539,26 @@
           getSwitchExpressionMemberInfo(node, i);
       flow.switchStatement_beginAlternatives();
       flow.switchStatement_beginAlternative();
+      handleSwitchBeforeAlternative(node, caseIndex: i, subIndex: 0);
       Node? pattern = memberInfo.head.pattern;
       Expression? guard;
       if (pattern != null) {
+        Map<String, List<Variable>> componentVariables = {};
+        Map<String, int> patternVariablePromotionKeys = {};
         dispatchPattern(
           new MatchContext<Node, Expression, Pattern, Type, Variable>(
             isFinal: false,
             switchScrutinee: scrutinee,
-            topPattern: pattern,
+            componentVariables: componentVariables,
+            patternVariablePromotionKeys: patternVariablePromotionKeys,
           ),
           pattern,
         );
-        _finishJoinedVariables(
+        _finishJoinedPatternVariables(
           memberInfo.head.variables,
-          reportErrors: true,
+          componentVariables,
+          patternVariablePromotionKeys,
+          location: JoinedPatternVariableLocation.singlePattern,
         );
         // Stack: (Expression, i * ExpressionCase, Pattern)
         guard = memberInfo.head.guard;
@@ -1258,7 +1572,7 @@
         }
         handleCaseHead(node, caseIndex: i, subIndex: 0);
       } else {
-        handleDefault(node, i);
+        handleDefault(node, caseIndex: i, subIndex: 0);
       }
       flow.switchStatement_endAlternative(guard);
       flow.switchStatement_endAlternatives(null, hasLabels: false);
@@ -1274,9 +1588,10 @@
       finishExpressionCase(node, i);
       // Stack: (Expression, (i + 1) * ExpressionCase)
     }
+    lubType ??= dynamicType;
     // Stack: (Expression, numCases * ExpressionCase)
     flow.switchStatement_end(true);
-    return new SimpleTypeAnalysisResult<Type>(type: lubType!);
+    return new SimpleTypeAnalysisResult<Type>(type: lubType);
   }
 
   /// Analyzes a statement of the form `switch (expression) { cases }`.
@@ -1293,6 +1608,8 @@
     bool hasDefault = false;
     bool lastCaseTerminates = true;
     for (int caseIndex = 0; caseIndex < numCases; caseIndex++) {
+      Map<String, List<Variable>> outerComponentVariables = {};
+      Map<String, int> outerPatternVariablePromotionKeys = {};
       // Stack: (Expression, numExecutionPaths * StatementCase)
       flow.switchStatement_beginAlternatives();
       // Stack: (Expression, numExecutionPaths * StatementCase,
@@ -1306,19 +1623,29 @@
             heads[headIndex];
         Node? pattern = head.pattern;
         flow.switchStatement_beginAlternative();
+        handleSwitchBeforeAlternative(node,
+            caseIndex: caseIndex, subIndex: headIndex);
         Expression? guard;
         if (pattern != null) {
+          Map<String, List<Variable>> componentVariables = {};
+          Map<String, int> patternVariablePromotionKeys = {};
           dispatchPattern(
             new MatchContext<Node, Expression, Pattern, Type, Variable>(
               isFinal: false,
               switchScrutinee: scrutinee,
-              topPattern: pattern,
+              componentVariables: componentVariables,
+              patternVariablePromotionKeys: patternVariablePromotionKeys,
             ),
             pattern,
           );
-          _finishJoinedVariables(
+          _finishJoinedPatternVariables(
             head.variables,
-            reportErrors: true,
+            componentVariables,
+            patternVariablePromotionKeys,
+            location: JoinedPatternVariableLocation.singlePattern,
+            outerComponentVariables: outerComponentVariables,
+            outerPatternVariablePromotionKeys:
+                outerPatternVariablePromotionKeys,
           );
           // Stack: (Expression, numExecutionPaths * StatementCase,
           //         numHeads * CaseHead, Pattern),
@@ -1333,7 +1660,7 @@
           handleCaseHead(node, caseIndex: caseIndex, subIndex: headIndex);
         } else {
           hasDefault = true;
-          handleDefault(node, caseIndex);
+          handleDefault(node, caseIndex: caseIndex, subIndex: headIndex);
         }
         // Stack: (Expression, numExecutionPaths * StatementCase,
         //         numHeads * CaseHead),
@@ -1344,28 +1671,29 @@
       flow.switchStatement_endAlternatives(node,
           hasLabels: memberInfo.hasLabels);
       Map<String, Variable> variables = memberInfo.variables;
-      _finishJoinedVariables(variables, reportErrors: false);
+      if (memberInfo.hasLabels || heads.length > 1) {
+        _finishJoinedPatternVariables(
+          variables,
+          outerComponentVariables,
+          outerPatternVariablePromotionKeys,
+          location: JoinedPatternVariableLocation.sharedCaseScope,
+        );
+      }
       handleCase_afterCaseHeads(node, caseIndex, variables.values);
       // Stack: (Expression, numExecutionPaths * StatementCase, CaseHeads)
       // If there are joined variables, declare them.
-      if (heads.length > 1 || memberInfo.hasLabels) {
-        for (Variable variable in variables.values) {
-          flow.declare(variable, true);
-        }
-      }
       for (Statement statement in memberInfo.body) {
         dispatchStatement(statement);
       }
       // Stack: (Expression, numExecutionPaths * StatementCase, CaseHeads,
       //         n * Statement), where n = body.length
-      lastCaseTerminates = !flow.isReachable;
+      lastCaseTerminates = !flow.switchStatement_afterCase();
       if (caseIndex < numCases - 1 &&
           options.nullSafetyEnabled &&
           !options.patternsEnabled &&
           !lastCaseTerminates) {
         errors?.switchCaseCompletesNormally(node, caseIndex, 1);
       }
-      flow.switchStatement_afterCase();
       handleMergedStatementCase(node,
           caseIndex: caseIndex, isTerminating: lastCaseTerminates);
       // Stack: (Expression, (numExecutionPaths + 1) * StatementCase)
@@ -1408,11 +1736,62 @@
       Node node, Variable variable, Type? declaredType,
       {required bool isFinal, required bool isLate}) {
     Type inferredType = declaredType ?? dynamicType;
-    flow.declare(variable, false);
     setVariableType(variable, inferredType);
+    flow.declare(variable, inferredType, initialized: false);
     return inferredType;
   }
 
+  /// Analyzes a wildcard pattern.  [node] is the pattern.
+  ///
+  /// See [dispatchPattern] for the meaning of [context].
+  ///
+  /// Stack effect: none.
+  void analyzeWildcardPattern({
+    required MatchContext<Node, Expression, Pattern, Type, Variable> context,
+    required Pattern node,
+    required Type? declaredType,
+  }) {
+    Type matchedType = flow.getMatchedValueType();
+    Node? irrefutableContext = context.irrefutableContext;
+    if (irrefutableContext != null && declaredType != null) {
+      if (!operations.isAssignableTo(matchedType, declaredType)) {
+        errors?.patternTypeMismatchInIrrefutableContext(
+          pattern: node,
+          context: irrefutableContext,
+          matchedType: matchedType,
+          requiredType: declaredType,
+        );
+      }
+    }
+
+    bool isAlwaysMatching;
+    if (declaredType != null) {
+      isAlwaysMatching = flow.promoteForPattern(
+          matchedType: matchedType, knownType: declaredType);
+    } else {
+      isAlwaysMatching = true;
+    }
+
+    UnnecessaryWildcardKind? unnecessaryWildcardKind =
+        context.unnecessaryWildcardKind;
+    if (isAlwaysMatching && unnecessaryWildcardKind != null) {
+      errors?.unnecessaryWildcardPattern(
+        pattern: node,
+        kind: unnecessaryWildcardKind,
+      );
+    }
+  }
+
+  /// Computes the type schema for a wildcard pattern.  [declaredType] is the
+  /// explicitly declared type (if present).
+  ///
+  /// Stack effect: none.
+  Type analyzeWildcardPatternSchema({
+    required Type? declaredType,
+  }) {
+    return declaredType ?? unknownType;
+  }
+
   /// If [type] is a record type, returns it.
   RecordType<Type>? asRecordType(Type type);
 
@@ -1478,13 +1857,12 @@
 
   void finishJoinedPatternVariable(
     Variable variable, {
+    required JoinedPatternVariableLocation location,
     required bool isConsistent,
     required bool isFinal,
     required Type type,
   });
 
-  List<Variable>? getJoinedVariableComponents(Variable variable);
-
   /// If the [element] is a map pattern entry, returns it.
   MapPatternEntry<Expression, Pattern>? getMapPatternEntry(Node element);
 
@@ -1513,20 +1891,11 @@
   SwitchStatementMemberInfo<Node, Statement, Expression, Variable>
       getSwitchStatementMemberInfo(Statement node, int caseIndex);
 
-  /// Returns the type of [node].
-  Type getVariableType(Variable node);
+  /// Returns the type of [variable].
+  Type getVariableType(Variable variable);
 
   /// Called after visiting the pattern in `if-case` statement.
-  /// [variables] are variables declared in the pattern.
-  ///
-  /// It is expected that the client will push a new scope with [variables]
-  /// available.  This scope should be used to analyze the guard, and the
-  /// `then` branch. The scope is not used for the `else` branch, so on
-  /// [handle_ifStatement_thenEnd] the client should pop it.
-  void handle_ifCaseStatement_afterPattern({
-    required Statement node,
-    required Iterable<Variable> variables,
-  }) {}
+  void handle_ifCaseStatement_afterPattern({required Statement node}) {}
 
   /// Called after visiting the expression of an `if` element.
   void handle_ifElement_conditionEnd(Node node) {}
@@ -1546,6 +1915,9 @@
   /// Called after visiting the `then` statement of an `if` statement.
   void handle_ifStatement_thenEnd(Statement node, Statement ifTrue) {}
 
+  /// Called after visiting the left hand side of a logical-or (`||`) pattern.
+  void handle_logicalOrPattern_afterLhs(Pattern node) {}
+
   /// Called after visiting a merged set of `case` / `default` clauses.
   ///
   /// [node] is the enclosing switch statement, [caseIndex] is the index of the
@@ -1569,9 +1941,14 @@
   ///
   /// [node] is the enclosing switch statement or switch expression and
   /// [caseIndex] is the index of the `default` clause.
+  /// [subIndex] is the index of the case head.
   ///
   /// Stack effect: pushes (CaseHead).
-  void handleDefault(Node node, int caseIndex);
+  void handleDefault(
+    Node node, {
+    required int caseIndex,
+    required int subIndex,
+  });
 
   /// Called after visiting a rest element in a list pattern.
   ///
@@ -1627,6 +2004,14 @@
   /// Stack effect: pushes (Statement).
   void handleNoStatement(Statement node);
 
+  /// Called before visiting a single `case` or `default` clause.
+  ///
+  /// [node] is the enclosing switch statement or switch expression and
+  /// [caseIndex] is the index of the `case` or `default` clause.
+  /// [subIndex] is the index of the case head.
+  void handleSwitchBeforeAlternative(Node node,
+      {required int caseIndex, required int subIndex});
+
   /// Called after visiting the scrutinee part of a switch statement or switch
   /// expression.  This is a hook to allow the client to start exhaustiveness
   /// analysis.
@@ -1660,6 +2045,9 @@
   /// Queries whether [pattern] is a variable pattern.
   bool isVariablePattern(Node pattern);
 
+  /// Returns the type `Iterable`, with type argument [elementType].
+  Type iterableType(Type elementType);
+
   /// Returns the type `List`, with type argument [elementType].
   Type listType(Type elementType);
 
@@ -1695,6 +2083,9 @@
   /// explicit or inferred.
   void setVariableType(Variable variable, Type type);
 
+  /// Returns the type `Stream`, with type argument [elementType].
+  Type streamType(Type elementType);
+
   /// Computes the type that should be inferred for an implicitly typed variable
   /// whose initializer expression has static type [type].
   Type variableTypeFromInitializerType(Type type);
@@ -1753,53 +2144,91 @@
     }
   }
 
-  void _finishJoinedVariables(
-    Map<String, Variable> variables, {
-    required bool reportErrors,
+  void _finishJoinedPatternVariables(
+    Map<String, Variable> variables,
+    Map<String, List<Variable>> componentVariables,
+    Map<String, int> patternVariablePromotionKeys, {
+    required JoinedPatternVariableLocation location,
+    Map<String, List<Variable>>? outerComponentVariables,
+    Map<String, int>? outerPatternVariablePromotionKeys,
   }) {
-    for (MapEntry<String, Variable> entry in variables.entries) {
-      Variable variable = entry.value;
-      List<Variable>? components = getJoinedVariableComponents(variable);
-      if (components != null) {
-        bool isConsistent = true;
-        bool? resultIsFinal;
-        Type? resultType;
-        for (Variable component in components) {
-          bool componentIsFinal = isVariableFinal(component);
-          Type componentType = getVariableType(component);
-          if (resultIsFinal == null || resultType == null) {
-            resultIsFinal = componentIsFinal;
-            resultType = componentType;
-          } else {
-            bool sameFinality = resultIsFinal == componentIsFinal;
-            bool sameType =
-                _structurallyEqualAfterNormTypes(resultType, componentType);
-            if (!sameFinality || !sameType) {
-              if (reportErrors) {
-                errors?.inconsistentJoinedPatternVariable(
-                  variable: variable,
-                  component: component,
-                );
-              }
-              isConsistent = false;
-              break;
-            }
+    assert(() {
+      // Every entry in `variables` should match a variable we know about.
+      for (String variableName in variables.keys) {
+        assert(patternVariablePromotionKeys.containsKey(variableName));
+      }
+      return true;
+    }());
+    for (MapEntry<String, int> entry in patternVariablePromotionKeys.entries) {
+      String variableName = entry.key;
+      int promotionKey = entry.value;
+      Variable? variable = variables[variableName];
+      List<Variable> components = componentVariables[variableName] ?? [];
+      bool isFirst = true;
+      Type? typeIfConsistent;
+      bool? isFinalIfConsistent;
+      bool isIdenticalToComponent = false;
+      for (Variable component in components) {
+        if (identical(variable, component)) {
+          isIdenticalToComponent = true;
+        }
+        Type componentType = getVariableType(component);
+        bool isComponentFinal = isVariableFinal(component);
+        if (isFirst) {
+          typeIfConsistent = componentType;
+          isFinalIfConsistent = isComponentFinal;
+          isFirst = false;
+        } else {
+          bool inconsistencyFound = false;
+          if (typeIfConsistent != null &&
+              !_structurallyEqualAfterNormTypes(
+                  typeIfConsistent, componentType)) {
+            typeIfConsistent = null;
+            inconsistencyFound = true;
+          }
+          if (isFinalIfConsistent != null &&
+              isFinalIfConsistent != isComponentFinal) {
+            isFinalIfConsistent = null;
+            inconsistencyFound = true;
+          }
+          if (inconsistencyFound &&
+              location == JoinedPatternVariableLocation.singlePattern &&
+              variable != null) {
+            errors?.inconsistentJoinedPatternVariable(
+                variable: variable, component: component);
           }
         }
-        if (isConsistent) {
-          finishJoinedPatternVariable(
-            variable,
-            isConsistent: true,
-            isFinal: resultIsFinal ?? false,
-            type: resultType ?? dynamicType,
-          );
+      }
+      if (variable != null) {
+        if (!isIdenticalToComponent) {
+          finishJoinedPatternVariable(variable,
+              location: location,
+              isConsistent:
+                  typeIfConsistent != null && isFinalIfConsistent != null,
+              isFinal: isFinalIfConsistent ?? false,
+              type: typeIfConsistent ?? errorType);
+          flow.assignMatchedPatternVariable(
+              variable, patternVariablePromotionKeys[variableName]!);
+        }
+        (outerComponentVariables?[variableName] ??= [])?.add(variable);
+      }
+      if (outerPatternVariablePromotionKeys != null) {
+        // We're finishing the pattern for one of the cases of a switch
+        // statement.  See if this variable appeared in any previous patterns
+        // that share the same case body.
+        int? previousPromotionKey =
+            outerPatternVariablePromotionKeys[variableName];
+        if (previousPromotionKey == null) {
+          // This variable hasn't been seen in any previous patterns that share
+          // the same body.  So we can safely use the promotion key we have to
+          // store information about this variable.
+          outerPatternVariablePromotionKeys[variableName] = promotionKey;
         } else {
-          finishJoinedPatternVariable(
-            variable,
-            isConsistent: false,
-            isFinal: false,
-            type: dynamicType,
-          );
+          // This variable has been seen in previous patterns, so we have to
+          // copy promotion data into the previously-used promotion key, to
+          // ensure that the promotion information is properly joined.
+          flow.copyPromotionData(
+              sourceKey: promotionKey, destinationKey: previousPromotionKey);
         }
       }
     }
@@ -1850,6 +2279,7 @@
 
   /// Reports errors for duplicate named record fields.
   void _reportDuplicateRecordPatternFields(
+    Pattern pattern,
     List<RecordPatternField<Node, Pattern>> fields,
   ) {
     Map<String, RecordPatternField<Node, Pattern>> nameToField = {};
@@ -1859,6 +2289,7 @@
         RecordPatternField<Node, Pattern>? original = nameToField[name];
         if (original != null) {
           errors?.duplicateRecordPatternField(
+            objectOrRecordPattern: pattern,
             name: name,
             original: original,
             duplicate: field,
@@ -1899,17 +2330,32 @@
   void caseExpressionTypeMismatch(
       {required Expression scrutinee,
       required Expression caseExpression,
-      required scrutineeType,
-      required caseExpressionType,
+      required Type scrutineeType,
+      required Type caseExpressionType,
       required bool nullSafetyEnabled});
 
+  /// Called for variable that is assigned more than once.
+  void duplicateAssignmentPatternVariable({
+    required Variable variable,
+    required Pattern original,
+    required Pattern duplicate,
+  });
+
   /// Called for a pair of named fields have the same name.
   void duplicateRecordPatternField({
+    required Pattern objectOrRecordPattern,
     required String name,
     required RecordPatternField<Node, Pattern> original,
     required RecordPatternField<Node, Pattern> duplicate,
   });
 
+  /// Called for a duplicate rest pattern found in a list or map pattern.
+  void duplicateRestPattern({
+    required Pattern mapOrListPattern,
+    required Node original,
+    required Node duplicate,
+  });
+
   /// Called when both branches have variables with the same name, but these
   /// variables either don't have the same finality, or their `NORM` types
   /// are not structurally equal.
@@ -1918,6 +2364,21 @@
     required Variable component,
   });
 
+  /// Called when a null-assert or null-check pattern is used with the matched
+  /// type that is strictly non-nullable, so the null check is not necessary.
+  void matchedTypeIsStrictlyNonNullable({
+    required Pattern pattern,
+    required Type matchedType,
+  });
+
+  /// Called when the matched type of a cast pattern is a subtype of the
+  /// required type, so the cast is not necessary.
+  void matchedTypeIsSubtypeOfRequired({
+    required Pattern pattern,
+    required Type matchedType,
+    required Type requiredType,
+  });
+
   /// Called if the static type of a condition is not assignable to `bool`.
   void nonBooleanCondition(Expression node);
 
@@ -1929,6 +2390,16 @@
   /// [pattern] is the AST node of the illegal pattern.
   void patternDoesNotAllowLate(Node pattern);
 
+  /// Called if in a pattern `for-in` statement or element, the [expression]
+  /// that should be an `Iterable` (or dynamic) is actually not.
+  ///
+  /// [expressionType] is the actual type of the [expression].
+  void patternForInExpressionIsNotIterable({
+    required Node node,
+    required Expression expression,
+    required Type expressionType,
+  });
+
   /// Called if, for a pattern in an irrefutable context, the matched type of
   /// the pattern is not assignable to the required type.
   ///
@@ -1953,10 +2424,15 @@
   /// Called if the [returnType] of the invoked relational operator is not
   /// assignable to `bool`.
   void relationalPatternOperatorReturnTypeNotAssignableToBool({
-    required Node node,
+    required Pattern pattern,
     required Type returnType,
   });
 
+  /// Called if a rest pattern inside a map pattern is not the last element.
+  ///
+  /// [node] is the map pattern.  [element] is the rest pattern.
+  void restPatternNotLastInMap(Pattern node, Node element);
+
   /// Called if a rest pattern inside a map pattern has a subpattern.
   ///
   /// [node] is the map pattern.  [element] is the rest pattern.
@@ -1971,6 +2447,14 @@
   /// the number of case heads sharing the erroneous case body.
   void switchCaseCompletesNormally(
       Statement node, int caseIndex, int numMergedCases);
+
+  /// Called when a wildcard pattern appears in the context where it is not
+  /// necessary, e.g. `0 && var _` vs. `[var _]`, and does not add anything
+  /// to type promotion, e.g. `final x = 0; if (x case int _ && > 0) {}`.
+  void unnecessaryWildcardPattern({
+    required Pattern pattern,
+    required UnnecessaryWildcardKind kind,
+  });
 }
 
 /// Base class for error reporting callbacks that might be reported either in
diff --git a/_fe_analyzer_shared/lib/src/type_inference/type_operations.dart b/_fe_analyzer_shared/lib/src/type_inference/type_operations.dart
index ba52563..0e988c4 100644
--- a/_fe_analyzer_shared/lib/src/type_inference/type_operations.dart
+++ b/_fe_analyzer_shared/lib/src/type_inference/type_operations.dart
@@ -98,6 +98,10 @@
   /// returns these `K` and `V`.  Otherwise returns `null`.
   MapPatternTypeArguments<Type>? matchMapType(Type type);
 
+  /// If [type] is a subtype of the type `Stream<T>` for some `T`, returns
+  /// the type `T`.  Otherwise returns `null`.
+  Type? matchStreamType(Type type);
+
   /// Computes `NORM` of [type].
   /// https://github.com/dart-lang/language
   /// See `resources/type-system/normalization.md`
diff --git a/_fe_analyzer_shared/lib/src/type_inference/variable_bindings.dart b/_fe_analyzer_shared/lib/src/type_inference/variable_bindings.dart
index fc49de6..1039b1b 100644
--- a/_fe_analyzer_shared/lib/src/type_inference/variable_bindings.dart
+++ b/_fe_analyzer_shared/lib/src/type_inference/variable_bindings.dart
@@ -67,45 +67,9 @@
     Map<String, Variable> variables = _variables.removeLast();
 
     if (sharedCaseScopeKey != null) {
-      Map<String, Variable> right = variables;
       _SharedCaseScope<Variable> sharedScope = _sharedCaseScopes.last;
       assert(sharedScope.key == sharedCaseScopeKey);
-      Map<String, Variable>? left = sharedScope.variables;
-      if (left == null) {
-        sharedScope.variables = right;
-      } else {
-        Map<String, Variable> result = {};
-        for (MapEntry<String, Variable> leftEntry in left.entries) {
-          String name = leftEntry.key;
-          Variable leftVariable = leftEntry.value;
-          Variable? rightVariable = right[name];
-          if (rightVariable != null) {
-            result[name] = joinPatternVariables(
-              key: sharedCaseScopeKey,
-              components: [leftVariable, rightVariable],
-              isConsistent: true,
-            );
-          } else {
-            result[name] = joinPatternVariables(
-              key: sharedCaseScopeKey,
-              components: [leftVariable],
-              isConsistent: false,
-            );
-          }
-        }
-        for (MapEntry<String, Variable> rightEntry in right.entries) {
-          String name = rightEntry.key;
-          Variable rightVariable = rightEntry.value;
-          if (!left.containsKey(name)) {
-            result[name] = joinPatternVariables(
-              key: sharedCaseScopeKey,
-              components: [rightVariable],
-              isConsistent: false,
-            );
-          }
-        }
-        sharedScope.variables = result;
-      }
+      sharedScope.addAll(variables);
     }
 
     return variables;
@@ -201,20 +165,7 @@
   void switchStatementSharedCaseScopeEmpty(Object key) {
     _SharedCaseScope<Variable> sharedScope = _sharedCaseScopes.last;
     assert(sharedScope.key == key);
-    Map<String, Variable>? left = sharedScope.variables;
-    if (left != null) {
-      Map<String, Variable> result = {};
-      for (MapEntry<String, Variable> leftEntry in left.entries) {
-        String name = leftEntry.key;
-        Variable leftVariable = leftEntry.value;
-        result[name] = joinPatternVariables(
-          key: key,
-          components: [leftVariable],
-          isConsistent: false,
-        );
-      }
-      sharedScope.variables = result;
-    }
+    sharedScope.addAll({});
   }
 
   /// Notifies that computing of the shared case scope was finished, returns
@@ -226,7 +177,23 @@
     assert(_variables.isEmpty);
     _SharedCaseScope<Variable> sharedScope = _sharedCaseScopes.removeLast();
     assert(sharedScope.key == key);
-    return sharedScope.variables ?? {};
+
+    Map<String, Variable> result = {};
+    for (MapEntry<String, _SharedCaseScopeVariable<Variable>> entry
+        in sharedScope.variables.entries) {
+      _SharedCaseScopeVariable<Variable> sharedVariable = entry.value;
+      List<Variable> variables = sharedVariable.variables;
+      if (sharedVariable.isConsistent && variables.length == 1) {
+        result[entry.key] = variables[0];
+      } else {
+        result[entry.key] = joinPatternVariables(
+          key: key,
+          components: variables,
+          isConsistent: sharedVariable.isConsistent,
+        );
+      }
+    }
+    return result;
   }
 
   /// Notifies that computing new shared case scope should be started.
@@ -262,7 +229,51 @@
 
 class _SharedCaseScope<Variable extends Object> {
   final Object key;
-  Map<String, Variable>? variables;
+  bool isEmpty = true;
+  Map<String, _SharedCaseScopeVariable<Variable>> variables = {};
 
   _SharedCaseScope(this.key);
+
+  /// Adds [newVariables] to [variables], marking absent variables as not
+  /// consistent. If [isEmpty], just sets given variables as the starting set.
+  void addAll(Map<String, Variable> newVariables) {
+    if (isEmpty) {
+      isEmpty = false;
+      for (MapEntry<String, Variable> entry in newVariables.entries) {
+        String name = entry.key;
+        Variable variable = entry.value;
+        _getVariable(name).variables.add(variable);
+      }
+    } else {
+      for (MapEntry<String, _SharedCaseScopeVariable<Variable>> entry
+          in variables.entries) {
+        String name = entry.key;
+        _SharedCaseScopeVariable<Variable> variable = entry.value;
+        Variable? newVariable = newVariables[name];
+        if (newVariable != null) {
+          variable.variables.add(newVariable);
+        } else {
+          variable.isConsistent = false;
+        }
+      }
+      for (MapEntry<String, Variable> newEntry in newVariables.entries) {
+        String name = newEntry.key;
+        Variable newVariable = newEntry.value;
+        if (!variables.containsKey(name)) {
+          _getVariable(name)
+            ..isConsistent = false
+            ..variables.add(newVariable);
+        }
+      }
+    }
+  }
+
+  _SharedCaseScopeVariable _getVariable(String name) {
+    return variables[name] ??= new _SharedCaseScopeVariable();
+  }
+}
+
+class _SharedCaseScopeVariable<Variable extends Object> {
+  bool isConsistent = true;
+  final List<Variable> variables = [];
 }
diff --git a/_fe_analyzer_shared/lib/src/util/null_value.dart b/_fe_analyzer_shared/lib/src/util/null_value.dart
new file mode 100644
index 0000000..b0a571b
--- /dev/null
+++ b/_fe_analyzer_shared/lib/src/util/null_value.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Interface for sentinel values used for typed `null` values on a stack.
+///
+/// This is used to avoid mixing `null` values between different kinds. For
+/// instance a stack entry is meant to contain an expression or null, the
+/// `NullValues.Expression` is pushed on the stack instead of `null` and when
+/// popping the entry `NullValues.Expression` is passed show how `null` is
+/// represented.
+class NullValue<T> {
+  const NullValue();
+
+  @override
+  String toString() => "NullValue<$T>";
+}
diff --git a/_fe_analyzer_shared/lib/src/util/stack_checker.dart b/_fe_analyzer_shared/lib/src/util/stack_checker.dart
new file mode 100644
index 0000000..a2450be
--- /dev/null
+++ b/_fe_analyzer_shared/lib/src/util/stack_checker.dart
@@ -0,0 +1,248 @@
+// Copyright (c) 2016, 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:math';
+import '../messages/codes.dart';
+import 'value_kind.dart';
+
+mixin StackChecker {
+  /// Used to report an internal error encountered in the stack listener.
+  Never internalProblem(Message message, int charOffset, Uri uri);
+
+  /// Checks that [value] matches the expected [kind].
+  ///
+  /// Use this in assert statements like
+  ///
+  ///     assert(checkStackValue(uri, fileOffset, ValueKind.Token, value));
+  ///
+  /// to document and validate the expected value kind.
+  bool checkStackValue(
+      Uri uri, int? fileOffset, ValueKind kind, Object? value) {
+    if (!kind.check(value)) {
+      String message = 'Unexpected value `${value}` (${value.runtimeType}). '
+          'Expected ${kind}.';
+      if (fileOffset != null) {
+        // If offset is available report and internal problem to show the
+        // parsed code in the output.
+        throw internalProblem(
+            new Message(const Code<String>('Internal error'),
+                problemMessage: message),
+            fileOffset,
+            uri);
+      } else {
+        throw message;
+      }
+    }
+    return true;
+  }
+
+  /// Returns the size of the stack.
+  int get stackHeight;
+
+  /// Returns the [index]th element on the stack from the top, i.e. the top of
+  /// the stack has index 0.
+  Object? lookupStack(int index);
+
+  /// Checks that [base] is a valid base stack height for a call to
+  /// [checkStackStateForAssert].
+  ///
+  /// This can be used to initialize a stack base for subsequent calls to
+  /// [checkStackStateForAssert]. For instance:
+  ///
+  ///      int? stackBase;
+  ///      // Set up the current stack height as the stack base.
+  ///      assert(checkStackBaseState(
+  ///          uri, fileOffset, stackBase = stackHeight));
+  ///      ...
+  ///      // Check that the stack is empty, relative to the stack base.
+  ///      assert(checkStackState(
+  ///          uri, fileOffset, [], base: stackBase));
+  ///
+  /// or
+  ///
+  ///      int? stackBase;
+  ///      // Assert that the current stack height is at least 4 and set
+  ///      // the stack height - 4 up as the stack base.
+  ///      assert(checkStackBaseState(
+  ///          uri, fileOffset, stackBase = stackHeight - 4));
+  ///      ...
+  ///      // Check that the stack contains a single `Foo` element, relative to
+  ///      // the stack base.
+  ///      assert(checkStackState(
+  ///          uri, fileOffset, [ValuesKind.Foo], base: stackBase));
+  ///
+  bool checkStackBaseStateForAssert(Uri uri, int? fileOffset, int base) {
+    if (base < 0) {
+      _throwProblem(
+          uri,
+          fileOffset,
+          "Too few elements on stack. "
+          "Expected ${stackHeight - base}, found $stackHeight.");
+    }
+    return true;
+  }
+
+  /// Checks the top of the current stack against [kinds]. If a mismatch is
+  /// found, a top of the current stack is print along with the expected [kinds]
+  /// marking the frames that don't match, and throws an exception.
+  ///
+  /// If [base] provided, it is used as the reference stack base height at
+  /// which the [kinds] are expected to occur. This allows for checking that
+  /// the stack is empty wrt. the stack base height.
+  ///
+  /// Use this in assert statements like
+  ///
+  ///     assert(checkStackState(
+  ///         uri, fileOffset, [ValueKind.Integer, ValueKind.StringOrNull]))
+  ///
+  /// to document the expected stack and get earlier errors on unexpected stack
+  /// content.
+  bool checkStackStateForAssert(Uri uri, int? fileOffset, List<ValueKind> kinds,
+      {int? base}) {
+    String? heightError;
+    String? kindError;
+    bool success = true;
+    int stackShift = 0;
+    if (base != null) {
+      int relativeStackHeight = stackHeight - base;
+      if (relativeStackHeight < kinds.length) {
+        heightError = "Too few elements on stack. "
+            "Expected ${kinds.length}, found $relativeStackHeight.";
+        success = false;
+      } else if (relativeStackHeight > kinds.length) {
+        heightError = "Too many elements on stack. "
+            "Expected ${kinds.length}, found $relativeStackHeight.";
+        success = false;
+      }
+      // Shift the stack lookup indices so that [kinds] are checked relative
+      // to the stack base instead of relative to the top of the stack.
+      stackShift = relativeStackHeight - kinds.length;
+    } else {
+      if (stackHeight < kinds.length) {
+        heightError = "Too few elements on stack. "
+            "Expected ${kinds.length}, found $stackHeight.";
+        success = false;
+      }
+    }
+    for (int kindIndex = 0; kindIndex < kinds.length; kindIndex++) {
+      ValueKind kind = kinds[kindIndex];
+      int stackOffset = kindIndex + stackShift;
+      if (0 <= stackOffset && stackOffset < stackHeight) {
+        Object? value = lookupStack(stackOffset);
+        if (!kind.check(value)) {
+          kindError = "Unexpected element kind(s).";
+          success = false;
+        }
+      } else {
+        success = false;
+      }
+    }
+    if (!success) {
+      StringBuffer sb = new StringBuffer();
+      if (heightError != null) {
+        sb.writeln(' $heightError');
+      }
+      if (kindError != null) {
+        sb.writeln(' $kindError');
+      }
+
+      String safeToString(Object? object) {
+        try {
+          return '$object'.replaceAll('\r', '').replaceAll('\n', '');
+        } catch (e) {
+          // Judgments fail on toString.
+          return object.runtimeType.toString();
+        }
+      }
+
+      String padLeft(Object object, int length) {
+        String text = safeToString(object);
+        if (text.length < length) {
+          return ' ' * (length - text.length) + text;
+        }
+        return text;
+      }
+
+      String padRight(Object object, int length) {
+        String text = safeToString(object);
+        if (text.length < length) {
+          return text + ' ' * (length - text.length);
+        }
+        return text;
+      }
+
+      // Compute kind/stack frame information for all expected values plus 3 more
+      // stack elements if available.
+
+      int startIndex = min(-stackShift, 0);
+      int endIndex = max(kinds.length + stackShift, stackHeight);
+
+      for (int kindIndex = startIndex; kindIndex < endIndex + 3; kindIndex++) {
+        int stackOffset = kindIndex + stackShift;
+        if (stackOffset >= stackHeight && kindIndex > kinds.length) {
+          // No more stack elements nor kinds to display.
+          break;
+        }
+        if (kindIndex == kinds.length && base != null) {
+          // Show where the stack base is in the stack. Elements printed above
+          // this line are the checked/expected stack.
+          sb.write('>');
+        } else {
+          sb.write(' ');
+        }
+        if (stackOffset >= 0) {
+          sb.write(padLeft(stackOffset, 3));
+        } else {
+          sb.write(padLeft('*', 3));
+        }
+        sb.write(': ');
+        ValueKind? kind;
+        if (kindIndex < 0) {
+          sb.write(padRight('', 60));
+        } else if (kindIndex < kinds.length) {
+          kind = kinds[kindIndex];
+          sb.write(padRight(kind, 60));
+        } else {
+          sb.write(padRight('---', 60));
+        }
+        if (0 <= stackOffset && stackOffset < stackHeight) {
+          Object? value = lookupStack(stackOffset);
+          if (kind == null || kind.check(value)) {
+            sb.write(' ');
+          } else {
+            sb.write('*');
+          }
+          sb.write(safeToString(value));
+          sb.write(' (${value.runtimeType})');
+        } else {
+          if (kind == null) {
+            sb.write(' ');
+          } else {
+            sb.write('*');
+          }
+          sb.write('---');
+        }
+        sb.writeln();
+      }
+
+      _throwProblem(uri, fileOffset, sb.toString());
+    }
+    return success;
+  }
+
+  Never _throwProblem(Uri uri, int? fileOffset, String text) {
+    String message = '$runtimeType failure\n$text';
+    if (fileOffset != null) {
+      // If offset is available report and internal problem to show the
+      // parsed code in the output.
+      throw internalProblem(
+          new Message(const Code<String>('Internal error'),
+              problemMessage: message),
+          fileOffset,
+          uri);
+    } else {
+      throw message;
+    }
+  }
+}
diff --git a/_fe_analyzer_shared/lib/src/parser/value_kind.dart b/_fe_analyzer_shared/lib/src/util/value_kind.dart
similarity index 92%
rename from _fe_analyzer_shared/lib/src/parser/value_kind.dart
rename to _fe_analyzer_shared/lib/src/util/value_kind.dart
index d9aaa69..b683522 100644
--- a/_fe_analyzer_shared/lib/src/parser/value_kind.dart
+++ b/_fe_analyzer_shared/lib/src/util/value_kind.dart
@@ -2,7 +2,7 @@
 // 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 'stack_listener.dart' show NullValue;
+import 'null_value.dart' show NullValue;
 
 /// [ValueKind] is used in [StackListener.checkState] to document and check the
 /// expected values of the stack.
@@ -13,13 +13,14 @@
   const ValueKind();
 
   /// Checks the [value] an returns `true` if the value is of the expected kind.
-  bool check(Object ?value);
+  bool check(Object? value);
 }
 
 /// A [ValueKind] for a particular type [T], optionally with a recognized
 /// [NullValue].
 class SingleValueKind<T> implements ValueKind {
-  final NullValue? nullValue;
+  // TODO(johnniwinther): Type this as `NullValue<T>?`.
+  final NullValue<Object>? nullValue;
 
   const SingleValueKind([this.nullValue]);
 
diff --git a/_fe_analyzer_shared/pubspec.yaml b/_fe_analyzer_shared/pubspec.yaml
index 9ba6afe..7208bbf 100644
--- a/_fe_analyzer_shared/pubspec.yaml
+++ b/_fe_analyzer_shared/pubspec.yaml
@@ -1,5 +1,5 @@
 name: _fe_analyzer_shared
-version: 52.0.0
+version: 53.0.0
 description: Logic that is shared between the front_end and analyzer packages.
 repository: https://github.com/dart-lang/sdk/tree/main/pkg/_fe_analyzer_shared
 
@@ -13,5 +13,5 @@
 # the dart-lang/sdk repo's DEPS file. Note that this is a special case; the
 # best practice for packages is to specify their compatible version ranges.
 # See also https://dart.dev/tools/pub/dependencies.
-#dev_dependencies:
+dev_dependencies:
 #  test: any
diff --git a/analyzer/BUILD.gn b/analyzer/BUILD.gn
index c376f4d..9e060ff 100644
--- a/analyzer/BUILD.gn
+++ b/analyzer/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by package_importer.py for analyzer-5.4.0
+# This file is generated by package_importer.py for analyzer-5.5.0
 
 import("//build/dart/dart_library.gni")
 
@@ -169,7 +169,6 @@
     "src/dart/error/ffi_code.g.dart",
     "src/dart/error/hint_codes.dart",
     "src/dart/error/hint_codes.g.dart",
-    "src/dart/error/inference_error_listener.dart",
     "src/dart/error/lint_codes.dart",
     "src/dart/error/syntactic_errors.dart",
     "src/dart/error/syntactic_errors.g.dart",
@@ -220,6 +219,7 @@
     "src/dart/scanner/reader.dart",
     "src/dart/scanner/scanner.dart",
     "src/dart/sdk/sdk.dart",
+    "src/dart/sdk/sdk_utils.dart",
     "src/dartdoc/dartdoc_directive_info.dart",
     "src/diagnostic/diagnostic.dart",
     "src/diagnostic/diagnostic_factory.dart",
@@ -267,6 +267,7 @@
     "src/generated/engine.dart",
     "src/generated/error_detection_helpers.dart",
     "src/generated/error_verifier.dart",
+    "src/generated/exhaustiveness.dart",
     "src/generated/ffi_verifier.dart",
     "src/generated/interner.dart",
     "src/generated/java_core.dart",
@@ -420,6 +421,7 @@
     "src/utilities/extensions/stream.dart",
     "src/utilities/extensions/string.dart",
     "src/utilities/legacy.dart",
+    "src/utilities/uri_cache.dart",
     "src/workspace/basic.dart",
     "src/workspace/blaze.dart",
     "src/workspace/blaze_watcher.dart",
diff --git a/analyzer/CHANGELOG.md b/analyzer/CHANGELOG.md
index 29b1639..6b9f9e2 100644
--- a/analyzer/CHANGELOG.md
+++ b/analyzer/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 5.5.0
+* Rename `RecordPatternField` to `PatternField`.
+* Rename `RecordPatternFieldName` to `PatternFieldName`.
+
 ## 5.4.0
 * Bug fixes: 50660
 
@@ -75,7 +79,7 @@
 * Added `FileResult.isAugmentation` and `isLibrary` to complement `isPart`.
 * Deprecated 'XyzDeclaration.name' in AST, use `name2` and `declaredElement` instead.
 * Deprecated `Element.enclosingElement2`, use `enclosingElement3` instead.  The meaningful change is that
-  `ConstructorElement.enclosingElement3` returns now `IntefaceElement`, not `ClassElement`.
+  `ConstructorElement.enclosingElement3` returns now `InterfaceElement`, not `ClassElement`.
 * Deprecated `get enums/mixin`, use `get enums2/mixins2` instead.
 * Deprecated `DartType.element`, check for `InterfaceType`, `TypeParameterType`, and then ask the element.
 * Deprecated `ClassElement.isEnum` and `isMixin`. Check for `is EnumElement` and `is MixinElement` instead.
@@ -919,7 +923,7 @@
   #36678, #36691.
 
 ## 0.36.0
-* Changed the return type of `Expression.precendence` to `Precedence`.  Clients
+* Changed the return type of `Expression.precedence` to `Precedence`.  Clients
   that prepared for this change by switching to `Expression.precedence2` should
   now return to using `Expression.precedence`.
 * AST cleanup related to the "UI as code" feature:
diff --git a/analyzer/analysis_options.yaml b/analyzer/analysis_options.yaml
index 000ed6c..19fb3e5 100644
--- a/analyzer/analysis_options.yaml
+++ b/analyzer/analysis_options.yaml
@@ -31,6 +31,7 @@
     provide_deprecation_message: ignore
 
   language:
+    strict-casts: true
     strict-inference: true
 
 linter:
diff --git a/analyzer/doc/implementation/diagnostics.md b/analyzer/doc/implementation/diagnostics.md
index 6e70ca0..a7bc2be 100644
--- a/analyzer/doc/implementation/diagnostics.md
+++ b/analyzer/doc/implementation/diagnostics.md
@@ -15,33 +15,45 @@
 
 For most diagnostics, a single message (code) is sufficient. But sometimes it's
 useful to tailor the message based on the context in which the problem occurs or
-because the message can be made more clear. For example, it's an error to
-declare two or more constructors with the same name. That's true whether the
-name is explicit or implicit (the default constructor). In order for the message
-to match the user's model of the language, we define two messages for this one
-problem: one that refers to the constructors by their name, and one that refers
-to the constructors as "unnamed". The way we define two messages is by defining
-two codes.
+because the message can be made more clear.
+
+For example, it's an error to declare two or more constructors with the same name.
+That's true whether the name is explicit or implicit (the default constructor).
+In order for the message to match the user's model of the language, we define
+two messages for this one problem: one that refers to the constructors by their
+name, and one that refers to the constructors as "unnamed". The way we define
+two messages is by defining two codes.
 
 Each code has a unique name (the key used in the map in `messages.yaml`) and can
 optionally define a shared name that links all the codes for a single diagnostic
 together. It is the shared name that is displayed to users. If a shared name
 isn't explicitly provided, it will default to being the same as the unique name.
 
-After every edit to the `messages.yaml` file, you will need to run the utility
-`analyzer/tool/messages/generate.dart` to update the generated files.
+### Updating generated files
 
-You also need to manually add the name of the code to the list of codes in two
-files:
-- `analyzer/lib/error/error.dart`
-- `analysis_server/lib/src/services/correction/error_fix_status.yaml`
+After every edit to the `messages.yaml` file, you will need to run the following
+to update the generated files:
+```bash
+dart run analyzer/tool/messages/generate.dart
+```
 
-In the status file, the code should have the line
+### Add code to `error_fix_status.yaml`
+
+You also need to manually add the name of the code to the list of codes in the
+file `analysis_server/lib/src/services/correction/error_fix_status.yaml`. The
+code should have the line
 ```yaml
   status: needsEvaluation
 ```
 nested under the name of the code.
 
+At some point, we'll evaluate the diagnostics that are marked as `needsEvaluation`.
+If we can think of a reasonable and useful fix, then we'll change it to `needsFix`
+with a comment indicating what fix we thought of. If we can't think of one, then
+we'll change it to `noFix`. The status is changed to `hasFix` when there's at least
+one fix associated with the diagnostic, which is something we can (and do) verify
+in a test.
+
 ## Write tests
 
 We recommend writing the tests for a diagnostic before writing the code to
@@ -51,6 +63,7 @@
 
 The tests for each diagnostic code (or set of codes that have the same shared
 name) are in a separate file in the directory `analyzer/test/src/diagnostics`.
+
 Looking at the implementation of tests in a few of the other files can help you
 see the basic pattern, but all the tests essentially work by setting up the code
 to be analyzed, then assert that either the expected diagnostic has been
@@ -61,8 +74,148 @@
 ## Report the diagnostic
 
 The last step is to write the code to report the diagnostic. Where that code
-lives depends on the kind of diagnostic you're adding. If you're adding a
-diagnostic that's defined by the language specification (with a severity of
-'error'), then the best place to implement it will usually be in one of the
-`<node class>Resolver` classes. If you're adding a warning, then the class
-`BestPracticesVerifier` is usually the best place for it.
\ No newline at end of file
+lives depends on the kind of diagnostic you're adding.
+
+If you're adding a diagnostic that's defined by the language specification
+(with a severity of 'error'), then the best place to implement it will usually
+be in one of the `<node class>Resolver` classes.
+
+If you're adding a warning, then the class `BestPracticesVerifier` is usually
+the best place for it.
+
+## Document the diagnostic
+
+After the diagnostic has been implemented and committed, documentation for the
+diagnostic needs to be written.
+
+__Note:__ We are in the process of defining a process for this task, so this
+section is currently incomplete. Contact us for details if you want to write the
+documentation yourself. If you don't want to write the documentation then we'll
+write it for you.
+
+Before you start writing documentation we recommend that you look at several of
+the existing examples of documentation to get a feeling for the general writing
+style and format of the docs. Some of this information is also found below. If
+you have questions about style, we follow the general
+[Google style guidelines](https://developers.google.com/style/).
+
+The documentation for the diagnostics that are implemented in the analyzer is in
+the file `analyzer/messages.yaml`. They are under the key `documentation:`, and
+are mostly standard markdown. The differences are described below.
+
+### Template
+
+The good news is that the documentation is highly stylized, so writing it is
+usually fairly easy.
+
+To start writing the documentation, copy the following template. Each section is
+discussed below.
+
+    #### Description
+
+    The analyzer produces this diagnostic when
+
+    #### Example
+
+    The following code produces this diagnostic because :
+
+    ```dart
+    ```
+
+    #### Common fixes
+
+    ```dart
+    ```
+
+### Description
+
+The Description section should start by explaining _when_ the diagnostic will be
+produced. Specifically, that means the conditions that cause the diagnostic to
+be produced. The goal is to help the user understand why the diagnostic is
+appearing in their code, so the explanation needs to cover all of the possible
+reasons.
+
+For example, the diagnostic `invalid_extension_argument_count` describes the
+conditions that cause the diagnostic this way:
+
+> The analyzer produces this diagnostic when an extension override doesn't
+> have exactly one argument.
+
+Unless it's fairly obvious, the description should also explain _why_ the
+condition is being reported. In most cases the reason for the diagnostic will be
+obvious from the description of when it's reported, but sometimes that isn't
+enough.
+
+For example, the user might not be familiar with extension overrides, so the
+explanation above might not be sufficient. By explaining why an override must
+have a single argument we can help the user learn about the feature, so the
+documentation goes on to explain that:
+
+> The argument is the expression used to compute the value of `this` within the
+> extension method, so there must be one argument.
+
+### Examples
+
+The Examples section should show at least one example of code that will produce
+the diagnostic. (If there's only one example, then the title should be singular
+as in the template above, but if there are multiple examples the title should be
+plural.)
+
+The examples should be complete in the sense that the user should be able to
+copy the example, paste it into an empty compilation unit, and see exactly the
+one diagnostic being reported. (One technique we often use for this purpose is
+to define local variables as parameters to a method or function so that the
+`unused_local_variable` diagnostic isn't also reported.)
+
+The examples should be minimal so that users aren't distracted by irrelevant
+details. They should only include code that is required in order to generate
+the diagnostic. They should use simple names, like `A`, `B`, and `C` for
+classes, `M` for mixins, `f` and `g` for functions, and so on. It's better to
+not use names with semantic value.
+
+Each example must have the range of characters that are highlighted by the
+diagnostic enclosed between `[!` and `!]` delimiters. These are used to
+highlight the region on the web page and are also validated by tests.
+
+Every code block must specify a file type, such as `dart` or `yaml`.
+
+The examples occasionally need some additional support, which is provided by
+"directives". The directives must be on the first lines of the code block, and
+have the form `%directiveName=`. There are two directives defined.
+
+The experiments directive (`%experiments=`) specifies a comma-separated list of
+the names of language experiments that are to be enabled when analyzing the
+example. This is necessary when writing documentation for experiments that
+haven't yet shipped. These directives should be removed once the experiment is
+enabled by default.
+
+The uri directive (`%uri=`) specifies the URI for the file containing the code
+block. Without a uri directive the standard uri will be used. This directive is
+necessary for cases when an example needs an auxiliary file to be defined,
+usually so that it can be imported in the example. Code blocks that have a uri
+directive are considered to be auxiliary files, not examples, and aren't
+analyzed or required to have highlight range markers. Auxiliary files exist
+when either an example or a common fix is analyzed.
+
+### Common fixes
+
+The Common fixes section should show examples of the ways to fix the problem
+that are most likely to be applicable. In some cases there's only one likely way
+to fix the problem (like removing the null check operator when the expression
+isn't nullable), but in other cases there might be multiple possible ways of
+fixing the problem.
+
+There should minimally be one fix shown for every action suggested by the
+diagnostic's correction message.
+
+Each fix should use one of the examples as the base and show how the invalid
+code can be changed to apply the described fix. The same example can be used by
+multiple fixes.
+
+Each fix should be introduced by a sentence that explains what change the user
+would make for the fix. Usually the description is written in the form "If
+_these conditions hold_, then _make this change_:" so that users can tell when a
+suggested fix can be applied.
+
+Fixes can't have highlight markers, and are expected to not have any diagnostics
+reported.
diff --git a/analyzer/doc/tutorial/ast.md b/analyzer/doc/tutorial/ast.md
index c3e275c..7471bb2 100644
--- a/analyzer/doc/tutorial/ast.md
+++ b/analyzer/doc/tutorial/ast.md
@@ -54,7 +54,7 @@
 the AST:
 
 ```dart
-void processFile(AnalysisSession session, String path) async {
+Future<void> processFile(AnalysisSession session, String path) async {
   var result = session.getParsedUnit(path);
   if (result is ParsedUnitResult) {
     CompilationUnit unit = result.unit;
@@ -66,7 +66,7 @@
 method to access it:
 
 ```dart
-void processFile(AnalysisSession session, String path) async {
+Future<void> processFile(AnalysisSession session, String path) async {
   var result = await session.getResolvedUnit(path);
   if (result is ResolvedUnitResult) {
     CompilationUnit unit = result.unit;
@@ -102,7 +102,7 @@
           if (classMember.name == null) {
             print('  ${unitMember.name.lexeme}');
           } else {
-            print('  ${unitMember.name.lexeme}.${classMember.name.lexeme}');
+            print('  ${unitMember.name.lexeme}.${classMember.name!.lexeme}');
           }
         }
       }
diff --git a/analyzer/doc/tutorial/element.md b/analyzer/doc/tutorial/element.md
index 912d65b..fe603ea 100644
--- a/analyzer/doc/tutorial/element.md
+++ b/analyzer/doc/tutorial/element.md
@@ -75,11 +75,7 @@
     print(classElement.name);
     for (ConstructorElement constructorElement in classElement.constructors) {
       if (!constructorElement.isSynthetic) {
-        if (constructorElement.name == null) {
-          print('  ${constructorElement.name}');
-        } else {
-          print('  ${classElement.name}.${constructorElement.name}');
-        }
+        print('  ${constructorElement.displayName}');
       }
     }
     for (FieldElement fieldElement in classElement.fields) {
diff --git a/analyzer/doc/tutorial/tutorial.md b/analyzer/doc/tutorial/tutorial.md
index 39cdac3..787fe0f 100644
--- a/analyzer/doc/tutorial/tutorial.md
+++ b/analyzer/doc/tutorial/tutorial.md
@@ -10,19 +10,19 @@
 [Introduction][introduction] -
 What capabilities does the analyzer package support?
 
-[Performing Analysis][analysis]
+[Performing Analysis][analysis] -
 How to set up the objects used to analyze code.
 
-[The Token Model][tokens]
+[The Token Model][tokens] -
 How are tokens represented?
 
-[The AST][ast]
+[The AST][ast] -
 What is an AST?
 
-[The Element Model][element]
+[The Element Model][element] -
 What is the element model?
 
-[The Type Model][type]
+[The Type Model][type] -
 What is the type model?
 
 [analysis]: analysis.md
diff --git a/analyzer/example/ddd01.dart b/analyzer/example/ddd01.dart
index 4c60e3e..8130a93 100644
--- a/analyzer/example/ddd01.dart
+++ b/analyzer/example/ddd01.dart
@@ -1,10 +1,8 @@
 import 'package:analyzer/dart/analysis/results.dart';
-import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
 
 void main() async {
-  var path = '/Users/scheglov/tmp/20221208/issue50660/lib/main.dart';
+  var path = '/Users/scheglov/dart/issue50962/br_table.0.dart';
   var collection = AnalysisContextCollectionImpl(includedPaths: [
     path,
   ]);
@@ -12,10 +10,5 @@
   var unitResult = await analysisContext.currentSession.getResolvedUnit(path);
   unitResult as ResolvedUnitResult;
 
-  unitResult.unit.accept(_Visitor());
-}
-
-class _Visitor extends RecursiveAstVisitor<void> {
-  @override
-  void visitSimpleIdentifier(SimpleIdentifier node) {}
+  // await Future<void>.delayed(const Duration(days: 1));
 }
diff --git a/analyzer/example/ddd02.dart b/analyzer/example/ddd02.dart
new file mode 100644
index 0000000..a3de4ab
--- /dev/null
+++ b/analyzer/example/ddd02.dart
@@ -0,0 +1,62 @@
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/file_system/overlay_file_system.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
+
+void main() async {
+  var resourceProvider = OverlayResourceProvider(
+    PhysicalResourceProvider.INSTANCE,
+  );
+
+  var path = '/Users/scheglov/dart/test/lib/a.dart';
+
+  var buffer = StringBuffer();
+  const classCount = 100 * 1000;
+  for (var i = 0; i < classCount; i++) {
+    buffer.writeln('class A$i {}');
+  }
+  resourceProvider.setOverlay(
+    path,
+    content: buffer.toString(),
+    modificationStamp: 0,
+  );
+
+  var collection = AnalysisContextCollectionImpl(
+    resourceProvider: resourceProvider,
+    includedPaths: [path],
+  );
+  var analysisContext = collection.contextFor(path);
+  var unitResult = analysisContext.currentSession.getParsedUnit(path);
+  unitResult as ParsedUnitResult;
+
+  var classList = unitResult.unit.declarations
+      .whereType<ClassDeclaration>()
+      .toList(growable: false);
+
+  var randomClassList = classList.toList();
+  randomClassList.shuffle();
+
+  for (var i = 0; i < 10; i++) {
+    _iterateClassList(i, 'sequential', classList);
+    _iterateClassList(i, '    random', randomClassList);
+  }
+}
+
+void _iterateClassList(int i, String name, List<ClassDeclaration> classList) {
+  var timer = Stopwatch()..start();
+  var result = 0;
+  for (var i = 0; i < 100; i++) {
+    for (var i = 0; i < classList.length; i++) {
+      var classDeclaration = classList[i];
+      result = (result + classDeclaration.offset) & 0xFFFF;
+      result = (result + classDeclaration.length) & 0xFFFF;
+      result = (result + classDeclaration.name.length) & 0xFFFF;
+    }
+  }
+  timer.stop();
+  print(
+    '[$i][$name][result: $result]'
+    '[time: ${timer.elapsedMilliseconds} ms]',
+  );
+}
diff --git a/analyzer/example/ddd03.dart b/analyzer/example/ddd03.dart
new file mode 100644
index 0000000..f8b3c89
--- /dev/null
+++ b/analyzer/example/ddd03.dart
@@ -0,0 +1,180 @@
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
+import 'package:analyzer/src/dart/analysis/byte_store.dart';
+import 'package:analyzer/src/dart/analysis/file_content_cache.dart';
+import 'package:analyzer/src/dart/analysis/unlinked_unit_store.dart';
+
+void main() async {
+  // var path = '/Users/scheglov/dart/flutter_plugins/packages/camera';
+  var path = '/Users/scheglov/dart/flutter_plugins/packages';
+
+  while (true) {
+    var resourceProvider = PhysicalResourceProvider.INSTANCE;
+    var fileContentCache = FileContentCache(resourceProvider);
+    var unlinkedUnitStore = UnlinkedUnitStoreImpl();
+
+    var collection = AnalysisContextCollectionImpl(
+      byteStore: MemoryByteStore(),
+      resourceProvider: resourceProvider,
+      fileContentCache: fileContentCache,
+      unlinkedUnitStore: unlinkedUnitStore,
+      sdkPath: '/Users/scheglov/Applications/dart-sdk',
+      // performanceLog: PerformanceLog(stdout),
+      includedPaths: [
+        path,
+      ],
+      packagesFile:
+          '/Users/scheglov/dart/flutter_plugins/packages/camera/camera/.dart_tool/package_config.json',
+    );
+
+    // print('[Analysis contexts: ${collection.contexts.length}]');
+
+    var timer = Stopwatch()..start();
+    for (var analysisContext in collection.contexts) {
+      // print(analysisContext.contextRoot.root.path);
+      for (var filePath in analysisContext.contextRoot.analyzedFiles()) {
+        if (filePath.endsWith('.dart')) {
+          // print('  $filePath');
+          var analysisSession = analysisContext.currentSession;
+          await analysisSession.getResolvedUnit(filePath);
+        }
+      }
+    }
+    timer.stop();
+    print('[time: ${timer.elapsedMilliseconds} ms]');
+
+    var profiler = ProcessProfiler.getProfilerForPlatform()!;
+    print((await profiler.getProcessUsage(pid))!.memoryMB);
+  }
+
+  // var analysisContext = collection.contextFor(path);
+  // var unitResult = await analysisContext.currentSession.getResolvedUnit(path);
+  // unitResult as ResolvedUnitResult;
+
+  // await Future<void>.delayed(const Duration(days: 1));
+}
+
+
+/// A class that can return memory and cpu usage information for a given
+/// process.
+abstract class ProcessProfiler {
+  ProcessProfiler._();
+
+  Future<UsageInfo?> getProcessUsage(int processId);
+
+  /// Return a [ProcessProfiler] instance suitable for the current host
+  /// platform. This can return `null` if we're not able to gather memory and
+  /// cpu information for the current platform.
+  static ProcessProfiler? getProfilerForPlatform() {
+    if (Platform.isLinux || Platform.isMacOS) {
+      return _PosixProcessProfiler();
+    }
+
+    if (Platform.isWindows) {
+      return _WindowsProcessProfiler();
+    }
+
+    // Not a supported platform.
+    return null;
+  }
+}
+
+class UsageInfo {
+  /// A number between 0.0 and 100.0 * the number of host CPUs (but typically
+  /// never more than slightly above 100.0).
+  final double? cpuPercentage;
+
+  /// The process memory usage in kilobytes.
+  final int memoryKB;
+
+  UsageInfo(this.cpuPercentage, this.memoryKB);
+
+  double get memoryMB => memoryKB / 1024;
+
+  @override
+  String toString() {
+    if (cpuPercentage != null) {
+      return '$cpuPercentage% ${memoryMB.toStringAsFixed(1)}MB';
+    }
+    return '${memoryMB.toStringAsFixed(1)}MB';
+  }
+}
+
+class _PosixProcessProfiler extends ProcessProfiler {
+  static final RegExp stringSplitRegExp = RegExp(r'\s+');
+
+  _PosixProcessProfiler() : super._();
+
+  @override
+  Future<UsageInfo?> getProcessUsage(int processId) {
+    try {
+      // Execution time is typically 2-4ms.
+      var future =
+      Process.run('ps', ['-o', '%cpu=,rss=', processId.toString()]);
+      return future.then((ProcessResult result) {
+        if (result.exitCode != 0) {
+          return Future.value(null);
+        }
+
+        return Future.value(_parse(result.stdout as String));
+      });
+    } catch (e) {
+      return Future.error(e);
+    }
+  }
+
+  UsageInfo? _parse(String psResults) {
+    try {
+      // "  0.0 378940"
+      var line = psResults.split('\n').first.trim();
+      var values = line.split(stringSplitRegExp);
+      return UsageInfo(double.parse(values[0]), int.parse(values[1]));
+    } catch (e) {
+      return null;
+    }
+  }
+}
+
+class _WindowsProcessProfiler extends ProcessProfiler {
+  _WindowsProcessProfiler() : super._();
+
+  @override
+  Future<UsageInfo?> getProcessUsage(int processId) async {
+    try {
+      var result = await Process.run(
+          'tasklist', ['/FI', 'PID eq $processId', '/NH', '/FO', 'csv']);
+
+      if (result.exitCode != 0) {
+        return Future.value(null);
+      }
+
+      return Future.value(_parse(result.stdout as String));
+    } catch (e) {
+      return Future.error(e);
+    }
+  }
+
+  UsageInfo? _parse(String tasklistResults) {
+    try {
+      var lines = tasklistResults.split(RegExp("\r?\n"));
+      for (var line in lines) {
+        if (line.trim().isEmpty) continue;
+        // Hacky parsing of csv line.
+        var entries = jsonDecode("[$line]") as List;
+        if (entries.length != 5) continue;
+        // E.g. 123,456 K
+        var memory = entries[4] as String;
+        memory = memory.substring(0, memory.indexOf(" "));
+        memory = memory.replaceAll(",", "");
+        memory = memory.replaceAll(".", "");
+        return UsageInfo(null, int.parse(memory));
+      }
+      return null;
+    } catch (e) {
+      return null;
+    }
+  }
+}
diff --git a/analyzer/example/ddd03.exe b/analyzer/example/ddd03.exe
new file mode 100755
index 0000000..c151315
--- /dev/null
+++ b/analyzer/example/ddd03.exe
Binary files differ
diff --git a/analyzer/example/ddd04.dart b/analyzer/example/ddd04.dart
new file mode 100644
index 0000000..0a21f3f
--- /dev/null
+++ b/analyzer/example/ddd04.dart
@@ -0,0 +1,267 @@
+// import 'dart:io' hide BytesBuilder;
+// import 'dart:typed_data';
+//
+// import 'package:analyzer/file_system/physical_file_system.dart';
+// import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
+// import 'package:vm_service/vm_service.dart';
+// import 'package:analyzer/src/dart/analysis/byte_store.dart';
+// import 'package:analyzer/src/dart/analysis/file_content_cache.dart';
+// import 'package:analyzer/src/dart/analysis/unlinked_unit_store.dart';
+//
+// import 'heap/analysis.dart';
+// import 'heap/format.dart';
+// import 'heap/load.dart';
+//
+// /// --observe:5000 --disable-service-auth-codes --pause_isolates_on_unhandled_exceptions=false --pause_isolates_on_exit=false
+// void main() async {
+//   // var path = '/Users/scheglov/dart/rwf-materials';
+//   // var path = '/Users/scheglov/dart/rwf-materials/01-setting-up-your-environment';
+//   var path =
+//       '/Users/scheglov/dart/rwf-materials/01-setting-up-your-environment/projects/starter/packages/component_library';
+//
+//   // var profiler = ProcessProfiler.getProfilerForPlatform()!;
+//   while (true) {
+//     var resourceProvider = PhysicalResourceProvider.INSTANCE;
+//     var fileContentCache = FileContentCache(resourceProvider);
+//     var unlinkedUnitStore = UnlinkedUnitStoreImpl();
+//
+//     var collection = AnalysisContextCollectionImpl(
+//       byteStore: MemoryByteStore(),
+//       resourceProvider: resourceProvider,
+//       fileContentCache: fileContentCache,
+//       unlinkedUnitStore: unlinkedUnitStore,
+//       sdkPath: '/Users/scheglov/Applications/dart-sdk',
+//       // performanceLog: PerformanceLog(stdout),
+//       includedPaths: [
+//         path,
+//       ],
+//       // packagesFile:
+//       //     '/Users/scheglov/dart/rwf-materials/15-automating-test-executions-and-build-distributions/projects/final/.dart_tool/package_config.json',
+//     );
+//
+//     print('[Analysis contexts: ${collection.contexts.length}]');
+//
+//     // double maxMemory = 0;
+//     var timer = Stopwatch()..start();
+//     for (var analysisContext in collection.contexts) {
+//       // print(analysisContext.contextRoot.root.path);
+//       var analyzedFiles = analysisContext.contextRoot.analyzedFiles().toList();
+//       for (var filePath in analyzedFiles) {
+//         if (filePath.endsWith('.dart')) {
+//           // print('  $filePath');
+//           var analysisSession = analysisContext.currentSession;
+//           await analysisSession.getResolvedUnit(filePath);
+//
+//           // collectAllGarbage();
+//
+//           // var usageInfo = await profiler.getProcessUsage(pid);
+//           // var memoryMB = usageInfo!.memoryMB;
+//           // if (memoryMB > maxMemory) {
+//           //   maxMemory = memoryMB;
+//           //   print('  heap: $maxMemory MB');
+//           //   // if (maxMemory > 2000) {
+//           //   //   writeHeapSnapshotToFile(
+//           //   //     '/Users/scheglov/dart/rwf-materials/2000.heap',
+//           //   //   );
+//           //   //   // await Future<void>.delayed(const Duration(seconds: 10));
+//           //   //   exit(0);
+//           //   // }
+//           // }
+//           // maxMemory = max(maxMemory, usageInfo!.memoryMB);
+//         }
+//       }
+//     }
+//     timer.stop();
+//     print('[time: ${timer.elapsedMilliseconds} ms]');
+//
+//     {
+//       var timer = Stopwatch()..start();
+//       var chunks = await loadFromUri(Uri.parse('http://127.0.0.1:5000'));
+//       // final length = chunks
+//       //     .map((e) => e.lengthInBytes)
+//       //     .fold<int>(0, (prev, e) => prev + e);
+//       // print(
+//       //   '  [${timer.elapsedMilliseconds} ms] '
+//       //   'Downloaded heap snapshot, ${length / 1024 / 1024} MB.',
+//       // );
+//
+//       if (0 == 1) {
+//         final bytesBuilder = BytesBuilder();
+//         for (final chunk in chunks) {
+//           bytesBuilder.add(
+//             chunk.buffer.asUint8List(
+//               chunk.offsetInBytes,
+//               chunk.lengthInBytes,
+//             ),
+//           );
+//         }
+//         final bytes = bytesBuilder.toBytes();
+//         final path = '/Users/scheglov/tmp/01.heap_snapshot';
+//         File(path).writeAsBytesSync(bytes);
+//         final lengthStr = (bytes.length / 1024 / 1024).toStringAsFixed(2);
+//         print('Stored $lengthStr MB into $path');
+//       }
+//
+//       final graph = HeapSnapshotGraph.fromChunks(chunks);
+//       print('  [${timer.elapsedMilliseconds} ms] Created HeapSnapshotGraph.');
+//       print('  externalSize: ${graph.externalSize}');
+//       print('  shallowSize: ${graph.shallowSize}');
+//       print('  Objects: ${graph.objects.length}');
+//
+//       final analysis = Analysis(graph);
+//       print('  [${timer.elapsedMilliseconds} ms] Created Analysis.');
+//
+//       {
+//         print('All objects.');
+//         final objects = analysis.reachableObjects;
+//         final stats = analysis.generateObjectStats(objects);
+//         print(formatHeapStats(stats, maxLines: 20));
+//         print('');
+//       }
+//
+//       {
+//         print('FileState(s)');
+//         var fileStateList = analysis.filter(
+//           analysis.reachableObjects,
+//               (object) {
+//             return object.klass.name == 'FileState';
+//           },
+//         );
+//         analysis.printObjectStats(fileStateList);
+//         print('');
+//         final allObjects = analysis.transitiveGraph(fileStateList);
+//         analysis.printObjectStats(allObjects);
+//         print('');
+//       }
+//
+//       if (0 == 1) {
+//         print('Instances of: _SimpleUri');
+//         final uriList = analysis.filterByClassPatterns(
+//           analysis.reachableObjects,
+//           ['_SimpleUri'],
+//         );
+//         final stats = analysis.generateObjectStats(uriList);
+//         print(formatHeapStats(stats, maxLines: 20));
+//         print('');
+//
+//         final uriStringList = analysis.findReferences(uriList, [':_uri']);
+//
+//         // TODO(scheglov) Restore
+//         final uniqueUriStrSet = Set<String>();
+//         for (final objectId in uriStringList) {
+//           var object = graph.objects[objectId];
+//           var uriStr = object.data as String;
+//           if (!uniqueUriStrSet.add(uriStr)) {
+//             throw StateError('Duplicate URI: $uriStr');
+//           }
+//         }
+//
+//         final dstats = analysis.generateDataStats(uriStringList);
+//         print(formatDataStats(dstats, maxLines: 20));
+//       }
+//
+//       if (0 == 0) {
+//         print('Instances of: LibraryElementImpl');
+//         final uriList = analysis.filterByClassPatterns(
+//           analysis.reachableObjects,
+//           ['LibraryElementImpl'],
+//         );
+//         final stats = analysis.generateObjectStats(uriList);
+//         print(formatHeapStats(stats, maxLines: 20));
+//         print('');
+//       }
+//
+//       if (0 == 0) {
+//         print('Instances of: _GrowableList');
+//         final objectList = analysis.filter(analysis.reachableObjects, (object) {
+//           return object.klass.libraryUri == Uri.parse('dart:core') &&
+//               object.klass.name == '_GrowableList';
+//           // return analysis.variableLengthOf(object) == 0;
+//         });
+//
+//         // final objectList = analysis.filterByClassPatterns(
+//         //   analysis.reachableObjects,
+//         //   ['_GrowableList'],
+//         // );
+//         final stats = analysis.generateObjectStats(objectList);
+//         print(formatHeapStats(stats, maxLines: 20));
+//         print('');
+//
+//         const maxEntries = 10;
+//         final paths = analysis.retainingPathsOf(objectList, 10);
+//         for (int i = 0; i < paths.length; ++i) {
+//           if (maxEntries != -1 && i >= maxEntries) break;
+//           final path = paths[i];
+//           print('There are ${path.count} retaining paths of');
+//           print(formatRetainingPath(analysis.graph, paths[i]));
+//           print('');
+//         }
+//
+//         {
+//           print('Instances of empty: _GrowableList');
+//           final emptyList = analysis.filter(objectList, (object) {
+//             return analysis.variableLengthOf(object) == 0;
+//           });
+//           final stats = analysis.generateObjectStats(emptyList);
+//           print(formatHeapStats(stats, maxLines: 20));
+//           print('');
+//
+//           // final paths = analysis.retainingPathsOf(emptyList, 10);
+//           // for (int i = 0; i < paths.length; ++i) {
+//           //   if (maxEntries != -1 && i >= maxEntries) break;
+//           //   final path = paths[i];
+//           //   print('There are ${path.count} retaining paths of');
+//           //   print(formatRetainingPath(analysis.graph, paths[i]));
+//           //   print('');
+//           // }
+//         }
+//         // final dstats = analysis.generateDataStats(uriStringList);
+//         // print(formatDataStats(dstats, maxLines: 20));
+//       }
+//     }
+//
+//     break;
+//
+//     // writeHeapSnapshotToFile(
+//     //   '/Users/scheglov/dart/rwf-materials/2001.heap',
+//     // );
+//   }
+//
+//   // var analysisContext = collection.contextFor(path);
+//   // var unitResult = await analysisContext.currentSession.getResolvedUnit(path);
+//   // unitResult as ResolvedUnitResult;
+//
+//   // await Future<void>.delayed(const Duration(days: 1));
+// }
+//
+// extension on Analysis {
+//   void printObjectStats(IntSet objectIds) {
+//     final stats = generateObjectStats(objectIds);
+//     print(formatHeapStats(stats, maxLines: 20));
+//     print('');
+//   }
+//
+//   void printRetainers(
+//       IntSet objectIds, {
+//         int maxEntries = 3,
+//       }) {
+//     final paths = retainingPathsOf(objectIds, 20);
+//     for (int i = 0; i < paths.length; ++i) {
+//       if (i >= maxEntries) break;
+//       final path = paths[i];
+//       print('There are ${path.count} retaining paths of');
+//       print(formatRetainingPath(graph, paths[i]));
+//       print('');
+//     }
+//   }
+//
+//   IntSet filterByClass(
+//       IntSet objectIds, {
+//         required Uri libraryUri,
+//         required String name,
+//       }) {
+//     return filter(reachableObjects, (object) {
+//       return object.klass.libraryUri == libraryUri && object.klass.name == name;
+//     });
+//   }
+// }
diff --git a/analyzer/example/ddd05.dart b/analyzer/example/ddd05.dart
new file mode 100644
index 0000000..fcdc8cd
--- /dev/null
+++ b/analyzer/example/ddd05.dart
@@ -0,0 +1,150 @@
+// import 'dart:async';
+// import 'dart:io' as io;
+//
+// import 'package:analyzer/file_system/physical_file_system.dart';
+// import 'package:analyzer/src/context/packages.dart';
+// import 'package:analyzer/src/dart/sdk/sdk.dart';
+// import 'package:analyzer/src/generated/utilities_dart.dart';
+// import 'package:analyzer/src/util/sdk.dart';
+// import 'package:analyzer/src/workspace/blaze.dart';
+// import 'package:analyzer/src/workspace/pub.dart';
+// import 'package:analyzer/src/workspace/workspace.dart';
+//
+// void main() async {
+//   final resourceProvider = PhysicalResourceProvider.INSTANCE;
+//
+//   final useGoogle3 = 1 == 1;
+//   Workspace workspace;
+//   String startPath;
+//   if (!useGoogle3) {
+//     final workspacePath =
+//         '/Users/scheglov/Source/Dart/sdk.git/sdk/pkg/analyzer';
+//     final packages = findPackagesFrom(
+//       resourceProvider,
+//       resourceProvider.getFolder(workspacePath),
+//     );
+//     workspace = PubWorkspace.find(
+//       resourceProvider,
+//       packages,
+//       workspacePath,
+//     )!;
+//     const pkgPath = '/Users/scheglov/Source/Dart/sdk.git/sdk/pkg';
+//     startPath = '$pkgPath/analyzer/example/ddd05.dart';
+//   } else {
+//     const workspacePath = '/google/src/cloud/scheglov/my-20230122/google3';
+//     workspace = BlazeWorkspace.forBuild(
+//       root: resourceProvider.getFolder(workspacePath),
+//     );
+//     const startPackagePath = '$workspacePath/nbu/paisa/gpay/app';
+//     startPath = '$startPackagePath/lib/src/programmatic_main.dart';
+//   }
+//
+//   final sdkPath = getSdkPath();
+//   final sourceFactory = workspace.createSourceFactory(
+//     FolderBasedDartSdk(
+//       resourceProvider,
+//       resourceProvider.getFolder(sdkPath),
+//     ),
+//     null,
+//   );
+//
+//   final readPathSet = <String>{};
+//
+//   final toReadPathSet = <String>{};
+//   final toReadPathSetController = StreamController<void>();
+//
+//   final importRegExp = RegExp(r'''import\s+'(.+)'(\s+as\s+\w+)?\s*;''');
+//   final exportRegExp = RegExp(r'''export\s+'(.+)'\s*;''');
+//   final partRegExp = RegExp(r'''part\s+'(.+)'\s*;''');
+//
+//   void readOne(String path, Uri uri) {
+//     if (readPathSet.add(path)) {
+//       print(path);
+//       toReadPathSet.add(path);
+//       io.File(path).readAsString().then(
+//         (content) {
+//           final allMatches = [
+//             ...importRegExp.allMatches(content),
+//             ...exportRegExp.allMatches(content),
+//             ...partRegExp.allMatches(content),
+//           ];
+//           for (final match in allMatches) {
+//             final uriStr = match.group(1)!;
+//             print('  ${match.group(0)}');
+//             print('  uriStr: $uriStr');
+//             final uri2 = Uri.parse(uriStr);
+//             final uri3 = resolveRelativeUri(uri, uri2);
+//             print('    uri3: $uri3');
+//             final source = sourceFactory.forUri2(uri3);
+//             print('    source: $source');
+//             if (source != null) {
+//               readOne(source.fullName, uri3);
+//             } else {
+//               print('    !!!! no Source');
+//             }
+//           }
+//         },
+//         onError: (exception, stackTrace) {},
+//       ).whenComplete(() {
+//         toReadPathSet.remove(path);
+//         toReadPathSetController.sink.add(null);
+//       });
+//     }
+//   }
+//
+//   void readOne2(String path, Uri uri, {int level = 0}) {
+//     if (readPathSet.add(path)) {
+//       print(path);
+//       toReadPathSet.add(path);
+//       String? content;
+//       try {
+//         content = io.File(path).readAsStringSync();
+//       } catch (_) {
+//         print('  !!!! cannot read');
+//       }
+//       //print(content);
+//       if (content != null) {
+//         final allMatches = [
+//           ...importRegExp.allMatches(content),
+//           ...exportRegExp.allMatches(content),
+//           ...partRegExp.allMatches(content),
+//         ];
+//
+//         for (final match in allMatches) {
+//           final uriStr = match.group(1)!;
+//           print('  ${match.group(0)}');
+//           print('  uriStr: $uriStr');
+//           final uri2 = Uri.parse(uriStr);
+//           final uri3 = resolveRelativeUri(uri, uri2);
+//           print('    uri3: $uri3');
+//           final source = sourceFactory.forUri2(uri3);
+//           print('    source: $source');
+//           if (source != null) {
+//             readOne2(source.fullName, uri3, level: level + 1);
+//           } else {
+//             print('    !!!! no Source');
+//           }
+//         }
+//       }
+//       toReadPathSet.remove(path);
+//       if (level == 0) {
+//         toReadPathSetController.sink.add(null);
+//       }
+//     }
+//   }
+//
+//   final startUri = sourceFactory.pathToUri(startPath)!;
+//   print('startPath: $startPath');
+//   print('startUri: $startUri');
+//
+//   final timer = Stopwatch()..start();
+//   readOne(startPath, startUri);
+//
+//   toReadPathSetController.stream.listen((_) {
+//     if (toReadPathSet.isEmpty) {
+//       timer.stop();
+//       print('Time: ${timer.elapsedMilliseconds}');
+//       print('Files: ${readPathSet.length}');
+//     }
+//   });
+// }
diff --git a/analyzer/example/ddd06.dart b/analyzer/example/ddd06.dart
new file mode 100644
index 0000000..9abfec4
--- /dev/null
+++ b/analyzer/example/ddd06.dart
@@ -0,0 +1,365 @@
+// import 'dart:io' as io;
+// import 'dart:isolate';
+//
+// import 'package:vm_service/vm_service.dart';
+//
+// import 'heap/analysis.dart';
+// import 'heap/format.dart';
+//
+// void main() async {
+//   const tmpPath = '/Users/scheglov/tmp';
+//   // const fileName = '20230203/cm_inf_11.heap_snapshot';
+//   // const fileName = '20230203/cm_100_11.heap_snapshot';
+//   const fileName = '20230203/b267486151_2_1.heap_snapshot';
+//   final path = '$tmpPath/cider-heap/$fileName';
+//
+//   final bytes = io.File(path).readAsBytesSync();
+//   final graph = HeapSnapshotGraph.fromChunks([bytes.buffer.asByteData()]);
+//
+//   print('Graph');
+//   print('  capacity: ${formatBytes(graph.capacity)}');
+//   print('  shallowSize: ${formatBytes(graph.shallowSize)}');
+//   print('  externalSize: ${formatBytes(graph.externalSize)}');
+//   print('');
+//
+//   final analysis = Analysis(graph);
+//
+//   {
+//     print('All objects: with garbage');
+//     final objects = graph.objects.map((e) => e.oid).toSet();
+//     final stats = analysis.generateObjectStats(objects);
+//     print(formatHeapStats(stats, maxLines: 20));
+//     print('');
+//   }
+//
+//   {
+//     print('All objects: live');
+//     final objects = analysis.reachableObjects;
+//     final stats = analysis.generateObjectStats(objects);
+//     print(formatHeapStats(stats, maxLines: 20));
+//     print('');
+//   }
+//
+//   if (1 == 1) {
+//     print('_Uint8List(s)');
+//     var libraryElements = analysis.filter(
+//       analysis.reachableObjects,
+//       (object) {
+//         return object.klass.name == '_Uint8List';
+//       },
+//     );
+//     analysis.printObjectStats(libraryElements);
+//     print('');
+//     // final allObjects = analysis.transitiveGraph(libraryElements);
+//     // analysis.printObjectStats(allObjects);
+//     // print('');
+//     // analysis.printRetainers(libraryElements, maxEntries: 3);
+//     // print('');
+//   }
+//
+//   if (1 == 0) {
+//     print('_StringCanonicalizer(s)');
+//     var libraryElements = analysis.filter(
+//       analysis.reachableObjects,
+//       (object) {
+//         return object.klass.name == '_StringCanonicalizer';
+//       },
+//     );
+//     analysis.printObjectStats(libraryElements);
+//     print('');
+//     final allObjects = analysis.transitiveGraph(libraryElements);
+//     analysis.printObjectStats(allObjects);
+//     print('');
+//     // analysis.printRetainers(libraryElements, maxEntries: 3);
+//     // print('');
+//   }
+//
+//   if (1 == 0) {
+//     print('View(s)');
+//     var libraryElements = analysis.filter(
+//       analysis.reachableObjects,
+//       (object) {
+//         return object.klass.name == 'View';
+//       },
+//     );
+//     analysis.printObjectStats(libraryElements);
+//     print('');
+//     final allObjects = analysis.transitiveGraph(libraryElements);
+//     analysis.printObjectStats(allObjects);
+//     print('');
+//     // analysis.printRetainers(libraryElements, maxEntries: 3);
+//     // print('');
+//   }
+//
+//   if (1 == 0) {
+//     print('CiderResourceProvider(s)');
+//     var libraryElements = analysis.filter(
+//       analysis.reachableObjects,
+//       (object) {
+//         return object.klass.name == 'CiderResourceProvider';
+//       },
+//     );
+//     analysis.printObjectStats(libraryElements);
+//     print('');
+//     final allObjects = analysis.transitiveGraph(libraryElements);
+//     analysis.printObjectStats(allObjects);
+//     print('');
+//     // analysis.printRetainers(libraryElements, maxEntries: 3);
+//     // print('');
+//   }
+//
+//   if (1 == 0) {
+//     print('_OneByteString(s)');
+//     var libraryElements = analysis.filter(
+//       analysis.reachableObjects,
+//       (object) {
+//         return object.klass.name == '_OneByteString';
+//       },
+//     );
+//     analysis.printObjectStats(libraryElements);
+//     print('');
+//     // final allObjects = analysis.transitiveGraph(libraryElements);
+//     // analysis.printObjectStats(allObjects);
+//     // print('');
+//     analysis.printRetainers(libraryElements, maxEntries: 5);
+//     print('');
+//   }
+//
+//   if (1 == 0) {
+//     print('_SimpleUri(s)');
+//     var libraryElements = analysis.filter(
+//       analysis.reachableObjects,
+//       (object) {
+//         return object.klass.name == '_SimpleUri';
+//       },
+//     );
+//     analysis.printObjectStats(libraryElements);
+//     print('');
+//     // final allObjects = analysis.transitiveGraph(libraryElements);
+//     // analysis.printObjectStats(allObjects);
+//     // print('');
+//     analysis.printRetainers(libraryElements, maxEntries: 3);
+//     print('');
+//   }
+//
+//   if (1 == 0) {
+//     print('_List(s)');
+//     var libraryElements = analysis.filter(
+//       analysis.reachableObjects,
+//       (object) {
+//         return object.klass.name == '_List';
+//       },
+//     );
+//     analysis.printObjectStats(libraryElements);
+//     print('');
+//     // final allObjects = analysis.transitiveGraph(libraryElements);
+//     // analysis.printObjectStats(allObjects);
+//     // print('');
+//     analysis.printRetainers(libraryElements, maxEntries: 10);
+//     print('');
+//   }
+//
+//   if (1 == 1) {
+//     print('LibraryElementImpl(s)');
+//     var libraryElements = analysis.filter(
+//       analysis.reachableObjects,
+//       (object) {
+//         return object.klass.name == 'LibraryElementImpl';
+//       },
+//     );
+//     analysis.printObjectStats(libraryElements);
+//     print('');
+//     final allObjects = analysis.transitiveGraph(libraryElements);
+//     analysis.printObjectStats(allObjects);
+//     print('');
+//     analysis.printRetainers(libraryElements, maxEntries: 3);
+//     print('');
+//   }
+//
+//   if (1 == 0) {
+//     print('FinalizerEntry(s)');
+//     var libraryElements = analysis.filter(
+//       analysis.reachableObjects,
+//       (object) {
+//         return object.klass.name == 'FinalizerEntry';
+//       },
+//     );
+//     analysis.printObjectStats(libraryElements);
+//     print('');
+//     final allObjects = analysis.transitiveGraph(libraryElements);
+//     analysis.printObjectStats(allObjects);
+//     print('');
+//     analysis.printRetainers(libraryElements, maxEntries: 3);
+//     print('');
+//   }
+//
+//   if (1 == 0) {
+//     print('CiderIsolateByteStore(s)');
+//     var fileStateList = analysis.filter(
+//       analysis.reachableObjects,
+//       (object) {
+//         return object.klass.name == 'CiderIsolateByteStore';
+//       },
+//     );
+//     analysis.printObjectStats(fileStateList);
+//     print('');
+//     final allObjects = analysis.transitiveGraph(fileStateList);
+//     analysis.printObjectStats(allObjects);
+//     print('');
+//   }
+//
+//   if (1 == 1) {
+//     print('FileState(s)');
+//     var fileStateList = analysis.filter(
+//       analysis.reachableObjects,
+//       (object) {
+//         return object.klass.name == 'FileState';
+//       },
+//     );
+//     analysis.printObjectStats(fileStateList);
+//     print('');
+//     final allObjects = analysis.transitiveGraph(fileStateList);
+//     analysis.printObjectStats(allObjects);
+//     print('');
+//     // analysis.printRetainers(fileStateList, maxEntries: 3);
+//     // print('');
+//     // if (1 == 1) {
+//     //   print('FileState(s) :: UnlinkedUnit(s)');
+//     //   var libraryElements = analysis.filter(
+//     //     allObjects,
+//     //     (object) {
+//     //       return object.klass.name == 'UnlinkedUnit';
+//     //     },
+//     //   );
+//     //   analysis.printObjectStats(libraryElements);
+//     //   print('');
+//     //   final allObjects2 = analysis.transitiveGraph(libraryElements);
+//     //   analysis.printObjectStats(allObjects2);
+//     //   print('');
+//     //   // analysis.printRetainers(libraryElements, maxEntries: 5);
+//     //   // print('');
+//     // }
+//     // if (1 == 0) {
+//     //   print('FileState(s) :: _Set(s)');
+//     //   var setObjects = analysis.filter(
+//     //     allObjects,
+//     //     (object) {
+//     //       return object.klass.name == '_Set';
+//     //     },
+//     //   );
+//     //   analysis.printObjectStats(setObjects);
+//     //   print('');
+//     //   final allObjects2 = analysis.transitiveGraph(
+//     //     setObjects,
+//     //     analysis.parseTraverseFilter(['^FileState']),
+//     //   );
+//     //   analysis.printObjectStats(allObjects2);
+//     //   print('');
+//     //   // analysis.printRetainers(libraryElements, maxEntries: 5);
+//     //   // print('');
+//     // }
+//   }
+//
+//   if (1 == 1) {
+//     final fileResolverList = analysis.filter(
+//       analysis.reachableObjects,
+//       (object) {
+//         return object.klass.name == 'FileResolver';
+//       },
+//     );
+//     analysis.printObjectStats(fileResolverList);
+//
+//     for (final fileResolver in fileResolverList) {
+//       print('');
+//       print('');
+//       print('FileResolver $fileResolver');
+//       print('');
+//
+//       var information = analysis.examine2(fileResolver, maxLevel: 8);
+//       print(information);
+//
+//       print('All objects.');
+//       final allObjects = analysis.transitiveGraph({fileResolver});
+//       analysis.printObjectStats(allObjects);
+//       print('');
+//
+//       if (1 == 0) {
+//         print('FileResolver :: LibraryElementImpl(s)');
+//         final libraryElements = analysis.filter(
+//           allObjects,
+//           (o) => o.klass.name == 'LibraryElementImpl',
+//         );
+//         analysis.printObjectStats(libraryElements);
+//         print('');
+//
+//         analysis.printRetainers(libraryElements);
+//       }
+//
+//       if (1 == 0) {
+//         print('FileResolver :: _List(s)');
+//         var listList = analysis.filter(
+//           allObjects,
+//           (object) {
+//             return object.klass.name == '_List';
+//           },
+//         );
+//         analysis.printObjectStats(listList);
+//         print('');
+//         // final allObjects = analysis.transitiveGraph(byteListList);
+//         // analysis.printObjectStats(allObjects);
+//         // print('');
+//         analysis.printRetainers(listList, maxEntries: 3);
+//         print('');
+//       }
+//
+//       if (1 == 1) {
+//         print('FileResolver :: _Uint8List(s)');
+//         var listList = analysis.filter(
+//           allObjects,
+//           (object) {
+//             return object.klass.name == '_Uint8List';
+//           },
+//         );
+//         analysis.printObjectStats(listList);
+//         print('');
+//         // final allObjects = analysis.transitiveGraph(byteListList);
+//         // analysis.printObjectStats(allObjects);
+//         // print('');
+//         analysis.printRetainers(listList, maxEntries: 3);
+//         print('');
+//       }
+//     }
+//   }
+// }
+//
+// extension on Analysis {
+//   void printObjectStats(IntSet objectIds) {
+//     final stats = generateObjectStats(objectIds);
+//     print(formatHeapStats(stats, maxLines: 20));
+//     print('');
+//   }
+//
+//   void printRetainers(
+//     IntSet objectIds, {
+//     int maxEntries = 3,
+//   }) {
+//     final paths = retainingPathsOf(objectIds, 20);
+//     for (int i = 0; i < paths.length; ++i) {
+//       if (i >= maxEntries) break;
+//       final path = paths[i];
+//       print('There are ${path.count} retaining paths of');
+//       print(formatRetainingPath(graph, paths[i]));
+//       print('');
+//     }
+//   }
+//
+//   IntSet filterByClass(
+//     IntSet objectIds, {
+//     required Uri libraryUri,
+//     required String name,
+//   }) {
+//     return filter(reachableObjects, (object) {
+//       return object.klass.libraryUri == libraryUri && object.klass.name == name;
+//     });
+//   }
+// }
diff --git a/analyzer/example/heap/analysis.dart b/analyzer/example/heap/analysis.dart
new file mode 100644
index 0000000..270dbc7
--- /dev/null
+++ b/analyzer/example/heap/analysis.dart
@@ -0,0 +1,1045 @@
+// // 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:typed_data';
+//
+// import 'package:vm_service/vm_service.dart';
+//
+// import 'format.dart';
+// import 'intset.dart';
+// export 'intset.dart';
+//
+// const int _invalidIdx = 0;
+// const int _rootObjectIdx = 1;
+//
+// class Analysis {
+//   final HeapSnapshotGraph graph;
+//
+//   late final reachableObjects = transitiveGraph(roots);
+//
+//   late final Uint32List _retainers = _calculateRetainers();
+//
+//   late final _oneByteStringCid = _findClassId('_OneByteString');
+//   late final _twoByteStringCid = _findClassId('_TwoByteString');
+//   late final _nonGrowableListCid = _findClassId('_List');
+//   late final _immutableListCid = _findClassId('_ImmutableList');
+//   late final _weakPropertyCid = _findClassId('_WeakProperty');
+//   late final _weakReferenceCid = _findClassId('_WeakReference');
+//   late final _patchClassCid = _findClassId('PatchClass');
+//   late final _finalizerEntryCid = _findClassId('FinalizerEntry');
+//
+//   late final _weakPropertyKeyIdx = _findFieldIndex(_weakPropertyCid, 'key_');
+//   late final _weakPropertyValueIdx =
+//       _findFieldIndex(_weakPropertyCid, 'value_');
+//
+//   late final _finalizerEntryDetachIdx =
+//       _findFieldIndex(_finalizerEntryCid, 'detach_');
+//   late final _finalizerEntryValueIdx =
+//       _findFieldIndex(_finalizerEntryCid, 'value_');
+//
+//   late final _Arch _arch = (() {
+//     // We want to figure out the architecture this heapsnapshot was made from
+//     // without it being directly included in the snapshot.
+//     // In order to distinguish 32-bit/64-bit/64-bit-compressed we need
+//     //   - an object whose shallowSize will be different for all 3 architectures
+//     //   - have an actual object in the heap snapshot
+//     // -> PatchClass seems to satisfy this.
+//     final size = graph.objects
+//         .firstWhere(
+//             (obj) => obj.classId == _patchClassCid && obj.shallowSize != 0)
+//         .shallowSize;
+//
+//     switch (size) {
+//       case 24:
+//         return _Arch.arch32;
+//       case 32:
+//         return _Arch.arch64c;
+//       case 48:
+//         return _Arch.arch64;
+//       default:
+//         throw 'Unexpected size of patch class: $size.';
+//     }
+//   })();
+//
+//   late final int _headerSize = _arch != _Arch.arch32 ? 8 : 4;
+//   late final int _wordSize = _arch == _Arch.arch64 ? 8 : 4;
+//
+//   Analysis(this.graph);
+//
+//   /// The roots from which alive data can be discovered.
+//   final IntSet roots = IntSet()..add(_rootObjectIdx);
+//
+//   /// Calculates retaining paths for all objects in [objs].
+//   ///
+//   /// All retaining paths will have the object itself plus at most [depth]
+//   /// retainers in it.
+//   List<DedupedUint32List> retainingPathsOf(IntSet objs, int depth) {
+//     final paths = <DedupedUint32List, int>{};
+//     for (var oId in objs) {
+//       final rpath = _retainingPathOf(oId, depth);
+//       final old = paths[rpath];
+//       paths[rpath] = (old == null) ? 1 : old + 1;
+//     }
+//     paths.forEach((path, count) {
+//       path.count = count;
+//     });
+//     return paths.keys.toList()..sort((a, b) => paths[b]! - paths[a]!);
+//   }
+//
+//   /// Returns information about a specific object.
+//   ObjectInformation examine(int oId) {
+//     String stringifyValue(int valueId) {
+//       if (valueId == _invalidIdx) return 'int/double/simd';
+//
+//       final object = graph.objects[valueId];
+//       final cid = object.classId;
+//       if (cid == _oneByteStringCid || cid == _twoByteStringCid) {
+//         return '"${truncateString(object.data as String)}"';
+//       }
+//
+//       final valueClass = graph.classes[cid];
+//       return '${valueClass.name}@${valueId} (${valueClass.libraryUri})';
+//     }
+//
+//     final object = graph.objects[oId];
+//     final cid = object.classId;
+//     final klass = graph.classes[cid];
+//     final fs = klass.fields.toList()..sort((a, b) => a.index - b.index);
+//     final fieldValues = <String, String>{};
+//     if (cid == _oneByteStringCid || cid == _twoByteStringCid) {
+//       fieldValues['data'] = stringifyValue(oId);
+//     } else {
+//       int maxFieldIndex = -1;
+//       for (final field in fs) {
+//         final valueId = object.references[field.index];
+//         fieldValues[field.name] = stringifyValue(valueId);
+//         if (field.index > maxFieldIndex) {
+//           maxFieldIndex = field.index;
+//         }
+//       }
+//
+//       if (cid == _immutableListCid || cid == _nonGrowableListCid) {
+//         final refs = object.references;
+//         int len = refs.length - (maxFieldIndex + 1);
+//         if (len < 10) {
+//           for (int i = 0; i < len; ++i) {
+//             fieldValues['[$i]'] = stringifyValue(refs[1 + maxFieldIndex + i]);
+//           }
+//         } else {
+//           for (int i = 0; i < 4; ++i) {
+//             fieldValues['[$i]'] = stringifyValue(refs[1 + maxFieldIndex + i]);
+//           }
+//           fieldValues['[...]'] = '';
+//           for (int i = len - 4; i < len; ++i) {
+//             fieldValues['[$i]'] = stringifyValue(refs[1 + maxFieldIndex + i]);
+//           }
+//         }
+//       }
+//     }
+//     return ObjectInformation(
+//         klass.name, klass.libraryUri.toString(), fieldValues);
+//   }
+//
+//   /// Returns information about a specific object.
+//   ObjectInformation examine2(
+//     int oId, {
+//     int maxLevel = 0,
+//     int level = 0,
+//   }) {
+//     Object stringifyValue(int valueId) {
+//       if (valueId == _invalidIdx) {
+//         return 'int/double/simd';
+//       }
+//
+//       if (level < maxLevel) {
+//         return examine2(valueId, maxLevel: maxLevel, level: level + 1);
+//       }
+//
+//       final object = graph.objects[valueId];
+//       final cid = object.classId;
+//       if (cid == _oneByteStringCid || cid == _twoByteStringCid) {
+//         return '"${truncateString(object.data as String)}"';
+//       }
+//
+//       final valueClass = graph.classes[cid];
+//       return '${valueClass.name}@${valueId} (${valueClass.libraryUri})';
+//     }
+//
+//     final object = graph.objects[oId];
+//     final cid = object.classId;
+//     final klass = graph.classes[cid];
+//     final fs = klass.fields.toList()..sort((a, b) => a.index - b.index);
+//     final fieldValues = <String, Object>{};
+//     if (cid == _oneByteStringCid || cid == _twoByteStringCid) {
+//       fieldValues['data'] = stringifyValue(oId);
+//     } else {
+//       int maxFieldIndex = -1;
+//       for (final field in fs) {
+//         final valueId = object.references[field.index];
+//         fieldValues[field.name] = stringifyValue(valueId);
+//         if (field.index > maxFieldIndex) {
+//           maxFieldIndex = field.index;
+//         }
+//       }
+//
+//       if (cid == _immutableListCid || cid == _nonGrowableListCid) {
+//         final refs = object.references;
+//         int len = refs.length - (maxFieldIndex + 1);
+//         if (len < 10) {
+//           for (int i = 0; i < len; ++i) {
+//             fieldValues['[$i]'] = stringifyValue(refs[1 + maxFieldIndex + i]);
+//           }
+//         } else {
+//           for (int i = 0; i < 4; ++i) {
+//             fieldValues['[$i]'] = stringifyValue(refs[1 + maxFieldIndex + i]);
+//           }
+//           fieldValues['[...]'] = '';
+//           for (int i = len - 4; i < len; ++i) {
+//             fieldValues['[$i]'] = stringifyValue(refs[1 + maxFieldIndex + i]);
+//           }
+//         }
+//       }
+//     }
+//     return ObjectInformation(
+//         klass.name, klass.libraryUri.toString(), fieldValues);
+//   }
+//
+//   /// Generates statistics about the given set of [objects].
+//   ///
+//   /// The classes are sored by sum of shallow-size of objects of a class if
+//   /// [sortBySize] is true and by number of objects per-class otherwise.
+//   HeapStats generateObjectStats(IntSet objects, {bool sortBySize = true}) {
+//     final graphObjects = graph.objects;
+//     final numCids = graph.classes.length;
+//
+//     final counts = Int32List(numCids);
+//     final sizes = Int32List(numCids);
+//     for (final objectId in objects) {
+//       final obj = graphObjects[objectId];
+//       final cid = obj.classId;
+//       counts[cid]++;
+//       sizes[cid] += obj.shallowSize;
+//     }
+//
+//     final classes = graph.classes.where((c) => counts[c.classId] > 0).toList();
+//     if (sortBySize) {
+//       classes.sort((a, b) {
+//         var diff = sizes[b.classId] - sizes[a.classId];
+//         if (diff != 0) return diff;
+//         diff = counts[b.classId] - counts[a.classId];
+//         if (diff != 0) return diff;
+//         return graph.classes[b.classId].name
+//             .compareTo(graph.classes[a.classId].name);
+//       });
+//     } else {
+//       classes.sort((a, b) {
+//         var diff = counts[b.classId] - counts[a.classId];
+//         if (diff != 0) return diff;
+//         diff = sizes[b.classId] - sizes[a.classId];
+//         if (diff != 0) return diff;
+//         return graph.classes[b.classId].name
+//             .compareTo(graph.classes[a.classId].name);
+//       });
+//     }
+//
+//     return HeapStats(classes, sizes, counts);
+//   }
+//
+//   /// Generate statistics about the variable-length data of [objects].
+//   ///
+//   /// The returned [HeapData]s are sorted by cumulative size if
+//   /// [sortBySize] is true and by number of objects otherwise.
+//   HeapDataStats generateDataStats(IntSet objects, {bool sortBySize = true}) {
+//     final graphObjects = graph.objects;
+//     final klasses = graph.classes;
+//     final counts = <HeapData, int>{};
+//     for (final objectId in objects) {
+//       final obj = graphObjects[objectId];
+//       final klass = klasses[obj.classId].name;
+//       // Should use length here instead!
+//       final len = variableLengthOf(obj);
+//       if (len == -1) continue;
+//       final data = HeapData(klass, obj.data, obj.shallowSize, len);
+//       counts[data] = (counts[data] ?? 0) + 1;
+//     }
+//     counts.forEach((HeapData data, int count) {
+//       data.count = count;
+//     });
+//
+//     final datas = counts.keys.toList();
+//     if (sortBySize) {
+//       datas.sort((a, b) => b.totalSize - a.totalSize);
+//     } else {
+//       datas.sort((a, b) => b.count - a.count);
+//     }
+//
+//     return HeapDataStats(datas);
+//   }
+//
+//   /// Calculates the set of objects transitively reachable by [roots].
+//   IntSet transitiveGraph(IntSet roots, [TraverseFilter? tfilter = null]) {
+//     final reachable = IntSet();
+//     final worklist = <int>[];
+//
+//     final objects = graph.objects;
+//
+//     reachable.addAll(roots);
+//     worklist.addAll(roots);
+//
+//     final weakProperties = IntSet();
+//
+//     while (worklist.isNotEmpty) {
+//       while (worklist.isNotEmpty) {
+//         final objectIdToExpand = worklist.removeLast();
+//         final objectToExpand = objects[objectIdToExpand];
+//         final cid = objectToExpand.classId;
+//
+//         // Weak references don't keep their value alive.
+//         if (cid == _weakReferenceCid) continue;
+//
+//         // Weak properties keep their value alive if the key is alive.
+//         if (cid == _weakPropertyCid) {
+//           if (tfilter == null ||
+//               tfilter._shouldTraverseEdge(
+//                   _weakPropertyCid, _weakPropertyValueIdx)) {
+//             weakProperties.add(objectIdToExpand);
+//           }
+//           continue;
+//         }
+//
+//         // Normal object (or FinalizerEntry).
+//         final references = objectToExpand.references;
+//         final bool isFinalizerEntry = cid == _finalizerEntryCid;
+//         for (int i = 0; i < references.length; ++i) {
+//           // [FinalizerEntry] objects don't keep their "detach" and "value"
+//           // fields alive.
+//           if (isFinalizerEntry &&
+//               (i == _finalizerEntryDetachIdx || i == _finalizerEntryValueIdx)) {
+//             continue;
+//           }
+//
+//           final successor = references[i];
+//           if (!reachable.contains(successor)) {
+//             if (tfilter == null ||
+//                 (tfilter._shouldTraverseEdge(objectToExpand.classId, i) &&
+//                     tfilter._shouldIncludeObject(objects[successor].classId))) {
+//               reachable.add(successor);
+//               worklist.add(successor);
+//             }
+//           }
+//         }
+//       }
+//
+//       // Enqueue values of weak properties if their key is alive.
+//       weakProperties.removeWhere((int weakProperty) {
+//         final wpReferences = objects[weakProperty].references;
+//         final keyId = wpReferences[_weakPropertyKeyIdx];
+//         final valueId = wpReferences[_weakPropertyValueIdx];
+//         if (reachable.contains(keyId)) {
+//           if (!reachable.contains(valueId)) {
+//             if (tfilter == null ||
+//                 tfilter._shouldIncludeObject(objects[valueId].classId)) {
+//               reachable.add(valueId);
+//               worklist.add(valueId);
+//             }
+//           }
+//           return true;
+//         }
+//         return false;
+//       });
+//     }
+//     return reachable;
+//   }
+//
+//   /// Calculates the set of objects that transitively can reach [oids].
+//   IntSet reverseTransitiveGraph(IntSet oids, [TraverseFilter? tfilter = null]) {
+//     final reachable = IntSet();
+//     final worklist = <int>[];
+//
+//     final objects = graph.objects;
+//
+//     reachable.addAll(oids);
+//     worklist.addAll(oids);
+//
+//     while (worklist.isNotEmpty) {
+//       final objectIdToExpand = worklist.removeLast();
+//       final objectToExpand = objects[objectIdToExpand];
+//       final referrers = objectToExpand.referrers;
+//       for (int i = 0; i < referrers.length; ++i) {
+//         final predecessorId = referrers[i];
+//         // This is a dead object in heap that refers to a live object.
+//         if (!reachableObjects.contains(predecessorId)) continue;
+//         if (!reachable.contains(predecessorId)) {
+//           final predecessor = objects[predecessorId];
+//           final cid = predecessor.classId;
+//
+//           // A WeakReference does not keep its object alive.
+//           if (cid == _weakReferenceCid) continue;
+//
+//           // A WeakProperty does not keep its key alive, but may keep it's value
+//           // alive.
+//           if (cid == _weakPropertyCid) {
+//             final refs = predecessor.references;
+//             bool hasRealRef = false;
+//             for (int i = 0; i < refs.length; ++i) {
+//               if (i == _weakPropertyKeyIdx) continue;
+//               if (refs[i] == objectIdToExpand) hasRealRef = true;
+//             }
+//             if (!hasRealRef) continue;
+//           }
+//
+//           // A FinalizerEntry] does not keep its {detach_,value_} fields alive.
+//           if (cid == _finalizerEntryCid) {
+//             final refs = predecessor.references;
+//             bool hasRealRef = false;
+//             for (int i = 0; i < refs.length; ++i) {
+//               if (i == _finalizerEntryDetachIdx) continue;
+//               if (i == _finalizerEntryValueIdx) continue;
+//               if (refs[i] == objectIdToExpand) hasRealRef = true;
+//             }
+//             if (!hasRealRef) continue;
+//           }
+//
+//           bool passedFilter = true;
+//           if (tfilter != null) {
+//             final index = predecessor.references.indexOf(objectIdToExpand);
+//             passedFilter =
+//                 (tfilter._shouldTraverseEdge(predecessor.classId, index) &&
+//                     tfilter._shouldIncludeObject(predecessor.classId));
+//           }
+//           if (passedFilter) {
+//             reachable.add(predecessorId);
+//             worklist.add(predecessorId);
+//           }
+//         }
+//       }
+//     }
+//     return reachable;
+//   }
+//
+//   // Only keep those in [toFilter] that have references from [from].
+//   IntSet filterObjectsReferencedBy(IntSet toFilter, IntSet from) {
+//     final result = IntSet();
+//     final objects = graph.objects;
+//
+//     for (final fromId in from) {
+//       final from = objects[fromId];
+//       for (final refId in from.references) {
+//         if (toFilter.contains(refId)) {
+//           result.add(refId);
+//           break;
+//         }
+//       }
+//     }
+//
+//     return result;
+//   }
+//
+//   /// Returns set of cids that are matching the provided [patterns].
+//   IntSet findClassIdsMatching(Iterable<String> patterns) {
+//     final regexPatterns = patterns.map((p) => RegExp(p)).toList();
+//
+//     final classes = graph.classes;
+//     final cids = IntSet();
+//     for (final klass in classes) {
+//       if (regexPatterns.any((pattern) =>
+//           pattern.hasMatch(klass.name) ||
+//           pattern.hasMatch(klass.libraryUri.toString()))) {
+//         cids.add(klass.classId);
+//       }
+//     }
+//     return cids;
+//   }
+//
+//   /// Create filters that can be used in traversing object graphs.
+//   TraverseFilter? parseTraverseFilter(List<String> patterns) {
+//     if (patterns.isEmpty) return null;
+//
+//     final aset = IntSet();
+//     final naset = IntSet();
+//
+//     int bits = 0;
+//
+//     final fmap = <int, IntSet>{};
+//     final nfmap = <int, IntSet>{};
+//     for (String pattern in patterns) {
+//       final bool isNegated = pattern.startsWith('^');
+//       if (isNegated) {
+//         pattern = pattern.substring(1);
+//       }
+//
+//       // Edge filter.
+//       final int sep = pattern.indexOf(':');
+//       if (sep != -1 && sep != (pattern.length - 1)) {
+//         final klassPattern = pattern.substring(0, sep);
+//
+//         final fieldNamePattern = pattern.substring(sep + 1);
+//         final cids = findClassIdsMatching([klassPattern]);
+//
+//         final fieldNameRegexp = RegExp(fieldNamePattern);
+//         for (final cid in cids) {
+//           final klass = graph.classes[cid];
+//           for (final field in klass.fields) {
+//             if (fieldNameRegexp.hasMatch(field.name)) {
+//               (isNegated ? nfmap : fmap)
+//                   .putIfAbsent(cid, IntSet.new)
+//                   .add(field.index);
+//             }
+//           }
+//         }
+//
+//         if (!isNegated) {
+//           bits |= TraverseFilter._hasPositiveEdgePatternBit;
+//         }
+//
+//         continue;
+//       }
+//
+//       // Class filter.
+//       final cids = findClassIdsMatching([pattern]);
+//       (isNegated ? naset : aset).addAll(cids);
+//
+//       if (!isNegated) {
+//         bits |= TraverseFilter._hasPositiveClassPatternBit;
+//       }
+//     }
+//     return TraverseFilter._(patterns, bits, aset, naset, fmap, nfmap);
+//   }
+//
+//   /// Returns set of objects from [objectIds] whose class id is in [cids].
+//   IntSet filterByClassId(IntSet objectIds, IntSet cids) {
+//     return filter(objectIds, (object) => cids.contains(object.classId));
+//   }
+//
+//   /// Returns set of objects from [objectIds] whose class id is in [cids].
+//   IntSet filterByClassPatterns(IntSet objectIds, List<String> patterns) {
+//     final tfilter = parseTraverseFilter(patterns);
+//     if (tfilter == null) return objectIds;
+//     return filter(objectIds, tfilter._shouldFilterObject);
+//   }
+//
+//   /// Returns set of objects from [objectIds] whose class id is in [cids].
+//   IntSet filter(IntSet objectIds, bool Function(HeapSnapshotObject) filter) {
+//     final result = IntSet();
+//     final objects = graph.objects;
+//     objectIds.forEach((int objId) {
+//       if (filter(objects[objId])) {
+//         result.add(objId);
+//       }
+//     });
+//     return result;
+//   }
+//
+//   /// Returns users of [objs].
+//   IntSet findUsers(IntSet objs, List<String> patterns) {
+//     final tfilter = parseTraverseFilter(patterns);
+//
+//     final objects = graph.objects;
+//     final result = IntSet();
+//     for (final objId in objs) {
+//       final object = objects[objId];
+//       final referrers = object.referrers;
+//       for (int i = 0; i < referrers.length; ++i) {
+//         final userId = referrers[i];
+//         // This is a dead object in heap that refers to a live object.
+//         if (!reachableObjects.contains(userId)) continue;
+//         bool passedFilter = true;
+//         if (tfilter != null) {
+//           final user = objects[userId];
+//           final idx = user.references.indexOf(objId);
+//           passedFilter = tfilter._shouldTraverseEdge(user.classId, idx) &&
+//               tfilter._shouldIncludeObject(user.classId);
+//         }
+//         if (passedFilter) {
+//           result.add(userId);
+//         }
+//       }
+//     }
+//     return result;
+//   }
+//
+//   /// Returns references of [objs].
+//   IntSet findReferences(IntSet objs, List<String> patterns) {
+//     final tfilter = parseTraverseFilter(patterns);
+//
+//     final objects = graph.objects;
+//     final result = IntSet();
+//     for (final objId in objs) {
+//       final object = objects[objId];
+//       final references = object.references;
+//       for (int i = 0; i < references.length; ++i) {
+//         final refId = references[i];
+//         bool passedFilter = true;
+//         if (tfilter != null) {
+//           final other = objects[refId];
+//           passedFilter = tfilter._shouldTraverseEdge(object.classId, i) &&
+//               tfilter._shouldIncludeObject(other.classId);
+//         }
+//         if (passedFilter) {
+//           var refObj = graph.objects[refId];
+//           if (graph.classes[refObj.classId].name == 'FileState') {
+//             // graph.classes[graph.objects[graph.objects[object.referrers.toList()[0]].referrers[0]].classId]
+//             // print('aaaaaa');
+//           }
+//           result.add(refId);
+//         }
+//       }
+//     }
+//     return result;
+//   }
+//
+//   /// Returns the size of the variable part of [object]
+//   ///
+//   /// For strings this is the length of the string (or approximation thereof).
+//   /// For typed data this is the number of elements.
+//   /// For fixed-length arrays this is the length of the array.
+//   int variableLengthOf(HeapSnapshotObject object) {
+//     final cid = object.classId;
+//
+//     final isList = cid == _nonGrowableListCid || cid == _immutableListCid;
+//     if (isList) {
+//       // Return the length of the non-growable array.
+//       final numFields = graph.classes[cid].fields.length;
+//       return object.references.length - numFields;
+//     }
+//
+//     final isString = cid == _oneByteStringCid || cid == _twoByteStringCid;
+//     if (isString) {
+//       // Return the length of the string.
+//       //
+//       // - For lengths <128 the length of string is precise
+//       // - For larger strings, the data is truncated, so we use the payload
+//       //   size.
+//       // - TODO: The *heapsnapshot format contains actual length but it gets
+//       //   lost after reading. Can we preserve it somewhere on
+//       //   `HeapSnapshotGraph`?
+//       //
+//       // The approximation is based on knowning the header size of a string:
+//       // - String has: header, length (hash - on 32-bit platforms) + payload
+//       final fixedSize =
+//           _headerSize + _wordSize * (_arch == _Arch.arch32 ? 2 : 1);
+//       final len =
+//           object.shallowSize == 0 ? 0 : (object.shallowSize - fixedSize);
+//       if (len < 128) return (object.data as String).length;
+//       return len; // Over-approximates to 2 * wordsize.
+//     }
+//
+//     final data = object.data;
+//     if (data is HeapSnapshotObjectLengthData) {
+//       // Most likely typed data object, return length in elements.
+//       return data.length;
+//     }
+//
+//     final fixedSize = _headerSize + _wordSize * object.references.length;
+//     final dataSize = object.shallowSize - fixedSize;
+//     if (dataSize > _wordSize) {
+//       final klass = graph.classes[cid];
+//       // User-visible, but VM-recognized objects with variable size.
+//       if (!['_RegExp', '_SuspendState'].contains(klass.name)) {
+//         // Non-user-visible, VM-recognized objects (empty library uri).
+//         final uri = klass.libraryUri.toString().trim();
+//         if (uri != '') {
+//           throw 'Object has fixed size: $fixedSize and total '
+//               'size: ${object.shallowSize} but is not known to '
+//               'be variable-length (class: ${graph.classes[cid].name})';
+//         }
+//       }
+//     }
+//
+//     return -1;
+//   }
+//
+//   int _findClassId(String className) {
+//     return graph.classes
+//         .singleWhere((klass) =>
+//             klass.name == className &&
+//             (klass.libraryUri.scheme == 'dart' ||
+//                 klass.libraryUri.toString() == ''))
+//         .classId;
+//   }
+//
+//   int _findFieldIndex(int cid, String fieldName) {
+//     return graph.classes[cid].fields
+//         .singleWhere((f) => f.name == fieldName)
+//         .index;
+//   }
+//
+//   DedupedUint32List _retainingPathOf(int oId, int depth) {
+//     final objects = graph.objects;
+//     final classes = graph.classes;
+//
+//     @pragma('vm:prefer-inline')
+//     int getFieldIndex(int oId, int childId) {
+//       final object = objects[oId];
+//       final fields = classes[object.classId].fields;
+//       final idx = object.references.indexOf(childId);
+//       if (idx == -1) throw 'should not happen';
+//
+//       int fieldIndex = fields.any((f) => f.index == idx)
+//           ? idx
+//           : DedupedUint32List.noFieldIndex;
+//       return fieldIndex;
+//     }
+//
+//     @pragma('vm:prefer-inline')
+//     int retainingPathLength(int id) {
+//       int length = 1;
+//       int id = oId;
+//       while (id != _rootObjectIdx && length <= depth) {
+//         id = _retainers[id];
+//         length++;
+//       }
+//       return length;
+//     }
+//
+//     @pragma('vm:prefer-inline')
+//     bool hasMoreThanOneAlive(IntSet reachableObjects, Uint32List list) {
+//       int count = 0;
+//       for (int i = 0; i < list.length; ++i) {
+//         if (reachableObjects.contains(list[i])) {
+//           count++;
+//           if (count >= 2) return true;
+//         }
+//       }
+//       return false;
+//     }
+//
+//     int lastId = oId;
+//     var lastObject = objects[lastId];
+//
+//     final path = Uint32List(2 * retainingPathLength(oId) - 1);
+//     path[0] = lastObject.classId;
+//     for (int i = 1; i < path.length; i += 2) {
+//       assert(lastId != _rootObjectIdx && ((i - 1) ~/ 2) < depth);
+//       final users = lastObject.referrers;
+//       final int userId = _retainers[lastId];
+//
+//       final user = objects[userId];
+//       int fieldIndex = getFieldIndex(userId, lastId);
+//       final lastWasUniqueRef = !hasMoreThanOneAlive(reachableObjects, users);
+//
+//       path[i] = (lastWasUniqueRef ? 1 : 0) << 0 | fieldIndex << 1;
+//       path[i + 1] = user.classId;
+//
+//       lastId = userId;
+//       lastObject = user;
+//     }
+//     return DedupedUint32List(path);
+//   }
+//
+//   Uint32List _calculateRetainers() {
+//     final retainers = Uint32List(graph.objects.length);
+//
+//     var worklist = IntSet()..add(_rootObjectIdx);
+//     while (!worklist.isEmpty) {
+//       final next = IntSet();
+//
+//       for (final objId in worklist) {
+//         final object = graph.objects[objId];
+//         final cid = object.classId;
+//
+//         // Weak references don't keep their value alive.
+//         if (cid == _weakReferenceCid) continue;
+//
+//         // Weak properties keep their value alive if the key is alive.
+//         if (cid == _weakPropertyCid) {
+//           final valueId = object.references[_weakPropertyValueIdx];
+//           if (reachableObjects.contains(valueId)) {
+//             if (retainers[valueId] == 0) {
+//               retainers[valueId] = objId;
+//               next.add(valueId);
+//             }
+//           }
+//           continue;
+//         }
+//
+//         // Normal object (or FinalizerEntry).
+//         final references = object.references;
+//         final bool isFinalizerEntry = cid == _finalizerEntryCid;
+//         for (int i = 0; i < references.length; ++i) {
+//           // [FinalizerEntry] objects don't keep their "detach" and "value"
+//           // fields alive.
+//           if (isFinalizerEntry &&
+//               (i == _finalizerEntryDetachIdx || i == _finalizerEntryValueIdx)) {
+//             continue;
+//           }
+//
+//           final refId = references[i];
+//           if (retainers[refId] == 0) {
+//             retainers[refId] = objId;
+//             next.add(refId);
+//           }
+//         }
+//       }
+//       worklist = next;
+//     }
+//     return retainers;
+//   }
+// }
+//
+// class TraverseFilter {
+//   static const int _hasPositiveClassPatternBit = (1 << 0);
+//   static const int _hasPositiveEdgePatternBit = (1 << 1);
+//
+//   final List<String> _patterns;
+//
+//   final int _bits;
+//
+//   final IntSet? _allowed;
+//   final IntSet? _disallowed;
+//
+//   final Map<int, IntSet>? _followMap;
+//   final Map<int, IntSet>? _notFollowMap;
+//
+//   const TraverseFilter._(this._patterns, this._bits, this._allowed,
+//       this._disallowed, this._followMap, this._notFollowMap);
+//
+//   bool get _hasPositiveClassPattern =>
+//       (_bits & _hasPositiveClassPatternBit) != 0;
+//   bool get _hasPositiveEdgePattern => (_bits & _hasPositiveEdgePatternBit) != 0;
+//
+//   String asString(HeapSnapshotGraph graph) {
+//     final sb = StringBuffer();
+//     sb.writeln(
+//         'The traverse filter expression "${_patterns.join(' ')}" matches:\n');
+//
+//     final ca = _allowed ?? IntSet();
+//     final cna = _disallowed ?? IntSet();
+//
+//     final klasses = graph.classes.toList()
+//       ..sort((a, b) => a.name.compareTo(b.name));
+//
+//     for (final klass in klasses) {
+//       final cid = klass.classId;
+//
+//       final posEdge = [];
+//       final negEdge = [];
+//
+//       final f = _followMap?[cid] ?? IntSet();
+//       final nf = _notFollowMap?[cid] ?? IntSet();
+//       for (final field in klass.fields) {
+//         final fieldIndex = field.index;
+//         if (f.contains(fieldIndex)) {
+//           posEdge.add(field.name);
+//         }
+//         if (nf.contains(fieldIndex)) {
+//           negEdge.add(field.name);
+//         }
+//       }
+//
+//       bool printedClass = false;
+//       final name = klass.name;
+//       if (ca.contains(cid)) {
+//         sb.writeln('[+] $name');
+//         printedClass = true;
+//       }
+//       if (cna.contains(cid)) {
+//         sb.writeln('[-] $name');
+//         printedClass = true;
+//       }
+//       if (posEdge.isNotEmpty || negEdge.isNotEmpty) {
+//         if (!printedClass) {
+//           sb.writeln('[ ] $name');
+//           printedClass = true;
+//         }
+//         for (final field in posEdge) {
+//           sb.writeln('[+]   .$field');
+//         }
+//         for (final field in negEdge) {
+//           sb.writeln('[-]   .$field');
+//         }
+//       }
+//     }
+//     return sb.toString().trim();
+//   }
+//
+//   // Should include the edge when building transitive graphs.
+//   bool _shouldTraverseEdge(int cid, int fieldIndex) {
+//     final nf = _notFollowMap?[cid];
+//     if (nf != null && nf.contains(fieldIndex)) return false;
+//
+//     final f = _followMap?[cid];
+//     if (f != null && f.contains(fieldIndex)) return true;
+//
+//     // If there's an allow list we only allow allowed ones, otherwise we allow
+//     // all.
+//     return !_hasPositiveEdgePattern;
+//   }
+//
+//   // Should include the object when building transitive graphs.
+//   bool _shouldIncludeObject(int cid) {
+//     if (_disallowed?.contains(cid) == true) return false;
+//     if (_allowed?.contains(cid) == true) return true;
+//
+//     // If there's an allow list we only allow allowed ones, otherwise we allow
+//     // all.
+//     return !_hasPositiveClassPattern;
+//   }
+//
+//   // Should include the object when filtering a set of objects.
+//   bool _shouldFilterObject(HeapSnapshotObject object) {
+//     final cid = object.classId;
+//     final numReferences = object.references.length;
+//     return __shouldFilterObject(cid, numReferences);
+//   }
+//
+//   bool __shouldFilterObject(int cid, int numReferences) {
+//     if (!_shouldIncludeObject(cid)) return false;
+//
+//     // Check if the object has an explicitly disallowed field.
+//     final nf = _notFollowMap?[cid];
+//     if (nf != null) {
+//       for (int fieldIndex = 0; fieldIndex < numReferences; ++fieldIndex) {
+//         if (nf.contains(fieldIndex)) return false;
+//       }
+//     }
+//
+//     // Check if the object has an explicitly allowed field.
+//     final f = _followMap?[cid];
+//     if (f != null) {
+//       for (int fieldIndex = 0; fieldIndex < numReferences; ++fieldIndex) {
+//         if (f.contains(fieldIndex)) return true;
+//       }
+//     }
+//
+//     // If there's an allow list we only allow allowed ones, otherwise we allow
+//     // all.
+//     return !_hasPositiveEdgePattern;
+//   }
+// }
+//
+// /// Stringified representation of a heap object.
+// class ObjectInformation {
+//   final String className;
+//   final String libraryUri;
+//   final Map<String, Object> fieldValues;
+//
+//   ObjectInformation(this.className, this.libraryUri, this.fieldValues);
+// }
+//
+// /// Heap usage statistics calculated for a set of heap objects.
+// class HeapStats {
+//   final List<HeapSnapshotClass> classes;
+//   final Int32List sizes;
+//   final Int32List counts;
+//
+//   HeapStats(this.classes, this.sizes, this.counts);
+//
+//   int get totalSize => sizes.fold(0, (int a, int b) => a + b);
+//   int get totalCount => counts.fold(0, (int a, int b) => a + b);
+// }
+//
+// /// Heap object data statistics calculated for a set of heap objects.
+// class HeapDataStats {
+//   final List<HeapData> datas;
+//
+//   HeapDataStats(this.datas);
+//
+//   int get totalSizeUniqueDatas =>
+//       datas.fold(0, (int sum, HeapData d) => sum + d.size);
+//   int get totalSize =>
+//       datas.fold(0, (int sum, HeapData d) => sum + d.totalSize);
+//   int get totalCount => datas.fold(0, (int sum, HeapData d) => sum + d.count);
+// }
+//
+// /// Representing the data of one heap object.
+// ///
+// /// Since the data can be truncated, it has an extra size that allows to
+// /// distinguish datas with same truncated value with high probability.
+// class HeapData {
+//   final String klass;
+//   final dynamic value;
+//   final int size;
+//   final int len;
+//
+//   late final int count;
+//
+//   HeapData(this.klass, this.value, this.size, this.len);
+//
+//   int? _hashCode;
+//   int get hashCode {
+//     if (_hashCode != null) return _hashCode!;
+//
+//     var valueToHash = value;
+//     if (valueToHash is! String &&
+//         valueToHash is! bool &&
+//         valueToHash is! double) {
+//       if (valueToHash is HeapSnapshotObjectLengthData) {
+//         valueToHash = valueToHash.length;
+//       } else if (valueToHash is HeapSnapshotObjectNoData) {
+//         valueToHash = 0;
+//       } else if (valueToHash is HeapSnapshotObjectNullData) {
+//         valueToHash = 0;
+//       } else {
+//         throw '${valueToHash.runtimeType}';
+//       }
+//     }
+//
+//     return _hashCode = Object.hash(klass, valueToHash, size, len);
+//   }
+//
+//   bool operator ==(other) {
+//     if (identical(this, other)) return true;
+//     if (other is! HeapData) return false;
+//     if (size != other.size) return false;
+//     if (len != other.len) return false;
+//     if (klass != other.klass) return false;
+//
+//     final ovalue = other.value;
+//     if (value is String || value is bool || value is double) {
+//       return value == ovalue;
+//     }
+//     // We don't have the typed data content, so we don't know whether they are
+//     // equal / dedupable.
+//     return false;
+//   }
+//
+//   String get valueAsString {
+//     var d = value;
+//     if (d is String) {
+//       final newLine = d.indexOf('\n');
+//       if (newLine >= 0) {
+//         d = d.substring(0, newLine);
+//       }
+//       if (d.length > 80) {
+//         d = d.substring(0, 80);
+//       }
+//       return d;
+//     }
+//     return 'len:$len';
+//   }
+//
+//   int get totalSize => size * count;
+// }
+//
+// /// Used to represent retaining paths.
+// ///
+// /// For retaining paths: `[cid0, fieldIdx1 << 1 | isUniqueOwner, cid1, ...]`
+// class DedupedUint32List {
+//   static const int noFieldIndex = (1 << 29);
+//
+//   final Uint32List path;
+//   late final int count;
+//
+//   DedupedUint32List(this.path);
+//
+//   int? _hashCode;
+//   int get hashCode => _hashCode ??= Object.hashAll(path);
+//
+//   bool operator ==(other) {
+//     if (identical(this, other)) return true;
+//     if (other is! DedupedUint32List) return false;
+//     if (path.length != other.path.length) return false;
+//     for (int i = 0; i < path.length; ++i) {
+//       if (path[i] != other.path[i]) return false;
+//     }
+//     return true;
+//   }
+// }
+//
+// enum _Arch {
+//   arch32,
+//   arch64,
+//   arch64c,
+// }
diff --git a/analyzer/example/heap/format.dart b/analyzer/example/heap/format.dart
new file mode 100644
index 0000000..fbbd7d5
--- /dev/null
+++ b/analyzer/example/heap/format.dart
@@ -0,0 +1,204 @@
+// // 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:typed_data';
+//
+// import 'package:vm_service/vm_service.dart';
+//
+// import 'analysis.dart';
+//
+// String format(int a) => a.toString().padLeft(6, ' ');
+// String formatBytes(int a) => (a ~/ 1024).toString().padLeft(6, ' ') + ' kb';
+// String truncateString(String s) {
+//   int index;
+//
+//   index = s.indexOf('\n');
+//   if (index >= 0) s = s.substring(index);
+//
+//   index = s.indexOf('\r');
+//   if (index >= 0) s = s.substring(index);
+//
+//   if (s.length > 30) s = s.substring(30);
+//   return s;
+// }
+//
+// String formatHeapStats(HeapStats stats, {int? maxLines, int? sizeCutoff}) {
+//   assert(sizeCutoff == null || sizeCutoff >= 0);
+//   assert(maxLines == null || maxLines >= 0);
+//
+//   final table = Table();
+//   table.addRow(['size', 'count', 'class']);
+//   table.addRow(['--------', '--------', '--------']);
+//   int totalSize = 0;
+//   int totalCount = 0;
+//   for (int i = 0; i < stats.classes.length; ++i) {
+//     final c = stats.classes[i];
+//     final count = stats.counts[c.classId];
+//     final size = stats.sizes[c.classId];
+//
+//     totalSize += size;
+//     totalCount += count;
+//
+//     if (sizeCutoff == null || size >= sizeCutoff) {
+//       if (maxLines == null || i < maxLines) {
+//         table.addRow(
+//             [formatBytes(size), format(count), '${c.name} ${c.libraryUri}']);
+//       }
+//     }
+//   }
+//   if (table.rows > 3) {
+//     table.addRow(['--------', '--------']);
+//     table.addRow([formatBytes(totalSize), format(totalCount)]);
+//   }
+//   return table.asString;
+// }
+//
+// String formatDataStats(HeapDataStats stats, {int? maxLines, int? sizeCutoff}) {
+//   assert(sizeCutoff == null || sizeCutoff >= 0);
+//   assert(maxLines == null || maxLines >= 0);
+//
+//   final table = Table();
+//   table.addRow(['size', 'unique-size', 'count', 'class', 'data']);
+//   table.addRow(['--------', '--------', '--------', '--------', '--------']);
+//
+//   int totalSize = 0;
+//   int totalUniqueSize = 0;
+//   int totalCount = 0;
+//
+//   final List<HeapData> datas = stats.datas;
+//   for (int i = 0; i < datas.length; ++i) {
+//     final data = datas[i];
+//
+//     totalSize += data.size;
+//     totalUniqueSize += data.totalSize;
+//     totalCount += data.count;
+//
+//     if (sizeCutoff == null || data.totalSize >= sizeCutoff) {
+//       if (maxLines == null || i < maxLines) {
+//         table.addRow([
+//           formatBytes(data.totalSize),
+//           formatBytes(data.size),
+//           format(data.count),
+//           data.klass,
+//           data.valueAsString,
+//         ]);
+//       }
+//     }
+//   }
+//   if (table.rows > 3) {
+//     table.addRow(['--------', '--------', '--------']);
+//     table.addRow([
+//       formatBytes(totalUniqueSize),
+//       formatBytes(totalSize),
+//       format(totalCount)
+//     ]);
+//   }
+//   return table.asString;
+// }
+//
+// String formatRetainingPath(HeapSnapshotGraph graph, DedupedUint32List rpath) {
+//   final path = _stringifyRetainingPath(graph, rpath);
+//   final bool wasTruncated = rpath.path.last != /*root*/ 1;
+//   final sb = StringBuffer();
+//   for (int i = 0; i < path.length; ++i) {
+//     final indent = i >= 2 ? (i - 1) : 0;
+//     sb.writeln(' ' * 4 * indent + (i == 0 ? '' : '⮑ ') + '${path[i]}');
+//   }
+//   if (wasTruncated) {
+//     sb.writeln(' ' * 4 * (path.length - 1) + '⮑  …');
+//   }
+//   return sb.toString();
+// }
+//
+// String formatDominatorPath(HeapSnapshotGraph graph, DedupedUint32List dpath) {
+//   final path = _stringifyDominatorPath(graph, dpath);
+//   final bool wasTruncated = dpath.path.last != /*root*/ 1;
+//   final sb = StringBuffer();
+//   for (int i = 0; i < path.length; ++i) {
+//     final indent = i >= 2 ? (i - 1) : 0;
+//     sb.writeln(' ' * 4 * indent + (i == 0 ? '' : '⮑  ') + '${path[i]}');
+//   }
+//   if (wasTruncated) {
+//     sb.writeln(' ' * 4 * (path.length - 1) + '⮑  …');
+//   }
+//   return sb.toString();
+// }
+//
+// List<String> _stringifyRetainingPath(
+//     HeapSnapshotGraph graph, DedupedUint32List rpath) {
+//   final path = rpath.path;
+//   final spath = <String>[];
+//   for (int i = 0; i < path.length; i += 2) {
+//     final klass = graph.classes[path[i]];
+//
+//     String? fieldName;
+//     String prefix = '';
+//     if (i > 0) {
+//       final int value = path[i - 1];
+//       final hasUniqueOwner = (value & (1 << 0)) == 1;
+//       final fieldIndex = value >> 1;
+//       if (fieldIndex != DedupedUint32List.noFieldIndex) {
+//         final field = klass.fields[fieldIndex];
+//         assert(field.index == fieldIndex);
+//         fieldName = field.name;
+//       }
+//       prefix = (hasUniqueOwner ? '・' : '﹢');
+//     }
+//
+//     spath.add(prefix +
+//         '${klass.name}' +
+//         (fieldName != null ? '.$fieldName' : '') +
+//         ' (${klass.libraryUri})');
+//   }
+//   return spath;
+// }
+//
+// List<String> _stringifyDominatorPath(
+//     HeapSnapshotGraph graph, DedupedUint32List rpath) {
+//   final path = rpath.path;
+//   final spath = <String>[];
+//   for (int i = 0; i < path.length; i++) {
+//     final klass = graph.classes[path[i]];
+//     spath.add('${klass.name} (${klass.libraryUri})');
+//   }
+//   return spath;
+// }
+//
+// class Table {
+//   final List<List<String>> _rows = [];
+//   int _maxColumn = -1;
+//
+//   int get rows => _rows.length;
+//
+//   void addRow(List<String> row) {
+//     _maxColumn = row.length > _maxColumn ? row.length : _maxColumn;
+//     _rows.add(row);
+//   }
+//
+//   String get asString {
+//     if (_rows.isEmpty) return '';
+//
+//     final colSizes = Uint32List(_maxColumn);
+//     for (final row in _rows) {
+//       for (int i = 0; i < row.length; ++i) {
+//         final value = row[i];
+//         final c = colSizes[i];
+//         if (value.length > c) colSizes[i] = value.length;
+//       }
+//     }
+//
+//     final sb = StringBuffer();
+//     for (final row in _rows) {
+//       for (int i = 0; i < row.length; ++i) {
+//         row[i] = row[i].padRight(colSizes[i], ' ');
+//       }
+//       sb.writeln(row.join('  '));
+//     }
+//     return sb.toString().trimRight();
+//   }
+// }
+//
+// String indent(String left, String text) {
+//   return left + text.replaceAll('\n', '\n$left');
+// }
diff --git a/analyzer/example/heap/intset.dart b/analyzer/example/heap/intset.dart
new file mode 100644
index 0000000..5eb4932
--- /dev/null
+++ b/analyzer/example/heap/intset.dart
@@ -0,0 +1,12 @@
+// 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.
+
+// The default set implementation is based on a Uint32List+List where both are
+// linear in the number of entries. That means we consume on 64-bit VMs at
+// least 12 bytes per entry.
+//
+// We should consider making a more memory efficient hash set implementation
+// that uses Int32List and utilizing the fact that we never store negative
+// numbers in it.
+typedef IntSet = Set<int>;
diff --git a/analyzer/example/heap/load.dart b/analyzer/example/heap/load.dart
new file mode 100644
index 0000000..8987a78
--- /dev/null
+++ b/analyzer/example/heap/load.dart
@@ -0,0 +1,60 @@
+// // 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:async';
+// import 'dart:typed_data';
+//
+// import 'package:vm_service/vm_service.dart';
+// import 'package:vm_service/vm_service_io.dart';
+//
+// Future<List<ByteData>> loadFromUri(Uri uri) async {
+//   final Uri wsUri;
+//   if (uri.isScheme("ws")) {
+//     wsUri = uri;
+//   } else {
+//     if (uri.path.isEmpty || uri.path == "/") {
+//       uri = uri.replace(path: "/ws");
+//     } else if (uri.path.endsWith("/")) {
+//       uri = uri.replace(path: "${uri.path}ws");
+//     } else {
+//       uri = uri.replace(path: "${uri.path}/ws");
+//     }
+//     wsUri = uri.replace(scheme: 'ws');
+//   }
+//   final service = await vmServiceConnectUri(wsUri.toString());
+//   try {
+//     final r = await _getHeapsnapshot(service);
+//     return r;
+//   } finally {
+//     await service.dispose();
+//   }
+// }
+//
+// Future<List<ByteData>> _getHeapsnapshot(VmService service) async {
+//   final vm = await service.getVM();
+//   final vmIsolates = vm.isolates!;
+//   if (vmIsolates.isEmpty) {
+//     throw 'Could not find first isolate (expected it to be running already)';
+//   }
+//   final isolateRef = vmIsolates.first;
+//
+//   await service.streamListen(EventStreams.kHeapSnapshot);
+//
+//   final chunks = <ByteData>[];
+//   final done = Completer();
+//   late StreamSubscription streamSubscription;
+//   streamSubscription = service.onHeapSnapshotEvent.listen((e) async {
+//     chunks.add(e.data!);
+//     if (e.last!) {
+//       await service.streamCancel(EventStreams.kHeapSnapshot);
+//       await streamSubscription.cancel();
+//       done.complete();
+//     }
+//   });
+//
+//   await service.requestHeapSnapshot(isolateRef.id!);
+//   await done.future;
+//
+//   return chunks;
+// }
diff --git a/analyzer/example/profiling.dart b/analyzer/example/profiling.dart
new file mode 100644
index 0000000..b6b1fec
--- /dev/null
+++ b/analyzer/example/profiling.dart
@@ -0,0 +1,127 @@
+// Copyright (c) 2017, 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:convert';
+import 'dart:io';
+
+/// A class that can return memory and cpu usage information for a given
+/// process.
+abstract class ProcessProfiler {
+  ProcessProfiler._();
+
+  Future<UsageInfo?> getProcessUsage(int processId);
+
+  /// Return a [ProcessProfiler] instance suitable for the current host
+  /// platform. This can return `null` if we're not able to gather memory and
+  /// cpu information for the current platform.
+  static ProcessProfiler? getProfilerForPlatform() {
+    if (Platform.isLinux || Platform.isMacOS) {
+      return _PosixProcessProfiler();
+    }
+
+    if (Platform.isWindows) {
+      return _WindowsProcessProfiler();
+    }
+
+    // Not a supported platform.
+    return null;
+  }
+}
+
+class UsageInfo {
+  /// A number between 0.0 and 100.0 * the number of host CPUs (but typically
+  /// never more than slightly above 100.0).
+  final double? cpuPercentage;
+
+  /// The process memory usage in kilobytes.
+  final int memoryKB;
+
+  UsageInfo(this.cpuPercentage, this.memoryKB);
+
+  double get memoryMB => memoryKB / 1024;
+
+  @override
+  String toString() {
+    if (cpuPercentage != null) {
+      return '$cpuPercentage% ${memoryMB.toStringAsFixed(1)}MB';
+    }
+    return '${memoryMB.toStringAsFixed(1)}MB';
+  }
+}
+
+class _PosixProcessProfiler extends ProcessProfiler {
+  static final RegExp stringSplitRegExp = RegExp(r'\s+');
+
+  _PosixProcessProfiler() : super._();
+
+  @override
+  Future<UsageInfo?> getProcessUsage(int processId) {
+    try {
+      // Execution time is typically 2-4ms.
+      var future =
+          Process.run('ps', ['-o', '%cpu=,rss=', processId.toString()]);
+      return future.then((ProcessResult result) {
+        if (result.exitCode != 0) {
+          return Future.value(null);
+        }
+
+        return Future.value(_parse(result.stdout as String));
+      });
+    } catch (e) {
+      return Future.error(e);
+    }
+  }
+
+  UsageInfo? _parse(String psResults) {
+    try {
+      // "  0.0 378940"
+      var line = psResults.split('\n').first.trim();
+      var values = line.split(stringSplitRegExp);
+      return UsageInfo(double.parse(values[0]), int.parse(values[1]));
+    } catch (e) {
+      return null;
+    }
+  }
+}
+
+class _WindowsProcessProfiler extends ProcessProfiler {
+  _WindowsProcessProfiler() : super._();
+
+  @override
+  Future<UsageInfo?> getProcessUsage(int processId) async {
+    try {
+      var result = await Process.run(
+          'tasklist', ['/FI', 'PID eq $processId', '/NH', '/FO', 'csv']);
+
+      if (result.exitCode != 0) {
+        return Future.value(null);
+      }
+
+      return Future.value(_parse(result.stdout as String));
+    } catch (e) {
+      return Future.error(e);
+    }
+  }
+
+  UsageInfo? _parse(String tasklistResults) {
+    try {
+      var lines = tasklistResults.split(RegExp("\r?\n"));
+      for (var line in lines) {
+        if (line.trim().isEmpty) continue;
+        // Hacky parsing of csv line.
+        var entries = jsonDecode("[$line]") as List;
+        if (entries.length != 5) continue;
+        // E.g. 123,456 K
+        var memory = entries[4] as String;
+        memory = memory.substring(0, memory.indexOf(" "));
+        memory = memory.replaceAll(",", "");
+        memory = memory.replaceAll(".", "");
+        return UsageInfo(null, int.parse(memory));
+      }
+      return null;
+    } catch (e) {
+      return null;
+    }
+  }
+}
diff --git a/analyzer/example/read_bytes_sync_async.dart b/analyzer/example/read_bytes_sync_async.dart
new file mode 100644
index 0000000..016b636
--- /dev/null
+++ b/analyzer/example/read_bytes_sync_async.dart
@@ -0,0 +1,40 @@
+import 'dart:io' as io;
+
+void main() async {
+  final timer = Stopwatch()..start();
+
+  final pathList = io.File('files.txt').readAsStringSync().split('\n');
+  var contentLength = 0;
+
+  if (1 == 0) {
+    await Future.wait(
+      pathList.map(
+        (path) async {
+          // return io.File(path).readAsString().then((content) {
+          //   contentLength += content.length;
+          // });
+          try {
+            final content = await io.File(path).readAsString();
+            contentLength += content.length;
+          } catch (_) {}
+          // return io.File(path).readAsString().onError(
+          //   (error, stackTrace) {
+          //     print('error');
+          //     return '';
+          //   },
+          // );
+        },
+      ),
+    );
+  } else {
+    for (final path in pathList) {
+      try {
+        contentLength += io.File(path).readAsStringSync().length;
+      } catch (_) {}
+    }
+  }
+
+  timer.stop();
+  print('Time: ${timer.elapsedMilliseconds} ms');
+  print('Content: $contentLength bytes');
+}
diff --git a/analyzer/lib/dart/ast/ast.dart b/analyzer/lib/dart/ast/ast.dart
index 7b76f61..8aa85ae 100644
--- a/analyzer/lib/dart/ast/ast.dart
+++ b/analyzer/lib/dart/ast/ast.dart
@@ -41,6 +41,9 @@
 import 'package:analyzer/src/generated/source.dart' show LineInfo;
 import 'package:meta/meta.dart';
 
+@Deprecated('Use PatternField and visitPatternField() instead')
+typedef RecordPatternField = PatternField;
+
 /// Two or more string literals that are implicitly concatenated because of
 /// being adjacent (separated only by whitespace).
 ///
@@ -224,15 +227,12 @@
 ///
 /// Clients may not extend, implement or mix-in this class.
 @experimental
-abstract class AssignedVariablePattern implements DartPattern {
+abstract class AssignedVariablePattern implements VariablePattern {
   /// Return the element referenced by this pattern, or `null` if either
   /// [name] does not resolve to an element, or the AST structure has not
   /// been resolved. In valid code this will be either [LocalVariableElement]
   /// or [ParameterElement].
   Element? get element;
-
-  /// The name of the variable being referenced.
-  Token get name;
 }
 
 /// An assignment expression.
@@ -390,8 +390,6 @@
 
   R? visitBinaryExpression(BinaryExpression node);
 
-  R? visitBinaryPattern(BinaryPattern node);
-
   R? visitBlock(Block node);
 
   R? visitBlockFunctionBody(BlockFunctionBody node);
@@ -552,6 +550,10 @@
 
   R? visitListPattern(ListPattern node);
 
+  R? visitLogicalAndPattern(LogicalAndPattern node);
+
+  R? visitLogicalOrPattern(LogicalOrPattern node);
+
   R? visitMapLiteralEntry(MapLiteralEntry node);
 
   R? visitMapPattern(MapPattern node);
@@ -572,6 +574,10 @@
 
   R? visitNativeFunctionBody(NativeFunctionBody node);
 
+  R? visitNullAssertPattern(NullAssertPattern node);
+
+  R? visitNullCheckPattern(NullCheckPattern node);
+
   R? visitNullLiteral(NullLiteral node);
 
   R? visitObjectPattern(ObjectPattern node);
@@ -588,6 +594,10 @@
 
   R? visitPatternAssignment(PatternAssignment node);
 
+  R? visitPatternField(PatternField node);
+
+  R? visitPatternFieldName(PatternFieldName node);
+
   R? visitPatternVariableDeclaration(PatternVariableDeclaration node);
 
   R? visitPatternVariableDeclarationStatement(
@@ -595,8 +605,6 @@
 
   R? visitPostfixExpression(PostfixExpression node);
 
-  R? visitPostfixPattern(PostfixPattern node);
-
   R? visitPrefixedIdentifier(PrefixedIdentifier node);
 
   R? visitPrefixExpression(PrefixExpression node);
@@ -607,10 +615,6 @@
 
   R? visitRecordPattern(RecordPattern node);
 
-  R? visitRecordPatternField(RecordPatternField node);
-
-  R? visitRecordPatternFieldName(RecordPatternFieldName node);
-
   R? visitRecordTypeAnnotation(RecordTypeAnnotation node);
 
   R? visitRecordTypeAnnotationNamedField(RecordTypeAnnotationNamedField node);
@@ -693,6 +697,8 @@
 
   R? visitWhileStatement(WhileStatement node);
 
+  R? visitWildcardPattern(WildcardPattern node);
+
   R? visitWithClause(WithClause node);
 
   R? visitYieldStatement(YieldStatement node);
@@ -759,24 +765,6 @@
   FunctionType? get staticInvokeType;
 }
 
-/// A binary (infix) pattern.
-///
-///    binaryPattern ::=
-///        [DartPattern] ('|' | '&') [DartPattern]
-///
-/// Clients may not extend, implement or mix-in this class.
-@experimental
-abstract class BinaryPattern implements DartPattern {
-  /// Return the pattern used to compute the left operand.
-  DartPattern get leftOperand;
-
-  /// Return the binary operator being applied.
-  Token get operator;
-
-  /// Return the pattern used to compute the right operand.
-  DartPattern get rightOperand;
-}
-
 /// A sequence of statements.
 ///
 ///    block ::=
@@ -1001,11 +989,13 @@
 /// The declaration of a class.
 ///
 ///    classDeclaration ::=
-///        classModifier? 'class' name [TypeParameterList]?
+///        classModifiers 'class' name [TypeParameterList]?
 ///        [ExtendsClause]? [WithClause]? [ImplementsClause]?
 ///        '{' [ClassMember]* '}'
 ///
-///    classModifier ::= 'sealed' | 'abstract'
+///    classModifiers ::= 'sealed'
+///      | 'abstract'? ('base' | 'interface' | 'final')?
+///      | 'abstract'? 'base'? 'mixin'
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class ClassDeclaration implements ClassOrAugmentationDeclaration {
@@ -1063,6 +1053,9 @@
   /// In valid code only [ClassDeclaration] can specify it.
   Token? get abstractKeyword;
 
+  /// Return the 'base' keyword, or `null` if the keyword was absent.
+  Token? get baseKeyword;
+
   /// Returns the token representing the 'class' keyword.
   Token get classKeyword;
 
@@ -1079,16 +1072,25 @@
   /// In valid code only [ClassDeclaration] can specify it.
   ExtendsClause? get extendsClause;
 
+  /// Return the 'final' keyword, or `null` if the keyword was absent.
+  Token? get finalKeyword;
+
   /// Returns the `implements` clause for the class, or `null` if the class
   /// does not implement any interfaces.
   ImplementsClause? get implementsClause;
 
+  /// Return the 'interface' keyword, or `null` if the keyword was absent.
+  Token? get interfaceKeyword;
+
   /// Returns the left curly bracket.
   Token get leftBracket;
 
   /// Returns the members defined by the class.
   NodeList<ClassMember> get members;
 
+  /// Return the 'mixin' keyword, or `null` if the keyword was absent.
+  Token? get mixinKeyword;
+
   /// Returns the right curly bracket.
   Token get rightBracket;
 
@@ -1107,9 +1109,11 @@
 /// A class type alias.
 ///
 ///    classTypeAlias ::=
-///        name [TypeParameterList]? '=' classModifier? mixinApplication
+///        name [TypeParameterList]? '=' classModifiers mixinApplication
 ///
-///    classModifier ::= 'sealed' | 'abstract'
+///    classModifiers ::= 'sealed'
+///      | 'abstract'? ('base' | 'interface' | 'final')?
+///      | 'abstract'? 'base'? 'mixin'
 ///
 ///    mixinApplication ::=
 ///        [TypeName] [WithClause] [ImplementsClause]? ';'
@@ -1120,6 +1124,9 @@
   /// defining an abstract class.
   Token? get abstractKeyword;
 
+  /// Return the 'base' keyword, or `null` if the keyword was absent.
+  Token? get baseKeyword;
+
   @override
   ClassElement? get declaredElement;
 
@@ -1130,10 +1137,19 @@
   /// Return the token for the '=' separating the name from the definition.
   Token get equals;
 
+  /// Return the 'final' keyword, or `null` if the keyword was absent.
+  Token? get finalKeyword;
+
   /// Return the implements clause for this class, or `null` if there is no
   /// implements clause.
   ImplementsClause? get implementsClause;
 
+  /// Return the 'interface' keyword, or `null` if the keyword was absent.
+  Token? get interfaceKeyword;
+
+  /// Return the 'mixin' keyword, or `null` if the keyword was absent.
+  Token? get mixinKeyword;
+
   /// Return the 'sealed' keyword, or `null` if the keyword was absent.
   Token? get sealedKeyword;
 
@@ -1450,7 +1466,7 @@
 /// - constant constructor invocations
 /// - constant list literals
 /// - constant set or map literals
-/// - constant expressions wrapped in parentheses and preceeded by the `const`
+/// - constant expressions wrapped in parentheses and preceded by the `const`
 ///   keyword
 ///
 /// This node is also used to recover from cases where a different kind of
@@ -1675,21 +1691,26 @@
 ///
 ///    pattern ::=
 ///        [AssignedVariablePattern]
-///      | [BinaryPattern]
 ///      | [DeclaredVariablePattern]
 ///      | [CastPattern]
 ///      | [ConstantPattern]
 ///      | [ListPattern]
+///      | [LogicalAndPattern]
+///      | [LogicalOrPattern]
 ///      | [MapPattern]
+///      | [NullAssertPattern]
+///      | [NullCheckPattern]
 ///      | [ObjectPattern]
 ///      | [ParenthesizedPattern]
-///      | [PostfixPattern]
 ///      | [RecordPattern]
 ///      | [RelationalPattern]
 ///
 /// Clients may not extend, implement or mix-in this class.
 @experimental
 abstract class DartPattern implements AstNode, ListPatternElement {
+  /// The matched value type, or `null` if the node is not resolved yet.
+  DartType? get matchedValueType;
+
   /// Return the precedence of this pattern.
   ///
   /// The precedence is a positive integer value that defines how the source
@@ -1762,20 +1783,14 @@
 ///
 /// Clients may not extend, implement or mix-in this class.
 @experimental
-abstract class DeclaredVariablePattern implements DartPattern {
-  /// Return the element associated with this declaration, or `null` if either
-  /// the variable name is `_` (in which case no variable is defined) or the AST
+abstract class DeclaredVariablePattern implements VariablePattern {
+  /// Return the element associated with this declaration, or `null` if the AST
   /// structure has not been resolved.
-  VariablePatternElement? get declaredElement;
+  BindPatternVariableElement? get declaredElement;
 
-  /// The 'var' or 'final' keyword used when there is no [type], or `null` if a
-  /// type is given.
+  /// The 'var' or 'final' keyword.
   Token? get keyword;
 
-  /// The name of the variable being bound, if `_` then no variable is bound,
-  /// and [declaredElement] is `null`.
-  Token get name;
-
   /// The type that the variable is required to match, or `null` if any type is
   /// matched.
   TypeAnnotation? get type;
@@ -3491,16 +3506,16 @@
 /// Clients may not extend, implement or mix-in this class.
 @experimental
 abstract class ListPattern implements DartPattern {
-  /// The required type, specified by [typeArguments] or inferred from the
-  /// matched value type; or `null` if the node is not resolved yet.
-  DartType? requiredType;
-
   /// Return the elements in this pattern.
   NodeList<ListPatternElement> get elements;
 
   /// Return the left square bracket.
   Token get leftBracket;
 
+  /// The required type, specified by [typeArguments] or inferred from the
+  /// matched value type; or `null` if the node is not resolved yet.
+  DartType? get requiredType;
+
   /// Return the right square bracket.
   Token get rightBracket;
 
@@ -3529,6 +3544,42 @@
 /// Clients may not extend, implement or mix-in this class.
 abstract class Literal implements Expression {}
 
+/// A logical-and pattern.
+///
+///    logicalAndPattern ::=
+///        [DartPattern] '&&' [DartPattern]
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class LogicalAndPattern implements DartPattern {
+  /// The left sub-pattern.
+  DartPattern get leftOperand;
+
+  /// The `&&` operator.
+  Token get operator;
+
+  /// The right sub-pattern.
+  DartPattern get rightOperand;
+}
+
+/// A logical-or pattern.
+///
+///    logicalOrPattern ::=
+///        [DartPattern] '||' [DartPattern]
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class LogicalOrPattern implements DartPattern {
+  /// The left sub-pattern.
+  DartPattern get leftOperand;
+
+  /// The `||` operator.
+  Token get operator;
+
+  /// The right sub-pattern.
+  DartPattern get rightOperand;
+}
+
 /// A single key/value pair in a map literal.
 ///
 ///    mapLiteralEntry ::=
@@ -3557,16 +3608,15 @@
 /// Clients may not extend, implement or mix-in this class.
 @experimental
 abstract class MapPattern implements DartPattern {
-  /// The required type, specified by [typeArguments] or inferred from the
-  /// matched value type; or `null` if the node is not resolved yet.
-  DartType? requiredType;
-
   /// Return the elements in this pattern.
   NodeList<MapPatternElement> get elements;
 
   /// Return the left curly bracket.
   Token get leftBracket;
 
+  /// The matched value type, or `null` if the node is not resolved yet.
+  DartType? get requiredType;
+
   /// Return the right curly bracket.
   Token get rightBracket;
 
@@ -3763,9 +3813,11 @@
 /// The declaration of a mixin.
 ///
 ///    mixinDeclaration ::=
-///        'sealed'? 'mixin' name [TypeParameterList]?
+///        mixinModifiers? 'mixin' name [TypeParameterList]?
 ///        [OnClause]? [ImplementsClause]? '{' [ClassMember]* '}'
 ///
+///    mixinModifiers ::= 'sealed' | 'base' | 'interface' | 'final'
+///
 /// Clients may not extend, implement or mix-in this class.
 abstract class MixinDeclaration implements MixinOrAugmentationDeclaration {
   @override
@@ -3805,6 +3857,9 @@
 @experimental
 abstract class MixinOrAugmentationDeclaration
     implements NamedCompilationUnitMember {
+  /// Return the 'base' keyword, or `null` if the keyword was absent.
+  Token? get baseKeyword;
+
   @override
   MixinOrAugmentationElement? get declaredElement;
 
@@ -3812,10 +3867,16 @@
   @override
   MixinOrAugmentationElement? get declaredElement2;
 
+  /// Return the 'final' keyword, or `null` if the keyword was absent.
+  Token? get finalKeyword;
+
   /// Returns the `implements` clause for the mixin, or `null` if the mixin
   /// does not implement any interfaces.
   ImplementsClause? get implementsClause;
 
+  /// Return the 'interface' keyword, or `null` if the keyword was absent.
+  Token? get interfaceKeyword;
+
   /// Returns the left curly bracket.
   Token get leftBracket;
 
@@ -4014,6 +4075,36 @@
   List<AstNode> get sortedCommentAndAnnotations;
 }
 
+/// A null-assert pattern.
+///
+///    nullAssertPattern ::=
+///        [DartPattern] '!'
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class NullAssertPattern implements DartPattern {
+  /// The `!` token.
+  Token get operator;
+
+  /// The sub-pattern.
+  DartPattern get pattern;
+}
+
+/// A null-check pattern.
+///
+///    nullCheckPattern ::=
+///        [DartPattern] '?'
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class NullCheckPattern implements DartPattern {
+  /// The `?` token.
+  Token get operator;
+
+  /// The sub-pattern.
+  DartPattern get pattern;
+}
+
 /// A null literal expression.
 ///
 ///    nullLiteral ::=
@@ -4046,13 +4137,13 @@
 /// An object pattern.
 ///
 ///    objectPattern ::=
-///        [Identifier] [TypeArgumentList]? '(' [RecordPatternField] ')'
+///        [Identifier] [TypeArgumentList]? '(' [PatternField] ')'
 ///
 /// Clients may not extend, implement or mix-in this class.
 @experimental
 abstract class ObjectPattern implements DartPattern {
   /// Return the patterns matching the properties of the object.
-  NodeList<RecordPatternField> get fields;
+  NodeList<PatternField> get fields;
 
   /// Return the left parenthesis.
   Token get leftParenthesis;
@@ -4178,6 +4269,42 @@
   DartPattern get pattern;
 }
 
+/// A field in an object or record pattern.
+///
+///    patternField ::=
+///        [PatternFieldName]? [DartPattern]
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class PatternField implements AstNode {
+  /// The element referenced explicitly by [name], or implicitly by the
+  /// variable pattern inside [pattern]. Is `null` if not resolved yet,
+  /// not `null` inside valid [ObjectPattern]s, always `null` inside
+  /// [RecordPattern]s.
+  Element? get element;
+
+  /// The name of the field, or `null` if the field is a positional field.
+  PatternFieldName? get name;
+
+  /// The pattern used to match the corresponding record field.
+  DartPattern get pattern;
+}
+
+/// A field name in an object or record pattern field.
+///
+///    patternFieldName ::=
+///        [Token]? ':'
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class PatternFieldName implements AstNode {
+  /// The colon following the name.
+  Token get colon;
+
+  /// The name of the field.
+  Token? get name;
+}
+
 /// A pattern variable declaration.
 ///
 ///    patternDeclaration ::=
@@ -4233,21 +4360,6 @@
   Token get operator;
 }
 
-/// A postfix (unary) pattern.
-///
-///    postfixPattern ::=
-///        [DartPattern] ('?' | '!')
-///
-/// Clients may not extend, implement or mix-in this class.
-@experimental
-abstract class PostfixPattern implements DartPattern {
-  /// Return the pattern used to compute the operand.
-  DartPattern get operand;
-
-  /// Return the unary operator being applied.
-  Token get operator;
-}
-
 /// An identifier that is prefixed or an access to an object property where the
 /// target of the property access is a simple identifier.
 ///
@@ -4367,13 +4479,13 @@
 /// A record pattern.
 ///
 ///    recordPattern ::=
-///        '(' [RecordPatternField] (',' [RecordPatternField])* ')'
+///        '(' [PatternField] (',' [PatternField])* ')'
 ///
 /// Clients may not extend, implement or mix-in this class.
 @experimental
 abstract class RecordPattern implements DartPattern {
   /// Return the fields of the record pattern.
-  NodeList<RecordPatternField> get fields;
+  NodeList<PatternField> get fields;
 
   /// Return the left parenthesis.
   Token get leftParenthesis;
@@ -4382,40 +4494,6 @@
   Token get rightParenthesis;
 }
 
-/// A field in a record pattern.
-///
-///    recordPatternField ::=
-///        [RecordPatternFieldName]? [DartPattern]
-///
-/// Clients may not extend, implement or mix-in this class.
-@experimental
-abstract class RecordPatternField implements AstNode {
-  /// The element referenced explicitly by [fieldName], or implicitly by the
-  /// variable pattern inside [pattern].
-  Element? get fieldElement;
-
-  /// The name of the field, or `null` if the field is a positional field.
-  RecordPatternFieldName? get fieldName;
-
-  /// The pattern used to match the corresponding record field.
-  DartPattern get pattern;
-}
-
-/// A field name in a record pattern field.
-///
-///    recordPatternField ::=
-///        [Token]? ':'
-///
-/// Clients may not extend, implement or mix-in this class.
-@experimental
-abstract class RecordPatternFieldName implements AstNode {
-  /// The colon following the name.
-  Token get colon;
-
-  /// The name of the field.
-  Token? get name;
-}
-
 /// A record type.
 ///
 /// recordType ::=
@@ -5451,6 +5529,16 @@
   VariableDeclarationList get variables;
 }
 
+/// The shared interface of [AssignedVariablePattern] and
+/// [DeclaredVariablePattern].
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class VariablePattern implements DartPattern {
+  /// The name of the variable declared or referenced by the pattern.
+  Token get name;
+}
+
 /// A guard in a pattern-based `case` in a `switch` statement, `switch`
 /// expression, `if` statement, or `if` element.
 ///
@@ -5492,6 +5580,25 @@
   Token get whileKeyword;
 }
 
+/// A wildcard pattern.
+///
+///    wildcardPattern ::=
+///        ( 'var' | 'final' | 'final'? [TypeAnnotation])? '_'
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class WildcardPattern implements DartPattern {
+  /// The 'var' or 'final' keyword.
+  Token? get keyword;
+
+  /// The `_` token.
+  Token get name;
+
+  /// The type that the pattern is required to match, or `null` if any type is
+  /// matched.
+  TypeAnnotation? get type;
+}
+
 /// The with clause in a class declaration.
 ///
 ///    withClause ::=
diff --git a/analyzer/lib/dart/ast/visitor.dart b/analyzer/lib/dart/ast/visitor.dart
index 8ae61e3..770a231 100644
--- a/analyzer/lib/dart/ast/visitor.dart
+++ b/analyzer/lib/dart/ast/visitor.dart
@@ -168,9 +168,6 @@
   R? visitBinaryExpression(BinaryExpression node) => visitExpression(node);
 
   @override
-  R? visitBinaryPattern(BinaryPattern node) => visitDartPattern(node);
-
-  @override
   R? visitBlock(Block node) => visitStatement(node);
 
   @override
@@ -481,6 +478,12 @@
   R? visitLiteral(Literal node) => visitExpression(node);
 
   @override
+  R? visitLogicalAndPattern(LogicalAndPattern node) => visitDartPattern(node);
+
+  @override
+  R? visitLogicalOrPattern(LogicalOrPattern node) => visitDartPattern(node);
+
+  @override
   R? visitMapLiteralEntry(MapLiteralEntry node) => visitCollectionElement(node);
 
   @override
@@ -528,6 +531,12 @@
       visitFormalParameter(node);
 
   @override
+  R? visitNullAssertPattern(NullAssertPattern node) => visitDartPattern(node);
+
+  @override
+  R? visitNullCheckPattern(NullCheckPattern node) => visitDartPattern(node);
+
+  @override
   R? visitNullLiteral(NullLiteral node) => visitLiteral(node);
 
   @override
@@ -554,6 +563,12 @@
   R? visitPatternAssignment(PatternAssignment node) => visitExpression(node);
 
   @override
+  R? visitPatternField(PatternField node) => visitNode(node);
+
+  @override
+  R? visitPatternFieldName(PatternFieldName node) => visitNode(node);
+
+  @override
   R? visitPatternVariableDeclaration(PatternVariableDeclaration node) =>
       visitNode(node);
 
@@ -566,9 +581,6 @@
   R? visitPostfixExpression(PostfixExpression node) => visitExpression(node);
 
   @override
-  R? visitPostfixPattern(PostfixPattern node) => visitDartPattern(node);
-
-  @override
   R? visitPrefixedIdentifier(PrefixedIdentifier node) => visitIdentifier(node);
 
   @override
@@ -584,13 +596,6 @@
   R? visitRecordPattern(RecordPattern node) => visitDartPattern(node);
 
   @override
-  R? visitRecordPatternField(RecordPatternField node) => visitNode(node);
-
-  @override
-  R? visitRecordPatternFieldName(RecordPatternFieldName node) =>
-      visitNode(node);
-
-  @override
   R? visitRecordTypeAnnotation(RecordTypeAnnotation node) =>
       visitTypeAnnotation(node);
 
@@ -748,6 +753,9 @@
   R? visitWhileStatement(WhileStatement node) => visitStatement(node);
 
   @override
+  R? visitWildcardPattern(WildcardPattern node) => visitDartPattern(node);
+
+  @override
   R? visitWithClause(WithClause node) => visitNode(node);
 
   @override
@@ -835,12 +843,6 @@
   }
 
   @override
-  R? visitBinaryPattern(BinaryPattern node) {
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
   R? visitBlock(Block node) {
     node.visitChildren(this);
     return null;
@@ -1321,6 +1323,18 @@
   }
 
   @override
+  R? visitLogicalAndPattern(LogicalAndPattern node) {
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  R? visitLogicalOrPattern(LogicalOrPattern node) {
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
   R? visitMapLiteralEntry(MapLiteralEntry node) {
     node.visitChildren(this);
     return null;
@@ -1381,6 +1395,18 @@
   }
 
   @override
+  R? visitNullAssertPattern(NullAssertPattern node) {
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  R? visitNullCheckPattern(NullCheckPattern node) {
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
   R? visitNullLiteral(NullLiteral node) {
     node.visitChildren(this);
     return null;
@@ -1429,6 +1455,18 @@
   }
 
   @override
+  R? visitPatternField(PatternField node) {
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
+  R? visitPatternFieldName(PatternFieldName node) {
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
   R? visitPatternVariableDeclaration(PatternVariableDeclaration node) {
     node.visitChildren(this);
     return null;
@@ -1448,12 +1486,6 @@
   }
 
   @override
-  R? visitPostfixPattern(PostfixPattern node) {
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
   R? visitPrefixedIdentifier(PrefixedIdentifier node) {
     node.visitChildren(this);
     return null;
@@ -1484,18 +1516,6 @@
   }
 
   @override
-  R? visitRecordPatternField(RecordPatternField node) {
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
-  R? visitRecordPatternFieldName(RecordPatternFieldName node) {
-    node.visitChildren(this);
-    return null;
-  }
-
-  @override
   R? visitRecordTypeAnnotation(RecordTypeAnnotation node) {
     node.visitChildren(this);
     return null;
@@ -1739,6 +1759,12 @@
   }
 
   @override
+  R? visitWildcardPattern(WildcardPattern node) {
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
   R? visitWithClause(WithClause node) {
     node.visitChildren(this);
     return null;
@@ -1795,9 +1821,6 @@
   R? visitBinaryExpression(BinaryExpression node) => null;
 
   @override
-  R? visitBinaryPattern(BinaryPattern node) => null;
-
-  @override
   R? visitBlock(Block node) => null;
 
   @override
@@ -2043,6 +2066,12 @@
   R? visitListPattern(ListPattern node) => null;
 
   @override
+  R? visitLogicalAndPattern(LogicalAndPattern node) => null;
+
+  @override
+  R? visitLogicalOrPattern(LogicalOrPattern node) => null;
+
+  @override
   R? visitMapLiteralEntry(MapLiteralEntry node) => null;
 
   @override
@@ -2073,6 +2102,12 @@
   R? visitNativeFunctionBody(NativeFunctionBody node) => null;
 
   @override
+  R? visitNullAssertPattern(NullAssertPattern node) => null;
+
+  @override
+  R? visitNullCheckPattern(NullCheckPattern node) => null;
+
+  @override
   R? visitNullLiteral(NullLiteral node) => null;
 
   @override
@@ -2097,6 +2132,12 @@
   R? visitPatternAssignment(PatternAssignment node) => null;
 
   @override
+  R? visitPatternField(PatternField node) => null;
+
+  @override
+  R? visitPatternFieldName(PatternFieldName node) => null;
+
+  @override
   R? visitPatternVariableDeclaration(PatternVariableDeclaration node) => null;
 
   @override
@@ -2108,9 +2149,6 @@
   R? visitPostfixExpression(PostfixExpression node) => null;
 
   @override
-  R? visitPostfixPattern(PostfixPattern node) => null;
-
-  @override
   R? visitPrefixedIdentifier(PrefixedIdentifier node) => null;
 
   @override
@@ -2125,11 +2163,8 @@
   @override
   R? visitRecordPattern(RecordPattern node) => null;
 
-  @override
-  R? visitRecordPatternField(RecordPatternField node) => null;
-
-  @override
-  R? visitRecordPatternFieldName(RecordPatternFieldName node) => null;
+  @Deprecated('Use visitPatternField() instead')
+  void visitRecordPatternField(RecordPatternField node) {}
 
   @override
   R? visitRecordTypeAnnotation(RecordTypeAnnotation node) => null;
@@ -2260,6 +2295,9 @@
   R? visitWhileStatement(WhileStatement node) => null;
 
   @override
+  R? visitWildcardPattern(WildcardPattern node) => null;
+
+  @override
   R? visitWithClause(WithClause node) => null;
 
   @override
@@ -2312,9 +2350,6 @@
   R? visitBinaryExpression(BinaryExpression node) => _throw(node);
 
   @override
-  R? visitBinaryPattern(BinaryPattern node) => _throw(node);
-
-  @override
   R? visitBlock(Block node) => _throw(node);
 
   @override
@@ -2565,6 +2600,12 @@
   R? visitListPattern(ListPattern node) => _throw(node);
 
   @override
+  R? visitLogicalAndPattern(LogicalAndPattern node) => _throw(node);
+
+  @override
+  R? visitLogicalOrPattern(LogicalOrPattern node) => _throw(node);
+
+  @override
   R? visitMapLiteralEntry(MapLiteralEntry node) => _throw(node);
 
   @override
@@ -2595,6 +2636,12 @@
   R? visitNativeFunctionBody(NativeFunctionBody node) => _throw(node);
 
   @override
+  R? visitNullAssertPattern(NullAssertPattern node) => _throw(node);
+
+  @override
+  R? visitNullCheckPattern(NullCheckPattern node) => _throw(node);
+
+  @override
   R? visitNullLiteral(NullLiteral node) => _throw(node);
 
   @override
@@ -2619,6 +2666,12 @@
   R? visitPatternAssignment(PatternAssignment node) => _throw(node);
 
   @override
+  R? visitPatternField(PatternField node) => _throw(node);
+
+  @override
+  R? visitPatternFieldName(PatternFieldName node) => _throw(node);
+
+  @override
   R? visitPatternVariableDeclaration(PatternVariableDeclaration node) =>
       _throw(node);
 
@@ -2631,9 +2684,6 @@
   R? visitPostfixExpression(PostfixExpression node) => _throw(node);
 
   @override
-  R? visitPostfixPattern(PostfixPattern node) => _throw(node);
-
-  @override
   R? visitPrefixedIdentifier(PrefixedIdentifier node) => _throw(node);
 
   @override
@@ -2649,12 +2699,6 @@
   R? visitRecordPattern(RecordPattern node) => _throw(node);
 
   @override
-  R? visitRecordPatternField(RecordPatternField node) => _throw(node);
-
-  @override
-  R? visitRecordPatternFieldName(RecordPatternFieldName node) => _throw(node);
-
-  @override
   R? visitRecordTypeAnnotation(RecordTypeAnnotation node) => _throw(node);
 
   @override
@@ -2785,6 +2829,9 @@
   R? visitWhileStatement(WhileStatement node) => _throw(node);
 
   @override
+  R? visitWildcardPattern(WildcardPattern node) => _throw(node);
+
+  @override
   R? visitWithClause(WithClause node) => _throw(node);
 
   @override
@@ -2903,14 +2950,6 @@
   }
 
   @override
-  T? visitBinaryPattern(BinaryPattern node) {
-    stopwatch.start();
-    T? result = _baseVisitor.visitBinaryPattern(node);
-    stopwatch.stop();
-    return result;
-  }
-
-  @override
   T? visitBlock(Block node) {
     stopwatch.start();
     T? result = _baseVisitor.visitBlock(node);
@@ -3551,6 +3590,22 @@
   }
 
   @override
+  T? visitLogicalAndPattern(LogicalAndPattern node) {
+    stopwatch.start();
+    T? result = _baseVisitor.visitLogicalAndPattern(node);
+    stopwatch.stop();
+    return result;
+  }
+
+  @override
+  T? visitLogicalOrPattern(LogicalOrPattern node) {
+    stopwatch.start();
+    T? result = _baseVisitor.visitLogicalOrPattern(node);
+    stopwatch.stop();
+    return result;
+  }
+
+  @override
   T? visitMapLiteralEntry(MapLiteralEntry node) {
     stopwatch.start();
     T? result = _baseVisitor.visitMapLiteralEntry(node);
@@ -3631,6 +3686,22 @@
   }
 
   @override
+  T? visitNullAssertPattern(NullAssertPattern node) {
+    stopwatch.start();
+    T? result = _baseVisitor.visitNullAssertPattern(node);
+    stopwatch.stop();
+    return result;
+  }
+
+  @override
+  T? visitNullCheckPattern(NullCheckPattern node) {
+    stopwatch.start();
+    T? result = _baseVisitor.visitNullCheckPattern(node);
+    stopwatch.stop();
+    return result;
+  }
+
+  @override
   T? visitNullLiteral(NullLiteral node) {
     stopwatch.start();
     T? result = _baseVisitor.visitNullLiteral(node);
@@ -3695,6 +3766,22 @@
   }
 
   @override
+  T? visitPatternField(PatternField node) {
+    stopwatch.start();
+    T? result = _baseVisitor.visitPatternField(node);
+    stopwatch.stop();
+    return result;
+  }
+
+  @override
+  T? visitPatternFieldName(PatternFieldName node) {
+    stopwatch.start();
+    T? result = _baseVisitor.visitPatternFieldName(node);
+    stopwatch.stop();
+    return result;
+  }
+
+  @override
   T? visitPatternVariableDeclaration(PatternVariableDeclaration node) {
     stopwatch.start();
     T? result = _baseVisitor.visitPatternVariableDeclaration(node);
@@ -3720,14 +3807,6 @@
   }
 
   @override
-  T? visitPostfixPattern(PostfixPattern node) {
-    stopwatch.start();
-    T? result = _baseVisitor.visitPostfixPattern(node);
-    stopwatch.stop();
-    return result;
-  }
-
-  @override
   T? visitPrefixedIdentifier(PrefixedIdentifier node) {
     stopwatch.start();
     T? result = _baseVisitor.visitPrefixedIdentifier(node);
@@ -3768,22 +3847,6 @@
   }
 
   @override
-  T? visitRecordPatternField(RecordPatternField node) {
-    stopwatch.start();
-    T? result = _baseVisitor.visitRecordPatternField(node);
-    stopwatch.stop();
-    return result;
-  }
-
-  @override
-  T? visitRecordPatternFieldName(RecordPatternFieldName node) {
-    stopwatch.start();
-    T? result = _baseVisitor.visitRecordPatternFieldName(node);
-    stopwatch.stop();
-    return result;
-  }
-
-  @override
   T? visitRecordTypeAnnotation(RecordTypeAnnotation node) {
     stopwatch.start();
     T? result = _baseVisitor.visitRecordTypeAnnotation(node);
@@ -4107,6 +4170,14 @@
   }
 
   @override
+  T? visitWildcardPattern(WildcardPattern node) {
+    stopwatch.start();
+    T? result = _baseVisitor.visitWildcardPattern(node);
+    stopwatch.stop();
+    return result;
+  }
+
+  @override
   T? visitWithClause(WithClause node) {
     stopwatch.start();
     T? result = _baseVisitor.visitWithClause(node);
@@ -4174,9 +4245,6 @@
   R? visitBinaryExpression(BinaryExpression node) => visitNode(node);
 
   @override
-  R? visitBinaryPattern(BinaryPattern node) => visitNode(node);
-
-  @override
   R? visitBlock(Block node) => visitNode(node);
 
   @override
@@ -4435,6 +4503,12 @@
   R? visitListPattern(ListPattern node) => visitNode(node);
 
   @override
+  R? visitLogicalAndPattern(LogicalAndPattern node) => visitNode(node);
+
+  @override
+  R? visitLogicalOrPattern(LogicalOrPattern node) => visitNode(node);
+
+  @override
   R? visitMapLiteralEntry(MapLiteralEntry node) => visitNode(node);
 
   @override
@@ -4470,6 +4544,12 @@
   }
 
   @override
+  R? visitNullAssertPattern(NullAssertPattern node) => visitNode(node);
+
+  @override
+  R? visitNullCheckPattern(NullCheckPattern node) => visitNode(node);
+
+  @override
   R? visitNullLiteral(NullLiteral node) => visitNode(node);
 
   @override
@@ -4495,6 +4575,12 @@
   R? visitPatternAssignment(PatternAssignment node) => visitNode(node);
 
   @override
+  R? visitPatternField(PatternField node) => visitNode(node);
+
+  @override
+  R? visitPatternFieldName(PatternFieldName node) => visitNode(node);
+
+  @override
   R? visitPatternVariableDeclaration(PatternVariableDeclaration node) =>
       visitNode(node);
 
@@ -4507,9 +4593,6 @@
   R? visitPostfixExpression(PostfixExpression node) => visitNode(node);
 
   @override
-  R? visitPostfixPattern(PostfixPattern node) => visitNode(node);
-
-  @override
   R? visitPrefixedIdentifier(PrefixedIdentifier node) => visitNode(node);
 
   @override
@@ -4525,13 +4608,6 @@
   R? visitRecordPattern(RecordPattern node) => visitNode(node);
 
   @override
-  R? visitRecordPatternField(RecordPatternField node) => visitNode(node);
-
-  @override
-  R? visitRecordPatternFieldName(RecordPatternFieldName node) =>
-      visitNode(node);
-
-  @override
   R? visitRecordTypeAnnotation(RecordTypeAnnotation node) => visitNode(node);
 
   @override
@@ -4663,6 +4739,9 @@
   R? visitWhileStatement(WhileStatement node) => visitNode(node);
 
   @override
+  R? visitWildcardPattern(WildcardPattern node) => visitNode(node);
+
+  @override
   R? visitWithClause(WithClause node) => visitNode(node);
 
   @override
diff --git a/analyzer/lib/dart/element/element.dart b/analyzer/lib/dart/element/element.dart
index 4cbfe2f..346e694 100644
--- a/analyzer/lib/dart/element/element.dart
+++ b/analyzer/lib/dart/element/element.dart
@@ -161,6 +161,12 @@
   List<InterfaceType> get superclassConstraints;
 }
 
+/// A pattern variable that is explicitly declared.
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class BindPatternVariableElement implements PatternVariableElement {}
+
 /// A class augmentation, defined by a class augmentation declaration.
 ///
 /// Clients may not extend, implement or mix-in this class.
@@ -194,6 +200,11 @@
   /// <i>abstract</i> is different from <i>has unimplemented members</i>.
   bool get isAbstract;
 
+  /// Return `true` if this class is a base class. A class is a base class if it
+  /// has an explicit `base` modifier.
+  @experimental
+  bool get isBase;
+
   /// Return `true` if this class represents the class 'Enum' defined in the
   /// dart:core library.
   bool get isDartCoreEnum;
@@ -202,10 +213,36 @@
   /// dart:core library.
   bool get isDartCoreObject;
 
+  /// Return `true` if this element has the property where, in a switch, if you
+  /// cover all of the subtypes of this element, then the compiler knows that
+  /// you have covered all possible instances of the type.
+  @experimental
+  bool get isExhaustive;
+
+  /// Return `true` if this class is a final class. A class is a final class if
+  /// it has an explicit `final` modifier.
+  @experimental
+  bool get isFinal;
+
+  /// Return `true` if this class is an interface class. A class is an interface
+  /// class if it has an explicit `interface` modifier.
+  @experimental
+  bool get isInterface;
+
   /// Return `true` if this class is a mixin application.  A class is a mixin
   /// application if it was declared using the syntax "class A = B with C;".
   bool get isMixinApplication;
 
+  /// Return `true` if this class is a mixin class. A class is a mixin class if
+  /// it has an explicit `mixin` modifier.
+  @experimental
+  bool get isMixinClass;
+
+  /// Return `true` if this class is a sealed class. A class is a sealed class
+  /// if it has an explicit `sealed` modifier.
+  @experimental
+  bool get isSealed;
+
   /// Return `true` if this class can validly be used as a mixin when defining
   /// another class. For classes defined by a class declaration or a mixin
   /// application, the behavior of this method is defined by the Dart Language
@@ -231,6 +268,21 @@
   /// guard against infinite loops.
   @Deprecated('This getter is implemented only for MixinElement')
   List<InterfaceType> get superclassConstraints;
+
+  /// Return `true` if this element, assuming that it is within scope, is
+  /// extendable to classes in the given [library].
+  @experimental
+  bool isExtendableIn(LibraryElement library);
+
+  /// Return `true` if this element, assuming that it is within scope, is
+  /// implementable to classes, mixins, and enums in the given [library].
+  @experimental
+  bool isImplementableIn(LibraryElement library);
+
+  /// Return `true` if this element, assuming that it is within scope, is
+  /// able to be mixed-in by classes and enums in the given [library].
+  @experimental
+  bool isMixableIn(LibraryElement library);
 }
 
 /// An element that is contained within a [ClassElement].
@@ -586,6 +638,9 @@
   /// Return `true` if this element has an annotation of the form `@protected`.
   bool get hasProtected;
 
+  /// Return `true` if this element has an annotation of the form `@reopen`.
+  bool get hasReopen;
+
   /// Return `true` if this element has an annotation of the form `@required`.
   bool get hasRequired;
 
@@ -826,6 +881,10 @@
   bool get isProxy;
 
   /// Return `true` if this annotation marks the associated member as being
+  /// reopened.
+  bool get isReopen;
+
+  /// Return `true` if this annotation marks the associated member as being
   /// required.
   bool get isRequired;
 
@@ -1627,6 +1686,20 @@
   String get name;
 }
 
+/// A pattern variable that is a join of other pattern variables, created
+/// for a logical-or patterns, or shared `case` bodies in `switch` statements.
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class JoinPatternVariableElement implements PatternVariableElement {
+  /// Returns `true` if [variables] are consistent, present in all branches,
+  /// and have the same type and finality.
+  bool get isConsistent;
+
+  /// Returns the variables that join into this variable.
+  List<PatternVariableElement> get variables;
+}
+
 /// A label associated with a statement.
 ///
 /// Clients may not extend, implement or mix-in this class.
@@ -1916,6 +1989,32 @@
   /// Returns the result of applying augmentations to this element.
   AugmentedMixinElement get augmented;
 
+  /// Return `true` if this mixin is a base mixin. A mixin is a base mixin if it
+  /// has an explicit `base` modifier.
+  @experimental
+  bool get isBase;
+
+  /// Return `true` if this element has the property where, in a switch, if you
+  /// cover all of the subtypes of this element, then the compiler knows that
+  /// you have covered all possible instances of the type.
+  @experimental
+  bool get isExhaustive;
+
+  /// Return `true` if this mixin is a final mixin. A mixin is a final mixin if
+  /// it has an explicit `final` modifier.
+  @experimental
+  bool get isFinal;
+
+  /// Return `true` if this mixin is an interface mixin. A mixin is an interface
+  /// mixin if it has an explicit `interface` modifier.
+  @experimental
+  bool get isInterface;
+
+  /// Return `true` if this mixin is a sealed mixin. A mixin is a sealed mixin
+  /// if it has an explicit `sealed` modifier.
+  @experimental
+  bool get isSealed;
+
   /// Returns the superclass constraints defined for this mixin. If the
   /// declaration does not have an `on` clause, then the list will contain
   /// the type for the class `Object`.
@@ -1926,6 +2025,16 @@
   /// a cycle. Clients that traverse the inheritance structure must explicitly
   /// guard against infinite loops.
   List<InterfaceType> get superclassConstraints;
+
+  /// Return `true` if this element, assuming that it is within scope, is
+  /// implementable to classes, mixins, and enums in the given [library].
+  @experimental
+  bool isImplementableIn(LibraryElement library);
+
+  /// Return `true` if this element, assuming that it is within scope, is
+  /// able to be mixed-in by classes and enums in the given [library].
+  @experimental
+  bool isMixableIn(LibraryElement library);
 }
 
 /// Shared interface between [MixinElement] and [MixinAugmentationElement].
@@ -2072,6 +2181,17 @@
   DirectiveUri get uri;
 }
 
+/// A pattern variable.
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class PatternVariableElement implements LocalVariableElement {
+  /// Returns the variable in which this variable joins with other pattern
+  /// variables with the same name, in a logical-or pattern, or shared case
+  /// scope.
+  JoinPatternVariableElement? get join;
+}
+
 /// A prefix used to import one or more libraries into another library.
 ///
 /// Clients may not extend, implement or mix-in this class.
@@ -2429,33 +2549,6 @@
   DartObject? computeConstantValue();
 }
 
-/// A pattern variable that is explicitly declared.
-///
-/// Clients may not extend, implement or mix-in this class.
-@experimental
-abstract class VariablePatternBindElement implements VariablePatternElement {}
-
-/// A pattern variable.
-///
-/// Clients may not extend, implement or mix-in this class.
-@experimental
-abstract class VariablePatternElement implements LocalVariableElement {}
-
-/// A pattern variable that is a join of other pattern variables, created
-/// for a logical-or patterns, or shared `case` bodies in `switch` statements
-/// or expressions.
-///
-/// Clients may not extend, implement or mix-in this class.
-@experimental
-abstract class VariablePatternJoinElement implements VariablePatternElement {
-  /// Returns the variables that join into this variable.
-  List<VariablePatternElement> get components;
-
-  /// Returns `true` if [components] are consistent, present in all branches,
-  /// and have the same type and finality.
-  bool get isConsistent;
-}
-
 /// This class exists to provide non-nullable overrides for existing elements,
 /// as opposite to artificial "multiply defined" element.
 abstract class _ExistingElement implements Element {
diff --git a/analyzer/lib/dart/element/type.dart b/analyzer/lib/dart/element/type.dart
index 0b6e1fb..fcb6243 100644
--- a/analyzer/lib/dart/element/type.dart
+++ b/analyzer/lib/dart/element/type.dart
@@ -22,6 +22,7 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type_visitor.dart';
+import 'package:analyzer/src/dart/element/type.dart' show RecordTypeImpl;
 import 'package:meta/meta.dart';
 
 /// The type associated with elements in the element model.
@@ -431,6 +432,13 @@
 /// Clients may not extend, implement or mix-in this class.
 @experimental
 abstract class RecordType implements DartType {
+  /// Creates a record type from of [positional] and [named] fields.
+  factory RecordType({
+    required List<DartType> positional,
+    required Map<String, DartType> named,
+    required NullabilitySuffix nullabilitySuffix,
+  }) = RecordTypeImpl.fromApi;
+
   @override
   Null get element;
 
diff --git a/analyzer/lib/src/analysis_options/analysis_options_provider.dart b/analyzer/lib/src/analysis_options/analysis_options_provider.dart
index 4269e6b..8975553 100644
--- a/analyzer/lib/src/analysis_options/analysis_options_provider.dart
+++ b/analyzer/lib/src/analysis_options/analysis_options_provider.dart
@@ -56,9 +56,10 @@
   }
 
   /// Provide the options found in [source].
-  /// Recursively merge options referenced by an include directive
-  /// and remove the include directive from the resulting options map.
-  /// Return an empty options map if the file does not exist.
+  ///
+  /// Recursively merge options referenced by an `include` directive and remove
+  /// the `include` directive from the resulting options map. Return an empty
+  /// options map if the file does not exist.
   YamlMap getOptionsFromSource(Source source) {
     YamlMap options = getOptionsFromString(_readAnalysisOptions(source));
     var node = options.valueAt(AnalyzerOptions.include);
diff --git a/analyzer/lib/src/analysis_options/error/option_codes.g.dart b/analyzer/lib/src/analysis_options/error/option_codes.g.dart
index fd73f75..a7e039f 100644
--- a/analyzer/lib/src/analysis_options/error/option_codes.g.dart
+++ b/analyzer/lib/src/analysis_options/error/option_codes.g.dart
@@ -130,7 +130,7 @@
   ///  An error code indicating a specified include file could not be found.
   ///
   ///  Parameters:
-  ///  0: the uri of the file to be included
+  ///  0: the URI of the file to be included
   ///  1: the path of the file containing the include directive
   ///  2: the path of the context being analyzed
   static const AnalysisOptionsWarningCode INCLUDE_FILE_NOT_FOUND =
@@ -161,6 +161,30 @@
     "Invalid format for the '{0}' section.",
   );
 
+  ///  An error code indicating multiple plugins have been specified as enabled.
+  ///
+  ///  Parameters:
+  ///  0: the name of the first plugin
+  static const AnalysisOptionsWarningCode MULTIPLE_PLUGINS =
+      AnalysisOptionsWarningCode(
+    'MULTIPLE_PLUGINS',
+    "Multiple plugins can't be enabled.",
+    correctionMessage: "Remove all plugins following the first, '{0}'.",
+  );
+
+  ///  An error code indicating a specified include file includes itself recursively.
+  ///
+  ///  Parameters:
+  ///  0: the URI of the file to be included
+  ///  1: the path of the file containing the include directive
+  static const AnalysisOptionsWarningCode RECURSIVE_INCLUDE_FILE =
+      AnalysisOptionsWarningCode(
+    'RECURSIVE_INCLUDE_FILE',
+    "The include file '{0}' in '{1}' includes itself recursively.",
+    correctionMessage:
+        "Try changing the chain of 'include's to not re-include this file.",
+  );
+
   ///  An error code indicating a removed lint rule.
   ///
   ///  Parameters:
diff --git a/analyzer/lib/src/context/builder.dart b/analyzer/lib/src/context/builder.dart
index 2a8df8a..af2102a 100644
--- a/analyzer/lib/src/context/builder.dart
+++ b/analyzer/lib/src/context/builder.dart
@@ -49,7 +49,7 @@
   /// setup the uri mapping.
   void _processEmbedderYaml(Folder libDir, String embedderYaml) {
     try {
-      YamlNode yaml = loadYaml(embedderYaml);
+      var yaml = loadYaml(embedderYaml);
       if (yaml is YamlMap) {
         embedderYamls[libDir] = yaml;
       }
diff --git a/analyzer/lib/src/context/source.dart b/analyzer/lib/src/context/source.dart
index f7d4c55..ad29021 100644
--- a/analyzer/lib/src/context/source.dart
+++ b/analyzer/lib/src/context/source.dart
@@ -9,9 +9,9 @@
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart' as utils;
 import 'package:analyzer/src/source/package_map_resolver.dart';
 import 'package:analyzer/src/util/file_paths.dart' as file_paths;
+import 'package:analyzer/src/utilities/uri_cache.dart';
 import 'package:analyzer/src/workspace/package_build.dart';
 
 /// Return `true` if the given [source] refers to a file that is assumed to be
@@ -67,7 +67,7 @@
     try {
       Uri uri;
       try {
-        uri = Uri.parse(absoluteUri);
+        uri = uriCache.parse(absoluteUri);
       } catch (exception, stackTrace) {
         AnalysisEngine.instance.instrumentationService
             .logInfo('Could not resolve URI: $absoluteUri $stackTrace');
@@ -121,7 +121,8 @@
     }
     try {
       // Force the creation of an escaped URI to deal with spaces, etc.
-      return _internalResolveUri(containingSource, Uri.parse(containedUri));
+      return _internalResolveUri(
+          containingSource, uriCache.parse(containedUri));
     } on FormatException {
       return null;
     } catch (exception, stackTrace) {
@@ -157,7 +158,7 @@
             "$containedUri");
       }
       containedUri =
-          utils.resolveRelativeUri(containingSource.uri, containedUri);
+          uriCache.resolveRelative(containingSource.uri, containedUri);
     }
 
     var result = _absoluteUriToSourceCache[containedUri];
diff --git a/analyzer/lib/src/dart/analysis/context_builder.dart b/analyzer/lib/src/dart/analysis/context_builder.dart
index f872699..cca1f5e 100644
--- a/analyzer/lib/src/dart/analysis/context_builder.dart
+++ b/analyzer/lib/src/dart/analysis/context_builder.dart
@@ -175,7 +175,7 @@
     }
   }
 
-  /// Return the SDK that that should be used to analyze code.
+  /// Return the SDK that should be used to analyze code.
   DartSdk _createSdk({
     required Workspace workspace,
     String? sdkPath,
diff --git a/analyzer/lib/src/dart/analysis/driver.dart b/analyzer/lib/src/dart/analysis/driver.dart
index a7d0485..690064c 100644
--- a/analyzer/lib/src/dart/analysis/driver.dart
+++ b/analyzer/lib/src/dart/analysis/driver.dart
@@ -49,6 +49,7 @@
 import 'package:analyzer/src/summary2/package_bundle_format.dart';
 import 'package:analyzer/src/util/file_paths.dart' as file_paths;
 import 'package:analyzer/src/util/performance/operation_performance.dart';
+import 'package:analyzer/src/utilities/uri_cache.dart';
 
 /// This class computes [AnalysisResult]s for Dart files.
 ///
@@ -58,7 +59,7 @@
 /// analyzed files to the most recent [AnalysisResult] delivered to [results]
 /// for each file. Let the "current file state" represent a map from file path
 /// to the file contents most recently read from that file, or fetched from the
-/// content cache (considering all possible possible file paths, regardless of
+/// content cache (considering all possible file paths, regardless of
 /// whether they're in the set of explicitly analyzed files). Let the
 /// "analysis state" be either "analyzing" or "idle".
 ///
@@ -86,7 +87,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 = 255;
+  static const int DATA_VERSION = 259;
 
   /// The number of exception contexts allowed to write. Once this field is
   /// zero, we stop writing any new exception contexts in this process.
@@ -747,7 +748,7 @@
   /// [uri], which is either resynthesized from the provided external summary
   /// store, or built for a file to which the given [uri] is resolved.
   Future<SomeLibraryElementResult> getLibraryByUri(String uri) async {
-    var uriObj = Uri.parse(uri);
+    var uriObj = uriCache.parse(uri);
     var fileOr = _fsState.getFileForUri(uriObj);
     return fileOr.map(
       (file) async {
@@ -1528,7 +1529,7 @@
     }
     _hasDartCoreDiscovered = true;
 
-    _fsState.getFileForUri(Uri.parse('dart:core')).map(
+    _fsState.getFileForUri(uriCache.parse('dart:core')).map(
       (file) {
         final kind = file?.kind as LibraryFileKind;
         kind.discoverReferencedFiles();
@@ -1654,7 +1655,7 @@
   }
 
   bool _hasLibraryByUri(String uriStr) {
-    var uri = Uri.parse(uriStr);
+    var uri = uriCache.parse(uriStr);
     var fileOr = _fsState.getFileForUri(uri);
     return fileOr.map(
       (file) => file != null && file.exists,
@@ -1772,52 +1773,59 @@
   Future<ResolvedForCompletionResultImpl?> _resolveForCompletion(
     _ResolveForCompletionRequest request,
   ) async {
-    final path = request.path;
-    if (!_isAbsolutePath(path)) {
-      return null;
-    }
+    return request.performance.runAsync('body', (performance) async {
+      final path = request.path;
+      if (!_isAbsolutePath(path)) {
+        return null;
+      }
 
-    if (!_fsState.hasUri(path)) {
-      return null;
-    }
+      if (!_fsState.hasUri(path)) {
+        return null;
+      }
 
-    var file = _fsState.getFileForPath(path);
+      var file = _fsState.getFileForPath(path);
 
-    // Prepare the library - the file itself, or the known library.
-    final kind = file.kind;
-    final library = kind.library ?? kind.asLibrary;
+      // Prepare the library - the file itself, or the known library.
+      final kind = file.kind;
+      final library = kind.library ?? kind.asLibrary;
 
-    await libraryContext.load(
-      targetLibrary: library,
-      performance: OperationPerformanceImpl('<root>'),
-    );
-    var unitElement = libraryContext.computeUnitElement(library, file);
+      await performance.runAsync(
+        'libraryContext',
+        (performance) async {
+          await libraryContext.load(
+            targetLibrary: library,
+            performance: performance,
+          );
+        },
+      );
+      var unitElement = libraryContext.computeUnitElement(library, file);
 
-    var analysisResult = LibraryAnalyzer(
-      analysisOptions as AnalysisOptionsImpl,
-      declaredVariables,
-      libraryContext.elementFactory.libraryOfUri2(library.file.uri),
-      libraryContext.elementFactory.analysisSession.inheritanceManager,
-      library,
-      testingData: testingData,
-    ).analyzeForCompletion(
-      file: file,
-      offset: request.offset,
-      unitElement: unitElement,
-      performance: request.performance,
-    );
+      var analysisResult = LibraryAnalyzer(
+        analysisOptions as AnalysisOptionsImpl,
+        declaredVariables,
+        libraryContext.elementFactory.libraryOfUri2(library.file.uri),
+        libraryContext.elementFactory.analysisSession.inheritanceManager,
+        library,
+        testingData: testingData,
+      ).analyzeForCompletion(
+        file: file,
+        offset: request.offset,
+        unitElement: unitElement,
+        performance: performance,
+      );
 
-    return ResolvedForCompletionResultImpl(
-      analysisSession: currentSession,
-      path: path,
-      uri: file.uri,
-      exists: file.exists,
-      content: file.content,
-      lineInfo: file.lineInfo,
-      parsedUnit: analysisResult.parsedUnit,
-      unitElement: unitElement,
-      resolvedNodes: analysisResult.resolvedNodes,
-    );
+      return ResolvedForCompletionResultImpl(
+        analysisSession: currentSession,
+        path: path,
+        uri: file.uri,
+        exists: file.exists,
+        content: file.content,
+        lineInfo: file.lineInfo,
+        parsedUnit: analysisResult.parsedUnit,
+        unitElement: unitElement,
+        resolvedNodes: analysisResult.resolvedNodes,
+      );
+    });
   }
 
   /// Serialize the given [resolvedUnit] errors and index into bytes.
@@ -2020,7 +2028,7 @@
     }
   }
 
-  /// Notify that there is a change to the [driver], it it might need to
+  /// Notify that there is a change to the [driver], it might need to
   /// perform some work.
   void notify(AnalysisDriverGeneric? driver) {
     // TODO(brianwilkerson) Consider removing the parameter, given that it isn't
diff --git a/analyzer/lib/src/dart/analysis/file_state.dart b/analyzer/lib/src/dart/analysis/file_state.dart
index fc1a2d4..4aab0f0 100644
--- a/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/analyzer/lib/src/dart/analysis/file_state.dart
@@ -4,8 +4,7 @@
 
 import 'dart:typed_data';
 
-import 'package:_fe_analyzer_shared/src/scanner/token_impl.dart'
-    show StringTokenImpl;
+import 'package:_fe_analyzer_shared/src/scanner/string_canonicalizer.dart';
 import 'package:analyzer/dart/analysis/declared_variables.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -29,7 +28,6 @@
 import 'package:analyzer/src/exception/exception.dart';
 import 'package:analyzer/src/generated/parser.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/source/source_resource.dart';
 import 'package:analyzer/src/summary/api_signature.dart';
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
@@ -38,6 +36,8 @@
 import 'package:analyzer/src/util/file_paths.dart' as file_paths;
 import 'package:analyzer/src/util/performance/operation_performance.dart';
 import 'package:analyzer/src/util/uri.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
+import 'package:analyzer/src/utilities/uri_cache.dart';
 import 'package:analyzer/src/workspace/workspace.dart';
 import 'package:collection/collection.dart';
 import 'package:convert/convert.dart';
@@ -570,14 +570,14 @@
       return DirectiveUri();
     }
 
-    final relativeUri = Uri.tryParse(relativeUriStr);
+    final relativeUri = uriCache.tryParse(relativeUriStr);
     if (relativeUri == null) {
       return DirectiveUriWithString(
         relativeUriStr: relativeUriStr,
       );
     }
 
-    final absoluteUri = resolveRelativeUri(uri, relativeUri);
+    final absoluteUri = uriCache.resolveRelative(uri, relativeUri);
     return _fsState.getFileForUri(absoluteUri).map(
       (file) {
         if (file != null) {
@@ -609,18 +609,18 @@
   ) {
     final primaryUri = _buildDirectiveUri(directive.uri);
 
-    final configurationUris = <DirectiveUri>[];
     DirectiveUri? selectedConfigurationUri;
-    for (final configuration in directive.configurations) {
+    final configurationUris = directive.configurations.map((configuration) {
       final configurationUri = _buildDirectiveUri(configuration.uri);
-      configurationUris.add(configurationUri);
       // Maybe select this URI.
       final name = configuration.name;
       final value = configuration.valueOrTrue;
       if (_fsState._declaredVariables.get(name) == value) {
         selectedConfigurationUri ??= configurationUri;
       }
-    }
+      // Include it anyway.
+      return configurationUri;
+    }).toFixedList();
 
     return NamespaceDirectiveUris(
       primary: primaryUri,
@@ -629,14 +629,15 @@
     );
   }
 
-  /// Return the [FileState] for the given [relativeUri], or `null` if the
+  /// Return the [FileState] for the given [relativeUriStr], or `null` if the
   /// URI cannot be parsed, cannot correspond any file, etc.
   Either2<FileState?, ExternalLibrary> _fileForRelativeUri(
-    String relativeUri,
+    String relativeUriStr,
   ) {
     Uri absoluteUri;
     try {
-      absoluteUri = resolveRelativeUri(uri, Uri.parse(relativeUri));
+      var relativeUri = uriCache.parse(relativeUriStr);
+      absoluteUri = uriCache.resolveRelative(uri, relativeUri);
     } on FormatException {
       return Either2.t1(null);
     }
@@ -730,9 +731,8 @@
       override: scanner.overrideVersion,
     );
 
-    // StringToken uses a static instance of StringCanonicalizer, so we need
-    // to clear it explicitly once we are done using it for this file.
-    StringTokenImpl.canonicalizer.clear();
+    // Ensure the string canonicalization cache size is reasonable.
+    pruneStringCanonicalizationCache();
 
     return unit;
   }
@@ -752,8 +752,8 @@
       }
       final Uri absoluteUri;
       try {
-        final relativeUri = Uri.parse(relativeUriStr);
-        absoluteUri = resolveRelativeUri(uri, relativeUri);
+        final relativeUri = uriCache.parse(relativeUriStr);
+        absoluteUri = uriCache.resolveRelative(uri, relativeUri);
       } on FormatException {
         return;
       }
@@ -930,7 +930,7 @@
               .whereType<ConstructorDeclaration>()
               .map((e) => e.name?.lexeme ?? '')
               .where((e) => !e.startsWith('_'))
-              .toList();
+              .toFixedList();
           if (constructors.isNotEmpty) {
             macroClasses.add(
               MacroClass(
@@ -945,8 +945,8 @@
     if (!isDartCore && !hasDartCoreImport) {
       imports.add(
         UnlinkedLibraryImportDirective(
-          combinators: [],
-          configurations: [],
+          combinators: const [],
+          configurations: const [],
           importKeywordOffset: -1,
           isSyntheticDartCore: true,
           prefix: null,
@@ -979,15 +979,15 @@
 
     return UnlinkedUnit(
       apiSignature: Uint8List.fromList(computeUnlinkedApiSignature(unit)),
-      augmentations: augmentations,
-      exports: exports,
-      imports: imports,
+      augmentations: augmentations.toFixedList(),
+      exports: exports.toFixedList(),
+      imports: imports.toFixedList(),
       informativeBytes: writeUnitInformative(unit),
       libraryAugmentationDirective: libraryAugmentationDirective,
       libraryDirective: libraryDirective,
       lineStarts: Uint32List.fromList(unit.lineInfo.lineStarts),
-      macroClasses: macroClasses,
-      parts: parts,
+      macroClasses: macroClasses.toFixedList(),
+      parts: parts.toFixedList(),
       partOfNameDirective: partOfNameDirective,
       partOfUriDirective: partOfUriDirective,
       topLevelDeclarations: topLevelDeclarations,
@@ -1021,7 +1021,7 @@
           keywordOffset: combinator.keyword.offset,
           endOffset: combinator.end,
           isShow: true,
-          names: combinator.shownNames.map((e) => e.name).toList(),
+          names: combinator.shownNames.map((e) => e.name).toFixedList(),
         );
       } else {
         combinator as HideCombinator;
@@ -1029,10 +1029,10 @@
           keywordOffset: combinator.keyword.offset,
           endOffset: combinator.end,
           isShow: false,
-          names: combinator.hiddenNames.map((e) => e.name).toList(),
+          names: combinator.hiddenNames.map((e) => e.name).toFixedList(),
         );
       }
-    }).toList();
+    }).toFixedList();
   }
 
   static List<UnlinkedNamespaceDirectiveConfiguration> _serializeConfigurations(
@@ -1046,7 +1046,7 @@
         value: value,
         uri: configuration.uri.stringValue,
       );
-    }).toList();
+    }).toFixedList();
   }
 
   static UnlinkedLibraryExportDirective _serializeExport(ExportDirective node) {
@@ -1749,7 +1749,7 @@
           uri: uri,
         );
       }
-    }).toList();
+    }).toFixedList();
   }
 
   @override
@@ -1941,7 +1941,7 @@
           uri: uri,
         );
       }
-    }).toList();
+    }).toFixedList();
   }
 
   List<LibraryExportState> get libraryExports {
@@ -1981,7 +1981,7 @@
           uris: uris,
         );
       }
-    }).toList();
+    }).toFixedList();
   }
 
   List<LibraryImportState> get libraryImports {
@@ -2021,7 +2021,7 @@
           uris: uris,
         );
       }
-    }).toList();
+    }).toFixedList();
   }
 
   /// Collect files that are transitively referenced by this library.
diff --git a/analyzer/lib/src/dart/analysis/index.dart b/analyzer/lib/src/dart/analysis/index.dart
index d5000e5..bff4eb5 100644
--- a/analyzer/lib/src/dart/analysis/index.dart
+++ b/analyzer/lib/src/dart/analysis/index.dart
@@ -548,9 +548,6 @@
       relNode = name as SimpleIdentifier;
     }
     recordRelation(element, kind, relNode, isQualified);
-    recordRelation(
-        element, IndexRelationKind.IS_REFERENCED_BY, relNode, isQualified);
-    namedType.typeArguments?.accept(this);
   }
 
   void recordUriReference(Element? element, StringLiteral uri) {
@@ -586,10 +583,7 @@
   void visitClassTypeAlias(ClassTypeAlias node) {
     _addSubtypeForClassTypeAlis(node);
     recordIsAncestorOf(node.declaredElement!);
-    var superclassName = node.superclass.name;
-    if (superclassName is PrefixedIdentifier) {
-      visitPrefixedIdentifier(superclassName);
-    }
+    recordSuperType(node.superclass, IndexRelationKind.IS_EXTENDED_BY);
     super.visitClassTypeAlias(node);
   }
 
@@ -721,10 +715,7 @@
   @override
   void visitExtendsClause(ExtendsClause node) {
     recordSuperType(node.superclass, IndexRelationKind.IS_EXTENDED_BY);
-    var superclassName = node.superclass.name;
-    if (superclassName is PrefixedIdentifier) {
-      visitPrefixedIdentifier(superclassName);
-    }
+    node.superclass.accept(this);
   }
 
   @override
@@ -744,10 +735,7 @@
   void visitImplementsClause(ImplementsClause node) {
     for (NamedType namedType in node.interfaces) {
       recordSuperType(namedType, IndexRelationKind.IS_IMPLEMENTED_BY);
-      var supertypeName = namedType.name;
-      if (supertypeName is PrefixedIdentifier) {
-        visitPrefixedIdentifier(supertypeName);
-      }
+      namedType.accept(this);
     }
   }
 
@@ -798,19 +786,10 @@
   }
 
   @override
-  void visitNamedType(NamedType node) {
-    AstNode parent = node.parent!;
-    if (parent is ClassTypeAlias && parent.superclass == node) {
-      recordSuperType(node, IndexRelationKind.IS_EXTENDED_BY);
-    } else {
-      super.visitNamedType(node);
-    }
-  }
-
-  @override
   void visitOnClause(OnClause node) {
     for (NamedType namedType in node.superclassConstraints) {
       recordSuperType(namedType, IndexRelationKind.CONSTRAINS);
+      namedType.accept(this);
     }
   }
 
@@ -945,10 +924,7 @@
   void visitWithClause(WithClause node) {
     for (NamedType namedType in node.mixinTypes) {
       recordSuperType(namedType, IndexRelationKind.IS_MIXED_IN_BY);
-      var supertypeName = namedType.name;
-      if (supertypeName is PrefixedIdentifier) {
-        visitPrefixedIdentifier(supertypeName);
-      }
+      namedType.accept(this);
     }
   }
 
diff --git a/analyzer/lib/src/dart/analysis/library_analyzer.dart b/analyzer/lib/src/dart/analysis/library_analyzer.dart
index 5657c96..eede372 100644
--- a/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -223,10 +223,13 @@
   }
 
   void _computeConstantErrors(
-      ErrorReporter errorReporter, CompilationUnit unit) {
-    ConstantVerifier constantVerifier =
-        ConstantVerifier(errorReporter, _libraryElement, _declaredVariables);
+      ErrorReporter errorReporter, FileState file, CompilationUnit unit) {
+    ConstantVerifier constantVerifier = ConstantVerifier(
+        errorReporter, _libraryElement, _declaredVariables,
+        retainDataForTesting: _testingData != null);
     unit.accept(constantVerifier);
+    _testingData?.recordExhaustivenessDataForTesting(
+        file.uri, constantVerifier.exhaustivenessDataForTesting!);
   }
 
   /// Compute [_constants] in all units.
@@ -454,7 +457,7 @@
     //
     // Use the ConstantVerifier to compute errors.
     //
-    _computeConstantErrors(errorReporter, unit);
+    _computeConstantErrors(errorReporter, file, unit);
 
     //
     // Compute inheritance and override errors.
diff --git a/analyzer/lib/src/dart/analysis/library_graph.dart b/analyzer/lib/src/dart/analysis/library_graph.dart
index 5de0460..d74630d 100644
--- a/analyzer/lib/src/dart/analysis/library_graph.dart
+++ b/analyzer/lib/src/dart/analysis/library_graph.dart
@@ -8,6 +8,7 @@
     show DependencyWalker, Node;
 import 'package:analyzer/src/dart/analysis/file_state.dart';
 import 'package:analyzer/src/summary/api_signature.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 import 'package:collection/collection.dart';
 
 /// Ensure that the [FileState.libraryCycle] for the [file] and anything it
@@ -223,7 +224,7 @@
 
     // Create the LibraryCycle instance for the cycle.
     var cycle = LibraryCycle(
-      libraries: libraries,
+      libraries: libraries.toFixedList(),
       directDependencies: directDependencies,
       apiSignature: apiSignature.toHex(),
       implSignature: implSignature.toHex(),
diff --git a/analyzer/lib/src/dart/analysis/search.dart b/analyzer/lib/src/dart/analysis/search.dart
index 72d7bbf..80f9029 100644
--- a/analyzer/lib/src/dart/analysis/search.dart
+++ b/analyzer/lib/src/dart/analysis/search.dart
@@ -317,6 +317,8 @@
       return _searchReferences_Function(element, searchedFiles);
     } else if (element is LibraryImportElement) {
       return _searchReferences_Import(element, searchedFiles);
+    } else if (element is PatternVariableElementImpl) {
+      return _searchReferences_PatternVariable(element, searchedFiles);
     } else if (kind == ElementKind.LABEL ||
         kind == ElementKind.LOCAL_VARIABLE) {
       return _searchReferences_Local(element, (n) => n is Block, searchedFiles);
@@ -708,8 +710,7 @@
     }
 
     // Find the matches.
-    _LocalReferencesVisitor visitor =
-        _LocalReferencesVisitor(element, unit.declaredElement!);
+    var visitor = _LocalReferencesVisitor({element}, unit.declaredElement!);
     enclosingNode.accept(visitor);
     return visitor.results;
   }
@@ -733,6 +734,40 @@
     return results;
   }
 
+  Future<List<SearchResult>> _searchReferences_PatternVariable(
+    PatternVariableElementImpl element,
+    SearchedFiles searchedFiles,
+  ) async {
+    var rootVariable = element.rootVariable;
+    var transitiveVariables = rootVariable is JoinPatternVariableElementImpl
+        ? rootVariable.transitiveVariables
+        : [rootVariable];
+
+    // Prepare a binding element for the variable.
+    var bindElement = transitiveVariables
+        .whereType<BindPatternVariableElementImpl>()
+        .firstOrNull;
+    if (bindElement == null) {
+      return const <SearchResult>[];
+    }
+
+    // Prepare the root node for search.
+    var rootNode = bindElement.node.thisOrAncestorMatching(
+      (node) => node is SwitchExpression || node is Block,
+    );
+    if (rootNode == null) {
+      return const <SearchResult>[];
+    }
+
+    // Find the matches.
+    var visitor = _LocalReferencesVisitor(
+      transitiveVariables.toSet(),
+      bindElement.enclosingUnit,
+    );
+    rootNode.accept(visitor);
+    return visitor.results;
+  }
+
   Future<List<SearchResult>> _searchReferences_Prefix(
       PrefixElement element, SearchedFiles searchedFiles) async {
     String path = element.source.fullName;
@@ -746,7 +781,7 @@
       String unitPath = unitElement.source.fullName;
       var unitResult = await _driver.getResult(unitPath);
       if (unitResult is ResolvedUnitResult) {
-        var visitor = _LocalReferencesVisitor(element, unitElement);
+        var visitor = _LocalReferencesVisitor({element}, unitElement);
         unitResult.unit.accept(visitor);
         results.addAll(visitor.results);
       }
@@ -1376,17 +1411,27 @@
 class _LocalReferencesVisitor extends RecursiveAstVisitor<void> {
   final List<SearchResult> results = <SearchResult>[];
 
-  final Element element;
+  final Set<Element> elements;
   final CompilationUnitElement enclosingUnitElement;
 
-  _LocalReferencesVisitor(this.element, this.enclosingUnitElement);
+  _LocalReferencesVisitor(this.elements, this.enclosingUnitElement);
+
+  @override
+  void visitAssignedVariablePattern(AssignedVariablePattern node) {
+    if (elements.contains(node.element)) {
+      _addResult(node, SearchResultKind.WRITE);
+    }
+
+    super.visitAssignedVariablePattern(node);
+  }
 
   @override
   void visitSimpleIdentifier(SimpleIdentifier node) {
     if (node.inDeclarationContext()) {
       return;
     }
-    if (node.staticElement == element) {
+    var element = node.staticElement;
+    if (elements.contains(element)) {
       var parent = node.parent;
       SearchResultKind kind = SearchResultKind.REFERENCE;
       if (element is FunctionElement) {
diff --git a/analyzer/lib/src/dart/analysis/testing_data.dart b/analyzer/lib/src/dart/analysis/testing_data.dart
index 5e6a288..bed0e61 100644
--- a/analyzer/lib/src/dart/analysis/testing_data.dart
+++ b/analyzer/lib/src/dart/analysis/testing_data.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
+import 'package:analyzer/src/generated/exhaustiveness.dart';
 
 /// Data structure maintaining intermediate analysis results for testing
 /// purposes.  Under normal execution, no instance of this class should be
@@ -11,6 +12,15 @@
   /// Map containing the results of flow analysis.
   final Map<Uri, FlowAnalysisDataForTesting> uriToFlowAnalysisData = {};
 
+  final Map<Uri, ExhaustivenessDataForTesting> uriToExhaustivenessData = {};
+
+  /// Called by the constant verifier, to record exhaustiveness data used in
+  /// testing.
+  void recordExhaustivenessDataForTesting(
+      Uri uri, ExhaustivenessDataForTesting result) {
+    uriToExhaustivenessData[uri] = result;
+  }
+
   /// Called by the analysis driver after performing flow analysis, to record
   /// flow analysis results.
   void recordFlowAnalysisDataForTesting(
diff --git a/analyzer/lib/src/dart/ast/ast.dart b/analyzer/lib/src/dart/ast/ast.dart
index 9840e70..026babb 100644
--- a/analyzer/lib/src/dart/ast/ast.dart
+++ b/analyzer/lib/src/dart/ast/ast.dart
@@ -5,6 +5,7 @@
 import 'dart:collection';
 import 'dart:math' as math;
 
+import 'package:_fe_analyzer_shared/src/scanner/string_canonicalizer.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/type_operations.dart'
     as shared;
 import 'package:analyzer/dart/analysis/features.dart';
@@ -661,16 +662,13 @@
 ///
 ///    variablePattern ::= identifier
 @experimental
-class AssignedVariablePatternImpl extends DartPatternImpl
+class AssignedVariablePatternImpl extends VariablePatternImpl
     implements AssignedVariablePattern {
   @override
   Element? element;
 
-  @override
-  final Token name;
-
   AssignedVariablePatternImpl({
-    required this.name,
+    required super.name,
   });
 
   @override
@@ -680,8 +678,7 @@
   Token get endToken => name;
 
   @override
-  ChildEntities get _childEntities =>
-      super._childEntities..addToken('name', name);
+  ChildEntities get _childEntities => ChildEntities()..addToken('name', name);
 
   @override
   E? accept<E>(AstVisitor<E> visitor) {
@@ -1135,79 +1132,6 @@
   }
 }
 
-/// A binary (infix) pattern.
-///
-///    binaryPattern ::=
-///        [DartPattern] ('|' | '&') [DartPattern]
-@experimental
-class BinaryPatternImpl extends DartPatternImpl implements BinaryPattern {
-  @override
-  final DartPatternImpl leftOperand;
-
-  @override
-  final Token operator;
-
-  @override
-  final DartPatternImpl rightOperand;
-
-  BinaryPatternImpl({
-    required this.leftOperand,
-    required this.operator,
-    required this.rightOperand,
-  }) {
-    _becomeParentOf(leftOperand);
-    _becomeParentOf(rightOperand);
-  }
-
-  @override
-  Token get beginToken => leftOperand.beginToken;
-
-  @override
-  Token get endToken => rightOperand.endToken;
-
-  @override
-  ChildEntities get _childEntities => super._childEntities
-    ..addNode('leftOperand', leftOperand)
-    ..addToken('operator', operator)
-    ..addNode('rightOperand', rightOperand);
-
-  @override
-  E? accept<E>(AstVisitor<E> visitor) => visitor.visitBinaryPattern(this);
-
-  @override
-  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
-    if (operator.type == TokenType.AMPERSAND_AMPERSAND) {
-      return resolverVisitor.analyzeLogicalAndPatternSchema(
-          leftOperand, rightOperand);
-    } else {
-      return resolverVisitor.analyzeLogicalOrPatternSchema(
-          leftOperand, rightOperand);
-    }
-  }
-
-  @override
-  void resolvePattern(
-    ResolverVisitor resolverVisitor,
-    SharedMatchContext context,
-  ) {
-    assert(operator.type == TokenType.AMPERSAND_AMPERSAND ||
-        operator.type == TokenType.BAR_BAR);
-    if (operator.type == TokenType.AMPERSAND_AMPERSAND) {
-      resolverVisitor.analyzeLogicalAndPattern(
-          context, this, leftOperand, rightOperand);
-    } else {
-      resolverVisitor.analyzeLogicalOrPattern(
-          context, this, leftOperand, rightOperand);
-    }
-  }
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    leftOperand.accept(visitor);
-    rightOperand.accept(visitor);
-  }
-}
-
 /// A function body that consists of a block of statements.
 ///
 ///    blockFunctionBody ::=
@@ -1601,7 +1525,7 @@
   Token get endToken => type.endToken;
 
   @override
-  DeclaredVariablePatternImpl? get variablePattern => pattern.variablePattern;
+  VariablePatternImpl? get variablePattern => pattern.variablePattern;
 
   @override
   ChildEntities get _childEntities => super._childEntities
@@ -1623,7 +1547,12 @@
     SharedMatchContext context,
   ) {
     type.accept(resolverVisitor);
-    resolverVisitor.analyzeCastPattern(context, pattern, type.typeOrThrow);
+    resolverVisitor.analyzeCastPattern(
+      context: context,
+      pattern: this,
+      innerPattern: pattern,
+      requiredType: type.typeOrThrow,
+    );
   }
 
   @override
@@ -1894,12 +1823,14 @@
 /// The declaration of a class.
 ///
 ///    classDeclaration ::=
-///        classModifiers? 'class' [SimpleIdentifier] [TypeParameterList]?
+///        classModifiers 'class' [SimpleIdentifier] [TypeParameterList]?
 ///        ([ExtendsClause] [WithClause]?)?
 ///        [ImplementsClause]?
 ///        '{' [ClassMember]* '}'
 ///
-///    classModifiers ::= 'sealed' | 'abstract'
+///    classModifiers ::= 'sealed'
+///      | 'abstract'? ('base' | 'interface' | 'final')?
+///      | 'abstract'? 'base'? 'mixin'
 ///
 class ClassDeclarationImpl extends NamedCompilationUnitMemberImpl
     implements ClassDeclaration {
@@ -1917,10 +1848,23 @@
   @override
   final Token? sealedKeyword;
 
+  /// The 'base' keyword, or `null` if the keyword was absent.
+  @override
+  final Token? baseKeyword;
+
+  /// The 'interface' keyword, or `null` if the keyword was absent.
+  @override
+  final Token? interfaceKeyword;
+
+  /// The 'final' keyword, or `null` if the keyword was absent.
+  @override
+  final Token? finalKeyword;
+
   /// The 'augment' keyword, or `null` if the keyword was absent.
   final Token? augmentKeyword;
 
   /// The 'mixin' keyword, or `null` if the keyword was absent.
+  @override
   final Token? mixinKeyword;
 
   /// The token representing the 'class' keyword.
@@ -1976,6 +1920,9 @@
     required this.macroKeyword,
     required this.inlineKeyword,
     required this.sealedKeyword,
+    required this.baseKeyword,
+    required this.interfaceKeyword,
+    required this.finalKeyword,
     required this.augmentKeyword,
     required this.mixinKeyword,
     required this.classKeyword,
@@ -2021,6 +1968,9 @@
         macroKeyword ??
         inlineKeyword ??
         sealedKeyword ??
+        baseKeyword ??
+        interfaceKeyword ??
+        finalKeyword ??
         augmentKeyword ??
         mixinKeyword ??
         classKeyword;
@@ -2063,6 +2013,9 @@
     ..addToken('macroKeyword', macroKeyword)
     ..addToken('inlineKeyword', inlineKeyword)
     ..addToken('sealedKeyword', sealedKeyword)
+    ..addToken('baseKeyword', baseKeyword)
+    ..addToken('interfaceKeyword', interfaceKeyword)
+    ..addToken('finalKeyword', finalKeyword)
     ..addToken('augmentKeyword', augmentKeyword)
     ..addToken('mixinKeyword', mixinKeyword)
     ..addToken('classKeyword', classKeyword)
@@ -2105,9 +2058,13 @@
 /// A class type alias.
 ///
 ///    classTypeAlias ::=
-///        [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'?
+///        [SimpleIdentifier] [TypeParameterList]? '=' classModifiers
 ///        mixinApplication
 ///
+///    classModifiers ::= 'sealed'
+///      | 'abstract'? ('base' | 'interface' | 'final')?
+///      | 'abstract'? 'base'? 'mixin'
+///
 ///    mixinApplication ::=
 ///        [TypeName] [WithClause] [ImplementsClause]? ';'
 class ClassTypeAliasImpl extends TypeAliasImpl implements ClassTypeAlias {
@@ -2137,12 +2094,28 @@
   @override
   final Token? sealedKeyword;
 
+  /// The token for the 'base' keyword, or `null` if this is not defining a base
+  /// class.
+  @override
+  final Token? baseKeyword;
+
+  /// The token for the 'interface' keyword, or `null` if this is not defining
+  /// an interface class.
+  @override
+  final Token? interfaceKeyword;
+
+  /// The token for the 'final' keyword, or `null` if this is not defining a
+  /// final class.
+  @override
+  final Token? finalKeyword;
+
   /// The token for the 'augment' keyword, or `null` if this is not defining an
   /// augmentation class.
   final Token? augmentKeyword;
 
   /// The token for the 'mixin' keyword, or `null` if this is not defining a
   /// mixin class.
+  @override
   final Token? mixinKeyword;
 
   /// The name of the superclass of the class being declared.
@@ -2175,6 +2148,9 @@
     required this.macroKeyword,
     required this.inlineKeyword,
     required this.sealedKeyword,
+    required this.baseKeyword,
+    required this.interfaceKeyword,
+    required this.finalKeyword,
     required this.augmentKeyword,
     required this.mixinKeyword,
     required NamedTypeImpl superclass,
@@ -2201,6 +2177,9 @@
         macroKeyword ??
         inlineKeyword ??
         sealedKeyword ??
+        baseKeyword ??
+        interfaceKeyword ??
+        finalKeyword ??
         augmentKeyword ??
         mixinKeyword ??
         typedefKeyword;
@@ -2244,6 +2223,9 @@
     ..addToken('inlineKeyword', inlineKeyword)
     ..addToken('macroKeyword', macroKeyword)
     ..addToken('sealedKeyword', sealedKeyword)
+    ..addToken('baseKeyword', baseKeyword)
+    ..addToken('interfaceKeyword', interfaceKeyword)
+    ..addToken('finalKeyword', finalKeyword)
     ..addToken('augmentKeyword', augmentKeyword)
     ..addToken('mixinKeyword', mixinKeyword)
     ..addNode('superclass', superclass)
@@ -3054,6 +3036,16 @@
   @override
   NodeListImpl<ConstructorInitializerImpl> get initializers => _initializers;
 
+  // A trivial constructor is a generative constructor that is not a
+  // redirecting constructor, declares no parameters, has no
+  // initializer list, has no body, and is not external.
+  bool get isTrivial =>
+      redirectedConstructor == null &&
+      parameters.parameters.isEmpty &&
+      initializers.isEmpty &&
+      body is EmptyFunctionBody &&
+      externalKeyword == null;
+
   @Deprecated('Use name instead')
   @override
   Token? get name2 => name;
@@ -3431,11 +3423,12 @@
 ///
 ///    pattern ::=
 ///        [AssignedVariablePattern]
-///      | [BinaryPattern]
 ///      | [DeclaredVariablePattern]
 ///      | [CastPattern]
 ///      | [ConstantPattern]
 ///      | [ListPattern]
+///      | [LogicalAndPattern]
+///      | [LogicalOrPattern]
 ///      | [MapPattern]
 ///      | [ObjectPattern]
 ///      | [ParenthesizedPattern]
@@ -3445,7 +3438,8 @@
 @experimental
 abstract class DartPatternImpl extends AstNodeImpl
     implements DartPattern, ListPatternElementImpl {
-  DartPatternImpl();
+  @override
+  DartType? matchedValueType;
 
   @override
   // TODO(brianwilkerson) Remove this and implement it in subclasses when we
@@ -3456,7 +3450,7 @@
   DartPattern get unParenthesized => this;
 
   /// The variable pattern, itself, or wrapped in a unary pattern.
-  DeclaredVariablePatternImpl? get variablePattern => null;
+  VariablePatternImpl? get variablePattern => null;
 
   DartType computePatternSchema(ResolverVisitor resolverVisitor);
 
@@ -3576,24 +3570,21 @@
 ///    variablePattern ::=
 ///        ( 'var' | 'final' | 'final'? [TypeAnnotation])? [Identifier]
 @experimental
-class DeclaredVariablePatternImpl extends DartPatternImpl
+class DeclaredVariablePatternImpl extends VariablePatternImpl
     implements DeclaredVariablePattern {
   @override
-  VariablePatternBindElementImpl? declaredElement;
+  BindPatternVariableElementImpl? declaredElement;
 
   @override
   final Token? keyword;
 
   @override
-  final Token name;
-
-  @override
   final TypeAnnotationImpl? type;
 
   DeclaredVariablePatternImpl({
-    required this.name,
     required this.keyword,
     required this.type,
+    required super.name,
   }) {
     _becomeParentOf(type);
   }
@@ -3605,7 +3596,7 @@
   Token get endToken => name;
 
   /// If [keyword] is `final`, returns it.
-  Token? get finalToken {
+  Token? get finalKeyword {
     final keyword = this.keyword;
     if (keyword != null && keyword.keyword == Keyword.FINAL) {
       return keyword;
@@ -3619,8 +3610,17 @@
   /// * Matching context: [GuardedPatternImpl]
   AstNodeImpl? get patternContext {
     for (DartPatternImpl current = this;;) {
-      final parent = current.parent;
-      if (parent is PatternVariableDeclarationImpl) {
+      var parent = current.parent;
+      if (parent is MapPatternEntry) {
+        parent = parent.parent;
+      } else if (parent is PatternFieldImpl) {
+        parent = parent.parent;
+      } else if (parent is RestPatternElementImpl) {
+        parent = parent.parent;
+      }
+      if (parent is ForEachPartsWithPatternImpl) {
+        return parent;
+      } else if (parent is PatternVariableDeclarationImpl) {
         return parent;
       } else if (parent is PatternAssignmentImpl) {
         return parent;
@@ -3635,10 +3635,7 @@
   }
 
   @override
-  DeclaredVariablePatternImpl? get variablePattern => this;
-
-  @override
-  ChildEntities get _childEntities => super._childEntities
+  ChildEntities get _childEntities => ChildEntities()
     ..addToken('keyword', keyword)
     ..addNode('type', type)
     ..addToken('name', name);
@@ -3658,8 +3655,12 @@
     ResolverVisitor resolverVisitor,
     SharedMatchContext context,
   ) {
-    resolverVisitor.analyzeDeclaredVariablePattern(context, this,
-        declaredElement, declaredElement?.name, type?.typeOrThrow);
+    declaredElement!.type = resolverVisitor.analyzeDeclaredVariablePattern(
+        context,
+        this,
+        declaredElement!,
+        declaredElement!.name,
+        type?.typeOrThrow);
   }
 
   @override
@@ -5253,6 +5254,9 @@
   @override
   final DartPatternImpl pattern;
 
+  /// Variables declared in [pattern].
+  late final List<BindPatternVariableElementImpl> variables;
+
   ForEachPartsWithPatternImpl({
     required List<AnnotationImpl>? metadata,
     required this.keyword,
@@ -5273,6 +5277,14 @@
     }
   }
 
+  /// If [keyword] is `final`, returns it.
+  Token? get finalKeyword {
+    if (keyword.keyword == Keyword.FINAL) {
+      return keyword;
+    }
+    return null;
+  }
+
   @override
   NodeListImpl<AnnotationImpl> get metadata => _metadata;
 
@@ -6672,7 +6684,7 @@
 
   /// Variables declared in [pattern], available in [whenClause] guard, and
   /// to the `ifTrue` node.
-  late Map<String, PromotableElement> variables;
+  late Map<String, PatternVariableElementImpl> variables;
 
   @override
   final WhenClauseImpl? whenClause;
@@ -8176,7 +8188,7 @@
       }
       buffer.write(identifier.name);
     }
-    return buffer.toString();
+    return considerCanonicalizeString(buffer.toString());
   }
 
   @override
@@ -8375,6 +8387,130 @@
   final Set<VariableElement> potentiallyMutatedInScope = <VariableElement>{};
 }
 
+/// A logical-and pattern.
+///
+///    logicalAndPattern ::=
+///        [DartPattern] '&&' [DartPattern]
+@experimental
+class LogicalAndPatternImpl extends DartPatternImpl
+    implements LogicalAndPattern {
+  @override
+  final DartPatternImpl leftOperand;
+
+  @override
+  final Token operator;
+
+  @override
+  final DartPatternImpl rightOperand;
+
+  LogicalAndPatternImpl({
+    required this.leftOperand,
+    required this.operator,
+    required this.rightOperand,
+  }) {
+    _becomeParentOf(leftOperand);
+    _becomeParentOf(rightOperand);
+  }
+
+  @override
+  Token get beginToken => leftOperand.beginToken;
+
+  @override
+  Token get endToken => rightOperand.endToken;
+
+  @override
+  ChildEntities get _childEntities => super._childEntities
+    ..addNode('leftOperand', leftOperand)
+    ..addToken('operator', operator)
+    ..addNode('rightOperand', rightOperand);
+
+  @override
+  E? accept<E>(AstVisitor<E> visitor) => visitor.visitLogicalAndPattern(this);
+
+  @override
+  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
+    return resolverVisitor.analyzeLogicalAndPatternSchema(
+        leftOperand, rightOperand);
+  }
+
+  @override
+  void resolvePattern(
+    ResolverVisitor resolverVisitor,
+    SharedMatchContext context,
+  ) {
+    resolverVisitor.analyzeLogicalAndPattern(
+        context, this, leftOperand, rightOperand);
+  }
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    leftOperand.accept(visitor);
+    rightOperand.accept(visitor);
+  }
+}
+
+/// A logical-or pattern.
+///
+///    logicalOrPattern ::=
+///        [DartPattern] '||' [DartPattern]
+@experimental
+class LogicalOrPatternImpl extends DartPatternImpl implements LogicalOrPattern {
+  @override
+  final DartPatternImpl leftOperand;
+
+  @override
+  final Token operator;
+
+  @override
+  final DartPatternImpl rightOperand;
+
+  LogicalOrPatternImpl({
+    required this.leftOperand,
+    required this.operator,
+    required this.rightOperand,
+  }) {
+    _becomeParentOf(leftOperand);
+    _becomeParentOf(rightOperand);
+  }
+
+  @override
+  Token get beginToken => leftOperand.beginToken;
+
+  @override
+  Token get endToken => rightOperand.endToken;
+
+  @override
+  ChildEntities get _childEntities => super._childEntities
+    ..addNode('leftOperand', leftOperand)
+    ..addToken('operator', operator)
+    ..addNode('rightOperand', rightOperand);
+
+  @override
+  E? accept<E>(AstVisitor<E> visitor) => visitor.visitLogicalOrPattern(this);
+
+  @override
+  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
+    return resolverVisitor.analyzeLogicalOrPatternSchema(
+        leftOperand, rightOperand);
+  }
+
+  @override
+  void resolvePattern(
+    ResolverVisitor resolverVisitor,
+    SharedMatchContext context,
+  ) {
+    resolverVisitor.analyzeLogicalOrPattern(
+        context, this, leftOperand, rightOperand);
+    resolverVisitor.nullSafetyDeadCodeVerifier.flowEnd(rightOperand);
+  }
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    leftOperand.accept(visitor);
+    rightOperand.accept(visitor);
+  }
+}
+
 /// A single key/value pair in a map literal.
 ///
 ///    mapLiteralEntry ::=
@@ -8926,8 +9062,11 @@
 /// The declaration of a mixin.
 ///
 ///    mixinDeclaration ::=
-///        'sealed'? metadata? 'mixin' [SimpleIdentifier] [TypeParameterList]?
-///        [RequiresClause]? [ImplementsClause]? '{' [ClassMember]* '}'
+///        metadata? mixinModifiers? 'mixin' [SimpleIdentifier]
+///        [TypeParameterList]? [RequiresClause]? [ImplementsClause]?
+///        '{' [ClassMember]* '}'
+///
+///    mixinModifiers ::= 'sealed' | 'base' | 'interface' | 'final'
 class MixinDeclarationImpl extends NamedCompilationUnitMemberImpl
     implements MixinDeclaration {
   /// Return the 'augment' keyword, or `null` if the keyword was absent.
@@ -8937,6 +9076,18 @@
   @override
   final Token? sealedKeyword;
 
+  /// Return the 'base' keyword, or `null` if the keyword was absent.
+  @override
+  final Token? baseKeyword;
+
+  /// Return the 'interface' keyword, or `null` if the keyword was absent.
+  @override
+  final Token? interfaceKeyword;
+
+  /// Return the 'final' keyword, or `null` if the keyword was absent.
+  @override
+  final Token? finalKeyword;
+
   @override
   final Token mixinKeyword;
 
@@ -8978,6 +9129,9 @@
     required super.metadata,
     required this.augmentKeyword,
     required this.sealedKeyword,
+    required this.baseKeyword,
+    required this.interfaceKeyword,
+    required this.finalKeyword,
     required this.mixinKeyword,
     required super.name,
     required TypeParameterListImpl? typeParameters,
@@ -9004,7 +9158,11 @@
 
   @override
   Token get firstTokenAfterCommentAndMetadata {
-    return sealedKeyword ?? mixinKeyword;
+    return sealedKeyword ??
+        baseKeyword ??
+        interfaceKeyword ??
+        finalKeyword ??
+        mixinKeyword;
   }
 
   @override
@@ -9034,6 +9192,9 @@
   @override
   ChildEntities get _childEntities => super._childEntities
     ..addToken('sealedKeyword', sealedKeyword)
+    ..addToken('baseKeyword', baseKeyword)
+    ..addToken('interfaceKeyword', interfaceKeyword)
+    ..addToken('finalKeyword', finalKeyword)
     ..addToken('mixinKeyword', mixinKeyword)
     ..addToken('name', name)
     ..addNode('typeParameters', typeParameters)
@@ -9597,6 +9758,125 @@
   }
 }
 
+/// A null-assert pattern.
+///
+///    nullAssertPattern ::=
+///        [DartPattern] '!'
+@experimental
+class NullAssertPatternImpl extends DartPatternImpl
+    implements NullAssertPattern {
+  @override
+  final DartPatternImpl pattern;
+
+  @override
+  final Token operator;
+
+  NullAssertPatternImpl({
+    required this.pattern,
+    required this.operator,
+  }) {
+    _becomeParentOf(pattern);
+  }
+
+  @override
+  Token get beginToken => pattern.beginToken;
+
+  @override
+  Token get endToken => operator;
+
+  @override
+  VariablePatternImpl? get variablePattern => pattern.variablePattern;
+
+  @override
+  ChildEntities get _childEntities => super._childEntities
+    ..addNode('pattern', pattern)
+    ..addToken('operator', operator);
+
+  @override
+  E? accept<E>(AstVisitor<E> visitor) => visitor.visitNullAssertPattern(this);
+
+  @override
+  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
+    return resolverVisitor.analyzeNullCheckOrAssertPatternSchema(
+      pattern,
+      isAssert: true,
+    );
+  }
+
+  @override
+  void resolvePattern(
+    ResolverVisitor resolverVisitor,
+    SharedMatchContext context,
+  ) {
+    resolverVisitor.analyzeNullCheckOrAssertPattern(context, this, pattern,
+        isAssert: true);
+  }
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    pattern.accept(visitor);
+  }
+}
+
+/// A null-check pattern.
+///
+///    nullCheckPattern ::=
+///        [DartPattern] '?'
+@experimental
+class NullCheckPatternImpl extends DartPatternImpl implements NullCheckPattern {
+  @override
+  final DartPatternImpl pattern;
+
+  @override
+  final Token operator;
+
+  NullCheckPatternImpl({
+    required this.pattern,
+    required this.operator,
+  }) {
+    _becomeParentOf(pattern);
+  }
+
+  @override
+  Token get beginToken => pattern.beginToken;
+
+  @override
+  Token get endToken => operator;
+
+  @override
+  VariablePatternImpl? get variablePattern => pattern.variablePattern;
+
+  @override
+  ChildEntities get _childEntities => super._childEntities
+    ..addNode('pattern', pattern)
+    ..addToken('operator', operator);
+
+  @override
+  E? accept<E>(AstVisitor<E> visitor) => visitor.visitNullCheckPattern(this);
+
+  @override
+  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
+    return resolverVisitor.analyzeNullCheckOrAssertPatternSchema(
+      pattern,
+      isAssert: false,
+    );
+  }
+
+  @override
+  void resolvePattern(
+    ResolverVisitor resolverVisitor,
+    SharedMatchContext context,
+  ) {
+    resolverVisitor.analyzeNullCheckOrAssertPattern(context, this, pattern,
+        isAssert: false);
+  }
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    pattern.accept(visitor);
+  }
+}
+
 /// A null literal expression.
 ///
 ///    nullLiteral ::=
@@ -9665,10 +9945,10 @@
 /// An object pattern.
 ///
 ///    objectPattern ::=
-///        [Identifier] [TypeArgumentList]? '(' [RecordPatternField] ')'
+///        [Identifier] [TypeArgumentList]? '(' [PatternField] ')'
 @experimental
 class ObjectPatternImpl extends DartPatternImpl implements ObjectPattern {
-  final NodeListImpl<RecordPatternFieldImpl> _fields = NodeListImpl._();
+  final NodeListImpl<PatternFieldImpl> _fields = NodeListImpl._();
 
   @override
   final Token leftParenthesis;
@@ -9682,7 +9962,7 @@
   ObjectPatternImpl({
     required this.type,
     required this.leftParenthesis,
-    required List<RecordPatternFieldImpl> fields,
+    required List<PatternFieldImpl> fields,
     required this.rightParenthesis,
   }) {
     _becomeParentOf(type);
@@ -9696,7 +9976,7 @@
   Token get endToken => rightParenthesis;
 
   @override
-  NodeList<RecordPatternFieldImpl> get fields => _fields;
+  NodeList<PatternFieldImpl> get fields => _fields;
 
   @override
   ChildEntities get _childEntities => super._childEntities
@@ -9721,7 +10001,7 @@
     resolverVisitor.analyzeObjectPattern(
       context,
       this,
-      fields: resolverVisitor.buildSharedRecordPatternFields(fields),
+      fields: resolverVisitor.buildSharedPatternFields(fields),
     );
   }
 
@@ -9890,7 +10170,7 @@
   }
 
   @override
-  DeclaredVariablePatternImpl? get variablePattern => pattern.variablePattern;
+  VariablePatternImpl? get variablePattern => pattern.variablePattern;
 
   @override
   ChildEntities get _childEntities => super._childEntities
@@ -10069,6 +10349,10 @@
   @override
   final DartPatternImpl pattern;
 
+  /// The pattern type schema, used for downward inference of [expression];
+  /// or `null` if the node is not resolved yet.
+  DartType? patternTypeSchema;
+
   PatternAssignmentImpl({
     required this.pattern,
     required this.equals,
@@ -10117,6 +10401,81 @@
   }
 }
 
+/// A field in a record pattern.
+///
+///    patternField ::=
+///        [PatternFieldName]? [DartPattern]
+@experimental
+class PatternFieldImpl extends AstNodeImpl implements PatternField {
+  @override
+  Element? element;
+
+  @override
+  final PatternFieldNameImpl? name;
+
+  @override
+  final DartPatternImpl pattern;
+
+  PatternFieldImpl({required this.name, required this.pattern}) {
+    _becomeParentOf(name);
+    _becomeParentOf(pattern);
+  }
+
+  @override
+  Token get beginToken => name?.beginToken ?? pattern.beginToken;
+
+  @override
+  Token get endToken => pattern.endToken;
+
+  @override
+  ChildEntities get _childEntities => super._childEntities
+    ..addNode('name', name)
+    ..addNode('pattern', pattern);
+
+  @override
+  E? accept<E>(AstVisitor<E> visitor) => visitor.visitPatternField(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    name?.accept(visitor);
+    pattern.accept(visitor);
+  }
+}
+
+/// A field name in a record pattern field.
+///
+///    patternFieldName ::=
+///        [Token]? ':'
+@experimental
+class PatternFieldNameImpl extends AstNodeImpl implements PatternFieldName {
+  @override
+  final Token colon;
+
+  @override
+  final Token? name;
+
+  PatternFieldNameImpl({required this.name, required this.colon});
+
+  @override
+  Token get beginToken => name ?? colon;
+
+  @override
+  Token get endToken => colon;
+
+  @override
+  ChildEntities get _childEntities => super._childEntities
+    ..addToken('name', name)
+    ..addToken('colon', colon);
+
+  @override
+  E? accept<E>(AstVisitor<E> visitor) => visitor.visitPatternFieldName(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    // There are no children to visit.
+  }
+}
+
 /// A pattern variable declaration.
 ///
 ///    patternDeclaration ::=
@@ -10135,8 +10494,12 @@
   @override
   final DartPatternImpl pattern;
 
+  /// The pattern type schema, used for downward inference of [expression];
+  /// or `null` if the node is not resolved yet.
+  DartType? patternTypeSchema;
+
   /// Variables declared in [pattern].
-  late final List<VariablePatternBindElementImpl> elements;
+  late final List<BindPatternVariableElementImpl> elements;
 
   PatternVariableDeclarationImpl({
     required this.keyword,
@@ -10161,7 +10524,7 @@
   }
 
   /// If [keyword] is `final`, returns it.
-  Token? get finalToken {
+  Token? get finalKeyword {
     if (keyword.keyword == Keyword.FINAL) {
       return keyword;
     }
@@ -10316,62 +10679,6 @@
       identical(descendant, operand);
 }
 
-/// A postfix (unary) pattern.
-///
-///    postfixPattern ::=
-///        [DartPattern] ('?' | '!')
-@experimental
-class PostfixPatternImpl extends DartPatternImpl implements PostfixPattern {
-  @override
-  final DartPatternImpl operand;
-
-  @override
-  final Token operator;
-
-  PostfixPatternImpl({required this.operand, required this.operator}) {
-    _becomeParentOf(operand);
-  }
-
-  @override
-  Token get beginToken => operand.beginToken;
-
-  @override
-  Token get endToken => operator;
-
-  @override
-  DeclaredVariablePatternImpl? get variablePattern => operand.variablePattern;
-
-  @override
-  ChildEntities get _childEntities => super._childEntities
-    ..addNode('operand', operand)
-    ..addToken('operator', operator);
-
-  @override
-  E? accept<E>(AstVisitor<E> visitor) => visitor.visitPostfixPattern(this);
-
-  @override
-  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
-    return resolverVisitor.analyzeNullCheckOrAssertPatternSchema(
-      operand,
-      isAssert: operator.type == TokenType.BANG,
-    );
-  }
-
-  @override
-  void resolvePattern(
-    ResolverVisitor resolverVisitor,
-    SharedMatchContext context,
-  ) {
-    resolverVisitor.analyzeNullCheckOrAssertPattern(context, this, operand,
-        isAssert: operator.type == TokenType.BANG);
-  }
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    operand.accept(visitor);
-  }
-}
-
 /// An identifier that is prefixed or an access to an object property where the
 /// target of the property access is a simple identifier.
 ///
@@ -10732,90 +11039,13 @@
   }
 }
 
-/// A field in a record pattern.
-///
-///    recordPatternField ::=
-///        [RecordPatternFieldName]? [DartPattern]
-@experimental
-class RecordPatternFieldImpl extends AstNodeImpl implements RecordPatternField {
-  @override
-  Element? fieldElement;
-
-  @override
-  final RecordPatternFieldNameImpl? fieldName;
-
-  @override
-  final DartPatternImpl pattern;
-
-  RecordPatternFieldImpl({required this.fieldName, required this.pattern}) {
-    _becomeParentOf(fieldName);
-    _becomeParentOf(pattern);
-  }
-
-  @override
-  Token get beginToken => fieldName?.beginToken ?? pattern.beginToken;
-
-  @override
-  Token get endToken => pattern.endToken;
-
-  @override
-  ChildEntities get _childEntities => super._childEntities
-    ..addNode('fieldName', fieldName)
-    ..addNode('pattern', pattern);
-
-  @override
-  E? accept<E>(AstVisitor<E> visitor) => visitor.visitRecordPatternField(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    fieldName?.accept(visitor);
-    pattern.accept(visitor);
-  }
-}
-
-/// A field name in a record pattern field.
-///
-///    recordPatternField ::=
-///        [Token]? ':'
-@experimental
-class RecordPatternFieldNameImpl extends AstNodeImpl
-    implements RecordPatternFieldName {
-  @override
-  final Token colon;
-
-  @override
-  final Token? name;
-
-  RecordPatternFieldNameImpl({required this.name, required this.colon});
-
-  @override
-  Token get beginToken => name ?? colon;
-
-  @override
-  Token get endToken => colon;
-
-  @override
-  ChildEntities get _childEntities => super._childEntities
-    ..addToken('name', name)
-    ..addToken('colon', colon);
-
-  @override
-  E? accept<E>(AstVisitor<E> visitor) =>
-      visitor.visitRecordPatternFieldName(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    // There are no children to visit.
-  }
-}
-
 /// A record pattern.
 ///
 ///    recordPattern ::=
-///        '(' [RecordPatternField] (',' [RecordPatternField])* ')'
+///        '(' [PatternField] (',' [PatternField])* ')'
 @experimental
 class RecordPatternImpl extends DartPatternImpl implements RecordPattern {
-  final NodeListImpl<RecordPatternFieldImpl> _fields = NodeListImpl._();
+  final NodeListImpl<PatternFieldImpl> _fields = NodeListImpl._();
 
   @override
   final Token leftParenthesis;
@@ -10825,7 +11055,7 @@
 
   RecordPatternImpl({
     required this.leftParenthesis,
-    required List<RecordPatternFieldImpl> fields,
+    required List<PatternFieldImpl> fields,
     required this.rightParenthesis,
   }) {
     _fields._initialize(this, fields);
@@ -10838,7 +11068,7 @@
   Token get endToken => rightParenthesis;
 
   @override
-  NodeList<RecordPatternFieldImpl> get fields => _fields;
+  NodeList<PatternFieldImpl> get fields => _fields;
 
   @override
   ChildEntities get _childEntities => super._childEntities
@@ -10852,7 +11082,7 @@
   @override
   DartType computePatternSchema(ResolverVisitor resolverVisitor) {
     return resolverVisitor.analyzeRecordPatternSchema(
-      fields: resolverVisitor.buildSharedRecordPatternFields(fields),
+      fields: resolverVisitor.buildSharedPatternFields(fields),
     );
   }
 
@@ -10864,7 +11094,7 @@
     resolverVisitor.analyzeRecordPattern(
       context,
       this,
-      fields: resolverVisitor.buildSharedRecordPatternFields(fields),
+      fields: resolverVisitor.buildSharedPatternFields(fields),
     );
   }
 
@@ -10945,7 +11175,7 @@
   Token get beginToken => leftParenthesis;
 
   @override
-  Token get endToken => rightParenthesis;
+  Token get endToken => question ?? rightParenthesis;
 
   @override
   ChildEntities get _childEntities => super._childEntities
@@ -13845,6 +14075,20 @@
   }
 }
 
+@experimental
+abstract class VariablePatternImpl extends DartPatternImpl
+    implements VariablePattern {
+  @override
+  final Token name;
+
+  VariablePatternImpl({
+    required this.name,
+  });
+
+  @override
+  VariablePatternImpl? get variablePattern => this;
+}
+
 /// A guard in a pattern-based `case` in a `switch` statement or `switch`
 /// expression.
 ///
@@ -13965,6 +14209,77 @@
   }
 }
 
+/// A wildcard pattern.
+///
+///    variablePattern ::=
+///        ( 'var' | 'final' | 'final'? [TypeAnnotation])? '_'
+@experimental
+class WildcardPatternImpl extends DartPatternImpl implements WildcardPattern {
+  @override
+  final Token? keyword;
+
+  @override
+  final Token name;
+
+  @override
+  final TypeAnnotationImpl? type;
+
+  WildcardPatternImpl({
+    required this.name,
+    required this.keyword,
+    required this.type,
+  }) {
+    _becomeParentOf(type);
+  }
+
+  @override
+  Token get beginToken => type?.beginToken ?? name;
+
+  @override
+  Token get endToken => name;
+
+  /// If [keyword] is `final`, returns it.
+  Token? get finalKeyword {
+    final keyword = this.keyword;
+    if (keyword != null && keyword.keyword == Keyword.FINAL) {
+      return keyword;
+    }
+    return null;
+  }
+
+  @override
+  ChildEntities get _childEntities => super._childEntities
+    ..addToken('keyword', keyword)
+    ..addNode('type', type)
+    ..addToken('name', name);
+
+  @override
+  E? accept<E>(AstVisitor<E> visitor) => visitor.visitWildcardPattern(this);
+
+  @override
+  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
+    return resolverVisitor
+        .analyzeDeclaredVariablePatternSchema(type?.typeOrThrow);
+  }
+
+  @override
+  void resolvePattern(
+    ResolverVisitor resolverVisitor,
+    SharedMatchContext context,
+  ) {
+    resolverVisitor.analyzeWildcardPattern(
+      context: context,
+      node: this,
+      declaredType: type?.typeOrThrow,
+    );
+  }
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    type?.accept(visitor);
+  }
+}
+
 /// The with clause in a class declaration.
 ///
 ///    withClause ::=
diff --git a/analyzer/lib/src/dart/ast/element_locator.dart b/analyzer/lib/src/dart/ast/element_locator.dart
index 8291b76..525f284 100644
--- a/analyzer/lib/src/dart/ast/element_locator.dart
+++ b/analyzer/lib/src/dart/ast/element_locator.dart
@@ -27,6 +27,11 @@
   }
 
   @override
+  Element? visitAssignedVariablePattern(AssignedVariablePattern node) {
+    return node.element;
+  }
+
+  @override
   Element? visitAssignmentExpression(AssignmentExpression node) {
     return node.staticElement;
   }
@@ -74,6 +79,11 @@
   }
 
   @override
+  Element? visitDeclaredVariablePattern(DeclaredVariablePattern node) {
+    return node.declaredElement;
+  }
+
+  @override
   Element? visitEnumConstantDeclaration(EnumConstantDeclaration node) {
     return node.declaredElement;
   }
@@ -192,6 +202,20 @@
   }
 
   @override
+  Element? visitPatternField(PatternField node) {
+    return node.element;
+  }
+
+  @override
+  Element? visitPatternFieldName(PatternFieldName node) {
+    final parent = node.parent;
+    if (parent is PatternField) {
+      return parent.element;
+    }
+    return super.visitPatternFieldName(node);
+  }
+
+  @override
   Element? visitPostfixExpression(PostfixExpression node) {
     return node.staticElement;
   }
diff --git a/analyzer/lib/src/dart/ast/to_source_visitor.dart b/analyzer/lib/src/dart/ast/to_source_visitor.dart
index d1bb803..3a6a358 100644
--- a/analyzer/lib/src/dart/ast/to_source_visitor.dart
+++ b/analyzer/lib/src/dart/ast/to_source_visitor.dart
@@ -106,15 +106,6 @@
   }
 
   @override
-  void visitBinaryPattern(BinaryPattern node) {
-    _visitNode(node.leftOperand);
-    sink.write(' ');
-    sink.write(node.operator.lexeme);
-    sink.write(' ');
-    _visitNode(node.rightOperand);
-  }
-
-  @override
   void visitBlock(Block node) {
     sink.write('{');
     _visitNodeList(node.statements, separator: ' ');
@@ -194,6 +185,9 @@
     _visitToken(node.abstractKeyword, suffix: ' ');
     _visitToken(node.macroKeyword, suffix: ' ');
     _visitToken(node.sealedKeyword, suffix: ' ');
+    _visitToken(node.baseKeyword, suffix: ' ');
+    _visitToken(node.interfaceKeyword, suffix: ' ');
+    _visitToken(node.finalKeyword, suffix: ' ');
     _visitToken(node.mixinKeyword, suffix: ' ');
     sink.write('class ');
     _visitToken(node.name);
@@ -213,6 +207,9 @@
     _visitToken(node.abstractKeyword, suffix: ' ');
     _visitToken(node.macroKeyword, suffix: ' ');
     _visitToken(node.sealedKeyword, suffix: ' ');
+    _visitToken(node.baseKeyword, suffix: ' ');
+    _visitToken(node.interfaceKeyword, suffix: ' ');
+    _visitToken(node.finalKeyword, suffix: ' ');
     _visitToken(node.mixinKeyword, suffix: ' ');
     sink.write('class ');
     _visitToken(node.name);
@@ -825,6 +822,24 @@
   }
 
   @override
+  void visitLogicalAndPattern(LogicalAndPattern node) {
+    _visitNode(node.leftOperand);
+    sink.write(' ');
+    sink.write(node.operator.lexeme);
+    sink.write(' ');
+    _visitNode(node.rightOperand);
+  }
+
+  @override
+  void visitLogicalOrPattern(LogicalOrPattern node) {
+    _visitNode(node.leftOperand);
+    sink.write(' ');
+    sink.write(node.operator.lexeme);
+    sink.write(' ');
+    _visitNode(node.rightOperand);
+  }
+
+  @override
   void visitMapLiteralEntry(MapLiteralEntry node) {
     _visitNode(node.key);
     sink.write(' : ');
@@ -874,6 +889,10 @@
   @override
   void visitMixinDeclaration(MixinDeclaration node) {
     _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+    _visitToken(node.sealedKeyword, suffix: ' ');
+    _visitToken(node.baseKeyword, suffix: ' ');
+    _visitToken(node.interfaceKeyword, suffix: ' ');
+    _visitToken(node.finalKeyword, suffix: ' ');
     sink.write('mixin ');
     _visitToken(node.name);
     _visitNode(node.typeParameters);
@@ -913,6 +932,18 @@
   }
 
   @override
+  void visitNullAssertPattern(NullAssertPattern node) {
+    _visitNode(node.pattern);
+    sink.write(node.operator.lexeme);
+  }
+
+  @override
+  void visitNullCheckPattern(NullCheckPattern node) {
+    _visitNode(node.pattern);
+    sink.write(node.operator.lexeme);
+  }
+
+  @override
   void visitNullLiteral(NullLiteral node) {
     sink.write('null');
   }
@@ -970,6 +1001,18 @@
   }
 
   @override
+  void visitPatternField(PatternField node) {
+    _visitNode(node.name, suffix: ' ');
+    _visitNode(node.pattern);
+  }
+
+  @override
+  void visitPatternFieldName(PatternFieldName node) {
+    _visitToken(node.name);
+    sink.write(':');
+  }
+
+  @override
   void visitPatternVariableDeclaration(PatternVariableDeclaration node) {
     _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
     sink.write(node.keyword.lexeme);
@@ -993,12 +1036,6 @@
   }
 
   @override
-  void visitPostfixPattern(PostfixPattern node) {
-    _visitNode(node.operand);
-    sink.write(node.operator.lexeme);
-  }
-
-  @override
   void visitPrefixedIdentifier(PrefixedIdentifier node) {
     _visitNode(node.prefix);
     sink.write('.');
@@ -1041,18 +1078,6 @@
   }
 
   @override
-  void visitRecordPatternField(RecordPatternField node) {
-    _visitNode(node.fieldName, suffix: ' ');
-    _visitNode(node.pattern);
-  }
-
-  @override
-  void visitRecordPatternFieldName(RecordPatternFieldName node) {
-    _visitToken(node.name);
-    sink.write(':');
-  }
-
-  @override
   void visitRecordTypeAnnotation(RecordTypeAnnotation node) {
     var positionalFields = node.positionalFields;
     var namedFields = node.namedFields;
@@ -1289,6 +1314,7 @@
 
   @override
   void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
+    _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
     _visitToken(node.externalKeyword, suffix: ' ');
     _visitNode(node.variables, suffix: ';');
   }
@@ -1370,6 +1396,13 @@
   }
 
   @override
+  void visitWildcardPattern(WildcardPattern node) {
+    _visitToken(node.keyword, suffix: ' ');
+    _visitNode(node.type, suffix: ' ');
+    sink.write(node.name.lexeme);
+  }
+
+  @override
   void visitWithClause(WithClause node) {
     sink.write('with ');
     _visitNodeList(node.mixinTypes, separator: ', ');
diff --git a/analyzer/lib/src/dart/ast/utilities.dart b/analyzer/lib/src/dart/ast/utilities.dart
index fdf7d61..69336f4 100644
--- a/analyzer/lib/src/dart/ast/utilities.dart
+++ b/analyzer/lib/src/dart/ast/utilities.dart
@@ -192,14 +192,6 @@
   }
 
   @override
-  bool visitBinaryPattern(BinaryPattern node) {
-    var other = _other as BinaryPattern;
-    return isEqualNodes(node.leftOperand, other.leftOperand) &&
-        isEqualTokens(node.operator, other.operator) &&
-        isEqualNodes(node.rightOperand, other.rightOperand);
-  }
-
-  @override
   bool visitBlock(Block node) {
     Block other = _other as Block;
     return isEqualTokens(node.leftBracket, other.leftBracket) &&
@@ -949,6 +941,22 @@
   }
 
   @override
+  bool visitLogicalAndPattern(LogicalAndPattern node) {
+    var other = _other as LogicalAndPattern;
+    return isEqualNodes(node.leftOperand, other.leftOperand) &&
+        isEqualTokens(node.operator, other.operator) &&
+        isEqualNodes(node.rightOperand, other.rightOperand);
+  }
+
+  @override
+  bool visitLogicalOrPattern(LogicalOrPattern node) {
+    var other = _other as LogicalOrPattern;
+    return isEqualNodes(node.leftOperand, other.leftOperand) &&
+        isEqualTokens(node.operator, other.operator) &&
+        isEqualNodes(node.rightOperand, other.rightOperand);
+  }
+
+  @override
   bool visitMapLiteralEntry(MapLiteralEntry node) {
     MapLiteralEntry other = _other as MapLiteralEntry;
     return isEqualNodes(node.key, other.key) &&
@@ -1045,6 +1053,20 @@
   }
 
   @override
+  bool visitNullAssertPattern(NullAssertPattern node) {
+    var other = _other as NullAssertPattern;
+    return isEqualNodes(node.pattern, other.pattern) &&
+        isEqualTokens(node.operator, other.operator);
+  }
+
+  @override
+  bool visitNullCheckPattern(NullCheckPattern node) {
+    var other = _other as NullCheckPattern;
+    return isEqualNodes(node.pattern, other.pattern) &&
+        isEqualTokens(node.operator, other.operator);
+  }
+
+  @override
   bool visitNullLiteral(NullLiteral node) {
     NullLiteral other = _other as NullLiteral;
     return isEqualTokens(node.literal, other.literal);
@@ -1115,6 +1137,20 @@
   }
 
   @override
+  bool visitPatternField(PatternField node) {
+    var other = _other as PatternField;
+    return isEqualNodes(node.name, other.name) &&
+        isEqualNodes(node.pattern, other.pattern);
+  }
+
+  @override
+  bool visitPatternFieldName(PatternFieldName node) {
+    var other = _other as PatternFieldName;
+    return isEqualTokens(node.name, other.name) &&
+        isEqualTokens(node.colon, other.colon);
+  }
+
+  @override
   bool visitPatternVariableDeclaration(PatternVariableDeclaration node) {
     var other = _other as PatternVariableDeclaration;
     return isEqualNodes(
@@ -1142,13 +1178,6 @@
   }
 
   @override
-  bool visitPostfixPattern(PostfixPattern node) {
-    var other = _other as PostfixPattern;
-    return isEqualNodes(node.operand, other.operand) &&
-        isEqualTokens(node.operator, other.operator);
-  }
-
-  @override
   bool visitPrefixedIdentifier(PrefixedIdentifier node) {
     PrefixedIdentifier other = _other as PrefixedIdentifier;
     return isEqualNodes(node.prefix, other.prefix) &&
@@ -1188,20 +1217,6 @@
   }
 
   @override
-  bool visitRecordPatternField(RecordPatternField node) {
-    var other = _other as RecordPatternField;
-    return isEqualNodes(node.fieldName, other.fieldName) &&
-        isEqualNodes(node.pattern, other.pattern);
-  }
-
-  @override
-  bool visitRecordPatternFieldName(RecordPatternFieldName node) {
-    var other = _other as RecordPatternFieldName;
-    return isEqualTokens(node.name, other.name) &&
-        isEqualTokens(node.colon, other.colon);
-  }
-
-  @override
   bool visitRecordTypeAnnotation(RecordTypeAnnotation node) {
     var other = _other as RecordTypeAnnotation;
     return _isEqualNodeLists(node.positionalFields, other.positionalFields) &&
@@ -1549,6 +1564,14 @@
   }
 
   @override
+  bool visitWildcardPattern(WildcardPattern node) {
+    var other = _other as WildcardPattern;
+    return isEqualTokens(node.keyword, other.keyword) &&
+        isEqualNodes(node.type, other.type) &&
+        isEqualTokens(node.name, other.name);
+  }
+
+  @override
   bool visitWithClause(WithClause node) {
     WithClause other = _other as WithClause;
     return isEqualTokens(node.withKeyword, other.withKeyword) &&
@@ -1623,7 +1646,7 @@
   /// Returns `true` if the exception was fully handled, and `false` if the
   /// exception should be rethrown.
   bool logException(
-      AstNode node, Object visitor, dynamic exception, StackTrace stackTrace) {
+      AstNode node, Object visitor, Object exception, StackTrace stackTrace) {
     StringBuffer buffer = StringBuffer();
     buffer.write('Exception while using a ${visitor.runtimeType} to visit a ');
     AstNode? currentNode = node;
@@ -1699,7 +1722,7 @@
   @override
   void visitConstructorDeclaration(ConstructorDeclaration node) {
     // Names do not have AstNodes but offsets at the end should be treated as
-    // part of the decleration (not parameter list).
+    // part of the declaration (not parameter list).
     if (_startOffset == _endOffset &&
         _startOffset == (node.name ?? node.returnType).end) {
       _foundNode = node;
@@ -1712,7 +1735,7 @@
   @override
   void visitFunctionDeclaration(FunctionDeclaration node) {
     // Names do not have AstNodes but offsets at the end should be treated as
-    // part of the decleration (not parameter list).
+    // part of the declaration (not parameter list).
     if (_startOffset == _endOffset && _startOffset == node.name.end) {
       _foundNode = node;
       return;
@@ -1724,7 +1747,7 @@
   @override
   void visitMethodDeclaration(MethodDeclaration node) {
     // Names do not have AstNodes but offsets at the end should be treated as
-    // part of the decleration (not parameter list).
+    // part of the declaration (not parameter list).
     if (_startOffset == _endOffset && _startOffset == node.name.end) {
       _foundNode = node;
       return;
@@ -1829,7 +1852,7 @@
   @override
   void visitConstructorDeclaration(ConstructorDeclaration node) {
     // Names do not have AstNodes but offsets at the end should be treated as
-    // part of the decleration (not parameter list).
+    // part of the declaration (not parameter list).
     if (_startOffset == _endOffset &&
         _startOffset == (node.name ?? node.returnType).end) {
       _foundNode = node;
@@ -1842,7 +1865,7 @@
   @override
   void visitFunctionDeclaration(FunctionDeclaration node) {
     // Names do not have AstNodes but offsets at the end should be treated as
-    // part of the decleration (not parameter list).
+    // part of the declaration (not parameter list).
     if (_startOffset == _endOffset && _startOffset == node.name.end) {
       _foundNode = node;
       return;
@@ -1854,7 +1877,7 @@
   @override
   void visitMethodDeclaration(MethodDeclaration node) {
     // Names do not have AstNodes but offsets at the end should be treated as
-    // part of the decleration (not parameter list).
+    // part of the declaration (not parameter list).
     if (_startOffset == _endOffset && _startOffset == node.name.end) {
       _foundNode = node;
       return;
@@ -2491,6 +2514,16 @@
   }
 
   @override
+  bool? visitForEachPartsWithPattern(ForEachPartsWithPattern node) {
+    if (identical(node.iterable, _oldNode)) {
+      (node as ForEachPartsWithPatternImpl).iterable =
+          _newNode as ExpressionImpl;
+      return true;
+    }
+    return visitNode(node);
+  }
+
+  @override
   bool visitForElement(ForElement node) {
     if (identical(node.forLoopParts, _oldNode)) {
       (node as ForElementImpl).forLoopParts = _newNode as ForLoopPartsImpl;
diff --git a/analyzer/lib/src/dart/constant/constant_verifier.dart b/analyzer/lib/src/dart/constant/constant_verifier.dart
index 032c528..45e8ceb 100644
--- a/analyzer/lib/src/dart/constant/constant_verifier.dart
+++ b/analyzer/lib/src/dart/constant/constant_verifier.dart
@@ -2,6 +2,10 @@
 // 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:collection';
+
+import 'package:_fe_analyzer_shared/src/exhaustiveness/exhaustive.dart';
+import 'package:_fe_analyzer_shared/src/exhaustiveness/space.dart';
 import 'package:analyzer/dart/analysis/declared_variables.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -22,6 +26,7 @@
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/diagnostic/diagnostic_factory.dart';
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/exhaustiveness.dart';
 
 /// Instances of the class `ConstantVerifier` traverse an AST structure looking
 /// for additional errors and warnings not covered by the parser and resolver.
@@ -47,17 +52,29 @@
 
   final DiagnosticFactory _diagnosticFactory = DiagnosticFactory();
 
+  /// Cache used for checking exhaustiveness.
+  final AnalyzerExhaustivenessCache _exhaustivenessCache;
+
+  /// Cache of constant values used for exhaustiveness checking.
+  ///
+  /// When verifying a switch statement/expression the constant values of the
+  /// contained [ConstantPattern]s are cached here. The cache is released once
+  /// the exhaustiveness of the switch has been checked.
+  Map<ConstantPattern, DartObjectImpl>? _constantPatternValues;
+
+  final ExhaustivenessDataForTesting? exhaustivenessDataForTesting;
+
   /// Initialize a newly created constant verifier.
-  ConstantVerifier(
-    ErrorReporter errorReporter,
-    LibraryElementImpl currentLibrary,
-    DeclaredVariables declaredVariables,
-  ) : this._(
+  ConstantVerifier(ErrorReporter errorReporter,
+      LibraryElementImpl currentLibrary, DeclaredVariables declaredVariables,
+      {bool retainDataForTesting = false})
+      : this._(
           errorReporter,
           currentLibrary,
           currentLibrary.typeSystem,
           currentLibrary.typeProvider,
           declaredVariables,
+          retainDataForTesting,
         );
 
   ConstantVerifier._(
@@ -66,12 +83,16 @@
     this._typeSystem,
     this._typeProvider,
     this.declaredVariables,
-  ) : _evaluationEngine = ConstantEvaluationEngine(
+    bool retainDataForTesting,
+  )   : _evaluationEngine = ConstantEvaluationEngine(
           declaredVariables: declaredVariables,
           isNonNullableByDefault:
               _currentLibrary.featureSet.isEnabled(Feature.non_nullable),
           configuration: ConstantEvaluationConfiguration(),
-        );
+        ),
+        _exhaustivenessCache = AnalyzerExhaustivenessCache(_typeSystem),
+        exhaustivenessDataForTesting =
+            retainDataForTesting ? ExhaustivenessDataForTesting() : null;
 
   @override
   void visitAnnotation(Annotation node) {
@@ -102,10 +123,13 @@
     super.visitConstantPattern(node);
 
     var expression = node.expression.unParenthesized;
-    _validate(
+    DartObjectImpl? value = _validate(
       expression,
       CompileTimeErrorCode.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION,
     );
+    if (value != null) {
+      _constantPatternValues?[node] = value;
+    }
   }
 
   @override
@@ -230,12 +254,70 @@
   }
 
   @override
+  void visitMapPattern(MapPattern node) {
+    node.typeArguments?.accept(this);
+
+    var uniqueKeys = HashMap<DartObjectImpl, Expression>(
+      hashCode: (_) => 0,
+      equals: (a, b) {
+        if (a.isIdentical2(_typeSystem, b).toBoolValue() == true) {
+          return true;
+        }
+        if (_isRecordTypeWithPrimitiveEqual(a.type) &&
+            _isRecordTypeWithPrimitiveEqual(b.type)) {
+          return a == b;
+        }
+        return false;
+      },
+    );
+    var duplicateKeys = <Expression, Expression>{};
+    for (var element in node.elements) {
+      element.accept(this);
+      if (element is MapPatternEntry) {
+        var key = element.key;
+        var keyValue = _validate(
+          key,
+          CompileTimeErrorCode.NON_CONSTANT_MAP_PATTERN_KEY,
+        );
+        if (keyValue != null) {
+          var existingKey = uniqueKeys[keyValue];
+          if (existingKey != null) {
+            duplicateKeys[key] = existingKey;
+          } else {
+            uniqueKeys[keyValue] = key;
+          }
+        }
+      }
+    }
+
+    for (var duplicateEntry in duplicateKeys.entries) {
+      _errorReporter.reportError(
+        _diagnosticFactory.equalKeysInMapPattern(
+          _errorReporter.source,
+          duplicateEntry.key,
+          duplicateEntry.value,
+        ),
+      );
+    }
+  }
+
+  @override
   void visitMethodDeclaration(MethodDeclaration node) {
     super.visitMethodDeclaration(node);
     _validateDefaultValues(node.parameters);
   }
 
   @override
+  void visitRelationalPattern(RelationalPattern node) {
+    super.visitRelationalPattern(node);
+
+    _validate(
+      node.operand,
+      CompileTimeErrorCode.NON_CONSTANT_RELATIONAL_PATTERN_EXPRESSION,
+    );
+  }
+
+  @override
   void visitSetOrMapLiteral(SetOrMapLiteral node) {
     super.visitSetOrMapLiteral(node);
     if (node.isSet) {
@@ -287,13 +369,37 @@
   }
 
   @override
+  void visitSwitchExpression(SwitchExpression node) {
+    _withConstantPatternValues((constantPatternValues) {
+      super.visitSwitchExpression(node);
+      _validateSwitchExhaustiveness(
+        node: node,
+        switchKeyword: node.switchKeyword,
+        scrutinee: node.expression,
+        caseNodes: node.cases,
+        constantPatternValues: constantPatternValues,
+      );
+    });
+  }
+
+  @override
   void visitSwitchStatement(SwitchStatement node) {
-    if (_currentLibrary.isNonNullableByDefault) {
-      _validateSwitchStatement_nullSafety(node);
-    } else {
-      _validateSwitchStatement_legacy(node);
-    }
-    super.visitSwitchStatement(node);
+    _withConstantPatternValues((constantPatternValues) {
+      super.visitSwitchStatement(node);
+      if (_currentLibrary.featureSet.isEnabled(Feature.patterns)) {
+        _validateSwitchExhaustiveness(
+          node: node,
+          switchKeyword: node.switchKeyword,
+          scrutinee: node.expression,
+          caseNodes: node.members,
+          constantPatternValues: constantPatternValues,
+        );
+      } else if (_currentLibrary.isNonNullableByDefault) {
+        _validateSwitchStatement_nullSafety(node);
+      } else {
+        _validateSwitchStatement_legacy(node);
+      }
+    });
   }
 
   @override
@@ -394,6 +500,10 @@
     return false;
   }
 
+  bool _isRecordTypeWithPrimitiveEqual(DartType type) {
+    return type is RecordType && !_implementsEqualsWhenNotAllowed(type);
+  }
+
   /// Report any errors in the given list. Except for special cases, use the
   /// given error code rather than the one reported in the error.
   ///
@@ -628,6 +738,97 @@
     }
   }
 
+  void _validateSwitchExhaustiveness({
+    required AstNode node,
+    required Token switchKeyword,
+    required Expression scrutinee,
+    required List<AstNode> caseNodes,
+    required Map<ConstantPattern, DartObjectImpl> constantPatternValues,
+  }) {
+    final scrutineeType = scrutinee.typeOrThrow;
+    final scrutineeTypeEx = _exhaustivenessCache.getStaticType(scrutineeType);
+
+    final caseNodesWithSpace = <AstNode>[];
+    final caseSpaces = <Space>[];
+    var hasDefault = false;
+
+    // Build spaces for cases.
+    for (final caseNode in caseNodes) {
+      GuardedPattern? guardedPattern;
+      if (caseNode is SwitchDefault) {
+        hasDefault = true;
+      } else if (caseNode is SwitchExpressionCase) {
+        guardedPattern = caseNode.guardedPattern;
+      } else if (caseNode is SwitchPatternCase) {
+        guardedPattern = caseNode.guardedPattern;
+      } else {
+        throw UnimplementedError('(${caseNode.runtimeType}) $caseNode');
+      }
+
+      if (guardedPattern != null) {
+        Space space;
+        if (guardedPattern.whenClause != null) {
+          // TODO(johnniwinther): Test this.
+          space = Space(_exhaustivenessCache.getUnknownStaticType());
+        } else {
+          final pattern = guardedPattern.pattern;
+          space = convertPatternToSpace(
+              _exhaustivenessCache, pattern, constantPatternValues);
+        }
+        caseNodesWithSpace.add(caseNode);
+        caseSpaces.add(space);
+      }
+    }
+
+    // Prepare for recording data for testing.
+    List<Space>? remainingSpaces;
+    final exhaustivenessDataForTesting = this.exhaustivenessDataForTesting;
+    if (exhaustivenessDataForTesting != null) {
+      remainingSpaces = [];
+    }
+
+    // Compute and report errors.
+    final errors = reportErrors(scrutineeTypeEx, caseSpaces, remainingSpaces);
+    for (final error in errors) {
+      if (error is UnreachableCaseError) {
+        final caseNode = caseNodesWithSpace[error.index];
+        final Token errorToken;
+        if (caseNode is SwitchExpressionCase) {
+          errorToken = caseNode.arrow;
+        } else if (caseNode is SwitchPatternCase) {
+          errorToken = caseNode.keyword;
+        } else {
+          throw UnimplementedError('(${caseNode.runtimeType}) $caseNode');
+        }
+        _errorReporter.reportErrorForToken(
+          HintCode.UNREACHABLE_SWITCH_CASE,
+          errorToken,
+        );
+      } else if (error is NonExhaustiveError &&
+          _typeSystem.isAlwaysExhaustive(scrutineeType) &&
+          !hasDefault) {
+        _errorReporter.reportErrorForToken(
+          CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH,
+          switchKeyword,
+          [scrutineeType, '${error.remaining}'],
+        );
+      }
+    }
+
+    // Record data for testing.
+    if (exhaustivenessDataForTesting != null && remainingSpaces != null) {
+      assert(remainingSpaces.length == caseSpaces.length + 1);
+      for (var i = 0; i < caseSpaces.length; i++) {
+        final caseNode = caseNodesWithSpace[i];
+        exhaustivenessDataForTesting.caseSpaces[caseNode] = caseSpaces[i];
+        exhaustivenessDataForTesting.remainingSpaces[caseNode] =
+            remainingSpaces[i];
+      }
+      exhaustivenessDataForTesting.switchScrutineeType[node] = scrutineeTypeEx;
+      exhaustivenessDataForTesting.remainingSpaces[node] = remainingSpaces.last;
+    }
+  }
+
   void _validateSwitchStatement_legacy(SwitchStatement node) {
     // TODO(paulberry): to minimize error messages, it would be nice to
     // compare all types with the most popular type rather than the first
@@ -715,6 +916,16 @@
       }
     }
   }
+
+  /// Runs [f] with new [_constantPatternValues].
+  void _withConstantPatternValues(
+    void Function(Map<ConstantPattern, DartObjectImpl> constantPatternValues) f,
+  ) {
+    final previous = _constantPatternValues;
+    final values = _constantPatternValues = {};
+    f(values);
+    _constantPatternValues = previous;
+  }
 }
 
 class _ConstLiteralVerifier {
diff --git a/analyzer/lib/src/dart/constant/evaluation.dart b/analyzer/lib/src/dart/constant/evaluation.dart
index 423e93f..db23259 100644
--- a/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/analyzer/lib/src/dart/constant/evaluation.dart
@@ -29,6 +29,7 @@
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/task/api/model.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 class ConstantEvaluationConfiguration {
   /// During evaluation of enum constants we might need to report an error
@@ -1367,7 +1368,7 @@
       var type = variableElement.instantiate(
         typeArguments: variableElement.typeParameters
             .map((t) => _typeProvider.dynamicType)
-            .toList(),
+            .toFixedList(),
         nullabilitySuffix: NullabilitySuffix.star,
       );
       return DartObjectImpl(
@@ -2038,15 +2039,16 @@
   /// The errors encountered while trying to evaluate the compile time constant.
   /// These errors may or may not have prevented the expression from being a
   /// valid compile time constant.
-  late final List<AnalysisError> _errors;
+  final List<AnalysisError> _errors;
 
   /// The value of the expression, or `null` if the value couldn't be computed
   /// due to errors.
   final DartObjectImpl? value;
 
-  EvaluationResultImpl(this.value, [List<AnalysisError>? errors]) {
-    _errors = errors ?? <AnalysisError>[];
-  }
+  EvaluationResultImpl(
+    this.value, [
+    this._errors = const [],
+  ]);
 
   List<AnalysisError> get errors => _errors;
 
diff --git a/analyzer/lib/src/dart/element/class_hierarchy.dart b/analyzer/lib/src/dart/element/class_hierarchy.dart
index 18764b6..8e34df0 100644
--- a/analyzer/lib/src/dart/element/class_hierarchy.dart
+++ b/analyzer/lib/src/dart/element/class_hierarchy.dart
@@ -7,6 +7,7 @@
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 class ClassHierarchy {
   final Map<InterfaceElement, _Hierarchy> _map = {};
@@ -88,8 +89,8 @@
       interfaces.add(collector.type);
     }
 
-    hierarchy.errors = errors;
-    hierarchy.interfaces = interfaces;
+    hierarchy.errors = errors.toFixedList();
+    hierarchy.interfaces = interfaces.toFixedList();
 
     return hierarchy;
   }
diff --git a/analyzer/lib/src/dart/element/display_string_builder.dart b/analyzer/lib/src/dart/element/display_string_builder.dart
index 26bff4b..abfdbda 100644
--- a/analyzer/lib/src/dart/element/display_string_builder.dart
+++ b/analyzer/lib/src/dart/element/display_string_builder.dart
@@ -34,9 +34,21 @@
   }
 
   void writeClassElement(ClassElementImpl element) {
-    if (element.isAbstract) {
+    if (element.isSealed) {
+      _write('sealed ');
+    } else if (element.isAbstract) {
       _write('abstract ');
     }
+    if (element.isBase) {
+      _write('base ');
+    } else if (element.isInterface) {
+      _write('interface ');
+    } else if (element.isFinal) {
+      _write('final ');
+    }
+    if (element.isMixinClass) {
+      _write('mixin ');
+    }
 
     _write('class ');
     _write(element.displayName);
@@ -150,6 +162,13 @@
   }
 
   void writeMixinElement(MixinElementImpl element) {
+    if (element.isBase) {
+      _write('base ');
+    } else if (element.isInterface) {
+      _write('interface ');
+    } else if (element.isFinal) {
+      _write('final ');
+    }
     _write('mixin ');
     _write(element.displayName);
     _writeTypeParameters(element.typeParameters);
diff --git a/analyzer/lib/src/dart/element/element.dart b/analyzer/lib/src/dart/element/element.dart
index 19c9bf1..c932e6a 100644
--- a/analyzer/lib/src/dart/element/element.dart
+++ b/analyzer/lib/src/dart/element/element.dart
@@ -4,6 +4,7 @@
 
 import 'dart:collection';
 
+import 'package:_fe_analyzer_shared/src/scanner/string_canonicalizer.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -48,6 +49,7 @@
 import 'package:analyzer/src/summary2/reference.dart';
 import 'package:analyzer/src/task/inference_error.dart';
 import 'package:analyzer/src/util/file_paths.dart' as file_paths;
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 import 'package:analyzer/src/utilities/extensions/string.dart';
 import 'package:collection/collection.dart';
 
@@ -206,7 +208,7 @@
       if (typeParameters.isNotEmpty) {
         typeArguments = typeParameters.map<DartType>((t) {
           return t.instantiate(nullabilitySuffix: _noneOrStarSuffix);
-        }).toList();
+        }).toFixedList();
       } else {
         typeArguments = const <DartType>[];
       }
@@ -409,7 +411,7 @@
   }
 
   /// Return an iterable containing all of the implementations of a getter with
-  /// the given [getterName] that are defined in this class any any superclass
+  /// the given [getterName] that are defined in this class and any superclass
   /// of this class (but not in interfaces).
   ///
   /// The getters that are returned are not filtered in any way. In particular,
@@ -439,7 +441,7 @@
   }
 
   /// Return an iterable containing all of the implementations of a method with
-  /// the given [methodName] that are defined in this class any any superclass
+  /// the given [methodName] that are defined in this class and any superclass
   /// of this class (but not in interfaces).
   ///
   /// The methods that are returned are not filtered in any way. In particular,
@@ -468,7 +470,7 @@
   }
 
   /// Return an iterable containing all of the implementations of a setter with
-  /// the given [setterName] that are defined in this class any any superclass
+  /// the given [setterName] that are defined in this class and any superclass
   /// of this class (but not in interfaces).
   ///
   /// The setters that are returned are not filtered in any way. In particular,
@@ -564,6 +566,13 @@
       visitor.visitAugmentationImportElement(this);
 }
 
+class BindPatternVariableElementImpl extends PatternVariableElementImpl
+    implements BindPatternVariableElement {
+  final DeclaredVariablePatternImpl node;
+
+  BindPatternVariableElementImpl(this.node, super.name, super.offset);
+}
+
 /// An [AbstractClassElementImpl] which is a class.
 class ClassElementImpl extends ClassOrMixinElementImpl implements ClassElement {
   /// Initialize a newly created class element to have the given [name] at the
@@ -730,6 +739,9 @@
     return true;
   }
 
+  @override
+  bool get isExhaustive => isSealed;
+
   bool get isMacro {
     return hasModifier(Modifier.MACRO);
   }
@@ -748,6 +760,7 @@
     setModifier(Modifier.MIXIN_APPLICATION, isMixinApplication);
   }
 
+  @override
   bool get isMixinClass {
     return hasModifier(Modifier.MIXIN_CLASS);
   }
@@ -795,6 +808,32 @@
     builder.writeClassElement(this);
   }
 
+  @override
+  bool isExtendableIn(LibraryElement library) {
+    if (library == this.library) {
+      return true;
+    }
+    return !isInterface && !isFinal && !isSealed;
+  }
+
+  @override
+  bool isImplementableIn(LibraryElement library) {
+    if (library == this.library) {
+      return true;
+    }
+    return !isBase && !isFinal && !isSealed;
+  }
+
+  @override
+  bool isMixableIn(LibraryElement library) {
+    if (library == this.library) {
+      return true;
+    } else if (this.library.featureSet.isEnabled(Feature.class_modifiers)) {
+      return isMixinClass && !isInterface && !isFinal && !isSealed;
+    }
+    return true;
+  }
+
   /// Compute a list of constructors for this class, which is a mixin
   /// application.  If specified, [visitedClasses] is a list of the other mixin
   /// application classes which have been visited on the way to reaching this
@@ -914,7 +953,7 @@
               ..staticType = implicitParameter.type,
           );
         }
-        implicitConstructor.parameters = implicitParameters;
+        implicitConstructor.parameters = implicitParameters.toFixedList();
       }
       implicitConstructor.enclosingElement = this;
       // TODO(scheglov) Why do we manually map parameters types above?
@@ -1006,6 +1045,30 @@
     return _interfaces;
   }
 
+  bool get isBase {
+    return hasModifier(Modifier.BASE);
+  }
+
+  set isBase(bool isBase) {
+    setModifier(Modifier.BASE, isBase);
+  }
+
+  bool get isFinal {
+    return hasModifier(Modifier.FINAL);
+  }
+
+  set isFinal(bool isFinal) {
+    setModifier(Modifier.FINAL, isFinal);
+  }
+
+  bool get isInterface {
+    return hasModifier(Modifier.INTERFACE);
+  }
+
+  set isInterface(bool isInterface) {
+    setModifier(Modifier.INTERFACE, isInterface);
+  }
+
   bool get isSealed {
     return hasModifier(Modifier.SEALED);
   }
@@ -1951,6 +2014,10 @@
   /// protected.
   static const String _protectedVariableName = 'protected';
 
+  /// The name of the top-level variable used to mark a class or mixin as being
+  /// reopened.
+  static const String _reopenVariableName = 'reopen';
+
   /// The name of the class used to mark a parameter as being required.
   static const String _requiredClassName = 'Required';
 
@@ -2088,6 +2155,9 @@
   bool get isProxy => false;
 
   @override
+  bool get isReopen => _isPackageMetaGetter(_reopenVariableName);
+
+  @override
   bool get isRequired =>
       _isConstructor(
           libraryName: _metaLibName, className: _requiredClassName) ||
@@ -2472,6 +2542,18 @@
   }
 
   @override
+  bool get hasReopen {
+    final metadata = this.metadata;
+    for (var i = 0; i < metadata.length; i++) {
+      var annotation = metadata[i];
+      if (annotation.isReopen) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @override
   bool get hasRequired {
     final metadata = this.metadata;
     for (var i = 0; i < metadata.length; i++) {
@@ -2823,7 +2905,7 @@
       components.insert(0, (ancestor as ElementImpl).identifier);
       ancestor = ancestor.enclosingElement;
     }
-    _components = components;
+    _components = components.toFixedList();
   }
 
   /// Initialize a newly created location from the given [encoding].
@@ -3575,7 +3657,7 @@
     if (enclosing is ExecutableElement || enclosing is VariableElement) {
       identifier += "@$nameOffset";
     }
-    return identifier;
+    return considerCanonicalizeString(identifier);
   }
 
   @override
@@ -3748,24 +3830,63 @@
   });
 }
 
+class JoinPatternVariableElementImpl extends PatternVariableElementImpl
+    implements JoinPatternVariableElement {
+  @override
+  final List<PatternVariableElementImpl> variables;
+
+  @override
+  bool isConsistent;
+
+  /// The identifiers that reference this element.
+  final List<SimpleIdentifier> references = [];
+
+  JoinPatternVariableElementImpl(
+    super.name,
+    super.offset,
+    this.variables,
+    this.isConsistent,
+  ) {
+    for (var component in variables) {
+      component.join = this;
+    }
+  }
+
+  @override
+  int get hashCode => identityHashCode(this);
+
+  /// Returns this variable, and variables that join into it.
+  List<PatternVariableElementImpl> get transitiveVariables {
+    var result = <PatternVariableElementImpl>[];
+
+    void append(PatternVariableElementImpl variable) {
+      result.add(variable);
+      if (variable is JoinPatternVariableElementImpl) {
+        for (var variable in variable.variables) {
+          append(variable);
+        }
+      }
+    }
+
+    append(this);
+    return result;
+  }
+
+  @override
+  bool operator ==(Object other) => identical(other, this);
+}
+
 /// A concrete implementation of a [LabelElement].
 class LabelElementImpl extends ElementImpl implements LabelElement {
-  /// A flag indicating whether this label is associated with a `switch`
-  /// statement.
-  // TODO(brianwilkerson) Make this a modifier.
-  final bool _onSwitchStatement;
-
   /// A flag indicating whether this label is associated with a `switch` member
   /// (`case` or `default`).
   // TODO(brianwilkerson) Make this a modifier.
   final bool _onSwitchMember;
 
   /// Initialize a newly created label element to have the given [name].
-  /// [onSwitchStatement] should be `true` if this label is associated with a
-  /// `switch` statement and [onSwitchMember] should be `true` if this label is
-  /// associated with a `switch` member.
-  LabelElementImpl(String super.name, super.nameOffset, this._onSwitchStatement,
-      this._onSwitchMember);
+  /// [onSwitchMember] should be `true` if this label is associated with a
+  /// `switch` member.
+  LabelElementImpl(String super.name, super.nameOffset, this._onSwitchMember);
 
   @override
   String get displayName => name;
@@ -3782,9 +3903,6 @@
   /// ` or`default`).
   bool get isOnSwitchMember => _onSwitchMember;
 
-  /// Return `true` if this label is associated with a `switch` statement.
-  bool get isOnSwitchStatement => _onSwitchStatement;
-
   @override
   ElementKind get kind => ElementKind.LABEL;
 
@@ -4307,7 +4425,7 @@
     }
 
     visitAugmentations(this);
-    return result;
+    return result.toFixedList();
   }
 
   @override
@@ -4622,7 +4740,11 @@
 
 mixin MacroTargetElement {
   /// Errors registered while applying macros to this element.
-  List<MacroApplicationError> macroApplicationErrors = [];
+  List<MacroApplicationError> macroApplicationErrors = const [];
+
+  void addMacroApplicationError(MacroApplicationError error) {
+    macroApplicationErrors = [...macroApplicationErrors, error];
+  }
 }
 
 /// Marker interface for elements that may have [MacroTargetElement]s.
@@ -4745,6 +4867,9 @@
   }
 
   @override
+  bool get isExhaustive => isSealed;
+
+  @override
   List<InterfaceType> get mixins => const <InterfaceType>[];
 
   @override
@@ -4762,7 +4887,7 @@
 
   @override
   set supertype(InterfaceType? supertype) {
-    throw StateError('Attempt to set a supertype for a mixin declaratio.');
+    throw StateError('Attempt to set a supertype for a mixin declaration.');
   }
 
   @override
@@ -4774,6 +4899,22 @@
   void appendTo(ElementDisplayStringBuilder builder) {
     builder.writeMixinElement(this);
   }
+
+  @override
+  bool isImplementableIn(LibraryElement library) {
+    if (library == this.library) {
+      return true;
+    }
+    return !isBase && !isFinal && !isSealed;
+  }
+
+  @override
+  bool isMixableIn(LibraryElement library) {
+    if (library == this.library) {
+      return true;
+    }
+    return !isInterface && !isFinal && !isSealed;
+  }
 }
 
 /// The constants for all of the modifiers defined by the Dart language and for
@@ -4788,97 +4929,110 @@
   /// asynchronous.
   static const Modifier ASYNCHRONOUS = Modifier('ASYNCHRONOUS', 1);
 
+  /// Indicates that the modifier 'base' was applied to the element.
+  static const Modifier BASE = Modifier('BASE', 2);
+
   /// Indicates that the modifier 'const' was applied to the element.
-  static const Modifier CONST = Modifier('CONST', 2);
+  static const Modifier CONST = Modifier('CONST', 3);
 
   /// Indicates that the modifier 'covariant' was applied to the element.
-  static const Modifier COVARIANT = Modifier('COVARIANT', 3);
+  static const Modifier COVARIANT = Modifier('COVARIANT', 4);
 
   /// Indicates that the class is `Object` from `dart:core`.
-  static const Modifier DART_CORE_OBJECT = Modifier('DART_CORE_OBJECT', 4);
+  static const Modifier DART_CORE_OBJECT = Modifier('DART_CORE_OBJECT', 5);
 
   /// Indicates that the import element represents a deferred library.
-  static const Modifier DEFERRED = Modifier('DEFERRED', 5);
+  static const Modifier DEFERRED = Modifier('DEFERRED', 6);
 
   /// Indicates that a class element was defined by an enum declaration.
-  static const Modifier ENUM = Modifier('ENUM', 6);
+  static const Modifier ENUM = Modifier('ENUM', 7);
 
   /// Indicates that the element is an enum constant field.
-  static const Modifier ENUM_CONSTANT = Modifier('ENUM_CONSTANT', 7);
+  static const Modifier ENUM_CONSTANT = Modifier('ENUM_CONSTANT', 8);
 
   /// Indicates that a class element was defined by an enum declaration.
-  static const Modifier EXTERNAL = Modifier('EXTERNAL', 8);
+  static const Modifier EXTERNAL = Modifier('EXTERNAL', 9);
 
   /// Indicates that the modifier 'factory' was applied to the element.
-  static const Modifier FACTORY = Modifier('FACTORY', 9);
+  static const Modifier FACTORY = Modifier('FACTORY', 10);
 
   /// Indicates that the modifier 'final' was applied to the element.
-  static const Modifier FINAL = Modifier('FINAL', 10);
+  static const Modifier FINAL = Modifier('FINAL', 11);
 
   /// Indicates that an executable element has a body marked as being a
   /// generator.
-  static const Modifier GENERATOR = Modifier('GENERATOR', 11);
+  static const Modifier GENERATOR = Modifier('GENERATOR', 12);
 
   /// Indicates that the pseudo-modifier 'get' was applied to the element.
-  static const Modifier GETTER = Modifier('GETTER', 12);
+  static const Modifier GETTER = Modifier('GETTER', 13);
 
   /// A flag used for libraries indicating that the variable has an explicit
   /// initializer.
-  static const Modifier HAS_INITIALIZER = Modifier('HAS_INITIALIZER', 13);
+  static const Modifier HAS_INITIALIZER = Modifier('HAS_INITIALIZER', 14);
 
   /// A flag used for libraries indicating that the defining compilation unit
   /// has a `part of` directive, meaning that this unit should be a part,
   /// but is used as a library.
   static const Modifier HAS_PART_OF_DIRECTIVE =
-      Modifier('HAS_PART_OF_DIRECTIVE', 14);
+      Modifier('HAS_PART_OF_DIRECTIVE', 15);
 
   /// Indicates that the associated element did not have an explicit type
   /// associated with it. If the element is an [ExecutableElement], then the
   /// type being referred to is the return type.
-  static const Modifier IMPLICIT_TYPE = Modifier('IMPLICIT_TYPE', 15);
+  static const Modifier IMPLICIT_TYPE = Modifier('IMPLICIT_TYPE', 16);
+
+  /// Indicates that the modifier 'interface' was applied to the element.
+  static const Modifier INTERFACE = Modifier('INTERFACE', 17);
 
   /// Indicates that the method invokes the super method with the same name.
-  static const Modifier INVOKES_SUPER_SELF = Modifier('INVOKES_SUPER_SELF', 16);
+  static const Modifier INVOKES_SUPER_SELF = Modifier('INVOKES_SUPER_SELF', 18);
 
   /// Indicates that modifier 'lazy' was applied to the element.
-  static const Modifier LATE = Modifier('LATE', 17);
+  static const Modifier LATE = Modifier('LATE', 19);
 
   /// Indicates that a class is a macro builder.
-  static const Modifier MACRO = Modifier('MACRO', 18);
+  static const Modifier MACRO = Modifier('MACRO', 20);
 
   /// Indicates that a class is a mixin application.
-  static const Modifier MIXIN_APPLICATION = Modifier('MIXIN_APPLICATION', 19);
+  static const Modifier MIXIN_APPLICATION = Modifier('MIXIN_APPLICATION', 21);
 
   /// Indicates that a class is a mixin class.
-  static const Modifier MIXIN_CLASS = Modifier('MIXIN_CLASS', 20);
+  static const Modifier MIXIN_CLASS = Modifier('MIXIN_CLASS', 22);
 
-  static const Modifier PROMOTABLE = Modifier('IS_PROMOTABLE', 21);
+  static const Modifier PROMOTABLE = Modifier('IS_PROMOTABLE', 23);
+
+  /// Indicates whether the type of a [PropertyInducingElementImpl] should be
+  /// used to infer the initializer. We set it to `false` if the type was
+  /// inferred from the initializer itself.
+  static const Modifier SHOULD_USE_TYPE_FOR_INITIALIZER_INFERENCE =
+      Modifier('SHOULD_USE_TYPE_FOR_INITIALIZER_INFERENCE', 24);
 
   /// Indicates that the modifier 'sealed' was applied to the element.
-  static const Modifier SEALED = Modifier('SEALED', 22);
+  static const Modifier SEALED = Modifier('SEALED', 25);
 
   /// Indicates that the pseudo-modifier 'set' was applied to the element.
-  static const Modifier SETTER = Modifier('SETTER', 23);
+  static const Modifier SETTER = Modifier('SETTER', 26);
 
   /// See [TypeParameterizedElement.isSimplyBounded].
-  static const Modifier SIMPLY_BOUNDED = Modifier('SIMPLY_BOUNDED', 24);
+  static const Modifier SIMPLY_BOUNDED = Modifier('SIMPLY_BOUNDED', 27);
 
   /// Indicates that the modifier 'static' was applied to the element.
-  static const Modifier STATIC = Modifier('STATIC', 25);
+  static const Modifier STATIC = Modifier('STATIC', 28);
 
   /// Indicates that the element does not appear in the source code but was
   /// implicitly created. For example, if a class does not define any
   /// constructors, an implicit zero-argument constructor will be created and it
   /// will be marked as being synthetic.
-  static const Modifier SYNTHETIC = Modifier('SYNTHETIC', 26);
+  static const Modifier SYNTHETIC = Modifier('SYNTHETIC', 29);
 
   /// Indicates that the element was appended to this enclosing element to
   /// simulate temporary the effect of applying augmentation.
-  static const Modifier TEMP_AUGMENTATION = Modifier('TEMP_AUGMENTATION', 27);
+  static const Modifier TEMP_AUGMENTATION = Modifier('TEMP_AUGMENTATION', 30);
 
   static const List<Modifier> values = [
     ABSTRACT,
     ASYNCHRONOUS,
+    BASE,
     CONST,
     COVARIANT,
     DART_CORE_OBJECT,
@@ -4893,6 +5047,8 @@
     HAS_INITIALIZER,
     HAS_PART_OF_DIRECTIVE,
     IMPLICIT_TYPE,
+    INTERFACE,
+    INVOKES_SUPER_SELF,
     LATE,
     MACRO,
     MIXIN_APPLICATION,
@@ -5014,6 +5170,9 @@
   bool get hasProtected => false;
 
   @override
+  bool get hasReopen => false;
+
+  @override
   bool get hasRequired => false;
 
   @override
@@ -5344,7 +5503,7 @@
 
   ParameterElementImpl_ofImplicitSetter(this.setter)
       : super(
-          name: '_${setter.variable.name}',
+          name: considerCanonicalizeString('_${setter.variable.name}'),
           nameOffset: -1,
           parameterKind: ParameterKind.REQUIRED,
         ) {
@@ -5482,6 +5641,23 @@
   }
 }
 
+class PatternVariableElementImpl extends LocalVariableElementImpl
+    implements PatternVariableElement {
+  @override
+  JoinPatternVariableElementImpl? join;
+
+  /// This flag is set to `true` while we are visiting the [WhenClause] of
+  /// the [GuardedPattern] that declares this variable.
+  bool isVisitingWhenClause = false;
+
+  PatternVariableElementImpl(super.name, super.offset);
+
+  /// Return the root [join], or self.
+  PatternVariableElementImpl get rootVariable {
+    return join?.rootVariable ?? this;
+  }
+}
+
 /// A concrete implementation of a [PrefixElement].
 class PrefixElementImpl extends _ExistingElementImpl implements PrefixElement {
   /// The scope of this prefix, `null` if it has not been created yet.
@@ -5590,7 +5766,7 @@
   String get identifier {
     String name = displayName;
     String suffix = isGetter ? "?" : "=";
-    return "$name$suffix";
+    return considerCanonicalizeString("$name$suffix");
   }
 
   /// Set whether this class is abstract.
@@ -5635,7 +5811,7 @@
   @override
   String get name {
     if (isSetter) {
-      return "${super.name}=";
+      return considerCanonicalizeString("${super.name}=");
     }
     return super.name;
   }
@@ -5753,9 +5929,9 @@
       return _parameters;
     }
 
-    return _parameters = <ParameterElement>[
-      ParameterElementImpl_ofImplicitSetter(this)
-    ];
+    return _parameters = List.generate(
+        1, (_) => ParameterElementImpl_ofImplicitSetter(this),
+        growable: false);
   }
 
   @override
@@ -5814,7 +5990,9 @@
 
   /// Initialize a newly created synthetic element to have the given [name] and
   /// [offset].
-  PropertyInducingElementImpl(super.name, super.offset);
+  PropertyInducingElementImpl(super.name, super.offset) {
+    setModifier(Modifier.SHOULD_USE_TYPE_FOR_INITIALIZER_INFERENCE, true);
+  }
 
   @override
   bool get isConstantEvaluated => true;
@@ -5839,6 +6017,14 @@
     }
   }
 
+  bool get shouldUseTypeForInitializerInference {
+    return hasModifier(Modifier.SHOULD_USE_TYPE_FOR_INITIALIZER_INFERENCE);
+  }
+
+  set shouldUseTypeForInitializerInference(bool value) {
+    setModifier(Modifier.SHOULD_USE_TYPE_FOR_INITIALIZER_INFERENCE, value);
+  }
+
   @override
   DartType get type => ElementTypeProvider.current.getFieldType(this);
 
@@ -5878,7 +6064,9 @@
     }
 
     // We must be linking, and the type has not been set yet.
-    return _type = typeInference!.perform();
+    _type = typeInference!.perform();
+    shouldUseTypeForInitializerInference = false;
+    return _type!;
   }
 
   /// Return `true` if this variable needs the setter.
@@ -6554,34 +6742,6 @@
   DartObject? computeConstantValue() => null;
 }
 
-class VariablePatternBindElementImpl extends VariablePatternElementImpl
-    implements VariablePatternBindElement {
-  final DeclaredVariablePatternImpl node;
-
-  VariablePatternBindElementImpl(this.node, super.name, super.offset);
-}
-
-class VariablePatternElementImpl extends LocalVariableElementImpl
-    implements VariablePatternElement {
-  VariablePatternElementImpl(super.name, super.offset);
-}
-
-class VariablePatternJoinElementImpl extends VariablePatternElementImpl
-    implements VariablePatternJoinElement {
-  @override
-  final List<VariablePatternElementImpl> components;
-
-  @override
-  bool isConsistent;
-
-  VariablePatternJoinElementImpl(
-    super.name,
-    super.offset,
-    this.components,
-    this.isConsistent,
-  );
-}
-
 abstract class _ExistingElementImpl extends ElementImpl with _HasLibraryMixin {
   _ExistingElementImpl(super.name, super.offset, {super.reference});
 }
diff --git a/analyzer/lib/src/dart/element/extensions.dart b/analyzer/lib/src/dart/element/extensions.dart
index f587aba..2f6f6b9 100644
--- a/analyzer/lib/src/dart/element/extensions.dart
+++ b/analyzer/lib/src/dart/element/extensions.dart
@@ -134,7 +134,7 @@
 
 extension RecordTypeExtension on RecordType {
   /// A regular expression used to match positional field names.
-  static final RegExp _positionalName = RegExp(r'^\$(([0-9])|([1-9][0-9]*))$');
+  static final RegExp _positionalName = RegExp(r'^\$[1-9]\d*$');
 
   List<RecordTypeField> get fields {
     return [
@@ -144,7 +144,7 @@
   }
 
   /// The [name] is either an actual name like `foo` in `({int foo})`, or
-  /// the name of a positional field like `$0` in `(int, String)`.
+  /// the name of a positional field like `$1` in `(int, String)`.
   RecordTypeField? fieldByName(String name) {
     return namedField(name) ?? positionalField(name);
   }
@@ -166,14 +166,15 @@
     return null;
   }
 
-  /// Attempt to parse `$0`, `$1`, etc.
+  /// Attempt to parse `$1`, `$2`, etc.
   static int? positionalFieldIndex(String name) {
-    final match = _positionalName.firstMatch(name);
-    if (match != null) {
-      final indexStr = match.group(1);
-      if (indexStr != null) {
-        return int.tryParse(indexStr);
-      }
+    if (_positionalName.hasMatch(name)) {
+      final positionString = name.substring(1);
+      // Use `tryParse` instead of `parse`
+      // even though the numeral matches the pattern `[1-9]\d*`,
+      // to reject numerals too big to fit in an `int`.
+      final position = int.tryParse(positionString);
+      if (position != null) return position - 1;
     }
     return null;
   }
diff --git a/analyzer/lib/src/dart/element/generic_inferrer.dart b/analyzer/lib/src/dart/element/generic_inferrer.dart
index b542af5..b857fa9 100644
--- a/analyzer/lib/src/dart/element/generic_inferrer.dart
+++ b/analyzer/lib/src/dart/element/generic_inferrer.dart
@@ -4,9 +4,18 @@
 
 import 'dart:math' as math;
 
-import 'package:analyzer/dart/ast/ast.dart' show AstNode;
+import 'package:analyzer/dart/ast/ast.dart'
+    show
+        Annotation,
+        AsExpression,
+        AstNode,
+        ConstructorName,
+        Expression,
+        InvocationExpression,
+        SimpleIdentifier;
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/error/listener.dart' show ErrorReporter;
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/nullability_eliminator.dart';
 import 'package:analyzer/src/dart/element/type.dart';
@@ -15,7 +24,8 @@
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/element/type_schema.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
-import 'package:analyzer/src/dart/error/inference_error_listener.dart';
+import 'package:analyzer/src/error/codes.dart'
+    show CompileTimeErrorCode, WarningCode;
 import 'package:meta/meta.dart';
 
 /// Tracks upper and lower type bounds for a set of type parameters.
@@ -25,7 +35,7 @@
 /// optimistically assume the constraint will be satisfied.
 ///
 /// For example if we are inferring type parameter A, and we ask if
-/// `A <: num`, this will record that A must be a subytpe of `num`. It also
+/// `A <: num`, this will record that A must be a subtype of `num`. It also
 /// handles cases when A appears as part of the structure of another type, for
 /// example `Iterable<A> <: Iterable<num>` would infer the same constraint
 /// (due to covariant generic types) as would `() -> A <: () -> num`. In
@@ -49,13 +59,12 @@
   /// The list of type parameters being inferred.
   final List<TypeParameterElement> _typeFormals;
 
-  /// The [InferenceErrorListener] to which inference errors should be reported,
-  /// or `null` if errors shouldn't be reported.
-  final InferenceErrorListener? _inferenceErrorListener;
+  /// The [ErrorReporter] to which inference errors should be reported, or
+  /// `null` if errors shouldn't be reported.
+  final ErrorReporter? errorReporter;
 
   /// The [AstNode] to which errors should be attached.  May be `null` if errors
-  /// are not being reported (that is, if [_inferenceErrorListener] is also
-  /// `null`).
+  /// are not being reported (that is, if [errorReporter] is also `null`).
   final AstNode? errorNode;
 
   /// Indicates whether the "generic metadata" feature is enabled.  When it is,
@@ -87,10 +96,12 @@
   final Map<TypeParameterElement, DartType> _typesInferredSoFar = {};
 
   GenericInferrer(this._typeSystem, this._typeFormals,
-      {InferenceErrorListener? inferenceErrorListener,
+      {this.errorReporter,
       this.errorNode,
-      required this.genericMetadataIsEnabled})
-      : _inferenceErrorListener = inferenceErrorListener {
+      required this.genericMetadataIsEnabled}) {
+    if (errorReporter != null) {
+      assert(errorNode != null);
+    }
     _typeParameters.addAll(_typeFormals);
     for (var formal in _typeFormals) {
       _constraints[formal] = [];
@@ -208,7 +219,9 @@
       if (!success) {
         if (failAtError) return null;
         hasErrorReported = true;
-        _inferenceErrorListener?.addCouldNotInferError(errorNode!,
+        errorReporter?.reportErrorForNode(
+            CompileTimeErrorCode.COULD_NOT_INFER,
+            errorNode!,
             [parameter.name, _formatError(parameter, inferred, constraints)]);
 
         // Heuristic: even if we failed, keep the erroneous type.
@@ -220,12 +233,13 @@
       if (inferred is FunctionType &&
           inferred.typeFormals.isNotEmpty &&
           !genericMetadataIsEnabled &&
-          _inferenceErrorListener != null) {
+          errorReporter != null) {
         if (failAtError) return null;
         hasErrorReported = true;
         var typeFormals = inferred.typeFormals;
         var typeFormalsStr = typeFormals.map(_elementStr).join(', ');
-        _inferenceErrorListener?.addCouldNotInferError(errorNode!, [
+        errorReporter!.reportErrorForNode(
+            CompileTimeErrorCode.COULD_NOT_INFER, errorNode!, [
           parameter.name,
           ' Inferred candidate type ${_typeStr(inferred)} has type parameters'
               ' [$typeFormalsStr], but a function with'
@@ -235,13 +249,16 @@
 
       if (UnknownInferredType.isKnown(inferred)) {
         knownTypes[parameter] = inferred;
-      } else if (!hasErrorReported && _typeSystem.strictInference) {
+      } else if (_typeSystem.strictInference) {
         // [typeParam] could not be inferred. A result will still be returned
         // by [infer], with [typeParam] filled in as its bounds. This is
         // considered a failure of inference, under the "strict-inference"
         // mode.
-        hasErrorReported = true;
-        _inferenceErrorListener?.reportInferenceFailure(errorNode!);
+        _reportInferenceFailure(
+          errorReporter: errorReporter,
+          errorNode: errorNode,
+          genericMetadataIsEnabled: genericMetadataIsEnabled,
+        );
       }
     }
 
@@ -259,7 +276,8 @@
         var typeParamBound = Substitution.fromPairs(_typeFormals, inferredTypes)
             .substituteType(typeParam.bound ?? typeProvider.objectType);
         // TODO(jmesserly): improve this error message.
-        _inferenceErrorListener?.addCouldNotInferError(errorNode!, [
+        errorReporter?.reportErrorForNode(
+            CompileTimeErrorCode.COULD_NOT_INFER, errorNode!, [
           typeParam.name,
           "\nRecursive bound cannot be instantiated: '$typeParamBound'."
               "\nConsider passing explicit type argument(s) "
@@ -270,6 +288,8 @@
 
     if (!hasErrorReported) {
       _checkArgumentsNotMatchingBounds(
+        errorNode: errorNode,
+        errorReporter: errorReporter,
         typeArguments: result,
       );
     }
@@ -284,6 +304,8 @@
 
   /// Check that inferred [typeArguments] satisfy the [typeParameters] bounds.
   void _checkArgumentsNotMatchingBounds({
+    required AstNode? errorNode,
+    required ErrorReporter? errorReporter,
     required List<DartType> typeArguments,
   }) {
     for (int i = 0; i < _typeFormals.length; i++) {
@@ -299,7 +321,8 @@
       var substitution = Substitution.fromPairs(_typeFormals, typeArguments);
       var bound = substitution.substituteType(rawBound);
       if (!_typeSystem.isSubtypeOf(argument, bound)) {
-        _inferenceErrorListener?.addCouldNotInferError(
+        errorReporter?.reportErrorForNode(
+          CompileTimeErrorCode.COULD_NOT_INFER,
           errorNode!,
           [
             parameter.name,
@@ -459,21 +482,21 @@
     }
 
     // Only report unique constraint origins.
-    Iterable<_TypeConstraint> isSatisified(bool expected) => constraintsByOrigin
+    Iterable<_TypeConstraint> isSatisfied(bool expected) => constraintsByOrigin
         .values
         .where((l) =>
             l.every((c) => c.isSatisfiedBy(_typeSystem, inferred)) == expected)
         .expand((i) => i);
 
-    String unsatisified = _formatConstraints(isSatisified(false));
-    String satisified = _formatConstraints(isSatisified(true));
+    String unsatisfied = _formatConstraints(isSatisfied(false));
+    String satisfied = _formatConstraints(isSatisfied(true));
 
-    assert(unsatisified.isNotEmpty);
-    if (satisified.isNotEmpty) {
-      satisified = "\nThe type '$inferredStr' was inferred from:\n$satisified";
+    assert(unsatisfied.isNotEmpty);
+    if (satisfied.isNotEmpty) {
+      satisfied = "\nThe type '$inferredStr' was inferred from:\n$satisfied";
     }
 
-    return '\n\n$intro\n$unsatisified$satisified\n\n'
+    return '\n\n$intro\n$unsatisfied$satisfied\n\n'
         'Consider passing explicit type argument(s) to the generic.\n\n';
   }
 
@@ -524,6 +547,83 @@
     }
   }
 
+  /// Reports an inference failure on [errorNode] according to its type.
+  void _reportInferenceFailure({
+    ErrorReporter? errorReporter,
+    AstNode? errorNode,
+    required bool genericMetadataIsEnabled,
+  }) {
+    if (errorReporter == null || errorNode == null) {
+      return;
+    }
+    if (errorNode.parent is InvocationExpression &&
+        errorNode.parent?.parent is AsExpression) {
+      // Casts via `as` do not play a part in downward inference. We allow an
+      // exception when inference has "failed" but the return value is
+      // immediately cast with `as`.
+      return;
+    }
+    if (errorNode is ConstructorName &&
+        !(errorNode.type.type as InterfaceType).element.hasOptionalTypeArgs) {
+      String constructorName = errorNode.name == null
+          ? errorNode.type.name.name
+          : '${errorNode.type}.${errorNode.name}';
+      errorReporter.reportErrorForNode(
+          WarningCode.INFERENCE_FAILURE_ON_INSTANCE_CREATION,
+          errorNode,
+          [constructorName]);
+    } else if (errorNode is Annotation) {
+      if (genericMetadataIsEnabled) {
+        // Only report an error if generic metadata is valid syntax.
+        var element = errorNode.name.staticElement;
+        if (element != null && !element.hasOptionalTypeArgs) {
+          String constructorName = errorNode.constructorName == null
+              ? errorNode.name.name
+              : '${errorNode.name.name}.${errorNode.constructorName}';
+          errorReporter.reportErrorForNode(
+              WarningCode.INFERENCE_FAILURE_ON_INSTANCE_CREATION,
+              errorNode,
+              [constructorName]);
+        }
+      }
+    } else if (errorNode is SimpleIdentifier) {
+      var element = errorNode.staticElement;
+      if (element != null) {
+        if (element is VariableElement) {
+          // For variable elements, we check their type and possible alias type.
+          var type = element.type;
+          final typeElement = type is InterfaceType ? type.element : null;
+          if (typeElement != null && typeElement.hasOptionalTypeArgs) {
+            return;
+          }
+          var typeAliasElement = type.alias?.element;
+          if (typeAliasElement != null &&
+              typeAliasElement.hasOptionalTypeArgs) {
+            return;
+          }
+        }
+        if (!element.hasOptionalTypeArgs) {
+          errorReporter.reportErrorForNode(
+              WarningCode.INFERENCE_FAILURE_ON_FUNCTION_INVOCATION,
+              errorNode,
+              [errorNode.name]);
+          return;
+        }
+      }
+    } else if (errorNode is Expression) {
+      var type = errorNode.staticType;
+      if (type != null) {
+        var typeDisplayString = type.getDisplayString(
+            withNullability: _typeSystem.isNonNullableByDefault);
+        errorReporter.reportErrorForNode(
+            WarningCode.INFERENCE_FAILURE_ON_GENERIC_INVOCATION,
+            errorNode,
+            [typeDisplayString]);
+        return;
+      }
+    }
+  }
+
   /// If in a legacy library, return the legacy version of the [type].
   /// Otherwise, return the original type.
   DartType _toLegacyElementIfOptOut(DartType type) {
diff --git a/analyzer/lib/src/dart/element/inheritance_manager3.dart b/analyzer/lib/src/dart/element/inheritance_manager3.dart
index 81c87a6..696154d 100644
--- a/analyzer/lib/src/dart/element/inheritance_manager3.dart
+++ b/analyzer/lib/src/dart/element/inheritance_manager3.dart
@@ -9,6 +9,7 @@
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 /// Failure because of there is no most specific signature in [candidates].
 class CandidatesConflict extends Conflict {
@@ -642,7 +643,7 @@
       noSuchMethodForwarders,
       namedCandidates,
       superImplemented,
-      conflicts,
+      conflicts.toFixedList(),
     );
   }
 
@@ -702,7 +703,10 @@
       {},
       interfaceCandidates,
       [superInterface],
-      <Conflict>[...superConflicts, ...interfaceConflicts],
+      <Conflict>[
+        ...superConflicts,
+        ...interfaceConflicts,
+      ].toFixedList(),
     );
   }
 
diff --git a/analyzer/lib/src/dart/element/member.dart b/analyzer/lib/src/dart/element/member.dart
index e46a7eb..a537763 100644
--- a/analyzer/lib/src/dart/element/member.dart
+++ b/analyzer/lib/src/dart/element/member.dart
@@ -570,6 +570,9 @@
   bool get hasProtected => _declaration.hasProtected;
 
   @override
+  bool get hasReopen => _declaration.hasReopen;
+
+  @override
   bool get hasRequired => _declaration.hasRequired;
 
   @override
diff --git a/analyzer/lib/src/dart/element/normalize.dart b/analyzer/lib/src/dart/element/normalize.dart
index a556a96..c9a7c6b 100644
--- a/analyzer/lib/src/dart/element/normalize.dart
+++ b/analyzer/lib/src/dart/element/normalize.dart
@@ -11,6 +11,7 @@
 import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 /// Helper for computing canonical presentation of types.
 ///
@@ -50,7 +51,7 @@
         return e.copyWith(
           type: _normalize(e.type),
         );
-      }).toList(),
+      }).toFixedList(),
       returnType: _normalize(functionType.returnType),
       nullabilitySuffix: NullabilitySuffix.none,
     );
@@ -140,7 +141,7 @@
     // NORM(C<T0, ..., Tn>) = C<R0, ..., Rn> where Ri is NORM(Ti)
     if (T is InterfaceType) {
       return T.element.instantiate(
-        typeArguments: T.typeArguments.map(_normalize).toList(),
+        typeArguments: T.typeArguments.map(_normalize).toFixedList(),
         nullabilitySuffix: NullabilitySuffix.none,
       );
     }
@@ -152,13 +153,13 @@
           return RecordTypePositionalFieldImpl(
             type: _normalize(field.type),
           );
-        }).toList(),
+        }).toFixedList(),
         namedFields: T.namedFields.map((field) {
           return RecordTypeNamedFieldImpl(
             name: field.name,
             type: _normalize(field.type),
           );
-        }).toList(),
+        }).toFixedList(),
         nullabilitySuffix: NullabilitySuffix.none,
       );
     }
diff --git a/analyzer/lib/src/dart/element/scope.dart b/analyzer/lib/src/dart/element/scope.dart
index d50dc40..17b15a9 100644
--- a/analyzer/lib/src/dart/element/scope.dart
+++ b/analyzer/lib/src/dart/element/scope.dart
@@ -2,12 +2,14 @@
 // 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:_fe_analyzer_shared/src/scanner/string_canonicalizer.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/scope.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/summary2/combinator.dart';
 import 'package:analyzer/src/summary2/export.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 /// The scope for the initializers in a constructor.
 class ConstructorInitializerScope extends EnclosedScope {
@@ -55,7 +57,7 @@
   void _addSetter(Element element) {
     var name = element.name;
     if (name != null && name.endsWith('=')) {
-      var id = name.substring(0, name.length - 1);
+      var id = considerCanonicalizeString(name.substring(0, name.length - 1));
       _setters[id] ??= element;
     }
   }
@@ -96,7 +98,7 @@
 
 class LibraryOrAugmentationScope extends EnclosedScope {
   final LibraryOrAugmentationElementImpl _container;
-  final List<ExtensionElement> extensions = [];
+  List<ExtensionElement> extensions = [];
 
   LibraryOrAugmentationScope(LibraryOrAugmentationElementImpl container)
       : _container = container,
@@ -115,6 +117,8 @@
       _addGetter(DynamicElementImpl.instance);
       _addGetter(NeverElementImpl.instance);
     }
+
+    extensions = extensions.toFixedList();
   }
 
   void _addExtension(ExtensionElement element) {
@@ -382,7 +386,7 @@
       ..._nullPrefixScope._extensions,
       for (var prefix in _container.prefixes)
         ...(prefix.scope as PrefixScope)._extensions,
-    }.toList();
+    }.toFixedList();
   }
 
   @override
diff --git a/analyzer/lib/src/dart/element/subtype.dart b/analyzer/lib/src/dart/element/subtype.dart
index 74f2a96..50e3c3e 100644
--- a/analyzer/lib/src/dart/element/subtype.dart
+++ b/analyzer/lib/src/dart/element/subtype.dart
@@ -164,7 +164,7 @@
       // * `T0 <: T1` iff `Future<S0> <: T1` and `S0 <: T1`
       if (isSubtypeOf(S0, T1)) {
         var FutureS0 = _typeProvider.futureElement.instantiate(
-          typeArguments: [S0],
+          typeArguments: fixedTypeList(S0),
           nullabilitySuffix: NullabilitySuffix.none,
         );
         return isSubtypeOf(FutureS0, T1);
@@ -210,7 +210,7 @@
       // `T0 <: T1` iff any of the following hold:
       // * either `T0 <: Future<S1>`
       var FutureS1 = _typeProvider.futureElement.instantiate(
-        typeArguments: [S1],
+        typeArguments: fixedTypeList(S1),
         nullabilitySuffix: NullabilitySuffix.none,
       );
       if (isSubtypeOf(T0, FutureS1)) {
diff --git a/analyzer/lib/src/dart/element/top_merge.dart b/analyzer/lib/src/dart/element/top_merge.dart
index b60f3b1..e6537c2 100644
--- a/analyzer/lib/src/dart/element/top_merge.dart
+++ b/analyzer/lib/src/dart/element/top_merge.dart
@@ -11,6 +11,7 @@
 import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 class TopMergeHelper {
   final TypeSystemImpl typeSystem;
@@ -263,8 +264,8 @@
     }
 
     return FunctionTypeImpl(
-      typeFormals: R_typeParameters,
-      parameters: R_parameters,
+      typeFormals: R_typeParameters.toFixedList(),
+      parameters: R_parameters.toFixedList(),
       returnType: R_returnType,
       nullabilitySuffix: NullabilitySuffix.none,
     );
@@ -283,6 +284,7 @@
       var arguments = List.generate(
         T_arguments.length,
         (i) => topMerge(T_arguments[i], S_arguments[i]),
+        growable: false,
       );
       return T.element.instantiate(
         typeArguments: arguments,
diff --git a/analyzer/lib/src/dart/element/type.dart b/analyzer/lib/src/dart/element/type.dart
index c519863..671cf20 100644
--- a/analyzer/lib/src/dart/element/type.dart
+++ b/analyzer/lib/src/dart/element/type.dart
@@ -16,8 +16,20 @@
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 import 'package:collection/collection.dart';
 
+/// Returns a [List] of fixed length with given types.
+List<DartType> fixedTypeList(DartType e1, [DartType? e2]) {
+  if (e2 != null) {
+    final result = List<DartType>.filled(2, e1, growable: false);
+    result[1] = e2;
+    return result;
+  } else {
+    return List<DartType>.filled(1, e1, growable: false);
+  }
+}
+
 /// The [Type] representing the type `dynamic`.
 class DynamicTypeImpl extends TypeImpl implements DynamicType {
   /// The unique instance of this class.
@@ -237,8 +249,9 @@
     return FunctionTypeImpl(
       returnType: substitution.substituteType(returnType),
       typeFormals: const [],
-      parameters:
-          parameters.map((p) => ParameterMember.from(p, substitution)).toList(),
+      parameters: parameters
+          .map((p) => ParameterMember.from(p, substitution))
+          .toFixedList(),
       nullabilitySuffix: nullabilitySuffix,
     );
   }
@@ -499,15 +512,9 @@
 
   @override
   List<ConstructorElement> get constructors {
-    if (_constructors == null) {
-      List<ConstructorElement> constructors = element.constructors;
-      var members = <ConstructorElement>[];
-      for (int i = 0; i < constructors.length; i++) {
-        members.add(ConstructorMember.from(constructors[i], this));
-      }
-      _constructors = members;
-    }
-    return _constructors!;
+    return _constructors ??= element.constructors.map((constructor) {
+      return ConstructorMember.from(constructor, this);
+    }).toFixedList();
   }
 
   @Deprecated('Use element instead')
@@ -1008,6 +1015,24 @@
     super.alias,
   }) : namedFields = _sortNamedFields(namedFields);
 
+  factory RecordTypeImpl.fromApi({
+    required List<DartType> positional,
+    required Map<String, DartType> named,
+    required NullabilitySuffix nullabilitySuffix,
+  }) {
+    return RecordTypeImpl(
+      positionalFields: [
+        for (final type in positional)
+          RecordTypePositionalFieldImpl(type: type),
+      ],
+      namedFields: [
+        for (final entry in named.entries)
+          RecordTypeNamedFieldImpl(name: entry.key, type: entry.value),
+      ],
+      nullabilitySuffix: nullabilitySuffix,
+    );
+  }
+
   @override
   Null get element => null;
 
diff --git a/analyzer/lib/src/dart/element/type_algebra.dart b/analyzer/lib/src/dart/element/type_algebra.dart
index 3844a5b..30c4732 100644
--- a/analyzer/lib/src/dart/element/type_algebra.dart
+++ b/analyzer/lib/src/dart/element/type_algebra.dart
@@ -14,6 +14,7 @@
 import 'package:analyzer/src/summary2/function_type_builder.dart';
 import 'package:analyzer/src/summary2/named_type_builder.dart';
 import 'package:analyzer/src/summary2/record_type_builder.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 /// Generates a fresh copy of the given type parameters, with their bounds
 /// substituted to reference the new parameters.
@@ -25,7 +26,7 @@
   var freshParameters = List<TypeParameterElementImpl>.generate(
     typeParameters.length,
     (i) => TypeParameterElementImpl(typeParameters[i].name, -1),
-    growable: true,
+    growable: false,
   );
 
   var map = <TypeParameterElement, DartType>{};
@@ -136,7 +137,7 @@
       parameters: type.parameters.map((parameter) {
         var type = substitute(parameter.type);
         return parameter.copyWith(type: type);
-      }).toList(),
+      }).toFixedList(),
       returnType: substitute(type.returnType),
       nullabilitySuffix: type.nullabilitySuffix,
     );
@@ -259,28 +260,26 @@
       return const <TypeParameterElement>[];
     }
 
-    var freshElements = <TypeParameterElement>[];
-    for (var i = 0; i < elements.length; i++) {
+    var freshElements = List.generate(elements.length, (index) {
       // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
       // variance is added to the interface.
-      var element = elements[i] as TypeParameterElementImpl;
+      var element = elements[index] as TypeParameterElementImpl;
       var freshElement = TypeParameterElementImpl(element.name, -1);
-      freshElements.add(freshElement);
       var freshType = freshElement.instantiate(
         nullabilitySuffix: NullabilitySuffix.none,
       );
       substitution[element] = freshType;
-
       if (!element.isLegacyCovariant) {
         freshElement.variance = element.variance;
       }
-    }
+      return freshElement;
+    }, growable: false);
 
     for (var i = 0; i < freshElements.length; i++) {
       var element = elements[i];
       var bound = element.bound;
       if (bound != null) {
-        var freshElement = freshElements[i] as TypeParameterElementImpl;
+        var freshElement = freshElements[i];
         freshElement.bound = bound.accept(this);
       }
     }
@@ -439,7 +438,7 @@
     var parameters = type.parameters.map((parameter) {
       var type = parameter.type.accept(inner);
       return parameter.copyWith(type: type);
-    }).toList();
+    }).toFixedList();
 
     inner.invertVariance();
 
@@ -614,7 +613,7 @@
   }
 
   List<DartType> _mapList(List<DartType> types) {
-    return types.map((e) => e.accept(this)).toList();
+    return types.map((e) => e.accept(this)).toFixedList();
   }
 }
 
diff --git a/analyzer/lib/src/dart/element/type_constraint_gatherer.dart b/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
index 0ebb0ba..95ecafd 100644
--- a/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
+++ b/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
@@ -535,10 +535,10 @@
     return true;
   }
 
-  InterfaceType _futureNone(DartType argument) {
+  InterfaceType _futureNone(DartType valueType) {
     var element = _typeSystem.typeProvider.futureElement;
     return element.instantiate(
-      typeArguments: [argument],
+      typeArguments: fixedTypeList(valueType),
       nullabilitySuffix: NullabilitySuffix.none,
     );
   }
diff --git a/analyzer/lib/src/dart/element/type_provider.dart b/analyzer/lib/src/dart/element/type_provider.dart
index 719c256..a5509d1 100644
--- a/analyzer/lib/src/dart/element/type_provider.dart
+++ b/analyzer/lib/src/dart/element/type_provider.dart
@@ -259,7 +259,7 @@
   InterfaceType get futureDynamicType {
     return _futureDynamicType ??= InterfaceTypeImpl(
       element: futureElement,
-      typeArguments: [dynamicType],
+      typeArguments: fixedTypeList(dynamicType),
       nullabilitySuffix: _nullabilitySuffix,
     );
   }
@@ -273,7 +273,7 @@
   InterfaceType get futureNullType {
     return _futureNullType ??= InterfaceTypeImpl(
       element: futureElement,
-      typeArguments: [nullType],
+      typeArguments: fixedTypeList(nullType),
       nullabilitySuffix: _nullabilitySuffix,
     );
   }
@@ -287,7 +287,7 @@
   InterfaceType get futureOrNullType {
     return _futureOrNullType ??= InterfaceTypeImpl(
       element: futureOrElement,
-      typeArguments: [nullType],
+      typeArguments: fixedTypeList(nullType),
       nullabilitySuffix: _nullabilitySuffix,
     );
   }
@@ -310,7 +310,7 @@
   InterfaceType get iterableDynamicType {
     return _iterableDynamicType ??= InterfaceTypeImpl(
       element: iterableElement,
-      typeArguments: [dynamicType],
+      typeArguments: fixedTypeList(dynamicType),
       nullabilitySuffix: _nullabilitySuffix,
     );
   }
@@ -324,7 +324,7 @@
   InterfaceType get iterableObjectType {
     return _iterableObjectType ??= InterfaceTypeImpl(
       element: iterableElement,
-      typeArguments: [objectType],
+      typeArguments: fixedTypeList(objectType),
       nullabilitySuffix: _nullabilitySuffix,
     );
   }
@@ -343,7 +343,7 @@
   InterfaceType get mapObjectObjectType {
     return _mapObjectObjectType ??= InterfaceTypeImpl(
       element: mapElement,
-      typeArguments: [objectType, objectType],
+      typeArguments: fixedTypeList(objectType, objectType),
       nullabilitySuffix: _nullabilitySuffix,
     );
   }
@@ -420,7 +420,7 @@
   InterfaceType get streamDynamicType {
     return _streamDynamicType ??= InterfaceTypeImpl(
       element: streamElement,
-      typeArguments: [dynamicType],
+      typeArguments: fixedTypeList(dynamicType),
       nullabilitySuffix: _nullabilitySuffix,
     );
   }
@@ -469,7 +469,7 @@
   @override
   InterfaceType futureOrType(DartType valueType) {
     return futureOrElement.instantiate(
-      typeArguments: [valueType],
+      typeArguments: fixedTypeList(valueType),
       nullabilitySuffix: _nullabilitySuffix,
     );
   }
@@ -477,7 +477,7 @@
   @override
   InterfaceType futureType(DartType valueType) {
     return futureElement.instantiate(
-      typeArguments: [valueType],
+      typeArguments: fixedTypeList(valueType),
       nullabilitySuffix: _nullabilitySuffix,
     );
   }
@@ -496,7 +496,7 @@
   @override
   InterfaceType iterableType(DartType elementType) {
     return iterableElement.instantiate(
-      typeArguments: [elementType],
+      typeArguments: fixedTypeList(elementType),
       nullabilitySuffix: _nullabilitySuffix,
     );
   }
@@ -504,7 +504,7 @@
   @override
   InterfaceType listType(DartType elementType) {
     return listElement.instantiate(
-      typeArguments: [elementType],
+      typeArguments: fixedTypeList(elementType),
       nullabilitySuffix: _nullabilitySuffix,
     );
   }
@@ -512,7 +512,7 @@
   @override
   InterfaceType mapType(DartType keyType, DartType valueType) {
     return mapElement.instantiate(
-      typeArguments: [keyType, valueType],
+      typeArguments: fixedTypeList(keyType, valueType),
       nullabilitySuffix: _nullabilitySuffix,
     );
   }
@@ -520,7 +520,7 @@
   @override
   InterfaceType setType(DartType elementType) {
     return setElement.instantiate(
-      typeArguments: [elementType],
+      typeArguments: fixedTypeList(elementType),
       nullabilitySuffix: _nullabilitySuffix,
     );
   }
@@ -528,7 +528,7 @@
   @override
   InterfaceType streamType(DartType elementType) {
     return streamElement.instantiate(
-      typeArguments: [elementType],
+      typeArguments: fixedTypeList(elementType),
       nullabilitySuffix: _nullabilitySuffix,
     );
   }
diff --git a/analyzer/lib/src/dart/element/type_system.dart b/analyzer/lib/src/dart/element/type_system.dart
index 97cd2eb..36ac716 100644
--- a/analyzer/lib/src/dart/element/type_system.dart
+++ b/analyzer/lib/src/dart/element/type_system.dart
@@ -13,6 +13,7 @@
 import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/error/listener.dart' show ErrorReporter;
 import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/extensions.dart';
 import 'package:analyzer/src/dart/element/generic_inferrer.dart';
 import 'package:analyzer/src/dart/element/greatest_lower_bound.dart';
 import 'package:analyzer/src/dart/element/least_greatest_closure.dart';
@@ -31,11 +32,11 @@
 import 'package:analyzer/src/dart/element/type_schema.dart';
 import 'package:analyzer/src/dart/element/type_schema_elimination.dart';
 import 'package:analyzer/src/dart/element/well_bounded.dart';
-import 'package:analyzer/src/dart/error/inference_error_listener.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 /// Fresh type parameters created to unify two lists of type parameters.
 class RelatedTypeParameters {
-  static final _empty = RelatedTypeParameters._([], []);
+  static final _empty = RelatedTypeParameters._(const [], const []);
 
   final List<TypeParameterElement> typeParameters;
   final List<TypeParameterType> typeParameterTypes;
@@ -494,13 +495,7 @@
     // subtypes (or supertypes) as necessary, and track the constraints that
     // are implied by this.
     var inferrer = GenericInferrer(this, fnType.typeFormals,
-        inferenceErrorListener: errorReporter == null
-            ? null
-            : InferenceErrorReporter(
-                errorReporter,
-                isNonNullableByDefault: isNonNullableByDefault,
-                isGenericMetadataEnabled: genericMetadataIsEnabled,
-              ),
+        errorReporter: errorReporter,
         errorNode: errorNode,
         genericMetadataIsEnabled: genericMetadataIsEnabled);
     inferrer.constrainGenericFunctionInContext(fnType, contextType);
@@ -665,10 +660,56 @@
     }
 
     List<DartType> orderedArguments =
-        typeFormals.map((p) => defaults[p]!).toList();
+        typeFormals.map((p) => defaults[p]!).toFixedList();
     return orderedArguments;
   }
 
+  /// https://github.com/dart-lang/language
+  /// accepted/future-releases/0546-patterns/feature-specification.md#exhaustiveness-and-reachability
+  bool isAlwaysExhaustive(DartType type) {
+    if (type is InterfaceType) {
+      if (type.isDartCoreBool) {
+        return true;
+      }
+      if (type.isDartCoreNull) {
+        return true;
+      }
+      final element = type.element;
+      if (element is EnumElement) {
+        return true;
+      }
+      if (element is ClassElement && element.isSealed) {
+        return true;
+      }
+      if (element is MixinElement && element.isSealed) {
+        return true;
+      }
+      if (type.isDartAsyncFutureOr) {
+        return isAlwaysExhaustive(type.typeArguments[0]);
+      }
+      return false;
+    } else if (type is TypeParameterTypeImpl) {
+      final promotedBound = type.promotedBound;
+      if (promotedBound != null && isAlwaysExhaustive(promotedBound)) {
+        return true;
+      }
+      final bound = type.element.bound;
+      if (bound != null && isAlwaysExhaustive(bound)) {
+        return true;
+      }
+      return false;
+    } else if (type is RecordType) {
+      for (final field in type.fields) {
+        if (!isAlwaysExhaustive(field.type)) {
+          return false;
+        }
+      }
+      return true;
+    } else {
+      return false;
+    }
+  }
+
   @override
   bool isAssignableTo(DartType fromType, DartType toType) {
     // An actual subtype
@@ -1271,7 +1312,7 @@
     var inferredTypes = inferrer
         .upwardsInfer()
         .map(_removeBoundsOfGenericFunctionTypes)
-        .toList();
+        .toFixedList();
     var substitution = Substitution.fromPairs(typeParameters, inferredTypes);
 
     for (int i = 0; i < srcTypes.length; i++) {
@@ -1409,7 +1450,7 @@
     }
   }
 
-  /// Given two lists of type parameters, check that that they have the same
+  /// Given two lists of type parameters, check that they have the same
   /// number of elements, and their bounds are equal.
   ///
   /// The return value will be a new list of fresh type parameters, that can
@@ -1425,21 +1466,20 @@
       return RelatedTypeParameters._empty;
     }
 
-    var freshTypeParameters = <TypeParameterElementImpl>[];
-    var freshTypeParameterTypes = <TypeParameterType>[];
-    for (var i = 0; i < typeParameters1.length; i++) {
-      var freshTypeParameter = TypeParameterElementImpl(
-        typeParameters1[i].name,
+    var length = typeParameters1.length;
+    var freshTypeParameters = List.generate(length, (index) {
+      return TypeParameterElementImpl(
+        typeParameters1[index].name,
         -1,
       );
-      freshTypeParameters.add(freshTypeParameter);
-      freshTypeParameterTypes.add(
-        TypeParameterTypeImpl(
-          element: freshTypeParameter,
-          nullabilitySuffix: NullabilitySuffix.none,
-        ),
+    }, growable: false);
+
+    var freshTypeParameterTypes = List.generate(length, (index) {
+      return TypeParameterTypeImpl(
+        element: freshTypeParameters[index],
+        nullabilitySuffix: NullabilitySuffix.none,
       );
-    }
+    }, growable: false);
 
     var substitution1 = Substitution.fromPairs(
       typeParameters1,
@@ -1540,7 +1580,6 @@
       required DartType declaredReturnType,
       required DartType? contextReturnType,
       ErrorReporter? errorReporter,
-      InferenceErrorListener? inferenceErrorListener,
       AstNode? errorNode,
       required bool genericMetadataIsEnabled,
       bool isConst = false}) {
@@ -1548,15 +1587,8 @@
     // inferred. It will optimistically assume these type parameters can be
     // subtypes (or supertypes) as necessary, and track the constraints that
     // are implied by this.
-    if (errorReporter != null) {
-      inferenceErrorListener ??= InferenceErrorReporter(
-        errorReporter,
-        isNonNullableByDefault: isNonNullableByDefault,
-        isGenericMetadataEnabled: genericMetadataIsEnabled,
-      );
-    }
     var inferrer = GenericInferrer(this, typeParameters,
-        inferenceErrorListener: inferenceErrorListener,
+        errorReporter: errorReporter,
         errorNode: errorNode,
         genericMetadataIsEnabled: genericMetadataIsEnabled);
 
@@ -1653,7 +1685,7 @@
     return typeParameters.map((typeParameter) {
       var typeParameterImpl = typeParameter as TypeParameterElementImpl;
       return typeParameterImpl.defaultType!;
-    }).toList();
+    }).toFixedList();
   }
 
   DartType _refineBinaryExpressionTypeLegacy(DartType leftType,
diff --git a/analyzer/lib/src/dart/error/hint_codes.g.dart b/analyzer/lib/src/dart/error/hint_codes.g.dart
index fecec97..4f73a43 100644
--- a/analyzer/lib/src/dart/error/hint_codes.g.dart
+++ b/analyzer/lib/src/dart/error/hint_codes.g.dart
@@ -15,17 +15,6 @@
 import "package:analyzer/src/error/analyzer_error_code.dart";
 
 class HintCode extends AnalyzerErrorCode {
-  ///  Parameters:
-  ///  0: the name of the actual argument type
-  ///  1: the name of the expected function return type
-  static const HintCode ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER =
-      HintCode(
-    'ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER',
-    "The argument type '{0}' can't be assigned to the parameter type '{1} "
-        "Function(Object)' or '{1} Function(Object, StackTrace)'.",
-    hasPublishedDocs: true,
-  );
-
   ///  Users should not assign values marked `@doNotStore`.
   ///
   ///  Parameters:
@@ -38,29 +27,10 @@
     hasPublishedDocs: true,
   );
 
-  ///  Parameters:
-  ///  0: the return type as derived by the type of the [Future].
-  static const HintCode BODY_MIGHT_COMPLETE_NORMALLY_CATCH_ERROR = HintCode(
-    'BODY_MIGHT_COMPLETE_NORMALLY_CATCH_ERROR',
-    "This 'onError' handler must return a value assignable to '{0}', but ends "
-        "without returning a value.",
-    correctionMessage: "Try adding a return statement.",
-    hasPublishedDocs: true,
-  );
-
-  ///  Parameters:
-  ///  0: the name of the declared return type
-  static const HintCode BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE = HintCode(
-    'BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE',
-    "This function has a nullable return type of '{0}', but ends without "
-        "returning a value.",
-    correctionMessage:
-        "Try adding a return statement, or if no value is ever returned, try "
-        "changing the return type to 'void'.",
-  );
-
   ///  When the target expression uses '?.' operator, it can be `null`, so all the
   ///  subsequent invocations should also use '?.' operator.
+  ///
+  ///  Note: This diagnostic is only generated in pre-null safe code.
   static const HintCode CAN_BE_NULL_AFTER_NULL_AWARE = HintCode(
     'CAN_BE_NULL_AFTER_NULL_AWARE',
     "The receiver uses '?.', so its value can be null.",
@@ -149,24 +119,6 @@
     hasPublishedDocs: true,
   );
 
-  ///  No parameters.
-  static const HintCode DEPRECATED_EXTENDS_FUNCTION = HintCode(
-    'DEPRECATED_SUBTYPE_OF_FUNCTION',
-    "Extending 'Function' is deprecated.",
-    correctionMessage: "Try removing 'Function' from the 'extends' clause.",
-    hasPublishedDocs: true,
-    uniqueName: 'DEPRECATED_EXTENDS_FUNCTION',
-  );
-
-  ///  No parameters.
-  static const HintCode DEPRECATED_IMPLEMENTS_FUNCTION = HintCode(
-    'DEPRECATED_SUBTYPE_OF_FUNCTION',
-    "Implementing 'Function' has no effect.",
-    correctionMessage: "Try removing 'Function' from the 'implements' clause.",
-    hasPublishedDocs: true,
-    uniqueName: 'DEPRECATED_IMPLEMENTS_FUNCTION',
-  );
-
   ///  Parameters:
   ///  0: the name of the member
   static const HintCode DEPRECATED_MEMBER_USE = HintCode(
@@ -213,23 +165,6 @@
   );
 
   ///  No parameters.
-  static const HintCode DEPRECATED_MIXIN_FUNCTION = HintCode(
-    'DEPRECATED_SUBTYPE_OF_FUNCTION',
-    "Mixing in 'Function' is deprecated.",
-    correctionMessage: "Try removing 'Function' from the 'with' clause.",
-    hasPublishedDocs: true,
-    uniqueName: 'DEPRECATED_MIXIN_FUNCTION',
-  );
-
-  ///  No parameters.
-  static const HintCode DEPRECATED_NEW_IN_COMMENT_REFERENCE = HintCode(
-    'DEPRECATED_NEW_IN_COMMENT_REFERENCE',
-    "Using the 'new' keyword in a comment reference is deprecated.",
-    correctionMessage: "Try referring to a constructor by its name.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
   static const HintCode DIVISION_OPTIMIZATION = HintCode(
     'DIVISION_OPTIMIZATION',
     "The operator x ~/ y is more efficient than (x / y).toInt().",
@@ -238,72 +173,6 @@
     hasPublishedDocs: true,
   );
 
-  ///  Duplicate exports.
-  ///
-  ///  No parameters.
-  static const HintCode DUPLICATE_EXPORT = HintCode(
-    'DUPLICATE_EXPORT',
-    "Duplicate export.",
-    correctionMessage: "Try removing all but one export of the library.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
-  static const HintCode DUPLICATE_HIDDEN_NAME = HintCode(
-    'DUPLICATE_HIDDEN_NAME',
-    "Duplicate hidden name.",
-    correctionMessage:
-        "Try removing the repeated name from the list of hidden members.",
-    hasPublishedDocs: true,
-  );
-
-  ///  Parameters:
-  ///  0: the name of the diagnostic being ignored
-  static const HintCode DUPLICATE_IGNORE = HintCode(
-    'DUPLICATE_IGNORE',
-    "The diagnostic '{0}' doesn't need to be ignored here because it's already "
-        "being ignored.",
-    correctionMessage:
-        "Try removing the name from the list, or removing the whole comment if "
-        "this is the only name in the list.",
-    hasPublishedDocs: true,
-  );
-
-  ///  Duplicate imports.
-  ///
-  ///  No parameters.
-  static const HintCode DUPLICATE_IMPORT = HintCode(
-    'DUPLICATE_IMPORT',
-    "Duplicate import.",
-    correctionMessage: "Try removing all but one import of the library.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
-  static const HintCode DUPLICATE_SHOWN_NAME = HintCode(
-    'DUPLICATE_SHOWN_NAME',
-    "Duplicate shown name.",
-    correctionMessage:
-        "Try removing the repeated name from the list of shown members.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
-  static const HintCode EQUAL_ELEMENTS_IN_SET = HintCode(
-    'EQUAL_ELEMENTS_IN_SET',
-    "Two elements in a set literal shouldn't be equal.",
-    correctionMessage: "Change or remove the duplicate element.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
-  static const HintCode EQUAL_KEYS_IN_MAP = HintCode(
-    'EQUAL_KEYS_IN_MAP',
-    "Two keys in a map literal shouldn't be equal.",
-    correctionMessage: "Change or remove the duplicate key.",
-    hasPublishedDocs: true,
-  );
-
   ///  It is a bad practice for a source file in a package "lib" directory
   ///  hierarchy to traverse outside that directory hierarchy. For example, a
   ///  source file in the "lib" directory should not contain a directive such as
@@ -319,7 +188,7 @@
         "directory.",
   );
 
-  ///  It is a bad practice for a source file ouside a package "lib" directory
+  ///  It is a bad practice for a source file outside a package "lib" directory
   ///  hierarchy to traverse into that directory hierarchy. For example, a source
   ///  file in the "web" directory should not contain a directive such as
   ///  `import '../lib/some.dart'` which references a file inside the lib
@@ -355,141 +224,6 @@
     hasPublishedDocs: true,
   );
 
-  ///  When "strict-inference" is enabled, collection literal types must be
-  ///  inferred via the context type, or have type arguments.
-  ///
-  ///  Parameters:
-  ///  0: the name of the collection
-  static const HintCode INFERENCE_FAILURE_ON_COLLECTION_LITERAL = HintCode(
-    'INFERENCE_FAILURE_ON_COLLECTION_LITERAL',
-    "The type argument(s) of '{0}' can't be inferred.",
-    correctionMessage: "Use explicit type argument(s) for '{0}'.",
-  );
-
-  ///  When "strict-inference" is enabled, types in function invocations must be
-  ///  inferred via the context type, or have type arguments.
-  ///
-  ///  Parameters:
-  ///  0: the name of the function
-  static const HintCode INFERENCE_FAILURE_ON_FUNCTION_INVOCATION = HintCode(
-    'INFERENCE_FAILURE_ON_FUNCTION_INVOCATION',
-    "The type argument(s) of the function '{0}' can't be inferred.",
-    correctionMessage: "Use explicit type argument(s) for '{0}'.",
-  );
-
-  ///  When "strict-inference" is enabled, recursive local functions, top-level
-  ///  functions, methods, and function-typed function parameters must all
-  ///  specify a return type. See the strict-inference resource:
-  ///
-  ///  https://github.com/dart-lang/language/blob/master/resources/type-system/strict-inference.md
-  ///
-  ///  Parameters:
-  ///  0: the name of the function or method
-  static const HintCode INFERENCE_FAILURE_ON_FUNCTION_RETURN_TYPE = HintCode(
-    'INFERENCE_FAILURE_ON_FUNCTION_RETURN_TYPE',
-    "The return type of '{0}' cannot be inferred.",
-    correctionMessage: "Declare the return type of '{0}'.",
-  );
-
-  ///  When "strict-inference" is enabled, types in function invocations must be
-  ///  inferred via the context type, or have type arguments.
-  ///
-  ///  Parameters:
-  ///  0: the name of the type
-  static const HintCode INFERENCE_FAILURE_ON_GENERIC_INVOCATION = HintCode(
-    'INFERENCE_FAILURE_ON_GENERIC_INVOCATION',
-    "The type argument(s) of the generic function type '{0}' can't be "
-        "inferred.",
-    correctionMessage: "Use explicit type argument(s) for '{0}'.",
-  );
-
-  ///  When "strict-inference" is enabled, types in instance creation
-  ///  (constructor calls) must be inferred via the context type, or have type
-  ///  arguments.
-  ///
-  ///  Parameters:
-  ///  0: the name of the constructor
-  static const HintCode INFERENCE_FAILURE_ON_INSTANCE_CREATION = HintCode(
-    'INFERENCE_FAILURE_ON_INSTANCE_CREATION',
-    "The type argument(s) of the constructor '{0}' can't be inferred.",
-    correctionMessage: "Use explicit type argument(s) for '{0}'.",
-  );
-
-  ///  When "strict-inference" in enabled, uninitialized variables must be
-  ///  declared with a specific type.
-  ///
-  ///  Parameters:
-  ///  0: the name of the variable
-  static const HintCode INFERENCE_FAILURE_ON_UNINITIALIZED_VARIABLE = HintCode(
-    'INFERENCE_FAILURE_ON_UNINITIALIZED_VARIABLE',
-    "The type of {0} can't be inferred without either a type or initializer.",
-    correctionMessage: "Try specifying the type of the variable.",
-  );
-
-  ///  When "strict-inference" in enabled, function parameters must be
-  ///  declared with a specific type, or inherit a type.
-  ///
-  ///  Parameters:
-  ///  0: the name of the parameter
-  static const HintCode INFERENCE_FAILURE_ON_UNTYPED_PARAMETER = HintCode(
-    'INFERENCE_FAILURE_ON_UNTYPED_PARAMETER',
-    "The type of {0} can't be inferred; a type must be explicitly provided.",
-    correctionMessage: "Try specifying the type of the parameter.",
-  );
-
-  ///  Parameters:
-  ///  0: the name of the annotation
-  ///  1: the list of valid targets
-  static const HintCode INVALID_ANNOTATION_TARGET = HintCode(
-    'INVALID_ANNOTATION_TARGET',
-    "The annotation '{0}' can only be used on {1}.",
-    hasPublishedDocs: true,
-  );
-
-  ///  Parameters:
-  ///  0: the name of the element
-  static const HintCode INVALID_EXPORT_OF_INTERNAL_ELEMENT = HintCode(
-    'INVALID_EXPORT_OF_INTERNAL_ELEMENT',
-    "The member '{0}' can't be exported as a part of a package's public API.",
-    correctionMessage: "Try using a hide clause to hide '{0}'.",
-    hasPublishedDocs: true,
-  );
-
-  ///  Parameters:
-  ///  0: the name of the element
-  ///  1: ?
-  static const HintCode INVALID_EXPORT_OF_INTERNAL_ELEMENT_INDIRECTLY =
-      HintCode(
-    'INVALID_EXPORT_OF_INTERNAL_ELEMENT_INDIRECTLY',
-    "The member '{0}' can't be exported as a part of a package's public API, "
-        "but is indirectly exported as part of the signature of '{1}'.",
-    correctionMessage: "Try using a hide clause to hide '{0}'.",
-    hasPublishedDocs: true,
-  );
-
-  ///  This hint is generated anywhere a @factory annotation is associated with
-  ///  anything other than a method.
-  static const HintCode INVALID_FACTORY_ANNOTATION = HintCode(
-    'INVALID_FACTORY_ANNOTATION',
-    "Only methods can be annotated as factories.",
-  );
-
-  ///  Parameters:
-  ///  0: The name of the method
-  static const HintCode INVALID_FACTORY_METHOD_DECL = HintCode(
-    'INVALID_FACTORY_METHOD_DECL',
-    "Factory method '{0}' must have a return type.",
-    hasPublishedDocs: true,
-  );
-
-  ///  Parameters:
-  ///  0: the name of the method
-  static const HintCode INVALID_FACTORY_METHOD_IMPL = HintCode(
-    'INVALID_FACTORY_METHOD_IMPL',
-    "Factory method '{0}' doesn't return a newly allocated object.",
-    hasPublishedDocs: true,
-  );
-
   ///  This hint is generated anywhere an @immutable annotation is associated with
   ///  anything other than a class.
   static const HintCode INVALID_IMMUTABLE_ANNOTATION = HintCode(
@@ -506,113 +240,6 @@
   );
 
   ///  No parameters.
-  static const HintCode INVALID_LANGUAGE_VERSION_OVERRIDE_AT_SIGN = HintCode(
-    'INVALID_LANGUAGE_VERSION_OVERRIDE',
-    "The Dart language version override number must begin with '@dart'.",
-    correctionMessage:
-        "Specify a Dart language version override with a comment like '// "
-        "@dart = 2.0'.",
-    hasPublishedDocs: true,
-    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_AT_SIGN',
-  );
-
-  ///  No parameters.
-  static const HintCode INVALID_LANGUAGE_VERSION_OVERRIDE_EQUALS = HintCode(
-    'INVALID_LANGUAGE_VERSION_OVERRIDE',
-    "The Dart language version override comment must be specified with an '=' "
-        "character.",
-    correctionMessage:
-        "Specify a Dart language version override with a comment like '// "
-        "@dart = 2.0'.",
-    hasPublishedDocs: true,
-    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_EQUALS',
-  );
-
-  ///  Parameters:
-  ///  0: the latest major version
-  ///  1: the latest minor version
-  static const HintCode INVALID_LANGUAGE_VERSION_OVERRIDE_GREATER = HintCode(
-    'INVALID_LANGUAGE_VERSION_OVERRIDE',
-    "The language version override can't specify a version greater than the "
-        "latest known language version: {0}.{1}.",
-    correctionMessage: "Try removing the language version override.",
-    hasPublishedDocs: true,
-    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_GREATER',
-  );
-
-  static const HintCode INVALID_LANGUAGE_VERSION_OVERRIDE_LOCATION = HintCode(
-    'INVALID_LANGUAGE_VERSION_OVERRIDE',
-    "The language version override must be specified before any declaration or "
-        "directive.",
-    correctionMessage:
-        "Try moving the language version override to the top of the file.",
-    hasPublishedDocs: true,
-    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_LOCATION',
-  );
-
-  ///  No parameters.
-  static const HintCode INVALID_LANGUAGE_VERSION_OVERRIDE_LOWER_CASE = HintCode(
-    'INVALID_LANGUAGE_VERSION_OVERRIDE',
-    "The Dart language version override comment must be specified with the "
-        "word 'dart' in all lower case.",
-    correctionMessage:
-        "Specify a Dart language version override with a comment like '// "
-        "@dart = 2.0'.",
-    hasPublishedDocs: true,
-    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_LOWER_CASE',
-  );
-
-  ///  No parameters.
-  static const HintCode INVALID_LANGUAGE_VERSION_OVERRIDE_NUMBER = HintCode(
-    'INVALID_LANGUAGE_VERSION_OVERRIDE',
-    "The Dart language version override comment must be specified with a "
-        "version number, like '2.0', after the '=' character.",
-    correctionMessage:
-        "Specify a Dart language version override with a comment like '// "
-        "@dart = 2.0'.",
-    hasPublishedDocs: true,
-    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_NUMBER',
-  );
-
-  ///  No parameters.
-  static const HintCode INVALID_LANGUAGE_VERSION_OVERRIDE_PREFIX = HintCode(
-    'INVALID_LANGUAGE_VERSION_OVERRIDE',
-    "The Dart language version override number can't be prefixed with a "
-        "letter.",
-    correctionMessage:
-        "Specify a Dart language version override with a comment like '// "
-        "@dart = 2.0'.",
-    hasPublishedDocs: true,
-    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_PREFIX',
-  );
-
-  ///  No parameters.
-  static const HintCode INVALID_LANGUAGE_VERSION_OVERRIDE_TRAILING_CHARACTERS =
-      HintCode(
-    'INVALID_LANGUAGE_VERSION_OVERRIDE',
-    "The Dart language version override comment can't be followed by any "
-        "non-whitespace characters.",
-    correctionMessage:
-        "Specify a Dart language version override with a comment like '// "
-        "@dart = 2.0'.",
-    hasPublishedDocs: true,
-    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_TRAILING_CHARACTERS',
-  );
-
-  ///  No parameters.
-  static const HintCode INVALID_LANGUAGE_VERSION_OVERRIDE_TWO_SLASHES =
-      HintCode(
-    'INVALID_LANGUAGE_VERSION_OVERRIDE',
-    "The Dart language version override comment must be specified with exactly "
-        "two slashes.",
-    correctionMessage:
-        "Specify a Dart language version override with a comment like '// "
-        "@dart = 2.0'.",
-    hasPublishedDocs: true,
-    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_TWO_SLASHES',
-  );
-
-  ///  No parameters.
   static const HintCode INVALID_LITERAL_ANNOTATION = HintCode(
     'INVALID_LITERAL_ANNOTATION',
     "Only const constructors can have the `@literal` annotation.",
@@ -644,104 +271,6 @@
     hasPublishedDocs: true,
   );
 
-  ///  This hint is generated anywhere where `@required` annotates a named
-  ///  parameter with a default value.
-  ///
-  ///  Parameters:
-  ///  0: the name of the member
-  static const HintCode INVALID_REQUIRED_NAMED_PARAM = HintCode(
-    'INVALID_REQUIRED_NAMED_PARAM',
-    "The type parameter '{0}' is annotated with @required but only named "
-        "parameters without a default value can be annotated with it.",
-    correctionMessage: "Remove @required.",
-  );
-
-  ///  This hint is generated anywhere where `@required` annotates an optional
-  ///  positional parameter.
-  ///
-  ///  Parameters:
-  ///  0: the name of the member
-  static const HintCode INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM = HintCode(
-    'INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM',
-    "Incorrect use of the annotation @required on the optional positional "
-        "parameter '{0}'. Optional positional parameters cannot be required.",
-    correctionMessage: "Remove @required.",
-  );
-
-  ///  This hint is generated anywhere where `@required` annotates a non optional
-  ///  positional parameter.
-  ///
-  ///  Parameters:
-  ///  0: the name of the member
-  static const HintCode INVALID_REQUIRED_POSITIONAL_PARAM = HintCode(
-    'INVALID_REQUIRED_POSITIONAL_PARAM',
-    "Redundant use of the annotation @required on the required positional "
-        "parameter '{0}'.",
-    correctionMessage: "Remove @required.",
-  );
-
-  ///  This hint is generated anywhere where `@sealed` annotates something other
-  ///  than a class.
-  ///
-  ///  No parameters.
-  static const HintCode INVALID_SEALED_ANNOTATION = HintCode(
-    'INVALID_SEALED_ANNOTATION',
-    "The annotation '@sealed' can only be applied to classes.",
-    correctionMessage: "Try removing the '@sealed' annotation.",
-    hasPublishedDocs: true,
-  );
-
-  ///  Parameters:
-  ///  0: the name of the member
-  static const HintCode INVALID_USE_OF_INTERNAL_MEMBER = HintCode(
-    'INVALID_USE_OF_INTERNAL_MEMBER',
-    "The member '{0}' can only be used within its package.",
-    hasPublishedDocs: true,
-  );
-
-  ///  This hint is generated anywhere where a member annotated with `@protected`
-  ///  is used outside of an instance member of a subclass.
-  ///
-  ///  Parameters:
-  ///  0: the name of the member
-  ///  1: the name of the defining class
-  static const HintCode INVALID_USE_OF_PROTECTED_MEMBER = HintCode(
-    'INVALID_USE_OF_PROTECTED_MEMBER',
-    "The member '{0}' can only be used within instance members of subclasses "
-        "of '{1}'.",
-  );
-
-  ///  Parameters:
-  ///  0: the name of the member
-  static const HintCode INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER = HintCode(
-    'INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER',
-    "The member '{0}' can only be used for overriding.",
-    hasPublishedDocs: true,
-  );
-
-  ///  This hint is generated anywhere where a member annotated with
-  ///  `@visibleForTemplate` is used outside of a "template" Dart file.
-  ///
-  ///  Parameters:
-  ///  0: the name of the member
-  ///  1: the name of the defining class
-  static const HintCode INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER = HintCode(
-    'INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER',
-    "The member '{0}' can only be used within '{1}' or a template library.",
-  );
-
-  ///  This hint is generated anywhere where a member annotated with
-  ///  `@visibleForTesting` is used outside the defining library, or a test.
-  ///
-  ///  Parameters:
-  ///  0: the name of the member
-  ///  1: the name of the defining class
-  static const HintCode INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER = HintCode(
-    'INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER',
-    "The member '{0}' can only be used within '{1}' or a test.",
-    hasPublishedDocs: true,
-  );
-
   ///  This hint is generated anywhere where a private declaration is annotated
   ///  with `@visibleForTemplate` or `@visibleForTesting`.
   ///
@@ -763,75 +292,6 @@
     hasPublishedDocs: true,
   );
 
-  ///  Parameters:
-  ///  0: the name of the member
-  static const HintCode MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_ONE = HintCode(
-    'MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN',
-    "Missing concrete override implementation of '{0}'.",
-    correctionMessage: "Try overriding the missing member.",
-    hasPublishedDocs: true,
-    uniqueName: 'MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_ONE',
-  );
-
-  ///  Parameters:
-  ///  0: the name of the first member
-  ///  1: the name of the second member
-  ///  2: the number of additional missing members that aren't listed
-  static const HintCode MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_THREE_PLUS =
-      HintCode(
-    'MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN',
-    "Missing concrete override implementation of '{0}', '{1}', and {2} more.",
-    correctionMessage: "Try overriding the missing members.",
-    hasPublishedDocs: true,
-    uniqueName: 'MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_THREE_PLUS',
-  );
-
-  ///  Parameters:
-  ///  0: the name of the first member
-  ///  1: the name of the second member
-  static const HintCode MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_TWO = HintCode(
-    'MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN',
-    "Missing concrete override implementation of '{0}' and '{1}'.",
-    correctionMessage: "Try overriding the missing members.",
-    hasPublishedDocs: true,
-    uniqueName: 'MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_TWO',
-  );
-
-  ///  Generate a hint for a constructor, function or method invocation where a
-  ///  required parameter is missing.
-  ///
-  ///  Parameters:
-  ///  0: the name of the parameter
-  static const HintCode MISSING_REQUIRED_PARAM = HintCode(
-    'MISSING_REQUIRED_PARAM',
-    "The parameter '{0}' is required.",
-    hasPublishedDocs: true,
-  );
-
-  ///  Generate a hint for a constructor, function or method invocation where a
-  ///  required parameter is missing.
-  ///
-  ///  Parameters:
-  ///  0: the name of the parameter
-  ///  1: message details
-  static const HintCode MISSING_REQUIRED_PARAM_WITH_DETAILS = HintCode(
-    'MISSING_REQUIRED_PARAM',
-    "The parameter '{0}' is required. {1}.",
-    hasPublishedDocs: true,
-    uniqueName: 'MISSING_REQUIRED_PARAM_WITH_DETAILS',
-  );
-
-  ///  Parameters:
-  ///  0: the name of the declared return type
-  static const HintCode MISSING_RETURN = HintCode(
-    'MISSING_RETURN',
-    "This function has a return type of '{0}', but doesn't end with a return "
-        "statement.",
-    correctionMessage:
-        "Try adding a return statement, or changing the return type to 'void'.",
-    hasPublishedDocs: true,
-  );
-
   ///  This hint is generated anywhere where a `@sealed` class is used as a
   ///  a superclass constraint of a mixin.
   ///
@@ -899,52 +359,6 @@
   );
 
   ///  No parameters.
-  static const HintCode NULLABLE_TYPE_IN_CATCH_CLAUSE = HintCode(
-    'NULLABLE_TYPE_IN_CATCH_CLAUSE',
-    "A potentially nullable type can't be used in an 'on' clause because it "
-        "isn't valid to throw a nullable expression.",
-    correctionMessage: "Try using a non-nullable type.",
-    hasPublishedDocs: true,
-  );
-
-  ///  Parameters:
-  ///  0: the name of the method being invoked
-  ///  1: the type argument associated with the method
-  static const HintCode NULL_ARGUMENT_TO_NON_NULL_TYPE = HintCode(
-    'NULL_ARGUMENT_TO_NON_NULL_TYPE',
-    "'{0}' shouldn't be called with a null argument for the non-nullable type "
-        "argument '{1}'.",
-    correctionMessage: "Try adding a non-null argument.",
-    hasPublishedDocs: true,
-  );
-
-  ///  When the left operand of a binary expression uses '?.' operator, it can be
-  ///  `null`.
-  static const HintCode NULL_AWARE_BEFORE_OPERATOR = HintCode(
-    'NULL_AWARE_BEFORE_OPERATOR',
-    "The left operand uses '?.', so its value can be null.",
-  );
-
-  ///  A condition in a control flow statement could evaluate to `null` because it
-  ///  uses the null-aware '?.' operator.
-  static const HintCode NULL_AWARE_IN_CONDITION = HintCode(
-    'NULL_AWARE_IN_CONDITION',
-    "The value of the '?.' operator can be 'null', which isn't appropriate in "
-        "a condition.",
-    correctionMessage:
-        "Try replacing the '?.' with a '.', testing the left-hand side for "
-        "null if necessary.",
-  );
-
-  ///  A condition in operands of a logical operator could evaluate to `null`
-  ///  because it uses the null-aware '?.' operator.
-  static const HintCode NULL_AWARE_IN_LOGICAL_OPERATOR = HintCode(
-    'NULL_AWARE_IN_LOGICAL_OPERATOR',
-    "The value of the '?.' operator can be 'null', which isn't appropriate as "
-        "an operand of a logical operator.",
-  );
-
-  ///  No parameters.
   static const HintCode NULL_CHECK_ALWAYS_FAILS = HintCode(
     'NULL_CHECK_ALWAYS_FAILS',
     "This null-check will always throw an exception because the expression "
@@ -1004,90 +418,6 @@
     uniqueName: 'OVERRIDE_ON_NON_OVERRIDING_SETTER',
   );
 
-  ///  It is a bad practice for a package import to reference anything outside the
-  ///  given package, or more generally, it is bad practice for a package import
-  ///  to contain a "..". For example, a source file should not contain a
-  ///  directive such as `import 'package:foo/../some.dart'`.
-  static const HintCode PACKAGE_IMPORT_CONTAINS_DOT_DOT = HintCode(
-    'PACKAGE_IMPORT_CONTAINS_DOT_DOT',
-    "A package import shouldn't contain '..'.",
-  );
-
-  ///  It is not an error to call or tear-off a method, setter, or getter, or to
-  ///  read or write a field, on a receiver of static type `Never`.
-  ///  Implementations that provide feedback about dead or unreachable code are
-  ///  encouraged to indicate that any arguments to the invocation are
-  ///  unreachable.
-  ///
-  ///  It is not an error to apply an expression of type `Never` in the function
-  ///  position of a function call. Implementations that provide feedback about
-  ///  dead or unreachable code are encouraged to indicate that any arguments to
-  ///  the call are unreachable.
-  ///
-  ///  Parameters: none
-  static const HintCode RECEIVER_OF_TYPE_NEVER = HintCode(
-    'RECEIVER_OF_TYPE_NEVER',
-    "The receiver is of type 'Never', and will never complete with a value.",
-    correctionMessage:
-        "Try checking for throw expressions or type errors in the receiver",
-  );
-
-  ///  An error code indicating use of a removed lint rule.
-  ///
-  ///  Parameters:
-  ///  0: the rule name
-  ///  1: the SDK version in which the lint was removed
-  static const HintCode REMOVED_LINT_USE = HintCode(
-    'REMOVED_LINT_USE',
-    "'{0}' was removed in Dart '{1}'",
-    correctionMessage: "Remove the reference to '{0}'.",
-  );
-
-  ///  An error code indicating use of a removed lint rule.
-  ///
-  ///  Parameters:
-  ///  0: the rule name
-  ///  1: the SDK version in which the lint was removed
-  ///  2: the name of a replacing lint
-  static const HintCode REPLACED_LINT_USE = HintCode(
-    'REPLACED_LINT_USE',
-    "'{0}' was replaced by '{2}' in Dart '{1}'.",
-    correctionMessage: "Replace '{0}' with '{1}'.",
-  );
-
-  ///  Parameters:
-  ///  0: the name of the annotated function being invoked
-  ///  1: the name of the function containing the return
-  static const HintCode RETURN_OF_DO_NOT_STORE = HintCode(
-    'RETURN_OF_DO_NOT_STORE',
-    "'{0}' is annotated with 'doNotStore' and shouldn't be returned unless "
-        "'{1}' is also annotated.",
-    correctionMessage: "Annotate '{1}' with 'doNotStore'.",
-    hasPublishedDocs: true,
-  );
-
-  ///  Parameters:
-  ///  0: the return type as declared in the return statement
-  ///  1: the expected return type as defined by the type of the Future
-  static const HintCode RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR = HintCode(
-    'INVALID_RETURN_TYPE_FOR_CATCH_ERROR',
-    "A value of type '{0}' can't be returned by the 'onError' handler because "
-        "it must be assignable to '{1}'.",
-    hasPublishedDocs: true,
-    uniqueName: 'RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR',
-  );
-
-  ///  Parameters:
-  ///  0: the return type of the function
-  ///  1: the expected return type as defined by the type of the Future
-  static const HintCode RETURN_TYPE_INVALID_FOR_CATCH_ERROR = HintCode(
-    'INVALID_RETURN_TYPE_FOR_CATCH_ERROR',
-    "The return type '{0}' isn't assignable to '{1}', as required by "
-        "'Future.catchError'.",
-    hasPublishedDocs: true,
-    uniqueName: 'RETURN_TYPE_INVALID_FOR_CATCH_ERROR',
-  );
-
   ///  When "strict-raw-types" is enabled, "raw types" must have type arguments.
   ///
   ///  A "raw type" is a type name that does not use inference to fill in missing
@@ -1114,58 +444,6 @@
   );
 
   ///  Parameters:
-  ///  0: the unicode sequence of the code point.
-  static const HintCode TEXT_DIRECTION_CODE_POINT_IN_COMMENT = HintCode(
-    'TEXT_DIRECTION_CODE_POINT_IN_COMMENT',
-    "The Unicode code point 'U+{0}' changes the appearance of text from how "
-        "it's interpreted by the compiler.",
-    correctionMessage:
-        "Try removing the code point or using the Unicode escape sequence "
-        "'\\u{0}'.",
-    hasPublishedDocs: true,
-  );
-
-  ///  Parameters:
-  ///  0: the unicode sequence of the code point.
-  static const HintCode TEXT_DIRECTION_CODE_POINT_IN_LITERAL = HintCode(
-    'TEXT_DIRECTION_CODE_POINT_IN_LITERAL',
-    "The Unicode code point 'U+{0}' changes the appearance of text from how "
-        "it's interpreted by the compiler.",
-    correctionMessage:
-        "Try removing the code point or using the Unicode escape sequence "
-        "'\\u{0}'.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
-  static const HintCode TYPE_CHECK_IS_NOT_NULL = HintCode(
-    'TYPE_CHECK_WITH_NULL',
-    "Tests for non-null should be done with '!= null'.",
-    correctionMessage: "Try replacing the 'is! Null' check with '!= null'.",
-    hasPublishedDocs: true,
-    uniqueName: 'TYPE_CHECK_IS_NOT_NULL',
-  );
-
-  ///  No parameters.
-  static const HintCode TYPE_CHECK_IS_NULL = HintCode(
-    'TYPE_CHECK_WITH_NULL',
-    "Tests for null should be done with '== null'.",
-    correctionMessage: "Try replacing the 'is Null' check with '== null'.",
-    hasPublishedDocs: true,
-    uniqueName: 'TYPE_CHECK_IS_NULL',
-  );
-
-  ///  Parameters:
-  ///  0: the name of the library being imported
-  ///  1: the name in the hide clause that isn't defined in the library
-  static const HintCode UNDEFINED_HIDDEN_NAME = HintCode(
-    'UNDEFINED_HIDDEN_NAME',
-    "The library '{0}' doesn't export a member with the hidden name '{1}'.",
-    correctionMessage: "Try removing the name from the list of hidden members.",
-    hasPublishedDocs: true,
-  );
-
-  ///  Parameters:
   ///  0: the name of the undefined parameter
   ///  1: the name of the targeted member
   static const HintCode UNDEFINED_REFERENCED_PARAMETER = HintCode(
@@ -1175,16 +453,6 @@
   );
 
   ///  Parameters:
-  ///  0: the name of the library being imported
-  ///  1: the name in the show clause that isn't defined in the library
-  static const HintCode UNDEFINED_SHOWN_NAME = HintCode(
-    'UNDEFINED_SHOWN_NAME',
-    "The library '{0}' doesn't export a member with the shown name '{1}'.",
-    correctionMessage: "Try removing the name from the list of shown members.",
-    hasPublishedDocs: true,
-  );
-
-  ///  Parameters:
   ///  0: the name of the non-diagnostic being ignored
   static const HintCode UNIGNORABLE_IGNORE = HintCode(
     'UNIGNORABLE_IGNORE',
@@ -1223,8 +491,8 @@
   );
 
   ///  Parameters:
-  ///  0: the uri that is not necessary
-  ///  1: the uri that makes it unnecessary
+  ///  0: the URI that is not necessary
+  ///  1: the URI that makes it unnecessary
   static const HintCode UNNECESSARY_IMPORT = HintCode(
     'UNNECESSARY_IMPORT',
     "The import of '{0}' is unnecessary because all of the used elements are "
@@ -1234,6 +502,22 @@
   );
 
   ///  No parameters.
+  static const HintCode UNNECESSARY_NAN_COMPARISON_FALSE = HintCode(
+    'UNNECESSARY_NAN_COMPARISON',
+    "A double can't equal 'double.nan', so the condition is always 'false'.",
+    correctionMessage: "Try using 'double.isNan', or removing the condition.",
+    uniqueName: 'UNNECESSARY_NAN_COMPARISON_FALSE',
+  );
+
+  ///  No parameters.
+  static const HintCode UNNECESSARY_NAN_COMPARISON_TRUE = HintCode(
+    'UNNECESSARY_NAN_COMPARISON',
+    "A double can't equal 'double.nan', so the condition is always 'true'.",
+    correctionMessage: "Try using 'double.isNan', or removing the condition.",
+    uniqueName: 'UNNECESSARY_NAN_COMPARISON_TRUE',
+  );
+
+  ///  No parameters.
   static const HintCode UNNECESSARY_NO_SUCH_METHOD = HintCode(
     'UNNECESSARY_NO_SUCH_METHOD',
     "Unnecessary 'noSuchMethod' declaration.",
@@ -1244,7 +528,7 @@
   ///  No parameters.
   static const HintCode UNNECESSARY_NULL_COMPARISON_FALSE = HintCode(
     'UNNECESSARY_NULL_COMPARISON',
-    "The operand can't be null, so the condition is always false.",
+    "The operand can't be null, so the condition is always 'false'.",
     correctionMessage:
         "Try removing the condition, an enclosing condition, or the whole "
         "conditional statement.",
@@ -1255,7 +539,7 @@
   ///  No parameters.
   static const HintCode UNNECESSARY_NULL_COMPARISON_TRUE = HintCode(
     'UNNECESSARY_NULL_COMPARISON',
-    "The operand can't be null, so the condition is always true.",
+    "The operand can't be null, so the condition is always 'true'.",
     correctionMessage: "Remove the condition.",
     hasPublishedDocs: true,
     uniqueName: 'UNNECESSARY_NULL_COMPARISON_TRUE',
@@ -1270,6 +554,13 @@
   );
 
   ///  No parameters.
+  static const HintCode UNNECESSARY_SET_LITERAL = HintCode(
+    'UNNECESSARY_SET_LITERAL',
+    "Braces unnecessarily wrap this expression in a set literal.",
+    correctionMessage: "Try removing the set literal around the expression.",
+  );
+
+  ///  No parameters.
   static const HintCode UNNECESSARY_TYPE_CHECK_FALSE = HintCode(
     'UNNECESSARY_TYPE_CHECK',
     "Unnecessary type check; the result is always 'false'.",
@@ -1289,23 +580,10 @@
     uniqueName: 'UNNECESSARY_TYPE_CHECK_TRUE',
   );
 
-  ///  Parameters:
-  ///  0: the name of the exception variable
-  static const HintCode UNUSED_CATCH_CLAUSE = HintCode(
-    'UNUSED_CATCH_CLAUSE',
-    "The exception variable '{0}' isn't used, so the 'catch' clause can be "
-        "removed.",
-    correctionMessage: "Try removing the catch clause.",
-    hasPublishedDocs: true,
-  );
-
-  ///  Parameters:
-  ///  0: the name of the stack trace variable
-  static const HintCode UNUSED_CATCH_STACK = HintCode(
-    'UNUSED_CATCH_STACK',
-    "The stack trace variable '{0}' isn't used and can be removed.",
-    correctionMessage: "Try removing the stack trace variable, or using it.",
-    hasPublishedDocs: true,
+  ///  No parameters.
+  static const HintCode UNREACHABLE_SWITCH_CASE = HintCode(
+    'UNREACHABLE_SWITCH_CASE',
+    "This case is covered by the previous cases.",
   );
 
   ///  Parameters:
@@ -1337,7 +615,7 @@
   );
 
   ///  Parameters:
-  ///  0: the content of the unused import's uri
+  ///  0: the content of the unused import's URI
   static const HintCode UNUSED_IMPORT = HintCode(
     'UNUSED_IMPORT',
     "Unused import: '{0}'.",
diff --git a/analyzer/lib/src/dart/error/inference_error_listener.dart b/analyzer/lib/src/dart/error/inference_error_listener.dart
deleted file mode 100644
index 3a1d0fa..0000000
--- a/analyzer/lib/src/dart/error/inference_error_listener.dart
+++ /dev/null
@@ -1,164 +0,0 @@
-import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/error/listener.dart';
-import 'package:analyzer/src/dart/error/hint_codes.g.dart';
-import 'package:analyzer/src/error/codes.g.dart';
-import 'package:analyzer/src/task/inference_error.dart';
-
-/// A listener which can receive various inference errors.
-///
-/// This is separate from [ErrorReporter] for the case of discovering inference
-/// errors during AST resolution, which happens far before type analysis and
-/// most static error reporting.
-abstract class InferenceErrorListener {
-  final bool _isNonNullableByDefault;
-  final bool _isGenericMetadataEnabled;
-
-  InferenceErrorListener({
-    required bool isNonNullableByDefault,
-    required bool isGenericMetadataEnabled,
-  })  : _isNonNullableByDefault = isNonNullableByDefault,
-        _isGenericMetadataEnabled = isGenericMetadataEnabled;
-
-  void addCouldNotInferError(AstNode node, List<String> arguments);
-
-  void addInferenceFailureOnFunctionInvocationError(
-      AstNode node, List<String> arguments);
-
-  void addInferenceFailureOnGenericInvocationError(
-      AstNode node, List<String> arguments);
-
-  void addInferenceFailureOnInstanceCreationError(
-      AstNode node, List<String> arguments);
-
-  /// Reports an inference failure on [errorNode] according to its type.
-  void reportInferenceFailure(AstNode errorNode) {
-    if (errorNode.parent is InvocationExpression &&
-        errorNode.parent?.parent is AsExpression) {
-      // Casts via `as` do not play a part in downward inference. We allow an
-      // exception when inference has "failed" but the return value is
-      // immediately cast with `as`.
-      return;
-    }
-    if (errorNode is ConstructorName &&
-        !(errorNode.type.type as InterfaceType).element.hasOptionalTypeArgs) {
-      String constructorName = errorNode.name == null
-          ? errorNode.type.name.name
-          : '${errorNode.type}.${errorNode.name}';
-      addInferenceFailureOnInstanceCreationError(errorNode, [constructorName]);
-    } else if (errorNode is Annotation) {
-      if (_isGenericMetadataEnabled) {
-        // Only report an error if generic metadata is valid syntax.
-        var element = errorNode.name.staticElement;
-        if (element != null && !element.hasOptionalTypeArgs) {
-          String constructorName = errorNode.constructorName == null
-              ? errorNode.name.name
-              : '${errorNode.name.name}.${errorNode.constructorName}';
-          addInferenceFailureOnInstanceCreationError(
-              errorNode, [constructorName]);
-        }
-      }
-    } else if (errorNode is SimpleIdentifier) {
-      var element = errorNode.staticElement;
-      if (element == null) {
-        return;
-      }
-      if (element is VariableElement) {
-        // For variable elements, we check their type and possible alias type.
-        var type = element.type;
-        final typeElement = type is InterfaceType ? type.element : null;
-        if (typeElement != null && typeElement.hasOptionalTypeArgs) {
-          return;
-        }
-        var typeAliasElement = type.alias?.element;
-        if (typeAliasElement != null && typeAliasElement.hasOptionalTypeArgs) {
-          return;
-        }
-      }
-      if (!element.hasOptionalTypeArgs) {
-        addInferenceFailureOnFunctionInvocationError(
-            errorNode, [errorNode.name]);
-      }
-    } else if (errorNode is Expression) {
-      var type = errorNode.staticType;
-      if (type != null) {
-        var typeDisplayString =
-            type.getDisplayString(withNullability: _isNonNullableByDefault);
-        addInferenceFailureOnGenericInvocationError(
-            errorNode, [typeDisplayString]);
-      }
-    }
-  }
-}
-
-class InferenceErrorRecorder extends InferenceErrorListener {
-  final Set<TopLevelInferenceError> errors = {};
-
-  InferenceErrorRecorder({
-    required super.isNonNullableByDefault,
-    required super.isGenericMetadataEnabled,
-  });
-
-  @override
-  void addCouldNotInferError(AstNode node, List<String> arguments) {
-    errors.add(TopLevelInferenceError(
-      kind: TopLevelInferenceErrorKind.couldNotInfer,
-      arguments: arguments,
-    ));
-  }
-
-  @override
-  void addInferenceFailureOnFunctionInvocationError(
-      AstNode node, List<String> arguments) {
-    // This error is re-discovered and reported during type analysis.
-  }
-
-  @override
-  void addInferenceFailureOnGenericInvocationError(
-      AstNode node, List<String> arguments) {
-    // This error is re-discovered and reported during type analysis.
-  }
-
-  @override
-  void addInferenceFailureOnInstanceCreationError(
-      AstNode node, List<String> arguments) {
-    errors.add(TopLevelInferenceError(
-      kind: TopLevelInferenceErrorKind.inferenceFailureOnInstanceCreation,
-      arguments: arguments,
-    ));
-  }
-}
-
-class InferenceErrorReporter extends InferenceErrorListener {
-  final ErrorReporter _errorReporter;
-
-  InferenceErrorReporter(
-    this._errorReporter, {
-    required super.isNonNullableByDefault,
-    required super.isGenericMetadataEnabled,
-  });
-
-  @override
-  void addCouldNotInferError(AstNode node, List<String> arguments) =>
-      _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.COULD_NOT_INFER, node, arguments);
-
-  @override
-  void addInferenceFailureOnFunctionInvocationError(
-          AstNode node, List<String> arguments) =>
-      _errorReporter.reportErrorForNode(
-          HintCode.INFERENCE_FAILURE_ON_FUNCTION_INVOCATION, node, arguments);
-
-  @override
-  void addInferenceFailureOnGenericInvocationError(
-          AstNode node, List<String> arguments) =>
-      _errorReporter.reportErrorForNode(
-          HintCode.INFERENCE_FAILURE_ON_GENERIC_INVOCATION, node, arguments);
-
-  @override
-  void addInferenceFailureOnInstanceCreationError(
-          AstNode node, List<String> arguments) =>
-      _errorReporter.reportErrorForNode(
-          HintCode.INFERENCE_FAILURE_ON_INSTANCE_CREATION, node, arguments);
-}
diff --git a/analyzer/lib/src/dart/error/syntactic_errors.g.dart b/analyzer/lib/src/dart/error/syntactic_errors.g.dart
index dfe67de..e81d53b 100644
--- a/analyzer/lib/src/dart/error/syntactic_errors.g.dart
+++ b/analyzer/lib/src/dart/error/syntactic_errors.g.dart
@@ -148,6 +148,12 @@
   ParserErrorCode.RECORD_TYPE_ONE_POSITIONAL_NO_TRAILING_COMMA,
   ParserErrorCode.ABSTRACT_SEALED_CLASS,
   ParserErrorCode.EXPERIMENT_NOT_ENABLED_OFF_BY_DEFAULT,
+  ParserErrorCode.ANNOTATION_SPACE_BEFORE_PARENTHESIS,
+  ParserErrorCode.INVALID_CONSTANT_PATTERN_NEGATION,
+  ParserErrorCode.INVALID_CONSTANT_PATTERN_UNARY,
+  ParserErrorCode.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST,
+  ParserErrorCode.INVALID_CONSTANT_PATTERN_EMPTY_RECORD_LITERAL,
+  ParserErrorCode.INVALID_CONSTANT_PATTERN_GENERIC,
 ];
 
 class ParserErrorCode extends ErrorCode {
@@ -218,6 +224,13 @@
     "Type arguments can't have annotations because they aren't declarations.",
   );
 
+  static const ParserErrorCode ANNOTATION_SPACE_BEFORE_PARENTHESIS =
+      ParserErrorCode(
+    'ANNOTATION_SPACE_BEFORE_PARENTHESIS',
+    "Annotations can't have spaces or comments before the parenthesis.",
+    correctionMessage: "Remove any spaces or comments before the parenthesis.",
+  );
+
   static const ParserErrorCode ANNOTATION_WITH_TYPE_ARGUMENTS = ParserErrorCode(
     'ANNOTATION_WITH_TYPE_ARGUMENTS',
     "An annotation can't use type arguments.",
@@ -901,6 +914,39 @@
         "start with 'new', but shouldn't contain anything else.",
   );
 
+  static const ParserErrorCode INVALID_CONSTANT_PATTERN_DUPLICATE_CONST =
+      ParserErrorCode(
+    'INVALID_CONSTANT_PATTERN_DUPLICATE_CONST',
+    "Duplicate 'const' keyword in constant expression.",
+    correctionMessage: "Try removing one of the 'const' keywords.",
+  );
+
+  static const ParserErrorCode INVALID_CONSTANT_PATTERN_EMPTY_RECORD_LITERAL =
+      ParserErrorCode(
+    'INVALID_CONSTANT_PATTERN_EMPTY_RECORD_LITERAL',
+    "The empty record literal is not supported as a constant pattern.",
+  );
+
+  static const ParserErrorCode INVALID_CONSTANT_PATTERN_GENERIC =
+      ParserErrorCode(
+    'INVALID_CONSTANT_PATTERN_GENERIC',
+    "This expression is not supported as a constant pattern.",
+    correctionMessage: "Try wrapping the expression in 'const ( ... )'.",
+  );
+
+  static const ParserErrorCode INVALID_CONSTANT_PATTERN_NEGATION =
+      ParserErrorCode(
+    'INVALID_CONSTANT_PATTERN_NEGATION',
+    "Only negation of a numeric literal is supported as a constant pattern.",
+    correctionMessage: "Try wrapping the expression in 'const ( ... )'.",
+  );
+
+  static const ParserErrorCode INVALID_CONSTANT_PATTERN_UNARY = ParserErrorCode(
+    'INVALID_CONSTANT_PATTERN_UNARY',
+    "The unary operator {0} is not supported as a constant pattern.",
+    correctionMessage: "Try wrapping the expression in 'const ( ... )'.",
+  );
+
   static const ParserErrorCode INVALID_CONSTRUCTOR_NAME = ParserErrorCode(
     'INVALID_CONSTRUCTOR_NAME',
     "The name of a constructor must match the name of the enclosing class.",
diff --git a/analyzer/lib/src/dart/micro/resolve_file.dart b/analyzer/lib/src/dart/micro/resolve_file.dart
index 9dd7802..15e3cc4 100644
--- a/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -36,6 +36,7 @@
 import 'package:analyzer/src/task/options.dart';
 import 'package:analyzer/src/util/performance/operation_performance.dart';
 import 'package:analyzer/src/utilities/extensions/file_system.dart';
+import 'package:analyzer/src/utilities/uri_cache.dart';
 import 'package:analyzer/src/workspace/workspace.dart';
 import 'package:collection/collection.dart';
 import 'package:meta/meta.dart';
@@ -401,7 +402,7 @@
   }) async {
     performance ??= OperationPerformanceImpl('<default>');
 
-    var uri = Uri.parse(uriStr);
+    var uri = uriCache.parse(uriStr);
     var path = sourceFactory.forUri2(uri)?.fullName;
 
     if (path == null) {
diff --git a/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
index 12e25af..fd10c92 100644
--- a/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -302,7 +302,8 @@
 
   ErrorReporter get _errorReporter => _resolver.errorReporter;
 
-  void checkFinalAlreadyAssigned(Expression left) {
+  void checkFinalAlreadyAssigned(Expression left,
+      {bool isForEachIdentifier = false}) {
     var flowAnalysis = _resolver.flowAnalysis;
 
     var flow = flowAnalysis.flow;
@@ -316,14 +317,14 @@
 
         if (element.isFinal) {
           if (element.isLate) {
-            if (assigned) {
+            if (isForEachIdentifier || assigned) {
               _errorReporter.reportErrorForNode(
                 CompileTimeErrorCode.LATE_FINAL_LOCAL_ALREADY_ASSIGNED,
                 left,
               );
             }
           } else {
-            if (!unassigned) {
+            if (isForEachIdentifier || !unassigned) {
               _errorReporter.reportErrorForNode(
                 CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL,
                 left,
diff --git a/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
index c8b04fa..050a614 100644
--- a/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
+++ b/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -4,6 +4,7 @@
 
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/syntactic_entity.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -106,21 +107,20 @@
 
   void _resolveEqual(BinaryExpressionImpl node,
       {required bool notEqual, required DartType? contextType}) {
-    var left = node.leftOperand;
-    left.accept(_resolver);
-    left = node.leftOperand;
+    _resolver.analyzeExpression(node.leftOperand, null);
+    var left = _resolver.popRewrite()!;
 
-    var flow = _resolver.flowAnalysis.flow;
+    var flowAnalysis = _resolver.flowAnalysis;
+    var flow = flowAnalysis.flow;
     EqualityInfo<DartType>? leftInfo;
     var leftExtensionOverride = left is ExtensionOverride;
     if (!leftExtensionOverride) {
       leftInfo = flow?.equalityOperand_end(left, left.typeOrThrow);
     }
 
-    var right = node.rightOperand;
-    right.accept(_resolver);
-    right = node.rightOperand;
-    var whyNotPromoted = _resolver.flowAnalysis.flow?.whyNotPromoted(right);
+    _resolver.analyzeExpression(node.rightOperand, null);
+    var right = _resolver.popRewrite()!;
+    var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(right);
 
     if (!leftExtensionOverride) {
       flow?.equalityOperation_end(
@@ -136,6 +136,28 @@
     _resolveUserDefinableType(node, contextType: contextType);
     _resolver.checkForArgumentTypeNotAssignableForArgument(node.rightOperand,
         promoteParameterToNullable: true, whyNotPromoted: whyNotPromoted);
+
+    void reportNullComparison(SyntacticEntity start, SyntacticEntity end) {
+      var errorCode = notEqual
+          ? HintCode.UNNECESSARY_NULL_COMPARISON_FALSE
+          : HintCode.UNNECESSARY_NULL_COMPARISON_TRUE;
+      var offset = start.offset;
+      _errorReporter.reportErrorForOffset(errorCode, offset, end.end - offset);
+    }
+
+    if (left is SimpleIdentifierImpl && right is NullLiteralImpl) {
+      var element = left.staticElement;
+      if (element is PromotableElement &&
+          flowAnalysis.isDefinitelyUnassigned(left, element)) {
+        reportNullComparison(left, node.operator);
+      }
+    } else if (right is SimpleIdentifierImpl && left is NullLiteralImpl) {
+      var element = right.staticElement;
+      if (element is PromotableElement &&
+          flowAnalysis.isDefinitelyUnassigned(right, element)) {
+        reportNullComparison(node.operator, right);
+      }
+    }
   }
 
   void _resolveIfNull(BinaryExpressionImpl node,
@@ -243,11 +265,8 @@
 
   void _resolveUserDefinable(BinaryExpressionImpl node,
       {required DartType? contextType}) {
-    var left = node.leftOperand;
-    var right = node.rightOperand;
-
-    left.accept(_resolver);
-    left = node.leftOperand; // In case it was rewritten
+    _resolver.analyzeExpression(node.leftOperand, null);
+    var left = _resolver.popRewrite()!;
 
     var operator = node.operator;
     _resolveUserDefinableElement(node, operator.lexeme);
@@ -262,8 +281,8 @@
           left.staticType, node.staticElement, contextType, rightParam.type);
     }
 
-    _resolver.analyzeExpression(right, rightContextType);
-    right = _resolver.popRewrite()!;
+    _resolver.analyzeExpression(node.rightOperand, rightContextType);
+    var right = _resolver.popRewrite()!;
     var whyNotPromoted = _resolver.flowAnalysis.flow?.whyNotPromoted(right);
 
     _resolveUserDefinableType(node, contextType: contextType);
@@ -301,7 +320,7 @@
 
     if (identical(leftType, NeverTypeImpl.instance)) {
       _resolver.errorReporter.reportErrorForNode(
-        HintCode.RECEIVER_OF_TYPE_NEVER,
+        WarningCode.RECEIVER_OF_TYPE_NEVER,
         leftOperand,
       );
       return;
diff --git a/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart b/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart
index c5b27cd..ec8401f 100644
--- a/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart
+++ b/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart
@@ -25,7 +25,7 @@
       // Only report this if [node] has no explicit type arguments; otherwise
       // the parser has already reported an error.
       _resolver.errorReporter.reportErrorForNode(
-          StaticWarningCode.SDK_VERSION_CONSTRUCTOR_TEAROFFS, node, []);
+          WarningCode.SDK_VERSION_CONSTRUCTOR_TEAROFFS, node, []);
     }
     node.constructorName.accept(_resolver);
     var element = node.constructorName.staticElement;
diff --git a/analyzer/lib/src/dart/resolver/exit_detector.dart b/analyzer/lib/src/dart/resolver/exit_detector.dart
index 077946d..2d6e4cb 100644
--- a/analyzer/lib/src/dart/resolver/exit_detector.dart
+++ b/analyzer/lib/src/dart/resolver/exit_detector.dart
@@ -208,10 +208,10 @@
         // TODO(jwren) Do we want to take all constant expressions into account?
         // If for(; true; ) (or for(;;)), and the body doesn't return or the body
         // doesn't have a break, then return true.
-        bool implicitOrExplictTrue = conditionExpression == null ||
+        bool implicitOrExplicitTrue = conditionExpression == null ||
             (conditionExpression is BooleanLiteral &&
                 conditionExpression.value);
-        if (implicitOrExplictTrue) {
+        if (implicitOrExplicitTrue) {
           if (blockReturns || !_enclosingBlockContainsBreak) {
             return true;
           }
@@ -279,9 +279,9 @@
       // TODO(jwren) Do we want to take all constant expressions into account?
       // If for(; true; ) (or for(;;)), and the body doesn't return or the body
       // doesn't have a break, then return true.
-      bool implicitOrExplictTrue =
+      bool implicitOrExplicitTrue =
           condition == null || (condition is BooleanLiteral && condition.value);
-      if (implicitOrExplictTrue) {
+      if (implicitOrExplicitTrue) {
         if (blockReturns || !_enclosingBlockContainsBreak) {
           return true;
         }
diff --git a/analyzer/lib/src/dart/resolver/extension_member_resolver.dart b/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
index 3465293..0e5d140 100644
--- a/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
+++ b/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
@@ -16,7 +16,6 @@
 import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/dart/element/type_schema.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
-import 'package:analyzer/src/dart/error/inference_error_listener.dart';
 import 'package:analyzer/src/dart/resolver/applicable_extensions.dart';
 import 'package:analyzer/src/dart/resolver/resolution_result.dart';
 import 'package:analyzer/src/error/codes.dart';
@@ -345,11 +344,7 @@
       }
     } else {
       var inferrer = GenericInferrer(_typeSystem, typeParameters,
-          inferenceErrorListener: InferenceErrorReporter(
-            _errorReporter,
-            isNonNullableByDefault: _isNonNullableByDefault,
-            isGenericMetadataEnabled: _genericMetadataIsEnabled,
-          ),
+          errorReporter: _errorReporter,
           errorNode: node.extensionName,
           genericMetadataIsEnabled: _genericMetadataIsEnabled);
       inferrer.constrainArgument(
diff --git a/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index d14bb11..9aa6ebc 100644
--- a/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -125,10 +125,8 @@
   }
 
   void breakStatement(BreakStatement node) {
-    var target = getLabelTarget(node, node.label?.staticElement);
-    if (target != null) {
-      flow!.handleBreak(target);
-    }
+    var target = getLabelTarget(node, node.label?.staticElement, isBreak: true);
+    flow!.handleBreak(target);
   }
 
   /// Mark the [node] as unreachable if it is not covered by another node that
@@ -143,10 +141,9 @@
   }
 
   void continueStatement(ContinueStatement node) {
-    var target = getLabelTarget(node, node.label?.staticElement);
-    if (target != null) {
-      flow!.handleContinue(target);
-    }
+    var target =
+        getLabelTarget(node, node.label?.staticElement, isBreak: false);
+    flow!.handleContinue(target);
   }
 
   void executableDeclaration_enter(
@@ -158,7 +155,11 @@
 
     if (parameters != null) {
       for (var parameter in parameters.parameters) {
-        flow!.declare(parameter.declaredElement!, true);
+        var declaredElement = parameter.declaredElement!;
+        // TODO(paulberry): `skipDuplicateCheck` is currently needed to work
+        // around a failure in duplicate_definition_test.dart; fix this.
+        flow!.declare(declaredElement, declaredElement.type,
+            initialized: true, skipDuplicateCheck: true);
       }
     }
   }
@@ -283,8 +284,9 @@
       var variables = node.variables;
       for (var i = 0; i < variables.length; ++i) {
         var variable = variables[i];
-        flow!.declare(variable.declaredElement as PromotableElement,
-            variable.initializer != null);
+        var declaredElement = variable.declaredElement as PromotableElement;
+        flow!.declare(declaredElement, declaredElement.type,
+            initialized: variable.initializer != null);
       }
     }
   }
@@ -312,12 +314,15 @@
   /// Return the target of the `break` or `continue` statement with the
   /// [element] label. The [element] might be `null` (when the statement does
   /// not specify a label), so the default enclosing target is returned.
-  static Statement? getLabelTarget(AstNode? node, Element? element) {
+  ///
+  /// [isBreak] is `true` for `break`, and `false` for `continue`.
+  static Statement? getLabelTarget(AstNode? node, Element? element,
+      {required bool isBreak}) {
     for (; node != null; node = node.parent) {
       if (element == null) {
         if (node is DoStatement ||
             node is ForStatement ||
-            node is SwitchStatement ||
+            (isBreak && node is SwitchStatement) ||
             node is WhileStatement) {
           return node as Statement;
         }
@@ -325,7 +330,12 @@
         if (node is LabeledStatement) {
           if (_hasLabel(node.labels, element)) {
             var statement = node.statement;
+            // The inner statement is returned for labeled loops and
+            // switch statements, while the LabeledStatement is returned
+            // for the other known targets. This could be possibly changed
+            // so that the inner statement is always returned.
             if (statement is Block ||
+                statement is BreakStatement ||
                 statement is IfStatement ||
                 statement is TryStatement) {
               return node;
@@ -483,6 +493,13 @@
   }
 
   @override
+  DartType? matchStreamType(DartType type) {
+    var streamElement = typeSystem.typeProvider.streamElement;
+    var listType = type.asInstanceOf(streamElement);
+    return listType?.typeArguments[0];
+  }
+
+  @override
   DartType normalize(DartType type) {
     return typeSystem.normalize(type);
   }
@@ -621,13 +638,13 @@
   }
 
   @override
-  void visitPatternVariableDeclarationStatement(
-    covariant PatternVariableDeclarationStatementImpl node,
+  void visitPatternVariableDeclaration(
+    covariant PatternVariableDeclarationImpl node,
   ) {
-    for (var variable in node.declaration.elements) {
+    for (var variable in node.elements) {
       assignedVariables.declare(variable);
     }
-    super.visitPatternVariableDeclarationStatement(node);
+    super.visitPatternVariableDeclaration(node);
   }
 
   @override
@@ -765,6 +782,8 @@
         forLoopParts.initialization?.accept(this);
       } else if (forLoopParts is ForPartsWithDeclarations) {
         forLoopParts.variables.accept(this);
+      } else if (forLoopParts is ForPartsWithPattern) {
+        forLoopParts.variables.accept(this);
       } else {
         throw StateError('Unrecognized for loop parts');
       }
@@ -787,6 +806,10 @@
       } else if (forLoopParts is ForEachPartsWithDeclaration) {
         var variable = forLoopParts.loopVariable.declaredElement!;
         assignedVariables.declare(variable);
+      } else if (forLoopParts is ForEachPartsWithPatternImpl) {
+        for (var variable in forLoopParts.variables) {
+          assignedVariables.declare(variable);
+        }
       } else {
         throw StateError('Unrecognized for loop parts');
       }
diff --git a/analyzer/lib/src/dart/resolver/for_resolver.dart b/analyzer/lib/src/dart/resolver/for_resolver.dart
index e43fa16..af8a8a3 100644
--- a/analyzer/lib/src/dart/resolver/for_resolver.dart
+++ b/analyzer/lib/src/dart/resolver/for_resolver.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
@@ -34,6 +35,15 @@
 
     if (forLoopParts is ForPartsImpl) {
       _forParts(node, forLoopParts, visitBody);
+    } else if (forLoopParts is ForEachPartsWithPatternImpl) {
+      _analyzePatternForIn(
+        node: node,
+        awaitKeyword: node.awaitKeyword,
+        forLoopParts: forLoopParts,
+        dispatchBody: () {
+          _resolver.dispatchCollectionElement(node.body, context);
+        },
+      );
     } else if (forLoopParts is ForEachPartsImpl) {
       _forEachParts(node, node.awaitKeyword != null, forLoopParts, visitBody);
     }
@@ -47,11 +57,36 @@
 
     if (forLoopParts is ForPartsImpl) {
       _forParts(node, forLoopParts, visitBody);
+    } else if (forLoopParts is ForEachPartsWithPatternImpl) {
+      _analyzePatternForIn(
+        node: node,
+        awaitKeyword: node.awaitKeyword,
+        forLoopParts: forLoopParts,
+        dispatchBody: () {
+          _resolver.dispatchStatement(node.body);
+        },
+      );
     } else if (forLoopParts is ForEachPartsImpl) {
       _forEachParts(node, node.awaitKeyword != null, forLoopParts, visitBody);
     }
   }
 
+  void _analyzePatternForIn({
+    required AstNodeImpl node,
+    required Token? awaitKeyword,
+    required ForEachPartsWithPatternImpl forLoopParts,
+    required void Function() dispatchBody,
+  }) {
+    _resolver.analyzePatternForIn(
+      node: node,
+      hasAwait: awaitKeyword != null,
+      pattern: forLoopParts.pattern,
+      expression: forLoopParts.iterable,
+      dispatchBody: dispatchBody,
+    );
+    _resolver.popRewrite();
+  }
+
   /// Given an iterable expression from a foreach loop, attempt to infer
   /// a type for the elements being iterated over.  Inference is based
   /// on the type of the iterator or stream over which the foreach loop
@@ -90,7 +125,7 @@
       identifier.accept(_resolver);
       AssignmentExpressionShared(
         resolver: _resolver,
-      ).checkFinalAlreadyAssigned(identifier);
+      ).checkFinalAlreadyAssigned(identifier, isForEachIdentifier: true);
     }
 
     DartType? valueType;
@@ -136,7 +171,9 @@
     }
 
     if (loopVariable != null) {
-      _resolver.flowAnalysis.flow?.declare(loopVariable.declaredElement!, true);
+      var declaredElement = loopVariable.declaredElement!;
+      _resolver.flowAnalysis.flow
+          ?.declare(declaredElement, declaredElement.type, initialized: true);
     }
 
     _resolver.flowAnalysis.flow?.forEach_bodyBegin(node);
@@ -156,6 +193,10 @@
       forParts.variables.accept(_resolver);
     } else if (forParts is ForPartsWithExpression) {
       forParts.initialization?.accept(_resolver);
+    } else if (forParts is ForPartsWithPattern) {
+      forParts.variables.accept(_resolver);
+    } else {
+      throw StateError('Unrecognized for loop parts');
     }
 
     _resolver.flowAnalysis.for_conditionBegin(node);
diff --git a/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart b/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
index 26bb256..331cb62 100644
--- a/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
+++ b/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
@@ -78,7 +78,7 @@
 
     if (identical(receiverType, NeverTypeImpl.instance)) {
       _errorReporter.reportErrorForNode(
-          HintCode.RECEIVER_OF_TYPE_NEVER, function);
+          WarningCode.RECEIVER_OF_TYPE_NEVER, function);
       _unresolved(node, NeverTypeImpl.instance, whyNotPromotedList,
           contextType: contextType);
       return;
diff --git a/analyzer/lib/src/dart/resolver/invocation_inferrer.dart b/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
index f0faa09..a1dabaa 100644
--- a/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
+++ b/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
@@ -195,7 +195,6 @@
         contextReturnType: contextType,
         isConst: _isConst,
         errorReporter: resolver.errorReporter,
-        inferenceErrorListener: resolver.inferenceErrorListener,
         errorNode: _errorNode,
         genericMetadataIsEnabled: resolver.genericMetadataIsEnabled,
       );
diff --git a/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index ef8be7e..3c51527 100644
--- a/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -522,7 +522,7 @@
           .resolveInvocation(rawType: null);
 
       _resolver.errorReporter.reportErrorForNode(
-        HintCode.RECEIVER_OF_TYPE_NEVER,
+        WarningCode.RECEIVER_OF_TYPE_NEVER,
         receiver,
       );
       return;
diff --git a/analyzer/lib/src/dart/resolver/named_type_resolver.dart b/analyzer/lib/src/dart/resolver/named_type_resolver.dart
index 7ea96bf..dc6fd3f 100644
--- a/analyzer/lib/src/dart/resolver/named_type_resolver.dart
+++ b/analyzer/lib/src/dart/resolver/named_type_resolver.dart
@@ -139,7 +139,8 @@
         node,
         [node.name.name, parameterCount, argumentCount],
       );
-      return List.filled(parameterCount, DynamicTypeImpl.instance);
+      return List.filled(parameterCount, DynamicTypeImpl.instance,
+          growable: false);
     }
 
     if (parameterCount == 0) {
@@ -149,6 +150,7 @@
     return List.generate(
       parameterCount,
       (i) => arguments[i].typeOrThrow,
+      growable: false,
     );
   }
 
diff --git a/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart b/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
index 05afade..9f5fa41 100644
--- a/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
+++ b/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
@@ -124,7 +124,7 @@
 
     if (identical(receiverType, NeverTypeImpl.instance)) {
       _resolver.errorReporter.reportErrorForNode(
-        HintCode.RECEIVER_OF_TYPE_NEVER,
+        WarningCode.RECEIVER_OF_TYPE_NEVER,
         operand,
       );
       return;
diff --git a/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart b/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
index 07b3969..f01c641 100644
--- a/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
+++ b/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
@@ -159,7 +159,7 @@
       var readType = node.readType ?? operand.typeOrThrow;
       if (identical(readType, NeverTypeImpl.instance)) {
         _resolver.errorReporter.reportErrorForNode(
-          HintCode.RECEIVER_OF_TYPE_NEVER,
+          WarningCode.RECEIVER_OF_TYPE_NEVER,
           operand,
         );
         return;
diff --git a/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/analyzer/lib/src/dart/resolver/property_element_resolver.dart
index af5772d..a4dc213 100644
--- a/analyzer/lib/src/dart/resolver/property_element_resolver.dart
+++ b/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -89,7 +89,7 @@
     if (identical(targetType, NeverTypeImpl.instance)) {
       // TODO(scheglov) Report directly in TypePropertyResolver?
       errorReporter.reportErrorForNode(
-        HintCode.RECEIVER_OF_TYPE_NEVER,
+        WarningCode.RECEIVER_OF_TYPE_NEVER,
         target,
       );
       return PropertyElementResolverResult();
diff --git a/analyzer/lib/src/dart/resolver/resolution_visitor.dart b/analyzer/lib/src/dart/resolver/resolution_visitor.dart
index 674bce5..31369f5 100644
--- a/analyzer/lib/src/dart/resolver/resolution_visitor.dart
+++ b/analyzer/lib/src/dart/resolver/resolution_visitor.dart
@@ -5,7 +5,6 @@
 import 'package:_fe_analyzer_shared/src/type_inference/variable_bindings.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
@@ -27,6 +26,7 @@
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/element_walker.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 class ElementHolder {
   final ElementImpl _element;
@@ -35,9 +35,13 @@
 
   ElementHolder(this._element);
 
-  List<ParameterElementImpl> get parameters => _parameters;
+  List<ParameterElementImpl> get parameters {
+    return _parameters.toFixedList();
+  }
 
-  List<TypeParameterElementImpl> get typeParameters => _typeParameters;
+  List<TypeParameterElementImpl> get typeParameters {
+    return _typeParameters.toFixedList();
+  }
 
   void addParameter(ParameterElementImpl element) {
     _parameters.add(element);
@@ -202,23 +206,6 @@
   }
 
   @override
-  void visitBinaryPattern(covariant BinaryPatternImpl node) {
-    assert(node.operator.type == TokenType.AMPERSAND_AMPERSAND ||
-        node.operator.type == TokenType.BAR_BAR);
-    final isOr = node.operator.type == TokenType.BAR_BAR;
-    if (isOr) {
-      _patternVariables.logicalOrPatternStart();
-      node.leftOperand.accept(this);
-      _patternVariables.logicalOrPatternFinishLeft();
-      node.rightOperand.accept(this);
-      _patternVariables.logicalOrPatternFinish(node);
-    } else {
-      node.leftOperand.accept(this);
-      node.rightOperand.accept(this);
-    }
-  }
-
-  @override
   void visitBlock(Block node) {
     var outerScope = _nameScope;
     try {
@@ -409,33 +396,32 @@
     node.type?.accept(this);
 
     final name = node.name.lexeme;
-    if (name != '_') {
-      var element = VariablePatternBindElementImpl(
-        node,
-        name,
-        node.name.offset,
-      );
-      _patternVariables.add(name, element);
-      _elementHolder.enclose(element);
-      _define(element);
-      element.hasImplicitType = node.type == null;
-      element.type = node.type?.type ?? _dynamicType;
-      node.declaredElement = element;
+    var element = BindPatternVariableElementImpl(
+      node,
+      name,
+      node.name.offset,
+    );
+    _patternVariables.add(name, element);
+    _elementHolder.enclose(element);
+    _define(element);
+    element.hasImplicitType = node.type == null;
+    element.type = node.type?.type ?? _dynamicType;
+    node.declaredElement = element;
 
-      var patternContext = node.patternContext;
-      if (patternContext is PatternVariableDeclarationImpl) {
-        element.isFinal = patternContext.finalToken != null;
-        var keyword = node.keyword;
-        if (keyword != null) {
-          _errorReporter.reportErrorForToken(
-            CompileTimeErrorCode
-                .VARIABLE_PATTERN_KEYWORD_IN_DECLARATION_CONTEXT,
-            keyword,
-          );
-        }
-      } else {
-        element.isFinal = node.finalToken != null;
+    var patternContext = node.patternContext;
+    if (patternContext is ForEachPartsWithPatternImpl) {
+      element.isFinal = patternContext.finalKeyword != null;
+    } else if (patternContext is PatternVariableDeclarationImpl) {
+      element.isFinal = patternContext.finalKeyword != null;
+      var keyword = node.keyword;
+      if (keyword != null) {
+        _errorReporter.reportErrorForToken(
+          CompileTimeErrorCode.VARIABLE_PATTERN_KEYWORD_IN_DECLARATION_CONTEXT,
+          keyword,
+        );
       }
+    } else {
+      element.isFinal = node.finalKeyword != null;
     }
   }
 
@@ -621,6 +607,18 @@
   }
 
   @override
+  void visitForEachPartsWithPattern(
+    covariant ForEachPartsWithPatternImpl node,
+  ) {
+    _patternVariables.casePatternStart();
+    super.visitForEachPartsWithPattern(node);
+    var variablesMap = _patternVariables.casePatternFinish();
+    node.variables = variablesMap.values
+        .whereType<BindPatternVariableElementImpl>()
+        .toList();
+  }
+
+  @override
   void visitForPartsWithDeclarations(ForPartsWithDeclarations node) {
     _withNameScope(() {
       super.visitForPartsWithDeclarations(node);
@@ -901,7 +899,7 @@
         // This is a case where the parser does not report an error, because the
         // parser thinks this could be an InstanceCreationExpression.
         _errorReporter.reportErrorForNode(
-            StaticWarningCode.SDK_VERSION_CONSTRUCTOR_TEAROFFS, node, []);
+            WarningCode.SDK_VERSION_CONSTRUCTOR_TEAROFFS, node, []);
       }
       return newNode.accept(this);
     }
@@ -911,8 +909,7 @@
 
   @override
   void visitLabeledStatement(LabeledStatement node) {
-    bool onSwitchStatement = node.statement is SwitchStatement;
-    _buildLabelElements(node.labels, onSwitchStatement, false);
+    _buildLabelElements(node.labels, false);
 
     var outerScope = _labelScope;
     try {
@@ -958,6 +955,21 @@
   }
 
   @override
+  void visitLogicalAndPattern(covariant LogicalAndPatternImpl node) {
+    node.leftOperand.accept(this);
+    node.rightOperand.accept(this);
+  }
+
+  @override
+  void visitLogicalOrPattern(covariant LogicalOrPatternImpl node) {
+    _patternVariables.logicalOrPatternStart();
+    node.leftOperand.accept(this);
+    _patternVariables.logicalOrPatternFinishLeft();
+    node.rightOperand.accept(this);
+    _patternVariables.logicalOrPatternFinish(node);
+  }
+
+  @override
   void visitMethodDeclaration(covariant MethodDeclarationImpl node) {
     ExecutableElementImpl element = node.isGetter || node.isSetter
         ? _elementWalker!.getAccessor()
@@ -1055,7 +1067,7 @@
     super.visitPatternVariableDeclaration(node);
     var variablesMap = _patternVariables.casePatternFinish();
     node.elements = variablesMap.values
-        .whereType<VariablePatternBindElementImpl>()
+        .whereType<BindPatternVariableElementImpl>()
         .toList();
   }
 
@@ -1199,12 +1211,14 @@
     node.expression.accept(this);
 
     for (var case_ in node.cases) {
-      _resolveGuardedPattern(
-        case_.guardedPattern,
-        then: () {
-          case_.expression.accept(this);
-        },
-      );
+      _withNameScope(() {
+        _resolveGuardedPattern(
+          case_.guardedPattern,
+          then: () {
+            case_.expression.accept(this);
+          },
+        );
+      });
     }
   }
 
@@ -1223,27 +1237,27 @@
     node.expression.accept(this);
 
     for (var group in node.memberGroups) {
-      _patternVariables.switchStatementSharedCaseScopeStart(node);
+      _patternVariables.switchStatementSharedCaseScopeStart(group);
       for (var member in group.members) {
-        _buildLabelElements(member.labels, false, true);
+        _buildLabelElements(member.labels, true);
         if (member is SwitchCaseImpl) {
           member.expression.accept(this);
         } else if (member is SwitchDefaultImpl) {
-          _patternVariables.switchStatementSharedCaseScopeEmpty(node);
+          _patternVariables.switchStatementSharedCaseScopeEmpty(group);
         } else if (member is SwitchPatternCaseImpl) {
           _resolveGuardedPattern(
             member.guardedPattern,
-            sharedCaseScopeKey: node,
+            sharedCaseScopeKey: group,
           );
         } else {
           throw UnimplementedError('(${member.runtimeType}) $member');
         }
       }
       if (group.hasLabels) {
-        _patternVariables.switchStatementSharedCaseScopeEmpty(node);
+        _patternVariables.switchStatementSharedCaseScopeEmpty(group);
       }
       group.variables =
-          _patternVariables.switchStatementSharedCaseScopeFinish(node);
+          _patternVariables.switchStatementSharedCaseScopeFinish(group);
       _withNameScope(() {
         var statements = group.statements;
         _buildLocalElements(statements);
@@ -1329,15 +1343,13 @@
 
   /// Builds the label elements associated with [labels] and stores them in the
   /// element holder.
-  void _buildLabelElements(
-      List<Label> labels, bool onSwitchStatement, bool onSwitchMember) {
+  void _buildLabelElements(List<Label> labels, bool onSwitchMember) {
     for (var label in labels) {
       label as LabelImpl;
       var labelName = label.label;
       var element = LabelElementImpl(
         labelName.name,
         labelName.offset,
-        onSwitchStatement,
         onSwitchMember,
       );
       labelName.staticElement = element;
@@ -1477,7 +1489,7 @@
       for (var variable in variables.values) {
         _define(variable);
       }
-      guardedPattern.variables = variables;
+      guardedPattern.variables = variables.cast();
       guardedPattern.whenClause?.accept(this);
       if (then != null) {
         then();
@@ -1675,27 +1687,36 @@
   _VariableBinder({required super.errors});
 
   @override
-  VariablePatternJoinElementImpl joinPatternVariables({
+  JoinPatternVariableElementImpl joinPatternVariables({
     required Object key,
     required List<PromotableElement> components,
     required bool isConsistent,
   }) {
     var first = components.first;
-    var expandedComponents = components.expand((component) {
-      component as VariablePatternElementImpl;
-      if (component is VariablePatternJoinElementImpl) {
-        return component.components;
-      } else {
-        return [component];
-      }
-    }).toList(growable: false);
-    return VariablePatternJoinElementImpl(
+    List<PatternVariableElementImpl> expandedVariables;
+    if (key is LogicalOrPatternImpl) {
+      expandedVariables = components.expand((variable) {
+        variable as PatternVariableElementImpl;
+        if (variable is JoinPatternVariableElementImpl) {
+          return variable.variables;
+        } else {
+          return [variable];
+        }
+      }).toList(growable: false);
+    } else if (key is SwitchStatementCaseGroup) {
+      expandedVariables = components
+          .map((e) => e as PatternVariableElementImpl)
+          .toList(growable: false);
+    } else {
+      throw UnimplementedError('(${key.runtimeType}) $key');
+    }
+    return JoinPatternVariableElementImpl(
       first.name,
       -1,
-      expandedComponents,
+      expandedVariables,
       isConsistent &&
           components.every((element) =>
-              element is! VariablePatternJoinElementImpl ||
+              element is! JoinPatternVariableElementImpl ||
               element.isConsistent),
     )..enclosingElement = first.enclosingElement;
   }
@@ -1716,8 +1737,8 @@
   @override
   void duplicateVariablePattern({
     required String name,
-    required covariant VariablePatternBindElementImpl original,
-    required covariant VariablePatternBindElementImpl duplicate,
+    required covariant BindPatternVariableElementImpl original,
+    required covariant BindPatternVariableElementImpl duplicate,
   }) {
     visitor._errorReporter.reportError(
       DiagnosticFactory().duplicateDefinitionForNodes(
@@ -1732,7 +1753,7 @@
 
   @override
   void logicalOrPatternBranchMissingVariable({
-    required covariant BinaryPatternImpl node,
+    required covariant LogicalOrPatternImpl node,
     required bool hasInLeft,
     required String name,
     required PromotableElement variable,
diff --git a/analyzer/lib/src/dart/resolver/scope.dart b/analyzer/lib/src/dart/resolver/scope.dart
index 60afc47..815b089 100644
--- a/analyzer/lib/src/dart/resolver/scope.dart
+++ b/analyzer/lib/src/dart/resolver/scope.dart
@@ -4,6 +4,7 @@
 
 import 'dart:collection';
 
+import 'package:_fe_analyzer_shared/src/scanner/string_canonicalizer.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
@@ -276,7 +277,7 @@
       if (element != null) {
         newNames[name] = element;
       }
-      String setterName = "$name=";
+      String setterName = considerCanonicalizeString("$name=");
       element = definedNames[setterName];
       if (element != null) {
         newNames[setterName] = element;
diff --git a/analyzer/lib/src/dart/resolver/shared_type_analyzer.dart b/analyzer/lib/src/dart/resolver/shared_type_analyzer.dart
index 7fd8cdb..9799524 100644
--- a/analyzer/lib/src/dart/resolver/shared_type_analyzer.dart
+++ b/analyzer/lib/src/dart/resolver/shared_type_analyzer.dart
@@ -2,6 +2,7 @@
 // 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:_fe_analyzer_shared/src/type_inference/type_analysis_result.dart';
 import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer.dart'
     as shared;
 import 'package:analyzer/dart/ast/ast.dart';
@@ -13,8 +14,8 @@
 import 'package:analyzer/src/error/codes.dart';
 import 'package:collection/collection.dart';
 
-typedef SharedRecordPatternField
-    = shared.RecordPatternField<RecordPatternFieldImpl, DartPattern>;
+typedef SharedPatternField
+    = shared.RecordPatternField<PatternFieldImpl, DartPatternImpl>;
 
 /// Implementation of [shared.TypeAnalyzerErrors] that reports errors using the
 /// analyzer's [ErrorReporter] class.
@@ -46,8 +47,8 @@
   void caseExpressionTypeMismatch(
       {required Expression scrutinee,
       required Expression caseExpression,
-      required scrutineeType,
-      required caseExpressionType,
+      required DartType scrutineeType,
+      required DartType caseExpressionType,
       required bool nullSafetyEnabled}) {
     if (nullSafetyEnabled) {
       _errorReporter.reportErrorForNode(
@@ -74,13 +75,30 @@
   }
 
   @override
-  void duplicateRecordPatternField({
-    required String name,
-    required covariant SharedRecordPatternField original,
-    required covariant SharedRecordPatternField duplicate,
+  void duplicateAssignmentPatternVariable({
+    required covariant PromotableElement variable,
+    required covariant AssignedVariablePatternImpl original,
+    required covariant AssignedVariablePatternImpl duplicate,
   }) {
     _errorReporter.reportError(
-      DiagnosticFactory().duplicateRecordPatternField(
+      DiagnosticFactory().duplicateAssignmentPatternVariable(
+        source: _errorReporter.source,
+        variable: variable,
+        original: original,
+        duplicate: duplicate,
+      ),
+    );
+  }
+
+  @override
+  void duplicateRecordPatternField({
+    required DartPattern objectOrRecordPattern,
+    required String name,
+    required covariant SharedPatternField original,
+    required covariant SharedPatternField duplicate,
+  }) {
+    _errorReporter.reportError(
+      DiagnosticFactory().duplicatePatternField(
         source: _errorReporter.source,
         name: name,
         duplicateField: duplicate.node,
@@ -90,20 +108,70 @@
   }
 
   @override
+  void duplicateRestPattern({
+    required DartPattern mapOrListPattern,
+    required covariant RestPatternElementImpl original,
+    required covariant RestPatternElementImpl duplicate,
+  }) {
+    _errorReporter.reportError(
+      DiagnosticFactory().duplicateRestElementInPattern(
+        source: _errorReporter.source,
+        originalElement: original,
+        duplicateElement: duplicate,
+      ),
+    );
+  }
+
+  @override
   void inconsistentJoinedPatternVariable({
     required PromotableElement variable,
     required PromotableElement component,
   }) {
     _errorReporter.reportErrorForElement(
-      CompileTimeErrorCode.NOT_CONSISTENT_VARIABLE_PATTERN,
+      CompileTimeErrorCode.INCONSISTENT_PATTERN_VARIABLE_LOGICAL_OR,
       component,
       [variable.name],
     );
   }
 
   @override
+  void matchedTypeIsStrictlyNonNullable({
+    required DartPattern pattern,
+    required DartType matchedType,
+  }) {
+    if (pattern is NullAssertPattern) {
+      _errorReporter.reportErrorForToken(
+        StaticWarningCode.UNNECESSARY_NULL_ASSERT_PATTERN,
+        pattern.operator,
+      );
+    } else if (pattern is NullCheckPattern) {
+      _errorReporter.reportErrorForToken(
+        StaticWarningCode.UNNECESSARY_NULL_CHECK_PATTERN,
+        pattern.operator,
+      );
+    } else {
+      throw UnimplementedError('(${pattern.runtimeType}) $pattern');
+    }
+  }
+
+  @override
+  void matchedTypeIsSubtypeOfRequired({
+    required covariant CastPatternImpl pattern,
+    required DartType matchedType,
+    required DartType requiredType,
+  }) {
+    _errorReporter.reportErrorForToken(
+      WarningCode.UNNECESSARY_CAST_PATTERN,
+      pattern.asToken,
+    );
+  }
+
+  @override
   void nonBooleanCondition(Expression node) {
-    throw UnimplementedError('TODO(paulberry)');
+    _errorReporter.reportErrorForNode(
+      CompileTimeErrorCode.NON_BOOL_CONDITION,
+      node,
+    );
   }
 
   @override
@@ -112,6 +180,19 @@
   }
 
   @override
+  void patternForInExpressionIsNotIterable({
+    required AstNode node,
+    required Expression expression,
+    required DartType expressionType,
+  }) {
+    _errorReporter.reportErrorForNode(
+      CompileTimeErrorCode.FOR_IN_OF_INVALID_TYPE,
+      expression,
+      [expressionType, 'Iterable'],
+    );
+  }
+
+  @override
   void patternTypeMismatchInIrrefutableContext({
     required covariant DartPatternImpl pattern,
     required AstNode context,
@@ -135,13 +216,24 @@
 
   @override
   void relationalPatternOperatorReturnTypeNotAssignableToBool({
-    required covariant RelationalPatternImpl node,
+    required covariant RelationalPatternImpl pattern,
     required DartType returnType,
   }) {
     _errorReporter.reportErrorForToken(
       CompileTimeErrorCode
           .RELATIONAL_PATTERN_OPERATOR_RETURN_TYPE_NOT_ASSIGNABLE_TO_BOOL,
-      node.operator,
+      pattern.operator,
+    );
+  }
+
+  @override
+  void restPatternNotLastInMap(
+    covariant MapPatternImpl node,
+    covariant RestPatternElementImpl element,
+  ) {
+    _errorReporter.reportErrorForNode(
+      CompileTimeErrorCode.REST_ELEMENT_NOT_LAST_IN_MAP_PATTERN,
+      element,
     );
   }
 
@@ -163,4 +255,19 @@
         CompileTimeErrorCode.SWITCH_CASE_COMPLETES_NORMALLY,
         node.members[caseIndex + numHeads - 1].keyword);
   }
+
+  @override
+  void unnecessaryWildcardPattern({
+    required covariant WildcardPatternImpl pattern,
+    required UnnecessaryWildcardKind kind,
+  }) {
+    switch (kind) {
+      case UnnecessaryWildcardKind.logicalAndPatternOperand:
+        _errorReporter.reportErrorForNode(
+          WarningCode.UNNECESSARY_WILDCARD_PATTERN,
+          pattern,
+        );
+        break;
+    }
+  }
 }
diff --git a/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart b/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart
index 203305e..e9ef959 100644
--- a/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart
+++ b/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart
@@ -494,7 +494,7 @@
       // no context type. If there are any elements, inference has not failed,
       // as the types of those elements are considered resolved.
       _errorReporter.reportErrorForNode(
-          HintCode.INFERENCE_FAILURE_ON_COLLECTION_LITERAL, node, ['List']);
+          WarningCode.INFERENCE_FAILURE_ON_COLLECTION_LITERAL, node, ['List']);
     }
 
     inferrer.constrainArguments(
@@ -624,7 +624,7 @@
         elementType = typeArguments[0].typeOrThrow;
       }
       node.staticType = _typeProvider.listElement.instantiate(
-        typeArguments: [elementType],
+        typeArguments: fixedTypeList(elementType),
         nullabilitySuffix: _noneOrStarSuffix,
       );
       return;
@@ -660,7 +660,7 @@
         node.becomeSet();
         var elementType = typeArguments[0].typeOrThrow;
         node.staticType = _typeProvider.setElement.instantiate(
-          typeArguments: [elementType],
+          typeArguments: fixedTypeList(elementType),
           nullabilitySuffix: _noneOrStarSuffix,
         );
         return;
@@ -669,7 +669,7 @@
         var keyType = typeArguments[0].typeOrThrow;
         var valueType = typeArguments[1].typeOrThrow;
         node.staticType = _typeProvider.mapElement.instantiate(
-          typeArguments: [keyType, valueType],
+          typeArguments: fixedTypeList(keyType, valueType),
           nullabilitySuffix: _noneOrStarSuffix,
         );
         return;
@@ -697,7 +697,7 @@
       // no context type. If there are any elements, inference has not failed,
       // as the types of those elements are considered resolved.
       _errorReporter.reportErrorForNode(
-          HintCode.INFERENCE_FAILURE_ON_COLLECTION_LITERAL,
+          WarningCode.INFERENCE_FAILURE_ON_COLLECTION_LITERAL,
           node,
           [node.isMap ? 'Map' : 'Set']);
     }
diff --git a/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart b/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
index c68e465..d475243 100644
--- a/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
+++ b/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
@@ -7,6 +7,7 @@
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type_schema.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 
@@ -29,7 +30,7 @@
     if (initializer == null) {
       if (_strictInference && parent.type == null) {
         _resolver.errorReporter.reportErrorForNode(
-          HintCode.INFERENCE_FAILURE_ON_UNINITIALIZED_VARIABLE,
+          WarningCode.INFERENCE_FAILURE_ON_UNINITIALIZED_VARIABLE,
           node,
           [node.name.lexeme],
         );
@@ -47,7 +48,11 @@
       _resolver.flowAnalysis.flow?.lateInitializer_begin(node);
     }
 
-    _resolver.analyzeExpression(initializer, element.type);
+    final contextType = element is! PropertyInducingElementImpl ||
+            element.shouldUseTypeForInitializerInference
+        ? element.type
+        : UnknownInferredType.instance;
+    _resolver.analyzeExpression(initializer, contextType);
     initializer = _resolver.popRewrite()!;
     var whyNotPromoted =
         _resolver.flowAnalysis.flow?.whyNotPromoted(initializer);
diff --git a/analyzer/lib/src/dart/scanner/scanner.dart b/analyzer/lib/src/dart/scanner/scanner.dart
index e6bd686..769f32c 100644
--- a/analyzer/lib/src/dart/scanner/scanner.dart
+++ b/analyzer/lib/src/dart/scanner/scanner.dart
@@ -200,7 +200,7 @@
           source,
           versionToken.offset,
           versionToken.length,
-          HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_GREATER,
+          WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_GREATER,
           [latestVersion.major, latestVersion.minor],
         ),
       );
diff --git a/analyzer/lib/src/dart/sdk/sdk.dart b/analyzer/lib/src/dart/sdk/sdk.dart
index b1ca57e..d3199db 100644
--- a/analyzer/lib/src/dart/sdk/sdk.dart
+++ b/analyzer/lib/src/dart/sdk/sdk.dart
@@ -10,10 +10,12 @@
 import 'package:analyzer/exception/exception.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/src/dart/sdk/sdk_utils.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_engine_io.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/utilities/uri_cache.dart';
 import 'package:pub_semver/pub_semver.dart';
 import 'package:yaml/yaml.dart';
 
@@ -63,7 +65,7 @@
       return null;
     }
     try {
-      return file.createSource(Uri.parse(path));
+      return file.createSource(uriCache.parse(path));
     } on FormatException catch (exception, stackTrace) {
       AnalysisEngine.instance.instrumentationService.logInfo(
           "Failed to create URI: $path",
@@ -112,7 +114,7 @@
     String filePath = srcPath.replaceAll('/', separator);
     try {
       File file = resourceProvider.getFile(filePath);
-      return file.createSource(Uri.parse(dartUri));
+      return file.createSource(uriCache.parse(dartUri));
     } on FormatException {
       return null;
     }
@@ -138,7 +140,7 @@
     }
 
     try {
-      return Uri.parse(uriStr);
+      return uriCache.parse(uriStr);
     } on FormatException {
       return null;
     }
@@ -161,12 +163,10 @@
     for (final library in libraryMap.sdkLibraries) {
       final pathContext = resourceProvider.pathContext;
       if (pathContext.isAbsolute(library.path)) {
-        final libraryFile = resourceProvider.getFile(library.path);
-        final libraryFolder = libraryFile.parent;
-        if (libraryFolder.contains(file.path)) {
-          final relPath = pathContext
-              .relative(file.path, from: libraryFolder.path)
-              .replaceAll(separator, '/');
+        String? relativePathIfInside =
+            getRelativePathIfInside(library.path, file.path);
+        if (relativePathIfInside != null) {
+          final relPath = relativePathIfInside.replaceAll(separator, '/');
           return '${library.shortName}/$relPath';
         }
       }
@@ -250,7 +250,7 @@
   // TODO(danrubel) Determine SDK version
   String get sdkVersion => '0';
 
-  /// The url mappings for this SDK.
+  /// The URL mappings for this SDK.
   Map<String, String> get urlMappings => _urlMappings;
 
   @override
@@ -290,7 +290,7 @@
     String filePath = srcPath.replaceAll('/', separator);
     try {
       File file = resourceProvider.getFile(filePath);
-      return file.createSource(Uri.parse(dartUri));
+      return file.createSource(uriCache.parse(dartUri));
     } on FormatException {
       return null;
     }
@@ -320,9 +320,10 @@
   ///
   /// If a key doesn't begin with `dart:` it is ignored.
   void _processEmbedderYaml(Folder libDir, YamlMap map) {
-    YamlNode embeddedLibs = map[_embeddedLibMapKey];
+    var embeddedLibs = map[_embeddedLibMapKey] as YamlNode;
     if (embeddedLibs is YamlMap) {
-      embeddedLibs.forEach((k, v) => _processEmbeddedLibs(k, v, libDir));
+      embeddedLibs.forEach(
+          (k, v) => _processEmbeddedLibs(k as String, v as String, libDir));
     }
   }
 }
@@ -544,11 +545,11 @@
         if (relativeFile.path == file.path) {
           // The relative file is the library, so return a Source for the
           // library rather than the part format.
-          return file.createSource(Uri.parse(library.shortName));
+          return file.createSource(uriCache.parse(library.shortName));
         }
         file = relativeFile;
       }
-      return file.createSource(Uri.parse(dartUri));
+      return file.createSource(uriCache.parse(dartUri));
     } on FormatException {
       return null;
     }
diff --git a/analyzer/lib/src/dart/sdk/sdk_utils.dart b/analyzer/lib/src/dart/sdk/sdk_utils.dart
new file mode 100644
index 0000000..976a4d9
--- /dev/null
+++ b/analyzer/lib/src/dart/sdk/sdk_utils.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:math' show min;
+
+String? getRelativePathIfInside(String libraryPath, String filePath) {
+  int minLength = min(libraryPath.length, filePath.length);
+
+  // Find how far the strings are the same.
+  int same = 0;
+  for (int i = 0; i < minLength; i++) {
+    if (libraryPath.codeUnitAt(i) == filePath.codeUnitAt(i)) {
+      same++;
+    } else {
+      break;
+    }
+  }
+  // They're the same up to and including index [same].
+  // If there isn't a path seperator left in the string [libPath],
+  // [filePath] is inside the same dir as [libPath] (possibly within
+  // subdirs).
+  const int forwardSlash = 47;
+  const int backwardsSlash = 92;
+  for (int i = same; i < libraryPath.length; i++) {
+    int c = libraryPath.codeUnitAt(i);
+    if (c == forwardSlash || c == backwardsSlash) {
+      return null;
+    }
+  }
+
+  // To get the relative path we need to go back to the previous path
+  // seperator.
+  for (int i = same; i >= 0; i--) {
+    int c = libraryPath.codeUnitAt(i);
+    if (c == forwardSlash || c == backwardsSlash) {
+      return filePath.substring(i + 1);
+    }
+  }
+  throw UnsupportedError("Unsupported input: $libraryPath and $filePath");
+}
diff --git a/analyzer/lib/src/diagnostic/diagnostic_factory.dart b/analyzer/lib/src/diagnostic/diagnostic_factory.dart
index b94b9e1..fd3c839 100644
--- a/analyzer/lib/src/diagnostic/diagnostic_factory.dart
+++ b/analyzer/lib/src/diagnostic/diagnostic_factory.dart
@@ -8,6 +8,7 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/diagnostic/diagnostic.dart';
 import 'package:analyzer/error/error.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/diagnostic/diagnostic.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -17,6 +18,32 @@
   /// Initialize a newly created diagnostic factory.
   DiagnosticFactory();
 
+  /// Return a diagnostic indicating that [duplicate] uses the same [variable]
+  /// as a previous [original] node in a pattern assignment.
+  AnalysisError duplicateAssignmentPatternVariable({
+    required Source source,
+    required PromotableElement variable,
+    required AssignedVariablePatternImpl original,
+    required AssignedVariablePatternImpl duplicate,
+  }) {
+    return AnalysisError(
+      source,
+      duplicate.offset,
+      duplicate.length,
+      CompileTimeErrorCode.DUPLICATE_PATTERN_ASSIGNMENT_VARIABLE,
+      [variable.name],
+      [
+        DiagnosticMessageImpl(
+          filePath: source.fullName,
+          length: original.length,
+          message: 'The first assigned variable pattern.',
+          offset: original.offset,
+          url: source.uri.toString(),
+        ),
+      ],
+    );
+  }
+
   /// Return a diagnostic indicating that [duplicateElement] reuses a name
   /// already used by [originalElement].
   AnalysisError duplicateDefinition(ErrorCode code, Element duplicateElement,
@@ -114,21 +141,21 @@
 
   /// Return a diagnostic indicating that [duplicateField] reuses a name
   /// already used by [originalField].
-  AnalysisError duplicateRecordPatternField({
+  AnalysisError duplicatePatternField({
     required Source source,
     required String name,
-    required RecordPatternField duplicateField,
-    required RecordPatternField originalField,
+    required PatternField duplicateField,
+    required PatternField originalField,
   }) {
-    var originalNode = originalField.fieldName!;
+    var originalNode = originalField.name!;
     var originalTarget = originalNode.name ?? originalNode.colon;
-    var duplicateNode = duplicateField.fieldName!;
+    var duplicateNode = duplicateField.name!;
     var duplicateTarget = duplicateNode.name ?? duplicateNode.colon;
     return AnalysisError(
       source,
       duplicateTarget.offset,
       duplicateTarget.length,
-      CompileTimeErrorCode.DUPLICATE_RECORD_PATTERN_FIELD,
+      CompileTimeErrorCode.DUPLICATE_PATTERN_FIELD,
       [name],
       [
         DiagnosticMessageImpl(
@@ -142,6 +169,31 @@
     );
   }
 
+  /// Return a diagnostic indicating that [duplicateElement] reuses a name
+  /// already used by [originalElement].
+  AnalysisError duplicateRestElementInPattern({
+    required Source source,
+    required RestPatternElement originalElement,
+    required RestPatternElement duplicateElement,
+  }) {
+    return AnalysisError(
+      source,
+      duplicateElement.offset,
+      duplicateElement.length,
+      CompileTimeErrorCode.DUPLICATE_REST_ELEMENT_IN_PATTERN,
+      [],
+      [
+        DiagnosticMessageImpl(
+          filePath: source.fullName,
+          length: originalElement.length,
+          message: 'The first rest element.',
+          offset: originalElement.offset,
+          url: source.uri.toString(),
+        ),
+      ],
+    );
+  }
+
   /// Return a diagnostic indicating that the [duplicateElement] (in a constant
   /// set) is a duplicate of the [originalElement].
   AnalysisError equalElementsInConstSet(
@@ -175,6 +227,22 @@
     ]);
   }
 
+  /// Return a diagnostic indicating that the [duplicateKey] (in a map pattern)
+  /// is a duplicate of the [originalKey].
+  AnalysisError equalKeysInMapPattern(
+      Source source, Expression duplicateKey, Expression originalKey) {
+    return AnalysisError(source, duplicateKey.offset, duplicateKey.length,
+        CompileTimeErrorCode.EQUAL_KEYS_IN_MAP_PATTERN, [], [
+      DiagnosticMessageImpl(
+        filePath: source.fullName,
+        message: "The first key with this value.",
+        offset: originalKey.offset,
+        length: originalKey.length,
+        url: null,
+      )
+    ]);
+  }
+
   /// Return a diagnostic indicating that the [duplicateKey] (in a constant map)
   /// is a duplicate of the [originalKey].
   AnalysisError invalidNullAwareAfterShortCircuit(Source source, int offset,
@@ -199,17 +267,17 @@
   /// [superMember].
   AnalysisError invalidOverride(
       Source source,
-      ErrorCode? errorCode,
+      ErrorCode errorCode,
       SyntacticEntity errorNode,
       ExecutableElement member,
-      ExecutableElement superMember) {
-    errorCode ??= CompileTimeErrorCode.INVALID_OVERRIDE;
+      ExecutableElement superMember,
+      String memberName) {
     // Elements enclosing members that can participate in overrides are always
     // named, so we can safely assume `_thisMember.enclosingElement3.name` and
     // `superMember.enclosingElement3.name` are non-`null`.
     return AnalysisError(
         source, errorNode.offset, errorNode.length, errorCode, [
-      member.name,
+      memberName,
       member.enclosingElement.name!,
       member.type,
       superMember.enclosingElement.name!,
@@ -226,6 +294,13 @@
             message: "The member being overridden.",
             offset: superMember.nonSynthetic.nameOffset,
             length: superMember.nonSynthetic.nameLength,
+            url: null),
+      if (errorCode == CompileTimeErrorCode.INVALID_OVERRIDE_SETTER)
+        DiagnosticMessageImpl(
+            filePath: superMember.source.fullName,
+            message: "The setter being overridden.",
+            offset: superMember.nonSynthetic.nameOffset,
+            length: superMember.nonSynthetic.nameLength,
             url: null)
     ]);
   }
diff --git a/analyzer/lib/src/error/analyzer_error_code.dart b/analyzer/lib/src/error/analyzer_error_code.dart
index 9324223..0c0319f 100644
--- a/analyzer/lib/src/error/analyzer_error_code.dart
+++ b/analyzer/lib/src/error/analyzer_error_code.dart
@@ -4,7 +4,7 @@
 
 import 'package:analyzer/error/error.dart';
 
-/// A superclass for error codes that can have a url associated with them.
+/// A superclass for error codes that can have a URL associated with them.
 abstract class AnalyzerErrorCode extends ErrorCode {
   /// Initialize a newly created error code.
   const AnalyzerErrorCode({
diff --git a/analyzer/lib/src/error/best_practices_verifier.dart b/analyzer/lib/src/error/best_practices_verifier.dart
index 4d1585e..d26a05a 100644
--- a/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/analyzer/lib/src/error/best_practices_verifier.dart
@@ -144,8 +144,8 @@
       if (parent is MethodDeclaration) {
         _checkForInvalidFactory(parent);
       } else {
-        _errorReporter
-            .reportErrorForNode(HintCode.INVALID_FACTORY_ANNOTATION, node, []);
+        _errorReporter.reportErrorForNode(
+            WarningCode.INVALID_FACTORY_ANNOTATION, node, []);
       }
     } else if (element.isImmutable) {
       if (parent is! ClassDeclaration &&
@@ -196,7 +196,7 @@
           parent.parent is ExtensionDeclaration ||
           parent.parent is EnumDeclaration) {
         _errorReporter.reportErrorForNode(
-          HintCode.INVALID_ANNOTATION_TARGET,
+          WarningCode.INVALID_ANNOTATION_TARGET,
           node,
           [node.name.name, 'instance members of classes and mixins'],
         );
@@ -207,7 +207,7 @@
           parent.parent is ExtensionDeclaration ||
           parent.parent is EnumDeclaration) {
         _errorReporter.reportErrorForNode(
-          HintCode.INVALID_ANNOTATION_TARGET,
+          WarningCode.INVALID_ANNOTATION_TARGET,
           node,
           [node.name.name, 'instance members of classes and mixins'],
         );
@@ -232,7 +232,7 @@
     } else if (element.isSealed) {
       if (!(parent is ClassDeclaration || parent is ClassTypeAlias)) {
         _errorReporter.reportErrorForNode(
-            HintCode.INVALID_SEALED_ANNOTATION, node);
+            WarningCode.INVALID_SEALED_ANNOTATION, node);
       }
     } else if (element.isVisibleForTemplate ||
         element.isVisibleForTesting ||
@@ -337,8 +337,8 @@
         var validKinds = kindNames.commaSeparatedWithOr;
         // Annotations always refer to named elements, so we can safely assume
         // that `name` is non-`null`.
-        _errorReporter.reportErrorForNode(
-            HintCode.INVALID_ANNOTATION_TARGET, node.name, [name!, validKinds]);
+        _errorReporter.reportErrorForNode(WarningCode.INVALID_ANNOTATION_TARGET,
+            node.name, [name!, validKinds]);
         return;
       }
     }
@@ -372,6 +372,7 @@
   void visitBinaryExpression(BinaryExpression node) {
     _checkForDivisionOptimizationHint(node);
     _deprecatedVerifier.binaryExpression(node);
+    _checkForInvariantNanComparison(node);
     _checkForInvariantNullComparison(node);
     _invalidAccessVerifier.verifyBinary(node);
     super.visitBinaryExpression(node);
@@ -422,7 +423,7 @@
     if (newKeyword != null &&
         _currentLibrary.featureSet.isEnabled(Feature.constructor_tearoffs)) {
       _errorReporter.reportErrorForToken(
-          HintCode.DEPRECATED_NEW_IN_COMMENT_REFERENCE, newKeyword, []);
+          WarningCode.DEPRECATED_NEW_IN_COMMENT_REFERENCE, newKeyword, []);
     }
     super.visitCommentReference(node);
   }
@@ -435,7 +436,7 @@
         // Check the block for a return statement, if not, create the hint.
         if (!ExitDetector.exits(node.body)) {
           _errorReporter.reportErrorForNode(
-              HintCode.MISSING_RETURN, node, [node.returnType.name]);
+              WarningCode.MISSING_RETURN, node, [node.returnType.name]);
         }
       }
     }
@@ -584,12 +585,14 @@
 
   @override
   void visitFunctionExpression(FunctionExpression node) {
+    var body = node.body;
     if (node.parent is! FunctionDeclaration) {
-      _checkForMissingReturn(node.body, node);
+      _checkForMissingReturn(body, node);
     }
     if (!(node as FunctionExpressionImpl).wasFunctionTypeSupplied) {
       _checkStrictInferenceInParameters(node.parameters, body: node.body);
     }
+    _checkForUnnecessarySetLiteral(body, node);
     super.visitFunctionExpression(node);
   }
 
@@ -884,8 +887,8 @@
       } else {
         _errorReporter.reportErrorForNode(
           node.notOperator == null
-              ? HintCode.TYPE_CHECK_IS_NULL
-              : HintCode.TYPE_CHECK_IS_NOT_NULL,
+              ? WarningCode.TYPE_CHECK_IS_NULL
+              : WarningCode.TYPE_CHECK_IS_NOT_NULL,
           node,
         );
       }
@@ -989,8 +992,8 @@
         var value = constEvaluation.value;
         if (value != null && !alreadySeen.add(value)) {
           var errorCode = node.isSet
-              ? HintCode.EQUAL_ELEMENTS_IN_SET
-              : HintCode.EQUAL_KEYS_IN_MAP;
+              ? WarningCode.EQUAL_ELEMENTS_IN_SET
+              : WarningCode.EQUAL_KEYS_IN_MAP;
           _errorReporter.reportErrorForNode(errorCode, expression);
         }
       }
@@ -1106,7 +1109,7 @@
     if (libraryElement == null) return;
     if (libraryElement.hasInternal) {
       _errorReporter.reportErrorForNode(
-          HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT,
+          WarningCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT,
           node,
           [libraryElement.displayName]);
     }
@@ -1115,7 +1118,7 @@
     exportNamespace.definedNames.forEach((String name, Element element) {
       if (element.hasInternal) {
         _errorReporter.reportErrorForNode(
-            HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT,
+            WarningCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT,
             node,
             [element.displayName]);
       } else if (element is FunctionElement) {
@@ -1128,7 +1131,7 @@
           var aliasElement = type?.alias?.element;
           if (aliasElement != null && aliasElement.hasInternal) {
             _errorReporter.reportErrorForNode(
-                HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT_INDIRECTLY,
+                WarningCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT_INDIRECTLY,
                 node,
                 [aliasElement.name, element.displayName]);
           }
@@ -1143,7 +1146,9 @@
     var returnType = decl.returnType?.type;
     if (returnType is VoidType) {
       _errorReporter.reportErrorForToken(
-          HintCode.INVALID_FACTORY_METHOD_DECL, decl.name, [decl.name.lexeme]);
+          WarningCode.INVALID_FACTORY_METHOD_DECL,
+          decl.name,
+          [decl.name.lexeme]);
       return;
     }
 
@@ -1172,7 +1177,7 @@
     }
 
     _errorReporter.reportErrorForToken(
-        HintCode.INVALID_FACTORY_METHOD_IMPL, decl.name, [decl.name.lexeme]);
+        WarningCode.INVALID_FACTORY_METHOD_IMPL, decl.name, [decl.name.lexeme]);
   }
 
   void _checkForInvalidSealedSuperclass(NamedCompilationUnitMember node) {
@@ -1207,6 +1212,40 @@
     }
   }
 
+  void _checkForInvariantNanComparison(BinaryExpression node) {
+    void reportStartEnd(
+      HintCode errorCode,
+      SyntacticEntity startEntity,
+      SyntacticEntity endEntity,
+    ) {
+      var offset = startEntity.offset;
+      _errorReporter.reportErrorForOffset(
+        errorCode,
+        offset,
+        endEntity.end - offset,
+      );
+    }
+
+    bool isDoubleNan(Expression expression) =>
+        expression is PrefixedIdentifier &&
+        expression.prefix.name == 'double' &&
+        expression.identifier.name == 'nan';
+
+    void checkLeftRight(HintCode errorCode) {
+      if (isDoubleNan(node.leftOperand)) {
+        reportStartEnd(errorCode, node.leftOperand, node.operator);
+      } else if (isDoubleNan(node.rightOperand)) {
+        reportStartEnd(errorCode, node.operator, node.rightOperand);
+      }
+    }
+
+    if (node.operator.type == TokenType.BANG_EQ) {
+      checkLeftRight(HintCode.UNNECESSARY_NAN_COMPARISON_TRUE);
+    } else if (node.operator.type == TokenType.EQ_EQ) {
+      checkLeftRight(HintCode.UNNECESSARY_NAN_COMPARISON_FALSE);
+    }
+  }
+
   void _checkForInvariantNullComparison(BinaryExpression node) {
     if (!_isNonNullableByDefault) return;
 
@@ -1306,7 +1345,7 @@
   /// Note: for async functions/methods, this hint only applies when the
   /// function has a return type that Future<Null> is not assignable to.
   ///
-  /// See [HintCode.MISSING_RETURN].
+  /// See [WarningCode.MISSING_RETURN].
   void _checkForMissingReturn(FunctionBody body, AstNode functionNode) {
     if (_isNonNullableByDefault) {
       return;
@@ -1335,19 +1374,19 @@
 
     if (functionNode is FunctionDeclaration) {
       _errorReporter.reportErrorForToken(
-        HintCode.MISSING_RETURN,
+        WarningCode.MISSING_RETURN,
         functionNode.name,
         [returnType],
       );
     } else if (functionNode is MethodDeclaration) {
       _errorReporter.reportErrorForToken(
-        HintCode.MISSING_RETURN,
+        WarningCode.MISSING_RETURN,
         functionNode.name,
         [returnType],
       );
     } else {
       _errorReporter.reportErrorForNode(
-        HintCode.MISSING_RETURN,
+        WarningCode.MISSING_RETURN,
         functionNode,
         [returnType],
       );
@@ -1366,7 +1405,7 @@
 
     if (_typeSystem.isPotentiallyNullable(type.typeOrThrow)) {
       _errorReporter.reportErrorForNode(
-        HintCode.NULLABLE_TYPE_IN_CATCH_CLAUSE,
+        WarningCode.NULLABLE_TYPE_IN_CATCH_CLAUSE,
         type,
       );
     }
@@ -1422,7 +1461,7 @@
         parent is ConditionalExpression && parent.condition == childOfParent ||
         parent is AssertStatement && parent.condition == childOfParent) {
       _errorReporter.reportErrorForNode(
-          HintCode.NULL_AWARE_IN_CONDITION, childOfParent);
+          WarningCode.NULL_AWARE_IN_CONDITION, childOfParent);
       return;
     }
 
@@ -1432,7 +1471,7 @@
             [TokenType.BAR_BAR, TokenType.AMPERSAND_AMPERSAND]
                 .contains(parent.operator.type)) {
       _errorReporter.reportErrorForNode(
-          HintCode.NULL_AWARE_IN_LOGICAL_OPERATOR, childOfParent);
+          WarningCode.NULL_AWARE_IN_LOGICAL_OPERATOR, childOfParent);
       return;
     }
 
@@ -1442,7 +1481,7 @@
             .contains(parent.operator.type) &&
         parent.leftOperand == childOfParent) {
       _errorReporter.reportErrorForNode(
-          HintCode.NULL_AWARE_BEFORE_OPERATOR, childOfParent);
+          WarningCode.NULL_AWARE_BEFORE_OPERATOR, childOfParent);
       return;
     }
   }
@@ -1464,7 +1503,7 @@
         // named elements, so we can safely assume `entry.value.name` is
         // non-`null`.
         _errorReporter.reportErrorForNode(
-          HintCode.RETURN_OF_DO_NOT_STORE,
+          WarningCode.RETURN_OF_DO_NOT_STORE,
           entry.key,
           [entry.value.name!, parent.declaredElement!.displayName],
         );
@@ -1518,6 +1557,47 @@
     return false;
   }
 
+  /// Generate hints related to returning a set literal in an
+  /// [ExpressionFunctionBody], having a single expression,
+  /// for a function of `void` return type.
+  void _checkForUnnecessarySetLiteral(
+      FunctionBody body, FunctionExpression node) {
+    if (body is ExpressionFunctionBodyImpl) {
+      var parameterType = node.staticParameterElement?.type;
+
+      DartType? returnType;
+      if (parameterType is FunctionType) {
+        returnType = parameterType.returnType;
+      } else {
+        var parent = node.parent;
+        if (parent is! FunctionDeclaration) return;
+        returnType = parent.returnType?.type;
+      }
+      if (returnType == null) return;
+
+      bool isReturnVoid;
+      if (returnType.isVoid) {
+        isReturnVoid = true;
+      } else if (returnType is ParameterizedType &&
+          (returnType.isDartAsyncFuture || returnType.isDartAsyncFutureOr)) {
+        var typeArguments = returnType.typeArguments;
+        isReturnVoid = typeArguments.length == 1 && typeArguments.first.isVoid;
+      } else {
+        isReturnVoid = false;
+      }
+      if (isReturnVoid) {
+        var expression = body.expression;
+        if (expression is SetOrMapLiteralImpl && expression.isSet) {
+          var elements = expression.elements;
+          if (elements.length == 1 && elements.first is Expression) {
+            _errorReporter.reportErrorForNode(
+                HintCode.UNNECESSARY_SET_LITERAL, expression);
+          }
+        }
+      }
+    }
+  }
+
   void _checkRequiredParameter(FormalParameterList node) {
     final requiredParameters =
         node.parameters.where((p) => p.declaredElement?.hasRequired == true);
@@ -1528,19 +1608,21 @@
         .where((p) => p.declaredElement!.defaultValueCode != null);
     for (final param in nonNamedParamsWithRequired.where((p) => p.isOptional)) {
       _errorReporter.reportErrorForNode(
-          HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM,
+          WarningCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM,
           param,
           [_formalParameterNameOrEmpty(param)]);
     }
     for (final param in nonNamedParamsWithRequired.where((p) => p.isRequired)) {
       _errorReporter.reportErrorForNode(
-          HintCode.INVALID_REQUIRED_POSITIONAL_PARAM,
+          WarningCode.INVALID_REQUIRED_POSITIONAL_PARAM,
           param,
           [_formalParameterNameOrEmpty(param)]);
     }
     for (final param in namedParamsWithRequiredAndDefault) {
-      _errorReporter.reportErrorForNode(HintCode.INVALID_REQUIRED_NAMED_PARAM,
-          param, [_formalParameterNameOrEmpty(param)]);
+      _errorReporter.reportErrorForNode(
+          WarningCode.INVALID_REQUIRED_NAMED_PARAM,
+          param,
+          [_formalParameterNameOrEmpty(param)]);
     }
   }
 
@@ -1579,7 +1661,7 @@
       if (parameter.type == null && isParameterReferenced(parameter)) {
         ParameterElement element = parameter.declaredElement!;
         _errorReporter.reportErrorForNode(
-          HintCode.INFERENCE_FAILURE_ON_UNTYPED_PARAMETER,
+          WarningCode.INFERENCE_FAILURE_ON_UNTYPED_PARAMETER,
           parameter,
           [element.displayName],
         );
@@ -1608,7 +1690,7 @@
     }
     if (returnType == null) {
       _errorReporter.reportErrorForNode(
-          HintCode.INFERENCE_FAILURE_ON_FUNCTION_RETURN_TYPE,
+          WarningCode.INFERENCE_FAILURE_ON_FUNCTION_RETURN_TYPE,
           reportNode,
           [displayName]);
     }
@@ -1932,7 +2014,7 @@
       }
 
       _errorReporter.reportErrorForToken(
-          HintCode.INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER,
+          WarningCode.INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER,
           operator,
           [operator.type.lexeme]);
     }
@@ -1946,8 +2028,10 @@
       // `stringValue` is if its string contains an interpolation, in which case
       // the element would never have resolved in the first place.  So we can
       // safely assume `node.uri.stringValue` is non-`null`.
-      _errorReporter.reportErrorForNode(HintCode.INVALID_USE_OF_INTERNAL_MEMBER,
-          node, [node.uri.stringValue!]);
+      _errorReporter.reportErrorForNode(
+          WarningCode.INVALID_USE_OF_INTERNAL_MEMBER,
+          node,
+          [node.uri.stringValue!]);
     }
   }
 
@@ -1960,7 +2044,7 @@
     if (_hasInternal(element) &&
         !_isLibraryInWorkspacePackage(element!.library)) {
       _errorReporter.reportErrorForNode(
-          HintCode.INVALID_USE_OF_INTERNAL_MEMBER, node, [element.name]);
+          WarningCode.INVALID_USE_OF_INTERNAL_MEMBER, node, [element.name]);
     }
   }
 
@@ -1982,7 +2066,7 @@
       }
 
       _errorReporter.reportErrorForNode(
-          HintCode.INVALID_USE_OF_INTERNAL_MEMBER, node, [name]);
+          WarningCode.INVALID_USE_OF_INTERNAL_MEMBER, node, [name]);
     }
   }
 
@@ -2032,20 +2116,20 @@
     var definingClass = element.enclosingElement;
     if (hasProtected) {
       _errorReporter.reportErrorForNode(
-          HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
+          WarningCode.INVALID_USE_OF_PROTECTED_MEMBER,
           node,
           [name, definingClass!.source!.uri]);
     }
     if (hasVisibleForTemplate) {
       _errorReporter.reportErrorForNode(
-          HintCode.INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER,
+          WarningCode.INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER,
           node,
           [name, definingClass!.source!.uri]);
     }
 
     if (hasVisibleForTesting) {
       _errorReporter.reportErrorForNode(
-          HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER,
+          WarningCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER,
           node,
           [name, definingClass!.source!.uri]);
     }
@@ -2063,7 +2147,7 @@
       }
       if (!validOverride) {
         _errorReporter.reportErrorForNode(
-            HintCode.INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER,
+            WarningCode.INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER,
             node,
             [name]);
       }
diff --git a/analyzer/lib/src/error/codes.g.dart b/analyzer/lib/src/error/codes.g.dart
index 9688517..3afdd68 100644
--- a/analyzer/lib/src/error/codes.g.dart
+++ b/analyzer/lib/src/error/codes.g.dart
@@ -12,6 +12,7 @@
 // ignore_for_file: constant_identifier_names
 
 import "package:analyzer/error/error.dart";
+import "package:analyzer/src/dart/error/hint_codes.g.dart";
 import "package:analyzer/src/error/analyzer_error_code.dart";
 
 class CompileTimeErrorCode extends AnalyzerErrorCode {
@@ -228,6 +229,26 @@
   );
 
   ///  Parameters:
+  ///  0: the name of the base class being implemented
+  static const CompileTimeErrorCode BASE_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY =
+      CompileTimeErrorCode(
+    'INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY',
+    "The class '{0}' can't be implemented outside of its library because it's "
+        "a base class.",
+    uniqueName: 'BASE_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY',
+  );
+
+  ///  Parameters:
+  ///  0: the name of the base mixin being implemented
+  static const CompileTimeErrorCode BASE_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY =
+      CompileTimeErrorCode(
+    'INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY',
+    "The mixin '{0}' can't be implemented outside of its library because it's "
+        "a base mixin.",
+    uniqueName: 'BASE_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY',
+  );
+
+  ///  Parameters:
   ///  0: the name of the return type
   static const CompileTimeErrorCode BODY_MIGHT_COMPLETE_NORMALLY =
       CompileTimeErrorCode(
@@ -390,6 +411,14 @@
     uniqueName: 'CLASS_INSTANTIATION_ACCESS_TO_UNKNOWN_MEMBER',
   );
 
+  ///  Parameters:
+  ///  0: the name of the class being used as a mixin
+  static const CompileTimeErrorCode CLASS_USED_AS_MIXIN = CompileTimeErrorCode(
+    'CLASS_USED_AS_MIXIN',
+    "The class '{0}' can't be used as a mixin because it isn't a mixin class "
+        "nor a mixin.",
+  );
+
   static const CompileTimeErrorCode CONCRETE_CLASS_HAS_ENUM_SUPERINTERFACE =
       CompileTimeErrorCode(
     'CONCRETE_CLASS_HAS_ENUM_SUPERINTERFACE',
@@ -1013,11 +1042,12 @@
     correctionMessage: "Try calling a different constructor.",
   );
 
-  static const CompileTimeErrorCode CONTINUE_LABEL_ON_SWITCH =
+  ///  No parameters.
+  static const CompileTimeErrorCode CONTINUE_LABEL_INVALID =
       CompileTimeErrorCode(
-    'CONTINUE_LABEL_ON_SWITCH',
-    "A `continue` label resolves to a `switch` statement, but the label must "
-        "be on a loop or a switch member.",
+    'CONTINUE_LABEL_INVALID',
+    "The label used in a 'continue' statement must be defined on either a loop "
+        "or a switch member.",
     hasPublishedDocs: true,
   );
 
@@ -1179,14 +1209,30 @@
   );
 
   ///  Parameters:
-  ///  0: the name of the field
-  static const CompileTimeErrorCode DUPLICATE_RECORD_PATTERN_FIELD =
+  ///  0: the name of the variable
+  static const CompileTimeErrorCode DUPLICATE_PATTERN_ASSIGNMENT_VARIABLE =
       CompileTimeErrorCode(
-    'DUPLICATE_RECORD_PATTERN_FIELD',
+    'DUPLICATE_PATTERN_ASSIGNMENT_VARIABLE',
+    "The variable '{0}' is already assigned in this pattern.",
+    correctionMessage: "Try renaming the variable.",
+  );
+
+  ///  Parameters:
+  ///  0: the name of the field
+  static const CompileTimeErrorCode DUPLICATE_PATTERN_FIELD =
+      CompileTimeErrorCode(
+    'DUPLICATE_PATTERN_FIELD',
     "The field '{0}' is already matched in this pattern.",
     correctionMessage: "Try removing the duplicate field.",
   );
 
+  static const CompileTimeErrorCode DUPLICATE_REST_ELEMENT_IN_PATTERN =
+      CompileTimeErrorCode(
+    'DUPLICATE_REST_ELEMENT_IN_PATTERN',
+    "At most one rest element is allowed in a list or map pattern.",
+    correctionMessage: "Try removing the duplicate rest element.",
+  );
+
   ///  Parameters:
   ///  0: the name of the variable
   static const CompileTimeErrorCode DUPLICATE_VARIABLE_PATTERN =
@@ -1264,6 +1310,14 @@
     hasPublishedDocs: true,
   );
 
+  ///  No parameters.
+  static const CompileTimeErrorCode EQUAL_KEYS_IN_MAP_PATTERN =
+      CompileTimeErrorCode(
+    'EQUAL_KEYS_IN_MAP_PATTERN',
+    "Two keys in a map pattern can't be equal.",
+    correctionMessage: "Change or remove the duplicate key.",
+  );
+
   ///  Parameters:
   ///  0: the number of provided type arguments
   static const CompileTimeErrorCode EXPECTED_ONE_LIST_PATTERN_TYPE_ARGUMENTS =
@@ -1313,7 +1367,7 @@
   );
 
   ///  Parameters:
-  ///  0: the uri pointing to a library
+  ///  0: the URI pointing to a library
   static const CompileTimeErrorCode EXPORT_INTERNAL_LIBRARY =
       CompileTimeErrorCode(
     'EXPORT_INTERNAL_LIBRARY',
@@ -1333,7 +1387,7 @@
   );
 
   ///  Parameters:
-  ///  0: the uri pointing to a non-library declaration
+  ///  0: the URI pointing to a non-library declaration
   static const CompileTimeErrorCode EXPORT_OF_NON_LIBRARY =
       CompileTimeErrorCode(
     'EXPORT_OF_NON_LIBRARY',
@@ -1609,6 +1663,26 @@
   );
 
   ///  Parameters:
+  ///  0: the name of the final class being extended.
+  static const CompileTimeErrorCode FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY =
+      CompileTimeErrorCode(
+    'INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY',
+    "The class '{0}' can't be extended outside of its library because it's a "
+        "final class.",
+    uniqueName: 'FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY',
+  );
+
+  ///  Parameters:
+  ///  0: the name of the final class being implemented.
+  static const CompileTimeErrorCode FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY =
+      CompileTimeErrorCode(
+    'INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY',
+    "The class '{0}' can't be implemented outside of its library because it's "
+        "a final class.",
+    uniqueName: 'FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY',
+  );
+
+  ///  Parameters:
   ///  0: the name of the field in question
   static const CompileTimeErrorCode
       FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR = CompileTimeErrorCode(
@@ -1620,6 +1694,26 @@
   );
 
   ///  Parameters:
+  ///  0: the name of the final mixin being implemented.
+  static const CompileTimeErrorCode FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY =
+      CompileTimeErrorCode(
+    'INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY',
+    "The mixin '{0}' can't be implemented outside of its library because it's "
+        "a final mixin.",
+    uniqueName: 'FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY',
+  );
+
+  ///  Parameters:
+  ///  0: the name of the final mixin being mixed in.
+  static const CompileTimeErrorCode FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY =
+      CompileTimeErrorCode(
+    'INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY',
+    "The mixin '{0}' can't be mixed-in outside of its library because it's a "
+        "final mixin.",
+    uniqueName: 'FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY',
+  );
+
+  ///  Parameters:
   ///  0: the name of the uninitialized final variable
   static const CompileTimeErrorCode FINAL_NOT_INITIALIZED =
       CompileTimeErrorCode(
@@ -1684,7 +1778,7 @@
   static const CompileTimeErrorCode FOR_IN_OF_INVALID_TYPE =
       CompileTimeErrorCode(
     'FOR_IN_OF_INVALID_TYPE',
-    "The type '{0}' used in the 'for' loop must implement {1}.",
+    "The type '{0}' used in the 'for' loop must implement '{1}'.",
     hasPublishedDocs: true,
   );
 
@@ -1949,7 +2043,7 @@
   );
 
   ///  Parameters:
-  ///  0: the uri pointing to a library
+  ///  0: the URI pointing to a library
   static const CompileTimeErrorCode IMPORT_INTERNAL_LIBRARY =
       CompileTimeErrorCode(
     'IMPORT_INTERNAL_LIBRARY',
@@ -1958,7 +2052,7 @@
   );
 
   ///  Parameters:
-  ///  0: the uri pointing to a non-library declaration
+  ///  0: the URI pointing to a non-library declaration
   static const CompileTimeErrorCode IMPORT_OF_NON_LIBRARY =
       CompileTimeErrorCode(
     'IMPORT_OF_NON_LIBRARY',
@@ -2034,6 +2128,30 @@
   );
 
   ///  Parameters:
+  ///  0: the name of the pattern variable
+  static const CompileTimeErrorCode INCONSISTENT_PATTERN_VARIABLE_LOGICAL_OR =
+      CompileTimeErrorCode(
+    'INCONSISTENT_PATTERN_VARIABLE_LOGICAL_OR',
+    "The variable '{0}' has a different type and/or finality in this branch of "
+        "the logical-or pattern.",
+    correctionMessage:
+        "Try declaring the variable pattern with the same type and finality in "
+        "both branches.",
+  );
+
+  ///  Parameters:
+  ///  0: the name of the pattern variable
+  static const CompileTimeErrorCode
+      INCONSISTENT_PATTERN_VARIABLE_SHARED_CASE_SCOPE = CompileTimeErrorCode(
+    'INCONSISTENT_PATTERN_VARIABLE_SHARED_CASE_SCOPE',
+    "The variable '{0}' doesn't have the same type and/or finality in all "
+        "cases that share this body.",
+    correctionMessage:
+        "Try declaring the variable pattern with the same type and finality in "
+        "all cases.",
+  );
+
+  ///  Parameters:
   ///  0: the name of the initializing formal that is not an instance variable in
   ///     the immediately enclosing class
   static const CompileTimeErrorCode INITIALIZER_FOR_NON_EXISTENT_FIELD =
@@ -2168,6 +2286,26 @@
     hasPublishedDocs: true,
   );
 
+  ///  Parameters:
+  ///  0: the name of the interface class being extended.
+  static const CompileTimeErrorCode
+      INTERFACE_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY = CompileTimeErrorCode(
+    'INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY',
+    "The class '{0}' can't be extended outside of its library because it's an "
+        "interface class.",
+    uniqueName: 'INTERFACE_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY',
+  );
+
+  ///  Parameters:
+  ///  0: the name of the interface mixin being mixed in.
+  static const CompileTimeErrorCode
+      INTERFACE_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY = CompileTimeErrorCode(
+    'INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY',
+    "The mixin '{0}' can't be mixed-in outside of its library because it's an "
+        "interface mixin.",
+    uniqueName: 'INTERFACE_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY',
+  );
+
   ///  No parameters.
   static const CompileTimeErrorCode INVALID_ANNOTATION = CompileTimeErrorCode(
     'INVALID_ANNOTATION',
@@ -2385,6 +2523,24 @@
     hasPublishedDocs: true,
   );
 
+  ///  Parameters:
+  ///  0: the name of the declared setter that is not a valid override.
+  ///  1: the name of the interface that declares the setter.
+  ///  2: the type of the declared setter in the interface.
+  ///  3: the name of the interface with the overridden setter.
+  ///  4: the type of the overridden setter.
+  ///
+  ///  These parameters must be kept in sync with those of
+  ///  [CompileTimeErrorCode.INVALID_OVERRIDE].
+  static const CompileTimeErrorCode INVALID_IMPLEMENTATION_OVERRIDE_SETTER =
+      CompileTimeErrorCode(
+    'INVALID_IMPLEMENTATION_OVERRIDE',
+    "The setter '{1}.{0}' ('{2}') isn't a valid concrete implementation of "
+        "'{3}.{0}' ('{4}').",
+    hasPublishedDocs: true,
+    uniqueName: 'INVALID_IMPLEMENTATION_OVERRIDE_SETTER',
+  );
+
   ///  No parameters.
   static const CompileTimeErrorCode INVALID_INLINE_FUNCTION_TYPE =
       CompileTimeErrorCode(
@@ -2428,6 +2584,20 @@
     hasPublishedDocs: true,
   );
 
+  ///  Parameters:
+  ///  0: the name of the declared setter that is not a valid override.
+  ///  1: the name of the interface that declares the setter.
+  ///  2: the type of the declared setter in the interface.
+  ///  3: the name of the interface with the overridden setter.
+  ///  4: the type of the overridden setter.
+  static const CompileTimeErrorCode INVALID_OVERRIDE_SETTER =
+      CompileTimeErrorCode(
+    'INVALID_OVERRIDE',
+    "The setter '{1}.{0}' ('{2}') isn't a valid override of '{3}.{0}' ('{4}').",
+    hasPublishedDocs: true,
+    uniqueName: 'INVALID_OVERRIDE_SETTER',
+  );
+
   static const CompileTimeErrorCode
       INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR = CompileTimeErrorCode(
     'INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR',
@@ -2835,6 +3005,17 @@
   );
 
   ///  Parameters:
+  ///  0: the display name of the setter without a concrete implementation
+  static const CompileTimeErrorCode
+      MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_SETTER = CompileTimeErrorCode(
+    'MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_MEMBER',
+    "The class doesn't have a concrete implementation of the super-invoked "
+        "setter '{0}'.",
+    hasPublishedDocs: true,
+    uniqueName: 'MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_SETTER',
+  );
+
+  ///  Parameters:
   ///  0: the name of the mixin that is invalid
   static const CompileTimeErrorCode MIXIN_CLASS_DECLARES_CONSTRUCTOR =
       CompileTimeErrorCode(
@@ -3218,6 +3399,14 @@
   );
 
   ///  No parameters.
+  static const CompileTimeErrorCode NON_CONSTANT_MAP_PATTERN_KEY =
+      CompileTimeErrorCode(
+    'NON_CONSTANT_MAP_PATTERN_KEY',
+    "Key expressions in map patterns must be constants.",
+    correctionMessage: "Try using constants instead.",
+  );
+
+  ///  No parameters.
   static const CompileTimeErrorCode NON_CONSTANT_MAP_VALUE =
       CompileTimeErrorCode(
     'NON_CONSTANT_MAP_VALUE',
@@ -3240,6 +3429,14 @@
   );
 
   ///  No parameters.
+  static const CompileTimeErrorCode NON_CONSTANT_RELATIONAL_PATTERN_EXPRESSION =
+      CompileTimeErrorCode(
+    'NON_CONSTANT_RELATIONAL_PATTERN_EXPRESSION',
+    "The relational pattern expression must be a constant.",
+    correctionMessage: "Try using a constant instead.",
+  );
+
+  ///  No parameters.
   static const CompileTimeErrorCode NON_CONSTANT_SET_ELEMENT =
       CompileTimeErrorCode(
     'NON_CONSTANT_SET_ELEMENT',
@@ -3266,6 +3463,16 @@
         "an expression statement.",
   );
 
+  ///  Parameters:
+  ///  0: the type of the switch scrutinee
+  ///  1: the unmatched space
+  static const CompileTimeErrorCode NON_EXHAUSTIVE_SWITCH =
+      CompileTimeErrorCode(
+    'NON_EXHAUSTIVE_SWITCH',
+    "The type '{0}' is not exhaustively matched by the switch cases.",
+    correctionMessage: "Try adding a default case or cases that match {1}.",
+  );
+
   ///  No parameters.
   static const CompileTimeErrorCode NON_FINAL_FIELD_IN_ENUM =
       CompileTimeErrorCode(
@@ -3386,18 +3593,6 @@
   );
 
   ///  Parameters:
-  ///  0: the name of the variable pattern
-  static const CompileTimeErrorCode NOT_CONSISTENT_VARIABLE_PATTERN =
-      CompileTimeErrorCode(
-    'NOT_CONSISTENT_VARIABLE_PATTERN',
-    "Variable pattern '{0}' has a different type or finality in this branch of "
-        "the logical-or pattern.",
-    correctionMessage:
-        "Try declaring the variable pattern with the same type and finality in "
-        "both branches.",
-  );
-
-  ///  Parameters:
   ///  0: the expected number of required arguments
   ///  1: the actual number of positional arguments given
   ///  2: name of the function or method
@@ -3660,7 +3855,7 @@
   );
 
   ///  Parameters:
-  ///  0: the uri pointing to a non-library declaration
+  ///  0: the URI pointing to a non-library declaration
   static const CompileTimeErrorCode PART_OF_NON_PART = CompileTimeErrorCode(
     'PART_OF_NON_PART',
     "The included part '{0}' must have a part-of directive.",
@@ -3710,6 +3905,14 @@
         "type.",
   );
 
+  static const CompileTimeErrorCode PATTERN_VARIABLE_ASSIGNMENT_INSIDE_GUARD =
+      CompileTimeErrorCode(
+    'PATTERN_VARIABLE_ASSIGNMENT_INSIDE_GUARD',
+    "Pattern variables can't be assigned inside the guard of the enclosing "
+        "guarded pattern.",
+    correctionMessage: "Try assigning to a different variable.",
+  );
+
   ///  No parameters.
   static const CompileTimeErrorCode
       POSITIONAL_SUPER_FORMAL_PARAMETER_WITH_POSITIONAL_ARGUMENT =
@@ -4047,6 +4250,13 @@
         "Try updating the operator declaration to return 'bool'.",
   );
 
+  static const CompileTimeErrorCode REST_ELEMENT_NOT_LAST_IN_MAP_PATTERN =
+      CompileTimeErrorCode(
+    'REST_ELEMENT_NOT_LAST_IN_MAP_PATTERN',
+    "A rest element in a map pattern must be the last element.",
+    correctionMessage: "Try moving the rest element to be the last element.",
+  );
+
   static const CompileTimeErrorCode
       REST_ELEMENT_WITH_SUBPATTERN_IN_MAP_PATTERN = CompileTimeErrorCode(
     'REST_ELEMENT_WITH_SUBPATTERN_IN_MAP_PATTERN',
@@ -4144,20 +4354,23 @@
   );
 
   ///  Parameters:
-  ///  0: the name of the supertype being extended, implemented, or mixed in
+  ///  0: the name of the sealed class being extended, implemented, or mixed in
   static const CompileTimeErrorCode SEALED_CLASS_SUBTYPE_OUTSIDE_OF_LIBRARY =
       CompileTimeErrorCode(
-    'SEALED_CLASS_SUBTYPE_OUTSIDE_OF_LIBRARY',
-    "The sealed class '{0}' can't be extended, implemented, or mixed in "
-        "outside of its library.",
+    'INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY',
+    "The class '{0}' can't be extended, implemented, or mixed in outside of "
+        "its library because it's a sealed class.",
+    uniqueName: 'SEALED_CLASS_SUBTYPE_OUTSIDE_OF_LIBRARY',
   );
 
   ///  Parameters:
-  ///  0: the name of the supertype being mixed in
+  ///  0: the name of the sealed mixin being mixed in
   static const CompileTimeErrorCode SEALED_MIXIN_SUBTYPE_OUTSIDE_OF_LIBRARY =
       CompileTimeErrorCode(
-    'SEALED_MIXIN_SUBTYPE_OUTSIDE_OF_LIBRARY',
-    "The sealed mixin '{0}' can't be mixed in outside of its library.",
+    'INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY',
+    "The mixin '{0}' can't be mixed in outside of its library because it's a "
+        "sealed mixin.",
+    uniqueName: 'SEALED_MIXIN_SUBTYPE_OUTSIDE_OF_LIBRARY',
   );
 
   ///  No parameters.
@@ -4910,7 +5123,7 @@
   );
 
   ///  Parameters:
-  ///  0: the URI pointing to a non-existent file
+  ///  0: the URI pointing to a nonexistent file
   static const CompileTimeErrorCode URI_DOES_NOT_EXIST = CompileTimeErrorCode(
     'URI_DOES_NOT_EXIST',
     "Target of URI doesn't exist: '{0}'.",
@@ -4921,7 +5134,7 @@
   );
 
   ///  Parameters:
-  ///  0: the URI pointing to a non-existent file
+  ///  0: the URI pointing to a nonexistent file
   static const CompileTimeErrorCode URI_HAS_NOT_BEEN_GENERATED =
       CompileTimeErrorCode(
     'URI_HAS_NOT_BEEN_GENERATED',
@@ -5416,138 +5629,6 @@
     hasPublishedDocs: true,
   );
 
-  ///  Parameters:
-  ///  0: the name of the class
-  static const StaticWarningCode SDK_VERSION_ASYNC_EXPORTED_FROM_CORE =
-      StaticWarningCode(
-    'SDK_VERSION_ASYNC_EXPORTED_FROM_CORE',
-    "The class '{0}' wasn't exported from 'dart:core' until version 2.1, but "
-        "this code is required to be able to run on earlier versions.",
-    correctionMessage:
-        "Try either importing 'dart:async' or updating the SDK constraints.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
-  static const StaticWarningCode SDK_VERSION_AS_EXPRESSION_IN_CONST_CONTEXT =
-      StaticWarningCode(
-    'SDK_VERSION_AS_EXPRESSION_IN_CONST_CONTEXT',
-    "The use of an as expression in a constant expression wasn't supported "
-        "until version 2.3.2, but this code is required to be able to run on "
-        "earlier versions.",
-    correctionMessage: "Try updating the SDK constraints.",
-    hasPublishedDocs: true,
-  );
-
-  ///  Parameters:
-  ///  0: the name of the operator
-  static const StaticWarningCode SDK_VERSION_BOOL_OPERATOR_IN_CONST_CONTEXT =
-      StaticWarningCode(
-    'SDK_VERSION_BOOL_OPERATOR_IN_CONST_CONTEXT',
-    "The use of the operator '{0}' for 'bool' operands in a constant context "
-        "wasn't supported until version 2.3.2, but this code is required to be "
-        "able to run on earlier versions.",
-    correctionMessage: "Try updating the SDK constraints.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
-  ///
-  ///  There is also a [ParserError.EXPERIMENT_NOT_ENABLED] code which catches
-  ///  some cases of constructor tearoff features (like `List<int>.filled;`).
-  ///  Other constructor tearoff cases are not realized until resolution
-  ///  (like `List.filled;`).
-  static const StaticWarningCode SDK_VERSION_CONSTRUCTOR_TEAROFFS =
-      StaticWarningCode(
-    'SDK_VERSION_CONSTRUCTOR_TEAROFFS',
-    "Tearing off a constructor requires the 'constructor-tearoffs' language "
-        "feature.",
-    correctionMessage:
-        "Try updating your pubspec.yaml to set the minimum SDK constraint to "
-        "2.15 or higher, and running 'pub get'.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
-  static const StaticWarningCode SDK_VERSION_EQ_EQ_OPERATOR_IN_CONST_CONTEXT =
-      StaticWarningCode(
-    'SDK_VERSION_EQ_EQ_OPERATOR_IN_CONST_CONTEXT',
-    "Using the operator '==' for non-primitive types wasn't supported until "
-        "version 2.3.2, but this code is required to be able to run on earlier "
-        "versions.",
-    correctionMessage: "Try updating the SDK constraints.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
-  static const StaticWarningCode SDK_VERSION_EXTENSION_METHODS =
-      StaticWarningCode(
-    'SDK_VERSION_EXTENSION_METHODS',
-    "Extension methods weren't supported until version 2.6.0, but this code is "
-        "required to be able to run on earlier versions.",
-    correctionMessage: "Try updating the SDK constraints.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
-  static const StaticWarningCode SDK_VERSION_GT_GT_GT_OPERATOR =
-      StaticWarningCode(
-    'SDK_VERSION_GT_GT_GT_OPERATOR',
-    "The operator '>>>' wasn't supported until version 2.14.0, but this code "
-        "is required to be able to run on earlier versions.",
-    correctionMessage: "Try updating the SDK constraints.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
-  static const StaticWarningCode SDK_VERSION_IS_EXPRESSION_IN_CONST_CONTEXT =
-      StaticWarningCode(
-    'SDK_VERSION_IS_EXPRESSION_IN_CONST_CONTEXT',
-    "The use of an is expression in a constant context wasn't supported until "
-        "version 2.3.2, but this code is required to be able to run on earlier "
-        "versions.",
-    correctionMessage: "Try updating the SDK constraints.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
-  static const StaticWarningCode SDK_VERSION_NEVER = StaticWarningCode(
-    'SDK_VERSION_NEVER',
-    "The type 'Never' wasn't supported until version 2.12.0, but this code is "
-        "required to be able to run on earlier versions.",
-    correctionMessage: "Try updating the SDK constraints.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
-  static const StaticWarningCode SDK_VERSION_SET_LITERAL = StaticWarningCode(
-    'SDK_VERSION_SET_LITERAL',
-    "Set literals weren't supported until version 2.2, but this code is "
-        "required to be able to run on earlier versions.",
-    correctionMessage: "Try updating the SDK constraints.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
-  static const StaticWarningCode SDK_VERSION_UI_AS_CODE = StaticWarningCode(
-    'SDK_VERSION_UI_AS_CODE',
-    "The for, if, and spread elements weren't supported until version 2.3.0, "
-        "but this code is required to be able to run on earlier versions.",
-    correctionMessage: "Try updating the SDK constraints.",
-    hasPublishedDocs: true,
-  );
-
-  ///  No parameters.
-  static const StaticWarningCode SDK_VERSION_UI_AS_CODE_IN_CONST_CONTEXT =
-      StaticWarningCode(
-    'SDK_VERSION_UI_AS_CODE_IN_CONST_CONTEXT',
-    "The if and spread elements weren't supported in constant expressions "
-        "until version 2.5.0, but this code is required to be able to run on "
-        "earlier versions.",
-    correctionMessage: "Try updating the SDK constraints.",
-    hasPublishedDocs: true,
-  );
-
   ///  No parameters.
   static const StaticWarningCode UNNECESSARY_NON_NULL_ASSERTION =
       StaticWarningCode(
@@ -5557,6 +5638,26 @@
     hasPublishedDocs: true,
   );
 
+  ///  No parameters.
+  static const StaticWarningCode UNNECESSARY_NULL_ASSERT_PATTERN =
+      StaticWarningCode(
+    'UNNECESSARY_NULL_ASSERT_PATTERN',
+    "The null-assert pattern will have no effect because the matched type "
+        "isn't nullable.",
+    correctionMessage:
+        "Try replacing the null-assert pattern with its nested pattern.",
+  );
+
+  ///  No parameters.
+  static const StaticWarningCode UNNECESSARY_NULL_CHECK_PATTERN =
+      StaticWarningCode(
+    'UNNECESSARY_NULL_CHECK_PATTERN',
+    "The null-check pattern will have no effect because the matched type isn't "
+        "nullable.",
+    correctionMessage:
+        "Try replacing the null-check pattern with its nested pattern.",
+  );
+
   /// Initialize a newly created error code to have the given [name].
   const StaticWarningCode(
     String name,
@@ -5577,3 +5678,972 @@
   @override
   ErrorType get type => ErrorType.STATIC_WARNING;
 }
+
+class WarningCode extends AnalyzerErrorCode {
+  ///  Parameters:
+  ///  0: the name of the actual argument type
+  ///  1: the name of the expected function return type
+  static const WarningCode ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER =
+      WarningCode(
+    'ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER',
+    "The argument type '{0}' can't be assigned to the parameter type '{1} "
+        "Function(Object)' or '{1} Function(Object, StackTrace)'.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Parameters:
+  ///  0: the return type as derived by the type of the [Future].
+  static const WarningCode BODY_MIGHT_COMPLETE_NORMALLY_CATCH_ERROR =
+      WarningCode(
+    'BODY_MIGHT_COMPLETE_NORMALLY_CATCH_ERROR',
+    "This 'onError' handler must return a value assignable to '{0}', but ends "
+        "without returning a value.",
+    correctionMessage: "Try adding a return statement.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Parameters:
+  ///  0: the name of the declared return type
+  static const WarningCode BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE = WarningCode(
+    'BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE',
+    "This function has a nullable return type of '{0}', but ends without "
+        "returning a value.",
+    correctionMessage:
+        "Try adding a return statement, or if no value is ever returned, try "
+        "changing the return type to 'void'.",
+  );
+
+  ///  This is the new replacement for [HintCode.DEAD_CODE].
+  static const HintCode DEAD_CODE = HintCode.DEAD_CODE;
+
+  ///  No parameters.
+  static const WarningCode DEPRECATED_EXTENDS_FUNCTION = WarningCode(
+    'DEPRECATED_SUBTYPE_OF_FUNCTION',
+    "Extending 'Function' is deprecated.",
+    correctionMessage: "Try removing 'Function' from the 'extends' clause.",
+    hasPublishedDocs: true,
+    uniqueName: 'DEPRECATED_EXTENDS_FUNCTION',
+  );
+
+  ///  No parameters.
+  static const WarningCode DEPRECATED_IMPLEMENTS_FUNCTION = WarningCode(
+    'DEPRECATED_SUBTYPE_OF_FUNCTION',
+    "Implementing 'Function' has no effect.",
+    correctionMessage: "Try removing 'Function' from the 'implements' clause.",
+    hasPublishedDocs: true,
+    uniqueName: 'DEPRECATED_IMPLEMENTS_FUNCTION',
+  );
+
+  ///  No parameters.
+  static const WarningCode DEPRECATED_MIXIN_FUNCTION = WarningCode(
+    'DEPRECATED_SUBTYPE_OF_FUNCTION',
+    "Mixing in 'Function' is deprecated.",
+    correctionMessage: "Try removing 'Function' from the 'with' clause.",
+    hasPublishedDocs: true,
+    uniqueName: 'DEPRECATED_MIXIN_FUNCTION',
+  );
+
+  ///  No parameters.
+  static const WarningCode DEPRECATED_NEW_IN_COMMENT_REFERENCE = WarningCode(
+    'DEPRECATED_NEW_IN_COMMENT_REFERENCE',
+    "Using the 'new' keyword in a comment reference is deprecated.",
+    correctionMessage: "Try referring to a constructor by its name.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Duplicate exports.
+  ///
+  ///  No parameters.
+  static const WarningCode DUPLICATE_EXPORT = WarningCode(
+    'DUPLICATE_EXPORT',
+    "Duplicate export.",
+    correctionMessage: "Try removing all but one export of the library.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  static const WarningCode DUPLICATE_HIDDEN_NAME = WarningCode(
+    'DUPLICATE_HIDDEN_NAME',
+    "Duplicate hidden name.",
+    correctionMessage:
+        "Try removing the repeated name from the list of hidden members.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Parameters:
+  ///  0: the name of the diagnostic being ignored
+  static const WarningCode DUPLICATE_IGNORE = WarningCode(
+    'DUPLICATE_IGNORE',
+    "The diagnostic '{0}' doesn't need to be ignored here because it's already "
+        "being ignored.",
+    correctionMessage:
+        "Try removing the name from the list, or removing the whole comment if "
+        "this is the only name in the list.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Duplicate imports.
+  ///
+  ///  No parameters.
+  static const WarningCode DUPLICATE_IMPORT = WarningCode(
+    'DUPLICATE_IMPORT',
+    "Duplicate import.",
+    correctionMessage: "Try removing all but one import of the library.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  static const WarningCode DUPLICATE_SHOWN_NAME = WarningCode(
+    'DUPLICATE_SHOWN_NAME',
+    "Duplicate shown name.",
+    correctionMessage:
+        "Try removing the repeated name from the list of shown members.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  static const WarningCode EQUAL_ELEMENTS_IN_SET = WarningCode(
+    'EQUAL_ELEMENTS_IN_SET',
+    "Two elements in a set literal shouldn't be equal.",
+    correctionMessage: "Change or remove the duplicate element.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  static const WarningCode EQUAL_KEYS_IN_MAP = WarningCode(
+    'EQUAL_KEYS_IN_MAP',
+    "Two keys in a map literal shouldn't be equal.",
+    correctionMessage: "Change or remove the duplicate key.",
+    hasPublishedDocs: true,
+  );
+
+  ///  When "strict-inference" is enabled, collection literal types must be
+  ///  inferred via the context type, or have type arguments.
+  ///
+  ///  Parameters:
+  ///  0: the name of the collection
+  static const WarningCode INFERENCE_FAILURE_ON_COLLECTION_LITERAL =
+      WarningCode(
+    'INFERENCE_FAILURE_ON_COLLECTION_LITERAL',
+    "The type argument(s) of '{0}' can't be inferred.",
+    correctionMessage: "Use explicit type argument(s) for '{0}'.",
+  );
+
+  ///  When "strict-inference" is enabled, types in function invocations must be
+  ///  inferred via the context type, or have type arguments.
+  ///
+  ///  Parameters:
+  ///  0: the name of the function
+  static const WarningCode INFERENCE_FAILURE_ON_FUNCTION_INVOCATION =
+      WarningCode(
+    'INFERENCE_FAILURE_ON_FUNCTION_INVOCATION',
+    "The type argument(s) of the function '{0}' can't be inferred.",
+    correctionMessage: "Use explicit type argument(s) for '{0}'.",
+  );
+
+  ///  When "strict-inference" is enabled, recursive local functions, top-level
+  ///  functions, methods, and function-typed function parameters must all
+  ///  specify a return type. See the strict-inference resource:
+  ///
+  ///  https://github.com/dart-lang/language/blob/master/resources/type-system/strict-inference.md
+  ///
+  ///  Parameters:
+  ///  0: the name of the function or method
+  static const WarningCode INFERENCE_FAILURE_ON_FUNCTION_RETURN_TYPE =
+      WarningCode(
+    'INFERENCE_FAILURE_ON_FUNCTION_RETURN_TYPE',
+    "The return type of '{0}' cannot be inferred.",
+    correctionMessage: "Declare the return type of '{0}'.",
+  );
+
+  ///  When "strict-inference" is enabled, types in function invocations must be
+  ///  inferred via the context type, or have type arguments.
+  ///
+  ///  Parameters:
+  ///  0: the name of the type
+  static const WarningCode INFERENCE_FAILURE_ON_GENERIC_INVOCATION =
+      WarningCode(
+    'INFERENCE_FAILURE_ON_GENERIC_INVOCATION',
+    "The type argument(s) of the generic function type '{0}' can't be "
+        "inferred.",
+    correctionMessage: "Use explicit type argument(s) for '{0}'.",
+  );
+
+  ///  When "strict-inference" is enabled, types in instance creation
+  ///  (constructor calls) must be inferred via the context type, or have type
+  ///  arguments.
+  ///
+  ///  Parameters:
+  ///  0: the name of the constructor
+  static const WarningCode INFERENCE_FAILURE_ON_INSTANCE_CREATION = WarningCode(
+    'INFERENCE_FAILURE_ON_INSTANCE_CREATION',
+    "The type argument(s) of the constructor '{0}' can't be inferred.",
+    correctionMessage: "Use explicit type argument(s) for '{0}'.",
+  );
+
+  ///  When "strict-inference" in enabled, uninitialized variables must be
+  ///  declared with a specific type.
+  ///
+  ///  Parameters:
+  ///  0: the name of the variable
+  static const WarningCode INFERENCE_FAILURE_ON_UNINITIALIZED_VARIABLE =
+      WarningCode(
+    'INFERENCE_FAILURE_ON_UNINITIALIZED_VARIABLE',
+    "The type of {0} can't be inferred without either a type or initializer.",
+    correctionMessage: "Try specifying the type of the variable.",
+  );
+
+  ///  When "strict-inference" in enabled, function parameters must be
+  ///  declared with a specific type, or inherit a type.
+  ///
+  ///  Parameters:
+  ///  0: the name of the parameter
+  static const WarningCode INFERENCE_FAILURE_ON_UNTYPED_PARAMETER = WarningCode(
+    'INFERENCE_FAILURE_ON_UNTYPED_PARAMETER',
+    "The type of {0} can't be inferred; a type must be explicitly provided.",
+    correctionMessage: "Try specifying the type of the parameter.",
+  );
+
+  ///  Parameters:
+  ///  0: the name of the annotation
+  ///  1: the list of valid targets
+  static const WarningCode INVALID_ANNOTATION_TARGET = WarningCode(
+    'INVALID_ANNOTATION_TARGET',
+    "The annotation '{0}' can only be used on {1}.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Parameters:
+  ///  0: the name of the element
+  static const WarningCode INVALID_EXPORT_OF_INTERNAL_ELEMENT = WarningCode(
+    'INVALID_EXPORT_OF_INTERNAL_ELEMENT',
+    "The member '{0}' can't be exported as a part of a package's public API.",
+    correctionMessage: "Try using a hide clause to hide '{0}'.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Parameters:
+  ///  0: the name of the element
+  ///  1: ?
+  static const WarningCode INVALID_EXPORT_OF_INTERNAL_ELEMENT_INDIRECTLY =
+      WarningCode(
+    'INVALID_EXPORT_OF_INTERNAL_ELEMENT_INDIRECTLY',
+    "The member '{0}' can't be exported as a part of a package's public API, "
+        "but is indirectly exported as part of the signature of '{1}'.",
+    correctionMessage: "Try using a hide clause to hide '{0}'.",
+    hasPublishedDocs: true,
+  );
+
+  ///  This hint is generated anywhere a @factory annotation is associated with
+  ///  anything other than a method.
+  static const WarningCode INVALID_FACTORY_ANNOTATION = WarningCode(
+    'INVALID_FACTORY_ANNOTATION',
+    "Only methods can be annotated as factories.",
+  );
+
+  ///  Parameters:
+  ///  0: The name of the method
+  static const WarningCode INVALID_FACTORY_METHOD_DECL = WarningCode(
+    'INVALID_FACTORY_METHOD_DECL',
+    "Factory method '{0}' must have a return type.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Parameters:
+  ///  0: the name of the method
+  static const WarningCode INVALID_FACTORY_METHOD_IMPL = WarningCode(
+    'INVALID_FACTORY_METHOD_IMPL',
+    "Factory method '{0}' doesn't return a newly allocated object.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  static const WarningCode INVALID_LANGUAGE_VERSION_OVERRIDE_AT_SIGN =
+      WarningCode(
+    'INVALID_LANGUAGE_VERSION_OVERRIDE',
+    "The Dart language version override number must begin with '@dart'.",
+    correctionMessage:
+        "Specify a Dart language version override with a comment like '// "
+        "@dart = 2.0'.",
+    hasPublishedDocs: true,
+    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_AT_SIGN',
+  );
+
+  ///  No parameters.
+  static const WarningCode INVALID_LANGUAGE_VERSION_OVERRIDE_EQUALS =
+      WarningCode(
+    'INVALID_LANGUAGE_VERSION_OVERRIDE',
+    "The Dart language version override comment must be specified with an '=' "
+        "character.",
+    correctionMessage:
+        "Specify a Dart language version override with a comment like '// "
+        "@dart = 2.0'.",
+    hasPublishedDocs: true,
+    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_EQUALS',
+  );
+
+  ///  Parameters:
+  ///  0: the latest major version
+  ///  1: the latest minor version
+  static const WarningCode INVALID_LANGUAGE_VERSION_OVERRIDE_GREATER =
+      WarningCode(
+    'INVALID_LANGUAGE_VERSION_OVERRIDE',
+    "The language version override can't specify a version greater than the "
+        "latest known language version: {0}.{1}.",
+    correctionMessage: "Try removing the language version override.",
+    hasPublishedDocs: true,
+    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_GREATER',
+  );
+
+  static const WarningCode INVALID_LANGUAGE_VERSION_OVERRIDE_LOCATION =
+      WarningCode(
+    'INVALID_LANGUAGE_VERSION_OVERRIDE',
+    "The language version override must be specified before any declaration or "
+        "directive.",
+    correctionMessage:
+        "Try moving the language version override to the top of the file.",
+    hasPublishedDocs: true,
+    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_LOCATION',
+  );
+
+  ///  No parameters.
+  static const WarningCode INVALID_LANGUAGE_VERSION_OVERRIDE_LOWER_CASE =
+      WarningCode(
+    'INVALID_LANGUAGE_VERSION_OVERRIDE',
+    "The Dart language version override comment must be specified with the "
+        "word 'dart' in all lower case.",
+    correctionMessage:
+        "Specify a Dart language version override with a comment like '// "
+        "@dart = 2.0'.",
+    hasPublishedDocs: true,
+    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_LOWER_CASE',
+  );
+
+  ///  No parameters.
+  static const WarningCode INVALID_LANGUAGE_VERSION_OVERRIDE_NUMBER =
+      WarningCode(
+    'INVALID_LANGUAGE_VERSION_OVERRIDE',
+    "The Dart language version override comment must be specified with a "
+        "version number, like '2.0', after the '=' character.",
+    correctionMessage:
+        "Specify a Dart language version override with a comment like '// "
+        "@dart = 2.0'.",
+    hasPublishedDocs: true,
+    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_NUMBER',
+  );
+
+  ///  No parameters.
+  static const WarningCode INVALID_LANGUAGE_VERSION_OVERRIDE_PREFIX =
+      WarningCode(
+    'INVALID_LANGUAGE_VERSION_OVERRIDE',
+    "The Dart language version override number can't be prefixed with a "
+        "letter.",
+    correctionMessage:
+        "Specify a Dart language version override with a comment like '// "
+        "@dart = 2.0'.",
+    hasPublishedDocs: true,
+    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_PREFIX',
+  );
+
+  ///  No parameters.
+  static const WarningCode
+      INVALID_LANGUAGE_VERSION_OVERRIDE_TRAILING_CHARACTERS = WarningCode(
+    'INVALID_LANGUAGE_VERSION_OVERRIDE',
+    "The Dart language version override comment can't be followed by any "
+        "non-whitespace characters.",
+    correctionMessage:
+        "Specify a Dart language version override with a comment like '// "
+        "@dart = 2.0'.",
+    hasPublishedDocs: true,
+    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_TRAILING_CHARACTERS',
+  );
+
+  ///  No parameters.
+  static const WarningCode INVALID_LANGUAGE_VERSION_OVERRIDE_TWO_SLASHES =
+      WarningCode(
+    'INVALID_LANGUAGE_VERSION_OVERRIDE',
+    "The Dart language version override comment must be specified with exactly "
+        "two slashes.",
+    correctionMessage:
+        "Specify a Dart language version override with a comment like '// "
+        "@dart = 2.0'.",
+    hasPublishedDocs: true,
+    uniqueName: 'INVALID_LANGUAGE_VERSION_OVERRIDE_TWO_SLASHES',
+  );
+
+  ///  This hint is generated anywhere where `@required` annotates a named
+  ///  parameter with a default value.
+  ///
+  ///  Parameters:
+  ///  0: the name of the member
+  static const WarningCode INVALID_REQUIRED_NAMED_PARAM = WarningCode(
+    'INVALID_REQUIRED_NAMED_PARAM',
+    "The type parameter '{0}' is annotated with @required but only named "
+        "parameters without a default value can be annotated with it.",
+    correctionMessage: "Remove @required.",
+  );
+
+  ///  This hint is generated anywhere where `@required` annotates an optional
+  ///  positional parameter.
+  ///
+  ///  Parameters:
+  ///  0: the name of the member
+  static const WarningCode INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM =
+      WarningCode(
+    'INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM',
+    "Incorrect use of the annotation @required on the optional positional "
+        "parameter '{0}'. Optional positional parameters cannot be required.",
+    correctionMessage: "Remove @required.",
+  );
+
+  ///  This hint is generated anywhere where `@required` annotates a non optional
+  ///  positional parameter.
+  ///
+  ///  Parameters:
+  ///  0: the name of the member
+  static const WarningCode INVALID_REQUIRED_POSITIONAL_PARAM = WarningCode(
+    'INVALID_REQUIRED_POSITIONAL_PARAM',
+    "Redundant use of the annotation @required on the required positional "
+        "parameter '{0}'.",
+    correctionMessage: "Remove @required.",
+  );
+
+  ///  This hint is generated anywhere where `@sealed` annotates something other
+  ///  than a class.
+  ///
+  ///  No parameters.
+  static const WarningCode INVALID_SEALED_ANNOTATION = WarningCode(
+    'INVALID_SEALED_ANNOTATION',
+    "The annotation '@sealed' can only be applied to classes.",
+    correctionMessage: "Try removing the '@sealed' annotation.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Parameters:
+  ///  0: the name of the member
+  static const WarningCode INVALID_USE_OF_INTERNAL_MEMBER = WarningCode(
+    'INVALID_USE_OF_INTERNAL_MEMBER',
+    "The member '{0}' can only be used within its package.",
+    hasPublishedDocs: true,
+  );
+
+  ///  This hint is generated anywhere where a member annotated with `@protected`
+  ///  is used outside of an instance member of a subclass.
+  ///
+  ///  Parameters:
+  ///  0: the name of the member
+  ///  1: the name of the defining class
+  static const WarningCode INVALID_USE_OF_PROTECTED_MEMBER = WarningCode(
+    'INVALID_USE_OF_PROTECTED_MEMBER',
+    "The member '{0}' can only be used within instance members of subclasses "
+        "of '{1}'.",
+  );
+
+  ///  Parameters:
+  ///  0: the name of the member
+  static const WarningCode INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER =
+      WarningCode(
+    'INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER',
+    "The member '{0}' can only be used for overriding.",
+    hasPublishedDocs: true,
+  );
+
+  ///  This hint is generated anywhere where a member annotated with
+  ///  `@visibleForTemplate` is used outside of a "template" Dart file.
+  ///
+  ///  Parameters:
+  ///  0: the name of the member
+  ///  1: the name of the defining class
+  static const WarningCode INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER =
+      WarningCode(
+    'INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER',
+    "The member '{0}' can only be used within '{1}' or a template library.",
+  );
+
+  ///  This hint is generated anywhere where a member annotated with
+  ///  `@visibleForTesting` is used outside the defining library, or a test.
+  ///
+  ///  Parameters:
+  ///  0: the name of the member
+  ///  1: the name of the defining class
+  static const WarningCode INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER =
+      WarningCode(
+    'INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER',
+    "The member '{0}' can only be used within '{1}' or a test.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Parameters:
+  ///  0: the name of the member
+  static const WarningCode MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_ONE =
+      WarningCode(
+    'MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN',
+    "Missing concrete implementation of '{0}'.",
+    correctionMessage: "Try overriding the missing member.",
+    hasPublishedDocs: true,
+    uniqueName: 'MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_ONE',
+  );
+
+  ///  Parameters:
+  ///  0: the name of the first member
+  ///  1: the name of the second member
+  ///  2: the number of additional missing members that aren't listed
+  static const WarningCode MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_THREE_PLUS =
+      WarningCode(
+    'MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN',
+    "Missing concrete implementations of '{0}', '{1}', and {2} more.",
+    correctionMessage: "Try overriding the missing members.",
+    hasPublishedDocs: true,
+    uniqueName: 'MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_THREE_PLUS',
+  );
+
+  ///  Parameters:
+  ///  0: the name of the first member
+  ///  1: the name of the second member
+  static const WarningCode MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_TWO =
+      WarningCode(
+    'MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN',
+    "Missing concrete implementations of '{0}' and '{1}'.",
+    correctionMessage: "Try overriding the missing members.",
+    hasPublishedDocs: true,
+    uniqueName: 'MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_TWO',
+  );
+
+  ///  Generate a hint for a constructor, function or method invocation where a
+  ///  required parameter is missing.
+  ///
+  ///  Parameters:
+  ///  0: the name of the parameter
+  static const WarningCode MISSING_REQUIRED_PARAM = WarningCode(
+    'MISSING_REQUIRED_PARAM',
+    "The parameter '{0}' is required.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Generate a hint for a constructor, function or method invocation where a
+  ///  required parameter is missing.
+  ///
+  ///  Parameters:
+  ///  0: the name of the parameter
+  ///  1: message details
+  static const WarningCode MISSING_REQUIRED_PARAM_WITH_DETAILS = WarningCode(
+    'MISSING_REQUIRED_PARAM',
+    "The parameter '{0}' is required. {1}.",
+    hasPublishedDocs: true,
+    uniqueName: 'MISSING_REQUIRED_PARAM_WITH_DETAILS',
+  );
+
+  ///  Parameters:
+  ///  0: the name of the declared return type
+  static const WarningCode MISSING_RETURN = WarningCode(
+    'MISSING_RETURN',
+    "This function has a return type of '{0}', but doesn't end with a return "
+        "statement.",
+    correctionMessage:
+        "Try adding a return statement, or changing the return type to 'void'.",
+    hasPublishedDocs: true,
+  );
+
+  ///  This is the new replacement for [HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR].
+  static const HintCode NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR =
+      HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR;
+
+  ///  No parameters.
+  static const WarningCode NULLABLE_TYPE_IN_CATCH_CLAUSE = WarningCode(
+    'NULLABLE_TYPE_IN_CATCH_CLAUSE',
+    "A potentially nullable type can't be used in an 'on' clause because it "
+        "isn't valid to throw a nullable expression.",
+    correctionMessage: "Try using a non-nullable type.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Parameters:
+  ///  0: the name of the method being invoked
+  ///  1: the type argument associated with the method
+  static const WarningCode NULL_ARGUMENT_TO_NON_NULL_TYPE = WarningCode(
+    'NULL_ARGUMENT_TO_NON_NULL_TYPE',
+    "'{0}' shouldn't be called with a null argument for the non-nullable type "
+        "argument '{1}'.",
+    correctionMessage: "Try adding a non-null argument.",
+    hasPublishedDocs: true,
+  );
+
+  ///  When the left operand of a binary expression uses '?.' operator, it can be
+  ///  `null`.
+  static const WarningCode NULL_AWARE_BEFORE_OPERATOR = WarningCode(
+    'NULL_AWARE_BEFORE_OPERATOR',
+    "The left operand uses '?.', so its value can be null.",
+  );
+
+  ///  A condition in a control flow statement could evaluate to `null` because it
+  ///  uses the null-aware '?.' operator.
+  static const WarningCode NULL_AWARE_IN_CONDITION = WarningCode(
+    'NULL_AWARE_IN_CONDITION',
+    "The value of the '?.' operator can be 'null', which isn't appropriate in "
+        "a condition.",
+    correctionMessage:
+        "Try replacing the '?.' with a '.', testing the left-hand side for "
+        "null if necessary.",
+  );
+
+  ///  A condition in operands of a logical operator could evaluate to `null`
+  ///  because it uses the null-aware '?.' operator.
+  static const WarningCode NULL_AWARE_IN_LOGICAL_OPERATOR = WarningCode(
+    'NULL_AWARE_IN_LOGICAL_OPERATOR',
+    "The value of the '?.' operator can be 'null', which isn't appropriate as "
+        "an operand of a logical operator.",
+  );
+
+  ///  This is the new replacement for [HintCode.OVERRIDE_ON_NON_OVERRIDING_FIELD].
+  static const HintCode OVERRIDE_ON_NON_OVERRIDING_FIELD =
+      HintCode.OVERRIDE_ON_NON_OVERRIDING_FIELD;
+
+  ///  It is not an error to call or tear-off a method, setter, or getter, or to
+  ///  read or write a field, on a receiver of static type `Never`.
+  ///  Implementations that provide feedback about dead or unreachable code are
+  ///  encouraged to indicate that any arguments to the invocation are
+  ///  unreachable.
+  ///
+  ///  It is not an error to apply an expression of type `Never` in the function
+  ///  position of a function call. Implementations that provide feedback about
+  ///  dead or unreachable code are encouraged to indicate that any arguments to
+  ///  the call are unreachable.
+  ///
+  ///  Parameters: none
+  static const WarningCode RECEIVER_OF_TYPE_NEVER = WarningCode(
+    'RECEIVER_OF_TYPE_NEVER',
+    "The receiver is of type 'Never', and will never complete with a value.",
+    correctionMessage:
+        "Try checking for throw expressions or type errors in the receiver",
+  );
+
+  ///  An error code indicating use of a removed lint rule.
+  ///
+  ///  Parameters:
+  ///  0: the rule name
+  ///  1: the SDK version in which the lint was removed
+  static const WarningCode REMOVED_LINT_USE = WarningCode(
+    'REMOVED_LINT_USE',
+    "'{0}' was removed in Dart '{1}'",
+    correctionMessage: "Remove the reference to '{0}'.",
+  );
+
+  ///  An error code indicating use of a removed lint rule.
+  ///
+  ///  Parameters:
+  ///  0: the rule name
+  ///  1: the SDK version in which the lint was removed
+  ///  2: the name of a replacing lint
+  static const WarningCode REPLACED_LINT_USE = WarningCode(
+    'REPLACED_LINT_USE',
+    "'{0}' was replaced by '{2}' in Dart '{1}'.",
+    correctionMessage: "Replace '{0}' with '{1}'.",
+  );
+
+  ///  Parameters:
+  ///  0: the name of the annotated function being invoked
+  ///  1: the name of the function containing the return
+  static const WarningCode RETURN_OF_DO_NOT_STORE = WarningCode(
+    'RETURN_OF_DO_NOT_STORE',
+    "'{0}' is annotated with 'doNotStore' and shouldn't be returned unless "
+        "'{1}' is also annotated.",
+    correctionMessage: "Annotate '{1}' with 'doNotStore'.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Parameters:
+  ///  0: the return type as declared in the return statement
+  ///  1: the expected return type as defined by the type of the Future
+  static const WarningCode RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR =
+      WarningCode(
+    'INVALID_RETURN_TYPE_FOR_CATCH_ERROR',
+    "A value of type '{0}' can't be returned by the 'onError' handler because "
+        "it must be assignable to '{1}'.",
+    hasPublishedDocs: true,
+    uniqueName: 'RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR',
+  );
+
+  ///  Parameters:
+  ///  0: the return type of the function
+  ///  1: the expected return type as defined by the type of the Future
+  static const WarningCode RETURN_TYPE_INVALID_FOR_CATCH_ERROR = WarningCode(
+    'INVALID_RETURN_TYPE_FOR_CATCH_ERROR',
+    "The return type '{0}' isn't assignable to '{1}', as required by "
+        "'Future.catchError'.",
+    hasPublishedDocs: true,
+    uniqueName: 'RETURN_TYPE_INVALID_FOR_CATCH_ERROR',
+  );
+
+  ///  Parameters:
+  ///  0: the name of the class
+  static const WarningCode SDK_VERSION_ASYNC_EXPORTED_FROM_CORE = WarningCode(
+    'SDK_VERSION_ASYNC_EXPORTED_FROM_CORE',
+    "The class '{0}' wasn't exported from 'dart:core' until version 2.1, but "
+        "this code is required to be able to run on earlier versions.",
+    correctionMessage:
+        "Try either importing 'dart:async' or updating the SDK constraints.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  static const WarningCode SDK_VERSION_AS_EXPRESSION_IN_CONST_CONTEXT =
+      WarningCode(
+    'SDK_VERSION_AS_EXPRESSION_IN_CONST_CONTEXT',
+    "The use of an as expression in a constant expression wasn't supported "
+        "until version 2.3.2, but this code is required to be able to run on "
+        "earlier versions.",
+    correctionMessage: "Try updating the SDK constraints.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Parameters:
+  ///  0: the name of the operator
+  static const WarningCode SDK_VERSION_BOOL_OPERATOR_IN_CONST_CONTEXT =
+      WarningCode(
+    'SDK_VERSION_BOOL_OPERATOR_IN_CONST_CONTEXT',
+    "The use of the operator '{0}' for 'bool' operands in a constant context "
+        "wasn't supported until version 2.3.2, but this code is required to be "
+        "able to run on earlier versions.",
+    correctionMessage: "Try updating the SDK constraints.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  ///
+  ///  There is also a [ParserError.EXPERIMENT_NOT_ENABLED] code which catches
+  ///  some cases of constructor tearoff features (like `List<int>.filled;`).
+  ///  Other constructor tearoff cases are not realized until resolution
+  ///  (like `List.filled;`).
+  static const WarningCode SDK_VERSION_CONSTRUCTOR_TEAROFFS = WarningCode(
+    'SDK_VERSION_CONSTRUCTOR_TEAROFFS',
+    "Tearing off a constructor requires the 'constructor-tearoffs' language "
+        "feature.",
+    correctionMessage:
+        "Try updating your pubspec.yaml to set the minimum SDK constraint to "
+        "2.15 or higher, and running 'pub get'.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  static const WarningCode SDK_VERSION_EQ_EQ_OPERATOR_IN_CONST_CONTEXT =
+      WarningCode(
+    'SDK_VERSION_EQ_EQ_OPERATOR_IN_CONST_CONTEXT',
+    "Using the operator '==' for non-primitive types wasn't supported until "
+        "version 2.3.2, but this code is required to be able to run on earlier "
+        "versions.",
+    correctionMessage: "Try updating the SDK constraints.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  static const WarningCode SDK_VERSION_EXTENSION_METHODS = WarningCode(
+    'SDK_VERSION_EXTENSION_METHODS',
+    "Extension methods weren't supported until version 2.6.0, but this code is "
+        "required to be able to run on earlier versions.",
+    correctionMessage: "Try updating the SDK constraints.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  static const WarningCode SDK_VERSION_GT_GT_GT_OPERATOR = WarningCode(
+    'SDK_VERSION_GT_GT_GT_OPERATOR',
+    "The operator '>>>' wasn't supported until version 2.14.0, but this code "
+        "is required to be able to run on earlier versions.",
+    correctionMessage: "Try updating the SDK constraints.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  static const WarningCode SDK_VERSION_IS_EXPRESSION_IN_CONST_CONTEXT =
+      WarningCode(
+    'SDK_VERSION_IS_EXPRESSION_IN_CONST_CONTEXT',
+    "The use of an is expression in a constant context wasn't supported until "
+        "version 2.3.2, but this code is required to be able to run on earlier "
+        "versions.",
+    correctionMessage: "Try updating the SDK constraints.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  static const WarningCode SDK_VERSION_NEVER = WarningCode(
+    'SDK_VERSION_NEVER',
+    "The type 'Never' wasn't supported until version 2.12.0, but this code is "
+        "required to be able to run on earlier versions.",
+    correctionMessage: "Try updating the SDK constraints.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  static const WarningCode SDK_VERSION_SET_LITERAL = WarningCode(
+    'SDK_VERSION_SET_LITERAL',
+    "Set literals weren't supported until version 2.2, but this code is "
+        "required to be able to run on earlier versions.",
+    correctionMessage: "Try updating the SDK constraints.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  static const WarningCode SDK_VERSION_UI_AS_CODE = WarningCode(
+    'SDK_VERSION_UI_AS_CODE',
+    "The for, if, and spread elements weren't supported until version 2.3.0, "
+        "but this code is required to be able to run on earlier versions.",
+    correctionMessage: "Try updating the SDK constraints.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  static const WarningCode SDK_VERSION_UI_AS_CODE_IN_CONST_CONTEXT =
+      WarningCode(
+    'SDK_VERSION_UI_AS_CODE_IN_CONST_CONTEXT',
+    "The if and spread elements weren't supported in constant expressions "
+        "until version 2.5.0, but this code is required to be able to run on "
+        "earlier versions.",
+    correctionMessage: "Try updating the SDK constraints.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Parameters:
+  ///  0: the unicode sequence of the code point.
+  static const WarningCode TEXT_DIRECTION_CODE_POINT_IN_COMMENT = WarningCode(
+    'TEXT_DIRECTION_CODE_POINT_IN_COMMENT',
+    "The Unicode code point 'U+{0}' changes the appearance of text from how "
+        "it's interpreted by the compiler.",
+    correctionMessage:
+        "Try removing the code point or using the Unicode escape sequence "
+        "'\\u{0}'.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Parameters:
+  ///  0: the unicode sequence of the code point.
+  static const WarningCode TEXT_DIRECTION_CODE_POINT_IN_LITERAL = WarningCode(
+    'TEXT_DIRECTION_CODE_POINT_IN_LITERAL',
+    "The Unicode code point 'U+{0}' changes the appearance of text from how "
+        "it's interpreted by the compiler.",
+    correctionMessage:
+        "Try removing the code point or using the Unicode escape sequence "
+        "'\\u{0}'.",
+    hasPublishedDocs: true,
+  );
+
+  ///  No parameters.
+  static const WarningCode TYPE_CHECK_IS_NOT_NULL = WarningCode(
+    'TYPE_CHECK_WITH_NULL',
+    "Tests for non-null should be done with '!= null'.",
+    correctionMessage: "Try replacing the 'is! Null' check with '!= null'.",
+    hasPublishedDocs: true,
+    uniqueName: 'TYPE_CHECK_IS_NOT_NULL',
+  );
+
+  ///  No parameters.
+  static const WarningCode TYPE_CHECK_IS_NULL = WarningCode(
+    'TYPE_CHECK_WITH_NULL',
+    "Tests for null should be done with '== null'.",
+    correctionMessage: "Try replacing the 'is Null' check with '== null'.",
+    hasPublishedDocs: true,
+    uniqueName: 'TYPE_CHECK_IS_NULL',
+  );
+
+  ///  Parameters:
+  ///  0: the name of the library being imported
+  ///  1: the name in the hide clause that isn't defined in the library
+  static const WarningCode UNDEFINED_HIDDEN_NAME = WarningCode(
+    'UNDEFINED_HIDDEN_NAME',
+    "The library '{0}' doesn't export a member with the hidden name '{1}'.",
+    correctionMessage: "Try removing the name from the list of hidden members.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Parameters:
+  ///  0: the name of the library being imported
+  ///  1: the name in the show clause that isn't defined in the library
+  static const WarningCode UNDEFINED_SHOWN_NAME = WarningCode(
+    'UNDEFINED_SHOWN_NAME',
+    "The library '{0}' doesn't export a member with the shown name '{1}'.",
+    correctionMessage: "Try removing the name from the list of shown members.",
+    hasPublishedDocs: true,
+  );
+
+  ///  This is the new replacement for [HintCode.UNNECESSARY_CAST].
+  static const HintCode UNNECESSARY_CAST = HintCode.UNNECESSARY_CAST;
+
+  ///  No parameters.
+  static const WarningCode UNNECESSARY_CAST_PATTERN = WarningCode(
+    'UNNECESSARY_CAST_PATTERN',
+    "Unnecessary cast pattern.",
+    correctionMessage: "Try removing the cast pattern.",
+  );
+
+  ///  This is the new replacement for [HintCode.UNNECESSARY_FINAL].
+  static const HintCode UNNECESSARY_FINAL = HintCode.UNNECESSARY_FINAL;
+
+  ///  This is the new replacement for [HintCode.UNNECESSARY_TYPE_CHECK_FALSE].
+  static const HintCode UNNECESSARY_TYPE_CHECK_FALSE =
+      HintCode.UNNECESSARY_TYPE_CHECK_FALSE;
+
+  ///  This is the new replacement for [HintCode.UNNECESSARY_TYPE_CHECK_TRUE].
+  static const HintCode UNNECESSARY_TYPE_CHECK_TRUE =
+      HintCode.UNNECESSARY_TYPE_CHECK_TRUE;
+
+  ///  No parameters.
+  static const WarningCode UNNECESSARY_WILDCARD_PATTERN = WarningCode(
+    'UNNECESSARY_WILDCARD_PATTERN',
+    "Unnecessary wildcard pattern.",
+    correctionMessage: "Try removing the wildcard pattern.",
+  );
+
+  ///  Parameters:
+  ///  0: the name of the exception variable
+  static const WarningCode UNUSED_CATCH_CLAUSE = WarningCode(
+    'UNUSED_CATCH_CLAUSE',
+    "The exception variable '{0}' isn't used, so the 'catch' clause can be "
+        "removed.",
+    correctionMessage: "Try removing the catch clause.",
+    hasPublishedDocs: true,
+  );
+
+  ///  Parameters:
+  ///  0: the name of the stack trace variable
+  static const WarningCode UNUSED_CATCH_STACK = WarningCode(
+    'UNUSED_CATCH_STACK',
+    "The stack trace variable '{0}' isn't used and can be removed.",
+    correctionMessage: "Try removing the stack trace variable, or using it.",
+    hasPublishedDocs: true,
+  );
+
+  ///  This is the new replacement for [HintCode.UNUSED_ELEMENT].
+  static const HintCode UNUSED_ELEMENT = HintCode.UNUSED_ELEMENT;
+
+  ///  This is the new replacement for [HintCode.UNUSED_ELEMENT_PARAMETER].
+  static const HintCode UNUSED_ELEMENT_PARAMETER =
+      HintCode.UNUSED_ELEMENT_PARAMETER;
+
+  ///  This is the new replacement for [HintCode.UNUSED_FIELD].
+  static const HintCode UNUSED_FIELD = HintCode.UNUSED_FIELD;
+
+  ///  This is the new replacement for [HintCode.UNUSED_IMPORT].
+  static const HintCode UNUSED_IMPORT = HintCode.UNUSED_IMPORT;
+
+  ///  This is the new replacement for [HintCode.UNUSED_LOCAL_VARIABLE].
+  static const HintCode UNUSED_LOCAL_VARIABLE = HintCode.UNUSED_LOCAL_VARIABLE;
+
+  /// Initialize a newly created error code to have the given [name].
+  const WarningCode(
+    String name,
+    String problemMessage, {
+    super.correctionMessage,
+    super.hasPublishedDocs = false,
+    super.isUnresolvedIdentifier = false,
+    String? uniqueName,
+  }) : super(
+          name: name,
+          problemMessage: problemMessage,
+          uniqueName: 'WarningCode.${uniqueName ?? name}',
+        );
+
+  @override
+  ErrorSeverity get errorSeverity => ErrorSeverity.WARNING;
+
+  @override
+  ErrorType get type => ErrorType.STATIC_WARNING;
+}
diff --git a/analyzer/lib/src/error/correct_override.dart b/analyzer/lib/src/error/correct_override.dart
index 5c38438..32d96e1 100644
--- a/analyzer/lib/src/error/correct_override.dart
+++ b/analyzer/lib/src/error/correct_override.dart
@@ -51,16 +51,23 @@
     required ExecutableElement superMember,
     required ErrorReporter errorReporter,
     required SyntacticEntity errorNode,
-    ErrorCode? errorCode,
+    required ErrorCode errorCode,
   }) {
     var isCorrect = isCorrectOverrideOf(superMember: superMember);
     if (!isCorrect) {
+      var member = _thisMember;
+      var memberName = member.name;
+      if (member is PropertyAccessorElement && member.isSetter) {
+        memberName = memberName.substring(0, memberName.length - 1);
+      }
       errorReporter.reportError(_diagnosticFactory.invalidOverride(
-          errorReporter.source,
-          errorCode,
-          errorNode,
-          _thisMember,
-          superMember));
+        errorReporter.source,
+        errorCode,
+        errorNode,
+        _thisMember,
+        superMember,
+        memberName,
+      ));
     }
   }
 
diff --git a/analyzer/lib/src/error/dead_code_verifier.dart b/analyzer/lib/src/error/dead_code_verifier.dart
index 19c161b..516ab84 100644
--- a/analyzer/lib/src/error/dead_code_verifier.dart
+++ b/analyzer/lib/src/error/dead_code_verifier.dart
@@ -67,7 +67,7 @@
     final importElement = node.element;
     if (importElement != null) {
       // The element is null when the URI is invalid, but not when the URI is
-      // valid but refers to a non-existent file.
+      // valid but refers to a nonexistent file.
       LibraryElement? library = importElement.importedLibrary;
       if (library != null && !library.isSynthetic) {
         for (Combinator combinator in node.combinators) {
@@ -105,10 +105,10 @@
     ErrorCode hintCode;
     if (combinator is HideCombinator) {
       names = combinator.hiddenNames;
-      hintCode = HintCode.UNDEFINED_HIDDEN_NAME;
+      hintCode = WarningCode.UNDEFINED_HIDDEN_NAME;
     } else {
       names = (combinator as ShowCombinator).shownNames;
-      hintCode = HintCode.UNDEFINED_SHOWN_NAME;
+      hintCode = WarningCode.UNDEFINED_SHOWN_NAME;
     }
     for (SimpleIdentifier name in names) {
       String nameStr = name.name;
@@ -488,6 +488,12 @@
         return;
       }
 
+      if (node is SwitchMember && node == firstDeadNode) {
+        _errorReporter.reportErrorForToken(HintCode.DEAD_CODE, node.keyword);
+        _firstDeadNode = null;
+        return;
+      }
+
       var parent = firstDeadNode.parent;
       if (parent is Assertion && identical(firstDeadNode, parent.message)) {
         // Don't report "dead code" for the message part of an assert statement,
@@ -496,7 +502,7 @@
       } else {
         var offset = firstDeadNode.offset;
         // We know that [node] is the first dead node, or contains it.
-        // So, technically the code code interval ends at the end of [node].
+        // So, technically the code interval ends at the end of [node].
         // But we trim it to the last statement for presentation purposes.
         if (node != firstDeadNode) {
           if (node is FunctionDeclaration) {
@@ -547,6 +553,8 @@
           if (grandParent is ForStatement) {
             _reportForUpdaters(grandParent);
           }
+        } else if (parent is LogicalOrPattern && node == parent.rightOperand) {
+          offset = parent.operator.offset;
         }
 
         var length = node.end - offset;
@@ -622,7 +630,7 @@
     if (flowAnalysis == null) return;
     flowAnalysis.checkUnreachableNode(node);
 
-    // If the first dead node is not `null`, even if this new new node is
+    // If the first dead node is not `null`, even if this new node is
     // unreachable, we can ignore it as it is part of the same dead code
     // range anyway.
     if (_firstDeadNode != null) return;
diff --git a/analyzer/lib/src/error/error_code_values.g.dart b/analyzer/lib/src/error/error_code_values.g.dart
index dc7bf91..2806a91 100644
--- a/analyzer/lib/src/error/error_code_values.g.dart
+++ b/analyzer/lib/src/error/error_code_values.g.dart
@@ -29,6 +29,8 @@
   AnalysisOptionsWarningCode.INCLUDE_FILE_NOT_FOUND,
   AnalysisOptionsWarningCode.INVALID_OPTION,
   AnalysisOptionsWarningCode.INVALID_SECTION_FORMAT,
+  AnalysisOptionsWarningCode.MULTIPLE_PLUGINS,
+  AnalysisOptionsWarningCode.RECURSIVE_INCLUDE_FILE,
   AnalysisOptionsWarningCode.REMOVED_LINT,
   AnalysisOptionsWarningCode.REPLACED_LINT,
   AnalysisOptionsWarningCode.SPEC_MODE_REMOVED,
@@ -57,6 +59,8 @@
   CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT,
   CompileTimeErrorCode.AWAIT_IN_LATE_LOCAL_VARIABLE_INITIALIZER,
   CompileTimeErrorCode.AWAIT_IN_WRONG_CONTEXT,
+  CompileTimeErrorCode.BASE_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY,
+  CompileTimeErrorCode.BASE_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY,
   CompileTimeErrorCode.BODY_MIGHT_COMPLETE_NORMALLY,
   CompileTimeErrorCode.BREAK_LABEL_ON_SWITCH_MEMBER,
   CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_EXTENSION_NAME,
@@ -72,6 +76,7 @@
   CompileTimeErrorCode.CLASS_INSTANTIATION_ACCESS_TO_INSTANCE_MEMBER,
   CompileTimeErrorCode.CLASS_INSTANTIATION_ACCESS_TO_STATIC_MEMBER,
   CompileTimeErrorCode.CLASS_INSTANTIATION_ACCESS_TO_UNKNOWN_MEMBER,
+  CompileTimeErrorCode.CLASS_USED_AS_MIXIN,
   CompileTimeErrorCode.CONCRETE_CLASS_HAS_ENUM_SUPERINTERFACE,
   CompileTimeErrorCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER,
   CompileTimeErrorCode.CONFLICTING_CONSTRUCTOR_AND_STATIC_FIELD,
@@ -126,7 +131,7 @@
   CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
   CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR,
   CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT,
-  CompileTimeErrorCode.CONTINUE_LABEL_ON_SWITCH,
+  CompileTimeErrorCode.CONTINUE_LABEL_INVALID,
   CompileTimeErrorCode.COULD_NOT_INFER,
   CompileTimeErrorCode.DEFAULT_LIST_CONSTRUCTOR,
   CompileTimeErrorCode.DEFAULT_VALUE_IN_REDIRECTING_FACTORY_CONSTRUCTOR,
@@ -142,7 +147,9 @@
   CompileTimeErrorCode.DUPLICATE_FIELD_NAME,
   CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT,
   CompileTimeErrorCode.DUPLICATE_PART,
-  CompileTimeErrorCode.DUPLICATE_RECORD_PATTERN_FIELD,
+  CompileTimeErrorCode.DUPLICATE_PATTERN_ASSIGNMENT_VARIABLE,
+  CompileTimeErrorCode.DUPLICATE_PATTERN_FIELD,
+  CompileTimeErrorCode.DUPLICATE_REST_ELEMENT_IN_PATTERN,
   CompileTimeErrorCode.DUPLICATE_VARIABLE_PATTERN,
   CompileTimeErrorCode.ENUM_CONSTANT_SAME_NAME_AS_ENCLOSING,
   CompileTimeErrorCode.ENUM_CONSTANT_WITH_NON_CONST_CONSTRUCTOR,
@@ -152,6 +159,7 @@
   CompileTimeErrorCode.ENUM_WITH_NAME_VALUES,
   CompileTimeErrorCode.EQUAL_ELEMENTS_IN_CONST_SET,
   CompileTimeErrorCode.EQUAL_KEYS_IN_CONST_MAP,
+  CompileTimeErrorCode.EQUAL_KEYS_IN_MAP_PATTERN,
   CompileTimeErrorCode.EXPECTED_ONE_LIST_PATTERN_TYPE_ARGUMENTS,
   CompileTimeErrorCode.EXPECTED_ONE_LIST_TYPE_ARGUMENTS,
   CompileTimeErrorCode.EXPECTED_ONE_SET_TYPE_ARGUMENTS,
@@ -185,7 +193,11 @@
   CompileTimeErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR,
   CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR,
   CompileTimeErrorCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE,
+  CompileTimeErrorCode.FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY,
+  CompileTimeErrorCode.FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY,
   CompileTimeErrorCode.FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR,
+  CompileTimeErrorCode.FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY,
+  CompileTimeErrorCode.FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY,
   CompileTimeErrorCode.FINAL_NOT_INITIALIZED,
   CompileTimeErrorCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1,
   CompileTimeErrorCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2,
@@ -222,6 +234,8 @@
   CompileTimeErrorCode.INCONSISTENT_INHERITANCE,
   CompileTimeErrorCode.INCONSISTENT_INHERITANCE_GETTER_AND_METHOD,
   CompileTimeErrorCode.INCONSISTENT_LANGUAGE_VERSION_OVERRIDE,
+  CompileTimeErrorCode.INCONSISTENT_PATTERN_VARIABLE_LOGICAL_OR,
+  CompileTimeErrorCode.INCONSISTENT_PATTERN_VARIABLE_SHARED_CASE_SCOPE,
   CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTENT_FIELD,
   CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD,
   CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD,
@@ -234,6 +248,8 @@
   CompileTimeErrorCode.INSTANTIATE_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
   CompileTimeErrorCode.INTEGER_LITERAL_IMPRECISE_AS_DOUBLE,
   CompileTimeErrorCode.INTEGER_LITERAL_OUT_OF_RANGE,
+  CompileTimeErrorCode.INTERFACE_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY,
+  CompileTimeErrorCode.INTERFACE_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY,
   CompileTimeErrorCode.INVALID_ANNOTATION,
   CompileTimeErrorCode.INVALID_ANNOTATION_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY,
   CompileTimeErrorCode.INVALID_ANNOTATION_FROM_DEFERRED_LIBRARY,
@@ -253,10 +269,12 @@
   CompileTimeErrorCode.INVALID_FIELD_NAME_POSITIONAL,
   CompileTimeErrorCode.INVALID_FIELD_NAME_PRIVATE,
   CompileTimeErrorCode.INVALID_IMPLEMENTATION_OVERRIDE,
+  CompileTimeErrorCode.INVALID_IMPLEMENTATION_OVERRIDE_SETTER,
   CompileTimeErrorCode.INVALID_INLINE_FUNCTION_TYPE,
   CompileTimeErrorCode.INVALID_MODIFIER_ON_CONSTRUCTOR,
   CompileTimeErrorCode.INVALID_MODIFIER_ON_SETTER,
   CompileTimeErrorCode.INVALID_OVERRIDE,
+  CompileTimeErrorCode.INVALID_OVERRIDE_SETTER,
   CompileTimeErrorCode.INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR,
   CompileTimeErrorCode.INVALID_REFERENCE_TO_THIS,
   CompileTimeErrorCode.INVALID_SUPER_FORMAL_PARAMETER_LOCATION,
@@ -296,6 +314,7 @@
   CompileTimeErrorCode.MIXIN_APPLICATION_CONCRETE_SUPER_INVOKED_MEMBER_TYPE,
   CompileTimeErrorCode.MIXIN_APPLICATION_NOT_IMPLEMENTED_INTERFACE,
   CompileTimeErrorCode.MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_MEMBER,
+  CompileTimeErrorCode.MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_SETTER,
   CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR,
   CompileTimeErrorCode.MIXIN_DEFERRED_CLASS,
   CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT,
@@ -332,11 +351,14 @@
   CompileTimeErrorCode.NON_CONSTANT_MAP_ELEMENT,
   CompileTimeErrorCode.NON_CONSTANT_MAP_KEY,
   CompileTimeErrorCode.NON_CONSTANT_MAP_KEY_FROM_DEFERRED_LIBRARY,
+  CompileTimeErrorCode.NON_CONSTANT_MAP_PATTERN_KEY,
   CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE,
   CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE_FROM_DEFERRED_LIBRARY,
+  CompileTimeErrorCode.NON_CONSTANT_RELATIONAL_PATTERN_EXPRESSION,
   CompileTimeErrorCode.NON_CONSTANT_SET_ELEMENT,
   CompileTimeErrorCode.NON_CONST_GENERATIVE_ENUM_CONSTRUCTOR,
   CompileTimeErrorCode.NON_CONST_MAP_AS_EXPRESSION_STATEMENT,
+  CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH,
   CompileTimeErrorCode.NON_FINAL_FIELD_IN_ENUM,
   CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR,
   CompileTimeErrorCode.NON_GENERATIVE_IMPLICIT_CONSTRUCTOR,
@@ -348,7 +370,6 @@
   CompileTimeErrorCode.NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE,
   CompileTimeErrorCode.NOT_A_TYPE,
   CompileTimeErrorCode.NOT_BINARY_OPERATOR,
-  CompileTimeErrorCode.NOT_CONSISTENT_VARIABLE_PATTERN,
   CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS_NAME_PLURAL,
   CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS_NAME_SINGULAR,
   CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS_PLURAL,
@@ -379,6 +400,7 @@
   CompileTimeErrorCode.PATTERN_ASSIGNMENT_NOT_LOCAL_VARIABLE,
   CompileTimeErrorCode.PATTERN_CONSTANT_FROM_DEFERRED_LIBRARY,
   CompileTimeErrorCode.PATTERN_TYPE_MISMATCH_IN_IRREFUTABLE_CONTEXT,
+  CompileTimeErrorCode.PATTERN_VARIABLE_ASSIGNMENT_INSIDE_GUARD,
   CompileTimeErrorCode
       .POSITIONAL_SUPER_FORMAL_PARAMETER_WITH_POSITIONAL_ARGUMENT,
   CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER,
@@ -409,6 +431,7 @@
   CompileTimeErrorCode.REFUTABLE_PATTERN_IN_IRREFUTABLE_CONTEXT,
   CompileTimeErrorCode
       .RELATIONAL_PATTERN_OPERATOR_RETURN_TYPE_NOT_ASSIGNABLE_TO_BOOL,
+  CompileTimeErrorCode.REST_ELEMENT_NOT_LAST_IN_MAP_PATTERN,
   CompileTimeErrorCode.REST_ELEMENT_WITH_SUBPATTERN_IN_MAP_PATTERN,
   CompileTimeErrorCode.RETHROW_OUTSIDE_CATCH,
   CompileTimeErrorCode.RETURN_IN_GENERATIVE_CONSTRUCTOR,
@@ -553,10 +576,7 @@
   FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS,
   FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_IMPLEMENTS,
   FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_WITH,
-  HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER,
   HintCode.ASSIGNMENT_OF_DO_NOT_STORE,
-  HintCode.BODY_MIGHT_COMPLETE_NORMALLY_CATCH_ERROR,
-  HintCode.BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE,
   HintCode.CAN_BE_NULL_AFTER_NULL_AWARE,
   HintCode.CAST_FROM_NULLABLE_ALWAYS_FAILS,
   HintCode.CAST_FROM_NULL_ALWAYS_FAILS,
@@ -565,114 +585,50 @@
   HintCode.DEAD_CODE_ON_CATCH_SUBTYPE,
   HintCode.DEPRECATED_COLON_FOR_DEFAULT_VALUE,
   HintCode.DEPRECATED_EXPORT_USE,
-  HintCode.DEPRECATED_EXTENDS_FUNCTION,
-  HintCode.DEPRECATED_IMPLEMENTS_FUNCTION,
   HintCode.DEPRECATED_MEMBER_USE,
   HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE,
   HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE,
   HintCode.DEPRECATED_MEMBER_USE_WITH_MESSAGE,
-  HintCode.DEPRECATED_MIXIN_FUNCTION,
-  HintCode.DEPRECATED_NEW_IN_COMMENT_REFERENCE,
   HintCode.DIVISION_OPTIMIZATION,
-  HintCode.DUPLICATE_EXPORT,
-  HintCode.DUPLICATE_HIDDEN_NAME,
-  HintCode.DUPLICATE_IGNORE,
-  HintCode.DUPLICATE_IMPORT,
-  HintCode.DUPLICATE_SHOWN_NAME,
-  HintCode.EQUAL_ELEMENTS_IN_SET,
-  HintCode.EQUAL_KEYS_IN_MAP,
   HintCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE,
   HintCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE,
   HintCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION,
   HintCode.IMPORT_OF_LEGACY_LIBRARY_INTO_NULL_SAFE,
-  HintCode.INFERENCE_FAILURE_ON_COLLECTION_LITERAL,
-  HintCode.INFERENCE_FAILURE_ON_FUNCTION_INVOCATION,
-  HintCode.INFERENCE_FAILURE_ON_FUNCTION_RETURN_TYPE,
-  HintCode.INFERENCE_FAILURE_ON_GENERIC_INVOCATION,
-  HintCode.INFERENCE_FAILURE_ON_INSTANCE_CREATION,
-  HintCode.INFERENCE_FAILURE_ON_UNINITIALIZED_VARIABLE,
-  HintCode.INFERENCE_FAILURE_ON_UNTYPED_PARAMETER,
-  HintCode.INVALID_ANNOTATION_TARGET,
-  HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT,
-  HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT_INDIRECTLY,
-  HintCode.INVALID_FACTORY_ANNOTATION,
-  HintCode.INVALID_FACTORY_METHOD_DECL,
-  HintCode.INVALID_FACTORY_METHOD_IMPL,
   HintCode.INVALID_IMMUTABLE_ANNOTATION,
   HintCode.INVALID_INTERNAL_ANNOTATION,
-  HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_AT_SIGN,
-  HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_EQUALS,
-  HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_GREATER,
-  HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_LOCATION,
-  HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_LOWER_CASE,
-  HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_NUMBER,
-  HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_PREFIX,
-  HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_TRAILING_CHARACTERS,
-  HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_TWO_SLASHES,
   HintCode.INVALID_LITERAL_ANNOTATION,
   HintCode.INVALID_NON_VIRTUAL_ANNOTATION,
   HintCode.INVALID_OVERRIDE_OF_NON_VIRTUAL_MEMBER,
-  HintCode.INVALID_REQUIRED_NAMED_PARAM,
-  HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM,
-  HintCode.INVALID_REQUIRED_POSITIONAL_PARAM,
-  HintCode.INVALID_SEALED_ANNOTATION,
-  HintCode.INVALID_USE_OF_INTERNAL_MEMBER,
-  HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
-  HintCode.INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER,
-  HintCode.INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER,
-  HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER,
   HintCode.INVALID_VISIBILITY_ANNOTATION,
   HintCode.INVALID_VISIBLE_FOR_OVERRIDING_ANNOTATION,
-  HintCode.MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_ONE,
-  HintCode.MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_THREE_PLUS,
-  HintCode.MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_TWO,
-  HintCode.MISSING_REQUIRED_PARAM,
-  HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS,
-  HintCode.MISSING_RETURN,
   HintCode.MIXIN_ON_SEALED_CLASS,
   HintCode.MUST_BE_IMMUTABLE,
   HintCode.MUST_CALL_SUPER,
   HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR,
   HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR_USING_NEW,
-  HintCode.NULLABLE_TYPE_IN_CATCH_CLAUSE,
-  HintCode.NULL_ARGUMENT_TO_NON_NULL_TYPE,
-  HintCode.NULL_AWARE_BEFORE_OPERATOR,
-  HintCode.NULL_AWARE_IN_CONDITION,
-  HintCode.NULL_AWARE_IN_LOGICAL_OPERATOR,
   HintCode.NULL_CHECK_ALWAYS_FAILS,
   HintCode.OVERRIDE_ON_NON_OVERRIDING_FIELD,
   HintCode.OVERRIDE_ON_NON_OVERRIDING_GETTER,
   HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD,
   HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER,
-  HintCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT,
-  HintCode.RECEIVER_OF_TYPE_NEVER,
-  HintCode.REMOVED_LINT_USE,
-  HintCode.REPLACED_LINT_USE,
-  HintCode.RETURN_OF_DO_NOT_STORE,
-  HintCode.RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR,
-  HintCode.RETURN_TYPE_INVALID_FOR_CATCH_ERROR,
   HintCode.STRICT_RAW_TYPE,
   HintCode.SUBTYPE_OF_SEALED_CLASS,
-  HintCode.TEXT_DIRECTION_CODE_POINT_IN_COMMENT,
-  HintCode.TEXT_DIRECTION_CODE_POINT_IN_LITERAL,
-  HintCode.TYPE_CHECK_IS_NOT_NULL,
-  HintCode.TYPE_CHECK_IS_NULL,
-  HintCode.UNDEFINED_HIDDEN_NAME,
   HintCode.UNDEFINED_REFERENCED_PARAMETER,
-  HintCode.UNDEFINED_SHOWN_NAME,
   HintCode.UNIGNORABLE_IGNORE,
   HintCode.UNNECESSARY_CAST,
   HintCode.UNNECESSARY_FINAL,
   HintCode.UNNECESSARY_IGNORE,
   HintCode.UNNECESSARY_IMPORT,
+  HintCode.UNNECESSARY_NAN_COMPARISON_FALSE,
+  HintCode.UNNECESSARY_NAN_COMPARISON_TRUE,
   HintCode.UNNECESSARY_NO_SUCH_METHOD,
   HintCode.UNNECESSARY_NULL_COMPARISON_FALSE,
   HintCode.UNNECESSARY_NULL_COMPARISON_TRUE,
   HintCode.UNNECESSARY_QUESTION_MARK,
+  HintCode.UNNECESSARY_SET_LITERAL,
   HintCode.UNNECESSARY_TYPE_CHECK_FALSE,
   HintCode.UNNECESSARY_TYPE_CHECK_TRUE,
-  HintCode.UNUSED_CATCH_CLAUSE,
-  HintCode.UNUSED_CATCH_STACK,
+  HintCode.UNREACHABLE_SWITCH_CASE,
   HintCode.UNUSED_ELEMENT,
   HintCode.UNUSED_ELEMENT_PARAMETER,
   HintCode.UNUSED_FIELD,
@@ -710,6 +666,7 @@
   ParserErrorCode.ABSTRACT_TOP_LEVEL_VARIABLE,
   ParserErrorCode.ABSTRACT_TYPEDEF,
   ParserErrorCode.ANNOTATION_ON_TYPE_ARGUMENT,
+  ParserErrorCode.ANNOTATION_SPACE_BEFORE_PARENTHESIS,
   ParserErrorCode.ANNOTATION_WITH_TYPE_ARGUMENTS,
   ParserErrorCode.ANNOTATION_WITH_TYPE_ARGUMENTS_UNINSTANTIATED,
   ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER,
@@ -809,6 +766,11 @@
   ParserErrorCode.INVALID_AWAIT_IN_FOR,
   ParserErrorCode.INVALID_CODE_POINT,
   ParserErrorCode.INVALID_COMMENT_REFERENCE,
+  ParserErrorCode.INVALID_CONSTANT_PATTERN_DUPLICATE_CONST,
+  ParserErrorCode.INVALID_CONSTANT_PATTERN_EMPTY_RECORD_LITERAL,
+  ParserErrorCode.INVALID_CONSTANT_PATTERN_GENERIC,
+  ParserErrorCode.INVALID_CONSTANT_PATTERN_NEGATION,
+  ParserErrorCode.INVALID_CONSTANT_PATTERN_UNARY,
   ParserErrorCode.INVALID_CONSTRUCTOR_NAME,
   ParserErrorCode.INVALID_GENERIC_FUNCTION_TYPE,
   ParserErrorCode.INVALID_HEX_ESCAPE,
@@ -950,21 +912,95 @@
   StaticWarningCode.INVALID_NULL_AWARE_OPERATOR,
   StaticWarningCode.INVALID_NULL_AWARE_OPERATOR_AFTER_SHORT_CIRCUIT,
   StaticWarningCode.MISSING_ENUM_CONSTANT_IN_SWITCH,
-  StaticWarningCode.SDK_VERSION_ASYNC_EXPORTED_FROM_CORE,
-  StaticWarningCode.SDK_VERSION_AS_EXPRESSION_IN_CONST_CONTEXT,
-  StaticWarningCode.SDK_VERSION_BOOL_OPERATOR_IN_CONST_CONTEXT,
-  StaticWarningCode.SDK_VERSION_CONSTRUCTOR_TEAROFFS,
-  StaticWarningCode.SDK_VERSION_EQ_EQ_OPERATOR_IN_CONST_CONTEXT,
-  StaticWarningCode.SDK_VERSION_EXTENSION_METHODS,
-  StaticWarningCode.SDK_VERSION_GT_GT_GT_OPERATOR,
-  StaticWarningCode.SDK_VERSION_IS_EXPRESSION_IN_CONST_CONTEXT,
-  StaticWarningCode.SDK_VERSION_NEVER,
-  StaticWarningCode.SDK_VERSION_SET_LITERAL,
-  StaticWarningCode.SDK_VERSION_UI_AS_CODE,
-  StaticWarningCode.SDK_VERSION_UI_AS_CODE_IN_CONST_CONTEXT,
   StaticWarningCode.UNNECESSARY_NON_NULL_ASSERTION,
+  StaticWarningCode.UNNECESSARY_NULL_ASSERT_PATTERN,
+  StaticWarningCode.UNNECESSARY_NULL_CHECK_PATTERN,
   TodoCode.FIXME,
   TodoCode.HACK,
   TodoCode.TODO,
   TodoCode.UNDONE,
+  WarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER,
+  WarningCode.BODY_MIGHT_COMPLETE_NORMALLY_CATCH_ERROR,
+  WarningCode.BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE,
+  WarningCode.DEPRECATED_EXTENDS_FUNCTION,
+  WarningCode.DEPRECATED_IMPLEMENTS_FUNCTION,
+  WarningCode.DEPRECATED_MIXIN_FUNCTION,
+  WarningCode.DEPRECATED_NEW_IN_COMMENT_REFERENCE,
+  WarningCode.DUPLICATE_EXPORT,
+  WarningCode.DUPLICATE_HIDDEN_NAME,
+  WarningCode.DUPLICATE_IGNORE,
+  WarningCode.DUPLICATE_IMPORT,
+  WarningCode.DUPLICATE_SHOWN_NAME,
+  WarningCode.EQUAL_ELEMENTS_IN_SET,
+  WarningCode.EQUAL_KEYS_IN_MAP,
+  WarningCode.INFERENCE_FAILURE_ON_COLLECTION_LITERAL,
+  WarningCode.INFERENCE_FAILURE_ON_FUNCTION_INVOCATION,
+  WarningCode.INFERENCE_FAILURE_ON_FUNCTION_RETURN_TYPE,
+  WarningCode.INFERENCE_FAILURE_ON_GENERIC_INVOCATION,
+  WarningCode.INFERENCE_FAILURE_ON_INSTANCE_CREATION,
+  WarningCode.INFERENCE_FAILURE_ON_UNINITIALIZED_VARIABLE,
+  WarningCode.INFERENCE_FAILURE_ON_UNTYPED_PARAMETER,
+  WarningCode.INVALID_ANNOTATION_TARGET,
+  WarningCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT,
+  WarningCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT_INDIRECTLY,
+  WarningCode.INVALID_FACTORY_ANNOTATION,
+  WarningCode.INVALID_FACTORY_METHOD_DECL,
+  WarningCode.INVALID_FACTORY_METHOD_IMPL,
+  WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_AT_SIGN,
+  WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_EQUALS,
+  WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_GREATER,
+  WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_LOCATION,
+  WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_LOWER_CASE,
+  WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_NUMBER,
+  WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_PREFIX,
+  WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_TRAILING_CHARACTERS,
+  WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_TWO_SLASHES,
+  WarningCode.INVALID_REQUIRED_NAMED_PARAM,
+  WarningCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM,
+  WarningCode.INVALID_REQUIRED_POSITIONAL_PARAM,
+  WarningCode.INVALID_SEALED_ANNOTATION,
+  WarningCode.INVALID_USE_OF_INTERNAL_MEMBER,
+  WarningCode.INVALID_USE_OF_PROTECTED_MEMBER,
+  WarningCode.INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER,
+  WarningCode.INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER,
+  WarningCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER,
+  WarningCode.MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_ONE,
+  WarningCode.MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_THREE_PLUS,
+  WarningCode.MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_TWO,
+  WarningCode.MISSING_REQUIRED_PARAM,
+  WarningCode.MISSING_REQUIRED_PARAM_WITH_DETAILS,
+  WarningCode.MISSING_RETURN,
+  WarningCode.NULLABLE_TYPE_IN_CATCH_CLAUSE,
+  WarningCode.NULL_ARGUMENT_TO_NON_NULL_TYPE,
+  WarningCode.NULL_AWARE_BEFORE_OPERATOR,
+  WarningCode.NULL_AWARE_IN_CONDITION,
+  WarningCode.NULL_AWARE_IN_LOGICAL_OPERATOR,
+  WarningCode.RECEIVER_OF_TYPE_NEVER,
+  WarningCode.REMOVED_LINT_USE,
+  WarningCode.REPLACED_LINT_USE,
+  WarningCode.RETURN_OF_DO_NOT_STORE,
+  WarningCode.RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR,
+  WarningCode.RETURN_TYPE_INVALID_FOR_CATCH_ERROR,
+  WarningCode.SDK_VERSION_ASYNC_EXPORTED_FROM_CORE,
+  WarningCode.SDK_VERSION_AS_EXPRESSION_IN_CONST_CONTEXT,
+  WarningCode.SDK_VERSION_BOOL_OPERATOR_IN_CONST_CONTEXT,
+  WarningCode.SDK_VERSION_CONSTRUCTOR_TEAROFFS,
+  WarningCode.SDK_VERSION_EQ_EQ_OPERATOR_IN_CONST_CONTEXT,
+  WarningCode.SDK_VERSION_EXTENSION_METHODS,
+  WarningCode.SDK_VERSION_GT_GT_GT_OPERATOR,
+  WarningCode.SDK_VERSION_IS_EXPRESSION_IN_CONST_CONTEXT,
+  WarningCode.SDK_VERSION_NEVER,
+  WarningCode.SDK_VERSION_SET_LITERAL,
+  WarningCode.SDK_VERSION_UI_AS_CODE,
+  WarningCode.SDK_VERSION_UI_AS_CODE_IN_CONST_CONTEXT,
+  WarningCode.TEXT_DIRECTION_CODE_POINT_IN_COMMENT,
+  WarningCode.TEXT_DIRECTION_CODE_POINT_IN_LITERAL,
+  WarningCode.TYPE_CHECK_IS_NOT_NULL,
+  WarningCode.TYPE_CHECK_IS_NULL,
+  WarningCode.UNDEFINED_HIDDEN_NAME,
+  WarningCode.UNDEFINED_SHOWN_NAME,
+  WarningCode.UNNECESSARY_CAST_PATTERN,
+  WarningCode.UNNECESSARY_WILDCARD_PATTERN,
+  WarningCode.UNUSED_CATCH_CLAUSE,
+  WarningCode.UNUSED_CATCH_STACK,
 ];
diff --git a/analyzer/lib/src/error/error_handler_verifier.dart b/analyzer/lib/src/error/error_handler_verifier.dart
index 004aacd..ceebfca 100644
--- a/analyzer/lib/src/error/error_handler_verifier.dart
+++ b/analyzer/lib/src/error/error_handler_verifier.dart
@@ -174,7 +174,7 @@
       {bool checkFirstParameterType = true}) {
     void report() {
       _errorReporter.reportErrorForNode(
-        HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER,
+        WarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER,
         expression,
         [expressionType, expectedFunctionReturnType],
       );
@@ -243,7 +243,7 @@
       DartType expectedType, DartType functionReturnType, Expression callback) {
     if (!_typeSystem.isAssignableTo(functionReturnType, expectedType)) {
       _errorReporter.reportErrorForNode(
-        HintCode.RETURN_TYPE_INVALID_FOR_CATCH_ERROR,
+        WarningCode.RETURN_TYPE_INVALID_FOR_CATCH_ERROR,
         callback,
         [functionReturnType, expectedType],
       );
diff --git a/analyzer/lib/src/error/ignore_validator.dart b/analyzer/lib/src/error/ignore_validator.dart
index 197bba7..24860cd 100644
--- a/analyzer/lib/src/error/ignore_validator.dart
+++ b/analyzer/lib/src/error/ignore_validator.dart
@@ -7,8 +7,6 @@
 import 'package:analyzer/source/line_info.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/ignore_comments/ignore_info.dart';
-import 'package:analyzer/src/lint/registry.dart';
-import 'package:analyzer/src/lint/state.dart';
 
 /// Used to validate the ignore comments in a single file.
 class IgnoreValidator {
@@ -128,12 +126,12 @@
     for (var ignoredElement in duplicated) {
       if (ignoredElement is DiagnosticName) {
         var name = ignoredElement.name;
-        _errorReporter.reportErrorForOffset(HintCode.DUPLICATE_IGNORE,
+        _errorReporter.reportErrorForOffset(WarningCode.DUPLICATE_IGNORE,
             ignoredElement.offset, name.length, [name]);
         list.remove(ignoredElement);
       } else if (ignoredElement is DiagnosticType) {
         _errorReporter.reportErrorForOffset(
-          HintCode.DUPLICATE_IGNORE,
+          WarningCode.DUPLICATE_IGNORE,
           ignoredElement.offset,
           ignoredElement.length,
           [ignoredElement.type],
@@ -146,36 +144,38 @@
   /// Report the [ignoredNames] as being unnecessary.
   void _reportUnnecessaryOrRemovedOrDeprecatedIgnores(
       List<IgnoredElement> ignoredNames) {
-    for (var ignoredName in ignoredNames) {
-      if (ignoredName is DiagnosticName) {
-        var name = ignoredName.name;
-        var rule = Registry.ruleRegistry.getRule(name);
-        if (rule != null) {
-          var state = rule.state;
-          var since = state.since.toString();
-          if (state is DeprecatedState) {
-            // todo(pq): implement
-          } else if (state is RemovedState) {
-            var replacedBy = state.replacedBy;
-            if (replacedBy != null) {
-              _errorReporter.reportErrorForOffset(HintCode.REPLACED_LINT_USE,
-                  ignoredName.offset, name.length, [name, since, replacedBy]);
-              continue;
-            } else {
-              _errorReporter.reportErrorForOffset(HintCode.REMOVED_LINT_USE,
-                  ignoredName.offset, name.length, [name, since]);
-              continue;
-            }
-          }
-        }
-
-        // TODO(brianwilkerson) Uncomment the code below after the unnecessary
-        //  ignores in the Flutter code base have been cleaned up.
-        //   _errorReporter.reportErrorForOffset(
-        //       HintCode.UNNECESSARY_IGNORE, ignoredName.offset, name.length,
-        //       [name]);
-      }
-    }
+    // todo(pq): find the right way to roll-out enablement and uncomment
+    // https://github.com/dart-lang/sdk/issues/51214
+    // for (var ignoredName in ignoredNames) {
+    //   if (ignoredName is DiagnosticName) {
+    //     var name = ignoredName.name;
+    //     var rule = Registry.ruleRegistry.getRule(name);
+    //     if (rule != null) {
+    //       var state = rule.state;
+    //       var since = state.since.toString();
+    //       if (state is DeprecatedState) {
+    //         // todo(pq): implement
+    //       } else if (state is RemovedState) {
+    //         var replacedBy = state.replacedBy;
+    //         if (replacedBy != null) {
+    //           _errorReporter.reportErrorForOffset(HintCode.REPLACED_LINT_USE,
+    //               ignoredName.offset, name.length, [name, since, replacedBy]);
+    //           continue;
+    //         } else {
+    //           _errorReporter.reportErrorForOffset(HintCode.REMOVED_LINT_USE,
+    //               ignoredName.offset, name.length, [name, since]);
+    //           continue;
+    //         }
+    //       }
+    //     }
+    //
+    //     // TODO(brianwilkerson) Uncomment the code below after the unnecessary
+    //     //  ignores in the Flutter code base have been cleaned up.
+    //     //   _errorReporter.reportErrorForOffset(
+    //     //       HintCode.UNNECESSARY_IGNORE, ignoredName.offset, name.length,
+    //     //       [name]);
+    //   }
+    // }
   }
 }
 
diff --git a/analyzer/lib/src/error/imports_verifier.dart b/analyzer/lib/src/error/imports_verifier.dart
index 319cda1..baca24c 100644
--- a/analyzer/lib/src/error/imports_verifier.dart
+++ b/analyzer/lib/src/error/imports_verifier.dart
@@ -316,50 +316,42 @@
 
   /// Any time after the defining compilation unit has been visited by this
   /// visitor, this method can be called to report an
-  /// [HintCode.DUPLICATE_EXPORT] hint for each of the export directives in the
-  /// [_duplicateExports] list.
-  ///
-  /// @param errorReporter the error reporter to report the set of
-  ///        [HintCode.DUPLICATE_EXPORT] hints to
+  /// [StaticWarningCode.DUPLICATE_EXPORT] hint for each of the export
+  /// directives in the [_duplicateExports] list.
   void generateDuplicateExportHints(ErrorReporter errorReporter) {
     var length = _duplicateExports.length;
     for (var i = 0; i < length; i++) {
       errorReporter.reportErrorForNode(
-          HintCode.DUPLICATE_EXPORT, _duplicateExports[i].uri);
+          WarningCode.DUPLICATE_EXPORT, _duplicateExports[i].uri);
     }
   }
 
   /// Any time after the defining compilation unit has been visited by this
   /// visitor, this method can be called to report an
-  /// [HintCode.DUPLICATE_IMPORT] hint for each of the import directives in the
-  /// [_duplicateImports] list.
-  ///
-  /// @param errorReporter the error reporter to report the set of
-  ///        [HintCode.DUPLICATE_IMPORT] hints to
+  /// [StaticWarningCode.DUPLICATE_IMPORT] hint for each of the import
+  /// directives in the [_duplicateImports] list.
   void generateDuplicateImportHints(ErrorReporter errorReporter) {
     var length = _duplicateImports.length;
     for (var i = 0; i < length; i++) {
       errorReporter.reportErrorForNode(
-          HintCode.DUPLICATE_IMPORT, _duplicateImports[i].uri);
+          WarningCode.DUPLICATE_IMPORT, _duplicateImports[i].uri);
     }
   }
 
-  /// Report a [HintCode.DUPLICATE_SHOWN_NAME] and
-  /// [HintCode.DUPLICATE_HIDDEN_NAME] hints for each duplicate shown or hidden
-  /// name.
+  /// Report a [StaticWarningCode.DUPLICATE_SHOWN_NAME] and
+  /// [StaticWarningCode.DUPLICATE_HIDDEN_NAME] hints for each duplicate shown
+  /// or hidden name.
   ///
   /// Only call this method after all of the compilation units have been visited
   /// by this visitor.
-  ///
-  /// @param errorReporter the error reporter used to report the set of
-  ///          [HintCode.UNUSED_SHOWN_NAME] hints
   void generateDuplicateShownHiddenNameHints(ErrorReporter reporter) {
     _duplicateHiddenNamesMap.forEach(
         (NamespaceDirective directive, List<SimpleIdentifier> identifiers) {
       int length = identifiers.length;
       for (int i = 0; i < length; i++) {
         Identifier identifier = identifiers[i];
-        reporter.reportErrorForNode(HintCode.DUPLICATE_HIDDEN_NAME, identifier);
+        reporter.reportErrorForNode(
+            WarningCode.DUPLICATE_HIDDEN_NAME, identifier);
       }
     });
     _duplicateShownNamesMap.forEach(
@@ -367,7 +359,8 @@
       int length = identifiers.length;
       for (int i = 0; i < length; i++) {
         Identifier identifier = identifiers[i];
-        reporter.reportErrorForNode(HintCode.DUPLICATE_SHOWN_NAME, identifier);
+        reporter.reportErrorForNode(
+            WarningCode.DUPLICATE_SHOWN_NAME, identifier);
       }
     });
   }
diff --git a/analyzer/lib/src/error/inheritance_override.dart b/analyzer/lib/src/error/inheritance_override.dart
index 4ad88c5..e8e65f5 100644
--- a/analyzer/lib/src/error/inheritance_override.dart
+++ b/analyzer/lib/src/error/inheritance_override.dart
@@ -312,7 +312,10 @@
           superMember: interfaceElement,
           errorReporter: reporter,
           errorNode: classNameToken,
-          errorCode: CompileTimeErrorCode.INVALID_IMPLEMENTATION_OVERRIDE,
+          errorCode: concreteElement is PropertyAccessorElement &&
+                  concreteElement.isSetter
+              ? CompileTimeErrorCode.INVALID_IMPLEMENTATION_OVERRIDE_SETTER
+              : CompileTimeErrorCode.INVALID_IMPLEMENTATION_OVERRIDE,
         );
       }
 
@@ -358,10 +361,12 @@
       }
 
       correctOverrideHelper.verify(
-        superMember: superMember,
-        errorReporter: reporter,
-        errorNode: node,
-      );
+          superMember: superMember,
+          errorReporter: reporter,
+          errorNode: node,
+          errorCode: member is PropertyAccessorElement && member.isSetter
+              ? CompileTimeErrorCode.INVALID_OVERRIDE_SETTER
+              : CompileTimeErrorCode.INVALID_OVERRIDE);
     }
 
     if (mixinIndex == -1) {
@@ -909,23 +914,32 @@
     }
 
     _missingMustBeOverridden[classNameToken] = notOverridden.toList();
-    final namesForError = notOverridden.map((e) => e.name).toSet().toList();
+    final namesForError = notOverridden
+        .map((e) {
+          var name = e.name;
+          if (name.endsWith('=')) {
+            name = name.substring(0, name.length - 1);
+          }
+          return name;
+        })
+        .toSet()
+        .toList();
 
     if (namesForError.length == 1) {
       reporter.reportErrorForToken(
-        HintCode.MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_ONE,
+        WarningCode.MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_ONE,
         classNameToken,
         namesForError,
       );
     } else if (namesForError.length == 2) {
       reporter.reportErrorForToken(
-        HintCode.MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_TWO,
+        WarningCode.MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_TWO,
         classNameToken,
         namesForError,
       );
     } else {
       reporter.reportErrorForToken(
-        HintCode.MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_THREE_PLUS,
+        WarningCode.MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_THREE_PLUS,
         classNameToken,
         [
           namesForError[0],
diff --git a/analyzer/lib/src/error/language_version_override_verifier.dart b/analyzer/lib/src/error/language_version_override_verifier.dart
index 5853f8e..86fd85f 100644
--- a/analyzer/lib/src/error/language_version_override_verifier.dart
+++ b/analyzer/lib/src/error/language_version_override_verifier.dart
@@ -187,7 +187,7 @@
 
     if (slashCount > 2) {
       _errorReporter.reportErrorForOffset(
-          HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_TWO_SLASHES,
+          WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_TWO_SLASHES,
           offset,
           length);
       return false;
@@ -195,14 +195,16 @@
 
     if (!atSignPresent) {
       _errorReporter.reportErrorForOffset(
-          HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_AT_SIGN, offset, length);
+          WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_AT_SIGN,
+          offset,
+          length);
       return false;
     }
 
     if (possibleDart != 'dart') {
       // The 4 characters after `@` are "dart", but in the wrong case.
       _errorReporter.reportErrorForOffset(
-          HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_LOWER_CASE,
+          WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_LOWER_CASE,
           offset,
           length);
       return false;
@@ -213,19 +215,19 @@
       // The separator between "@dart" and the version number is either not
       // present, or is not a single "=" character.
       _errorReporter.reportErrorForOffset(
-          HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_EQUALS, offset, length);
+          WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_EQUALS, offset, length);
       return false;
     }
 
     if (containsInvalidVersionNumberPrefix) {
       _errorReporter.reportErrorForOffset(
-          HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_PREFIX, offset, length);
+          WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_PREFIX, offset, length);
       return false;
     }
 
     void reportInvalidNumber() {
       _errorReporter.reportErrorForOffset(
-          HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_NUMBER, offset, length);
+          WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_NUMBER, offset, length);
     }
 
     // Nothing preceding the version number makes this comment invalid. Check
@@ -258,7 +260,7 @@
     // This comment is a valid language version override, except for trailing
     // characters.
     _errorReporter.reportErrorForOffset(
-        HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_TRAILING_CHARACTERS,
+        WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_TRAILING_CHARACTERS,
         offset,
         length);
     return false;
@@ -286,7 +288,7 @@
           if (match != null) {
             var atDartStart = lexeme.indexOf('@dart');
             _errorReporter.reportErrorForOffset(
-              HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_LOCATION,
+              WarningCode.INVALID_LANGUAGE_VERSION_OVERRIDE_LOCATION,
               commentToken.offset + atDartStart,
               match.end - atDartStart,
             );
diff --git a/analyzer/lib/src/error/null_safe_api_verifier.dart b/analyzer/lib/src/error/null_safe_api_verifier.dart
index 7043bd2..5ebd0e4 100644
--- a/analyzer/lib/src/error/null_safe_api_verifier.dart
+++ b/analyzer/lib/src/error/null_safe_api_verifier.dart
@@ -6,7 +6,7 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
-import 'package:analyzer/src/dart/error/hint_codes.dart';
+import 'package:analyzer/src/error/codes.g.dart';
 
 /// Verifies usages of `Future.value` and `Completer.complete` when null-safety
 /// is enabled.
@@ -74,7 +74,7 @@
 
     if (argumentIsNull) {
       _errorReporter.reportErrorForNode(
-          HintCode.NULL_ARGUMENT_TO_NON_NULL_TYPE,
+          WarningCode.NULL_ARGUMENT_TO_NON_NULL_TYPE,
           argument ?? node,
           [memberName, type.getDisplayString(withNullability: true)]);
     }
diff --git a/analyzer/lib/src/error/required_parameters_verifier.dart b/analyzer/lib/src/error/required_parameters_verifier.dart
index 8dbae46..293a487 100644
--- a/analyzer/lib/src/error/required_parameters_verifier.dart
+++ b/analyzer/lib/src/error/required_parameters_verifier.dart
@@ -140,14 +140,14 @@
             var reason = annotation.reason;
             if (reason != null) {
               _errorReporter.reportErrorForOffset(
-                HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS,
+                WarningCode.MISSING_REQUIRED_PARAM_WITH_DETAILS,
                 errorNode.offset,
                 errorNode.length,
                 [parameterName, reason],
               );
             } else {
               _errorReporter.reportErrorForOffset(
-                HintCode.MISSING_REQUIRED_PARAM,
+                WarningCode.MISSING_REQUIRED_PARAM,
                 errorNode.offset,
                 errorNode.length,
                 [parameterName],
diff --git a/analyzer/lib/src/error/return_type_verifier.dart b/analyzer/lib/src/error/return_type_verifier.dart
index 2ae92c7..f28c22f 100644
--- a/analyzer/lib/src/error/return_type_verifier.dart
+++ b/analyzer/lib/src/error/return_type_verifier.dart
@@ -156,7 +156,7 @@
     void reportTypeError() {
       if (enclosingExecutable.catchErrorOnErrorReturnType != null) {
         _errorReporter.reportErrorForNode(
-          HintCode.RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR,
+          WarningCode.RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR,
           expression,
           [S, T],
         );
@@ -275,7 +275,7 @@
     void reportTypeError() {
       if (enclosingExecutable.catchErrorOnErrorReturnType != null) {
         _errorReporter.reportErrorForNode(
-          HintCode.RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR,
+          WarningCode.RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR,
           expression,
           [S, T],
         );
diff --git a/analyzer/lib/src/error/unicode_text_verifier.dart b/analyzer/lib/src/error/unicode_text_verifier.dart
index cdbe7ad..effbad1 100644
--- a/analyzer/lib/src/error/unicode_text_verifier.dart
+++ b/analyzer/lib/src/error/unicode_text_verifier.dart
@@ -27,8 +27,8 @@
         // (where Unicode is outside a string or comment).
         var errorCode =
             node is SimpleStringLiteral || node is InterpolationString
-                ? HintCode.TEXT_DIRECTION_CODE_POINT_IN_LITERAL
-                : HintCode.TEXT_DIRECTION_CODE_POINT_IN_COMMENT;
+                ? WarningCode.TEXT_DIRECTION_CODE_POINT_IN_LITERAL
+                : WarningCode.TEXT_DIRECTION_CODE_POINT_IN_COMMENT;
         var code = codeUnit.toRadixString(16).toUpperCase();
         errorReporter.reportErrorForOffset(errorCode, offset, 1, [code]);
       }
diff --git a/analyzer/lib/src/error/unused_local_elements_verifier.dart b/analyzer/lib/src/error/unused_local_elements_verifier.dart
index 7ed2fa0..dfc767e 100644
--- a/analyzer/lib/src/error/unused_local_elements_verifier.dart
+++ b/analyzer/lib/src/error/unused_local_elements_verifier.dart
@@ -193,6 +193,13 @@
   }
 
   @override
+  void visitPatternField(PatternField node) {
+    usedElements.addMember(node.element);
+    usedElements.addReadMember(node.element);
+    super.visitPatternField(node);
+  }
+
+  @override
   void visitPostfixExpression(PostfixExpression node) {
     var element = node.staticElement;
     usedElements.addMember(element);
@@ -209,6 +216,7 @@
   @override
   void visitRelationalPattern(RelationalPattern node) {
     usedElements.addMember(node.element);
+    usedElements.addReadMember(node.element);
     super.visitRelationalPattern(node);
   }
 
@@ -491,6 +499,14 @@
   }
 
   @override
+  void visitDeclaredVariablePattern(DeclaredVariablePattern node) {
+    final declaredElement = node.declaredElement!;
+    _visitLocalVariableElement(declaredElement);
+
+    super.visitDeclaredVariablePattern(node);
+  }
+
+  @override
   void visitEnumConstantDeclaration(EnumConstantDeclaration node) {
     final declaredElement = node.declaredElement as FieldElement;
     _visitFieldElement(declaredElement);
@@ -894,11 +910,11 @@
 
   void _visitLocalVariableElement(LocalVariableElement element) {
     if (!_isUsedElement(element) && !_isNamedUnderscore(element)) {
-      HintCode errorCode;
+      ErrorCode errorCode;
       if (_usedElements.isCatchException(element)) {
-        errorCode = HintCode.UNUSED_CATCH_CLAUSE;
+        errorCode = WarningCode.UNUSED_CATCH_CLAUSE;
       } else if (_usedElements.isCatchStackTrace(element)) {
-        errorCode = HintCode.UNUSED_CATCH_STACK;
+        errorCode = WarningCode.UNUSED_CATCH_STACK;
       } else {
         errorCode = HintCode.UNUSED_LOCAL_VARIABLE;
       }
@@ -993,7 +1009,9 @@
   }
 
   void addElement(Element? element) {
-    if (element != null) {
+    if (element is JoinPatternVariableElementImpl) {
+      elements.addAll(element.transitiveVariables);
+    } else if (element != null) {
       elements.add(element);
     }
   }
@@ -1010,6 +1028,11 @@
   }
 
   void addReadMember(Element? element) {
+    // Store un-parameterized members.
+    if (element is ExecutableMember) {
+      element = element.declaration;
+    }
+
     if (element != null) {
       readMembers.add(element);
     }
diff --git a/analyzer/lib/src/fasta/ast_builder.dart b/analyzer/lib/src/fasta/ast_builder.dart
index f3be609..f6b47d9 100644
--- a/analyzer/lib/src/fasta/ast_builder.dart
+++ b/analyzer/lib/src/fasta/ast_builder.dart
@@ -46,7 +46,7 @@
         Parser;
 import 'package:_fe_analyzer_shared/src/parser/quote.dart';
 import 'package:_fe_analyzer_shared/src/parser/stack_listener.dart'
-    show NullValue, StackListener;
+    show NullValues, StackListener;
 import 'package:_fe_analyzer_shared/src/scanner/errors.dart'
     show translateErrorToken;
 import 'package:_fe_analyzer_shared/src/scanner/scanner.dart';
@@ -216,7 +216,7 @@
         ),
       );
     }
-    push(NullValue.CascadeReceiver);
+    push(NullValues.CascadeReceiver);
   }
 
   @override
@@ -226,6 +226,9 @@
       Token? macroToken,
       Token? inlineToken,
       Token? sealedToken,
+      Token? baseToken,
+      Token? interfaceToken,
+      Token? finalToken,
       Token? augmentToken,
       Token? mixinToken,
       Token name) {
@@ -262,6 +265,32 @@
       }
     }
     if (!enableClassModifiers) {
+      if (baseToken != null) {
+        _reportFeatureNotEnabled(
+          feature: ExperimentalFeatures.class_modifiers,
+          startToken: baseToken,
+        );
+        // Pretend that 'base' didn't occur while this feature is incomplete.
+        baseToken = null;
+      }
+      if (interfaceToken != null) {
+        _reportFeatureNotEnabled(
+          feature: ExperimentalFeatures.class_modifiers,
+          startToken: interfaceToken,
+        );
+        // Pretend that 'interface' didn't occur while this feature is
+        // incomplete.
+        interfaceToken = null;
+      }
+      if (finalToken != null) {
+        _reportFeatureNotEnabled(
+          feature: ExperimentalFeatures.class_modifiers,
+          startToken: finalToken,
+        );
+        // Pretend that 'final' didn't occur while this feature is
+        // incomplete.
+        finalToken = null;
+      }
       if (mixinToken != null) {
         _reportFeatureNotEnabled(
           feature: ExperimentalFeatures.class_modifiers,
@@ -271,11 +300,14 @@
         mixinToken = null;
       }
     }
-    push(macroToken ?? NullValue.Token);
-    push(inlineToken ?? NullValue.Token);
-    push(sealedToken ?? NullValue.Token);
-    push(augmentToken ?? NullValue.Token);
-    push(mixinToken ?? NullValue.Token);
+    push(macroToken ?? NullValues.Token);
+    push(inlineToken ?? NullValues.Token);
+    push(sealedToken ?? NullValues.Token);
+    push(baseToken ?? NullValues.Token);
+    push(interfaceToken ?? NullValues.Token);
+    push(finalToken ?? NullValues.Token);
+    push(augmentToken ?? NullValues.Token);
+    push(mixinToken ?? NullValues.Token);
   }
 
   @override
@@ -284,6 +316,9 @@
   }
 
   @override
+  void beginConstantPattern(Token? constKeyword) {}
+
+  @override
   void beginEnum(Token enumKeyword) {}
 
   @override
@@ -397,7 +432,13 @@
 
   @override
   void beginMixinDeclaration(
-      Token? augmentToken, Token? sealedToken, Token mixinKeyword, Token name) {
+      Token? augmentToken,
+      Token? sealedToken,
+      Token? baseToken,
+      Token? interfaceToken,
+      Token? finalToken,
+      Token mixinKeyword,
+      Token name) {
     assert(_classLikeBuilder == null);
     if (!enableSealedClass) {
       if (sealedToken != null) {
@@ -409,8 +450,37 @@
         sealedToken = null;
       }
     }
-    push(augmentToken ?? NullValue.Token);
-    push(sealedToken ?? NullValue.Token);
+    if (!enableClassModifiers) {
+      if (baseToken != null) {
+        _reportFeatureNotEnabled(
+          feature: ExperimentalFeatures.class_modifiers,
+          startToken: baseToken,
+        );
+        // Pretend that 'base' didn't occur while this feature is incomplete.
+        baseToken = null;
+      }
+      if (interfaceToken != null) {
+        _reportFeatureNotEnabled(
+          feature: ExperimentalFeatures.class_modifiers,
+          startToken: interfaceToken,
+        );
+        // Pretend that 'interface' didn't occur while this feature is incomplete.
+        interfaceToken = null;
+      }
+      if (finalToken != null) {
+        _reportFeatureNotEnabled(
+          feature: ExperimentalFeatures.class_modifiers,
+          startToken: finalToken,
+        );
+        // Pretend that 'final' didn't occur while this feature is incomplete.
+        finalToken = null;
+      }
+    }
+    push(augmentToken ?? NullValues.Token);
+    push(sealedToken ?? NullValues.Token);
+    push(baseToken ?? NullValues.Token);
+    push(interfaceToken ?? NullValues.Token);
+    push(finalToken ?? NullValues.Token);
   }
 
   @override
@@ -420,6 +490,9 @@
       Token? macroToken,
       Token? inlineToken,
       Token? sealedToken,
+      Token? baseToken,
+      Token? interfaceToken,
+      Token? finalToken,
       Token? augmentToken,
       Token? mixinToken,
       Token name) {
@@ -455,6 +528,31 @@
       }
     }
     if (!enableClassModifiers) {
+      if (baseToken != null) {
+        _reportFeatureNotEnabled(
+          feature: ExperimentalFeatures.class_modifiers,
+          startToken: baseToken,
+        );
+        // Pretend that 'base' didn't occur while this feature is incomplete.
+        baseToken = null;
+      }
+      if (interfaceToken != null) {
+        _reportFeatureNotEnabled(
+          feature: ExperimentalFeatures.class_modifiers,
+          startToken: interfaceToken,
+        );
+        // Pretend that 'interface' didn't occur while this feature is
+        // incomplete.
+        interfaceToken = null;
+      }
+      if (finalToken != null) {
+        _reportFeatureNotEnabled(
+          feature: ExperimentalFeatures.class_modifiers,
+          startToken: finalToken,
+        );
+        // Pretend that 'final' didn't occur while this feature is incomplete.
+        finalToken = null;
+      }
       if (mixinToken != null) {
         _reportFeatureNotEnabled(
           feature: ExperimentalFeatures.class_modifiers,
@@ -464,11 +562,14 @@
         mixinToken = null;
       }
     }
-    push(macroToken ?? NullValue.Token);
-    push(inlineToken ?? NullValue.Token);
-    push(sealedToken ?? NullValue.Token);
-    push(augmentToken ?? NullValue.Token);
-    push(mixinToken ?? NullValue.Token);
+    push(macroToken ?? NullValues.Token);
+    push(inlineToken ?? NullValues.Token);
+    push(sealedToken ?? NullValues.Token);
+    push(baseToken ?? NullValues.Token);
+    push(interfaceToken ?? NullValues.Token);
+    push(finalToken ?? NullValues.Token);
+    push(augmentToken ?? NullValues.Token);
+    push(mixinToken ?? NullValues.Token);
   }
 
   @override
@@ -477,6 +578,11 @@
   }
 
   @override
+  void beginSwitchCaseWhenClause(Token when) {
+    debugEvent("PatternSwitchCaseGuard");
+  }
+
+  @override
   void beginTopLevelMethod(
       Token lastConsumed, Token? augmentToken, Token? externalToken) {
     push(_Modifiers()
@@ -510,7 +616,7 @@
         ..finalConstOrVarKeyword = varFinalOrConst
         ..lateToken = lateToken);
     } else {
-      push(NullValue.Modifiers);
+      push(NullValues.Modifiers);
     }
   }
 
@@ -682,6 +788,9 @@
       macroKeyword: null,
       inlineKeyword: null,
       sealedKeyword: null,
+      baseKeyword: null,
+      interfaceKeyword: null,
+      finalKeyword: null,
       augmentKeyword: null,
       mixinKeyword: null,
       classKeyword: Token(Keyword.CLASS, 0),
@@ -927,10 +1036,25 @@
 
     var right = pop() as DartPatternImpl;
     var left = pop() as DartPatternImpl;
-    push(
-      BinaryPatternImpl(
-          leftOperand: left, operator: operatorToken, rightOperand: right),
-    );
+    if (operatorToken.lexeme == '&&') {
+      push(
+        LogicalAndPatternImpl(
+          leftOperand: left,
+          operator: operatorToken,
+          rightOperand: right,
+        ),
+      );
+    } else if (operatorToken.lexeme == '||') {
+      push(
+        LogicalOrPatternImpl(
+          leftOperand: left,
+          operator: operatorToken,
+          rightOperand: right,
+        ),
+      );
+    } else {
+      throw UnimplementedError('operatorToken: $operatorToken');
+    }
   }
 
   @override
@@ -1379,7 +1503,7 @@
   @override
   void endCombinators(int count) {
     debugEvent("Combinators");
-    push(popTypedList<CombinatorImpl>(count) ?? NullValue.Combinators);
+    push(popTypedList<CombinatorImpl>(count) ?? NullValues.Combinators);
   }
 
   @override
@@ -1460,7 +1584,13 @@
   void endConditionalUris(int count) {
     debugEvent("ConditionalUris");
 
-    push(popTypedList<ConfigurationImpl>(count) ?? NullValue.ConditionalUris);
+    push(popTypedList<ConfigurationImpl>(count) ?? NullValues.ConditionalUris);
+  }
+
+  @override
+  void endConstantPattern(Token? constKeyword) {
+    push(ConstantPatternImpl(
+        constKeyword: constKeyword, expression: pop() as ExpressionImpl));
   }
 
   @override
@@ -1772,7 +1902,7 @@
     var forLoopParts = pop() as ForEachPartsImpl;
     var leftParenthesis = pop() as Token;
     var forToken = pop() as Token;
-    var awaitToken = pop(NullValue.AwaitToken) as Token?;
+    var awaitToken = pop(NullValues.AwaitToken) as Token?;
 
     push(
       ForStatementImpl(
@@ -1799,7 +1929,7 @@
     var forLoopParts = pop() as ForEachPartsImpl;
     var leftParenthesis = pop() as Token;
     var forToken = pop() as Token;
-    var awaitToken = pop(NullValue.AwaitToken) as Token?;
+    var awaitToken = pop(NullValues.AwaitToken) as Token?;
 
     push(
       ForElementImpl(
@@ -2215,9 +2345,9 @@
     debugEvent("Import");
 
     var combinators = pop() as List<CombinatorImpl>?;
-    var deferredKeyword = pop(NullValue.Deferred) as Token?;
-    var asKeyword = pop(NullValue.As) as Token?;
-    var prefix = pop(NullValue.Prefix) as SimpleIdentifierImpl?;
+    var deferredKeyword = pop(NullValues.Deferred) as Token?;
+    var asKeyword = pop(NullValues.As) as Token?;
+    var prefix = pop(NullValues.Prefix) as SimpleIdentifierImpl?;
     var configurations = pop() as List<ConfigurationImpl>?;
     var uri = pop() as StringLiteralImpl;
     var metadata = pop() as List<AnnotationImpl>?;
@@ -2490,7 +2620,7 @@
     var name = pop() as SimpleIdentifierImpl;
     var returnType = pop() as TypeAnnotationImpl?;
     var typeParameters = pop() as TypeParameterListImpl?;
-    var metadata = pop(NullValue.Metadata) as List<AnnotationImpl>?;
+    var metadata = pop(NullValues.Metadata) as List<AnnotationImpl>?;
     final functionExpression = FunctionExpressionImpl(
       typeParameters: typeParameters,
       parameters: parameters,
@@ -2552,7 +2682,7 @@
   void endMetadataStar(int count) {
     debugEvent("MetadataStar");
 
-    push(popTypedList<AnnotationImpl>(count) ?? NullValue.Metadata);
+    push(popTypedList<AnnotationImpl>(count) ?? NullValues.Metadata);
   }
 
   @override
@@ -2658,7 +2788,7 @@
         interfaces: interfaces,
       );
     }
-    var withClause = pop(NullValue.WithClause) as WithClauseImpl;
+    var withClause = pop(NullValues.WithClause) as WithClauseImpl;
     var superclass = pop() as TypeAnnotationImpl;
     if (superclass is! NamedTypeImpl) {
       errorReporter.errorReporter?.reportErrorForNode(
@@ -2678,11 +2808,14 @@
           typeArguments: null,
           question: null);
     }
-    var mixinKeyword = pop(NullValue.Token) as Token?;
-    var augmentKeyword = pop(NullValue.Token) as Token?;
-    var sealedKeyword = pop(NullValue.Token) as Token?;
-    var inlineKeyword = pop(NullValue.Token) as Token?;
-    var macroKeyword = pop(NullValue.Token) as Token?;
+    var mixinKeyword = pop(NullValues.Token) as Token?;
+    var augmentKeyword = pop(NullValues.Token) as Token?;
+    var finalKeyword = pop(NullValues.Token) as Token?;
+    var interfaceKeyword = pop(NullValues.Token) as Token?;
+    var baseKeyword = pop(NullValues.Token) as Token?;
+    var sealedKeyword = pop(NullValues.Token) as Token?;
+    var inlineKeyword = pop(NullValues.Token) as Token?;
+    var macroKeyword = pop(NullValues.Token) as Token?;
     var modifiers = pop() as _Modifiers?;
     var typeParameters = pop() as TypeParameterListImpl?;
     var name = pop() as SimpleIdentifierImpl;
@@ -2701,6 +2834,9 @@
         macroKeyword: macroKeyword,
         inlineKeyword: inlineKeyword,
         sealedKeyword: sealedKeyword,
+        baseKeyword: baseKeyword,
+        interfaceKeyword: interfaceKeyword,
+        finalKeyword: finalKeyword,
         augmentKeyword: augmentKeyword,
         mixinKeyword: mixinKeyword,
         superclass: superclass,
@@ -2721,16 +2857,16 @@
 
   @override
   void endOptionalFormalParameters(
-      int count, Token leftDelimeter, Token rightDelimeter) {
-    assert((optional('[', leftDelimeter) && optional(']', rightDelimeter)) ||
-        (optional('{', leftDelimeter) && optional('}', rightDelimeter)));
+      int count, Token leftDelimiter, Token rightDelimiter) {
+    assert((optional('[', leftDelimiter) && optional(']', rightDelimiter)) ||
+        (optional('{', leftDelimiter) && optional('}', rightDelimiter)));
     debugEvent("OptionalFormalParameters");
 
     push(
       _OptionalFormalParameters(
         popTypedList2<FormalParameterImpl>(count),
-        leftDelimeter,
-        rightDelimeter,
+        leftDelimiter,
+        rightDelimiter,
       ),
     );
   }
@@ -3093,6 +3229,11 @@
   }
 
   @override
+  void endSwitchCaseWhenClause(Token token) {
+    debugEvent("SwitchCaseWhenClause");
+  }
+
+  @override
   void endSwitchExpression(Token switchKeyword, Token endToken) {
     assert(optional('switch', switchKeyword));
     debugEvent("SwitchExpression");
@@ -3355,7 +3496,7 @@
   @override
   void endTypeList(int count) {
     debugEvent("TypeList");
-    push(popTypedList<TypeAnnotationImpl>(count) ?? NullValue.TypeList);
+    push(popTypedList<TypeAnnotationImpl>(count) ?? NullValues.TypeList);
   }
 
   @override
@@ -3425,7 +3566,7 @@
     debugEvent("VariablesDeclaration");
 
     var variables = popTypedList2<VariableDeclarationImpl>(count);
-    var modifiers = pop(NullValue.Modifiers) as _Modifiers?;
+    var modifiers = pop(NullValues.Modifiers) as _Modifiers?;
     var type = pop() as TypeAnnotationImpl?;
     var keyword = modifiers?.finalConstOrVarKeyword;
     var metadata = pop() as List<AnnotationImpl>?;
@@ -3539,8 +3680,8 @@
     assert(optionalOrNull('*', starToken));
     debugEvent("AsyncModifier");
 
-    push(asyncToken ?? NullValue.FunctionBodyAsyncToken);
-    push(starToken ?? NullValue.FunctionBodyStarToken);
+    push(asyncToken ?? NullValues.FunctionBodyAsyncToken);
+    push(starToken ?? NullValues.FunctionBodyStarToken);
   }
 
   @override
@@ -3644,7 +3785,7 @@
         ),
       );
     } else {
-      push(NullValue.ExtendsClause);
+      push(NullValues.ExtendsClause);
       // TODO(brianwilkerson) Consider (a) extending `ExtendsClause` to accept
       //  any type annotation for recovery purposes, and (b) extending the
       //  parser to parse a generic function type at this location.
@@ -3672,14 +3813,17 @@
       );
     }
     var implementsClause =
-        pop(NullValue.IdentifierList) as ImplementsClauseImpl?;
-    var withClause = pop(NullValue.WithClause) as WithClauseImpl?;
-    var extendsClause = pop(NullValue.ExtendsClause) as ExtendsClauseImpl?;
-    var mixinKeyword = pop(NullValue.Token) as Token?;
-    var augmentKeyword = pop(NullValue.Token) as Token?;
-    var sealedKeyword = pop(NullValue.Token) as Token?;
-    var inlineKeyword = pop(NullValue.Token) as Token?;
-    var macroKeyword = pop(NullValue.Token) as Token?;
+        pop(NullValues.IdentifierList) as ImplementsClauseImpl?;
+    var withClause = pop(NullValues.WithClause) as WithClauseImpl?;
+    var extendsClause = pop(NullValues.ExtendsClause) as ExtendsClauseImpl?;
+    var mixinKeyword = pop(NullValues.Token) as Token?;
+    var augmentKeyword = pop(NullValues.Token) as Token?;
+    var finalKeyword = pop(NullValues.Token) as Token?;
+    var interfaceKeyword = pop(NullValues.Token) as Token?;
+    var baseKeyword = pop(NullValues.Token) as Token?;
+    var sealedKeyword = pop(NullValues.Token) as Token?;
+    var inlineKeyword = pop(NullValues.Token) as Token?;
+    var macroKeyword = pop(NullValues.Token) as Token?;
     var modifiers = pop() as _Modifiers?;
     var typeParameters = pop() as TypeParameterListImpl?;
     var name = pop() as SimpleIdentifierImpl;
@@ -3695,6 +3839,9 @@
       macroKeyword: macroKeyword,
       inlineKeyword: inlineKeyword,
       sealedKeyword: sealedKeyword,
+      baseKeyword: baseKeyword,
+      interfaceKeyword: interfaceKeyword,
+      finalKeyword: finalKeyword,
       augmentKeyword: augmentKeyword,
       mixinKeyword: mixinKeyword,
       classKeyword: classKeyword,
@@ -3711,7 +3858,7 @@
 
   @override
   void handleClassNoWithClause() {
-    push(NullValue.WithClause);
+    push(NullValues.WithClause);
   }
 
   @override
@@ -3784,12 +3931,6 @@
   }
 
   @override
-  void handleConstantPattern(Token? constKeyword) {
-    push(ConstantPatternImpl(
-        constKeyword: constKeyword, expression: pop() as ExpressionImpl));
-  }
-
-  @override
   void handleConstFactory(Token constKeyword) {
     debugEvent("ConstFactory");
     // TODO(kallentu): Removal of const factory error for const function feature
@@ -3939,8 +4080,8 @@
     debugEvent("EnumHeader");
 
     var implementsClause =
-        pop(NullValue.IdentifierList) as ImplementsClauseImpl?;
-    var withClause = pop(NullValue.WithClause) as WithClauseImpl?;
+        pop(NullValues.IdentifierList) as ImplementsClauseImpl?;
+    var withClause = pop(NullValues.WithClause) as WithClauseImpl?;
     var typeParameters = pop() as TypeParameterListImpl?;
     var name = pop() as SimpleIdentifierImpl;
     var metadata = pop() as List<AnnotationImpl>?;
@@ -3977,7 +4118,7 @@
 
   @override
   void handleEnumNoWithClause() {
-    push(NullValue.WithClause);
+    push(NullValues.WithClause);
   }
 
   @override
@@ -4063,7 +4204,7 @@
   @override
   void handleForInitializerEmptyStatement(Token token) {
     debugEvent("ForInitializerEmptyStatement");
-    push(NullValue.Expression);
+    push(NullValues.Expression);
   }
 
   @override
@@ -4139,7 +4280,7 @@
       );
     }
 
-    push(awaitToken ?? NullValue.AwaitToken);
+    push(awaitToken ?? NullValues.AwaitToken);
     push(forToken);
     push(leftParenthesis);
     push(forLoopParts);
@@ -4201,7 +4342,7 @@
   void handleFormalParameterWithoutValue(Token token) {
     debugEvent("FormalParameterWithoutValue");
 
-    push(NullValue.ParameterDefaultValue);
+    push(NullValues.ParameterDefaultValue);
   }
 
   @override
@@ -4242,7 +4383,8 @@
   void handleIdentifierList(int count) {
     debugEvent("IdentifierList");
 
-    push(popTypedList<SimpleIdentifierImpl>(count) ?? NullValue.IdentifierList);
+    push(
+        popTypedList<SimpleIdentifierImpl>(count) ?? NullValues.IdentifierList);
   }
 
   @override
@@ -4262,7 +4404,7 @@
         ),
       );
     } else {
-      push(NullValue.IdentifierList);
+      push(NullValues.IdentifierList);
     }
   }
 
@@ -4275,12 +4417,12 @@
     if (asKeyword == null) {
       // If asKeyword is null, then no prefix has been pushed on the stack.
       // Push a placeholder indicating that there is no prefix.
-      push(NullValue.Prefix);
-      push(NullValue.As);
+      push(NullValues.Prefix);
+      push(NullValues.As);
     } else {
       push(asKeyword);
     }
-    push(deferredKeyword ?? NullValue.Deferred);
+    push(deferredKeyword ?? NullValues.Deferred);
   }
 
   @override
@@ -4603,10 +4745,13 @@
     debugEvent("MixinHeader");
 
     var implementsClause =
-        pop(NullValue.IdentifierList) as ImplementsClauseImpl?;
-    var onClause = pop(NullValue.IdentifierList) as OnClauseImpl?;
-    var sealedKeyword = pop(NullValue.Token) as Token?;
-    var augmentKeyword = pop(NullValue.Token) as Token?;
+        pop(NullValues.IdentifierList) as ImplementsClauseImpl?;
+    var onClause = pop(NullValues.IdentifierList) as OnClauseImpl?;
+    var finalKeyword = pop(NullValues.Token) as Token?;
+    var interfaceKeyword = pop(NullValues.Token) as Token?;
+    var baseKeyword = pop(NullValues.Token) as Token?;
+    var sealedKeyword = pop(NullValues.Token) as Token?;
+    var augmentKeyword = pop(NullValues.Token) as Token?;
     var typeParameters = pop() as TypeParameterListImpl?;
     var name = pop() as SimpleIdentifierImpl;
     var metadata = pop() as List<AnnotationImpl>?;
@@ -4617,6 +4762,9 @@
       metadata: metadata,
       augmentKeyword: augmentKeyword,
       sealedKeyword: sealedKeyword,
+      baseKeyword: baseKeyword,
+      interfaceKeyword: interfaceKeyword,
+      finalKeyword: finalKeyword,
       mixinKeyword: mixinKeyword,
       name: name.token,
       typeParameters: typeParameters,
@@ -4644,7 +4792,7 @@
         ),
       );
     } else {
-      push(NullValue.IdentifierList);
+      push(NullValues.IdentifierList);
     }
   }
 
@@ -4726,7 +4874,7 @@
   void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) {
     debugEvent("NoConstructorReferenceContinuationAfterTypeArguments");
 
-    push(NullValue.ConstructorReferenceContinuationAfterTypeArguments);
+    push(NullValues.ConstructorReferenceContinuationAfterTypeArguments);
   }
 
   @override
@@ -4748,8 +4896,8 @@
     debugEvent("NoInitializers");
 
     if (!isFullAst) return;
-    push(NullValue.ConstructorInitializerSeparator);
-    push(NullValue.ConstructorInitializers);
+    push(NullValues.ConstructorInitializerSeparator);
+    push(NullValues.ConstructorInitializers);
   }
 
   @override
@@ -4786,7 +4934,12 @@
   @override
   void handleNullAssertPattern(Token bang) {
     debugEvent("NullAssertPattern");
-    push(PostfixPatternImpl(operand: pop() as DartPatternImpl, operator: bang));
+    push(
+      NullAssertPatternImpl(
+        pattern: pop() as DartPatternImpl,
+        operator: bang,
+      ),
+    );
   }
 
   @override
@@ -4796,8 +4949,12 @@
       // TODO(paulberry): report the appropriate error
       throw UnimplementedError('Patterns not enabled');
     }
-    push(PostfixPatternImpl(
-        operand: pop() as DartPatternImpl, operator: question));
+    push(
+      NullCheckPatternImpl(
+        pattern: pop() as DartPatternImpl,
+        operator: question,
+      ),
+    );
   }
 
   @override
@@ -4832,7 +4989,7 @@
   @override
   void handleObjectPatternFields(int count, Token beginToken, Token endToken) {
     debugEvent("ExtractorPatternFields");
-    var fields = popTypedList2<RecordPatternFieldImpl>(count);
+    var fields = popTypedList2<PatternFieldImpl>(count);
     push(_ObjectPatternFields(beginToken, endToken, fields));
   }
 
@@ -4899,12 +5056,12 @@
     debugEvent("PatternField");
 
     var pattern = pop() as DartPatternImpl;
-    RecordPatternFieldNameImpl? fieldName;
+    PatternFieldNameImpl? fieldName;
     if (colon != null) {
       var name = (pop() as SimpleIdentifierImpl?)?.token;
-      fieldName = RecordPatternFieldNameImpl(name: name, colon: colon);
+      fieldName = PatternFieldNameImpl(name: name, colon: colon);
     }
-    push(RecordPatternFieldImpl(fieldName: fieldName, pattern: pattern));
+    push(PatternFieldImpl(name: fieldName, pattern: pattern));
   }
 
   @override
@@ -4955,7 +5112,7 @@
   void handleRecordPattern(Token token, int count) {
     debugEvent("RecordPattern");
 
-    var fields = popTypedList2<RecordPatternFieldImpl>(count);
+    var fields = popTypedList2<PatternFieldImpl>(count);
     push(
       RecordPatternImpl(
         leftParenthesis: token,
@@ -4991,9 +5148,9 @@
     debugEvent("RecoverClassHeader");
 
     var implementsClause =
-        pop(NullValue.IdentifierList) as ImplementsClauseImpl?;
-    var withClause = pop(NullValue.WithClause) as WithClauseImpl?;
-    var extendsClause = pop(NullValue.ExtendsClause) as ExtendsClauseImpl?;
+        pop(NullValues.IdentifierList) as ImplementsClauseImpl?;
+    var withClause = pop(NullValues.WithClause) as WithClauseImpl?;
+    var extendsClause = pop(NullValues.ExtendsClause) as ExtendsClauseImpl?;
     var declaration = _classLikeBuilder as _ClassDeclarationBuilder;
     if (extendsClause != null) {
       if (declaration.extendsClause?.superclass == null) {
@@ -5036,9 +5193,9 @@
     debugEvent("RecoverImport");
 
     var combinators = pop() as List<CombinatorImpl>?;
-    var deferredKeyword = pop(NullValue.Deferred) as Token?;
-    var asKeyword = pop(NullValue.As) as Token?;
-    var prefix = pop(NullValue.Prefix) as SimpleIdentifierImpl?;
+    var deferredKeyword = pop(NullValues.Deferred) as Token?;
+    var asKeyword = pop(NullValues.As) as Token?;
+    var prefix = pop(NullValues.Prefix) as SimpleIdentifierImpl?;
     var configurations = pop() as List<ConfigurationImpl>?;
 
     final directive = directives.last as ImportDirectiveImpl;
@@ -5075,8 +5232,8 @@
   void handleRecoverMixinHeader() {
     final builder = _classLikeBuilder as _MixinDeclarationBuilder;
     var implementsClause =
-        pop(NullValue.IdentifierList) as ImplementsClauseImpl?;
-    var onClause = pop(NullValue.IdentifierList) as OnClauseImpl?;
+        pop(NullValues.IdentifierList) as ImplementsClauseImpl?;
+    var onClause = pop(NullValues.IdentifierList) as OnClauseImpl?;
 
     if (onClause != null) {
       final existingClause = builder.onClause;
@@ -5183,6 +5340,16 @@
   }
 
   @override
+  void handleSwitchCaseNoWhenClause(Token token) {
+    debugEvent("SwitchCaseNoWhenClause");
+  }
+
+  @override
+  void handleSwitchExpressionCasePattern(Token token) {
+    debugEvent("SwitchExpressionCasePattern");
+  }
+
+  @override
   void handleSymbolVoid(Token voidKeyword) {
     assert(optional('void', voidKeyword));
     debugEvent("SymbolVoid");
@@ -5328,7 +5495,15 @@
       throw UnimplementedError('Patterns not enabled');
     }
     var type = pop() as TypeAnnotationImpl?;
-    if (inAssignmentPattern) {
+    if (variable.lexeme == '_') {
+      push(
+        WildcardPatternImpl(
+          keyword: keyword,
+          type: type,
+          name: variable,
+        ),
+      );
+    } else if (inAssignmentPattern) {
       push(
         AssignedVariablePatternImpl(
           name: variable,
@@ -5391,8 +5566,8 @@
     count = 0;
     int index = 0;
     while (index < sourcesAndOffsets.length) {
-      String referenceSource = sourcesAndOffsets[index++];
-      int referenceOffset = sourcesAndOffsets[index++];
+      var referenceSource = sourcesAndOffsets[index++] as String;
+      var referenceOffset = sourcesAndOffsets[index++] as int;
       ScannerResult result = scanString(referenceSource);
       if (!result.hasErrors) {
         Token token = result.tokens;
@@ -5592,6 +5767,9 @@
   final Token? macroKeyword;
   final Token? inlineKeyword;
   final Token? sealedKeyword;
+  final Token? baseKeyword;
+  final Token? interfaceKeyword;
+  final Token? finalKeyword;
   final Token? augmentKeyword;
   final Token? mixinKeyword;
   final Token classKeyword;
@@ -5611,6 +5789,9 @@
     required this.macroKeyword,
     required this.inlineKeyword,
     required this.sealedKeyword,
+    required this.baseKeyword,
+    required this.interfaceKeyword,
+    required this.finalKeyword,
     required this.augmentKeyword,
     required this.mixinKeyword,
     required this.classKeyword,
@@ -5629,6 +5810,9 @@
       macroKeyword: macroKeyword,
       inlineKeyword: inlineKeyword,
       sealedKeyword: sealedKeyword,
+      baseKeyword: baseKeyword,
+      interfaceKeyword: interfaceKeyword,
+      finalKeyword: finalKeyword,
       augmentKeyword: augmentKeyword,
       mixinKeyword: mixinKeyword,
       classKeyword: classKeyword,
@@ -5747,6 +5931,9 @@
 class _MixinDeclarationBuilder extends _ClassLikeDeclarationBuilder {
   final Token? augmentKeyword;
   final Token? sealedKeyword;
+  final Token? baseKeyword;
+  final Token? interfaceKeyword;
+  final Token? finalKeyword;
   final Token mixinKeyword;
   final Token name;
   OnClauseImpl? onClause;
@@ -5760,6 +5947,9 @@
     required super.rightBracket,
     required this.augmentKeyword,
     required this.sealedKeyword,
+    required this.baseKeyword,
+    required this.interfaceKeyword,
+    required this.finalKeyword,
     required this.mixinKeyword,
     required this.name,
     required this.onClause,
@@ -5772,6 +5962,9 @@
       metadata: metadata,
       augmentKeyword: augmentKeyword,
       sealedKeyword: sealedKeyword,
+      baseKeyword: baseKeyword,
+      interfaceKeyword: interfaceKeyword,
+      finalKeyword: finalKeyword,
       mixinKeyword: mixinKeyword,
       name: name,
       typeParameters: typeParameters,
@@ -5832,7 +6025,7 @@
 class _ObjectPatternFields {
   final Token leftParenthesis;
   final Token rightParenthesis;
-  final List<RecordPatternFieldImpl> fields;
+  final List<PatternFieldImpl> fields;
 
   _ObjectPatternFields(
       this.leftParenthesis, this.rightParenthesis, this.fields);
diff --git a/analyzer/lib/src/fasta/error_converter.dart b/analyzer/lib/src/fasta/error_converter.dart
index 6ce8f76..09b08a0 100644
--- a/analyzer/lib/src/fasta/error_converter.dart
+++ b/analyzer/lib/src/fasta/error_converter.dart
@@ -56,7 +56,7 @@
             ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, offset, length);
         return;
       case "CONST_NOT_INITIALIZED":
-        String name = arguments['name'];
+        var name = arguments['name'] as String;
         errorReporter?.reportErrorForOffset(
             CompileTimeErrorCode.CONST_NOT_INITIALIZED, offset, length, [name]);
         return;
@@ -69,7 +69,7 @@
             CompileTimeErrorCode.LABEL_UNDEFINED,
             offset,
             length,
-            [arguments['name']]);
+            [arguments['name'] as Object]);
         return;
       case "EMPTY_ENUM_BODY":
         errorReporter?.reportErrorForOffset(
@@ -89,7 +89,7 @@
         return;
       case "EXPECTED_TOKEN":
         errorReporter?.reportErrorForOffset(ParserErrorCode.EXPECTED_TOKEN,
-            offset, length, [arguments['string']]);
+            offset, length, [arguments['string'] as Object]);
         return;
       case "EXPECTED_TYPE_NAME":
         errorReporter?.reportErrorForOffset(
@@ -102,12 +102,12 @@
             length);
         return;
       case "FINAL_NOT_INITIALIZED":
-        String name = arguments['name'];
+        var name = arguments['name'] as String;
         errorReporter?.reportErrorForOffset(
             CompileTimeErrorCode.FINAL_NOT_INITIALIZED, offset, length, [name]);
         return;
       case "FINAL_NOT_INITIALIZED_CONSTRUCTOR_1":
-        String name = arguments['name'];
+        var name = arguments['name'] as String;
         errorReporter?.reportErrorForOffset(
             CompileTimeErrorCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1,
             offset,
@@ -123,8 +123,8 @@
             ScannerErrorCode.ILLEGAL_CHARACTER, offset, length);
         return;
       case "INVALID_ASSIGNMENT":
-        var type1 = arguments['type'];
-        var type2 = arguments['type2'];
+        var type1 = arguments['type'] as Object;
+        var type2 = arguments['type2'] as Object;
         errorReporter?.reportErrorForOffset(
             CompileTimeErrorCode.INVALID_ASSIGNMENT,
             offset,
diff --git a/analyzer/lib/src/generated/engine.dart b/analyzer/lib/src/generated/engine.dart
index 0fc9372..00fcced 100644
--- a/analyzer/lib/src/generated/engine.dart
+++ b/analyzer/lib/src/generated/engine.dart
@@ -4,7 +4,7 @@
 
 import 'dart:typed_data';
 
-import 'package:_fe_analyzer_shared/src/scanner/token_impl.dart';
+import 'package:_fe_analyzer_shared/src/scanner/string_canonicalizer.dart';
 import 'package:analyzer/dart/analysis/analysis_options.dart';
 import 'package:analyzer/dart/analysis/code_style_options.dart';
 import 'package:analyzer/dart/analysis/features.dart';
@@ -17,6 +17,7 @@
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/services/lint.dart';
 import 'package:analyzer/src/summary/api_signature.dart';
+import 'package:analyzer/src/utilities/legacy.dart';
 import 'package:pub_semver/pub_semver.dart';
 
 export 'package:analyzer/dart/analysis/analysis_options.dart';
@@ -107,8 +108,8 @@
   /// Clear any caches holding on to analysis results so that a full re-analysis
   /// will be performed the next time an analysis context is created.
   void clearCaches() {
-    // See https://github.com/dart-lang/sdk/issues/30314.
-    StringTokenImpl.canonicalizer.clear();
+    // Ensure the string canonicalization cache size is reasonable.
+    pruneStringCanonicalizationCache();
   }
 }
 
@@ -157,7 +158,8 @@
 
   /// The constraint on the language version for every Dart file.
   /// Violations will be reported as analysis errors.
-  VersionConstraint? sourceLanguageConstraint;
+  VersionConstraint? sourceLanguageConstraint =
+      noSoundNullSafety ? VersionConstraint.parse('>= 2.12.0') : null;
 
   ExperimentStatus _contextFeatures = ExperimentStatus();
 
diff --git a/analyzer/lib/src/generated/error_verifier.dart b/analyzer/lib/src/generated/error_verifier.dart
index 4a2ef98..1cd5a8e 100644
--- a/analyzer/lib/src/generated/error_verifier.dart
+++ b/analyzer/lib/src/generated/error_verifier.dart
@@ -448,6 +448,7 @@
       _checkForBadFunctionUse(node);
       _checkForWrongTypeParameterVarianceInSuperinterfaces();
       _checkForMainFunction1(node.name, node.declaredElement!);
+      _checkForMixinClassErrorCodes(node, members, superclass, withClause);
       _reportMacroApplicationErrors(
         annotations: node.metadata,
         macroErrors: element.macroApplicationErrors,
@@ -476,6 +477,8 @@
       _checkClassInheritance(
           node, node.superclass, node.withClause, node.implementsClause);
       _checkForMainFunction1(node.name, node.declaredElement!);
+      _checkForMixinClassErrorCodes(
+          node, List.empty(), node.superclass, node.withClause);
       _checkForWrongTypeParameterVarianceInSuperinterfaces();
     } finally {
       _enclosingClass = outerClassElement;
@@ -557,19 +560,6 @@
   }
 
   @override
-  void visitContinueStatement(ContinueStatement node) {
-    var labelNode = node.label;
-    if (labelNode != null) {
-      var labelElement = labelNode.staticElement;
-      if (labelElement is LabelElementImpl &&
-          labelElement.isOnSwitchStatement) {
-        errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.CONTINUE_LABEL_ON_SWITCH, labelNode);
-      }
-    }
-  }
-
-  @override
   void visitDefaultFormalParameter(DefaultFormalParameter node) {
     final defaultValue = node.defaultValue;
     if (defaultValue != null) {
@@ -1404,8 +1394,14 @@
       _checkMixinsSuperClass(withClause);
       _checkForMixinWithConflictingPrivateMember(withClause, superclass);
       _checkForConflictingGenerics(node);
+      _checkForBaseClassOrMixinImplementedOutsideOfLibrary(implementsClause);
+      _checkForInterfaceClassOrMixinSuperclassOutsideOfLibrary(
+          superclass, withClause);
+      _checkForFinalSupertypeOutsideOfLibrary(
+          superclass, withClause, implementsClause);
+      _checkForClassUsedAsMixin(withClause);
       _checkForSealedSupertypeOutsideOfLibrary(
-          node, superclass, withClause, implementsClause);
+          superclass, withClause, implementsClause);
       if (node is ClassDeclaration) {
         _checkForNoDefaultSuperConstructorImplicit(node);
       }
@@ -1500,8 +1496,11 @@
               problemReported = true;
             }
           } else {
-            if (_checkForMixinClassDeclaresConstructor(
-                mixinName, mixinElement)) {
+            bool isMixinClass =
+                mixinElement is ClassElementImpl && mixinElement.isMixinClass;
+            if (!isMixinClass &&
+                _checkForMixinClassDeclaresConstructor(
+                    mixinName, mixinElement)) {
               problemReported = true;
             }
             if (_checkForMixinInheritsNotFromObject(mixinName, mixinElement)) {
@@ -1705,7 +1704,7 @@
       var superElement = extendsClause.superclass.name.staticElement;
       if (superElement != null && superElement.name == "Function") {
         errorReporter.reportErrorForNode(
-            HintCode.DEPRECATED_EXTENDS_FUNCTION, extendsClause.superclass);
+            WarningCode.DEPRECATED_EXTENDS_FUNCTION, extendsClause.superclass);
       }
     }
 
@@ -1714,7 +1713,7 @@
         var type = interface.type;
         if (type != null && type.isDartCoreFunction) {
           errorReporter.reportErrorForNode(
-            HintCode.DEPRECATED_IMPLEMENTS_FUNCTION,
+            WarningCode.DEPRECATED_IMPLEMENTS_FUNCTION,
             interface,
           );
           break;
@@ -1727,7 +1726,38 @@
         var mixinElement = type.name.staticElement;
         if (mixinElement != null && mixinElement.name == "Function") {
           errorReporter.reportErrorForNode(
-              HintCode.DEPRECATED_MIXIN_FUNCTION, type);
+              WarningCode.DEPRECATED_MIXIN_FUNCTION, type);
+        }
+      }
+    }
+  }
+
+  /// Verify that if a class is implementing a base class or mixin, it must be
+  /// within the same library as that class or mixin.
+  ///
+  /// See [CompileTimeErrorCode.BASE_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY],
+  /// [CompileTimeErrorCode.BASE_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY].
+  void _checkForBaseClassOrMixinImplementedOutsideOfLibrary(
+      ImplementsClause? implementsClause) {
+    if (implementsClause == null) return;
+    for (NamedType interface in implementsClause.interfaces) {
+      final interfaceType = interface.type;
+      if (interfaceType is InterfaceType) {
+        final interfaceElement = interfaceType.element;
+        if (interfaceElement is ClassOrMixinElementImpl &&
+            interfaceElement.isBase &&
+            interfaceElement.library != _currentLibrary) {
+          if (interfaceElement is ClassElement) {
+            errorReporter.reportErrorForNode(
+                CompileTimeErrorCode.BASE_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY,
+                interface,
+                [interfaceElement.name]);
+          } else if (interfaceElement is MixinElement) {
+            errorReporter.reportErrorForNode(
+                CompileTimeErrorCode.BASE_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY,
+                interface,
+                [interfaceElement.name]);
+          }
         }
       }
     }
@@ -1805,6 +1835,34 @@
     }
   }
 
+  /// Verify that if a class is being mixed in and class modifiers are enabled
+  /// in that class' library, then the mixin application must be in the same
+  /// library as that class declaration.
+  ///
+  /// No error is emitted if the class being mixed in is a mixin class.
+  ///
+  /// See [CompileTimeErrorCode.CLASS_USED_AS_MIXIN].
+  void _checkForClassUsedAsMixin(WithClause? withClause) {
+    if (withClause != null) {
+      for (NamedType withMixin in withClause.mixinTypes) {
+        final withType = withMixin.type;
+        if (withType is InterfaceType) {
+          final withElement = withType.element;
+          if (withElement is ClassElementImpl &&
+              !withElement.isMixinClass &&
+              withElement.library != _currentLibrary &&
+              withElement.library.featureSet
+                  .isEnabled(Feature.class_modifiers)) {
+            errorReporter.reportErrorForNode(
+                CompileTimeErrorCode.CLASS_USED_AS_MIXIN,
+                withMixin,
+                [withElement.name]);
+          }
+        }
+      }
+    }
+  }
+
   /// Verify that the [_enclosingClass] does not have a method and getter pair
   /// with the same name, via inheritance.
   ///
@@ -2789,6 +2847,69 @@
     }
   }
 
+  /// Check that if a direct supertype of a node is final, then it must be in
+  /// the same library.
+  ///
+  /// See [CompileTimeErrorCode.FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY],
+  /// [CompileTimeErrorCode.FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY],
+  /// [CompileTimeErrorCode.FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY],
+  /// [CompileTimeErrorCode.FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY].
+  void _checkForFinalSupertypeOutsideOfLibrary(NamedType? superclass,
+      WithClause? withClause, ImplementsClause? implementsClause) {
+    if (superclass != null) {
+      final type = superclass.type;
+      if (type is InterfaceType) {
+        final element = type.element;
+        if (element is ClassElementImpl &&
+            element.isFinal &&
+            element.library != _currentLibrary) {
+          errorReporter.reportErrorForNode(
+              CompileTimeErrorCode.FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY,
+              superclass,
+              [element.name]);
+        }
+      }
+    }
+    if (withClause != null) {
+      for (NamedType namedType in withClause.mixinTypes) {
+        final type = namedType.type;
+        if (type is InterfaceType) {
+          final element = type.element;
+          if (element is MixinElementImpl &&
+              element.isFinal &&
+              element.library != _currentLibrary) {
+            errorReporter.reportErrorForNode(
+                CompileTimeErrorCode.FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY,
+                namedType,
+                [element.name]);
+          }
+        }
+      }
+    }
+    if (implementsClause != null) {
+      for (NamedType namedType in implementsClause.interfaces) {
+        final type = namedType.type;
+        if (type is InterfaceType) {
+          final element = type.element;
+          if (element is ClassOrMixinElementImpl &&
+              element.isFinal &&
+              element.library != _currentLibrary) {
+            final ErrorCode errorCode;
+            if (element is ClassElement) {
+              errorCode = CompileTimeErrorCode
+                  .FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY;
+            } else {
+              errorCode = CompileTimeErrorCode
+                  .FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY;
+            }
+            errorReporter
+                .reportErrorForNode(errorCode, namedType, [element.name]);
+          }
+        }
+      }
+    }
+  }
+
   void _checkForGenericFunctionType(TypeAnnotation? node) {
     if (node == null) {
       return;
@@ -2821,13 +2942,6 @@
         languageVersionToken,
         ['$sourceLanguageConstraint'],
       );
-    } else {
-      errorReporter.reportErrorForOffset(
-        CompileTimeErrorCode.ILLEGAL_LANGUAGE_VERSION_OVERRIDE,
-        0,
-        0,
-        ['$sourceLanguageConstraint'],
-      );
     }
   }
 
@@ -2984,6 +3098,48 @@
     }
   }
 
+  /// Verify that if a class is extending an interface class or mixing in an
+  /// interface mixin, it must be within the same library as that class or
+  /// mixin.
+  ///
+  /// See
+  /// [CompileTimeErrorCode.INTERFACE_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY],
+  /// [CompileTimeErrorCode.INTERFACE_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY].
+  void _checkForInterfaceClassOrMixinSuperclassOutsideOfLibrary(
+      NamedType? superclass, WithClause? withClause) {
+    if (superclass != null) {
+      final superclassType = superclass.type;
+      if (superclassType is InterfaceType) {
+        final superclassElement = superclassType.element;
+        if (superclassElement is ClassElementImpl &&
+            superclassElement.isInterface &&
+            superclassElement.library != _currentLibrary) {
+          errorReporter.reportErrorForNode(
+              CompileTimeErrorCode.INTERFACE_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY,
+              superclass,
+              [superclassElement.name]);
+        }
+      }
+    }
+    if (withClause != null) {
+      for (NamedType withMixin in withClause.mixinTypes) {
+        final withType = withMixin.type;
+        if (withType is InterfaceType) {
+          final withElement = withType.element;
+          if (withElement is MixinElementImpl &&
+              withElement.isInterface &&
+              withElement.library != _currentLibrary) {
+            errorReporter.reportErrorForNode(
+                CompileTimeErrorCode
+                    .INTERFACE_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY,
+                withMixin,
+                [withElement.name]);
+          }
+        }
+      }
+    }
+  }
+
   /// Verify that an 'int' can be assigned to the parameter corresponding to the
   /// given [argument]. This is used for prefix and postfix expressions where
   /// the argument value is implicit.
@@ -3308,6 +3464,11 @@
   /// an enum type either have a default case or include all of the enum
   /// constants.
   void _checkForMissingEnumConstantInSwitch(SwitchStatement statement) {
+    if (_currentLibrary.featureSet.isEnabled(Feature.patterns)) {
+      // Exhaustiveness checking cover this warning.
+      return;
+    }
+
     // TODO(brianwilkerson) This needs to be checked after constant values have
     // been computed.
     var expressionType = statement.expression.staticType;
@@ -3392,6 +3553,54 @@
     return false;
   }
 
+  /// Verify that mixin classes must have 'Object' as their superclass and that
+  /// they do not have a constructor.
+  ///
+  /// See [CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR],
+  /// [CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT].
+  void _checkForMixinClassErrorCodes(
+      NamedCompilationUnitMember node,
+      List<ClassMember> members,
+      NamedType? superclass,
+      WithClause? withClause) {
+    final element = node.declaredElement;
+    if (element is ClassElementImpl && element.isMixinClass) {
+      // Check that the class does not have a constructor.
+      for (ClassMember member in members) {
+        if (member is ConstructorDeclarationImpl) {
+          if (!member.isSynthetic && member.factoryKeyword == null) {
+            // Report errors on non-trivial generative constructors on mixin
+            // classes.
+            if (!member.isTrivial) {
+              errorReporter.reportErrorForNode(
+                  CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR,
+                  member.returnType,
+                  [element.name]);
+            }
+          }
+        }
+      }
+      // Check that the class has 'Object' as their superclass.
+      final supertype = element.supertype;
+      if (superclass != null &&
+          supertype != null &&
+          !supertype.isDartCoreObject) {
+        errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT,
+          superclass,
+          [element.name],
+        );
+      } else if (withClause != null &&
+          !(element.isMixinApplication && withClause.mixinTypes.length < 2)) {
+        errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT,
+          withClause,
+          [element.name],
+        );
+      }
+    }
+  }
+
   /// Verify that the given mixin has the 'Object' superclass.
   ///
   /// The [mixinName] is the node to report problem on. The [mixinElement] is
@@ -3480,11 +3689,19 @@
           forMixinIndex: mixinIndex, concrete: true, forSuper: true);
 
       if (superMember == null) {
-        errorReporter.reportErrorForNode(
-            CompileTimeErrorCode
-                .MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_MEMBER,
-            mixinName.name,
-            [name]);
+        var isSetter = name.endsWith('=');
+
+        var errorCode = isSetter
+            ? CompileTimeErrorCode
+                .MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_SETTER
+            : CompileTimeErrorCode
+                .MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_MEMBER;
+
+        if (isSetter) {
+          name = name.substring(0, name.length - 1);
+        }
+
+        errorReporter.reportErrorForNode(errorCode, mixinName.name, [name]);
         return true;
       }
 
@@ -3533,10 +3750,12 @@
     bool isConflictingName(
         String name, LibraryElement library, NamedType namedType) {
       if (Identifier.isPrivateName(name)) {
-        Map<String, String> names =
-            mixedInNames.putIfAbsent(library, () => <String, String>{});
+        Map<String, String> names = mixedInNames.putIfAbsent(library, () => {});
         var conflictingName = names[name];
         if (conflictingName != null) {
+          if (name.endsWith('=')) {
+            name = name.substring(0, name.length - 1);
+          }
           errorReporter.reportErrorForNode(
               CompileTimeErrorCode.PRIVATE_COLLISION_IN_MIXIN_APPLICATION,
               namedType,
@@ -3550,6 +3769,9 @@
           concrete: true,
         );
         if (inheritedMember != null) {
+          if (name.endsWith('=')) {
+            name = name.substring(0, name.length - 1);
+          }
           // Inherited members are always contained inside named elements, so we
           // can safely assume `inheritedMember.enclosingElement3.name` is
           // non-`null`.
@@ -3965,7 +4187,7 @@
   ///
   /// If e is -n and n is an integer literal, then
   ///   - If the context type is double, it is a compile-time error if the
-  ///   numerical value of n is not precisley representable by a double.
+  ///   numerical value of n is not precisely representable by a double.
   ///   Otherwise the static type of e is double and the result of evaluating e
   ///   is the result of calling the unary minus operator on a double instance
   ///   representing the numerical value of n.
@@ -4198,60 +4420,39 @@
   ///
   /// See [CompileTimeErrorCode.SEALED_CLASS_SUBTYPE_OUTSIDE_OF_LIBRARY],
   /// [CompileTimeErrorCode.SEALED_MIXIN_SUBTYPE_OUTSIDE_OF_LIBRARY].
-  void _checkForSealedSupertypeOutsideOfLibrary(
-      NamedCompilationUnitMember node,
-      NamedType? superclass,
-      WithClause? withClause,
-      ImplementsClause? implementsClause) {
-    void reportSealedClassOrMixinSubtypeOutsideOfLibraryError(
-        ClassOrMixinElementImpl superclass) {
-      if (superclass.isSealed && superclass.library != _currentLibrary) {
-        if (superclass is MixinElementImpl) {
-          errorReporter.reportErrorForNode(
-              CompileTimeErrorCode.SEALED_MIXIN_SUBTYPE_OUTSIDE_OF_LIBRARY,
-              node,
-              [superclass.name]);
-        } else {
-          errorReporter.reportErrorForNode(
-              CompileTimeErrorCode.SEALED_CLASS_SUBTYPE_OUTSIDE_OF_LIBRARY,
-              node,
-              [superclass.name]);
+  void _checkForSealedSupertypeOutsideOfLibrary(NamedType? superclass,
+      WithClause? withClause, ImplementsClause? implementsClause) {
+    void reportErrorsForSealedClassesAndMixins(List<NamedType> namedTypes) {
+      for (NamedType namedType in namedTypes) {
+        final type = namedType.type;
+        if (type is InterfaceType) {
+          final element = type.element;
+          if (element is ClassOrMixinElementImpl &&
+              element.isSealed &&
+              element.library != _currentLibrary) {
+            final ErrorCode errorCode;
+            if (element is MixinElementImpl) {
+              errorCode =
+                  CompileTimeErrorCode.SEALED_MIXIN_SUBTYPE_OUTSIDE_OF_LIBRARY;
+            } else {
+              errorCode =
+                  CompileTimeErrorCode.SEALED_CLASS_SUBTYPE_OUTSIDE_OF_LIBRARY;
+            }
+            errorReporter
+                .reportErrorForNode(errorCode, namedType, [element.name]);
+          }
         }
       }
     }
 
     if (superclass != null) {
-      final superclassType = superclass.type;
-      if (superclassType is InterfaceType) {
-        final superclassElement = superclassType.element;
-        if (superclassElement is ClassElementImpl) {
-          reportSealedClassOrMixinSubtypeOutsideOfLibraryError(
-              superclassElement);
-        }
-      }
+      reportErrorsForSealedClassesAndMixins([superclass]);
     }
     if (withClause != null) {
-      for (NamedType withMixin in withClause.mixinTypes) {
-        final withType = withMixin.type;
-        if (withType is InterfaceType) {
-          final withElement = withType.element;
-          if (withElement is ClassOrMixinElementImpl) {
-            reportSealedClassOrMixinSubtypeOutsideOfLibraryError(withElement);
-          }
-        }
-      }
+      reportErrorsForSealedClassesAndMixins(withClause.mixinTypes);
     }
     if (implementsClause != null) {
-      for (NamedType interface in implementsClause.interfaces) {
-        final interfaceType = interface.type;
-        if (interfaceType is InterfaceType) {
-          final interfaceElement = interfaceType.element;
-          if (interfaceElement is ClassElementImpl) {
-            reportSealedClassOrMixinSubtypeOutsideOfLibraryError(
-                interfaceElement);
-          }
-        }
-      }
+      reportErrorsForSealedClassesAndMixins(implementsClause.interfaces);
     }
   }
 
@@ -4398,7 +4599,7 @@
           }
           if (step == parameters.length) {
             var element = parameter.declaredElement!;
-            // This error can only occur if there is a bound, so we can saefly
+            // This error can only occur if there is a bound, so we can safely
             // assume `element.bound` is non-`null`.
             errorReporter.reportErrorForToken(
               CompileTimeErrorCode.TYPE_PARAMETER_SUPERTYPE_OF_ITS_BOUND,
@@ -5031,8 +5232,9 @@
         CompileTimeErrorCode.IMPLEMENTS_REPEATED,
       );
       _checkForConflictingGenerics(node);
-      _checkForSealedSupertypeOutsideOfLibrary(
-          node, null, null, implementsClause);
+      _checkForBaseClassOrMixinImplementedOutsideOfLibrary(implementsClause);
+      _checkForFinalSupertypeOutsideOfLibrary(null, null, implementsClause);
+      _checkForSealedSupertypeOutsideOfLibrary(null, null, implementsClause);
     }
   }
 
diff --git a/analyzer/lib/src/generated/exhaustiveness.dart b/analyzer/lib/src/generated/exhaustiveness.dart
new file mode 100644
index 0000000..4140958
--- /dev/null
+++ b/analyzer/lib/src/generated/exhaustiveness.dart
@@ -0,0 +1,260 @@
+// 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:_fe_analyzer_shared/src/exhaustiveness/space.dart';
+import 'package:_fe_analyzer_shared/src/exhaustiveness/static_type.dart';
+import 'package:_fe_analyzer_shared/src/exhaustiveness/static_types.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type_system.dart';
+import 'package:analyzer/src/generated/constant.dart';
+
+Space convertConstantValueToSpace(
+    AnalyzerExhaustivenessCache cache, DartObjectImpl? constantValue) {
+  if (constantValue != null) {
+    InstanceState state = constantValue.state;
+    if (constantValue.isNull) {
+      return Space.nullSpace;
+    } else if (state is BoolState && state.value != null) {
+      return Space(cache.getBoolValueStaticType(state.value!));
+    }
+    DartType type = constantValue.type;
+    if (type is InterfaceType && type.element.kind == ElementKind.ENUM) {
+      return Space(cache.getEnumElementStaticType(
+          type.element as EnumElement, constantValue));
+    }
+    return Space(cache.getUniqueStaticType(
+        type, constantValue, constantValue.toString()));
+  }
+  // TODO(johnniwinther): Assert that constant value is available when the
+  // exhaustiveness checking is complete.
+  return Space(cache.getUnknownStaticType());
+}
+
+Space convertPatternToSpace(
+    AnalyzerExhaustivenessCache cache,
+    DartPattern pattern,
+    Map<ConstantPattern, DartObjectImpl> constantPatternValues) {
+  if (pattern is DeclaredVariablePatternImpl) {
+    DartType type = pattern.declaredElement!.type;
+    return Space(cache.getStaticType(type));
+  } else if (pattern is ObjectPattern) {
+    Map<String, Space> fields = {};
+    for (PatternField field in pattern.fields) {
+      PatternFieldName? fieldName = field.name;
+      String? name;
+      if (fieldName?.name != null) {
+        name = fieldName!.name!.lexeme;
+      } else {
+        name = field.element?.name;
+      }
+      if (name == null) {
+        // TODO(johnniwinther): How do we handle error cases?
+        continue;
+      }
+      fields[name] =
+          convertPatternToSpace(cache, field.pattern, constantPatternValues);
+    }
+    return Space(cache.getStaticType(pattern.type.type!), fields);
+  }
+  // TODO(johnniwinther): Handle remaining patterns.
+  DartObjectImpl? value = constantPatternValues[pattern];
+  return convertConstantValueToSpace(cache, value);
+}
+
+class AnalyzerEnumOperations
+    implements EnumOperations<DartType, EnumElement, FieldElement, DartObject> {
+  const AnalyzerEnumOperations();
+
+  @override
+  EnumElement? getEnumClass(DartType type) {
+    Element? element = type.element;
+    if (element is EnumElement) {
+      return element;
+    }
+    return null;
+  }
+
+  @override
+  String getEnumElementName(FieldElement enumField) {
+    return '${enumField.enclosingElement.name}.${enumField.name}';
+  }
+
+  @override
+  Iterable<FieldElement> getEnumElements(EnumElement enumClass) sync* {
+    for (FieldElement field in enumClass.fields) {
+      if (field.isEnumConstant) {
+        yield field;
+      }
+    }
+  }
+
+  @override
+  InterfaceType getEnumElementType(FieldElement enumField) {
+    return enumField.type as InterfaceType;
+  }
+
+  @override
+  DartObject getEnumElementValue(FieldElement enumField) {
+    return enumField.computeConstantValue()!;
+  }
+}
+
+class AnalyzerExhaustivenessCache extends ExhaustivenessCache<DartType,
+    ClassElement, EnumElement, FieldElement, DartObject> {
+  AnalyzerExhaustivenessCache(TypeSystemImpl typeSystem)
+      : super(
+            AnalyzerTypeOperations(typeSystem),
+            const AnalyzerEnumOperations(),
+            const AnalyzerSealedClassOperations());
+}
+
+class AnalyzerSealedClassOperations
+    implements SealedClassOperations<DartType, ClassElement> {
+  const AnalyzerSealedClassOperations();
+
+  @override
+  List<ClassElement> getDirectSubclasses(ClassElement sealedClass) {
+    List<ClassElement> subclasses = [];
+    LibraryElement library = sealedClass.library;
+    for (Element declaration in library.topLevelElements) {
+      if (declaration != sealedClass && declaration is ClassElement) {
+        for (InterfaceType supertype in declaration.allSupertypes) {
+          if (supertype.element == sealedClass) {
+            subclasses.add(declaration);
+            break;
+          }
+        }
+      }
+    }
+    return subclasses;
+  }
+
+  @override
+  ClassElement? getSealedClass(DartType type) {
+    Element? element = type.element;
+    if (element is ClassElementImpl && element.isSealed) {
+      return element;
+    }
+    return null;
+  }
+
+  @override
+  DartType? getSubclassAsInstanceOf(
+      ClassElement subClass, DartType sealedClassType) {
+    // TODO(johnniwinther): Handle generic types.
+    return subClass.thisType;
+  }
+}
+
+class AnalyzerTypeOperations implements TypeOperations<DartType> {
+  final TypeSystemImpl _typeSystem;
+
+  final Map<InterfaceType, Map<String, DartType>> _interfaceFieldTypesCaches =
+      {};
+
+  AnalyzerTypeOperations(this._typeSystem);
+
+  @override
+  DartType get boolType => _typeSystem.typeProvider.boolType;
+
+  @override
+  DartType get nullableObjectType => _typeSystem.objectQuestion;
+
+  @override
+  Map<String, DartType> getFieldTypes(DartType type) {
+    if (type is InterfaceType) {
+      return _getInterfaceFieldTypes(type);
+    } else if (type is RecordType) {
+      Map<String, DartType> fieldTypes = {};
+      for (int index = 0; index < type.positionalFields.length; index++) {
+        RecordTypePositionalField field = type.positionalFields[index];
+        fieldTypes['\$$index'] = field.type;
+      }
+      for (RecordTypeNamedField field in type.namedFields) {
+        fieldTypes[field.name] = field.type;
+      }
+      return fieldTypes;
+    }
+    return const {};
+  }
+
+  @override
+  DartType getNonNullable(DartType type) {
+    return _typeSystem.promoteToNonNull(type);
+  }
+
+  @override
+  bool isBoolType(DartType type) {
+    return type.isDartCoreBool && !isNullable(type);
+  }
+
+  @override
+  bool isNeverType(DartType type) {
+    return type is NeverType;
+  }
+
+  @override
+  bool isNonNullableObject(DartType type) {
+    return type.isDartCoreObject && !isNullable(type);
+  }
+
+  @override
+  bool isNullable(DartType type) {
+    return type.nullabilitySuffix == NullabilitySuffix.question;
+  }
+
+  @override
+  bool isNullableObject(DartType type) {
+    return type.isDartCoreObject && isNullable(type);
+  }
+
+  @override
+  bool isNullType(DartType type) {
+    return type.isDartCoreNull;
+  }
+
+  @override
+  bool isSubtypeOf(DartType s, DartType t) {
+    return _typeSystem.isSubtypeOf(s, t);
+  }
+
+  @override
+  String typeToString(DartType type) => type.toString();
+
+  Map<String, DartType> _getInterfaceFieldTypes(InterfaceType type) {
+    Map<String, DartType>? fieldTypes = _interfaceFieldTypesCaches[type];
+    if (fieldTypes == null) {
+      _interfaceFieldTypesCaches[type] = fieldTypes = {};
+      for (InterfaceType supertype in type.allSupertypes) {
+        fieldTypes.addAll(_getInterfaceFieldTypes(supertype));
+      }
+      for (PropertyAccessorElement accessor in type.accessors) {
+        if (accessor.isGetter && !accessor.isStatic) {
+          fieldTypes[accessor.name] = accessor.type.returnType;
+        }
+      }
+    }
+    return fieldTypes;
+  }
+}
+
+/// Data gathered by the exhaustiveness computation, retained for testing
+/// purposes.
+class ExhaustivenessDataForTesting {
+  /// Map from switch statement/expression nodes to the static type of the
+  /// scrutinee.
+  Map<AstNode, StaticType> switchScrutineeType = {};
+
+  /// Map from switch case nodes to the space for its pattern/expression.
+  Map<AstNode, Space> caseSpaces = {};
+
+  /// Map from switch case nodes to the remaining space before the case or
+  /// from statement/expression nodes to the remaining space after all cases.
+  Map<AstNode, Space> remainingSpaces = {};
+}
diff --git a/analyzer/lib/src/generated/ffi_verifier.dart b/analyzer/lib/src/generated/ffi_verifier.dart
index efea28a..8933ca0 100644
--- a/analyzer/lib/src/generated/ffi_verifier.dart
+++ b/analyzer/lib/src/generated/ffi_verifier.dart
@@ -13,6 +13,7 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/error/ffi_code.dart';
+import 'package:analyzer/src/utilities/legacy.dart';
 
 /// A visitor used to find problems with the way the `dart:ffi` APIs are being
 /// used. See 'pkg/vm/lib/transformations/ffi_checks.md' for the specification
@@ -172,7 +173,9 @@
 
   @override
   void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
-    if (!typeSystem.isNonNullableByDefault && inCompound) {
+    if (!noSoundNullSafety &&
+        !typeSystem.isNonNullableByDefault &&
+        inCompound) {
       _errorReporter.reportErrorForNode(
         FfiCode.FIELD_INITIALIZER_IN_STRUCT,
         node,
@@ -496,7 +499,8 @@
         return false;
       }
 
-      for (final DartType typeArg in nativeType.normalParameterTypes) {
+      for (final DartType typeArg
+          in nativeType.normalParameterTypes.flattenVarArgs()) {
         if (!_isValidFfiNativeType(typeArg,
             allowVoid: false, allowEmptyStruct: false, allowHandle: true)) {
           return false;
@@ -825,9 +829,12 @@
       return false;
     }
 
+    final nativeTypeNormalParameterTypes =
+        nativeType.normalParameterTypes.flattenVarArgs();
+
     // We disallow any optional parameters.
     final int parameterCount = dartType.normalParameterTypes.length;
-    if (parameterCount != nativeType.normalParameterTypes.length) {
+    if (parameterCount != nativeTypeNormalParameterTypes.length) {
       return false;
     }
     // We disallow generic function types.
@@ -859,7 +866,7 @@
     for (int i = 0; i < parameterCount; ++i) {
       if (!_validateCompatibleNativeType(
         dartType.normalParameterTypes[i],
-        nativeType.normalParameterTypes[i],
+        nativeTypeNormalParameterTypes[i],
         checkCovariance: true,
         nativeFieldWrappersAsPointer: nativeFieldWrappersAsPointer,
       )) {
@@ -1022,7 +1029,7 @@
       }
     }
 
-    if (!typeSystem.isNonNullableByDefault) {
+    if (!noSoundNullSafety && !typeSystem.isNonNullableByDefault) {
       for (VariableDeclaration field in fields.variables) {
         if (field.initializer != null) {
           _errorReporter.reportErrorForToken(
@@ -1666,6 +1673,16 @@
     final self = this;
     return self is InterfaceType && self.element.isPointer;
   }
+
+  /// Returns `true` iff this is a `ffi.VarArgs` type.
+  bool get isVarArgs {
+    final self = this;
+    if (self is InterfaceType) {
+      final element = self.element;
+      return element.name == 'VarArgs' && element.isFfiClass;
+    }
+    return false;
+  }
 }
 
 extension on NamedType {
@@ -1692,3 +1709,34 @@
     return false;
   }
 }
+
+extension on List<DartType> {
+  /// Removes the VarArgs from a DartType list.
+  ///
+  /// ```
+  /// [Int8, Int8] -> [Int8, Int8]
+  /// [Int8, VarArgs<(Int8,)>] -> [Int8, Int8]
+  /// [Int8, VarArgs<(Int8, Int8)>] -> [Int8, Int8, Int8]
+  /// ```
+  List<DartType> flattenVarArgs() {
+    if (isEmpty) {
+      return this;
+    }
+    final last = this.last;
+    if (!last.isVarArgs) {
+      return this;
+    }
+    final typeArgument = (last as InterfaceType).typeArguments.single;
+    if (typeArgument is! RecordType) {
+      return this;
+    }
+    if (typeArgument.namedFields.isNotEmpty) {
+      // Don't flatten if invalid record.
+      return this;
+    }
+    return [
+      ...take(length - 1),
+      for (final field in typeArgument.positionalFields) field.type,
+    ];
+  }
+}
diff --git a/analyzer/lib/src/generated/parser.dart b/analyzer/lib/src/generated/parser.dart
index f11abec..43b6dc3 100644
--- a/analyzer/lib/src/generated/parser.dart
+++ b/analyzer/lib/src/generated/parser.dart
@@ -190,8 +190,10 @@
 
   Expression parsePrimaryExpression() {
     currentToken = fastaParser
-        .parsePrimary(fastaParser.syntheticPreviousToken(currentToken),
-            fasta.IdentifierContext.expression)
+        .parsePrimary(
+            fastaParser.syntheticPreviousToken(currentToken),
+            fasta.IdentifierContext.expression,
+            fasta.ConstantPatternContext.none)
         .next!;
     return astBuilder.pop() as Expression;
   }
diff --git a/analyzer/lib/src/generated/resolver.dart b/analyzer/lib/src/generated/resolver.dart
index 6d49618..de8704e 100644
--- a/analyzer/lib/src/generated/resolver.dart
+++ b/analyzer/lib/src/generated/resolver.dart
@@ -9,7 +9,7 @@
 import 'package:_fe_analyzer_shared/src/type_inference/type_analysis_result.dart'
     as shared;
 import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer.dart'
-    hide NamedType, RecordPatternField, RecordType;
+    hide NamedType, RecordType;
 import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer.dart'
     as shared;
 import 'package:_fe_analyzer_shared/src/type_inference/type_operations.dart'
@@ -41,7 +41,6 @@
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/element/type_schema.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
-import 'package:analyzer/src/dart/error/inference_error_listener.dart';
 import 'package:analyzer/src/dart/resolver/annotation_resolver.dart';
 import 'package:analyzer/src/dart/resolver/assignment_expression_resolver.dart';
 import 'package:analyzer/src/dart/resolver/binary_expression_resolver.dart';
@@ -95,8 +94,8 @@
 typedef SharedMatchContext = shared.MatchContext<AstNode, Expression,
     DartPattern, DartType, PromotableElement>;
 
-typedef SharedRecordPatternField
-    = shared.RecordPatternField<RecordPatternFieldImpl, DartPatternImpl>;
+typedef SharedPatternField
+    = shared.RecordPatternField<PatternFieldImpl, DartPatternImpl>;
 
 /// A function which returns [NonPromotionReason]s that various types are not
 /// promoted.
@@ -181,12 +180,6 @@
   @override
   final ErrorReporter errorReporter;
 
-  /// The [InferenceErrorListener] to which inference errors should be reported,
-  /// or `null` if such errors shouldn't be reported.
-  ///
-  /// If `null`, errors will still be reported to [errorReporter].
-  final InferenceErrorListener? inferenceErrorListener;
-
   /// The class containing the AST nodes being visited,
   /// or `null` if we are not in the scope of a class.
   InterfaceElement? enclosingClass;
@@ -334,8 +327,7 @@
       TypeProvider typeProvider,
       AnalysisErrorListener errorListener,
       {FeatureSet? featureSet,
-      required FlowAnalysisHelper flowAnalysisHelper,
-      InferenceErrorListener? inferenceErrorListener})
+      required FlowAnalysisHelper flowAnalysisHelper})
       : this._(
             inheritanceManager,
             definingLibrary,
@@ -343,7 +335,6 @@
             definingLibrary.typeSystem,
             typeProvider as TypeProviderImpl,
             errorListener,
-            inferenceErrorListener,
             featureSet ??
                 definingLibrary.context.analysisOptions.contextFeatures,
             flowAnalysisHelper,
@@ -357,7 +348,6 @@
       this.typeSystem,
       this.typeProvider,
       AnalysisErrorListener errorListener,
-      this.inferenceErrorListener,
       FeatureSet featureSet,
       this.flowAnalysis,
       this._migratableAstInfoProvider,
@@ -458,6 +448,9 @@
   ExecutableElement? get enclosingFunction => _enclosingFunction;
 
   @override
+  DartType get errorType => typeProvider.dynamicType;
+
+  @override
   FlowAnalysis<AstNode, Statement, Expression, PromotableElement, DartType>
       get flow => flowAnalysis.flow!;
 
@@ -522,12 +515,12 @@
     return null;
   }
 
-  List<SharedRecordPatternField> buildSharedRecordPatternFields(
-    List<RecordPatternFieldImpl> fields,
+  List<SharedPatternField> buildSharedPatternFields(
+    List<PatternFieldImpl> fields,
   ) {
     return fields.map((field) {
       Token? nameToken;
-      var fieldName = field.fieldName;
+      var fieldName = field.name;
       if (fieldName != null) {
         nameToken = fieldName.name;
         if (nameToken == null) {
@@ -600,7 +593,7 @@
         // use the result of that check to determine whether this check should
         // be done.
         var lowerBound = typeProvider.futureElement.instantiate(
-          typeArguments: [NeverTypeImpl.instance],
+          typeArguments: fixedTypeList(NeverTypeImpl.instance),
           nullabilitySuffix: NullabilitySuffix.star,
         );
         var imposedType = bodyContext.imposedType;
@@ -622,7 +615,7 @@
             returnTypeBase.isDartCoreNull) {
           return;
         } else {
-          errorCode = HintCode.BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE;
+          errorCode = WarningCode.BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE;
         }
       }
       if (errorNode is ConstructorDeclaration) {
@@ -782,7 +775,22 @@
         _replacements[expression] ?? expression, replacementExpression));
     var staticType = replacementExpression.staticType;
     if (staticType == null) {
-      assert(replacementExpression is ExtensionOverride);
+      var shouldHaveType = true;
+      if (replacementExpression is ExtensionOverride) {
+        shouldHaveType = false;
+      } else if (replacementExpression is IdentifierImpl) {
+        var element = replacementExpression.staticElement;
+        if (element is ExtensionElement || element is InterfaceElement) {
+          shouldHaveType = false;
+        }
+      }
+      if (shouldHaveType) {
+        assert(
+          false,
+          'No static type for: '
+          '(${replacementExpression.runtimeType}) $replacementExpression',
+        );
+      }
       staticType = unknownType;
     }
     return SimpleTypeAnalysisResult<DartType>(type: staticType);
@@ -791,6 +799,7 @@
   @override
   void dispatchPattern(SharedMatchContext context, AstNode node) {
     if (node is DartPatternImpl) {
+      node.matchedValueType = flow.getMatchedValueType();
       node.resolvePattern(this, context);
     } else {
       // This can occur inside conventional switch statements, since
@@ -860,12 +869,15 @@
     covariant SwitchExpressionImpl node,
     int caseIndex,
   ) {
-    node.cases[caseIndex].expression = popRewrite()!;
+    final case_ = node.cases[caseIndex];
+    case_.expression = popRewrite()!;
+    nullSafetyDeadCodeVerifier.flowEnd(case_);
   }
 
   @override
   void finishJoinedPatternVariable(
-    covariant VariablePatternJoinElementImpl variable, {
+    covariant JoinPatternVariableElementImpl variable, {
+    required JoinedPatternVariableLocation location,
     required bool isConsistent,
     required bool isFinal,
     required DartType type,
@@ -873,16 +885,19 @@
     variable.isConsistent &= isConsistent;
     variable.isFinal = isFinal;
     variable.type = type;
-    flow.declare(variable, true);
-  }
 
-  @override
-  List<PromotableElement>? getJoinedVariableComponents(
-      PromotableElement variable) {
-    if (variable is VariablePatternJoinElementImpl) {
-      return variable.components;
+    if (location == JoinedPatternVariableLocation.sharedCaseScope) {
+      for (var reference in variable.references) {
+        if (!variable.isConsistent) {
+          errorReporter.reportErrorForNode(
+            CompileTimeErrorCode
+                .INCONSISTENT_PATTERN_VARIABLE_SHARED_CASE_SCOPE,
+            reference,
+            [variable.name],
+          );
+        }
+      }
     }
-    return null;
   }
 
   @override
@@ -1036,6 +1051,11 @@
   }
 
   @override
+  void handle_logicalOrPattern_afterLhs(covariant LogicalOrPatternImpl node) {
+    checkUnreachableNode(node.rightOperand);
+  }
+
+  @override
   void handleCase_afterCaseHeads(
       AstNode node, int caseIndex, Iterable<PromotableElement> variables) {}
 
@@ -1049,15 +1069,21 @@
     popRewrite(); // "when" expression
     // Stack: ()
     if (node is SwitchStatementImpl) {
-      legacySwitchExhaustiveness
-          ?.visitSwitchMember(node.memberGroups[caseIndex]);
+      final group = node.memberGroups[caseIndex];
+      legacySwitchExhaustiveness?.visitSwitchMember(group);
+      nullSafetyDeadCodeVerifier.flowEnd(group.members[subIndex]);
     }
-    // TODO(scheglov) Exhaustiveness for SwitchExpressions?
   }
 
   @override
-  void handleDefault(covariant SwitchStatementImpl node, int caseIndex) {
-    legacySwitchExhaustiveness?.visitSwitchMember(node.memberGroups[caseIndex]);
+  void handleDefault(
+    covariant SwitchStatementImpl node, {
+    required int caseIndex,
+    required int subIndex,
+  }) {
+    final group = node.memberGroups[caseIndex];
+    legacySwitchExhaustiveness?.visitSwitchMember(group);
+    nullSafetyDeadCodeVerifier.flowEnd(group.members[subIndex]);
   }
 
   @override
@@ -1103,6 +1129,21 @@
   void handleNoStatement(Statement node) {}
 
   @override
+  void handleSwitchBeforeAlternative(
+    covariant AstNodeImpl node, {
+    required int caseIndex,
+    required int subIndex,
+  }) {
+    if (node is SwitchExpressionImpl) {
+      final case_ = node.cases[caseIndex];
+      checkUnreachableNode(case_);
+    } else if (node is SwitchStatementImpl) {
+      final member = node.memberGroups[caseIndex].members[subIndex];
+      checkUnreachableNode(member);
+    }
+  }
+
+  @override
   void handleSwitchScrutinee(DartType type) {
     if (!options.patternsEnabled) {
       legacySwitchExhaustiveness = SwitchExhaustiveness(type);
@@ -1167,24 +1208,7 @@
 
   @override
   bool isAlwaysExhaustiveType(DartType type) {
-    if (type is InterfaceType) {
-      if (type.isDartCoreBool) return true;
-      if (type.isDartCoreNull) return true;
-      var element = type.element;
-      if (element is EnumElement) return true;
-      // TODO(paulberry): return `true` if `element` is a sealed class
-      if (type.isDartAsyncFutureOr) {
-        return isAlwaysExhaustiveType(type.typeArguments[0]);
-      }
-      return false;
-    } else if (type is RecordType) {
-      for (var field in type.fields) {
-        if (!isAlwaysExhaustiveType(field.type)) return false;
-      }
-      return true;
-    } else {
-      return false;
-    }
+    return typeSystem.isAlwaysExhaustive(type);
   }
 
   @override
@@ -1205,6 +1229,11 @@
   bool isVariablePattern(AstNode pattern) => pattern is DeclaredVariablePattern;
 
   @override
+  DartType iterableType(DartType elementType) {
+    return typeProvider.iterableType(elementType);
+  }
+
+  @override
   DartType listType(DartType elementType) {
     return typeProvider.listType(elementType);
   }
@@ -1392,11 +1421,16 @@
   /// Resolve LHS [node] of an assignment, an explicit [AssignmentExpression],
   /// or implicit [PrefixExpression] or [PostfixExpression].
   PropertyElementResolverResult resolveForWrite({
-    required AstNode node,
+    required Expression node,
     required bool hasRead,
   }) {
     if (node is IndexExpression) {
-      node.target?.accept(this);
+      var target = node.target;
+      if (target != null) {
+        analyzeExpression(target, null);
+        popRewrite();
+      }
+
       startNullAwareIndexExpression(node);
 
       var result = _propertyElementResolver.resolveIndexExpression(
@@ -1465,7 +1499,8 @@
 
       return result;
     } else {
-      node.accept(this);
+      analyzeExpression(node, null);
+      popRewrite();
       return PropertyElementResolverResult();
     }
   }
@@ -1505,10 +1540,10 @@
   @override
   DartType resolveObjectPatternPropertyGet({
     required DartType receiverType,
-    required covariant SharedRecordPatternField field,
+    required covariant SharedPatternField field,
   }) {
     var fieldNode = field.node;
-    var nameToken = fieldNode.fieldName?.name;
+    var nameToken = fieldNode.name?.name;
     nameToken ??= field.pattern.variablePattern?.name;
     if (nameToken == null) {
       errorReporter.reportErrorForNode(
@@ -1536,16 +1571,10 @@
 
     var getter = result.getter;
     if (getter != null) {
-      fieldNode.fieldElement = getter;
+      fieldNode.element = getter;
       if (getter is PropertyAccessorElement) {
         return getter.returnType;
       } else {
-        // TODO(scheglov) https://github.com/dart-lang/language/issues/2561
-        errorReporter.reportErrorForToken(
-          CompileTimeErrorCode.UNDEFINED_GETTER,
-          nameToken,
-          [nameToken.lexeme, receiverType],
-        );
         return getter.type;
       }
     }
@@ -1564,8 +1593,18 @@
     DartType matchedType,
   ) {
     var operatorLexeme = node.operator.lexeme;
-    var isEquality = const {'==', '!='}.contains(operatorLexeme);
-    var methodName = isEquality ? '==' : operatorLexeme;
+    RelationalOperatorKind kind;
+    String methodName;
+    if (operatorLexeme == '==') {
+      kind = RelationalOperatorKind.equals;
+      methodName = '==';
+    } else if (operatorLexeme == '!=') {
+      kind = RelationalOperatorKind.notEquals;
+      methodName = '==';
+    } else {
+      kind = RelationalOperatorKind.other;
+      methodName = operatorLexeme;
+    }
 
     var result = typePropertyResolver.resolve(
       receiver: null,
@@ -1596,7 +1635,7 @@
     }
 
     return RelationalOperatorResolution(
-      isEquality: isEquality,
+      kind: kind,
       parameterType: parameterType,
       returnType: element.returnType,
     );
@@ -1717,6 +1756,11 @@
     }
   }
 
+  @override
+  DartType streamType(DartType elementType) {
+    return typeProvider.streamType(elementType);
+  }
+
   /// Returns the result of an implicit `this.` lookup for the identifier string
   /// [id] in a getter context, or `null` if no match was found.
   LexicalLookupResult? thisLookupGetter(SimpleIdentifier node) {
@@ -1781,11 +1825,18 @@
   }
 
   @override
-  void visitAsExpression(AsExpression node, {DartType? contextType}) {
+  void visitAsExpression(
+    covariant AsExpressionImpl node, {
+    DartType? contextType,
+  }) {
     checkUnreachableNode(node);
-    node.visitChildren(this);
-    typeAnalyzer.visitAsExpression(node as AsExpressionImpl,
-        contextType: contextType);
+
+    analyzeExpression(node.expression, null);
+    popRewrite();
+
+    node.type.accept(this);
+
+    typeAnalyzer.visitAsExpression(node, contextType: contextType);
     flowAnalysis.asExpression(node);
     _insertImplicitCallReference(
         insertGenericFunctionInstantiation(node, contextType: contextType),
@@ -2530,12 +2581,15 @@
   }
 
   @override
-  void visitFunctionExpressionInvocation(FunctionExpressionInvocation node,
-      {DartType? contextType}) {
+  void visitFunctionExpressionInvocation(
+    covariant FunctionExpressionInvocationImpl node, {
+    DartType? contextType,
+  }) {
+    analyzeExpression(node.function, null);
+    node.function = popRewrite()!;
+
     var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
-    node.function.accept(this);
-    _functionExpressionInvocationResolver.resolve(
-        node as FunctionExpressionInvocationImpl, whyNotPromotedList,
+    _functionExpressionInvocationResolver.resolve(node, whyNotPromotedList,
         contextType: contextType);
     nullShortingTermination(node);
     var replacement =
@@ -2592,6 +2646,7 @@
         node: node,
         expression: node.expression,
         pattern: guardedPattern.pattern,
+        variables: guardedPattern.variables,
         guard: guardedPattern.whenClause?.expression,
         ifTrue: node.thenElement,
         ifFalse: node.elseElement,
@@ -2666,7 +2721,13 @@
   void visitIndexExpression(covariant IndexExpressionImpl node,
       {DartType? contextType}) {
     checkUnreachableNode(node);
-    node.target?.accept(this);
+
+    var target = node.target;
+    if (target != null) {
+      analyzeExpression(target, null);
+      popRewrite();
+    }
+
     startNullAwareIndexExpression(node);
 
     var result = _propertyElementResolver.resolveIndexExpression(
@@ -2735,11 +2796,18 @@
   }
 
   @override
-  void visitIsExpression(IsExpression node, {DartType? contextType}) {
+  void visitIsExpression(
+    covariant IsExpressionImpl node, {
+    DartType? contextType,
+  }) {
     checkUnreachableNode(node);
-    node.visitChildren(this);
-    typeAnalyzer.visitIsExpression(node as IsExpressionImpl,
-        contextType: contextType);
+
+    analyzeExpression(node.expression, null);
+    popRewrite();
+
+    node.type.accept(this);
+
+    typeAnalyzer.visitIsExpression(node, contextType: contextType);
     flowAnalysis.isExpression(node);
   }
 
@@ -2968,9 +3036,22 @@
   @override
   void visitPatternAssignment(covariant PatternAssignmentImpl node) {
     checkUnreachableNode(node);
-    node.staticType =
-        analyzePatternAssignment(node, node.pattern, node.expression)
-            .resolveShorting();
+    final analysisResult =
+        analyzePatternAssignment(node, node.pattern, node.expression);
+    node.patternTypeSchema = analysisResult.patternSchema;
+    node.staticType = analysisResult.resolveShorting();
+    popRewrite(); // expression
+  }
+
+  @override
+  void visitPatternVariableDeclaration(
+    covariant PatternVariableDeclarationImpl node,
+  ) {
+    // TODO(scheglov) Support for `late` was removed.
+    final patternSchema = analyzePatternVariableDeclaration(
+        node, node.pattern, node.expression,
+        isFinal: node.keyword.keyword == Keyword.FINAL, isLate: false);
+    node.patternTypeSchema = patternSchema;
     popRewrite(); // expression
   }
 
@@ -2978,12 +3059,7 @@
   void visitPatternVariableDeclarationStatement(
       PatternVariableDeclarationStatement node) {
     checkUnreachableNode(node);
-    var declaration = node.declaration;
-    // TODO(scheglov) Support for `late` was removed.
-    analyzePatternVariableDeclarationStatement(
-        node, declaration.pattern, declaration.expression,
-        isFinal: declaration.keyword.keyword == Keyword.FINAL, isLate: false);
-    popRewrite(); // expression
+    node.declaration.accept(this);
   }
 
   @override
@@ -3025,7 +3101,13 @@
   void visitPropertyAccess(covariant PropertyAccessImpl node,
       {DartType? contextType}) {
     checkUnreachableNode(node);
-    node.target?.accept(this);
+
+    var target = node.target;
+    if (target != null) {
+      analyzeExpression(target, null);
+      popRewrite();
+    }
+
     startNullAwarePropertyAccess(node);
 
     var result = _propertyElementResolver.resolvePropertyAccess(
@@ -3262,6 +3344,15 @@
   }
 
   @override
+  void visitSwitchExpression(
+    covariant SwitchExpressionImpl node, {
+    DartType? contextType,
+  }) {
+    analyzeExpression(node, contextType);
+    popRewrite();
+  }
+
+  @override
   void visitSwitchStatement(covariant SwitchStatementImpl node) {
     // Stack: ()
     checkUnreachableNode(node);
@@ -3476,7 +3567,7 @@
         }
 
         errorReporter.reportErrorForToken(
-          HintCode.BODY_MIGHT_COMPLETE_NORMALLY_CATCH_ERROR,
+          WarningCode.BODY_MIGHT_COMPLETE_NORMALLY_CATCH_ERROR,
           errorNode.block.leftBracket,
           [returnTypeBase],
         );
@@ -3498,27 +3589,10 @@
     if (error == null) {
       return;
     }
-    switch (error.kind) {
-      case TopLevelInferenceErrorKind.none:
-        break;
-      case TopLevelInferenceErrorKind.couldNotInfer:
-        errorReporter.reportErrorForToken(
-            CompileTimeErrorCode.COULD_NOT_INFER, node.name, error.arguments);
-        break;
-      case TopLevelInferenceErrorKind.dependencyCycle:
-        var argumentsText = error.arguments.join(', ');
-        errorReporter.reportErrorForToken(CompileTimeErrorCode.TOP_LEVEL_CYCLE,
-            node.name, [node.name.lexeme, argumentsText]);
-        break;
-      case TopLevelInferenceErrorKind.inferenceFailureOnInstanceCreation:
-        errorReporter.reportErrorForToken(
-            HintCode.INFERENCE_FAILURE_ON_INSTANCE_CREATION,
-            node.name,
-            error.arguments);
-        break;
-      case TopLevelInferenceErrorKind.overrideNoCombinedSuperSignature:
-        // TODO: Handle this case.
-        break;
+    if (error.kind == TopLevelInferenceErrorKind.dependencyCycle) {
+      var argumentsText = error.arguments.join(', ');
+      errorReporter.reportErrorForToken(CompileTimeErrorCode.TOP_LEVEL_CYCLE,
+          node.name, [node.name.lexeme, argumentsText]);
     }
   }
 
@@ -3550,11 +3624,6 @@
     var inferrer = GenericInferrer(
       typeSystem,
       typeParameters,
-      inferenceErrorListener: InferenceErrorReporter(
-        errorReporter,
-        isNonNullableByDefault: typeSystem.isNonNullableByDefault,
-        isGenericMetadataEnabled: genericMetadataIsEnabled,
-      ),
       errorNode: errorNode,
       genericMetadataIsEnabled: genericMetadataIsEnabled,
     );
@@ -3914,7 +3983,6 @@
       Source source,
       TypeProvider typeProvider,
       AnalysisErrorListener errorListener,
-      InferenceErrorListener? inferenceErrorListener,
       TypeSystemImpl typeSystem,
       FeatureSet featureSet,
       MigrationResolutionHooks migrationResolutionHooks)
@@ -3926,7 +3994,6 @@
             typeSystem,
             typeProvider as TypeProviderImpl,
             errorListener,
-            inferenceErrorListener,
             featureSet,
             FlowAnalysisHelperForMigration(
                 typeSystem, migrationResolutionHooks, featureSet),
@@ -4306,6 +4373,23 @@
   }
 
   @override
+  void visitForEachPartsWithPattern(
+    covariant ForEachPartsWithPatternImpl node,
+  ) {
+    //
+    // We visit the iterator before the pattern because the pattern variables
+    // cannot be in scope while visiting the iterator.
+    //
+    node.iterable.accept(this);
+
+    for (var variable in node.variables) {
+      _define(variable);
+    }
+
+    node.pattern.accept(this);
+  }
+
+  @override
   void visitForElement(ForElement node) {
     Scope outerNameScope = nameScope;
     try {
@@ -4545,6 +4629,26 @@
   }
 
   @override
+  void visitGuardedPattern(covariant GuardedPatternImpl node) {
+    var patternVariables = node.variables.values.toList();
+    for (var variable in patternVariables) {
+      _define(variable);
+    }
+
+    node.pattern.accept(this);
+
+    for (var variable in patternVariables) {
+      variable.isVisitingWhenClause = true;
+    }
+
+    node.whenClause?.accept(this);
+
+    for (var variable in patternVariables) {
+      variable.isVisitingWhenClause = false;
+    }
+  }
+
+  @override
   void visitIfElement(covariant IfElementImpl node) {
     _visitIf(node);
   }
@@ -4646,6 +4750,17 @@
   }
 
   @override
+  void visitPatternVariableDeclaration(
+    covariant PatternVariableDeclarationImpl node,
+  ) {
+    for (var variable in node.elements) {
+      _define(variable);
+    }
+
+    super.visitPatternVariableDeclaration(node);
+  }
+
+  @override
   void visitPrefixedIdentifier(PrefixedIdentifier node) {
     // Do not visit the identifier after the `.`, since it is not meant to be
     // looked up in the current scope.
@@ -4694,6 +4809,13 @@
     if (kind == ElementKind.LOCAL_VARIABLE || kind == ElementKind.PARAMETER) {
       node.staticElement = element;
       if (node.inSetterContext()) {
+        if (element is PatternVariableElementImpl &&
+            element.isVisitingWhenClause) {
+          errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.PATTERN_VARIABLE_ASSIGNMENT_INSIDE_GUARD,
+            node,
+          );
+        }
         _localVariableInfo.potentiallyMutatedInScope.add(element);
         if (_enclosingClosure != null &&
             element.enclosingElement != _enclosingClosure) {
@@ -4701,6 +4823,9 @@
         }
       }
     }
+    if (element is JoinPatternVariableElementImpl) {
+      element.references.add(node);
+    }
   }
 
   /// Visit the given statement after it's scope has been created. This is used
@@ -4761,10 +4886,6 @@
             member.expression.accept(this);
           } else if (member is SwitchPatternCaseImpl) {
             _withNameScope(() {
-              var variables = member.guardedPattern.variables;
-              for (var variable in variables.values) {
-                _define(variable);
-              }
               member.guardedPattern.accept(this);
             });
           }
@@ -4859,7 +4980,16 @@
             labelNode,
             [labelNode.name]);
       }
-      return definingScope.node;
+      var node = definingScope.node;
+      if (isContinue &&
+          node is! DoStatement &&
+          node is! ForStatement &&
+          node is! SwitchMember &&
+          node is! WhileStatement) {
+        errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.CONTINUE_LABEL_INVALID, parentNode);
+      }
+      return node;
     }
   }
 
@@ -4870,10 +5000,6 @@
     if (caseClause != null) {
       var guardedPattern = caseClause.guardedPattern;
       _withNameScope(() {
-        var patternVariables = guardedPattern.variables;
-        for (var variable in patternVariables.values) {
-          _define(variable);
-        }
         guardedPattern.accept(this);
         node.ifTrue.accept(this);
       });
diff --git a/analyzer/lib/src/generated/source.dart b/analyzer/lib/src/generated/source.dart
index 80af1a5..ab917f2 100644
--- a/analyzer/lib/src/generated/source.dart
+++ b/analyzer/lib/src/generated/source.dart
@@ -129,7 +129,7 @@
 ///
 /// If the instances that implement this API are the system of record, then they
 /// will typically be unique. In that case, sources that are created that
-/// represent non-existent files must also be retained so that if those files
+/// represent nonexistent files must also be retained so that if those files
 /// are created at a later date the long-lived sources representing those files
 /// will know that they now exist.
 abstract class Source {
diff --git a/analyzer/lib/src/generated/testing/element_factory.dart b/analyzer/lib/src/generated/testing/element_factory.dart
index 7ec58de..4d7405c 100644
--- a/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/analyzer/lib/src/generated/testing/element_factory.dart
@@ -75,6 +75,19 @@
     return element;
   }
 
+  static ClassElementImpl classElement4(String typeName,
+          {bool isBase = false,
+          bool isInterface = false,
+          bool isFinal = false,
+          bool isSealed = false,
+          bool isMixinClass = false}) =>
+      classElement2(typeName)
+        ..isBase = isBase
+        ..isInterface = isInterface
+        ..isFinal = isFinal
+        ..isSealed = isSealed
+        ..isMixinClass = isMixinClass;
+
   static ClassElementImpl classTypeAlias(
       String typeName, InterfaceType superclassType,
       [List<String>? parameterNames]) {
@@ -185,8 +198,9 @@
     return getter;
   }
 
-  static LibraryElementImpl library(
-      AnalysisContext context, String libraryName) {
+  static LibraryElementImpl library(AnalysisContext context, String libraryName,
+      {FeatureSet? featureSet}) {
+    FeatureSet features = featureSet ?? FeatureSet.latestLanguageVersion();
     String fileName = "/$libraryName.dart";
     CompilationUnitElementImpl unit = compilationUnit(
       source: NonExistingSource(fileName, toUri(fileName)),
@@ -197,7 +211,7 @@
       libraryName,
       0,
       libraryName.length,
-      FeatureSet.latestLanguageVersion(),
+      features,
     );
     library.definingCompilationUnit = unit;
     return library;
@@ -250,6 +264,17 @@
     return element;
   }
 
+  static MixinElementImpl mixinElement2(String name,
+          {bool isBase = false,
+          bool isInterface = false,
+          bool isFinal = false,
+          bool isSealed = false}) =>
+      mixinElement(name: name)
+        ..isBase = isBase
+        ..isInterface = isInterface
+        ..isFinal = isFinal
+        ..isSealed = isSealed;
+
   static ParameterElementImpl namedParameter(String name) {
     return ParameterElementImpl(
       name: name,
diff --git a/analyzer/lib/src/generated/testing/test_type_provider.dart b/analyzer/lib/src/generated/testing/test_type_provider.dart
index a8bc5df..5c7f2fb 100644
--- a/analyzer/lib/src/generated/testing/test_type_provider.dart
+++ b/analyzer/lib/src/generated/testing/test_type_provider.dart
@@ -9,6 +9,7 @@
 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/test_utilities/mock_sdk_elements.dart';
+import 'package:analyzer/src/utilities/uri_cache.dart';
 
 /// A type provider that can be used by tests without creating the element model
 /// for the core library.
@@ -65,7 +66,7 @@
 class _MockSourceFactory implements SourceFactory {
   @override
   Source forUri(String uriStr) {
-    var uri = Uri.parse(uriStr);
+    var uri = uriCache.parse(uriStr);
     return _MockSource(uri);
   }
 
diff --git a/analyzer/lib/src/hint/sdk_constraint_extractor.dart b/analyzer/lib/src/hint/sdk_constraint_extractor.dart
index e43c03b..ba7b677 100644
--- a/analyzer/lib/src/hint/sdk_constraint_extractor.dart
+++ b/analyzer/lib/src/hint/sdk_constraint_extractor.dart
@@ -80,7 +80,7 @@
           if (environment is YamlMap) {
             YamlNode? sdk = environment.nodes['sdk'];
             if (sdk is YamlScalar) {
-              _constraintText = sdk.value;
+              _constraintText = sdk.value as String?;
               _constraintOffset = sdk.span.start.offset;
               if (sdk.style == ScalarStyle.SINGLE_QUOTED ||
                   sdk.style == ScalarStyle.DOUBLE_QUOTED) {
diff --git a/analyzer/lib/src/hint/sdk_constraint_verifier.dart b/analyzer/lib/src/hint/sdk_constraint_verifier.dart
index 4e326f2..07f17ad 100644
--- a/analyzer/lib/src/hint/sdk_constraint_verifier.dart
+++ b/analyzer/lib/src/hint/sdk_constraint_verifier.dart
@@ -127,7 +127,7 @@
   void visitAsExpression(AsExpression node) {
     if (checkConstantUpdate2018 && node.inConstantContext) {
       _errorReporter.reportErrorForNode(
-          StaticWarningCode.SDK_VERSION_AS_EXPRESSION_IN_CONST_CONTEXT, node);
+          WarningCode.SDK_VERSION_AS_EXPRESSION_IN_CONST_CONTEXT, node);
     }
     super.visitAsExpression(node);
   }
@@ -138,7 +138,7 @@
       TokenType operatorType = node.operator.type;
       if (operatorType == TokenType.GT_GT_GT) {
         _errorReporter.reportErrorForToken(
-            StaticWarningCode.SDK_VERSION_GT_GT_GT_OPERATOR, node.operator);
+            WarningCode.SDK_VERSION_GT_GT_GT_OPERATOR, node.operator);
       } else if (checkConstantUpdate2018) {
         if ((operatorType == TokenType.AMPERSAND ||
                 operatorType == TokenType.BAR ||
@@ -146,7 +146,7 @@
             node.inConstantContext) {
           if (node.leftOperand.typeOrThrow.isDartCoreBool) {
             _errorReporter.reportErrorForToken(
-                StaticWarningCode.SDK_VERSION_BOOL_OPERATOR_IN_CONST_CONTEXT,
+                WarningCode.SDK_VERSION_BOOL_OPERATOR_IN_CONST_CONTEXT,
                 node.operator,
                 [node.operator.lexeme]);
           }
@@ -162,7 +162,7 @@
 
           if (!primitive(node.leftOperand) || !primitive(node.rightOperand)) {
             _errorReporter.reportErrorForToken(
-                StaticWarningCode.SDK_VERSION_EQ_EQ_OPERATOR_IN_CONST_CONTEXT,
+                WarningCode.SDK_VERSION_EQ_EQ_OPERATOR_IN_CONST_CONTEXT,
                 node.operator);
           }
         }
@@ -175,8 +175,7 @@
   void visitExtensionDeclaration(ExtensionDeclaration node) {
     if (checkExtensionMethods) {
       _errorReporter.reportErrorForToken(
-          StaticWarningCode.SDK_VERSION_EXTENSION_METHODS,
-          node.extensionKeyword);
+          WarningCode.SDK_VERSION_EXTENSION_METHODS, node.extensionKeyword);
     }
     super.visitExtensionDeclaration(node);
   }
@@ -185,7 +184,7 @@
   void visitExtensionOverride(ExtensionOverride node) {
     if (checkExtensionMethods) {
       _errorReporter.reportErrorForNode(
-          StaticWarningCode.SDK_VERSION_EXTENSION_METHODS, node.extensionName);
+          WarningCode.SDK_VERSION_EXTENSION_METHODS, node.extensionName);
     }
     super.visitExtensionOverride(node);
   }
@@ -219,7 +218,7 @@
   void visitIsExpression(IsExpression node) {
     if (checkConstantUpdate2018 && node.inConstantContext) {
       _errorReporter.reportErrorForNode(
-          StaticWarningCode.SDK_VERSION_IS_EXPRESSION_IN_CONST_CONTEXT, node);
+          WarningCode.SDK_VERSION_IS_EXPRESSION_IN_CONST_CONTEXT, node);
     }
     super.visitIsExpression(node);
   }
@@ -228,7 +227,7 @@
   void visitMethodDeclaration(MethodDeclaration node) {
     if (checkTripleShift && node.isOperator && node.name.lexeme == '>>>') {
       _errorReporter.reportErrorForToken(
-          StaticWarningCode.SDK_VERSION_GT_GT_GT_OPERATOR, node.name);
+          WarningCode.SDK_VERSION_GT_GT_GT_OPERATOR, node.name);
     }
     super.visitMethodDeclaration(node);
   }
@@ -237,7 +236,7 @@
   void visitSetOrMapLiteral(SetOrMapLiteral node) {
     if (node.isSet && checkSetLiterals && !_inSetLiteral) {
       _errorReporter.reportErrorForNode(
-          StaticWarningCode.SDK_VERSION_SET_LITERAL, node);
+          WarningCode.SDK_VERSION_SET_LITERAL, node);
     }
     bool wasInSetLiteral = _inSetLiteral;
     _inSetLiteral = true;
@@ -270,12 +269,11 @@
         }
       }
       _errorReporter.reportErrorForNode(
-          StaticWarningCode.SDK_VERSION_ASYNC_EXPORTED_FROM_CORE,
+          WarningCode.SDK_VERSION_ASYNC_EXPORTED_FROM_CORE,
           node,
           [element.name]);
     } else if (checkNnbd && element == _typeProvider.neverType.element) {
-      _errorReporter.reportErrorForNode(
-          StaticWarningCode.SDK_VERSION_NEVER, node);
+      _errorReporter.reportErrorForNode(WarningCode.SDK_VERSION_NEVER, node);
     }
   }
 
@@ -295,7 +293,7 @@
   void _validateUiAsCode(AstNode node) {
     if (checkUiAsCode && !_inUiAsCode) {
       _errorReporter.reportErrorForNode(
-          StaticWarningCode.SDK_VERSION_UI_AS_CODE, node);
+          WarningCode.SDK_VERSION_UI_AS_CODE, node);
     }
   }
 
@@ -307,7 +305,7 @@
         !_inUiAsCode &&
         node.thisOrAncestorOfType<TypedLiteral>()!.isConst) {
       _errorReporter.reportErrorForNode(
-          StaticWarningCode.SDK_VERSION_UI_AS_CODE_IN_CONST_CONTEXT, node);
+          WarningCode.SDK_VERSION_UI_AS_CODE_IN_CONST_CONTEXT, node);
     }
   }
 }
diff --git a/analyzer/lib/src/lint/linter_visitor.dart b/analyzer/lib/src/lint/linter_visitor.dart
index 4d118f6..b027e35 100644
--- a/analyzer/lib/src/lint/linter_visitor.dart
+++ b/analyzer/lib/src/lint/linter_visitor.dart
@@ -12,7 +12,7 @@
 /// Returns `true` if the exception was fully handled, or `false` if
 /// the exception should be rethrown.
 typedef LintRuleExceptionHandler = bool Function(
-    AstNode node, LintRule linter, dynamic exception, StackTrace stackTrace);
+    AstNode node, LintRule linter, Object exception, StackTrace stackTrace);
 
 /// The AST visitor that runs handlers for nodes from the [registry].
 class LinterVisitor implements AstVisitor<void> {
@@ -90,12 +90,6 @@
   }
 
   @override
-  void visitBinaryPattern(BinaryPattern node) {
-    _runSubscriptions(node, registry._forBinaryPattern);
-    node.visitChildren(this);
-  }
-
-  @override
   void visitBlock(Block node) {
     _runSubscriptions(node, registry._forBlock);
     node.visitChildren(this);
@@ -576,6 +570,18 @@
   }
 
   @override
+  void visitLogicalAndPattern(LogicalAndPattern node) {
+    _runSubscriptions(node, registry._forLogicalAndPattern);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitLogicalOrPattern(LogicalOrPattern node) {
+    _runSubscriptions(node, registry._forLogicalOrPattern);
+    node.visitChildren(this);
+  }
+
+  @override
   void visitMapLiteralEntry(MapLiteralEntry node) {
     _runSubscriptions(node, registry._forMapLiteralEntry);
     node.visitChildren(this);
@@ -636,6 +642,18 @@
   }
 
   @override
+  void visitNullAssertPattern(NullAssertPattern node) {
+    _runSubscriptions(node, registry._forNullAssertPattern);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitNullCheckPattern(NullCheckPattern node) {
+    _runSubscriptions(node, registry._forNullCheckPattern);
+    node.visitChildren(this);
+  }
+
+  @override
   void visitNullLiteral(NullLiteral node) {
     _runSubscriptions(node, registry._forNullLiteral);
     node.visitChildren(this);
@@ -684,6 +702,18 @@
   }
 
   @override
+  void visitPatternField(PatternField node) {
+    _runSubscriptions(node, registry._forPatternField);
+    node.visitChildren(this);
+  }
+
+  @override
+  void visitPatternFieldName(PatternFieldName node) {
+    _runSubscriptions(node, registry._forPatternFieldName);
+    node.visitChildren(this);
+  }
+
+  @override
   void visitPatternVariableDeclaration(PatternVariableDeclaration node) {
     _runSubscriptions(node, registry._forPatternVariableDeclaration);
     node.visitChildren(this);
@@ -703,12 +733,6 @@
   }
 
   @override
-  void visitPostfixPattern(PostfixPattern node) {
-    _runSubscriptions(node, registry._forPostfixPattern);
-    node.visitChildren(this);
-  }
-
-  @override
   void visitPrefixedIdentifier(PrefixedIdentifier node) {
     _runSubscriptions(node, registry._forPrefixedIdentifier);
     node.visitChildren(this);
@@ -739,18 +763,6 @@
   }
 
   @override
-  void visitRecordPatternField(RecordPatternField node) {
-    _runSubscriptions(node, registry._forRecordPatternField);
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitRecordPatternFieldName(RecordPatternFieldName node) {
-    _runSubscriptions(node, registry._forRecordPatternFieldName);
-    node.visitChildren(this);
-  }
-
-  @override
   void visitRecordTypeAnnotation(RecordTypeAnnotation node) {
     _runSubscriptions(node, registry._forRecordTypeAnnotation);
     node.visitChildren(this);
@@ -995,6 +1007,12 @@
   }
 
   @override
+  void visitWildcardPattern(WildcardPattern node) {
+    _runSubscriptions(node, registry._forWildcardPattern);
+    node.visitChildren(this);
+  }
+
+  @override
   void visitWithClause(WithClause node) {
     _runSubscriptions(node, registry._forWithClause);
     node.visitChildren(this);
@@ -1041,7 +1059,6 @@
       _forAugmentationImportDirective = [];
   final List<_Subscription<AwaitExpression>> _forAwaitExpression = [];
   final List<_Subscription<BinaryExpression>> _forBinaryExpression = [];
-  final List<_Subscription<BinaryPattern>> _forBinaryPattern = [];
   final List<_Subscription<Block>> _forBlock = [];
   final List<_Subscription<BlockFunctionBody>> _forBlockFunctionBody = [];
   final List<_Subscription<BooleanLiteral>> _forBooleanLiteral = [];
@@ -1143,6 +1160,8 @@
   final List<_Subscription<LibraryIdentifier>> _forLibraryIdentifier = [];
   final List<_Subscription<ListLiteral>> _forListLiteral = [];
   final List<_Subscription<ListPattern>> _forListPattern = [];
+  final List<_Subscription<LogicalAndPattern>> _forLogicalAndPattern = [];
+  final List<_Subscription<LogicalOrPattern>> _forLogicalOrPattern = [];
   final List<_Subscription<MapLiteralEntry>> _forMapLiteralEntry = [];
   final List<_Subscription<MapPatternEntry>> _forMapPatternEntry = [];
   final List<_Subscription<MapPattern>> _forMapPattern = [];
@@ -1153,6 +1172,8 @@
   final List<_Subscription<NamedType>> _forNamedType = [];
   final List<_Subscription<NativeClause>> _forNativeClause = [];
   final List<_Subscription<NativeFunctionBody>> _forNativeFunctionBody = [];
+  final List<_Subscription<NullAssertPattern>> _forNullAssertPattern = [];
+  final List<_Subscription<NullCheckPattern>> _forNullCheckPattern = [];
   final List<_Subscription<NullLiteral>> _forNullLiteral = [];
   final List<_Subscription<OnClause>> _forOnClause = [];
   final List<_Subscription<ParenthesizedExpression>>
@@ -1166,14 +1187,12 @@
   final List<_Subscription<PatternVariableDeclarationStatement>>
       _forPatternVariableDeclarationStatement = [];
   final List<_Subscription<PostfixExpression>> _forPostfixExpression = [];
-  final List<_Subscription<PostfixPattern>> _forPostfixPattern = [];
   final List<_Subscription<PrefixedIdentifier>> _forPrefixedIdentifier = [];
   final List<_Subscription<PrefixExpression>> _forPrefixExpression = [];
   final List<_Subscription<PropertyAccess>> _forPropertyAccess = [];
   final List<_Subscription<RecordLiteral>> _forRecordLiterals = [];
-  final List<_Subscription<RecordPatternField>> _forRecordPatternField = [];
-  final List<_Subscription<RecordPatternFieldName>> _forRecordPatternFieldName =
-      [];
+  final List<_Subscription<PatternField>> _forPatternField = [];
+  final List<_Subscription<PatternFieldName>> _forPatternFieldName = [];
   final List<_Subscription<RecordPattern>> _forRecordPattern = [];
   final List<_Subscription<RecordTypeAnnotation>> _forRecordTypeAnnotation = [];
   final List<_Subscription<RecordTypeAnnotationNamedField>>
@@ -1224,6 +1243,7 @@
       _forVariableDeclarationStatement = [];
   final List<_Subscription<WhenClause>> _forWhenClause = [];
   final List<_Subscription<WhileStatement>> _forWhileStatement = [];
+  final List<_Subscription<WildcardPattern>> _forWildcardPattern = [];
   final List<_Subscription<WithClause>> _forWithClause = [];
   final List<_Subscription<YieldStatement>> _forYieldStatement = [];
 
@@ -1277,10 +1297,6 @@
     _forBinaryExpression.add(_Subscription(linter, visitor, _getTimer(linter)));
   }
 
-  void addBinaryPattern(LintRule linter, AstVisitor visitor) {
-    _forBinaryPattern.add(_Subscription(linter, visitor, _getTimer(linter)));
-  }
-
   void addBlock(LintRule linter, AstVisitor visitor) {
     _forBlock.add(_Subscription(linter, visitor, _getTimer(linter)));
   }
@@ -1642,6 +1658,15 @@
     _forListPattern.add(_Subscription(linter, visitor, _getTimer(linter)));
   }
 
+  void addLogicalAndPattern(LintRule linter, AstVisitor visitor) {
+    _forLogicalAndPattern
+        .add(_Subscription(linter, visitor, _getTimer(linter)));
+  }
+
+  void addLogicalOrPattern(LintRule linter, AstVisitor visitor) {
+    _forLogicalOrPattern.add(_Subscription(linter, visitor, _getTimer(linter)));
+  }
+
   void addMapLiteralEntry(LintRule linter, AstVisitor visitor) {
     _forMapLiteralEntry.add(_Subscription(linter, visitor, _getTimer(linter)));
   }
@@ -1684,6 +1709,15 @@
         .add(_Subscription(linter, visitor, _getTimer(linter)));
   }
 
+  void addNullAssertPattern(LintRule linter, AstVisitor visitor) {
+    _forNullAssertPattern
+        .add(_Subscription(linter, visitor, _getTimer(linter)));
+  }
+
+  void addNullCheckPattern(LintRule linter, AstVisitor visitor) {
+    _forNullCheckPattern.add(_Subscription(linter, visitor, _getTimer(linter)));
+  }
+
   void addNullLiteral(LintRule linter, AstVisitor visitor) {
     _forNullLiteral.add(_Subscription(linter, visitor, _getTimer(linter)));
   }
@@ -1719,6 +1753,14 @@
         .add(_Subscription(linter, visitor, _getTimer(linter)));
   }
 
+  void addPatternField(LintRule linter, AstVisitor visitor) {
+    _forPatternField.add(_Subscription(linter, visitor, _getTimer(linter)));
+  }
+
+  void addPatternFieldName(LintRule linter, AstVisitor visitor) {
+    _forPatternFieldName.add(_Subscription(linter, visitor, _getTimer(linter)));
+  }
+
   void addPatternVariableDeclaration(LintRule linter, AstVisitor visitor) {
     _forPatternVariableDeclaration
         .add(_Subscription(linter, visitor, _getTimer(linter)));
@@ -1735,10 +1777,6 @@
         .add(_Subscription(linter, visitor, _getTimer(linter)));
   }
 
-  void addPostfixPattern(LintRule linter, AstVisitor visitor) {
-    _forPostfixPattern.add(_Subscription(linter, visitor, _getTimer(linter)));
-  }
-
   void addPrefixedIdentifier(LintRule linter, AstVisitor visitor) {
     _forPrefixedIdentifier
         .add(_Subscription(linter, visitor, _getTimer(linter)));
@@ -1760,14 +1798,9 @@
     _forRecordPattern.add(_Subscription(linter, visitor, _getTimer(linter)));
   }
 
+  @Deprecated('Use addPatternField instead')
   void addRecordPatternField(LintRule linter, AstVisitor visitor) {
-    _forRecordPatternField
-        .add(_Subscription(linter, visitor, _getTimer(linter)));
-  }
-
-  void addRecordPatternFieldName(LintRule linter, AstVisitor visitor) {
-    _forRecordPatternFieldName
-        .add(_Subscription(linter, visitor, _getTimer(linter)));
+    _forPatternField.add(_Subscription(linter, visitor, _getTimer(linter)));
   }
 
   void addRecordTypeAnnotation(LintRule linter, AstVisitor visitor) {
diff --git a/analyzer/lib/src/lint/options_rule_validator.dart b/analyzer/lib/src/lint/options_rule_validator.dart
index 450f20d..0dae515 100644
--- a/analyzer/lib/src/lint/options_rule_validator.dart
+++ b/analyzer/lib/src/lint/options_rule_validator.dart
@@ -11,6 +11,7 @@
 import 'package:analyzer/src/plugin/options.dart';
 import 'package:analyzer/src/util/yaml.dart';
 import 'package:collection/collection.dart';
+import 'package:pub_semver/pub_semver.dart';
 import 'package:yaml/yaml.dart';
 
 // TODO(pq): migrate these codes to `option_codes.dart`?
@@ -59,13 +60,35 @@
   static const rulesKey = 'rules';
 
   final LintRuleProvider ruleProvider;
+  final VersionConstraint? sdkVersionConstraint;
+  final bool sourceIsOptionsForContextRoot;
 
-  LinterRuleOptionsValidator({LintRuleProvider? provider})
-      : ruleProvider = provider ?? (() => Registry.ruleRegistry.rules);
+  LinterRuleOptionsValidator({
+    LintRuleProvider? provider,
+    this.sdkVersionConstraint,
+    this.sourceIsOptionsForContextRoot = true,
+  }) : ruleProvider = provider ?? (() => Registry.ruleRegistry.rules);
+
+  bool currentSdkAllows(Version? since) {
+    if (since == null) return true;
+    var sdk = sdkVersionConstraint;
+    if (sdk == null) return false;
+    return sdk.allows(since);
+  }
 
   LintRule? getRegisteredLint(Object value) =>
       ruleProvider().firstWhereOrNull((rule) => rule.name == value);
 
+  bool isDeprecatedInCurrentSdk(State state) {
+    if (state is! DeprecatedState) return false;
+    return currentSdkAllows(state.since);
+  }
+
+  bool isRemovedInCurrentSdk(State state) {
+    if (state is! RemovedState) return false;
+    return currentSdkAllows(state.since);
+  }
+
   @override
   List<AnalysisError> validate(ErrorReporter reporter, YamlMap options) {
     List<AnalysisError> errors = <AnalysisError>[];
@@ -93,7 +116,7 @@
       var value = node.value;
       if (value == null) return;
 
-      final rule = getRegisteredLint(value);
+      final rule = getRegisteredLint(value as Object);
       if (rule == null) {
         reporter.reportErrorForSpan(UNDEFINED_LINT_WARNING, node.span, [value]);
         return;
@@ -108,18 +131,24 @@
           reporter.reportErrorForSpan(DUPLICATE_RULE_HINT, node.span, [value]);
         }
       }
-      var state = rule.state;
-      if (state is DeprecatedState) {
-        reporter.reportErrorForSpan(DEPRECATED_LINT_HINT, node.span, [value]);
-      } else if (state is RemovedState) {
-        var since = state.since.toString();
-        var replacedBy = state.replacedBy;
-        if (replacedBy != null) {
-          reporter.reportErrorForSpan(AnalysisOptionsWarningCode.REPLACED_LINT,
-              node.span, [value, since, replacedBy]);
-        } else {
-          reporter.reportErrorForSpan(AnalysisOptionsWarningCode.REMOVED_LINT,
-              node.span, [value, since]);
+      // Report removed or deprecated lint warnings defined directly (and not in
+      // includes).
+      if (sourceIsOptionsForContextRoot) {
+        var state = rule.state;
+        if (isDeprecatedInCurrentSdk(state)) {
+          reporter.reportErrorForSpan(DEPRECATED_LINT_HINT, node.span, [value]);
+        } else if (isRemovedInCurrentSdk(state)) {
+          var since = state.since.toString();
+          var replacedBy = (state as RemovedState).replacedBy;
+          if (replacedBy != null) {
+            reporter.reportErrorForSpan(
+                AnalysisOptionsWarningCode.REPLACED_LINT,
+                node.span,
+                [value, since, replacedBy]);
+          } else {
+            reporter.reportErrorForSpan(AnalysisOptionsWarningCode.REMOVED_LINT,
+                node.span, [value, since]);
+          }
         }
       }
     }
@@ -130,7 +159,7 @@
       }
     } else if (rules is YamlMap) {
       for (var ruleEntry in rules.nodeMap.entries) {
-        validateRule(ruleEntry.key, ruleEntry.value.value);
+        validateRule(ruleEntry.key, ruleEntry.value.value as bool);
       }
     }
   }
diff --git a/analyzer/lib/src/lint/pub.dart b/analyzer/lib/src/lint/pub.dart
index abcae60..bcb3bac 100644
--- a/analyzer/lib/src/lint/pub.dart
+++ b/analyzer/lib/src/lint/pub.dart
@@ -22,60 +22,66 @@
 }
 
 PSDependencyList? _processDependencies(
-    YamlScalar key, YamlNode v, ResourceProvider? resourceProvider) {
-  if (v is! YamlMap) {
+    YamlScalar key, YamlNode value, ResourceProvider? resourceProvider) {
+  if (value is! YamlMap) {
     return null;
   }
-  YamlMap depsMap = v;
 
   _PSDependencyList deps = _PSDependencyList(_PSNode(key, resourceProvider));
-  depsMap.nodes.forEach((k, v) {
+  value.nodes.forEach((k, v) {
     if (k is YamlScalar) deps.add(_PSDependency(k, v, resourceProvider));
   });
   return deps;
 }
 
-PSGitRepo? _processGitRepo(
-    YamlScalar key, YamlNode v, ResourceProvider? resourceProvider) {
-  if (v is YamlScalar) {
-    _PSGitRepo repo = _PSGitRepo();
-    repo.token = _PSNode(key, resourceProvider);
-    repo.url = PSEntry(repo.token, _PSNode(v, resourceProvider));
-    return repo;
-  }
-  if (v is! YamlMap) {
+PSEnvironment? _processEnvironment(
+    YamlScalar key, YamlNode value, ResourceProvider? resourceProvider) {
+  if (value is! YamlMap) {
     return null;
   }
-  YamlMap hostMap = v;
+
+  _PSEnvironment env = _PSEnvironment(_PSNode(key, resourceProvider));
+  env.flutter = _findEntry(value, 'flutter', resourceProvider);
+  env.sdk = _findEntry(value, 'sdk', resourceProvider);
+  return env;
+}
+
+PSGitRepo? _processGitRepo(
+    YamlScalar key, YamlNode value, ResourceProvider? resourceProvider) {
+  if (value is YamlScalar) {
+    _PSGitRepo repo = _PSGitRepo(_PSNode(key, resourceProvider));
+    repo.url = PSEntry(repo.token, _PSNode(value, resourceProvider));
+    return repo;
+  }
+  if (value is! YamlMap) {
+    return null;
+  }
+
   // url: git://github.com/munificent/kittens.git
   // ref: some-branch
-  _PSGitRepo repo = _PSGitRepo();
-  repo.token = _PSNode(key, resourceProvider);
-  repo.ref = _findEntry(hostMap, 'ref', resourceProvider);
-  repo.url = _findEntry(hostMap, 'url', resourceProvider);
+  _PSGitRepo repo = _PSGitRepo(_PSNode(key, resourceProvider));
+  repo.ref = _findEntry(value, 'ref', resourceProvider);
+  repo.url = _findEntry(value, 'url', resourceProvider);
   return repo;
 }
 
 PSHost? _processHost(
-    YamlScalar key, YamlNode v, ResourceProvider? resourceProvider) {
-  if (v is YamlScalar) {
+    YamlScalar key, YamlNode value, ResourceProvider? resourceProvider) {
+  if (value is YamlScalar) {
     // dependencies:
     //   mypkg:
     //     hosted:  https://some-pub-server.com
     //     version: ^1.2.3
-    _PSHost host = _PSHost(isShortForm: true);
-    host.token = _PSNode(key, resourceProvider);
-    host.url = _processScalar(key, v, resourceProvider);
+    _PSHost host = _PSHost(_PSNode(key, resourceProvider), isShortForm: true);
+    host.url = _processScalar(key, value, resourceProvider);
     return host;
   }
-  if (v is YamlMap) {
-    YamlMap hostMap = v;
+  if (value is YamlMap) {
     // name: transmogrify
     // url: http://your-package-server.com
-    _PSHost host = _PSHost(isShortForm: false);
-    host.token = _PSNode(key, resourceProvider);
-    host.name = _findEntry(hostMap, 'name', resourceProvider);
-    host.url = _findEntry(hostMap, 'url', resourceProvider);
+    _PSHost host = _PSHost(_PSNode(key, resourceProvider), isShortForm: false);
+    host.name = _findEntry(value, 'name', resourceProvider);
+    host.url = _findEntry(value, 'url', resourceProvider);
     return host;
   }
   return null;
@@ -92,15 +98,13 @@
 }
 
 PSNodeList? _processScalarList(
-    YamlScalar key, YamlNode v, ResourceProvider? resourceProvider) {
-  if (v is! YamlList) {
+    YamlScalar key, YamlNode value, ResourceProvider? resourceProvider) {
+  if (value is! YamlList) {
     return null;
   }
-  YamlList nodeList = v;
-
   return _PSNodeList(
       _PSNode(key, resourceProvider),
-      nodeList.nodes
+      value.nodes
           .whereType<YamlScalar>()
           .map((n) => _PSNode(n, resourceProvider)));
 }
@@ -117,9 +121,13 @@
 /// ```
 abstract class PSDependency {
   PSGitRepo? get git;
+
   PSHost? get host;
+
   PSNode? get name;
+
   PSEntry? get path;
+
   PSEntry? get version;
 }
 
@@ -130,12 +138,29 @@
 class PSEntry {
   final PSNode? key;
   final PSNode value;
+
   PSEntry(this.key, this.value);
 
   @override
   String toString() => '${key != null ? ('$key: ') : ''}$value';
 }
 
+/// Representation of environment in `pubspec.yaml`.
+///
+/// **Example** of an environment:
+/// ```yaml
+/// environment:
+///   sdk: '>=2.12.0 <4.0.0'
+///   flutter: ^3.3.10
+/// ```
+abstract class PSEnvironment {
+  PSEntry? get flutter;
+
+  PSEntry? get sdk;
+
+  PSNode get token;
+}
+
 /// Representation of git-dependency in `pubspec.yaml`.
 ///
 /// **Example** of a git-dependency:
@@ -162,7 +187,7 @@
 
   /// The `'git'` from the `pubspec.yaml`, this is the key that indicates this
   /// is a git-dependency.
-  PSNode? get token;
+  PSNode get token;
 
   /// [PSEntry] for `url: https://...` or `git: https://`, where [PSEntry.key]
   /// is either `url` or `git`, and [PSEntry.key] is the URL.
@@ -206,13 +231,16 @@
   bool get isShortForm;
 
   PSEntry? get name;
-  PSNode? get token;
+
+  PSNode get token;
+
   PSEntry? get url;
 }
 
 /// Representation of a leaf-node from `pubspec.yaml`.
 abstract class PSNode {
   Source get source;
+
   SourceSpan get span;
 
   /// String value of the node, or `null` if value in pubspec.yaml is `null` or
@@ -232,6 +260,7 @@
 abstract class PSNodeList with IterableMixin<PSNode> {
   @override
   Iterator<PSNode> get iterator;
+
   PSNode get token;
 }
 
@@ -240,36 +269,67 @@
           {Uri? sourceUrl, ResourceProvider? resourceProvider}) =>
       _Pubspec(source,
           sourceUrl: sourceUrl, resourceProvider: resourceProvider);
+
   PSEntry? get author;
+
   PSNodeList? get authors;
+
   PSDependencyList? get dependencies;
+
   PSDependencyList? get dependencyOverrides;
+
   PSEntry? get description;
+
   PSDependencyList? get devDependencies;
+
   PSEntry? get documentation;
+
+  PSEnvironment? get environment;
+
   PSEntry? get homepage;
+
   PSEntry? get issueTracker;
+
   PSEntry? get name;
+
   PSEntry? get repository;
+
   PSEntry? get version;
+
   void accept(PubspecVisitor visitor);
 }
 
 abstract class PubspecVisitor<T> {
   T? visitPackageAuthor(PSEntry author) => null;
+
   T? visitPackageAuthors(PSNodeList authors) => null;
+
   T? visitPackageDependencies(PSDependencyList dependencies) => null;
+
   T? visitPackageDependency(PSDependency dependency) => null;
+
   T? visitPackageDependencyOverride(PSDependency dependency) => null;
+
   T? visitPackageDependencyOverrides(PSDependencyList dependencies) => null;
+
   T? visitPackageDescription(PSEntry description) => null;
+
   T? visitPackageDevDependencies(PSDependencyList dependencies) => null;
+
   T? visitPackageDevDependency(PSDependency dependency) => null;
+
   T? visitPackageDocumentation(PSEntry documentation) => null;
+
+  T? visitPackageEnvironment(PSEnvironment environment) => null;
+
   T? visitPackageHomepage(PSEntry homepage) => null;
+
   T? visitPackageIssueTracker(PSEntry issueTracker) => null;
+
   T? visitPackageName(PSEntry name) => null;
-  T? visitPackageRepository(PSEntry repostory) => null;
+
+  T? visitPackageRepository(PSEntry repository) => null;
+
   T? visitPackageVersion(PSEntry version) => null;
 }
 
@@ -370,13 +430,33 @@
   String toString() => '$token\n${dependencies.join('  ')}';
 }
 
+class _PSEnvironment implements PSEnvironment {
+  @override
+  PSNode token;
+  @override
+  PSEntry? flutter;
+  @override
+  PSEntry? sdk;
+
+  _PSEnvironment(this.token);
+
+  @override
+  String toString() => '''
+    $token:
+      $sdk
+      $flutter''';
+}
+
 class _PSGitRepo implements PSGitRepo {
   @override
-  PSNode? token;
+  PSNode token;
   @override
   PSEntry? ref;
   @override
   PSEntry? url;
+
+  _PSGitRepo(this.token);
+
   @override
   String toString() => '''
     $token:
@@ -392,12 +472,12 @@
   PSEntry? name;
 
   @override
-  PSNode? token;
+  PSNode token;
 
   @override
   PSEntry? url;
 
-  _PSHost({required this.isShortForm});
+  _PSHost(this.token, {required this.isShortForm});
 
   @override
   String toString() => '''
@@ -453,6 +533,8 @@
   @override
   PSEntry? documentation;
   @override
+  PSEnvironment? environment;
+  @override
   PSEntry? homepage;
   @override
   PSEntry? issueTracker;
@@ -491,6 +573,9 @@
     if (documentation != null) {
       visitor.visitPackageDocumentation(documentation!);
     }
+    if (environment != null) {
+      visitor.visitPackageEnvironment(environment!);
+    }
     if (homepage != null) {
       visitor.visitPackageHomepage(homepage!);
     }
@@ -583,6 +668,9 @@
         case 'dependency_overrides':
           dependencyOverrides = _processDependencies(key, v, resourceProvider);
           break;
+        case 'environment':
+          environment = _processEnvironment(key, v, resourceProvider);
+          break;
         case 'version':
           version = _processScalar(key, v, resourceProvider);
           break;
@@ -593,8 +681,10 @@
 
 class _StringBuilder {
   StringBuffer buffer = StringBuffer();
+
   @override
   String toString() => buffer.toString();
+
   void writelin(Object? value) {
     if (value != null) {
       buffer.writeln(value);
diff --git a/analyzer/lib/src/lint/state.dart b/analyzer/lib/src/lint/state.dart
index f7c6824..9ac6f4e 100644
--- a/analyzer/lib/src/lint/state.dart
+++ b/analyzer/lib/src/lint/state.dart
@@ -4,7 +4,10 @@
 
 import 'package:pub_semver/pub_semver.dart';
 
-/// A version describing Dart 3.0.0.
+/// A version describing Dart language version 2.12.0.
+final Version dart2_12 = Version(2, 12, 0);
+
+/// A version describing Dart language version 3.0.0.
 final Version dart3 = Version(3, 0, 0);
 
 /// A state that marks a lint as deprecated.
@@ -29,8 +32,7 @@
   final String? replacedBy;
 
   /// Initialize a newly created removed state with given values.
-  const RemovedState({required super.since, this.replacedBy})
-      : super(label: 'removed');
+  const RemovedState({super.since, this.replacedBy}) : super(label: 'removed');
 }
 
 /// A state that marks a lint as stable.
@@ -41,10 +43,11 @@
 
 /// Describes the state of a lint.
 abstract class State {
-  /// A sentinel for a state that is 'unknown'.
-  static const State unknown = UnknownState();
+  static const _undatedStable = StableState();
+  static const _undatedDeprecated = DeprecatedState();
+  static const _undatedExperimental = ExperimentalState();
 
-  /// An Optional Dart SDK version that identifies the start of this state.
+  /// An Optional Dart language version that identifies the start of this state.
   final Version? since;
 
   /// A short description, suitable for displaying in documentation or a
@@ -56,30 +59,27 @@
 
   /// Initialize a newly created deprecated state with given values.
   factory State.deprecated({Version? since, String? replacedBy}) =>
-      DeprecatedState(since: since, replacedBy: replacedBy);
+      since == null && replacedBy == null
+          ? _undatedDeprecated
+          : DeprecatedState(since: since, replacedBy: replacedBy);
 
   /// Initialize a newly created experimental state with given values.
   factory State.experimental({Version? since}) =>
-      ExperimentalState(since: since);
+      since == null ? _undatedExperimental : ExperimentalState(since: since);
 
   /// Initialize a newly created removed state with given values.
-  factory State.removed({required Version since, String? replacedBy}) =>
+  factory State.removed({Version? since, String? replacedBy}) =>
       RemovedState(since: since, replacedBy: replacedBy);
 
   /// Initialize a newly created stable state with given values.
-  factory State.stable({Version? since}) => StableState(since: since);
+  factory State.stable({Version? since}) =>
+      since == null ? _undatedStable : StableState(since: since);
 
   /// An optional description that can be used in documentation or diagnostic
   /// reporting.
   String? getDescription() => null;
 }
 
-/// A state that is unknown.
-class UnknownState extends State {
-  /// Initialize a newly created unknown state.
-  const UnknownState() : super(label: 'unknown');
-}
-
 extension StateExtension on State {
   bool get isDeprecated => this is DeprecatedState;
   bool get isExperimental => this is ExperimentalState;
diff --git a/analyzer/lib/src/pubspec/validators/field_validator.dart b/analyzer/lib/src/pubspec/validators/field_validator.dart
index 49bbc30..63a1113 100644
--- a/analyzer/lib/src/pubspec/validators/field_validator.dart
+++ b/analyzer/lib/src/pubspec/validators/field_validator.dart
@@ -21,7 +21,9 @@
   void validate(ErrorReporter reporter, Map<dynamic, YamlNode> contents) {
     for (var field in contents.keys) {
       var name = asString(field);
-      if (name != null && deprecatedFields.contains(name)) {
+      if (field is YamlNode &&
+          name != null &&
+          deprecatedFields.contains(name)) {
         reportErrorForNode(
             reporter, field, PubspecWarningCode.DEPRECATED_FIELD, [name]);
       }
diff --git a/analyzer/lib/src/services/available_declarations.dart b/analyzer/lib/src/services/available_declarations.dart
index 748dc48..bf204bf 100644
--- a/analyzer/lib/src/services/available_declarations.dart
+++ b/analyzer/lib/src/services/available_declarations.dart
@@ -19,12 +19,12 @@
 import 'package:analyzer/src/dart/analysis/session.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/dartdoc/dartdoc_directive_info.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/summary/api_signature.dart';
 import 'package:analyzer/src/summary/format.dart' as idl;
 import 'package:analyzer/src/summary/idl.dart' as idl;
 import 'package:analyzer/src/util/comment.dart';
 import 'package:analyzer/src/util/file_paths.dart' as file_paths;
+import 'package:analyzer/src/utilities/uri_cache.dart';
 import 'package:collection/collection.dart';
 import 'package:convert/convert.dart';
 import 'package:meta/meta.dart';
@@ -1891,7 +1891,7 @@
     List<String> partOrUriList,
     Uri relative,
   ) {
-    var absoluteUri = resolveRelativeUri(uri, relative);
+    var absoluteUri = uriCache.resolveRelative(uri, relative);
     return tracker._getFileByUri(context, partOrUriList, absoluteUri);
   }
 
diff --git a/analyzer/lib/src/services/top_level_declarations.dart b/analyzer/lib/src/services/top_level_declarations.dart
index aa6a420..44ce77f 100644
--- a/analyzer/lib/src/services/top_level_declarations.dart
+++ b/analyzer/lib/src/services/top_level_declarations.dart
@@ -19,7 +19,7 @@
     return analysisContext as DriverBasedAnalysisContext;
   }
 
-  /// Return the first public library that that exports (but does not necessary
+  /// Return the first public library that exports (but does not necessary
   /// declare) [element].
   Future<LibraryElement?> publiclyExporting(Element element,
       {Map<Element, LibraryElement?>? resultCache}) async {
diff --git a/analyzer/lib/src/source/package_map_resolver.dart b/analyzer/lib/src/source/package_map_resolver.dart
index ba4a334..63f2aaf 100644
--- a/analyzer/lib/src/source/package_map_resolver.dart
+++ b/analyzer/lib/src/source/package_map_resolver.dart
@@ -5,6 +5,7 @@
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/util/asserts.dart' as asserts;
+import 'package:analyzer/src/utilities/uri_cache.dart';
 import 'package:path/path.dart' as pathos;
 
 /// A [UriResolver] implementation for the `package:` scheme that uses a map of
@@ -46,7 +47,7 @@
         String relPath = path.substring(pkgFolderPath.length + 1);
         List<String> relPathComponents = pathContext.split(relPath);
         String relUriPath = pathos.posix.joinAll(relPathComponents);
-        return Uri.parse('$_packageScheme:$pkgName/$relUriPath');
+        return uriCache.parse('$_packageScheme:$pkgName/$relUriPath');
       }
     }
     return null;
diff --git a/analyzer/lib/src/summary/flat_buffers.dart b/analyzer/lib/src/summary/flat_buffers.dart
index 0dfd67c..a1b841d 100644
--- a/analyzer/lib/src/summary/flat_buffers.dart
+++ b/analyzer/lib/src/summary/flat_buffers.dart
@@ -843,7 +843,7 @@
     }
   }
 
-  /// Outputs this VTable to [buf], which is is expected to be aligned to 16-bit
+  /// Outputs this VTable to [buf], which is expected to be aligned to 16-bit
   /// and have at least [numOfUint16] 16-bit words available.
   void output(ByteData buf, int bufOffset) {
     // VTable size.
diff --git a/analyzer/lib/src/summary/summary_sdk.dart b/analyzer/lib/src/summary/summary_sdk.dart
index fc2e44b..eba3d20 100644
--- a/analyzer/lib/src/summary/summary_sdk.dart
+++ b/analyzer/lib/src/summary/summary_sdk.dart
@@ -6,6 +6,7 @@
 import 'package:analyzer/src/generated/source.dart' show Source;
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:analyzer/src/summary2/package_bundle_format.dart';
+import 'package:analyzer/src/utilities/uri_cache.dart';
 import 'package:pub_semver/pub_semver.dart';
 
 /// An implementation of [DartSdk] which provides analysis results for `dart:`
@@ -43,7 +44,7 @@
 
   /// Returns URIs of all libraries.
   List<Uri> get libraryUris {
-    return _bundle.libraries.map((e) => Uri.parse(e.uriStr)).toList();
+    return _bundle.libraries.map((e) => uriCache.parse(e.uriStr)).toList();
   }
 
   @override
@@ -77,7 +78,7 @@
 
   @override
   Source? mapDartUri(String uriStr) {
-    Uri uri = Uri.parse(uriStr);
+    Uri uri = uriCache.parse(uriStr);
     return _uriResolver.resolveAbsolute(uri);
   }
 
diff --git a/analyzer/lib/src/summary2/ast_binary_reader.dart b/analyzer/lib/src/summary2/ast_binary_reader.dart
index cabc3e3..ecfc79d 100644
--- a/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -2,6 +2,7 @@
 // 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:_fe_analyzer_shared/src/scanner/string_canonicalizer.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -440,7 +441,8 @@
   DoubleLiteral _readDoubleLiteral() {
     var value = _reader.readDouble();
     var node = DoubleLiteralImpl(
-      literal: StringToken(TokenType.STRING, '$value', -1),
+      literal: StringToken(
+          TokenType.STRING, considerCanonicalizeString('$value'), -1),
       value: value,
     );
     _readExpressionResolution(node);
diff --git a/analyzer/lib/src/summary2/ast_resolver.dart b/analyzer/lib/src/summary2/ast_resolver.dart
index 05614c2..baa81d4 100644
--- a/analyzer/lib/src/summary2/ast_resolver.dart
+++ b/analyzer/lib/src/summary2/ast_resolver.dart
@@ -10,12 +10,10 @@
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/error/inference_error_listener.dart';
 import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
 import 'package:analyzer/src/dart/resolver/resolution_visitor.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/summary2/link.dart';
-import 'package:analyzer/src/task/inference_error.dart';
 
 /// Used to resolve some AST nodes - variable initializers, and annotations.
 class AstResolver {
@@ -25,12 +23,6 @@
   final FeatureSet _featureSet;
   final AnalysisErrorListener _errorListener =
       AnalysisErrorListener.NULL_LISTENER;
-  late final _inferenceErrorRecorder = InferenceErrorRecorder(
-    isNonNullableByDefault:
-        _unitElement.library.typeSystem.isNonNullableByDefault,
-    isGenericMetadataEnabled:
-        _unitElement.library.featureSet.isEnabled(Feature.generic_metadata),
-  );
   final InterfaceElement? enclosingClassElement;
   final ExecutableElement? enclosingExecutableElement;
   late final _resolutionVisitor = ResolutionVisitor(
@@ -56,7 +48,6 @@
     _errorListener,
     featureSet: _featureSet,
     flowAnalysisHelper: _flowAnalysis,
-    inferenceErrorListener: _inferenceErrorRecorder,
   );
 
   AstResolver(
@@ -67,10 +58,6 @@
     this.enclosingExecutableElement,
   }) : _featureSet = _unitElement.library.featureSet;
 
-  /// All inference errors recorded by [_inferenceErrorRecorder].
-  List<TopLevelInferenceError> get errors =>
-      _inferenceErrorRecorder.errors.toList(growable: false);
-
   void resolveAnnotation(AnnotationImpl node) {
     node.accept(_resolutionVisitor);
     node.accept(_scopeResolverVisitor);
diff --git a/analyzer/lib/src/summary2/bundle_reader.dart b/analyzer/lib/src/summary2/bundle_reader.dart
index fef7c32..48d7727 100644
--- a/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/analyzer/lib/src/summary2/bundle_reader.dart
@@ -28,7 +28,9 @@
 import 'package:analyzer/src/summary2/macro_application_error.dart';
 import 'package:analyzer/src/summary2/reference.dart';
 import 'package:analyzer/src/task/inference_error.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 import 'package:analyzer/src/utilities/extensions/string.dart';
+import 'package:analyzer/src/utilities/uri_cache.dart';
 import 'package:pub_semver/pub_semver.dart';
 
 class BundleReader {
@@ -59,7 +61,7 @@
     _reader.offset = librariesOffset;
     var libraryHeaderList = _reader.readTypedList(() {
       return _LibraryHeader(
-        uri: Uri.parse(_reader.readStringReference()),
+        uri: uriCache.parse(_reader.readStringReference()),
         offset: _reader.readUInt30(),
         classMembersLengths: _reader.readUInt30List(),
       );
@@ -630,8 +632,8 @@
     _readFields(unitElement, element, reference, accessors, fields);
     _readPropertyAccessors(
         unitElement, element, reference, accessors, fields, '@field');
-    element.fields = fields;
-    element.accessors = accessors;
+    element.fields = fields.toFixedList();
+    element.accessors = accessors.toFixedList();
 
     element.constructors = _readConstructors(unitElement, element, reference);
     element.methods = _readMethods(unitElement, element, reference);
@@ -641,8 +643,7 @@
     CompilationUnitElementImpl unitElement,
     Reference unitReference,
   ) {
-    var length = _reader.readUInt30();
-    unitElement.classes = List.generate(length, (index) {
+    unitElement.classes = _reader.readTypedList(() {
       return _readClassElement(unitElement, unitReference);
     });
   }
@@ -653,8 +654,7 @@
     Reference classReference,
   ) {
     var containerRef = classReference.getChild('@constructor');
-    var length = _reader.readUInt30();
-    return List.generate(length, (_) {
+    return _reader.readTypedList(() {
       var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
       var name = _reader.readStringReference();
       var referenceName = name.ifNotEmptyOrElse('new');
@@ -685,7 +685,7 @@
 
     DirectiveUriWithRelativeUriImpl readWithRelativeUri() {
       final parent = readWithRelativeUriString();
-      final relativeUri = Uri.parse(_reader.readStringReference());
+      final relativeUri = uriCache.parse(_reader.readStringReference());
       return DirectiveUriWithRelativeUriImpl(
         relativeUriString: parent.relativeUriString,
         relativeUri: relativeUri,
@@ -699,7 +699,7 @@
       final sourceFactory = analysisContext.sourceFactory;
 
       final sourceUriStr = _reader.readStringReference();
-      final sourceUri = Uri.parse(sourceUriStr);
+      final sourceUri = uriCache.parse(sourceUriStr);
       final source = sourceFactory.forUri2(sourceUri);
 
       // TODO(scheglov) https://github.com/dart-lang/sdk/issues/49431
@@ -784,8 +784,8 @@
     _readFields(unitElement, element, reference, accessors, fields);
     _readPropertyAccessors(
         unitElement, element, reference, accessors, fields, '@field');
-    element.fields = fields;
-    element.accessors = accessors;
+    element.fields = fields.toFixedList();
+    element.accessors = accessors.toFixedList();
 
     element.constructors = _readConstructors(unitElement, element, reference);
     element.methods = _readMethods(unitElement, element, reference);
@@ -797,8 +797,7 @@
     CompilationUnitElementImpl unitElement,
     Reference unitReference,
   ) {
-    var count = _reader.readUInt30();
-    unitElement.enums = List.generate(count, (_) {
+    unitElement.enums = _reader.readTypedList(() {
       return _readEnumElement(unitElement, unitReference);
     });
   }
@@ -881,8 +880,7 @@
     CompilationUnitElementImpl unitElement,
     Reference unitReference,
   ) {
-    var count = _reader.readUInt30();
-    unitElement.extensions = List.generate(count, (_) {
+    unitElement.extensions = _reader.readTypedList(() {
       return _readExtensionElement(unitElement, unitReference);
     });
   }
@@ -957,8 +955,7 @@
     CompilationUnitElementImpl unitElement,
     Reference unitReference,
   ) {
-    var count = _reader.readUInt30();
-    unitElement.functions = List.generate(count, (_) {
+    unitElement.functions = _reader.readTypedList(() {
       var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
       var name = _reader.readStringReference();
       var reference = unitReference.getChild('@function').getChild(name);
@@ -1081,8 +1078,7 @@
     Reference enclosingReference,
   ) {
     var containerRef = enclosingReference.getChild('@method');
-    var length = _reader.readUInt30();
-    return List.generate(length, (_) {
+    return _reader.readTypedList(() {
       var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
       var name = _reader.readStringReference();
       var reference = containerRef.getChild(name);
@@ -1128,8 +1124,8 @@
     _readFields(unitElement, element, reference, accessors, fields);
     _readPropertyAccessors(
         unitElement, element, reference, accessors, fields, '@field');
-    element.fields = fields;
-    element.accessors = accessors;
+    element.fields = fields.toFixedList();
+    element.accessors = accessors.toFixedList();
 
     element.constructors = _readConstructors(unitElement, element, reference);
     element.methods = _readMethods(unitElement, element, reference);
@@ -1142,8 +1138,7 @@
     CompilationUnitElementImpl unitElement,
     Reference unitReference,
   ) {
-    var length = _reader.readUInt30();
-    unitElement.mixins = List.generate(length, (index) {
+    unitElement.mixins = _reader.readTypedList(() {
       return _readMixinElement(unitElement, unitReference);
     });
   }
@@ -1168,8 +1163,7 @@
     Reference enclosingReference,
   ) {
     var containerRef = enclosingReference.getChild('@parameter');
-    var length = _reader.readUInt30();
-    return List.generate(length, (_) {
+    return _reader.readTypedList(() {
       var name = _reader.readStringReference();
       var isInitializingFormal = _reader.readBool();
       var isSuperFormal = _reader.readBool();
@@ -1439,15 +1433,13 @@
     CompilationUnitElementImpl unitElement,
     Reference unitReference,
   ) {
-    var length = _reader.readUInt30();
-    unitElement.typeAliases = List.generate(length, (_) {
+    unitElement.typeAliases = _reader.readTypedList(() {
       return _readTypeAliasElement(unitElement, unitReference);
     });
   }
 
   List<TypeParameterElementImpl> _readTypeParameters() {
-    var length = _reader.readUInt30();
-    return List.generate(length, (_) {
+    return _reader.readTypedList(() {
       var name = _reader.readStringReference();
       var varianceEncoding = _reader.readByte();
       var variance = _decodeVariance(varianceEncoding);
@@ -1496,8 +1488,8 @@
     _readTopLevelVariables(unitElement, unitReference, accessors, variables);
     _readPropertyAccessors(unitElement, unitElement, unitReference, accessors,
         variables, '@variable');
-    unitElement.accessors = accessors;
-    unitElement.topLevelVariables = variables;
+    unitElement.accessors = accessors.toFixedList();
+    unitElement.topLevelVariables = variables.toFixedList();
     return unitElement;
   }
 
@@ -1747,10 +1739,7 @@
   }
 
   List<T> readTypedList<T>(T Function() read) {
-    var length = readUInt30();
-    return List<T>.generate(length, (_) {
-      return read();
-    });
+    return _reader.readTypedList(read);
   }
 
   int readUInt30() {
@@ -1857,11 +1846,7 @@
   List<ElementAnnotationImpl> _readAnnotationList({
     required CompilationUnitElementImpl unitElement,
   }) {
-    var length = _reader.readUInt30();
-    if (length == 0) {
-      return const <ElementAnnotationImpl>[];
-    }
-    return List.generate(length, (_) {
+    return readTypedList(() {
       var ast = _readRequiredNode() as Annotation;
       return ElementAnnotationImpl(unitElement)
         ..annotationAst = ast
@@ -1872,8 +1857,7 @@
   List<ParameterElementImpl> _readFormalParameters(
     CompilationUnitElementImpl? unitElement,
   ) {
-    var formalParameterCount = _reader.readUInt30();
-    return List.generate(formalParameterCount, (_) {
+    return readTypedList(() {
       var kindIndex = _reader.readByte();
       var kind = _formalParameterKind(kindIndex);
       var hasImplicitType = _reader.readBool();
@@ -1948,16 +1932,11 @@
   }
 
   List<InterfaceType> _readInterfaceTypeList() {
-    var length = _reader.readUInt30();
-    if (length == 0) {
-      return const <InterfaceType>[];
-    }
-    return List.generate(length, (_) => _readInterfaceType());
+    return readTypedList(_readInterfaceType);
   }
 
   List<T> _readNodeList<T>() {
-    var length = _reader.readUInt30();
-    return List<T>.generate(length, (_) {
+    return readTypedList(() {
       return _readRequiredNode() as T;
     });
   }
@@ -2021,20 +2000,15 @@
   }
 
   List<DartType> _readTypeList() {
-    var types = <DartType>[];
-    var length = _reader.readUInt30();
-    for (var i = 0; i < length; i++) {
-      var argument = readType()!;
-      types.add(argument);
-    }
-    return types;
+    return readTypedList(() {
+      return readRequiredType();
+    });
   }
 
   List<TypeParameterElementImpl> _readTypeParameters(
     CompilationUnitElementImpl? unitElement,
   ) {
-    var typeParameterCount = _reader.readUInt30();
-    var typeParameters = List.generate(typeParameterCount, (_) {
+    var typeParameters = readTypedList(() {
       var name = readStringReference();
       var typeParameter = TypeParameterElementImpl(name, -1);
       _localElements.add(typeParameter);
diff --git a/analyzer/lib/src/summary2/data_reader.dart b/analyzer/lib/src/summary2/data_reader.dart
index c5798ee..1f5cc09 100644
--- a/analyzer/lib/src/summary2/data_reader.dart
+++ b/analyzer/lib/src/summary2/data_reader.dart
@@ -5,6 +5,8 @@
 import 'dart:convert';
 import 'dart:typed_data';
 
+import 'package:_fe_analyzer_shared/src/scanner/string_canonicalizer.dart';
+
 /// Helper for reading primitive types from bytes.
 class SummaryDataReader {
   final Uint8List bytes;
@@ -97,7 +99,7 @@
 
   String readStringUtf8() {
     var bytes = readUint8List();
-    return utf8.decode(bytes);
+    return considerCanonicalizeString(utf8.decode(bytes));
   }
 
   List<String> readStringUtf8List() {
@@ -116,9 +118,12 @@
 
   List<T> readTypedList<T>(T Function() read) {
     var length = readUInt30();
+    if (length == 0) {
+      return const <Never>[];
+    }
     return List<T>.generate(length, (_) {
       return read();
-    });
+    }, growable: false);
   }
 
   int readUInt30() {
@@ -213,6 +218,7 @@
 
     if (result == null) {
       result = _readStringEntry(_offsets[index], _lengths[index]);
+      result = considerCanonicalizeString(result);
       _strings[index] = result;
     }
 
diff --git a/analyzer/lib/src/summary2/detach_nodes.dart b/analyzer/lib/src/summary2/detach_nodes.dart
index 1d11afe..7f069ca 100644
--- a/analyzer/lib/src/summary2/detach_nodes.dart
+++ b/analyzer/lib/src/summary2/detach_nodes.dart
@@ -8,6 +8,7 @@
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/summary2/not_serializable_nodes.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 /// Elements have references to AST nodes, for example initializers of constant
 /// variables. These nodes are attached to the whole compilation unit, and
@@ -30,7 +31,7 @@
   void visitConstructorElement(ConstructorElement element) {
     if (element is ConstructorElementImpl) {
       // Make a copy, so that it is not a NodeList.
-      var initializers = element.constantInitializers.toList();
+      var initializers = element.constantInitializers.toFixedList();
       initializers.forEach(_detachNode);
       element.constantInitializers = initializers;
     }
diff --git a/analyzer/lib/src/summary2/element_builder.dart b/analyzer/lib/src/summary2/element_builder.dart
index 0345bbf..6352210 100644
--- a/analyzer/lib/src/summary2/element_builder.dart
+++ b/analyzer/lib/src/summary2/element_builder.dart
@@ -16,6 +16,7 @@
 import 'package:analyzer/src/summary2/link.dart';
 import 'package:analyzer/src/summary2/reference.dart';
 import 'package:analyzer/src/util/comment.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 import 'package:analyzer/src/utilities/extensions/string.dart';
 import 'package:collection/collection.dart';
 
@@ -95,6 +96,9 @@
       element.isSealed = true;
       element.isAbstract = true;
     }
+    element.isBase = node.baseKeyword != null;
+    element.isInterface = node.interfaceKeyword != null;
+    element.isFinal = node.finalKeyword != null;
     element.isMixinClass = node.mixinKeyword != null;
     element.metadata = _buildAnnotations(node.metadata);
     _setCodeRange(element, node);
@@ -133,6 +137,9 @@
       element.isSealed = true;
       element.isAbstract = true;
     }
+    element.isBase = node.baseKeyword != null;
+    element.isInterface = node.interfaceKeyword != null;
+    element.isFinal = node.finalKeyword != null;
     element.isMixinApplication = true;
     element.isMixinClass = node.mixinKeyword != null;
     element.metadata = _buildAnnotations(node.metadata);
@@ -859,6 +866,9 @@
 
     var element = MixinElementImpl(name, nameToken.offset);
     element.isSealed = node.sealedKeyword != null;
+    element.isBase = node.baseKeyword != null;
+    element.isInterface = node.interfaceKeyword != null;
+    element.isFinal = node.finalKeyword != null;
     element.metadata = _buildAnnotations(node.metadata);
     _setCodeRange(element, node);
     _setDocumentation(element, node);
@@ -1131,7 +1141,7 @@
       _visitPropertyFirst<FieldDeclaration>(node.members);
     });
 
-    if (holder.constructors.isEmpty) {
+    if (!holder.hasConstructors) {
       holder.addConstructor(
         ConstructorElementImpl('', -1)..isSynthetic = true,
       );
@@ -1290,15 +1300,13 @@
       return const <ElementAnnotation>[];
     }
 
-    var annotations = <ElementAnnotation>[];
-    for (int i = 0; i < length; i++) {
-      var ast = nodeList[i] as AnnotationImpl;
+    return List<ElementAnnotation>.generate(length, (index) {
+      var ast = nodeList[index] as AnnotationImpl;
       var element = ElementAnnotationImpl(unitElement);
       element.annotationAst = ast;
       ast.elementAnnotation = element;
-      annotations.add(element);
-    }
-    return annotations;
+      return element;
+    }, growable: false);
   }
 
   static void _setCodeRange(ElementImpl element, AstNode node) {
@@ -1328,19 +1336,19 @@
 class _EnclosingContext {
   final Reference reference;
   final ElementImpl element;
-  final List<ClassElementImpl> classes = [];
-  final List<ConstructorElementImpl> constructors = [];
-  final List<EnumElementImpl> enums = [];
-  final List<ExtensionElementImpl> extensions = [];
-  final List<FieldElementImpl> fields = [];
-  final List<FunctionElementImpl> functions = [];
-  final List<MethodElementImpl> methods = [];
-  final List<MixinElementImpl> mixins = [];
-  final List<ParameterElementImpl> parameters = [];
-  final List<PropertyAccessorElementImpl> propertyAccessors = [];
-  final List<TopLevelVariableElementImpl> topLevelVariables = [];
-  final List<TypeAliasElementImpl> typeAliases = [];
-  final List<TypeParameterElementImpl> typeParameters = [];
+  final List<ClassElementImpl> _classes = [];
+  final List<ConstructorElementImpl> _constructors = [];
+  final List<EnumElementImpl> _enums = [];
+  final List<ExtensionElementImpl> _extensions = [];
+  final List<FieldElementImpl> _fields = [];
+  final List<FunctionElementImpl> _functions = [];
+  final List<MethodElementImpl> _methods = [];
+  final List<MixinElementImpl> _mixins = [];
+  final List<ParameterElementImpl> _parameters = [];
+  final List<PropertyAccessorElementImpl> _propertyAccessors = [];
+  final List<TopLevelVariableElementImpl> _topLevelVariables = [];
+  final List<TypeAliasElementImpl> _typeAliases = [];
+  final List<TypeParameterElementImpl> _typeParameters = [];
   final bool hasConstConstructor;
 
   _EnclosingContext(
@@ -1349,55 +1357,109 @@
     this.hasConstConstructor = false,
   });
 
+  List<ClassElementImpl> get classes {
+    return _classes.toFixedList();
+  }
+
+  List<ConstructorElementImpl> get constructors {
+    return _constructors.toFixedList();
+  }
+
+  List<EnumElementImpl> get enums {
+    return _enums.toFixedList();
+  }
+
+  List<ExtensionElementImpl> get extensions {
+    return _extensions.toFixedList();
+  }
+
+  List<FieldElementImpl> get fields {
+    return _fields.toFixedList();
+  }
+
+  List<FunctionElementImpl> get functions {
+    return _functions.toFixedList();
+  }
+
+  bool get hasConstructors => _constructors.isNotEmpty;
+
   bool get isDartCoreEnum {
     final element = this.element;
     return element is ClassElementImpl && element.isDartCoreEnum;
   }
 
+  List<MethodElementImpl> get methods {
+    return _methods.toFixedList();
+  }
+
+  List<MixinElementImpl> get mixins {
+    return _mixins.toFixedList();
+  }
+
+  List<ParameterElementImpl> get parameters {
+    return _parameters.toFixedList();
+  }
+
+  List<PropertyAccessorElementImpl> get propertyAccessors {
+    return _propertyAccessors.toFixedList();
+  }
+
+  List<TopLevelVariableElementImpl> get topLevelVariables {
+    return _topLevelVariables.toFixedList();
+  }
+
+  List<TypeAliasElementImpl> get typeAliases {
+    return _typeAliases.toFixedList();
+  }
+
+  List<TypeParameterElementImpl> get typeParameters {
+    return _typeParameters.toFixedList();
+  }
+
   Reference addClass(String name, ClassElementImpl element) {
-    classes.add(element);
+    _classes.add(element);
     return _bindReference('@class', name, element);
   }
 
   Reference addConstructor(ConstructorElementImpl element) {
-    constructors.add(element);
+    _constructors.add(element);
 
     final referenceName = element.name.ifNotEmptyOrElse('new');
     return _bindReference('@constructor', referenceName, element);
   }
 
   Reference addEnum(String name, EnumElementImpl element) {
-    enums.add(element);
+    _enums.add(element);
     return _bindReference('@enum', name, element);
   }
 
   Reference addExtension(String name, ExtensionElementImpl element) {
-    extensions.add(element);
+    _extensions.add(element);
     return _bindReference('@extension', name, element);
   }
 
   Reference addField(String name, FieldElementImpl element) {
-    fields.add(element);
+    _fields.add(element);
     return _bindReference('@field', name, element);
   }
 
   Reference addFunction(String name, FunctionElementImpl element) {
-    functions.add(element);
+    _functions.add(element);
     return _bindReference('@function', name, element);
   }
 
   Reference addGetter(String name, PropertyAccessorElementImpl element) {
-    propertyAccessors.add(element);
+    _propertyAccessors.add(element);
     return _bindReference('@getter', name, element);
   }
 
   Reference addMethod(String name, MethodElementImpl element) {
-    methods.add(element);
+    _methods.add(element);
     return _bindReference('@method', name, element);
   }
 
   Reference addMixin(String name, MixinElementImpl element) {
-    mixins.add(element);
+    _mixins.add(element);
     return _bindReference('@mixin', name, element);
   }
 
@@ -1419,7 +1481,7 @@
   }
 
   Reference? addParameter(String? name, ParameterElementImpl element) {
-    parameters.add(element);
+    _parameters.add(element);
     if (name == null) {
       return null;
     } else {
@@ -1428,23 +1490,23 @@
   }
 
   Reference addSetter(String name, PropertyAccessorElementImpl element) {
-    propertyAccessors.add(element);
+    _propertyAccessors.add(element);
     return _bindReference('@setter', name, element);
   }
 
   Reference addTopLevelVariable(
       String name, TopLevelVariableElementImpl element) {
-    topLevelVariables.add(element);
+    _topLevelVariables.add(element);
     return _bindReference('@variable', name, element);
   }
 
   Reference addTypeAlias(String name, TypeAliasElementImpl element) {
-    typeAliases.add(element);
+    _typeAliases.add(element);
     return _bindReference('@typeAlias', name, element);
   }
 
   void addTypeParameter(String name, TypeParameterElementImpl element) {
-    typeParameters.add(element);
+    _typeParameters.add(element);
     this.element.encloseElement(element);
   }
 
diff --git a/analyzer/lib/src/summary2/element_flags.dart b/analyzer/lib/src/summary2/element_flags.dart
index 833537e..88026b8 100644
--- a/analyzer/lib/src/summary2/element_flags.dart
+++ b/analyzer/lib/src/summary2/element_flags.dart
@@ -8,15 +8,21 @@
 
 class ClassElementFlags {
   static const int _isAbstract = 1 << 0;
-  static const int _isMacro = 1 << 1;
-  static const int _isMixinApplication = 1 << 2;
-  static const int _isMixinClass = 1 << 3;
-  static const int _isSealed = 1 << 4;
-  static const int _isSimplyBounded = 1 << 5;
+  static const int _isBase = 1 << 1;
+  static const int _isFinal = 1 << 2;
+  static const int _isInterface = 1 << 3;
+  static const int _isMacro = 1 << 4;
+  static const int _isMixinApplication = 1 << 5;
+  static const int _isMixinClass = 1 << 6;
+  static const int _isSealed = 1 << 7;
+  static const int _isSimplyBounded = 1 << 8;
 
   static void read(SummaryDataReader reader, ClassElementImpl element) {
-    var byte = reader.readByte();
+    var byte = reader.readUInt30();
     element.isAbstract = (byte & _isAbstract) != 0;
+    element.isBase = (byte & _isBase) != 0;
+    element.isFinal = (byte & _isFinal) != 0;
+    element.isInterface = (byte & _isInterface) != 0;
     element.isMacro = (byte & _isMacro) != 0;
     element.isMixinApplication = (byte & _isMixinApplication) != 0;
     element.isMixinClass = (byte & _isMixinClass) != 0;
@@ -27,12 +33,15 @@
   static void write(BufferedSink sink, ClassElementImpl element) {
     var result = 0;
     result |= element.isAbstract ? _isAbstract : 0;
+    result |= element.isBase ? _isBase : 0;
+    result |= element.isFinal ? _isFinal : 0;
+    result |= element.isInterface ? _isInterface : 0;
     result |= element.isMacro ? _isMacro : 0;
     result |= element.isMixinApplication ? _isMixinApplication : 0;
     result |= element.isMixinClass ? _isMixinClass : 0;
     result |= element.isSealed ? _isSealed : 0;
     result |= element.isSimplyBounded ? _isSimplyBounded : 0;
-    sink.writeByte(result);
+    sink.writeUInt30(result);
   }
 }
 
@@ -90,9 +99,10 @@
   static const int _isFinal = 1 << 8;
   static const int _isLate = 1 << 9;
   static const int _isPromotable = 1 << 10;
-  static const int _isStatic = 1 << 11;
-  static const int _isSynthetic = 1 << 12;
-  static const int _isTempAugmentation = 1 << 13;
+  static const int _shouldUseTypeForInitializerInference = 1 << 11;
+  static const int _isStatic = 1 << 12;
+  static const int _isSynthetic = 1 << 13;
+  static const int _isTempAugmentation = 1 << 14;
 
   static void read(SummaryDataReader reader, FieldElementImpl element) {
     var byte = reader.readUInt30();
@@ -107,6 +117,8 @@
     element.isFinal = (byte & _isFinal) != 0;
     element.isLate = (byte & _isLate) != 0;
     element.isPromotable = (byte & _isPromotable) != 0;
+    element.shouldUseTypeForInitializerInference =
+        (byte & _shouldUseTypeForInitializerInference) != 0;
     element.isStatic = (byte & _isStatic) != 0;
     element.isSynthetic = (byte & _isSynthetic) != 0;
     element.isTempAugmentation = (byte & _isTempAugmentation) != 0;
@@ -125,6 +137,9 @@
     result |= element.isFinal ? _isFinal : 0;
     result |= element.isLate ? _isLate : 0;
     result |= element.isPromotable ? _isPromotable : 0;
+    result |= element.shouldUseTypeForInitializerInference
+        ? _shouldUseTypeForInitializerInference
+        : 0;
     result |= element.isStatic ? _isStatic : 0;
     result |= element.isSynthetic ? _isSynthetic : 0;
     result |= element.isTempAugmentation ? _isTempAugmentation : 0;
@@ -229,17 +244,26 @@
 }
 
 class MixinElementFlags {
-  static const int _isSealed = 1 << 0;
-  static const int _isSimplyBounded = 1 << 1;
+  static const int _isBase = 1 << 0;
+  static const int _isFinal = 1 << 1;
+  static const int _isInterface = 1 << 2;
+  static const int _isSealed = 1 << 3;
+  static const int _isSimplyBounded = 1 << 4;
 
   static void read(SummaryDataReader reader, MixinElementImpl element) {
     var byte = reader.readByte();
+    element.isBase = (byte & _isBase) != 0;
+    element.isFinal = (byte & _isFinal) != 0;
+    element.isInterface = (byte & _isInterface) != 0;
     element.isSealed = (byte & _isSealed) != 0;
     element.isSimplyBounded = (byte & _isSimplyBounded) != 0;
   }
 
   static void write(BufferedSink sink, MixinElementImpl element) {
     var result = 0;
+    result |= element.isBase ? _isBase : 0;
+    result |= element.isFinal ? _isFinal : 0;
+    result |= element.isInterface ? _isInterface : 0;
     result |= element.isSealed ? _isSealed : 0;
     result |= element.isSimplyBounded ? _isSimplyBounded : 0;
     sink.writeByte(result);
@@ -321,7 +345,8 @@
   static const int _isExternal = 1 << 2;
   static const int _isFinal = 1 << 3;
   static const int _isLate = 1 << 4;
-  static const int _isTempAugmentation = 1 << 5;
+  static const int _shouldUseTypeForInitializerInference = 1 << 5;
+  static const int _isTempAugmentation = 1 << 6;
 
   static void read(
     SummaryDataReader reader,
@@ -333,6 +358,8 @@
     element.isExternal = (byte & _isExternal) != 0;
     element.isFinal = (byte & _isFinal) != 0;
     element.isLate = (byte & _isLate) != 0;
+    element.shouldUseTypeForInitializerInference =
+        (byte & _shouldUseTypeForInitializerInference) != 0;
     element.isTempAugmentation = (byte & _isTempAugmentation) != 0;
   }
 
@@ -343,6 +370,9 @@
     result |= element.isExternal ? _isExternal : 0;
     result |= element.isFinal ? _isFinal : 0;
     result |= element.isLate ? _isLate : 0;
+    result |= element.shouldUseTypeForInitializerInference
+        ? _shouldUseTypeForInitializerInference
+        : 0;
     result |= element.isTempAugmentation ? _isTempAugmentation : 0;
     sink.writeByte(result);
   }
diff --git a/analyzer/lib/src/summary2/export.dart b/analyzer/lib/src/summary2/export.dart
index 17686aa..9190943 100644
--- a/analyzer/lib/src/summary2/export.dart
+++ b/analyzer/lib/src/summary2/export.dart
@@ -6,6 +6,7 @@
 import 'package:analyzer/src/summary2/combinator.dart';
 import 'package:analyzer/src/summary2/library_builder.dart';
 import 'package:analyzer/src/summary2/reference.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 class Export {
   final LibraryBuilder exporter;
@@ -33,6 +34,9 @@
     required this.reference,
   });
 
+  /// We are done updating this object, returns the immutable version.
+  ExportedReference toFinalized() => this;
+
   @override
   String toString() {
     return '$reference';
@@ -61,6 +65,14 @@
       locations.add(location);
     }
   }
+
+  @override
+  ExportedReference toFinalized() {
+    return ExportedReferenceExported(
+      reference: reference,
+      locations: locations.toFixedList(),
+    );
+  }
 }
 
 class ExportLocation {
@@ -132,4 +144,10 @@
   void forEach(void Function(String name, ExportedReference reference) f) {
     map.forEach(f);
   }
+
+  List<ExportedReference> toReferences() {
+    return map.values.map((reference) {
+      return reference.toFinalized();
+    }).toFixedList();
+  }
 }
diff --git a/analyzer/lib/src/summary2/function_type_builder.dart b/analyzer/lib/src/summary2/function_type_builder.dart
index e81d0d8..c191f4a 100644
--- a/analyzer/lib/src/summary2/function_type_builder.dart
+++ b/analyzer/lib/src/summary2/function_type_builder.dart
@@ -14,6 +14,7 @@
 import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/dart/element/type_visitor.dart';
 import 'package:analyzer/src/summary2/type_builder.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 /// The type builder for a [GenericFunctionType].
 class FunctionTypeBuilder extends TypeBuilder {
@@ -154,7 +155,7 @@
         _getParameterType(isNNBD, parameter),
         parameter.kind,
       );
-    }).toList();
+    }).toFixedList();
   }
 
   /// If the [type] is a [TypeBuilder], build it; otherwise return as is.
@@ -208,6 +209,6 @@
     TypeParameterList? node,
   ) {
     if (node == null) return const [];
-    return node.typeParameters.map((n) => n.declaredElement!).toList();
+    return node.typeParameters.map((n) => n.declaredElement!).toFixedList();
   }
 }
diff --git a/analyzer/lib/src/summary2/kernel_compilation_service.dart b/analyzer/lib/src/summary2/kernel_compilation_service.dart
index 36caada..35b7917 100644
--- a/analyzer/lib/src/summary2/kernel_compilation_service.dart
+++ b/analyzer/lib/src/summary2/kernel_compilation_service.dart
@@ -9,6 +9,7 @@
 
 import 'package:_fe_analyzer_shared/src/macros/compiler/request_channel.dart';
 import 'package:analyzer/src/summary2/macro.dart';
+import 'package:analyzer/src/utilities/uri_cache.dart';
 import 'package:meta/meta.dart';
 import 'package:path/path.dart' as package_path;
 
@@ -92,7 +93,7 @@
       final requestChannel = instance.requestChannel;
 
       MacroFileEntry uriStrToFile(Object? uriStr) {
-        final uri = Uri.parse(uriStr as String);
+        final uri = uriCache.parse(uriStr as String);
         final path = fileSystem.pathContext.fromUri(uri);
         return fileSystem.getFile(path);
       }
diff --git a/analyzer/lib/src/summary2/library_builder.dart b/analyzer/lib/src/summary2/library_builder.dart
index 76b414c..434f912 100644
--- a/analyzer/lib/src/summary2/library_builder.dart
+++ b/analyzer/lib/src/summary2/library_builder.dart
@@ -27,6 +27,7 @@
 import 'package:analyzer/src/summary2/reference_resolver.dart';
 import 'package:analyzer/src/summary2/types_builder.dart';
 import 'package:analyzer/src/util/performance/operation_performance.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 class DefiningLinkingUnit extends LinkingUnit {
   DefiningLinkingUnit({
@@ -363,7 +364,8 @@
     var unitReference = reference.getChild('@unit').getChild('$unitUri');
     _bindReference(unitReference, unitElement);
 
-    element.parts.add(
+    element.parts = [
+      ...element.parts,
       PartElementImpl(
         uri: DirectiveUriWithUnitImpl(
           relativeUriString: '_macro_types.dart',
@@ -371,7 +373,7 @@
           unit: unitElement,
         ),
       ),
-    );
+    ];
 
     ElementBuilder(
       libraryBuilder: this,
@@ -428,7 +430,7 @@
   }
 
   void storeExportScope() {
-    element.exportedReferences = exportScope.map.values.toList();
+    element.exportedReferences = exportScope.toReferences();
 
     var definedNames = <String, Element>{};
     for (var entry in exportScope.map.entries) {
@@ -540,7 +542,7 @@
         // TODO(scheglov) Why no offsets?
         return HideElementCombinatorImpl()..hiddenNames = unlinked.names;
       }
-    }).toList();
+    }).toFixedList();
   }
 
   /// Builds directive elements, for the library and recursively for its
@@ -549,17 +551,20 @@
     required LibraryOrAugmentationFileKind kind,
     required LibraryOrAugmentationElementImpl container,
   }) {
-    container.libraryExports = kind.libraryExports.map(_buildExport).toList();
+    container.libraryExports = kind.libraryExports.map((state) {
+      return _buildExport(state);
+    }).toFixedList();
+
     container.libraryImports = kind.libraryImports.map((state) {
       return _buildImport(
         container: container,
         state: state,
       );
-    }).toList();
+    }).toFixedList();
 
     container.augmentationImports = kind.augmentationImports.map((state) {
       return _buildAugmentationImport(container, state);
-    }).toList();
+    }).toFixedList();
   }
 
   LibraryExportElementImpl _buildExport(LibraryExportState state) {
@@ -819,10 +824,8 @@
       libraryElement.definingCompilationUnit = unitElement;
     }
 
-    final parts = <PartElementImpl>[];
-    for (final partState in inputLibrary.parts) {
+    libraryElement.parts = inputLibrary.parts.map((partState) {
       final uriState = partState.uri;
-
       final DirectiveUri directiveUri;
       if (partState is PartWithFile) {
         final includedPart = partState.includedPart;
@@ -880,15 +883,12 @@
       } else {
         directiveUri = DirectiveUriImpl();
       }
-
-      parts.add(
-        PartElementImpl(
-          uri: directiveUri,
-        ),
+      return directiveUri;
+    }).map((directiveUri) {
+      return PartElementImpl(
+        uri: directiveUri,
       );
-    }
-
-    libraryElement.parts = parts;
+    }).toFixedList();
 
     final builder = LibraryBuilder._(
       linker: linker,
diff --git a/analyzer/lib/src/summary2/link.dart b/analyzer/lib/src/summary2/link.dart
index f2ba1b0..a47ae31 100644
--- a/analyzer/lib/src/summary2/link.dart
+++ b/analyzer/lib/src/summary2/link.dart
@@ -26,6 +26,7 @@
 import 'package:analyzer/src/summary2/types_builder.dart';
 import 'package:analyzer/src/summary2/variance_builder.dart';
 import 'package:analyzer/src/util/performance/operation_performance.dart';
+import 'package:analyzer/src/utilities/uri_cache.dart';
 
 Future<LinkResult> link({
   required LinkedElementFactory elementFactory,
@@ -73,7 +74,7 @@
   Reference get rootReference => elementFactory.rootReference;
 
   bool get _isLinkingDartCore {
-    var dartCoreUri = Uri.parse('dart:core');
+    var dartCoreUri = uriCache.parse('dart:core');
     return builders.containsKey(dartCoreUri);
   }
 
diff --git a/analyzer/lib/src/summary2/linked_element_factory.dart b/analyzer/lib/src/summary2/linked_element_factory.dart
index 45859a4..aed4049 100644
--- a/analyzer/lib/src/summary2/linked_element_factory.dart
+++ b/analyzer/lib/src/summary2/linked_element_factory.dart
@@ -13,6 +13,7 @@
 import 'package:analyzer/src/summary2/bundle_reader.dart';
 import 'package:analyzer/src/summary2/export.dart';
 import 'package:analyzer/src/summary2/reference.dart';
+import 'package:analyzer/src/utilities/uri_cache.dart';
 import 'package:meta/meta.dart';
 
 final _logRing = Queue<String>();
@@ -25,8 +26,8 @@
 }
 
 class LinkedElementFactory {
-  static final _dartCoreUri = Uri.parse('dart:core');
-  static final _dartAsyncUri = Uri.parse('dart:async');
+  static final _dartCoreUri = uriCache.parse('dart:core');
+  static final _dartAsyncUri = uriCache.parse('dart:async');
 
   final AnalysisContextImpl analysisContext;
   AnalysisSessionImpl analysisSession;
@@ -112,7 +113,13 @@
 
     var reader = _libraryReaders[uri];
     if (reader == null) {
-      final rootChildren = rootReference.children.map((e) => e.name).toList();
+      var rootChildren = rootReference.children.map((e) => e.name).toList();
+      if (rootChildren.length > 100) {
+        rootChildren = [
+          ...rootChildren.take(100),
+          '... (${rootChildren.length} total)'
+        ];
+      }
       throw ArgumentError(
         'Missing library: $uri\n'
         'Libraries: $uriListWithLibraryElements\n'
@@ -176,7 +183,7 @@
     }
 
     if (reference.isLibrary) {
-      final uri = Uri.parse(reference.name);
+      final uri = uriCache.parse(reference.name);
       return createLibraryElementForReading(uri);
     }
 
diff --git a/analyzer/lib/src/summary2/macro.dart b/analyzer/lib/src/summary2/macro.dart
index 46f36e9..12b2368 100644
--- a/analyzer/lib/src/summary2/macro.dart
+++ b/analyzer/lib/src/summary2/macro.dart
@@ -39,7 +39,7 @@
   Uri get _kernelUri {
     return _kernelUriCached ??=
         // ignore: avoid_dynamic_calls
-        (Isolate.current as dynamic).createUriForKernelBlob(kernelBytes);
+        (Isolate.current as dynamic).createUriForKernelBlob(kernelBytes) as Uri;
   }
 
   void dispose() {
diff --git a/analyzer/lib/src/summary2/macro_application.dart b/analyzer/lib/src/summary2/macro_application.dart
index d4c7ff3..af167a7 100644
--- a/analyzer/lib/src/summary2/macro_application.dart
+++ b/analyzer/lib/src/summary2/macro_application.dart
@@ -91,7 +91,7 @@
             },
             annotationIndex: application.annotationIndex,
             onError: (error) {
-              target.element.macroApplicationErrors.add(error);
+              target.element.addMacroApplicationError(error);
             },
           );
         }
@@ -114,7 +114,7 @@
             },
             annotationIndex: application.annotationIndex,
             onError: (error) {
-              target.element.macroApplicationErrors.add(error);
+              target.element.addMacroApplicationError(error);
             },
           );
         }
@@ -160,7 +160,7 @@
             },
             annotationIndex: i,
             onError: (error) {
-              targetElement.macroApplicationErrors.add(error);
+              targetElement.addMacroApplicationError(error);
             },
           );
         }
diff --git a/analyzer/lib/src/summary2/named_type_builder.dart b/analyzer/lib/src/summary2/named_type_builder.dart
index 824cc53..29370bb 100644
--- a/analyzer/lib/src/summary2/named_type_builder.dart
+++ b/analyzer/lib/src/summary2/named_type_builder.dart
@@ -16,6 +16,7 @@
 import 'package:analyzer/src/dart/element/type_visitor.dart';
 import 'package:analyzer/src/summary2/link.dart';
 import 'package:analyzer/src/summary2/type_builder.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 /// The type builder for a [NamedType].
 class NamedTypeBuilder extends TypeBuilder {
@@ -188,7 +189,7 @@
         return List.generate(arguments.length, (index) {
           var type = arguments[index];
           return _buildType(type);
-        });
+        }, growable: false);
       } else {
         return _listOfDynamic(parameters.length);
       }
@@ -197,7 +198,7 @@
         var parameter = parameters[index] as TypeParameterElementImpl;
         var defaultType = parameter.defaultType!;
         return _buildType(defaultType);
-      });
+      }, growable: false);
     }
   }
 
@@ -251,7 +252,7 @@
         _buildFormalParameterType(parameter),
         parameter.kind,
       );
-    }).toList();
+    }).toFixedList();
   }
 
   DartType _getAliasedType(TypeAliasElementImpl element) {
@@ -309,7 +310,7 @@
   }
 
   static List<DartType> _listOfDynamic(int length) {
-    return List<DartType>.filled(length, _dynamicType);
+    return List<DartType>.filled(length, _dynamicType, growable: false);
   }
 
   static void _setAliasedType(AstNode node, DartType type) {
@@ -320,7 +321,7 @@
     if (node != null) {
       return node.typeParameters
           .map<TypeParameterElement>((p) => p.declaredElement!)
-          .toList();
+          .toFixedList();
     } else {
       return const <TypeParameterElement>[];
     }
diff --git a/analyzer/lib/src/summary2/top_level_inference.dart b/analyzer/lib/src/summary2/top_level_inference.dart
index 699bba3..db1d0e3 100644
--- a/analyzer/lib/src/summary2/top_level_inference.dart
+++ b/analyzer/lib/src/summary2/top_level_inference.dart
@@ -79,11 +79,6 @@
       var astResolver = AstResolver(linker, _unitElement, _scope);
       astResolver.resolveExpression(() => variable.initializer!,
           contextType: element.type);
-      var errors = astResolver.errors;
-      if (errors.isNotEmpty) {
-        assert(errors.length == 1, 'Unexpected errors: $errors');
-        element.typeInferenceError = errors.first;
-      }
     }
 
     if (element is ConstVariableElement) {
@@ -267,12 +262,6 @@
       _status = _InferenceStatus.inferred;
     }
 
-    var errors = astResolver.errors;
-    if (errors.isNotEmpty) {
-      assert(errors.length == 1, 'Unexpected errors: $errors');
-      _element.typeInferenceError = errors.first;
-    }
-
     var initializerType = _node.initializer!.typeOrThrow;
     return _refineType(initializerType);
   }
diff --git a/analyzer/lib/src/summary2/types_builder.dart b/analyzer/lib/src/summary2/types_builder.dart
index 044a7c5..41d6d93 100644
--- a/analyzer/lib/src/summary2/types_builder.dart
+++ b/analyzer/lib/src/summary2/types_builder.dart
@@ -16,6 +16,7 @@
 import 'package:analyzer/src/summary2/default_types_builder.dart';
 import 'package:analyzer/src/summary2/link.dart';
 import 'package:analyzer/src/summary2/type_builder.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 /// Return `true` if [type] can be used as a class.
 bool _isInterfaceTypeClass(InterfaceType type) {
@@ -257,7 +258,7 @@
   List<ParameterElement> _formalParameters(FormalParameterList node) {
     return node.parameters.asImpl.map((parameter) {
       return parameter.declaredElement!;
-    }).toList();
+    }).toFixedList();
   }
 
   void _functionTypeAlias(FunctionTypeAlias node) {
@@ -348,7 +349,7 @@
 
     return node.typeParameters
         .map<TypeParameterElement>((p) => p.declaredElement!)
-        .toList();
+        .toFixedList();
   }
 
   /// The [FunctionType] to use when a function type is expected for a type
diff --git a/analyzer/lib/src/task/inference_error.dart b/analyzer/lib/src/task/inference_error.dart
index d4ebb35..9a7c57e 100644
--- a/analyzer/lib/src/task/inference_error.dart
+++ b/analyzer/lib/src/task/inference_error.dart
@@ -19,8 +19,6 @@
 /// Enum used to indicate the kind of the error during top-level inference.
 enum TopLevelInferenceErrorKind {
   none,
-  couldNotInfer,
   dependencyCycle,
-  inferenceFailureOnInstanceCreation,
   overrideNoCombinedSuperSignature,
 }
diff --git a/analyzer/lib/src/task/options.dart b/analyzer/lib/src/task/options.dart
index f56c0c0..ecaef2b 100644
--- a/analyzer/lib/src/task/options.dart
+++ b/analyzer/lib/src/task/options.dart
@@ -21,6 +21,7 @@
 import 'package:analyzer/src/plugin/options.dart';
 import 'package:analyzer/src/util/yaml.dart';
 import 'package:analyzer/src/utilities/extensions/string.dart';
+import 'package:pub_semver/pub_semver.dart';
 import 'package:source_span/source_span.dart';
 import 'package:yaml/yaml.dart';
 
@@ -31,18 +32,26 @@
   String content,
   SourceFactory sourceFactory,
   String contextRoot,
-) {
-  List<AnalysisError> errors = <AnalysisError>[];
+  VersionConstraint? sdkVersionConstraint, {
+  LintRuleProvider? provider,
+}) {
+  List<AnalysisError> errors = [];
   Source initialSource = source;
   SourceSpan? initialIncludeSpan;
   AnalysisOptionsProvider optionsProvider =
       AnalysisOptionsProvider(sourceFactory);
+  String? firstPluginName;
+  Map<Source, SourceSpan> includeChain = {};
 
-  // Validate the specified options and any included option files
-  void validate(Source source, YamlMap options) {
-    List<AnalysisError> validationErrors =
-        OptionsFileValidator(source).validate(options);
-    if (initialIncludeSpan != null && validationErrors.isNotEmpty) {
+  // TODO(srawlins): This code is getting quite complex, with multiple local
+  // functions, and should be refactored to a class maintaining state, with less
+  // variable shadowing.
+  void addDirectErrorOrIncludedError(
+      List<AnalysisError> validationErrors, Source source,
+      {required bool sourceIsOptionsForContextRoot}) {
+    if (!sourceIsOptionsForContextRoot) {
+      // [source] is an included file, and we should only report errors in
+      // [initialSource], noting that the included file has warnings.
       for (AnalysisError error in validationErrors) {
         var args = [
           source.fullName,
@@ -58,17 +67,46 @@
             args));
       }
     } else {
+      // [source] is the options file for [contextRoot]. Report all errors
+      // directly.
       errors.addAll(validationErrors);
     }
+  }
 
-    var node = options.valueAt(AnalyzerOptions.include);
-    if (node == null) {
+  // Validate the specified options and any included option files.
+  void validate(Source source, YamlMap options, LintRuleProvider? provider) {
+    var sourceIsOptionsForContextRoot = initialIncludeSpan == null;
+    var validationErrors = OptionsFileValidator(
+      source,
+      sdkVersionConstraint: sdkVersionConstraint,
+      sourceIsOptionsForContextRoot: sourceIsOptionsForContextRoot,
+      provider: provider,
+    ).validate(options);
+    addDirectErrorOrIncludedError(validationErrors, source,
+        sourceIsOptionsForContextRoot: sourceIsOptionsForContextRoot);
+
+    var includeNode = options.valueAt(AnalyzerOptions.include);
+    if (includeNode == null) {
+      // Validate the 'plugins' option in [options], understanding that no other
+      // options are included.
+      addDirectErrorOrIncludedError(
+          _validatePluginsOption(source, options: options), source,
+          sourceIsOptionsForContextRoot: sourceIsOptionsForContextRoot);
       return;
     }
-    SourceSpan span = node.span;
-    initialIncludeSpan ??= span;
-    String includeUri = span.text;
+    var includeSpan = includeNode.span;
+    initialIncludeSpan ??= includeSpan;
+    String includeUri = includeSpan.text;
     var includedSource = sourceFactory.resolveUri(source, includeUri);
+    if (includedSource == initialSource) {
+      errors.add(AnalysisError(
+          initialSource,
+          initialIncludeSpan!.start.offset,
+          initialIncludeSpan!.length,
+          AnalysisOptionsWarningCode.RECURSIVE_INCLUDE_FILE,
+          [includeUri, source.fullName]));
+      return;
+    }
     if (includedSource == null || !includedSource.exists()) {
       errors.add(AnalysisError(
           initialSource,
@@ -78,10 +116,35 @@
           [includeUri, source.fullName, contextRoot]));
       return;
     }
+    var spanInChain = includeChain[includedSource];
+    if (spanInChain != null) {
+      errors.add(AnalysisError(
+          initialSource,
+          initialIncludeSpan!.start.offset,
+          initialIncludeSpan!.length,
+          AnalysisOptionsWarningCode.INCLUDED_FILE_WARNING, [
+        includedSource,
+        spanInChain.start.offset,
+        spanInChain.length,
+        'The file includes itself recursively.',
+      ]));
+      return;
+    }
+    includeChain[includedSource] = includeSpan;
+
     try {
-      YamlMap options =
+      var includedOptions =
           optionsProvider.getOptionsFromString(includedSource.contents.data);
-      validate(includedSource, options);
+      validate(includedSource, includedOptions, provider);
+      firstPluginName ??= _firstPluginName(includedOptions);
+      // Validate the 'plugins' option in [options], taking into account any
+      // plugins enabled by [includedOptions].
+      addDirectErrorOrIncludedError(
+        _validatePluginsOption(source,
+            options: options, firstEnabledPluginName: firstPluginName),
+        source,
+        sourceIsOptionsForContextRoot: sourceIsOptionsForContextRoot,
+      );
     } on OptionsFormatException catch (e) {
       var args = [
         includedSource.fullName,
@@ -89,8 +152,8 @@
         e.span!.end.offset.toString(),
         e.message,
       ];
-      // Report errors for included option files
-      // on the include directive located in the initial options file.
+      // Report errors for included option files on the `include` directive
+      // located in the initial options file.
       errors.add(AnalysisError(
           initialSource,
           initialIncludeSpan!.start.offset,
@@ -102,7 +165,7 @@
 
   try {
     YamlMap options = optionsProvider.getOptionsFromString(content);
-    validate(source, options);
+    validate(source, options, provider);
   } on OptionsFormatException catch (e) {
     SourceSpan span = e.span!;
     errors.add(AnalysisError(source, span.start.offset, span.length,
@@ -115,6 +178,42 @@
   _processor.applyToAnalysisOptions(options, optionMap);
 }
 
+/// Returns the name of the first plugin, if one is specified in [options],
+/// otherwise `null`.
+String? _firstPluginName(YamlMap options) {
+  var analyzerMap = options.valueAt(AnalyzerOptions.analyzer);
+  if (analyzerMap is! YamlMap) {
+    return null;
+  }
+  var plugins = analyzerMap.valueAt(AnalyzerOptions.plugins);
+  if (plugins is YamlScalar) {
+    return plugins.value as String?;
+  } else if (plugins is YamlList) {
+    return plugins.first as String?;
+  } else if (plugins is YamlMap) {
+    return plugins.keys.first as String?;
+  } else {
+    return null;
+  }
+}
+
+/// Validates the 'plugins' options in [options], given
+/// [firstEnabledPluginName].
+List<AnalysisError> _validatePluginsOption(
+  Source source, {
+  required YamlMap options,
+  String? firstEnabledPluginName,
+}) {
+  RecordingErrorListener recorder = RecordingErrorListener();
+  ErrorReporter reporter = ErrorReporter(
+    recorder,
+    source,
+    isNonNullableByDefault: true,
+  );
+  PluginsOptionValidator(firstEnabledPluginName).validate(reporter, options);
+  return recorder.errors;
+}
+
 /// `analyzer` analysis options constants.
 class AnalyzerOptions {
   static const String analyzer = 'analyzer';
@@ -597,14 +696,23 @@
   /// The source being validated.
   final Source source;
 
-  final List<OptionsValidator> _validators = [
-    AnalyzerOptionsValidator(),
-    CodeStyleOptionsValidator(),
-    LinterOptionsValidator(),
-    LinterRuleOptionsValidator()
-  ];
+  final List<OptionsValidator> _validators;
 
-  OptionsFileValidator(this.source);
+  OptionsFileValidator(
+    this.source, {
+    required VersionConstraint? sdkVersionConstraint,
+    required bool sourceIsOptionsForContextRoot,
+    LintRuleProvider? provider,
+  }) : _validators = [
+          AnalyzerOptionsValidator(),
+          CodeStyleOptionsValidator(),
+          LinterOptionsValidator(),
+          LinterRuleOptionsValidator(
+            provider: provider,
+            sdkVersionConstraint: sdkVersionConstraint,
+            sourceIsOptionsForContextRoot: sourceIsOptionsForContextRoot,
+          ),
+        ];
 
   List<AnalysisError> validate(YamlMap options) {
     RecordingErrorListener recorder = RecordingErrorListener();
@@ -620,6 +728,103 @@
   }
 }
 
+/// Validates `analyzer` plugins configuration options.
+class PluginsOptionValidator extends OptionsValidator {
+  /// The name of the first included plugin, if there is one.
+  ///
+  /// If there are no included plugins, this is `null`.
+  final String? _firstIncludedPluginName;
+
+  PluginsOptionValidator(this._firstIncludedPluginName);
+
+  @override
+  void validate(ErrorReporter reporter, YamlMap options) {
+    var analyzer = options.valueAt(AnalyzerOptions.analyzer);
+    if (analyzer is! YamlMap) {
+      return;
+    }
+    var plugins = analyzer.valueAt(AnalyzerOptions.plugins);
+    if (plugins is YamlScalar && plugins.value != null) {
+      if (_firstIncludedPluginName != null &&
+          _firstIncludedPluginName != plugins.value) {
+        reporter.reportErrorForSpan(
+          AnalysisOptionsWarningCode.MULTIPLE_PLUGINS,
+          plugins.span,
+          [_firstIncludedPluginName!],
+        );
+      }
+    } else if (plugins is YamlList) {
+      var pluginValues = plugins.nodes.whereType<YamlNode>().toList();
+      if (_firstIncludedPluginName != null) {
+        // There is already at least one plugin specified in included options.
+        for (var plugin in pluginValues) {
+          if (plugin.value != _firstIncludedPluginName) {
+            reporter.reportErrorForSpan(
+              AnalysisOptionsWarningCode.MULTIPLE_PLUGINS,
+              plugin.span,
+              [_firstIncludedPluginName!],
+            );
+          }
+        }
+      } else if (plugins.length > 1) {
+        String? firstPlugin;
+        for (var plugin in pluginValues) {
+          if (firstPlugin == null) {
+            var pluginValue = plugin.value;
+            if (pluginValue is String) {
+              firstPlugin = pluginValue;
+              continue;
+            } else {
+              // This plugin is bad and should not be marked as the first one.
+              continue;
+            }
+          } else if (plugin.value != firstPlugin) {
+            reporter.reportErrorForSpan(
+              AnalysisOptionsWarningCode.MULTIPLE_PLUGINS,
+              plugin.span,
+              [firstPlugin],
+            );
+          }
+        }
+      }
+    } else if (plugins is YamlMap) {
+      var pluginValues = plugins.nodes.keys.cast<YamlNode?>();
+      if (_firstIncludedPluginName != null) {
+        // There is already at least one plugin specified in included options.
+        for (var plugin in pluginValues) {
+          if (plugin != null && plugin.value != _firstIncludedPluginName) {
+            reporter.reportErrorForSpan(
+              AnalysisOptionsWarningCode.MULTIPLE_PLUGINS,
+              plugin.span,
+              [_firstIncludedPluginName!],
+            );
+          }
+        }
+      } else if (plugins.length > 1) {
+        String? firstPlugin;
+        for (var plugin in pluginValues) {
+          if (firstPlugin == null) {
+            var pluginValue = plugin?.value;
+            if (pluginValue is String) {
+              firstPlugin = pluginValue;
+              continue;
+            } else {
+              // This plugin is bad and should not be marked as the first one.
+              continue;
+            }
+          } else if (plugin != null && plugin.value != firstPlugin) {
+            reporter.reportErrorForSpan(
+              AnalysisOptionsWarningCode.MULTIPLE_PLUGINS,
+              plugin.span,
+              [firstPlugin],
+            );
+          }
+        }
+      }
+    }
+  }
+}
+
 /// Validates `analyzer` strong-mode value configuration options.
 class StrongModeOptionValueValidator extends OptionsValidator {
   final ErrorBuilder _builder = ErrorBuilder(AnalyzerOptions.strongModeOptions);
@@ -689,7 +894,7 @@
       reporter.reportErrorForSpan(
           AnalysisOptionsWarningCode.UNSUPPORTED_VALUE, strongModeNode.span, [
         AnalyzerOptions.strongMode,
-        strongModeNode.value,
+        strongModeNode.valueOrThrow,
         AnalyzerOptions.trueOrFalseProposal
       ]);
     } else if (stringValue == 'false') {
@@ -793,27 +998,8 @@
       _applyUnignorables(options, cannotIgnore);
 
       // Process plugins.
-      var names = analyzer.valueAt(AnalyzerOptions.plugins);
-      List<String> pluginNames = <String>[];
-      var pluginName = _toString(names);
-      if (pluginName != null) {
-        pluginNames.add(pluginName);
-      } else if (names is YamlList) {
-        for (var element in names.nodes) {
-          var pluginName = _toString(element);
-          if (pluginName != null) {
-            pluginNames.add(pluginName);
-          }
-        }
-      } else if (names is YamlMap) {
-        for (var key in names.nodes.keys.cast<YamlNode?>()) {
-          var pluginName = _toString(key);
-          if (pluginName != null) {
-            pluginNames.add(pluginName);
-          }
-        }
-      }
-      options.enabledPluginNames = pluginNames;
+      var plugins = analyzer.valueAt(AnalyzerOptions.plugins);
+      _applyPlugins(options, plugins);
     }
 
     // Process the 'code-style' option.
@@ -892,6 +1078,31 @@
     }
   }
 
+  void _applyPlugins(AnalysisOptionsImpl options, YamlNode? plugins) {
+    var pluginName = _toString(plugins);
+    if (pluginName != null) {
+      options.enabledPluginNames = [pluginName];
+    } else if (plugins is YamlList) {
+      for (var element in plugins.nodes) {
+        var pluginName = _toString(element);
+        if (pluginName != null) {
+          // Only the first plugin is supported.
+          options.enabledPluginNames = [pluginName];
+          return;
+        }
+      }
+    } else if (plugins is YamlMap) {
+      for (var key in plugins.nodes.keys.cast<YamlNode?>()) {
+        var pluginName = _toString(key);
+        if (pluginName != null) {
+          // Only the first plugin is supported.
+          options.enabledPluginNames = [pluginName];
+          return;
+        }
+      }
+    }
+  }
+
   void _applyProcessors(AnalysisOptionsImpl options, YamlNode? codes) {
     ErrorConfig config = ErrorConfig(codes);
     options.errorProcessors = config.processors;
diff --git a/analyzer/lib/src/test_utilities/find_element.dart b/analyzer/lib/src/test_utilities/find_element.dart
index d642f21..6db2857 100644
--- a/analyzer/lib/src/test_utilities/find_element.dart
+++ b/analyzer/lib/src/test_utilities/find_element.dart
@@ -139,6 +139,9 @@
       declaredIdentifier: (node) {
         updateResult(node.declaredElement!);
       },
+      declaredVariablePattern: (node) {
+        updateResult(node.declaredElement!);
+      },
       variableDeclaration: (node) {
         updateResult(node.declaredElement!);
       },
diff --git a/analyzer/lib/src/test_utilities/find_node.dart b/analyzer/lib/src/test_utilities/find_node.dart
index 3a67104..aab3ed7 100644
--- a/analyzer/lib/src/test_utilities/find_node.dart
+++ b/analyzer/lib/src/test_utilities/find_node.dart
@@ -27,6 +27,32 @@
     return result;
   }
 
+  /// Returns the [ForElement], there must be only one.
+  ForElement get singleForElement {
+    var nodes = <ForElement>[];
+    unit.accept(
+      FunctionAstVisitor(
+        forElement: (node) {
+          nodes.add(node);
+        },
+      ),
+    );
+    return nodes.single;
+  }
+
+  /// Returns the [ForStatement], there must be only one.
+  ForStatement get singleForStatement {
+    var nodes = <ForStatement>[];
+    unit.accept(
+      FunctionAstVisitor(
+        forStatement: (node) {
+          nodes.add(node);
+        },
+      ),
+    );
+    return nodes.single;
+  }
+
   /// Returns the [GuardedPattern], there must be only one.
   GuardedPattern get singleGuardedPattern {
     var nodes = <GuardedPattern>[];
@@ -87,6 +113,19 @@
     return nodes.single;
   }
 
+  /// Returns the [SwitchExpression], there must be only one.
+  SwitchExpression get singleSwitchExpression {
+    var nodes = <SwitchExpression>[];
+    unit.accept(
+      FunctionAstVisitor(
+        switchExpression: (node) {
+          nodes.add(node);
+        },
+      ),
+    );
+    return nodes.single;
+  }
+
   AdjacentStrings adjacentStrings(String search) {
     return _node(search, (n) => n is AdjacentStrings);
   }
@@ -107,6 +146,10 @@
     return _node(search, (n) => n is AsExpression);
   }
 
+  AsExpression asExpression(String search) {
+    return _node(search, (n) => n is AsExpression);
+  }
+
   AssertStatement assertStatement(String search) {
     return _node(search, (n) => n is AssertStatement);
   }
@@ -131,10 +174,6 @@
     return _node(search, (n) => n is BinaryExpression);
   }
 
-  BinaryPattern binaryPattern(String search) {
-    return _node(search, (n) => n is BinaryPattern);
-  }
-
   Block block(String search) {
     return _node(search, (n) => n is Block);
   }
@@ -455,6 +494,14 @@
     return _node(search, (n) => n is ListPattern);
   }
 
+  LogicalAndPattern logicalAndPattern(String search) {
+    return _node(search, (n) => n is LogicalAndPattern);
+  }
+
+  LogicalOrPattern logicalOrPattern(String search) {
+    return _node(search, (n) => n is LogicalOrPattern);
+  }
+
   MapLiteralEntry mapLiteralEntry(String search) {
     return _node(search, (n) => n is MapLiteralEntry);
   }
@@ -499,6 +546,14 @@
     return _node(search, (n) => n is NativeFunctionBody);
   }
 
+  NullAssertPattern nullAssertPattern(String search) {
+    return _node(search, (n) => n is NullAssertPattern);
+  }
+
+  NullCheckPattern nullCheckPattern(String search) {
+    return _node(search, (n) => n is NullCheckPattern);
+  }
+
   NullLiteral nullLiteral(String search) {
     return _node(search, (n) => n is NullLiteral);
   }
@@ -540,6 +595,14 @@
     return _node(search, (n) => n is PatternAssignment);
   }
 
+  PatternField patternField(String search) {
+    return _node(search, (n) => n is PatternField);
+  }
+
+  PatternFieldName patternFieldName(String search) {
+    return _node(search, (n) => n is PatternFieldName);
+  }
+
   PatternVariableDeclaration patternVariableDeclaration(String search) {
     return _node(search, (n) => n is PatternVariableDeclaration);
   }
@@ -553,10 +616,6 @@
     return _node(search, (n) => n is PostfixExpression);
   }
 
-  PostfixPattern postfixPattern(String search) {
-    return _node(search, (n) => n is PostfixPattern);
-  }
-
   PrefixExpression prefix(String search) {
     return _node(search, (n) => n is PrefixExpression);
   }
@@ -577,14 +636,6 @@
     return _node(search, (n) => n is RecordPattern);
   }
 
-  RecordPatternField recordPatternField(String search) {
-    return _node(search, (n) => n is RecordPatternField);
-  }
-
-  RecordPatternFieldName recordPatternFieldName(String search) {
-    return _node(search, (n) => n is RecordPatternFieldName);
-  }
-
   RecordTypeAnnotation recordTypeAnnotation(String search) {
     return _node(search, (n) => n is RecordTypeAnnotation);
   }
@@ -759,6 +810,10 @@
     return _node(search, (n) => n is WhileStatement);
   }
 
+  WildcardPattern wildcardPattern(String search) {
+    return _node(search, (n) => n is WildcardPattern);
+  }
+
   WithClause withClause(String search) {
     return _node(search, (n) => n is WithClause);
   }
diff --git a/analyzer/lib/src/test_utilities/function_ast_visitor.dart b/analyzer/lib/src/test_utilities/function_ast_visitor.dart
index 61bed73..eba58a8 100644
--- a/analyzer/lib/src/test_utilities/function_ast_visitor.dart
+++ b/analyzer/lib/src/test_utilities/function_ast_visitor.dart
@@ -9,6 +9,9 @@
 class FunctionAstVisitor extends RecursiveAstVisitor<void> {
   final void Function(CatchClauseParameter)? catchClauseParameter;
   final void Function(DeclaredIdentifier)? declaredIdentifier;
+  final void Function(DeclaredVariablePattern)? declaredVariablePattern;
+  final void Function(ForElement)? forElement;
+  final void Function(ForStatement)? forStatement;
   final void Function(FunctionDeclarationStatement)?
       functionDeclarationStatement;
   final void Function(FunctionExpression, bool)? functionExpression;
@@ -21,6 +24,7 @@
   final void Function(PatternVariableDeclarationStatement)?
       patternVariableDeclarationStatement;
   final void Function(SimpleIdentifier)? simpleIdentifier;
+  final void Function(SwitchExpression)? switchExpression;
   final void Function(SwitchExpressionCase)? switchExpressionCase;
   final void Function(SwitchPatternCase)? switchPatternCase;
   final void Function(VariableDeclaration)? variableDeclaration;
@@ -28,6 +32,9 @@
   FunctionAstVisitor({
     this.catchClauseParameter,
     this.declaredIdentifier,
+    this.declaredVariablePattern,
+    this.forElement,
+    this.forStatement,
     this.functionDeclarationStatement,
     this.functionExpression,
     this.guardedPattern,
@@ -38,6 +45,7 @@
     this.patternVariableDeclaration,
     this.patternVariableDeclarationStatement,
     this.simpleIdentifier,
+    this.switchExpression,
     this.switchExpressionCase,
     this.switchPatternCase,
     this.variableDeclaration,
@@ -58,6 +66,28 @@
   }
 
   @override
+  void visitDeclaredVariablePattern(DeclaredVariablePattern node) {
+    declaredVariablePattern?.call(node);
+    super.visitDeclaredVariablePattern(node);
+  }
+
+  @override
+  void visitForElement(ForElement node) {
+    if (forElement != null) {
+      forElement!(node);
+    }
+    super.visitForElement(node);
+  }
+
+  @override
+  void visitForStatement(ForStatement node) {
+    if (forStatement != null) {
+      forStatement!(node);
+    }
+    super.visitForStatement(node);
+  }
+
+  @override
   void visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
     if (functionDeclarationStatement != null) {
       functionDeclarationStatement!(node);
@@ -131,6 +161,12 @@
   }
 
   @override
+  void visitSwitchExpression(SwitchExpression node) {
+    switchExpression?.call(node);
+    super.visitSwitchExpression(node);
+  }
+
+  @override
   void visitSwitchExpressionCase(SwitchExpressionCase node) {
     switchExpressionCase?.call(node);
     super.visitSwitchExpressionCase(node);
diff --git a/analyzer/lib/src/test_utilities/mock_packages.dart b/analyzer/lib/src/test_utilities/mock_packages.dart
index d6c64be..6dd9139 100644
--- a/analyzer/lib/src/test_utilities/mock_packages.dart
+++ b/analyzer/lib/src/test_utilities/mock_packages.dart
@@ -84,6 +84,8 @@
 
 const _Protected protected = _Protected();
 
+const _Reopen reopen = _Reopen();
+
 const Required required = Required();
 
 const _Sealed sealed = _Sealed();
@@ -103,6 +105,14 @@
   const Immutable([this.reason = '']);
 }
 
+@Target({
+  TargetKind.classType,
+  TargetKind.mixinType,
+})
+class _Reopen {
+  const _Reopen();
+}
+
 class Required {
   final String reason;
 
diff --git a/analyzer/lib/src/test_utilities/mock_sdk.dart b/analyzer/lib/src/test_utilities/mock_sdk.dart
index edbed2e..8a97b2b 100644
--- a/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -333,6 +333,7 @@
   static const double minPositive = 5e-324;
   static const double maxFinite = 1.7976931348623157e+308;
 
+  bool get isNaN;
   double get sign;
   double operator %(num other);
   double operator *(num other);
@@ -363,6 +364,17 @@
   int compareTo(Duration other) => 0;
 }
 
+abstract class Enum {
+  int get index; // Enum
+  String get _name;
+}
+
+abstract class _Enum implements Enum {
+  final int index;
+  final String _name;
+  const _Enum(this.index, this._name);
+}
+
 class Error {
   Error();
   static String safeToString(Object? object) => '';
@@ -567,17 +579,6 @@
   static int hashAllUnordered(Iterable<Object?> objects) => 0;
 }
 
-abstract class Enum {
-  int get index; // Enum
-  String get _name;
-}
-
-abstract class _Enum implements Enum {
-  final int index;
-  final String _name;
-  const _Enum(this.index, this._name);
-}
-
 abstract class Pattern {
   Iterable<Match> allMatches(String string, [int start = 0]);
 }
@@ -610,6 +611,10 @@
       throw '';
 }
 
+abstract class Sink {
+  void close();
+}
+
 class StackTrace {}
 
 abstract class String implements Comparable<String>, Pattern {
@@ -887,6 +892,8 @@
 abstract class Finalizable {
   factory Finalizable._() => throw UnsupportedError("");
 }
+
+abstract class VarArgs<T extends Record> extends NativeType {}
 ''',
   )
 ]);
@@ -1231,6 +1238,10 @@
     Encoding? stderrEncoding,
   });
 }
+
+abstract class Socket {
+  void destroy() {}
+}
 ''',
     )
   ],
diff --git a/analyzer/lib/src/test_utilities/test_code_format.dart b/analyzer/lib/src/test_utilities/test_code_format.dart
index bd93eb8..dedf1bf 100644
--- a/analyzer/lib/src/test_utilities/test_code_format.dart
+++ b/analyzer/lib/src/test_utilities/test_code_format.dart
@@ -193,7 +193,7 @@
   /// Returns whether the end of the string has been reached.
   bool get isDone => _position == _source.length;
 
-  /// Returns the last match from scalling [scan] if the position has not
+  /// Returns the last match from scaling [scan] if the position has not
   /// advanced since.
   Match? get lastMatch {
     return _position == _lastMatchPosition ? _lastMatch : null;
diff --git a/analyzer/lib/src/util/ast_data_extractor.dart b/analyzer/lib/src/util/ast_data_extractor.dart
index ff0650a..8ad5243 100644
--- a/analyzer/lib/src/util/ast_data_extractor.dart
+++ b/analyzer/lib/src/util/ast_data_extractor.dart
@@ -77,6 +77,12 @@
     registerValue(uri, _nodeOffset(node), id, value, node);
   }
 
+  void computeForNode(AstNode node, NodeId? id) {
+    if (id == null) return;
+    T? value = computeNodeValue(id, node);
+    registerValue(uri, _nodeOffset(node), id, value, node);
+  }
+
   void computeForStatement(Statement node, NodeId? id) {
     if (id == null) return;
     T? value = computeNodeValue(id, node);
@@ -187,6 +193,12 @@
   }
 
   @override
+  void visitSwitchMember(SwitchMember node) {
+    computeForNode(node, computeDefaultNodeId(node));
+    super.visitSwitchMember(node);
+  }
+
+  @override
   void visitVariableDeclaration(VariableDeclaration node) {
     if (node.parent!.parent is TopLevelVariableDeclaration) {
       computeForMember(node, createMemberId(node));
diff --git a/analyzer/lib/src/utilities/extensions/collection.dart b/analyzer/lib/src/utilities/extensions/collection.dart
index 8563d02..645aac0 100644
--- a/analyzer/lib/src/utilities/extensions/collection.dart
+++ b/analyzer/lib/src/utilities/extensions/collection.dart
@@ -2,6 +2,17 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+extension IterableExtension<E> on Iterable<E> {
+  /// Returns the fixed-length [List] with elements of `this`.
+  List<E> toFixedList() {
+    var result = toList(growable: false);
+    if (result.isEmpty) {
+      return const <Never>[];
+    }
+    return result;
+  }
+}
+
 extension ListExtension<E> on List<E> {
   void addIfNotNull(E? element) {
     if (element != null) {
diff --git a/analyzer/lib/src/utilities/uri_cache.dart b/analyzer/lib/src/utilities/uri_cache.dart
new file mode 100644
index 0000000..8c9feb3
--- /dev/null
+++ b/analyzer/lib/src/utilities/uri_cache.dart
@@ -0,0 +1,98 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:_fe_analyzer_shared/src/util/resolve_relative_uri.dart';
+
+/// The instance of [UriCache] that should be used in the analyzer.
+final UriCache uriCache = UriCache();
+
+/// The object that provides the [Uri] instance for each unique string,
+/// representing either relative or absolute URI.
+///
+/// In a package it is usual to have multiple libraries, which import same
+/// other libraries. This means that when we process import directives,
+/// we get the same URIs. We don't want to create new instances of [Uri] for
+/// each such URI string. So, each method of this class returns either the
+/// already cached instance of [Uri], or creates a new instance, puts it into
+/// the cache, and returns.
+///
+/// When a [Uri] instance is not used anymore, it will be garbage collected,
+/// because the cache uses [WeakReference]s.
+class UriCache {
+  static const _getCountBeforePruning = 10000;
+  static const _minLengthForPruning = 1000;
+
+  final Map<String, WeakReference<Uri>> _map = {};
+  int _getCount = 0;
+
+  /// Returns the [Uri] for [uriStr].
+  Uri parse(String uriStr) {
+    return _parse(uriStr);
+  }
+
+  /// Resolves [contained] against [base].
+  Uri resolveRelative(Uri base, Uri contained) {
+    if (contained.isAbsolute) {
+      return contained;
+    }
+    var result = resolveRelativeUri(base, contained);
+    return _unique(result);
+  }
+
+  /// Returns the [Uri] for [uriStr], or `null` if it cannot be parsed.
+  Uri? tryParse(String uriStr) {
+    _prune();
+    var result = _map[uriStr]?.target;
+    if (result == null) {
+      result = Uri.tryParse(uriStr);
+      if (result != null) {
+        _put(uriStr, result);
+      }
+    }
+    return result;
+  }
+
+  /// Returns the [Uri] for [uriStr], or given [uri] if provided.
+  Uri _parse(String uriStr, {Uri? uri}) {
+    _prune();
+    var result = _map[uriStr]?.target;
+    if (result == null) {
+      result = uri ?? Uri.parse(uriStr);
+      _put(uriStr, result);
+    }
+    return result;
+  }
+
+  void _prune() {
+    if (_getCount++ < _getCountBeforePruning) {
+      return;
+    }
+    _getCount = 0;
+
+    if (_map.length < _minLengthForPruning) {
+      return;
+    }
+
+    final keysToRemove = <String>[];
+    for (final entry in _map.entries) {
+      if (entry.value.target == null) {
+        keysToRemove.add(entry.key);
+      }
+    }
+
+    for (final key in keysToRemove) {
+      _map.remove(key);
+    }
+  }
+
+  void _put(String uriStr, Uri uri) {
+    _map[uriStr] = WeakReference(uri);
+  }
+
+  /// Returns the shared [Uri] for the given [uri].
+  Uri _unique(Uri uri) {
+    var uriStr = uri.toString();
+    return _parse(uriStr, uri: uri);
+  }
+}
diff --git a/analyzer/lib/src/workspace/blaze.dart b/analyzer/lib/src/workspace/blaze.dart
index 32af5d8..5a1de4f 100644
--- a/analyzer/lib/src/workspace/blaze.dart
+++ b/analyzer/lib/src/workspace/blaze.dart
@@ -12,6 +12,7 @@
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:analyzer/src/util/file_paths.dart' as file_paths;
 import 'package:analyzer/src/util/uri.dart';
+import 'package:analyzer/src/utilities/uri_cache.dart';
 import 'package:analyzer/src/workspace/blaze_watcher.dart';
 import 'package:analyzer/src/workspace/workspace.dart';
 import 'package:path/path.dart' as path;
@@ -77,7 +78,7 @@
     ]) {
       var uriParts = _restoreUriParts(root, path);
       if (uriParts != null) {
-        return Uri.parse('package:${uriParts[0]}/${uriParts[1]}');
+        return uriCache.parse('package:${uriParts[0]}/${uriParts[1]}');
       }
     }
 
diff --git a/analyzer/lib/src/workspace/blaze_watcher.dart b/analyzer/lib/src/workspace/blaze_watcher.dart
index 10dea55..328987a 100644
--- a/analyzer/lib/src/workspace/blaze_watcher.dart
+++ b/analyzer/lib/src/workspace/blaze_watcher.dart
@@ -279,7 +279,7 @@
 ///    isolate is supposed to shut down. No more messages should be exchanged
 ///    afterwards.
 class BlazeFileWatcherService {
-  final InstrumentationService _instrumetation;
+  final InstrumentationService _instrumentation;
 
   final _events = StreamController<List<WatchEvent>>.broadcast();
 
@@ -296,7 +296,7 @@
   /// True if the isolate is ready to watch files.
   final _isolateHasStarted = Completer<void>();
 
-  BlazeFileWatcherService(this._instrumetation);
+  BlazeFileWatcherService(this._instrumentation);
 
   Stream<List<WatchEvent>> get events => _events.stream;
 
@@ -342,9 +342,9 @@
     } else if (message is BlazeWatcherEvents) {
       _events.add(message.events);
     } else if (message is BlazeWatcherError) {
-      _instrumetation.logError(message.message);
+      _instrumentation.logError(message.message);
     } else {
-      _instrumetation.logError(
+      _instrumentation.logError(
           'Received unexpected message from BlazeFileWatcherIsolate: $message');
     }
   }
diff --git a/analyzer/lib/src/workspace/package_build.dart b/analyzer/lib/src/workspace/package_build.dart
index e9ce5dc..d49c7f8 100644
--- a/analyzer/lib/src/workspace/package_build.dart
+++ b/analyzer/lib/src/workspace/package_build.dart
@@ -12,6 +12,7 @@
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:analyzer/src/util/file_paths.dart' as file_paths;
 import 'package:analyzer/src/util/uri.dart';
+import 'package:analyzer/src/utilities/uri_cache.dart';
 import 'package:analyzer/src/workspace/pub.dart';
 import 'package:analyzer/src/workspace/workspace.dart';
 import 'package:meta/meta.dart';
@@ -27,6 +28,28 @@
   PackageBuildFileUriResolver(this.workspace) : super(workspace.provider);
 
   @override
+  Uri pathToUri(String path) {
+    var pathContext = workspace.provider.pathContext;
+    if (pathContext.isWithin(workspace.root, path)) {
+      var relative = pathContext.relative(path, from: workspace.root);
+      var components = pathContext.split(relative);
+      if (components.length > 4 &&
+          components[0] == '.dart_tool' &&
+          components[1] == 'build' &&
+          components[2] == 'generated' &&
+          components[3] == workspace.projectPackageName) {
+        var canonicalPath = pathContext.joinAll([
+          workspace.root,
+          ...components.skip(4),
+        ]);
+        return pathContext.toUri(canonicalPath);
+      }
+    }
+
+    return super.pathToUri(path);
+  }
+
+  @override
   Source? resolveAbsolute(Uri uri) {
     if (!ResourceUriResolver.isFileUri(uri)) {
       return null;
@@ -64,7 +87,7 @@
     if (_context.isWithin(_workspace.root, path)) {
       var uriParts = _restoreUriParts(path);
       if (uriParts != null) {
-        return Uri.parse('package:${uriParts[0]}/${uriParts[1]}');
+        return uriCache.parse('package:${uriParts[0]}/${uriParts[1]}');
       }
     }
 
diff --git a/analyzer/lib/src/workspace/workspace.dart b/analyzer/lib/src/workspace/workspace.dart
index 1b47d0c..16b5488 100644
--- a/analyzer/lib/src/workspace/workspace.dart
+++ b/analyzer/lib/src/workspace/workspace.dart
@@ -102,10 +102,10 @@
 /// Classes that provide information of such a workspace should implement this
 /// interface.
 class WorkspaceWithDefaultAnalysisOptions {
-  /// The uri for the default analysis options file.
+  /// The URI for the default analysis options file.
   static const String uri = 'package:dart.analysis_options/default.yaml';
 
-  ///  The uri for third_party analysis options file.
+  ///  The URI for third_party analysis options file.
   static const String thirdPartyUri =
       'package:dart.analysis_options/third_party.yaml';
 }
diff --git a/analyzer/messages.yaml b/analyzer/messages.yaml
index 1609b04..4b1dc5d 100644
--- a/analyzer/messages.yaml
+++ b/analyzer/messages.yaml
@@ -92,7 +92,7 @@
       An error code indicating a specified include file could not be found.
 
       Parameters:
-      0: the uri of the file to be included
+      0: the URI of the file to be included
       1: the path of the file containing the include directive
       2: the path of the context being analyzed
   INVALID_OPTION:
@@ -111,6 +111,23 @@
 
       Parameters:
       0: the section name
+  MULTIPLE_PLUGINS:
+    problemMessage: "Multiple plugins can't be enabled."
+    correctionMessage: "Remove all plugins following the first, '{0}'."
+    comment: |-
+      An error code indicating multiple plugins have been specified as enabled.
+
+      Parameters:
+      0: the name of the first plugin
+  RECURSIVE_INCLUDE_FILE:
+    problemMessage: "The include file '{0}' in '{1}' includes itself recursively."
+    correctionMessage: "Try changing the chain of 'include's to not re-include this file."
+    comment: |-
+      An error code indicating a specified include file includes itself recursively.
+
+      Parameters:
+      0: the URI of the file to be included
+      1: the path of the file containing the include directive
   REMOVED_LINT:
     problemMessage: "'{0}' was removed in Dart '{1}'"
     correctionMessage: "Remove the reference to '{0}'."
@@ -1004,7 +1021,7 @@
       ```
   ASYNC_FOR_IN_WRONG_CONTEXT:
     problemMessage: The async for-in loop can only be used in an async function.
-    correctionMessage: "Try marking the function body with either 'async' or 'async*', or removing the 'await' before the for-in loop."
+    correctionMessage: Try marking the function body with either 'async' or 'async*', or removing the 'await' before the for-in loop.
     hasPublishedDocs: true
     comment: No parameters.
     documentation: |-
@@ -1105,13 +1122,25 @@
       ```
   AWAIT_IN_WRONG_CONTEXT:
     problemMessage: The await expression can only be used in an async function.
-    correctionMessage: "Try marking the function body with either 'async' or 'async*'."
+    correctionMessage: Try marking the function body with either 'async' or 'async*'.
     comment: |-
       16.30 Await Expressions: It is a compile-time error if the function
       immediately enclosing _a_ is not declared asynchronous. (Where _a_ is the
       await expression.)
+  BASE_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY:
+    sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
+    problemMessage: "The class '{0}' can't be implemented outside of its library because it's a base class."
+    comment: |-
+      Parameters:
+      0: the name of the base class being implemented
+  BASE_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY:
+    sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
+    problemMessage: "The mixin '{0}' can't be implemented outside of its library because it's a base mixin."
+    comment: |-
+      Parameters:
+      0: the name of the base mixin being implemented
   BODY_MIGHT_COMPLETE_NORMALLY:
-    problemMessage: "The body might complete normally, causing 'null' to be returned, but the return type, '{0}', is a potentially non-nullable type."
+    problemMessage: The body might complete normally, causing 'null' to be returned, but the return type, '{0}', is a potentially non-nullable type.
     correctionMessage: Try adding either a return or a throw statement at the end.
     hasPublishedDocs: true
     comment: |-
@@ -1190,7 +1219,7 @@
       }
       ```
   BREAK_LABEL_ON_SWITCH_MEMBER:
-    problemMessage: "A break label resolves to the 'case' or 'default' statement."
+    problemMessage: A break label resolves to the 'case' or 'default' statement.
     hasPublishedDocs: true
     comment: No parameters.
     documentation: |-
@@ -1247,7 +1276,7 @@
       }
       ```
   BUILT_IN_IDENTIFIER_AS_TYPE:
-    problemMessage: "The built-in identifier '{0}' can't be used as a type."
+    problemMessage: The built-in identifier '{0}' can't be used as a type.
     correctionMessage: Try correcting the name to match an existing type.
     hasPublishedDocs: true
     comment: |-
@@ -1568,6 +1597,11 @@
       num x = 0;
       int y = x as int;
       ```
+  CLASS_USED_AS_MIXIN:
+    problemMessage: "The class '{0}' can't be used as a mixin because it isn't a mixin class nor a mixin."
+    comment: |-
+      Parameters:
+      0: the name of the class being used as a mixin
   CLASS_INSTANTIATION_ACCESS_TO_INSTANCE_MEMBER:
     sharedName: CLASS_INSTANTIATION_ACCESS_TO_MEMBER
     problemMessage: "The instance member '{0}' can't be accessed on a class instantiation."
@@ -2910,9 +2944,11 @@
     problemMessage: The expression of a constant pattern must be a valid constant.
     correctionMessage: Try making the expression a valid constant.
     comment: No parameters.
-  CONTINUE_LABEL_ON_SWITCH:
-    problemMessage: A `continue` label resolves to a `switch` statement, but the label must be on a loop or a switch member.
+  CONTINUE_LABEL_INVALID:
+    previousName: CONTINUE_LABEL_ON_SWITCH
     hasPublishedDocs: true
+    problemMessage: The label used in a 'continue' statement must be defined on either a loop or a switch member.
+    comment: No parameters.
     documentation: |-
       #### Description
 
@@ -2928,7 +2964,7 @@
       void f(int i) {
         l: switch (i) {
           case 0:
-            continue [!l!];
+            [!continue l;!]
         }
       }
       ```
@@ -3555,12 +3591,21 @@
 
       part 'part.dart';
       ```
-  DUPLICATE_RECORD_PATTERN_FIELD:
+  DUPLICATE_PATTERN_ASSIGNMENT_VARIABLE:
+    problemMessage: The variable '{0}' is already assigned in this pattern.
+    correctionMessage: Try renaming the variable.
+    comment: |-
+      Parameters:
+      0: the name of the variable
+  DUPLICATE_PATTERN_FIELD:
     problemMessage: The field '{0}' is already matched in this pattern.
     correctionMessage: Try removing the duplicate field.
     comment: |-
       Parameters:
       0: the name of the field
+  DUPLICATE_REST_ELEMENT_IN_PATTERN:
+    problemMessage: At most one rest element is allowed in a list or map pattern.
+    correctionMessage: Try removing the duplicate rest element.
   DUPLICATE_VARIABLE_PATTERN:
     problemMessage: The variable '{0}' is already defined in this pattern.
     correctionMessage: Try renaming the variable.
@@ -3831,6 +3876,10 @@
       Note that literal maps preserve the order of their entries, so the choice
       of which entry to remove might affect the order in which keys and values
       are returned by an iterator.
+  EQUAL_KEYS_IN_MAP_PATTERN:
+    problemMessage: Two keys in a map pattern can't be equal.
+    correctionMessage: Change or remove the duplicate key.
+    comment: No parameters.
   EXPECTED_ONE_LIST_PATTERN_TYPE_ARGUMENTS:
     problemMessage: List patterns require one type argument or none, but {0} found.
     correctionMessage: Try adjusting the number of type arguments.
@@ -3935,7 +3984,7 @@
     hasPublishedDocs: true
     comment: |-
       Parameters:
-      0: the uri pointing to a library
+      0: the URI pointing to a library
     documentation: |-
       #### Description
 
@@ -4013,7 +4062,7 @@
     hasPublishedDocs: true
     comment: |-
       Parameters:
-      0: the uri pointing to a non-library declaration
+      0: the URI pointing to a non-library declaration
     documentation: |-
       #### Description
 
@@ -4969,6 +5018,18 @@
         C(String s) : f = int.parse(s);
       }
       ```
+  FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY:
+    sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
+    problemMessage: "The class '{0}' can't be extended outside of its library because it's a final class."
+    comment: |-
+      Parameters:
+      0: the name of the final class being extended.
+  FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY:
+    sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
+    problemMessage: "The class '{0}' can't be implemented outside of its library because it's a final class."
+    comment: |-
+      Parameters:
+      0: the name of the final class being implemented.
   FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR:
     problemMessage: "'{0}' is final and was given a value when it was declared, so it can't be set to a new value."
     correctionMessage: Try removing one of the initializations.
@@ -5018,6 +5079,18 @@
         C(this.f);
       }
       ```
+  FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY:
+    sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
+    problemMessage: "The mixin '{0}' can't be implemented outside of its library because it's a final mixin."
+    comment: |-
+      Parameters:
+      0: the name of the final mixin being implemented.
+  FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY:
+    sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
+    problemMessage: "The mixin '{0}' can't be mixed-in outside of its library because it's a final mixin."
+    comment: |-
+      Parameters:
+      0: the name of the final mixin being mixed in.
   FINAL_NOT_INITIALIZED:
     problemMessage: "The final variable '{0}' must be initialized."
     correctionMessage: Try initializing the variable.
@@ -5230,7 +5303,7 @@
       }
       ```
   FOR_IN_OF_INVALID_TYPE:
-    problemMessage: "The type '{0}' used in the 'for' loop must implement {1}."
+    problemMessage: "The type '{0}' used in the 'for' loop must implement '{1}'."
     hasPublishedDocs: true
     comment: |-
       Parameters:
@@ -5944,7 +6017,7 @@
     hasPublishedDocs: true
     comment: |-
       Parameters:
-      0: the uri pointing to a library
+      0: the URI pointing to a library
     documentation: |-
       #### Description
 
@@ -5968,7 +6041,7 @@
     correctionMessage: Try importing the library that the part is a part of.
     comment: |-
       Parameters:
-      0: the uri pointing to a non-library declaration
+      0: the URI pointing to a non-library declaration
     hasPublishedDocs: true
     documentation: |-
       #### Description
@@ -6100,7 +6173,7 @@
 
       ```dart
       %uri="lib/part.dart"
-      // @dart = 2.6
+      // @dart = 2.14
       part of 'test.dart';
       ```
 
@@ -6108,7 +6181,7 @@
       must have the same language version as the defining compilation unit:
 
       ```dart
-      // @dart = 2.5
+      // @dart = 2.15
       part [!'part.dart'!];
       ```
 
@@ -6126,6 +6199,18 @@
       compilation unit to be appropriate for the code in the part, or migrate
       the code in the [part file][] to be consistent with the new language
       version.
+  INCONSISTENT_PATTERN_VARIABLE_LOGICAL_OR:
+    problemMessage: "The variable '{0}' has a different type and/or finality in this branch of the logical-or pattern."
+    correctionMessage: Try declaring the variable pattern with the same type and finality in both branches.
+    comment: |-
+      Parameters:
+      0: the name of the pattern variable
+  INCONSISTENT_PATTERN_VARIABLE_SHARED_CASE_SCOPE:
+    problemMessage: "The variable '{0}' doesn't have the same type and/or finality in all cases that share this body."
+    correctionMessage: Try declaring the variable pattern with the same type and finality in all cases.
+    comment: |-
+      Parameters:
+      0: the name of the pattern variable
   INITIALIZER_FOR_NON_EXISTENT_FIELD:
     problemMessage: "'{0}' isn't a field in the enclosing class."
     correctionMessage: "Try correcting the name to match an existing field, or defining a field named '{0}'."
@@ -6651,6 +6736,18 @@
       ```dart
       var x = BigInt.parse('9223372036854775810');
       ```
+  INTERFACE_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY:
+    sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
+    problemMessage: "The class '{0}' can't be extended outside of its library because it's an interface class."
+    comment: |-
+      Parameters:
+      0: the name of the interface class being extended.
+  INTERFACE_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY:
+    sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
+    problemMessage: "The mixin '{0}' can't be mixed-in outside of its library because it's an interface mixin."
+    comment: |-
+      Parameters:
+      0: the name of the interface mixin being mixed in.
   INVALID_ANNOTATION:
     problemMessage: Annotation must be either a const variable reference or const constructor invocation.
     hasPublishedDocs: true
@@ -6878,7 +6975,7 @@
 
       This error is only reported in libraries which are not null safe.
   INVALID_CAST_FUNCTION_EXPR:
-    problemMessage: "The function expression type '{0}' isn't of type '{1}'. This means its parameter or return type doesn't match what is expected. Consider changing parameter type(s) or the returned type(s)."
+    problemMessage: The function expression type '{0}' isn't of type '{1}'. This means its parameter or return type doesn't match what is expected. Consider changing parameter type(s) or the returned type(s).
     comment: |-
       Parameters:
       0: the type of the torn-off function expression
@@ -7175,6 +7272,20 @@
         int add(num a) => a.floor();
       }
       ```
+  INVALID_IMPLEMENTATION_OVERRIDE_SETTER:
+    sharedName: INVALID_IMPLEMENTATION_OVERRIDE
+    problemMessage: "The setter '{1}.{0}' ('{2}') isn't a valid concrete implementation of '{3}.{0}' ('{4}')."
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the name of the declared setter that is not a valid override.
+      1: the name of the interface that declares the setter.
+      2: the type of the declared setter in the interface.
+      3: the name of the interface with the overridden setter.
+      4: the type of the overridden setter.
+
+      These parameters must be kept in sync with those of
+      [CompileTimeErrorCode.INVALID_OVERRIDE].
   INVALID_INLINE_FUNCTION_TYPE:
     problemMessage: "Inline function types can't be used for parameters in a generic function type."
     correctionMessage: "Try using a generic function type (returnType 'Function(' parameters ')')."
@@ -7358,6 +7469,17 @@
         void m2(String s) {}
       }
       ```
+  INVALID_OVERRIDE_SETTER:
+    sharedName: INVALID_OVERRIDE
+    problemMessage: "The setter '{1}.{0}' ('{2}') isn't a valid override of '{3}.{0}' ('{4}')."
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the name of the declared setter that is not a valid override.
+      1: the name of the interface that declares the setter.
+      2: the type of the declared setter in the interface.
+      3: the name of the interface with the overridden setter.
+      4: the type of the overridden setter.
   INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR:
     problemMessage: Generative enum constructors can only be used as targets of redirection.
     correctionMessage: Try using an enum constant, or a factory constructor.
@@ -8613,6 +8735,13 @@
 
       class X = A with M;
       ```
+  MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_SETTER:
+    sharedName: MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_MEMBER
+    problemMessage: "The class doesn't have a concrete implementation of the super-invoked setter '{0}'."
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the display name of the setter without a concrete implementation
   MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_MEMBER:
     problemMessage: "The class doesn't have a concrete implementation of the super-invoked member '{0}'."
     hasPublishedDocs: true
@@ -9744,6 +9873,10 @@
       var a = 'a';
       var m = {a: 0};
       ```
+  NON_CONSTANT_MAP_PATTERN_KEY:
+    problemMessage: Key expressions in map patterns must be constants.
+    correctionMessage: Try using constants instead.
+    comment: No parameters.
   NON_CONSTANT_MAP_VALUE:
     problemMessage: The values in a const map literal must be constant.
     correctionMessage: "Try removing the keyword 'const' from the map literal."
@@ -9780,6 +9913,10 @@
       var a = 'a';
       var m = {0: a};
       ```
+  NON_CONSTANT_RELATIONAL_PATTERN_EXPRESSION:
+    problemMessage: The relational pattern expression must be a constant.
+    correctionMessage: Try using a constant instead.
+    comment: No parameters.
   NON_CONSTANT_SET_ELEMENT:
     problemMessage: The values in a const set literal must be constants.
     correctionMessage: "Try removing the keyword 'const' from the set literal."
@@ -9824,6 +9961,13 @@
       13.2 Expression Statements: It is a compile-time error if a non-constant
       map literal that has no explicit type arguments appears in a place where a
       statement is expected.
+  NON_EXHAUSTIVE_SWITCH:
+    problemMessage: "The type '{0}' is not exhaustively matched by the switch cases."
+    correctionMessage: "Try adding a default case or cases that match {1}."
+    comment: |-
+      Parameters:
+      0: the type of the switch scrutinee
+      1: the unmatched space
   NON_FINAL_FIELD_IN_ENUM:
     problemMessage: Enums can only declare final fields.
     correctionMessage: Try making the field final.
@@ -10320,12 +10464,6 @@
       #### Common fixes
 
       Replace the name with the name of a type.
-  NOT_CONSISTENT_VARIABLE_PATTERN:
-    problemMessage: "Variable pattern '{0}' has a different type or finality in this branch of the logical-or pattern."
-    correctionMessage: "Try declaring the variable pattern with the same type and finality in both branches."
-    comment: |-
-      Parameters:
-      0: the name of the variable pattern
   NOT_BINARY_OPERATOR:
     problemMessage: "'{0}' isn't a binary operator."
     hasPublishedDocs: true
@@ -11116,7 +11254,7 @@
     hasPublishedDocs: true
     comment: |-
       Parameters:
-      0: the uri pointing to a non-library declaration
+      0: the URI pointing to a non-library declaration
     documentation: |-
       #### Description
 
@@ -11208,6 +11346,9 @@
       Parameters:
       0: the matched type
       1: the required type
+  PATTERN_VARIABLE_ASSIGNMENT_INSIDE_GUARD:
+    problemMessage: Pattern variables can't be assigned inside the guard of the enclosing guarded pattern.
+    correctionMessage: Try assigning to a different variable.
   POSITIONAL_SUPER_FORMAL_PARAMETER_WITH_POSITIONAL_ARGUMENT:
     problemMessage: Positional super parameters can't be used when the super constructor invocation has a positional argument.
     correctionMessage: Try making all the positional parameters passed to the super constructor be either all super parameters or all normal parameters.
@@ -11431,16 +11572,16 @@
 
       ```dart
       %uri="lib/a.dart"
-      class A {
+      mixin A {
         void _foo() {}
       }
 
-      class B {
+      mixin B {
         void _foo() {}
       }
       ```
 
-      The following code produces this diagnostic because the classes `A` and `B`
+      The following code produces this diagnostic because the mixins `A` and `B`
       both define the method `_foo`:
 
       ```dart
@@ -12313,6 +12454,9 @@
   REST_ELEMENT_WITH_SUBPATTERN_IN_MAP_PATTERN:
     problemMessage: A rest element in a map pattern can't have a subpattern.
     correctionMessage: Try removing the subpattern.
+  REST_ELEMENT_NOT_LAST_IN_MAP_PATTERN:
+    problemMessage: A rest element in a map pattern must be the last element.
+    correctionMessage: Try moving the rest element to be the last element.
   RETHROW_OUTSIDE_CATCH:
     problemMessage: A rethrow must be inside of a catch clause.
     correctionMessage: "Try moving the expression into a catch clause, or using a 'throw' expression."
@@ -12589,15 +12733,17 @@
       }
       ```
   SEALED_CLASS_SUBTYPE_OUTSIDE_OF_LIBRARY:
-    problemMessage: "The sealed class '{0}' can't be extended, implemented, or mixed in outside of its library."
+    sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
+    problemMessage: "The class '{0}' can't be extended, implemented, or mixed in outside of its library because it's a sealed class."
     comment: |-
       Parameters:
-      0: the name of the supertype being extended, implemented, or mixed in
+      0: the name of the sealed class being extended, implemented, or mixed in
   SEALED_MIXIN_SUBTYPE_OUTSIDE_OF_LIBRARY:
-    problemMessage: "The sealed mixin '{0}' can't be mixed in outside of its library."
+    sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
+    problemMessage: "The mixin '{0}' can't be mixed in outside of its library because it's a sealed mixin."
     comment: |-
       Parameters:
-      0: the name of the supertype being mixed in
+      0: the name of the sealed mixin being mixed in
   SET_ELEMENT_TYPE_NOT_ASSIGNABLE:
     problemMessage: "The element type '{0}' can't be assigned to the set type '{1}'."
     hasPublishedDocs: true
@@ -15173,7 +15319,7 @@
     hasPublishedDocs: true
     comment: |-
       Parameters:
-      0: the URI pointing to a non-existent file
+      0: the URI pointing to a nonexistent file
     documentation: |-
       #### Description
 
@@ -15200,7 +15346,7 @@
     hasPublishedDocs: true
     comment: |-
       Parameters:
-      0: the URI pointing to a non-existent file
+      0: the URI pointing to a nonexistent file
     documentation: |-
       #### Description
 
@@ -17643,66 +17789,6 @@
       1: the name of the class being extended, implemented, or mixed in
     hasPublishedDocs: true
 HintCode:
-  ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER:
-    problemMessage: "The argument type '{0}' can't be assigned to the parameter type '{1} Function(Object)' or '{1} Function(Object, StackTrace)'."
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the name of the actual argument type
-      1: the name of the expected function return type
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when an invocation of
-      `Future.catchError` has an argument that is a function whose parameters
-      aren't compatible with the arguments that will be passed to the function
-      when it's invoked. The static type of the first argument to `catchError`
-      is just `Function`, even though the function that is passed in is expected
-      to have either a single parameter of type `Object` or two parameters of
-      type `Object` and `StackTrace`.
-
-      #### Examples
-
-      The following code produces this diagnostic because the closure being
-      passed to `catchError` doesn't take any parameters, but the function is
-      required to take at least one parameter:
-
-      ```dart
-      void f(Future<int> f) {
-        f.catchError([!() => 0!]);
-      }
-      ```
-
-      The following code produces this diagnostic because the closure being
-      passed to `catchError` takes three parameters, but it can't have more than
-      two required parameters:
-
-      ```dart
-      void f(Future<int> f) {
-        f.catchError([!(one, two, three) => 0!]);
-      }
-      ```
-
-      The following code produces this diagnostic because even though the closure
-      being passed to `catchError` takes one parameter, the closure doesn't have
-      a type that is compatible with `Object`:
-
-      ```dart
-      void f(Future<int> f) {
-        f.catchError([!(String error) => 0!]);
-      }
-      ```
-
-      #### Common fixes
-
-      Change the function being passed to `catchError` so that it has either one
-      or two required parameters, and the parameters have the required types:
-
-      ```dart
-      void f(Future<int> f) {
-        f.catchError((Object error) => 0);
-      }
-      ```
   ASSIGNMENT_OF_DO_NOT_STORE:
     problemMessage: "'{0}' is marked 'doNotStore' and shouldn't be assigned to a field or top-level variable."
     correctionMessage: Try removing the assignment.
@@ -17738,101 +17824,14 @@
 
       Replace references to the field or variable with invocations of the
       function producing the value.
-  BODY_MIGHT_COMPLETE_NORMALLY_CATCH_ERROR:
-    problemMessage: "This 'onError' handler must return a value assignable to '{0}', but ends without returning a value."
-    correctionMessage: Try adding a return statement.
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the return type as derived by the type of the [Future].
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when the closure passed to the
-      `onError` parameter of the `Future.catchError` method is required to
-      return a non-`null` value (because of the `Future`s type argument) but can
-      implicitly return `null`.
-
-      #### Example
-
-      The following code produces this diagnostic because the closure passed to
-      the `catchError` method is required to return an `int` but doesn't end
-      with an explicit `return`, causing it to implicitly return `null`:
-
-      ```dart
-      void g(Future<int> f) {
-        f.catchError((e, st) [!{!]});
-      }
-      ```
-
-      #### Common fixes
-
-      If the closure should sometimes return a non-`null` value, then add an
-      explicit return to the closure:
-
-      ```dart
-      void g(Future<int> f) {
-        f.catchError((e, st) {
-          return -1;
-        });
-      }
-      ```
-
-      If the closure should always return `null`, then change the type argument
-      of the `Future` to be either `void` or `Null`:
-
-      ```dart
-      void g(Future<void> f) {
-        f.catchError((e, st) {});
-      }
-      ```
-  BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE:
-    problemMessage: "This function has a nullable return type of '{0}', but ends without returning a value."
-    correctionMessage: "Try adding a return statement, or if no value is ever returned, try changing the return type to 'void'."
-    hasPublishedDocs: false
-    comment: |-
-      Parameters:
-      0: the name of the declared return type
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a method or function can
-      implicitly return `null` by falling off the end. While this is valid Dart
-      code, it's better for the return of `null` to be explicit.
-
-      #### Example
-
-      The following code produces this diagnostic because the function `f`
-      implicitly returns `null`:
-
-      ```dart
-      String? [!f!]() {}
-      ```
-
-      #### Common fixes
-
-      If the return of `null` is intentional, then make it explicit:
-
-      ```dart
-      String? f() {
-        return null;
-      }
-      ```
-
-      If the function should return a non-null value along that path, then add
-      the missing return statement:
-
-      ```dart
-      String? f() {
-        return '';
-      }
-      ```
   CAN_BE_NULL_AFTER_NULL_AWARE:
     problemMessage: "The receiver uses '?.', so its value can be null."
     correctionMessage: "Replace the '.' with a '?.' in the invocation."
     comment: |-
       When the target expression uses '?.' operator, it can be `null`, so all the
       subsequent invocations should also use '?.' operator.
+
+      Note: This diagnostic is only generated in pre-null safe code.
   DEAD_CODE:
     problemMessage: Dead code.
     correctionMessage: Try removing the code, or fixing the code before it so that it can be reached.
@@ -18162,103 +18161,6 @@
       Parameters:
       0: the name of the member
       1: message details
-  DEPRECATED_NEW_IN_COMMENT_REFERENCE:
-    problemMessage: "Using the 'new' keyword in a comment reference is deprecated."
-    correctionMessage: Try referring to a constructor by its name.
-    comment: No parameters.
-    hasPublishedDocs: true
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a comment reference (the name
-      of a declaration enclosed in square brackets in a documentation comment)
-      uses the keyword `new` to refer to a constructor. This form is deprecated.
-
-      #### Examples
-
-      The following code produces this diagnostic because the unnamed
-      constructor is being referenced using `new C`:
-
-      ```dart
-      /// See [[!new!] C].
-      class C {
-        C();
-      }
-      ```
-
-      The following code produces this diagnostic because the constructor named
-      `c` is being referenced using `new C.c`:
-
-      ```dart
-      /// See [[!new!] C.c].
-      class C {
-        C.c();
-      }
-      ```
-
-      #### Common fixes
-
-      If you're referencing a named constructor, then remove the keyword `new`:
-
-      ```dart
-      /// See [C.c].
-      class C {
-        C.c();
-      }
-      ```
-
-      If you're referencing the unnamed constructor, then remove the keyword
-      `new` and append `.new` after the class name:
-
-      ```dart
-      /// See [C.new].
-      class C {
-        C.c();
-      }
-      ```
-  DEPRECATED_MIXIN_FUNCTION:
-    sharedName: DEPRECATED_SUBTYPE_OF_FUNCTION
-    problemMessage: "Mixing in 'Function' is deprecated."
-    correctionMessage: "Try removing 'Function' from the 'with' clause."
-    hasPublishedDocs: true
-    comment: No parameters.
-  DEPRECATED_IMPLEMENTS_FUNCTION:
-    sharedName: DEPRECATED_SUBTYPE_OF_FUNCTION
-    problemMessage: "Implementing 'Function' has no effect."
-    correctionMessage: "Try removing 'Function' from the 'implements' clause."
-    hasPublishedDocs: true
-    comment: No parameters.
-  DEPRECATED_EXTENDS_FUNCTION:
-    sharedName: DEPRECATED_SUBTYPE_OF_FUNCTION
-    problemMessage: "Extending 'Function' is deprecated."
-    correctionMessage: "Try removing 'Function' from the 'extends' clause."
-    hasPublishedDocs: true
-    comment: No parameters.
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when the class `Function` is used in
-      either the `extends`, `implements`, or `with` clause of a class or mixin.
-      Using the class `Function` in this way has no semantic value, so it's
-      effectively dead code.
-
-      #### Example
-
-      The following code produces this diagnostic because `Function` is used as
-      the superclass of `F`:
-
-      ```dart
-      class F extends [!Function!] {}
-      ```
-
-      #### Common fixes
-
-      Remove the class `Function` from whichever clause it's in, and remove the
-      whole clause if `Function` is the only type in the clause:
-
-      ```dart
-      class F {}
-      ```
   DIVISION_OPTIMIZATION:
     problemMessage: The operator x ~/ y is more efficient than (x / y).toInt().
     correctionMessage: "Try re-writing the expression to use the '~/' operator."
@@ -18287,296 +18189,6 @@
       ```dart
       int divide(num x, num y) => x ~/ y;
       ```
-  DUPLICATE_HIDDEN_NAME:
-    problemMessage: Duplicate hidden name.
-    correctionMessage: Try removing the repeated name from the list of hidden members.
-    hasPublishedDocs: true
-    comment: No parameters.
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a name occurs multiple times in
-      a `hide` clause. Repeating the name is unnecessary.
-
-      #### Example
-
-      The following code produces this diagnostic because the name `min` is
-      hidden more than once:
-
-      ```dart
-      import 'dart:math' hide min, [!min!];
-
-      var x = pi;
-      ```
-
-      #### Common fixes
-
-      If the name was mistyped in one or more places, then correct the mistyped
-      names:
-
-      ```dart
-      import 'dart:math' hide max, min;
-
-      var x = pi;
-      ```
-
-      If the name wasn't mistyped, then remove the unnecessary name from the
-      list:
-
-      ```dart
-      import 'dart:math' hide min;
-
-      var x = pi;
-      ```
-  DUPLICATE_EXPORT:
-    problemMessage: Duplicate export.
-    correctionMessage: Try removing all but one export of the library.
-    hasPublishedDocs: true
-    comment: |-
-      Duplicate exports.
-
-      No parameters.
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when an export directive is found
-      that is the same as an export before it in the file. The second export
-      doesn't add value and should be removed.
-
-      #### Example
-
-      The following code produces this diagnostic because the same library is
-      being exported twice:
-
-      ```dart
-      export 'package:meta/meta.dart';
-      export [!'package:meta/meta.dart'!];
-      ```
-
-      #### Common fixes
-
-      Remove the unnecessary export:
-
-      ```dart
-      export 'package:meta/meta.dart';
-      ```
-  DUPLICATE_IGNORE:
-    problemMessage: "The diagnostic '{0}' doesn't need to be ignored here because it's already being ignored."
-    correctionMessage: Try removing the name from the list, or removing the whole comment if this is the only name in the list.
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the name of the diagnostic being ignored
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a diagnostic name appears in an
-      `ignore` comment, but the diagnostic is already being ignored, either
-      because it's already included in the same `ignore` comment or because it
-      appears in an `ignore-in-file` comment.
-
-      #### Examples
-
-      The following code produces this diagnostic because the diagnostic named
-      `unused_local_variable` is already being ignored for the whole file so it
-      doesn't need to be ignored on a specific line:
-
-      ```dart
-      // ignore_for_file: unused_local_variable
-      void f() {
-        // ignore: [!unused_local_variable!]
-        var x = 0;
-      }
-      ```
-
-      The following code produces this diagnostic because the diagnostic named
-      `unused_local_variable` is being ignored twice on the same line:
-
-      ```dart
-      void f() {
-        // ignore: unused_local_variable, [!unused_local_variable!]
-        var x = 0;
-      }
-      ```
-
-      #### Common fixes
-
-      Remove the ignore comment, or remove the unnecessary diagnostic name if the
-      ignore comment is ignoring more than one diagnostic:
-
-      ```dart
-      // ignore_for_file: unused_local_variable
-      void f() {
-        var x = 0;
-      }
-      ```
-  DUPLICATE_IMPORT:
-    problemMessage: Duplicate import.
-    correctionMessage: Try removing all but one import of the library.
-    hasPublishedDocs: true
-    comment: |-
-      Duplicate imports.
-
-      No parameters.
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when an import directive is found
-      that is the same as an import before it in the file. The second import
-      doesn't add value and should be removed.
-
-      #### Example
-
-      The following code produces this diagnostic:
-
-      ```dart
-      import 'package:meta/meta.dart';
-      import [!'package:meta/meta.dart'!];
-
-      @sealed class C {}
-      ```
-
-      #### Common fixes
-
-      Remove the unnecessary import:
-
-      ```dart
-      import 'package:meta/meta.dart';
-
-      @sealed class C {}
-      ```
-  DUPLICATE_SHOWN_NAME:
-    problemMessage: Duplicate shown name.
-    correctionMessage: Try removing the repeated name from the list of shown members.
-    hasPublishedDocs: true
-    comment: No parameters.
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a name occurs multiple times in
-      a `show` clause. Repeating the name is unnecessary.
-
-      #### Example
-
-      The following code produces this diagnostic because the name `min` is shown
-      more than once:
-
-      ```dart
-      import 'dart:math' show min, [!min!];
-
-      var x = min(2, min(0, 1));
-      ```
-
-      #### Common fixes
-
-      If the name was mistyped in one or more places, then correct the mistyped
-      names:
-
-      ```dart
-      import 'dart:math' show max, min;
-
-      var x = max(2, min(0, 1));
-      ```
-
-      If the name wasn't mistyped, then remove the unnecessary name from the
-      list:
-
-      ```dart
-      import 'dart:math' show min;
-
-      var x = min(2, min(0, 1));
-      ```
-  EQUAL_ELEMENTS_IN_SET:
-    problemMessage: "Two elements in a set literal shouldn't be equal."
-    correctionMessage: Change or remove the duplicate element.
-    hasPublishedDocs: true
-    comment: No parameters.
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when an element in a non-constant set
-      is the same as a previous element in the same set. If two elements are the
-      same, then the second value is ignored, which makes having both elements
-      pointless and likely signals a bug.
-
-      #### Example
-
-      The following code produces this diagnostic because the element `1` appears
-      twice:
-
-      ```dart
-      const a = 1;
-      const b = 1;
-      var s = <int>{a, [!b!]};
-      ```
-
-      #### Common fixes
-
-      If both elements should be included in the set, then change one of the
-      elements:
-
-      ```dart
-      const a = 1;
-      const b = 2;
-      var s = <int>{a, b};
-      ```
-
-      If only one of the elements is needed, then remove the one that isn't
-      needed:
-
-      ```dart
-      const a = 1;
-      var s = <int>{a};
-      ```
-
-      Note that literal sets preserve the order of their elements, so the choice
-      of which element to remove might affect the order in which elements are
-      returned by an iterator.
-  EQUAL_KEYS_IN_MAP:
-    problemMessage: "Two keys in a map literal shouldn't be equal."
-    correctionMessage: Change or remove the duplicate key.
-    hasPublishedDocs: true
-    comment: No parameters.
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a key in a non-constant map is
-      the same as a previous key in the same map. If two keys are the same, then
-      the second value overwrites the first value, which makes having both pairs
-      pointless and likely signals a bug.
-
-      #### Example
-
-      The following code produces this diagnostic because the keys `a` and `b`
-      have the same value:
-
-      ```dart
-      const a = 1;
-      const b = 1;
-      var m = <int, String>{a: 'a', [!b!]: 'b'};
-      ```
-
-      #### Common fixes
-
-      If both entries should be included in the map, then change one of the keys:
-
-      ```dart
-      const a = 1;
-      const b = 2;
-      var m = <int, String>{a: 'a', b: 'b'};
-      ```
-
-      If only one of the entries is needed, then remove the one that isn't
-      needed:
-
-      ```dart
-      const a = 1;
-      var m = <int, String>{a: 'a'};
-      ```
-
-      Note that literal maps preserve the order of their entries, so the choice
-      of which entry to remove might affect the order in which the keys and
-      values are returned by an iterator.
   FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE:
     problemMessage: "A file in the 'lib' directory shouldn't import a file outside the 'lib' directory."
     correctionMessage: "Try removing the import, or moving the imported file inside the 'lib' directory."
@@ -18590,7 +18202,7 @@
     problemMessage: "A file outside the 'lib' directory shouldn't reference a file inside the 'lib' directory using a relative path."
     correctionMessage: "Try using a 'package:' URI instead."
     comment: |-
-      It is a bad practice for a source file ouside a package "lib" directory
+      It is a bad practice for a source file outside a package "lib" directory
       hierarchy to traverse into that directory hierarchy. For example, a source
       file in the "web" directory should not contain a directive such as
       `import '../lib/some.dart'` which references a file inside the lib
@@ -18711,283 +18323,6 @@
       If you can't migrate the imported library, then the importing library
       needs to have a language version that is before 2.12, when null safety was
       enabled by default.
-  INFERENCE_FAILURE_ON_COLLECTION_LITERAL:
-    problemMessage: "The type argument(s) of '{0}' can't be inferred."
-    correctionMessage: "Use explicit type argument(s) for '{0}'."
-    comment: |-
-      When "strict-inference" is enabled, collection literal types must be
-      inferred via the context type, or have type arguments.
-
-      Parameters:
-      0: the name of the collection
-  INFERENCE_FAILURE_ON_FUNCTION_INVOCATION:
-    problemMessage: "The type argument(s) of the function '{0}' can't be inferred."
-    correctionMessage: "Use explicit type argument(s) for '{0}'."
-    comment: |-
-      When "strict-inference" is enabled, types in function invocations must be
-      inferred via the context type, or have type arguments.
-
-      Parameters:
-      0: the name of the function
-  INFERENCE_FAILURE_ON_FUNCTION_RETURN_TYPE:
-    problemMessage: "The return type of '{0}' cannot be inferred."
-    correctionMessage: "Declare the return type of '{0}'."
-    comment: |-
-      When "strict-inference" is enabled, recursive local functions, top-level
-      functions, methods, and function-typed function parameters must all
-      specify a return type. See the strict-inference resource:
-
-      https://github.com/dart-lang/language/blob/master/resources/type-system/strict-inference.md
-
-      Parameters:
-      0: the name of the function or method
-  INFERENCE_FAILURE_ON_GENERIC_INVOCATION:
-    problemMessage: "The type argument(s) of the generic function type '{0}' can't be inferred."
-    correctionMessage: "Use explicit type argument(s) for '{0}'."
-    comment: |-
-      When "strict-inference" is enabled, types in function invocations must be
-      inferred via the context type, or have type arguments.
-
-      Parameters:
-      0: the name of the type
-  INFERENCE_FAILURE_ON_INSTANCE_CREATION:
-    problemMessage: "The type argument(s) of the constructor '{0}' can't be inferred."
-    correctionMessage: "Use explicit type argument(s) for '{0}'."
-    comment: |-
-      When "strict-inference" is enabled, types in instance creation
-      (constructor calls) must be inferred via the context type, or have type
-      arguments.
-
-      Parameters:
-      0: the name of the constructor
-  INFERENCE_FAILURE_ON_UNINITIALIZED_VARIABLE:
-    problemMessage: "The type of {0} can't be inferred without either a type or initializer."
-    correctionMessage: Try specifying the type of the variable.
-    comment: |-
-      When "strict-inference" in enabled, uninitialized variables must be
-      declared with a specific type.
-
-      Parameters:
-      0: the name of the variable
-  INFERENCE_FAILURE_ON_UNTYPED_PARAMETER:
-    problemMessage: "The type of {0} can't be inferred; a type must be explicitly provided."
-    correctionMessage: Try specifying the type of the parameter.
-    comment: |-
-      When "strict-inference" in enabled, function parameters must be
-      declared with a specific type, or inherit a type.
-
-      Parameters:
-      0: the name of the parameter
-  INVALID_ANNOTATION_TARGET:
-    problemMessage: "The annotation '{0}' can only be used on {1}."
-    comment: |-
-      Parameters:
-      0: the name of the annotation
-      1: the list of valid targets
-    hasPublishedDocs: true
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when an annotation is applied to a
-      kind of declaration that it doesn't support.
-
-      #### Example
-
-      The following code produces this diagnostic because the `optionalTypeArgs`
-      annotation isn't defined to be valid for top-level variables:
-
-      ```dart
-      import 'package:meta/meta.dart';
-
-      @[!optionalTypeArgs!]
-      int x = 0;
-      ```
-
-      #### Common fixes
-
-      Remove the annotation from the declaration.
-  INVALID_EXPORT_OF_INTERNAL_ELEMENT:
-    problemMessage: "The member '{0}' can't be exported as a part of a package's public API."
-    correctionMessage: "Try using a hide clause to hide '{0}'."
-    comment: |-
-      Parameters:
-      0: the name of the element
-    hasPublishedDocs: true
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a [public library][] exports a
-      declaration that is marked with the `[internal][meta-internal]`
-      annotation.
-
-      #### Example
-
-      Given a file named `a.dart` in the `src` directory that contains:
-
-      ```dart
-      %uri="lib/src/a.dart"
-      import 'package:meta/meta.dart';
-
-      @internal class One {}
-      ```
-
-      The following code, when found in a [public library][] produces this
-      diagnostic because the `export` directive is exporting a name that is only
-      intended to be used internally:
-
-      ```dart
-      [!export 'src/a.dart';!]
-      ```
-
-      #### Common fixes
-
-      If the export is needed, then add a `hide` clause to hide the internal
-      names:
-
-      ```dart
-      export 'src/a.dart' hide One;
-      ```
-
-      If the export isn't needed, then remove it.
-  INVALID_EXPORT_OF_INTERNAL_ELEMENT_INDIRECTLY:
-    problemMessage: "The member '{0}' can't be exported as a part of a package's public API, but is indirectly exported as part of the signature of '{1}'."
-    correctionMessage: "Try using a hide clause to hide '{0}'."
-    comment: |-
-      Parameters:
-      0: the name of the element
-      1: ?
-    hasPublishedDocs: true
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a [public library][] exports a
-      top-level function  with a return type or at least one parameter type that
-      is marked with the `[internal][meta-internal]` annotation.
-
-      #### Example
-
-      Given a file named `a.dart` in the `src` directory that contains the
-      following:
-
-      ```dart
-      %uri="lib/src/a.dart"
-      import 'package:meta/meta.dart';
-
-      @internal
-      typedef IntFunction = int Function();
-
-      int f(IntFunction g) => g();
-      ```
-
-      The following code produces this diagnostic because the function `f` has a
-      parameter of type `IntFunction`, and `IntFunction` is only intended to be
-      used internally:
-
-      ```dart
-      [!export 'src/a.dart' show f;!]
-      ```
-
-      #### Common fixes
-
-      If the function must be public, then make all the types in the function's
-      signature public types.
-
-      If the function doesn't need to be exported, then stop exporting it,
-      either by removing it from the `show` clause, adding it to the `hide`
-      clause, or by removing the export.
-  INVALID_FACTORY_ANNOTATION:
-    problemMessage: Only methods can be annotated as factories.
-    comment: |-
-      This hint is generated anywhere a @factory annotation is associated with
-      anything other than a method.
-  INVALID_FACTORY_METHOD_DECL:
-    problemMessage: "Factory method '{0}' must have a return type."
-    comment: |-
-      Parameters:
-      0: The name of the method
-    hasPublishedDocs: true
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a method that is annotated with
-      the `[factory][meta-factory]` annotation has a return type of `void`.
-
-      #### Example
-
-      The following code produces this diagnostic because the method `createC`
-      is annotated with the `[factory][meta-factory]` annotation but doesn't
-      return any value:
-
-      ```dart
-      import 'package:meta/meta.dart';
-
-      class Factory {
-        @factory
-        void [!createC!]() {}
-      }
-
-      class C {}
-      ```
-
-      #### Common fixes
-
-      Change the return type to something other than `void`:
-
-      ```dart
-      import 'package:meta/meta.dart';
-
-      class Factory {
-        @factory
-        C createC() => C();
-      }
-
-      class C {}
-      ```
-  INVALID_FACTORY_METHOD_IMPL:
-    problemMessage: "Factory method '{0}' doesn't return a newly allocated object."
-    comment: |-
-      Parameters:
-      0: the name of the method
-    hasPublishedDocs: true
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a method that is annotated with
-      the `[factory][meta-factory]` annotation doesn't return a newly allocated
-      object.
-
-      #### Example
-
-      The following code produces this diagnostic because the method `createC`
-      returns the value of a field rather than a newly created instance of `C`:
-
-      ```dart
-      import 'package:meta/meta.dart';
-
-      class Factory {
-        C c = C();
-
-        @factory
-        C [!createC!]() => c;
-      }
-
-      class C {}
-      ```
-
-      #### Common fixes
-
-      Change the method to return a newly created instance of the return type:
-
-      ```dart
-      import 'package:meta/meta.dart';
-
-      class Factory {
-        @factory
-        C createC() => C();
-      }
-
-      class C {}
-      ```
   INVALID_IMMUTABLE_ANNOTATION:
     problemMessage: Only classes can be annotated as being immutable.
     comment: |-
@@ -19050,95 +18385,6 @@
       ```dart
       class C {}
       ```
-  INVALID_LANGUAGE_VERSION_OVERRIDE_GREATER:
-    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
-    problemMessage: "The language version override can't specify a version greater than the latest known language version: {0}.{1}."
-    correctionMessage: Try removing the language version override.
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the latest major version
-      1: the latest minor version
-  INVALID_LANGUAGE_VERSION_OVERRIDE_AT_SIGN:
-    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
-    problemMessage: "The Dart language version override number must begin with '@dart'."
-    correctionMessage: "Specify a Dart language version override with a comment like '// @dart = 2.0'."
-    comment: |-
-      No parameters.
-    hasPublishedDocs: true
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a comment that appears to be an
-      attempt to specify a language version override doesn't conform to the
-      requirements for such a comment. For more information, see
-      [Per-library language version selection](https://dart.dev/guides/language/evolution#per-library-language-version-selection).
-
-      #### Example
-
-      The following code produces this diagnostic because the word `dart` must
-      be lowercase in such a comment and because there's no equal sign between
-      the word `dart` and the version number:
-
-      ```dart
-      [!// @Dart 2.9!]
-      ```
-
-      #### Common fixes
-
-      If the comment is intended to be a language version override, then change
-      the comment to follow the correct format:
-
-      ```dart
-      // @dart = 2.9
-      ```
-  INVALID_LANGUAGE_VERSION_OVERRIDE_LOCATION:
-    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
-    problemMessage: The language version override must be specified before any declaration or directive.
-    correctionMessage: Try moving the language version override to the top of the file.
-    hasPublishedDocs: true
-  INVALID_LANGUAGE_VERSION_OVERRIDE_LOWER_CASE:
-    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
-    problemMessage: "The Dart language version override comment must be specified with the word 'dart' in all lower case."
-    correctionMessage: "Specify a Dart language version override with a comment like '// @dart = 2.0'."
-    comment: |-
-      No parameters.
-    hasPublishedDocs: true
-  INVALID_LANGUAGE_VERSION_OVERRIDE_NUMBER:
-    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
-    problemMessage: "The Dart language version override comment must be specified with a version number, like '2.0', after the '=' character."
-    correctionMessage: "Specify a Dart language version override with a comment like '// @dart = 2.0'."
-    comment: |-
-      No parameters.
-    hasPublishedDocs: true
-  INVALID_LANGUAGE_VERSION_OVERRIDE_PREFIX:
-    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
-    problemMessage: "The Dart language version override number can't be prefixed with a letter."
-    correctionMessage: "Specify a Dart language version override with a comment like '// @dart = 2.0'."
-    comment: |-
-      No parameters.
-    hasPublishedDocs: true
-  INVALID_LANGUAGE_VERSION_OVERRIDE_TRAILING_CHARACTERS:
-    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
-    problemMessage: "The Dart language version override comment can't be followed by any non-whitespace characters."
-    correctionMessage: "Specify a Dart language version override with a comment like '// @dart = 2.0'."
-    comment: |-
-      No parameters.
-    hasPublishedDocs: true
-  INVALID_LANGUAGE_VERSION_OVERRIDE_TWO_SLASHES:
-    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
-    problemMessage: The Dart language version override comment must be specified with exactly two slashes.
-    correctionMessage: "Specify a Dart language version override with a comment like '// @dart = 2.0'."
-    comment: |-
-      No parameters.
-    hasPublishedDocs: true
-  INVALID_LANGUAGE_VERSION_OVERRIDE_EQUALS:
-    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
-    problemMessage: "The Dart language version override comment must be specified with an '=' character."
-    correctionMessage: "Specify a Dart language version override with a comment like '// @dart = 2.0'."
-    comment: |-
-      No parameters.
-    hasPublishedDocs: true
   INVALID_LITERAL_ANNOTATION:
     problemMessage: Only const constructors can have the `@literal` annotation.
     hasPublishedDocs: true
@@ -19343,300 +18589,6 @@
         void m() {}
       }
       ```
-  INVALID_REQUIRED_NAMED_PARAM:
-    problemMessage: "The type parameter '{0}' is annotated with @required but only named parameters without a default value can be annotated with it."
-    correctionMessage: Remove @required.
-    comment: |-
-      This hint is generated anywhere where `@required` annotates a named
-      parameter with a default value.
-
-      Parameters:
-      0: the name of the member
-  INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM:
-    problemMessage: "Incorrect use of the annotation @required on the optional positional parameter '{0}'. Optional positional parameters cannot be required."
-    correctionMessage: Remove @required.
-    comment: |-
-      This hint is generated anywhere where `@required` annotates an optional
-      positional parameter.
-
-      Parameters:
-      0: the name of the member
-  INVALID_REQUIRED_POSITIONAL_PARAM:
-    problemMessage: "Redundant use of the annotation @required on the required positional parameter '{0}'."
-    correctionMessage: Remove @required.
-    comment: |-
-      This hint is generated anywhere where `@required` annotates a non optional
-      positional parameter.
-
-      Parameters:
-      0: the name of the member
-  RETURN_TYPE_INVALID_FOR_CATCH_ERROR:
-    sharedName: INVALID_RETURN_TYPE_FOR_CATCH_ERROR
-    problemMessage: "The return type '{0}' isn't assignable to '{1}', as required by 'Future.catchError'."
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the return type of the function
-      1: the expected return type as defined by the type of the Future
-  RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR:
-    sharedName: INVALID_RETURN_TYPE_FOR_CATCH_ERROR
-    problemMessage: "A value of type '{0}' can't be returned by the 'onError' handler because it must be assignable to '{1}'."
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the return type as declared in the return statement
-      1: the expected return type as defined by the type of the Future
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when an invocation of
-      `Future.catchError` has an argument whose return type isn't compatible with
-      the type returned by the instance of `Future`. At runtime, the method
-      `catchError` attempts to return the value from the callback as the result
-      of the future, which results in another exception being thrown.
-
-      #### Examples
-
-      The following code produces this diagnostic because `future` is declared to
-      return an `int` while `callback` is declared to return a `String`, and
-      `String` isn't a subtype of `int`:
-
-      ```dart
-      void f(Future<int> future, String Function(dynamic, StackTrace) callback) {
-        future.catchError([!callback!]);
-      }
-      ```
-
-      The following code produces this diagnostic because the closure being
-      passed to `catchError` returns an `int` while `future` is declared to
-      return a `String`:
-
-      ```dart
-      void f(Future<String> future) {
-        future.catchError((error, stackTrace) => [!3!]);
-      }
-      ```
-
-      #### Common fixes
-
-      If the instance of `Future` is declared correctly, then change the callback
-      to match:
-
-      ```dart
-      void f(Future<int> future, int Function(dynamic, StackTrace) callback) {
-        future.catchError(callback);
-      }
-      ```
-
-      If the declaration of the instance of `Future` is wrong, then change it to
-      match the callback:
-
-      ```dart
-      void f(Future<String> future, String Function(dynamic, StackTrace) callback) {
-        future.catchError(callback);
-      }
-      ```
-  INVALID_SEALED_ANNOTATION:
-    problemMessage: "The annotation '@sealed' can only be applied to classes."
-    correctionMessage: Try removing the '@sealed' annotation.
-    hasPublishedDocs: true
-    comment: |-
-      This hint is generated anywhere where `@sealed` annotates something other
-      than a class.
-
-      No parameters.
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a declaration other than a
-      class declaration has the `@sealed` annotation on it.
-
-      #### Example
-
-      The following code produces this diagnostic because the `@sealed`
-      annotation is on a method declaration:
-
-      ```dart
-      import 'package:meta/meta.dart';
-
-      class A {
-        [!@sealed!]
-        void m() {}
-      }
-      ```
-
-      #### Common fixes
-
-      Remove the annotation:
-
-      ```dart
-      class A {
-        void m() {}
-      }
-      ```
-  INVALID_USE_OF_INTERNAL_MEMBER:
-    problemMessage: "The member '{0}' can only be used within its package."
-    comment: |-
-      Parameters:
-      0: the name of the member
-    hasPublishedDocs: true
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a reference to a declaration
-      that is annotated with the `[internal][meta-internal]` annotation is found
-      outside the package containing the declaration.
-
-      #### Example
-
-      Given a package `p` that defines a library containing a declaration marked
-      with the `[internal][meta-internal]` annotation:
-
-      ```dart
-      %uri="package:p/src/p.dart"
-      import 'package:meta/meta.dart';
-
-      @internal
-      class C {}
-      ```
-
-      The following code produces this diagnostic because it's referencing the
-      class `C`, which isn't intended to be used outside the package `p`:
-
-      ```dart
-      import 'package:p/src/p.dart';
-
-      void f([!C!] c) {}
-      ```
-
-      #### Common fixes
-
-      Remove the reference to the internal declaration.
-  INVALID_USE_OF_PROTECTED_MEMBER:
-    problemMessage: "The member '{0}' can only be used within instance members of subclasses of '{1}'."
-    comment: |-
-      This hint is generated anywhere where a member annotated with `@protected`
-      is used outside of an instance member of a subclass.
-
-      Parameters:
-      0: the name of the member
-      1: the name of the defining class
-  INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER:
-    problemMessage: "The member '{0}' can only be used for overriding."
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the name of the member
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when an instance member that is
-      annotated with `[visibleForOverriding][meta-visibleForOverriding]` is
-      referenced outside the library in which it's declared for any reason other
-      than to override it.
-
-      #### Example
-
-      Given a file named `a.dart` containing the following declaration:
-
-      ```dart
-      %uri="lib/a.dart"
-      import 'package:meta/meta.dart';
-
-      class A {
-        @visibleForOverriding
-        void a() {}
-      }
-      ```
-
-      The following code produces this diagnostic because the method `m` is being
-      invoked even though the only reason it's public is to allow it to be
-      overridden:
-
-      ```dart
-      import 'a.dart';
-
-      class B extends A {
-        void b() {
-          [!a!]();
-        }
-      }
-      ```
-
-      #### Common fixes
-
-      Remove the invalid use of the member.
-  INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER:
-    problemMessage: "The member '{0}' can only be used within '{1}' or a template library."
-    comment: |-
-      This hint is generated anywhere where a member annotated with
-      `@visibleForTemplate` is used outside of a "template" Dart file.
-
-      Parameters:
-      0: the name of the member
-      1: the name of the defining class
-  INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER:
-    problemMessage: "The member '{0}' can only be used within '{1}' or a test."
-    hasPublishedDocs: true
-    comment: |-
-      This hint is generated anywhere where a member annotated with
-      `@visibleForTesting` is used outside the defining library, or a test.
-
-      Parameters:
-      0: the name of the member
-      1: the name of the defining class
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a member annotated with
-      `@visibleForTesting` is referenced anywhere other than the library in
-      which it is declared or in a library in the `test` directory.
-
-      #### Example
-
-      Given a file named `c.dart` that contains the following:
-
-      ```dart
-      %uri="lib/c.dart"
-      import 'package:meta/meta.dart';
-
-      class C {
-        @visibleForTesting
-        void m() {}
-      }
-      ```
-
-      The following code, when not inside the `test` directory, produces this
-      diagnostic because the method `m` is marked as being visible only for
-      tests:
-
-      ```dart
-      import 'c.dart';
-
-      void f(C c) {
-        c.[!m!]();
-      }
-      ```
-
-      #### Common fixes
-
-      If the annotated member should not be referenced outside of tests, then
-      remove the reference:
-
-      ```dart
-      import 'c.dart';
-
-      void f(C c) {}
-      ```
-
-      If it's OK to reference the annotated member outside of tests, then remove
-      the annotation:
-
-      ```dart
-      class C {
-        void m() {}
-      }
-      ```
   INVALID_VISIBILITY_ANNOTATION:
     problemMessage: "The member '{0}' is annotated with '{1}', but this annotation is only meaningful on declarations of public members."
     hasPublishedDocs: true
@@ -19720,174 +18672,6 @@
       ```dart
       class C {}
       ```
-  MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_ONE:
-    sharedName: MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN
-    problemMessage: "Missing concrete override implementation of '{0}'."
-    correctionMessage: Try overriding the missing member.
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the name of the member
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when an instance member that has the
-      `@mustBeOverridden` annotation isn't overridden in a subclass.
-
-      #### Example
-
-      The following code produces this diagnostic because the class `B` doesn't
-      have an override of the inherited method `A.m` when `A.m` is annotated
-      with `@mustBeOverridden`:
-
-      ```dart
-      import 'package:meta/meta.dart';
-
-      class A {
-        @mustBeOverridden
-        void m() {}
-      }
-
-      class [!B!] extends A {}
-      ```
-
-      #### Common fixes
-
-      If the annotation is appropriate for the member, then override the member
-      in the subclass:
-
-      ```dart
-      import 'package:meta/meta.dart';
-
-      class A {
-        @mustBeOverridden
-        void m() {}
-      }
-
-      class B extends A {
-        @override
-        void m() {}
-      }
-      ```
-
-      If the annotation isn't appropriate for the member, then remove the
-      annotation:
-
-      ```dart
-      class A {
-        void m() {}
-      }
-
-      class B extends A {}
-      ```
-  MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_TWO:
-    sharedName: MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN
-    problemMessage: "Missing concrete override implementation of '{0}' and '{1}'."
-    correctionMessage: Try overriding the missing members.
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the name of the first member
-      1: the name of the second member
-  MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_THREE_PLUS:
-    sharedName: MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN
-    problemMessage: "Missing concrete override implementation of '{0}', '{1}', and {2} more."
-    correctionMessage: Try overriding the missing members.
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the name of the first member
-      1: the name of the second member
-      2: the number of additional missing members that aren't listed
-  MISSING_REQUIRED_PARAM:
-    problemMessage: "The parameter '{0}' is required."
-    hasPublishedDocs: true
-    comment: |-
-      Generate a hint for a constructor, function or method invocation where a
-      required parameter is missing.
-
-      Parameters:
-      0: the name of the parameter
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a method or function with a
-      named parameter that is annotated as being required is invoked without
-      providing a value for the parameter.
-
-      #### Example
-
-      The following code produces this diagnostic because the named parameter `x`
-      is required:
-
-      ```dart
-      %language=2.9
-      import 'package:meta/meta.dart';
-
-      void f({@required int x}) {}
-
-      void g() {
-        [!f!]();
-      }
-      ```
-
-      #### Common fixes
-
-      Provide the required value:
-
-      ```dart
-      %language=2.9
-      import 'package:meta/meta.dart';
-
-      void f({@required int x}) {}
-
-      void g() {
-        f(x: 2);
-      }
-      ```
-  MISSING_REQUIRED_PARAM_WITH_DETAILS:
-    sharedName: MISSING_REQUIRED_PARAM
-    problemMessage: "The parameter '{0}' is required. {1}."
-    hasPublishedDocs: true
-    comment: |-
-      Generate a hint for a constructor, function or method invocation where a
-      required parameter is missing.
-
-      Parameters:
-      0: the name of the parameter
-      1: message details
-  MISSING_RETURN:
-    problemMessage: "This function has a return type of '{0}', but doesn't end with a return statement."
-    correctionMessage: "Try adding a return statement, or changing the return type to 'void'."
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the name of the declared return type
-    documentation: |-
-      #### Description
-
-      Any function or method that doesn't end with either an explicit return or a
-      throw implicitly returns `null`. This is rarely the desired behavior. The
-      analyzer produces this diagnostic when it finds an implicit return.
-
-      #### Example
-
-      The following code produces this diagnostic because `f` doesn't end with a
-      return:
-
-      ```dart
-      %language=2.9
-      int [!f!](int x) {
-        if (x < 0) {
-          return 0;
-        }
-      }
-      ```
-
-      #### Common fixes
-
-      Add a `return` statement that makes the return value explicit, even if
-      `null` is the appropriate value.
   MIXIN_ON_SEALED_CLASS:
     problemMessage: "The class '{0}' shouldn't be used as a mixin constraint because it is sealed, and any class mixing in this mixin must have '{0}' as a superclass."
     correctionMessage: Try composing with this class, or refer to its documentation for more information.
@@ -20102,99 +18886,6 @@
 
       void f() => const C();
       ```
-  NULLABLE_TYPE_IN_CATCH_CLAUSE:
-    problemMessage: "A potentially nullable type can't be used in an 'on' clause because it isn't valid to throw a nullable expression."
-    correctionMessage: Try using a non-nullable type.
-    hasPublishedDocs: true
-    comment: No parameters.
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when the type following `on` in a
-      `catch` clause is a nullable type. It isn't valid to specify a nullable
-      type because it isn't possible to catch `null` (because it's a runtime
-      error to throw `null`).
-
-      #### Example
-
-      The following code produces this diagnostic because the exception type is
-      specified to allow `null` when `null` can't be thrown:
-
-      ```dart
-      void f() {
-        try {
-          // ...
-        } on [!FormatException?!] {
-        }
-      }
-      ```
-
-      #### Common fixes
-
-      Remove the question mark from the type:
-
-      ```dart
-      void f() {
-        try {
-          // ...
-        } on FormatException {
-        }
-      }
-      ```
-  NULL_ARGUMENT_TO_NON_NULL_TYPE:
-    problemMessage: "'{0}' shouldn't be called with a null argument for the non-nullable type argument '{1}'."
-    correctionMessage: Try adding a non-null argument.
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the name of the method being invoked
-      1: the type argument associated with the method
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when `null` is passed to either the
-      constructor `Future.value` or the method `Completer.complete` when the type
-      argument used to create the instance was non-nullable. Even though the type
-      system can't express this restriction, passing in a `null` results in a
-      runtime exception.
-
-      #### Example
-
-      The following code produces this diagnostic because `null` is being passed
-      to the constructor `Future.value` even though the type argument is the
-      non-nullable type `String`:
-
-      ```dart
-      Future<String> f() {
-        return Future.value([!null!]);
-      }
-      ```
-
-      #### Common fixes
-
-      Pass in a non-null value:
-
-      ```dart
-      Future<String> f() {
-        return Future.value('');
-      }
-      ```
-  NULL_AWARE_BEFORE_OPERATOR:
-    problemMessage: "The left operand uses '?.', so its value can be null."
-    comment: |-
-      When the left operand of a binary expression uses '?.' operator, it can be
-      `null`.
-  NULL_AWARE_IN_CONDITION:
-    problemMessage: "The value of the '?.' operator can be 'null', which isn't appropriate in a condition."
-    correctionMessage: "Try replacing the '?.' with a '.', testing the left-hand side for null if necessary."
-    comment: |-
-      A condition in a control flow statement could evaluate to `null` because it
-      uses the null-aware '?.' operator.
-  NULL_AWARE_IN_LOGICAL_OPERATOR:
-    problemMessage: "The value of the '?.' operator can be 'null', which isn't appropriate as an operand of a logical operator."
-    comment: |-
-      A condition in operands of a logical operator could evaluate to `null`
-      because it uses the null-aware '?.' operator.
   CAST_FROM_NULL_ALWAYS_FAILS:
     problemMessage: "This cast always throws an exception because the expression always evaluates to 'null'."
     comment: |-
@@ -20387,103 +19078,6 @@
       A setter with the override annotation does not override an existing setter.
 
       No parameters.
-  PACKAGE_IMPORT_CONTAINS_DOT_DOT:
-    problemMessage: "A package import shouldn't contain '..'."
-    comment: |-
-      It is a bad practice for a package import to reference anything outside the
-      given package, or more generally, it is bad practice for a package import
-      to contain a "..". For example, a source file should not contain a
-      directive such as `import 'package:foo/../some.dart'`.
-  RECEIVER_OF_TYPE_NEVER:
-    problemMessage: "The receiver is of type 'Never', and will never complete with a value."
-    correctionMessage: Try checking for throw expressions or type errors in the receiver
-    comment: |-
-      It is not an error to call or tear-off a method, setter, or getter, or to
-      read or write a field, on a receiver of static type `Never`.
-      Implementations that provide feedback about dead or unreachable code are
-      encouraged to indicate that any arguments to the invocation are
-      unreachable.
-
-      It is not an error to apply an expression of type `Never` in the function
-      position of a function call. Implementations that provide feedback about
-      dead or unreachable code are encouraged to indicate that any arguments to
-      the call are unreachable.
-
-      Parameters: none
-  REMOVED_LINT_USE:
-    problemMessage: "'{0}' was removed in Dart '{1}'"
-    correctionMessage: "Remove the reference to '{0}'."
-    comment: |-
-      An error code indicating use of a removed lint rule.
-
-      Parameters:
-      0: the rule name
-      1: the SDK version in which the lint was removed
-  REPLACED_LINT_USE:
-    problemMessage:  "'{0}' was replaced by '{2}' in Dart '{1}'."
-    correctionMessage: "Replace '{0}' with '{1}'."
-    comment: |-
-      An error code indicating use of a removed lint rule.
-
-      Parameters:
-      0: the rule name
-      1: the SDK version in which the lint was removed
-      2: the name of a replacing lint
-  RETURN_OF_DO_NOT_STORE:
-    problemMessage: "'{0}' is annotated with 'doNotStore' and shouldn't be returned unless '{1}' is also annotated."
-    correctionMessage: "Annotate '{1}' with 'doNotStore'."
-    comment: |-
-      Parameters:
-      0: the name of the annotated function being invoked
-      1: the name of the function containing the return
-    hasPublishedDocs: true
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a value that is annotated with
-      the `[doNotStore][meta-doNotStore]` annotation is returned from a method,
-      getter, or function that doesn't have the same annotation.
-
-      #### Example
-
-      The following code produces this diagnostic because the result of invoking
-      `f` shouldn't be stored, but the function `g` isn't annotated to preserve
-      that semantic:
-
-      ```dart
-      import 'package:meta/meta.dart';
-
-      @doNotStore
-      int f() => 0;
-
-      int g() => [!f()!];
-      ```
-
-      #### Common fixes
-
-      If the value that shouldn't be stored is the correct value to return, then
-      mark the function with the `[doNotStore][meta-doNotStore]` annotation:
-
-      ```dart
-      import 'package:meta/meta.dart';
-
-      @doNotStore
-      int f() => 0;
-
-      @doNotStore
-      int g() => f();
-      ```
-
-      Otherwise, return a different value from the function:
-
-      ```dart
-      import 'package:meta/meta.dart';
-
-      @doNotStore
-      int f() => 0;
-
-      int g() => 0;
-      ```
   STRICT_RAW_TYPE:
     problemMessage: "The generic type '{0}' should have explicit type arguments but doesn't."
     correctionMessage: "Use explicit type arguments for '{0}'."
@@ -20549,179 +19143,6 @@
       If the class needs to be a subtype of the sealed class, then either change
       the sealed class so that it's no longer sealed or move the subclass into
       the same package as the sealed class.
-  TEXT_DIRECTION_CODE_POINT_IN_COMMENT:
-    problemMessage: The Unicode code point 'U+{0}' changes the appearance of text from how it's interpreted by the compiler.
-    correctionMessage: Try removing the code point or using the Unicode escape sequence '\u{0}'.
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the unicode sequence of the code point.
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when it encounters source that
-      contains text direction Unicode code points. These code points cause
-      source code in either a string literal or a comment to be interpreted
-      and compiled differently than how it appears in editors, leading to
-      possible security vulnerabilities.
-
-      #### Example
-
-      The following code produces this diagnostic twice because there are
-      hidden characters at the start and end of the label string:
-
-      ```dart
-      var label = '[!I!]nteractive text[!'!];
-      ```
-
-      #### Common fixes
-
-      If the code points are intended to be included in the string literal,
-      then escape them:
-
-      ```dart
-      var label = '\u202AInteractive text\u202C';
-      ```
-
-      If the code points aren't intended to be included in the string literal,
-      then remove them:
-
-      ```dart
-      var label = 'Interactive text';
-      ```
-  TEXT_DIRECTION_CODE_POINT_IN_LITERAL:
-    problemMessage: The Unicode code point 'U+{0}' changes the appearance of text from how it's interpreted by the compiler.
-    correctionMessage: Try removing the code point or using the Unicode escape sequence '\u{0}'.
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the unicode sequence of the code point.
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when it encounters source that
-      contains text direction Unicode code points. These code points cause
-      source code in either a string literal or a comment to be interpreted
-      and compiled differently than how it appears in editors, leading to
-      possible security vulnerabilities.
-
-      #### Example
-
-      The following code produces this diagnostic twice because there are
-      hidden characters at the start and end of the label string:
-
-      ```dart
-      var label = '[!I!]nteractive text[!'!];
-      ```
-
-      #### Common fixes
-
-      If the code points are intended to be included in the string literal,
-      then escape them:
-
-      ```dart
-      var label = '\u202AInteractive text\u202C';
-      ```
-
-      If the code points aren't intended to be included in the string literal,
-      then remove them:
-
-      ```dart
-      var label = 'Interactive text';
-      ```
-  TYPE_CHECK_IS_NOT_NULL:
-    sharedName: TYPE_CHECK_WITH_NULL
-    problemMessage: "Tests for non-null should be done with '!= null'."
-    correctionMessage: "Try replacing the 'is! Null' check with '!= null'."
-    hasPublishedDocs: true
-    comment: No parameters.
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when there's a type check (using the
-      `as` operator) where the type is `Null`. There's only one value whose type
-      is `Null`, so the code is both more readable and more performant when it
-      tests for `null` explicitly.
-
-      #### Examples
-
-      The following code produces this diagnostic because the code is testing to
-      see whether the value of `s` is `null` by using a type check:
-
-      ```dart
-      void f(String? s) {
-        if ([!s is Null!]) {
-          return;
-        }
-        print(s);
-      }
-      ```
-
-      The following code produces this diagnostic because the code is testing to
-      see whether the value of `s` is something other than `null` by using a type
-      check:
-
-      ```dart
-      void f(String? s) {
-        if ([!s is! Null!]) {
-          print(s);
-        }
-      }
-      ```
-
-      #### Common fixes
-
-      Replace the type check with the equivalent comparison with `null`:
-
-      ```dart
-      void f(String? s) {
-        if (s == null) {
-          return;
-        }
-        print(s);
-      }
-      ```
-  TYPE_CHECK_IS_NULL:
-    sharedName: TYPE_CHECK_WITH_NULL
-    problemMessage: "Tests for null should be done with '== null'."
-    correctionMessage: "Try replacing the 'is Null' check with '== null'."
-    hasPublishedDocs: true
-    comment: No parameters.
-  UNDEFINED_HIDDEN_NAME:
-    problemMessage: "The library '{0}' doesn't export a member with the hidden name '{1}'."
-    correctionMessage: Try removing the name from the list of hidden members.
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the name of the library being imported
-      1: the name in the hide clause that isn't defined in the library
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a hide combinator includes a
-      name that isn't defined by the library being imported.
-
-      #### Example
-
-      The following code produces this diagnostic because `dart:math` doesn't
-      define the name `String`:
-
-      ```dart
-      import 'dart:math' hide [!String!], max;
-
-      var x = min(0, 1);
-      ```
-
-      #### Common fixes
-
-      If a different name should be hidden, then correct the name. Otherwise,
-      remove the name from the list:
-
-      ```dart
-      import 'dart:math' hide max;
-
-      var x = min(0, 1);
-      ```
   UNDEFINED_REFERENCED_PARAMETER:
     problemMessage: "The parameter '{0}' isn't defined by '{1}'."
     hasPublishedDocs: true
@@ -20759,41 +19180,6 @@
       @UseResult.unless(parameterDefined: 'a')
       int f([int? a]) => a ?? 0;
       ```
-  UNDEFINED_SHOWN_NAME:
-    problemMessage: "The library '{0}' doesn't export a member with the shown name '{1}'."
-    correctionMessage: Try removing the name from the list of shown members.
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the name of the library being imported
-      1: the name in the show clause that isn't defined in the library
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a show combinator includes a
-      name that isn't defined by the library being imported.
-
-      #### Example
-
-      The following code produces this diagnostic because `dart:math` doesn't
-      define the name `String`:
-
-      ```dart
-      import 'dart:math' show min, [!String!];
-
-      var x = min(0, 1);
-      ```
-
-      #### Common fixes
-
-      If a different name should be shown, then correct the name. Otherwise,
-      remove the name from the list:
-
-      ```dart
-      import 'dart:math' show min;
-
-      var x = min(0, 1);
-      ```
   UNIGNORABLE_IGNORE:
     problemMessage: "The diagnostic '{0}' can't be ignored."
     correctionMessage: Try removing the name from the list, or removing the whole comment if this is the only name in the list.
@@ -20899,8 +19285,8 @@
     hasPublishedDocs: true
     comment: |-
       Parameters:
-      0: the uri that is not necessary
-      1: the uri that makes it unnecessary
+      0: the URI that is not necessary
+      1: the URI that makes it unnecessary
     documentation: |-
       #### Description
 
@@ -20944,6 +19330,49 @@
       If some of the names imported by this import are intended to be used but
       aren't yet, and if those names aren't imported by other imports, then add
       the missing references to those names.
+  UNNECESSARY_NAN_COMPARISON_FALSE:
+    sharedName: UNNECESSARY_NAN_COMPARISON
+    problemMessage: A double can't equal 'double.nan', so the condition is always 'false'.
+    correctionMessage: Try using 'double.isNan', or removing the condition.
+    hasPublishedDocs: false
+    comment: No parameters.
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a value is compared to
+      `double.nan` using either `==` or `!=`.
+
+      Dart follows the [IEEE 754] floating-point standard for the semantics of
+      floating point operations, which states that, for any floating point value
+      `x` (including NaN, positive infinity, and negative infinity),
+      - `NaN == x` is always false
+      - `NaN != x` is always true
+
+      As a result, comparing any value to NaN is pointless because the result is
+      already known (based on the comparison operator being used).
+
+      #### Example
+
+      The following code produces this diagnostic because `d` is being compared
+      to `double.nan`:
+
+      ```dart
+      bool isNaN(double d) => d [!== double.nan!];
+      ```
+
+      #### Common fixes
+
+      Use the getter `double.isNaN` instead:
+
+      ```dart
+      bool isNaN(double d) => d.isNaN;
+      ```
+  UNNECESSARY_NAN_COMPARISON_TRUE:
+    sharedName: UNNECESSARY_NAN_COMPARISON
+    problemMessage: A double can't equal 'double.nan', so the condition is always 'true'.
+    correctionMessage: Try using 'double.isNan', or removing the condition.
+    hasPublishedDocs: false
+    comment: No parameters.
   UNNECESSARY_NO_SUCH_METHOD:
     problemMessage: "Unnecessary 'noSuchMethod' declaration."
     correctionMessage: "Try removing the declaration of 'noSuchMethod'."
@@ -20995,7 +19424,7 @@
       ```
   UNNECESSARY_NULL_COMPARISON_FALSE:
     sharedName: UNNECESSARY_NULL_COMPARISON
-    problemMessage: "The operand can't be null, so the condition is always false."
+    problemMessage: "The operand can't be null, so the condition is always 'false'."
     correctionMessage: Try removing the condition, an enclosing condition, or the whole conditional statement.
     hasPublishedDocs: true
     comment: No parameters.
@@ -21053,7 +19482,7 @@
       ```
   UNNECESSARY_NULL_COMPARISON_TRUE:
     sharedName: UNNECESSARY_NULL_COMPARISON
-    problemMessage: "The operand can't be null, so the condition is always true."
+    problemMessage: "The operand can't be null, so the condition is always 'true'."
     correctionMessage: Remove the condition.
     hasPublishedDocs: true
     comment: No parameters.
@@ -21086,6 +19515,11 @@
       ```dart
       dynamic x;
       ```
+  UNNECESSARY_SET_LITERAL:
+    problemMessage: Braces unnecessarily wrap this expression in a set literal.
+    correctionMessage: Try removing the set literal around the expression.
+    hasPublishedDocs: false
+    comment: No parameters.
   UNNECESSARY_TYPE_CHECK_FALSE:
     sharedName: UNNECESSARY_TYPE_CHECK
     problemMessage: "Unnecessary type check; the result is always 'false'."
@@ -21128,89 +19562,9 @@
     correctionMessage: Try correcting the type check, or removing the type check.
     hasPublishedDocs: true
     comment: No parameters.
-  UNUSED_CATCH_CLAUSE:
-    problemMessage: "The exception variable '{0}' isn't used, so the 'catch' clause can be removed."
-    correctionMessage: Try removing the catch clause.
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the name of the exception variable
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when a `catch` clause is found, and
-      neither the exception parameter nor the optional stack trace parameter are
-      used in the `catch` block.
-
-      #### Example
-
-      The following code produces this diagnostic because `e` isn't referenced:
-
-      ```dart
-      void f() {
-        try {
-          int.parse(';');
-        } on FormatException catch ([!e!]) {
-          // ignored
-        }
-      }
-      ```
-
-      #### Common fixes
-
-      Remove the unused `catch` clause:
-
-      ```dart
-      void f() {
-        try {
-          int.parse(';');
-        } on FormatException {
-          // ignored
-        }
-      }
-      ```
-  UNUSED_CATCH_STACK:
-    problemMessage: "The stack trace variable '{0}' isn't used and can be removed."
-    correctionMessage: Try removing the stack trace variable, or using it.
-    hasPublishedDocs: true
-    comment: |-
-      Parameters:
-      0: the name of the stack trace variable
-    documentation: |-
-      #### Description
-
-      The analyzer produces this diagnostic when the stack trace parameter in a
-      `catch` clause isn't referenced within the body of the `catch` block.
-
-      #### Example
-
-      The following code produces this diagnostic because `stackTrace` isn't
-      referenced:
-
-      ```dart
-      void f() {
-        try {
-          // ...
-        } catch (exception, [!stackTrace!]) {
-          // ...
-        }
-      }
-      ```
-
-      #### Common fixes
-
-      If you need to reference the stack trace parameter, then add a reference to
-      it. Otherwise, remove it:
-
-      ```dart
-      void f() {
-        try {
-          // ...
-        } catch (exception) {
-          // ...
-        }
-      }
-      ```
+  UNREACHABLE_SWITCH_CASE:
+    problemMessage: "This case is covered by the previous cases."
+    comment: No parameters.
   UNUSED_ELEMENT:
     problemMessage: "The declaration '{0}' isn't referenced."
     correctionMessage: "Try removing the declaration of '{0}'."
@@ -21324,7 +19678,7 @@
     hasPublishedDocs: true
     comment: |-
       Parameters:
-      0: the content of the unused import's uri
+      0: the content of the unused import's URI
     documentation: |-
       #### Description
 
@@ -22667,6 +21021,7 @@
       isn't handled:
 
       ```dart
+      %language=2.19
       enum E { e1, e2 }
 
       void f(E e) {
@@ -22712,6 +21067,1601 @@
       ```
       TODO(brianwilkerson) This documentation will need to be updated when NNBD
        ships.
+  UNNECESSARY_NON_NULL_ASSERTION:
+    problemMessage: "The '!' will have no effect because the receiver can't be null."
+    correctionMessage: "Try removing the '!' operator."
+    hasPublishedDocs: true
+    comment: No parameters.
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when the operand of the `!` operator
+      can't be `null`.
+
+      #### Example
+
+      The following code produces this diagnostic because `x` can't be `null`:
+
+      ```dart
+      int f(int x) {
+        return x[!!!];
+      }
+      ```
+
+      #### Common fixes
+
+      Remove the null check operator (`!`):
+
+      ```dart
+      int f(int x) {
+        return x;
+      }
+      ```
+  UNNECESSARY_NULL_ASSERT_PATTERN:
+    problemMessage: The null-assert pattern will have no effect because the matched type isn't nullable.
+    correctionMessage: Try replacing the null-assert pattern with its nested pattern.
+    comment: No parameters.
+  UNNECESSARY_NULL_CHECK_PATTERN:
+    problemMessage: The null-check pattern will have no effect because the matched type isn't nullable.
+    correctionMessage: Try replacing the null-check pattern with its nested pattern.
+    comment: No parameters.
+WarningCode:
+  ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER:
+    problemMessage: "The argument type '{0}' can't be assigned to the parameter type '{1} Function(Object)' or '{1} Function(Object, StackTrace)'."
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the name of the actual argument type
+      1: the name of the expected function return type
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when an invocation of
+      `Future.catchError` has an argument that is a function whose parameters
+      aren't compatible with the arguments that will be passed to the function
+      when it's invoked. The static type of the first argument to `catchError`
+      is just `Function`, even though the function that is passed in is expected
+      to have either a single parameter of type `Object` or two parameters of
+      type `Object` and `StackTrace`.
+
+      #### Examples
+
+      The following code produces this diagnostic because the closure being
+      passed to `catchError` doesn't take any parameters, but the function is
+      required to take at least one parameter:
+
+      ```dart
+      void f(Future<int> f) {
+        f.catchError([!() => 0!]);
+      }
+      ```
+
+      The following code produces this diagnostic because the closure being
+      passed to `catchError` takes three parameters, but it can't have more than
+      two required parameters:
+
+      ```dart
+      void f(Future<int> f) {
+        f.catchError([!(one, two, three) => 0!]);
+      }
+      ```
+
+      The following code produces this diagnostic because even though the closure
+      being passed to `catchError` takes one parameter, the closure doesn't have
+      a type that is compatible with `Object`:
+
+      ```dart
+      void f(Future<int> f) {
+        f.catchError([!(String error) => 0!]);
+      }
+      ```
+
+      #### Common fixes
+
+      Change the function being passed to `catchError` so that it has either one
+      or two required parameters, and the parameters have the required types:
+
+      ```dart
+      void f(Future<int> f) {
+        f.catchError((Object error) => 0);
+      }
+      ```
+  BODY_MIGHT_COMPLETE_NORMALLY_CATCH_ERROR:
+    problemMessage: "This 'onError' handler must return a value assignable to '{0}', but ends without returning a value."
+    correctionMessage: Try adding a return statement.
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the return type as derived by the type of the [Future].
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when the closure passed to the
+      `onError` parameter of the `Future.catchError` method is required to
+      return a non-`null` value (because of the `Future`s type argument) but can
+      implicitly return `null`.
+
+      #### Example
+
+      The following code produces this diagnostic because the closure passed to
+      the `catchError` method is required to return an `int` but doesn't end
+      with an explicit `return`, causing it to implicitly return `null`:
+
+      ```dart
+      void g(Future<int> f) {
+        f.catchError((e, st) [!{!]});
+      }
+      ```
+
+      #### Common fixes
+
+      If the closure should sometimes return a non-`null` value, then add an
+      explicit return to the closure:
+
+      ```dart
+      void g(Future<int> f) {
+        f.catchError((e, st) {
+          return -1;
+        });
+      }
+      ```
+
+      If the closure should always return `null`, then change the type argument
+      of the `Future` to be either `void` or `Null`:
+
+      ```dart
+      void g(Future<void> f) {
+        f.catchError((e, st) {});
+      }
+      ```
+  BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE:
+    problemMessage: "This function has a nullable return type of '{0}', but ends without returning a value."
+    correctionMessage: "Try adding a return statement, or if no value is ever returned, try changing the return type to 'void'."
+    hasPublishedDocs: false
+    comment: |-
+      Parameters:
+      0: the name of the declared return type
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a method or function can
+      implicitly return `null` by falling off the end. While this is valid Dart
+      code, it's better for the return of `null` to be explicit.
+
+      #### Example
+
+      The following code produces this diagnostic because the function `f`
+      implicitly returns `null`:
+
+      ```dart
+      String? [!f!]() {}
+      ```
+
+      #### Common fixes
+
+      If the return of `null` is intentional, then make it explicit:
+
+      ```dart
+      String? f() {
+        return null;
+      }
+      ```
+
+      If the function should return a non-null value along that path, then add
+      the missing return statement:
+
+      ```dart
+      String? f() {
+        return '';
+      }
+      ```
+  DEAD_CODE:
+    aliasFor: HintCode.DEAD_CODE
+    comment: This is the new replacement for [HintCode.DEAD_CODE].
+  DEPRECATED_EXTENDS_FUNCTION:
+    sharedName: DEPRECATED_SUBTYPE_OF_FUNCTION
+    problemMessage: "Extending 'Function' is deprecated."
+    correctionMessage: "Try removing 'Function' from the 'extends' clause."
+    hasPublishedDocs: true
+    comment: No parameters.
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when the class `Function` is used in
+      either the `extends`, `implements`, or `with` clause of a class or mixin.
+      Using the class `Function` in this way has no semantic value, so it's
+      effectively dead code.
+
+      #### Example
+
+      The following code produces this diagnostic because `Function` is used as
+      the superclass of `F`:
+
+      ```dart
+      class F extends [!Function!] {}
+      ```
+
+      #### Common fixes
+
+      Remove the class `Function` from whichever clause it's in, and remove the
+      whole clause if `Function` is the only type in the clause:
+
+      ```dart
+      class F {}
+      ```
+  DEPRECATED_IMPLEMENTS_FUNCTION:
+    sharedName: DEPRECATED_SUBTYPE_OF_FUNCTION
+    problemMessage: "Implementing 'Function' has no effect."
+    correctionMessage: "Try removing 'Function' from the 'implements' clause."
+    hasPublishedDocs: true
+    comment: No parameters.
+  DEPRECATED_MIXIN_FUNCTION:
+    sharedName: DEPRECATED_SUBTYPE_OF_FUNCTION
+    problemMessage: "Mixing in 'Function' is deprecated."
+    correctionMessage: "Try removing 'Function' from the 'with' clause."
+    hasPublishedDocs: true
+    comment: No parameters.
+  DEPRECATED_NEW_IN_COMMENT_REFERENCE:
+    problemMessage: "Using the 'new' keyword in a comment reference is deprecated."
+    correctionMessage: Try referring to a constructor by its name.
+    comment: No parameters.
+    hasPublishedDocs: true
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a comment reference (the name
+      of a declaration enclosed in square brackets in a documentation comment)
+      uses the keyword `new` to refer to a constructor. This form is deprecated.
+
+      #### Examples
+
+      The following code produces this diagnostic because the unnamed
+      constructor is being referenced using `new C`:
+
+      ```dart
+      /// See [[!new!] C].
+      class C {
+        C();
+      }
+      ```
+
+      The following code produces this diagnostic because the constructor named
+      `c` is being referenced using `new C.c`:
+
+      ```dart
+      /// See [[!new!] C.c].
+      class C {
+        C.c();
+      }
+      ```
+
+      #### Common fixes
+
+      If you're referencing a named constructor, then remove the keyword `new`:
+
+      ```dart
+      /// See [C.c].
+      class C {
+        C.c();
+      }
+      ```
+
+      If you're referencing the unnamed constructor, then remove the keyword
+      `new` and append `.new` after the class name:
+
+      ```dart
+      /// See [C.new].
+      class C {
+        C.c();
+      }
+      ```
+  DUPLICATE_EXPORT:
+    problemMessage: Duplicate export.
+    correctionMessage: Try removing all but one export of the library.
+    hasPublishedDocs: true
+    comment: |-
+      Duplicate exports.
+
+      No parameters.
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when an export directive is found
+      that is the same as an export before it in the file. The second export
+      doesn't add value and should be removed.
+
+      #### Example
+
+      The following code produces this diagnostic because the same library is
+      being exported twice:
+
+      ```dart
+      export 'package:meta/meta.dart';
+      export [!'package:meta/meta.dart'!];
+      ```
+
+      #### Common fixes
+
+      Remove the unnecessary export:
+
+      ```dart
+      export 'package:meta/meta.dart';
+      ```
+  DUPLICATE_HIDDEN_NAME:
+    problemMessage: Duplicate hidden name.
+    correctionMessage: Try removing the repeated name from the list of hidden members.
+    hasPublishedDocs: true
+    comment: No parameters.
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a name occurs multiple times in
+      a `hide` clause. Repeating the name is unnecessary.
+
+      #### Example
+
+      The following code produces this diagnostic because the name `min` is
+      hidden more than once:
+
+      ```dart
+      import 'dart:math' hide min, [!min!];
+
+      var x = pi;
+      ```
+
+      #### Common fixes
+
+      If the name was mistyped in one or more places, then correct the mistyped
+      names:
+
+      ```dart
+      import 'dart:math' hide max, min;
+
+      var x = pi;
+      ```
+
+      If the name wasn't mistyped, then remove the unnecessary name from the
+      list:
+
+      ```dart
+      import 'dart:math' hide min;
+
+      var x = pi;
+      ```
+  DUPLICATE_IGNORE:
+    problemMessage: "The diagnostic '{0}' doesn't need to be ignored here because it's already being ignored."
+    correctionMessage: Try removing the name from the list, or removing the whole comment if this is the only name in the list.
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the name of the diagnostic being ignored
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a diagnostic name appears in an
+      `ignore` comment, but the diagnostic is already being ignored, either
+      because it's already included in the same `ignore` comment or because it
+      appears in an `ignore-in-file` comment.
+
+      #### Examples
+
+      The following code produces this diagnostic because the diagnostic named
+      `unused_local_variable` is already being ignored for the whole file so it
+      doesn't need to be ignored on a specific line:
+
+      ```dart
+      // ignore_for_file: unused_local_variable
+      void f() {
+        // ignore: [!unused_local_variable!]
+        var x = 0;
+      }
+      ```
+
+      The following code produces this diagnostic because the diagnostic named
+      `unused_local_variable` is being ignored twice on the same line:
+
+      ```dart
+      void f() {
+        // ignore: unused_local_variable, [!unused_local_variable!]
+        var x = 0;
+      }
+      ```
+
+      #### Common fixes
+
+      Remove the ignore comment, or remove the unnecessary diagnostic name if the
+      ignore comment is ignoring more than one diagnostic:
+
+      ```dart
+      // ignore_for_file: unused_local_variable
+      void f() {
+        var x = 0;
+      }
+      ```
+  DUPLICATE_IMPORT:
+    problemMessage: Duplicate import.
+    correctionMessage: Try removing all but one import of the library.
+    hasPublishedDocs: true
+    comment: |-
+      Duplicate imports.
+
+      No parameters.
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when an import directive is found
+      that is the same as an import before it in the file. The second import
+      doesn't add value and should be removed.
+
+      #### Example
+
+      The following code produces this diagnostic:
+
+      ```dart
+      import 'package:meta/meta.dart';
+      import [!'package:meta/meta.dart'!];
+
+      @sealed class C {}
+      ```
+
+      #### Common fixes
+
+      Remove the unnecessary import:
+
+      ```dart
+      import 'package:meta/meta.dart';
+
+      @sealed class C {}
+      ```
+  DUPLICATE_SHOWN_NAME:
+    problemMessage: Duplicate shown name.
+    correctionMessage: Try removing the repeated name from the list of shown members.
+    hasPublishedDocs: true
+    comment: No parameters.
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a name occurs multiple times in
+      a `show` clause. Repeating the name is unnecessary.
+
+      #### Example
+
+      The following code produces this diagnostic because the name `min` is shown
+      more than once:
+
+      ```dart
+      import 'dart:math' show min, [!min!];
+
+      var x = min(2, min(0, 1));
+      ```
+
+      #### Common fixes
+
+      If the name was mistyped in one or more places, then correct the mistyped
+      names:
+
+      ```dart
+      import 'dart:math' show max, min;
+
+      var x = max(2, min(0, 1));
+      ```
+
+      If the name wasn't mistyped, then remove the unnecessary name from the
+      list:
+
+      ```dart
+      import 'dart:math' show min;
+
+      var x = min(2, min(0, 1));
+      ```
+  EQUAL_ELEMENTS_IN_SET:
+    problemMessage: "Two elements in a set literal shouldn't be equal."
+    correctionMessage: Change or remove the duplicate element.
+    hasPublishedDocs: true
+    comment: No parameters.
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when an element in a non-constant set
+      is the same as a previous element in the same set. If two elements are the
+      same, then the second value is ignored, which makes having both elements
+      pointless and likely signals a bug.
+
+      #### Example
+
+      The following code produces this diagnostic because the element `1` appears
+      twice:
+
+      ```dart
+      const a = 1;
+      const b = 1;
+      var s = <int>{a, [!b!]};
+      ```
+
+      #### Common fixes
+
+      If both elements should be included in the set, then change one of the
+      elements:
+
+      ```dart
+      const a = 1;
+      const b = 2;
+      var s = <int>{a, b};
+      ```
+
+      If only one of the elements is needed, then remove the one that isn't
+      needed:
+
+      ```dart
+      const a = 1;
+      var s = <int>{a};
+      ```
+
+      Note that literal sets preserve the order of their elements, so the choice
+      of which element to remove might affect the order in which elements are
+      returned by an iterator.
+  EQUAL_KEYS_IN_MAP:
+    problemMessage: "Two keys in a map literal shouldn't be equal."
+    correctionMessage: Change or remove the duplicate key.
+    hasPublishedDocs: true
+    comment: No parameters.
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a key in a non-constant map is
+      the same as a previous key in the same map. If two keys are the same, then
+      the second value overwrites the first value, which makes having both pairs
+      pointless and likely signals a bug.
+
+      #### Example
+
+      The following code produces this diagnostic because the keys `a` and `b`
+      have the same value:
+
+      ```dart
+      const a = 1;
+      const b = 1;
+      var m = <int, String>{a: 'a', [!b!]: 'b'};
+      ```
+
+      #### Common fixes
+
+      If both entries should be included in the map, then change one of the keys:
+
+      ```dart
+      const a = 1;
+      const b = 2;
+      var m = <int, String>{a: 'a', b: 'b'};
+      ```
+
+      If only one of the entries is needed, then remove the one that isn't
+      needed:
+
+      ```dart
+      const a = 1;
+      var m = <int, String>{a: 'a'};
+      ```
+
+      Note that literal maps preserve the order of their entries, so the choice
+      of which entry to remove might affect the order in which the keys and
+      values are returned by an iterator.
+  INFERENCE_FAILURE_ON_COLLECTION_LITERAL:
+    problemMessage: "The type argument(s) of '{0}' can't be inferred."
+    correctionMessage: "Use explicit type argument(s) for '{0}'."
+    comment: |-
+      When "strict-inference" is enabled, collection literal types must be
+      inferred via the context type, or have type arguments.
+
+      Parameters:
+      0: the name of the collection
+  INFERENCE_FAILURE_ON_FUNCTION_INVOCATION:
+    problemMessage: "The type argument(s) of the function '{0}' can't be inferred."
+    correctionMessage: "Use explicit type argument(s) for '{0}'."
+    comment: |-
+      When "strict-inference" is enabled, types in function invocations must be
+      inferred via the context type, or have type arguments.
+
+      Parameters:
+      0: the name of the function
+  INFERENCE_FAILURE_ON_FUNCTION_RETURN_TYPE:
+    problemMessage: "The return type of '{0}' cannot be inferred."
+    correctionMessage: "Declare the return type of '{0}'."
+    comment: |-
+      When "strict-inference" is enabled, recursive local functions, top-level
+      functions, methods, and function-typed function parameters must all
+      specify a return type. See the strict-inference resource:
+
+      https://github.com/dart-lang/language/blob/master/resources/type-system/strict-inference.md
+
+      Parameters:
+      0: the name of the function or method
+  INFERENCE_FAILURE_ON_GENERIC_INVOCATION:
+    problemMessage: "The type argument(s) of the generic function type '{0}' can't be inferred."
+    correctionMessage: "Use explicit type argument(s) for '{0}'."
+    comment: |-
+      When "strict-inference" is enabled, types in function invocations must be
+      inferred via the context type, or have type arguments.
+
+      Parameters:
+      0: the name of the type
+  INFERENCE_FAILURE_ON_INSTANCE_CREATION:
+    problemMessage: "The type argument(s) of the constructor '{0}' can't be inferred."
+    correctionMessage: "Use explicit type argument(s) for '{0}'."
+    comment: |-
+      When "strict-inference" is enabled, types in instance creation
+      (constructor calls) must be inferred via the context type, or have type
+      arguments.
+
+      Parameters:
+      0: the name of the constructor
+  INFERENCE_FAILURE_ON_UNINITIALIZED_VARIABLE:
+    problemMessage: "The type of {0} can't be inferred without either a type or initializer."
+    correctionMessage: Try specifying the type of the variable.
+    comment: |-
+      When "strict-inference" in enabled, uninitialized variables must be
+      declared with a specific type.
+
+      Parameters:
+      0: the name of the variable
+  INFERENCE_FAILURE_ON_UNTYPED_PARAMETER:
+    problemMessage: "The type of {0} can't be inferred; a type must be explicitly provided."
+    correctionMessage: Try specifying the type of the parameter.
+    comment: |-
+      When "strict-inference" in enabled, function parameters must be
+      declared with a specific type, or inherit a type.
+
+      Parameters:
+      0: the name of the parameter
+  INVALID_ANNOTATION_TARGET:
+    problemMessage: "The annotation '{0}' can only be used on {1}."
+    comment: |-
+      Parameters:
+      0: the name of the annotation
+      1: the list of valid targets
+    hasPublishedDocs: true
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when an annotation is applied to a
+      kind of declaration that it doesn't support.
+
+      #### Example
+
+      The following code produces this diagnostic because the `optionalTypeArgs`
+      annotation isn't defined to be valid for top-level variables:
+
+      ```dart
+      import 'package:meta/meta.dart';
+
+      @[!optionalTypeArgs!]
+      int x = 0;
+      ```
+
+      #### Common fixes
+
+      Remove the annotation from the declaration.
+  INVALID_EXPORT_OF_INTERNAL_ELEMENT:
+    problemMessage: "The member '{0}' can't be exported as a part of a package's public API."
+    correctionMessage: "Try using a hide clause to hide '{0}'."
+    comment: |-
+      Parameters:
+      0: the name of the element
+    hasPublishedDocs: true
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a [public library][] exports a
+      declaration that is marked with the `[internal][meta-internal]`
+      annotation.
+
+      #### Example
+
+      Given a file named `a.dart` in the `src` directory that contains:
+
+      ```dart
+      %uri="lib/src/a.dart"
+      import 'package:meta/meta.dart';
+
+      @internal class One {}
+      ```
+
+      The following code, when found in a [public library][] produces this
+      diagnostic because the `export` directive is exporting a name that is only
+      intended to be used internally:
+
+      ```dart
+      [!export 'src/a.dart';!]
+      ```
+
+      #### Common fixes
+
+      If the export is needed, then add a `hide` clause to hide the internal
+      names:
+
+      ```dart
+      export 'src/a.dart' hide One;
+      ```
+
+      If the export isn't needed, then remove it.
+  INVALID_EXPORT_OF_INTERNAL_ELEMENT_INDIRECTLY:
+    problemMessage: "The member '{0}' can't be exported as a part of a package's public API, but is indirectly exported as part of the signature of '{1}'."
+    correctionMessage: "Try using a hide clause to hide '{0}'."
+    comment: |-
+      Parameters:
+      0: the name of the element
+      1: ?
+    hasPublishedDocs: true
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a [public library][] exports a
+      top-level function  with a return type or at least one parameter type that
+      is marked with the `[internal][meta-internal]` annotation.
+
+      #### Example
+
+      Given a file named `a.dart` in the `src` directory that contains the
+      following:
+
+      ```dart
+      %uri="lib/src/a.dart"
+      import 'package:meta/meta.dart';
+
+      @internal
+      typedef IntFunction = int Function();
+
+      int f(IntFunction g) => g();
+      ```
+
+      The following code produces this diagnostic because the function `f` has a
+      parameter of type `IntFunction`, and `IntFunction` is only intended to be
+      used internally:
+
+      ```dart
+      [!export 'src/a.dart' show f;!]
+      ```
+
+      #### Common fixes
+
+      If the function must be public, then make all the types in the function's
+      signature public types.
+
+      If the function doesn't need to be exported, then stop exporting it,
+      either by removing it from the `show` clause, adding it to the `hide`
+      clause, or by removing the export.
+  INVALID_FACTORY_ANNOTATION:
+    problemMessage: Only methods can be annotated as factories.
+    comment: |-
+      This hint is generated anywhere a @factory annotation is associated with
+      anything other than a method.
+  INVALID_FACTORY_METHOD_DECL:
+    problemMessage: "Factory method '{0}' must have a return type."
+    comment: |-
+      Parameters:
+      0: The name of the method
+    hasPublishedDocs: true
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a method that is annotated with
+      the `[factory][meta-factory]` annotation has a return type of `void`.
+
+      #### Example
+
+      The following code produces this diagnostic because the method `createC`
+      is annotated with the `[factory][meta-factory]` annotation but doesn't
+      return any value:
+
+      ```dart
+      import 'package:meta/meta.dart';
+
+      class Factory {
+        @factory
+        void [!createC!]() {}
+      }
+
+      class C {}
+      ```
+
+      #### Common fixes
+
+      Change the return type to something other than `void`:
+
+      ```dart
+      import 'package:meta/meta.dart';
+
+      class Factory {
+        @factory
+        C createC() => C();
+      }
+
+      class C {}
+      ```
+  INVALID_FACTORY_METHOD_IMPL:
+    problemMessage: "Factory method '{0}' doesn't return a newly allocated object."
+    comment: |-
+      Parameters:
+      0: the name of the method
+    hasPublishedDocs: true
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a method that is annotated with
+      the `[factory][meta-factory]` annotation doesn't return a newly allocated
+      object.
+
+      #### Example
+
+      The following code produces this diagnostic because the method `createC`
+      returns the value of a field rather than a newly created instance of `C`:
+
+      ```dart
+      import 'package:meta/meta.dart';
+
+      class Factory {
+        C c = C();
+
+        @factory
+        C [!createC!]() => c;
+      }
+
+      class C {}
+      ```
+
+      #### Common fixes
+
+      Change the method to return a newly created instance of the return type:
+
+      ```dart
+      import 'package:meta/meta.dart';
+
+      class Factory {
+        @factory
+        C createC() => C();
+      }
+
+      class C {}
+      ```
+  INVALID_LANGUAGE_VERSION_OVERRIDE_GREATER:
+    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
+    problemMessage: "The language version override can't specify a version greater than the latest known language version: {0}.{1}."
+    correctionMessage: Try removing the language version override.
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the latest major version
+      1: the latest minor version
+  INVALID_LANGUAGE_VERSION_OVERRIDE_AT_SIGN:
+    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
+    problemMessage: "The Dart language version override number must begin with '@dart'."
+    correctionMessage: "Specify a Dart language version override with a comment like '// @dart = 2.0'."
+    comment: |-
+      No parameters.
+    hasPublishedDocs: true
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a comment that appears to be an
+      attempt to specify a language version override doesn't conform to the
+      requirements for such a comment. For more information, see
+      [Per-library language version selection](https://dart.dev/guides/language/evolution#per-library-language-version-selection).
+
+      #### Example
+
+      The following code produces this diagnostic because the word `dart` must
+      be lowercase in such a comment and because there's no equal sign between
+      the word `dart` and the version number:
+
+      ```dart
+      [!// @Dart 2.13!]
+      ```
+
+      #### Common fixes
+
+      If the comment is intended to be a language version override, then change
+      the comment to follow the correct format:
+
+      ```dart
+      // @dart = 2.13
+      ```
+  INVALID_LANGUAGE_VERSION_OVERRIDE_LOCATION:
+    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
+    problemMessage: The language version override must be specified before any declaration or directive.
+    correctionMessage: Try moving the language version override to the top of the file.
+    hasPublishedDocs: true
+  INVALID_LANGUAGE_VERSION_OVERRIDE_LOWER_CASE:
+    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
+    problemMessage: "The Dart language version override comment must be specified with the word 'dart' in all lower case."
+    correctionMessage: "Specify a Dart language version override with a comment like '// @dart = 2.0'."
+    comment: |-
+      No parameters.
+    hasPublishedDocs: true
+  INVALID_LANGUAGE_VERSION_OVERRIDE_NUMBER:
+    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
+    problemMessage: "The Dart language version override comment must be specified with a version number, like '2.0', after the '=' character."
+    correctionMessage: "Specify a Dart language version override with a comment like '// @dart = 2.0'."
+    comment: |-
+      No parameters.
+    hasPublishedDocs: true
+  INVALID_LANGUAGE_VERSION_OVERRIDE_PREFIX:
+    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
+    problemMessage: "The Dart language version override number can't be prefixed with a letter."
+    correctionMessage: "Specify a Dart language version override with a comment like '// @dart = 2.0'."
+    comment: |-
+      No parameters.
+    hasPublishedDocs: true
+  INVALID_LANGUAGE_VERSION_OVERRIDE_TRAILING_CHARACTERS:
+    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
+    problemMessage: "The Dart language version override comment can't be followed by any non-whitespace characters."
+    correctionMessage: "Specify a Dart language version override with a comment like '// @dart = 2.0'."
+    comment: |-
+      No parameters.
+    hasPublishedDocs: true
+  INVALID_LANGUAGE_VERSION_OVERRIDE_TWO_SLASHES:
+    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
+    problemMessage: The Dart language version override comment must be specified with exactly two slashes.
+    correctionMessage: "Specify a Dart language version override with a comment like '// @dart = 2.0'."
+    comment: |-
+      No parameters.
+    hasPublishedDocs: true
+  INVALID_LANGUAGE_VERSION_OVERRIDE_EQUALS:
+    sharedName: INVALID_LANGUAGE_VERSION_OVERRIDE
+    problemMessage: "The Dart language version override comment must be specified with an '=' character."
+    correctionMessage: "Specify a Dart language version override with a comment like '// @dart = 2.0'."
+    comment: |-
+      No parameters.
+    hasPublishedDocs: true
+  INVALID_REQUIRED_NAMED_PARAM:
+    problemMessage: "The type parameter '{0}' is annotated with @required but only named parameters without a default value can be annotated with it."
+    correctionMessage: Remove @required.
+    comment: |-
+      This hint is generated anywhere where `@required` annotates a named
+      parameter with a default value.
+
+      Parameters:
+      0: the name of the member
+  INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM:
+    problemMessage: "Incorrect use of the annotation @required on the optional positional parameter '{0}'. Optional positional parameters cannot be required."
+    correctionMessage: Remove @required.
+    comment: |-
+      This hint is generated anywhere where `@required` annotates an optional
+      positional parameter.
+
+      Parameters:
+      0: the name of the member
+  INVALID_REQUIRED_POSITIONAL_PARAM:
+    problemMessage: "Redundant use of the annotation @required on the required positional parameter '{0}'."
+    correctionMessage: Remove @required.
+    comment: |-
+      This hint is generated anywhere where `@required` annotates a non optional
+      positional parameter.
+
+      Parameters:
+      0: the name of the member
+  INVALID_USE_OF_INTERNAL_MEMBER:
+    problemMessage: "The member '{0}' can only be used within its package."
+    comment: |-
+      Parameters:
+      0: the name of the member
+    hasPublishedDocs: true
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a reference to a declaration
+      that is annotated with the `[internal][meta-internal]` annotation is found
+      outside the package containing the declaration.
+
+      #### Example
+
+      Given a package `p` that defines a library containing a declaration marked
+      with the `[internal][meta-internal]` annotation:
+
+      ```dart
+      %uri="package:p/src/p.dart"
+      import 'package:meta/meta.dart';
+
+      @internal
+      class C {}
+      ```
+
+      The following code produces this diagnostic because it's referencing the
+      class `C`, which isn't intended to be used outside the package `p`:
+
+      ```dart
+      import 'package:p/src/p.dart';
+
+      void f([!C!] c) {}
+      ```
+
+      #### Common fixes
+
+      Remove the reference to the internal declaration.
+  INVALID_USE_OF_PROTECTED_MEMBER:
+    problemMessage: "The member '{0}' can only be used within instance members of subclasses of '{1}'."
+    comment: |-
+      This hint is generated anywhere where a member annotated with `@protected`
+      is used outside of an instance member of a subclass.
+
+      Parameters:
+      0: the name of the member
+      1: the name of the defining class
+  INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER:
+    problemMessage: "The member '{0}' can only be used for overriding."
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the name of the member
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when an instance member that is
+      annotated with `[visibleForOverriding][meta-visibleForOverriding]` is
+      referenced outside the library in which it's declared for any reason other
+      than to override it.
+
+      #### Example
+
+      Given a file named `a.dart` containing the following declaration:
+
+      ```dart
+      %uri="lib/a.dart"
+      import 'package:meta/meta.dart';
+
+      class A {
+        @visibleForOverriding
+        void a() {}
+      }
+      ```
+
+      The following code produces this diagnostic because the method `m` is being
+      invoked even though the only reason it's public is to allow it to be
+      overridden:
+
+      ```dart
+      import 'a.dart';
+
+      class B extends A {
+        void b() {
+          [!a!]();
+        }
+      }
+      ```
+
+      #### Common fixes
+
+      Remove the invalid use of the member.
+  INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER:
+    problemMessage: "The member '{0}' can only be used within '{1}' or a template library."
+    comment: |-
+      This hint is generated anywhere where a member annotated with
+      `@visibleForTemplate` is used outside of a "template" Dart file.
+
+      Parameters:
+      0: the name of the member
+      1: the name of the defining class
+  INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER:
+    problemMessage: "The member '{0}' can only be used within '{1}' or a test."
+    hasPublishedDocs: true
+    comment: |-
+      This hint is generated anywhere where a member annotated with
+      `@visibleForTesting` is used outside the defining library, or a test.
+
+      Parameters:
+      0: the name of the member
+      1: the name of the defining class
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a member annotated with
+      `@visibleForTesting` is referenced anywhere other than the library in
+      which it is declared or in a library in the `test` directory.
+
+      #### Example
+
+      Given a file named `c.dart` that contains the following:
+
+      ```dart
+      %uri="lib/c.dart"
+      import 'package:meta/meta.dart';
+
+      class C {
+        @visibleForTesting
+        void m() {}
+      }
+      ```
+
+      The following code, when not inside the `test` directory, produces this
+      diagnostic because the method `m` is marked as being visible only for
+      tests:
+
+      ```dart
+      import 'c.dart';
+
+      void f(C c) {
+        c.[!m!]();
+      }
+      ```
+
+      #### Common fixes
+
+      If the annotated member should not be referenced outside of tests, then
+      remove the reference:
+
+      ```dart
+      import 'c.dart';
+
+      void f(C c) {}
+      ```
+
+      If it's OK to reference the annotated member outside of tests, then remove
+      the annotation:
+
+      ```dart
+      class C {
+        void m() {}
+      }
+      ```
+  RETURN_TYPE_INVALID_FOR_CATCH_ERROR:
+    sharedName: INVALID_RETURN_TYPE_FOR_CATCH_ERROR
+    problemMessage: "The return type '{0}' isn't assignable to '{1}', as required by 'Future.catchError'."
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the return type of the function
+      1: the expected return type as defined by the type of the Future
+  RETURN_OF_INVALID_TYPE_FROM_CATCH_ERROR:
+    sharedName: INVALID_RETURN_TYPE_FOR_CATCH_ERROR
+    problemMessage: "A value of type '{0}' can't be returned by the 'onError' handler because it must be assignable to '{1}'."
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the return type as declared in the return statement
+      1: the expected return type as defined by the type of the Future
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when an invocation of
+      `Future.catchError` has an argument whose return type isn't compatible with
+      the type returned by the instance of `Future`. At runtime, the method
+      `catchError` attempts to return the value from the callback as the result
+      of the future, which results in another exception being thrown.
+
+      #### Examples
+
+      The following code produces this diagnostic because `future` is declared to
+      return an `int` while `callback` is declared to return a `String`, and
+      `String` isn't a subtype of `int`:
+
+      ```dart
+      void f(Future<int> future, String Function(dynamic, StackTrace) callback) {
+        future.catchError([!callback!]);
+      }
+      ```
+
+      The following code produces this diagnostic because the closure being
+      passed to `catchError` returns an `int` while `future` is declared to
+      return a `String`:
+
+      ```dart
+      void f(Future<String> future) {
+        future.catchError((error, stackTrace) => [!3!]);
+      }
+      ```
+
+      #### Common fixes
+
+      If the instance of `Future` is declared correctly, then change the callback
+      to match:
+
+      ```dart
+      void f(Future<int> future, int Function(dynamic, StackTrace) callback) {
+        future.catchError(callback);
+      }
+      ```
+
+      If the declaration of the instance of `Future` is wrong, then change it to
+      match the callback:
+
+      ```dart
+      void f(Future<String> future, String Function(dynamic, StackTrace) callback) {
+        future.catchError(callback);
+      }
+      ```
+  INVALID_SEALED_ANNOTATION:
+    problemMessage: "The annotation '@sealed' can only be applied to classes."
+    correctionMessage: Try removing the '@sealed' annotation.
+    hasPublishedDocs: true
+    comment: |-
+      This hint is generated anywhere where `@sealed` annotates something other
+      than a class.
+
+      No parameters.
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a declaration other than a
+      class declaration has the `@sealed` annotation on it.
+
+      #### Example
+
+      The following code produces this diagnostic because the `@sealed`
+      annotation is on a method declaration:
+
+      ```dart
+      import 'package:meta/meta.dart';
+
+      class A {
+        [!@sealed!]
+        void m() {}
+      }
+      ```
+
+      #### Common fixes
+
+      Remove the annotation:
+
+      ```dart
+      class A {
+        void m() {}
+      }
+      ```
+  MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_ONE:
+    sharedName: MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN
+    problemMessage: "Missing concrete implementation of '{0}'."
+    correctionMessage: Try overriding the missing member.
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the name of the member
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when an instance member that has the
+      `@mustBeOverridden` annotation isn't overridden in a subclass.
+
+      #### Example
+
+      The following code produces this diagnostic because the class `B` doesn't
+      have an override of the inherited method `A.m` when `A.m` is annotated
+      with `@mustBeOverridden`:
+
+      ```dart
+      import 'package:meta/meta.dart';
+
+      class A {
+        @mustBeOverridden
+        void m() {}
+      }
+
+      class [!B!] extends A {}
+      ```
+
+      #### Common fixes
+
+      If the annotation is appropriate for the member, then override the member
+      in the subclass:
+
+      ```dart
+      import 'package:meta/meta.dart';
+
+      class A {
+        @mustBeOverridden
+        void m() {}
+      }
+
+      class B extends A {
+        @override
+        void m() {}
+      }
+      ```
+
+      If the annotation isn't appropriate for the member, then remove the
+      annotation:
+
+      ```dart
+      class A {
+        void m() {}
+      }
+
+      class B extends A {}
+      ```
+  MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_TWO:
+    sharedName: MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN
+    problemMessage: "Missing concrete implementations of '{0}' and '{1}'."
+    correctionMessage: Try overriding the missing members.
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the name of the first member
+      1: the name of the second member
+  MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN_THREE_PLUS:
+    sharedName: MISSING_OVERRIDE_OF_MUST_BE_OVERRIDDEN
+    problemMessage: "Missing concrete implementations of '{0}', '{1}', and {2} more."
+    correctionMessage: Try overriding the missing members.
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the name of the first member
+      1: the name of the second member
+      2: the number of additional missing members that aren't listed
+  MISSING_REQUIRED_PARAM:
+    problemMessage: "The parameter '{0}' is required."
+    hasPublishedDocs: true
+    comment: |-
+      Generate a hint for a constructor, function or method invocation where a
+      required parameter is missing.
+
+      Parameters:
+      0: the name of the parameter
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a method or function with a
+      named parameter that is annotated as being required is invoked without
+      providing a value for the parameter.
+
+      #### Example
+
+      The following code produces this diagnostic because the named parameter `x`
+      is required:
+
+      ```dart
+      %language=2.9
+      import 'package:meta/meta.dart';
+
+      void f({@required int x}) {}
+
+      void g() {
+        [!f!]();
+      }
+      ```
+
+      #### Common fixes
+
+      Provide the required value:
+
+      ```dart
+      %language=2.9
+      import 'package:meta/meta.dart';
+
+      void f({@required int x}) {}
+
+      void g() {
+        f(x: 2);
+      }
+      ```
+  MISSING_REQUIRED_PARAM_WITH_DETAILS:
+    sharedName: MISSING_REQUIRED_PARAM
+    problemMessage: "The parameter '{0}' is required. {1}."
+    hasPublishedDocs: true
+    comment: |-
+      Generate a hint for a constructor, function or method invocation where a
+      required parameter is missing.
+
+      Parameters:
+      0: the name of the parameter
+      1: message details
+  MISSING_RETURN:
+    problemMessage: "This function has a return type of '{0}', but doesn't end with a return statement."
+    correctionMessage: "Try adding a return statement, or changing the return type to 'void'."
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the name of the declared return type
+    documentation: |-
+      #### Description
+
+      Any function or method that doesn't end with either an explicit return or a
+      throw implicitly returns `null`. This is rarely the desired behavior. The
+      analyzer produces this diagnostic when it finds an implicit return.
+
+      #### Example
+
+      The following code produces this diagnostic because `f` doesn't end with a
+      return:
+
+      ```dart
+      %language=2.9
+      int [!f!](int x) {
+        if (x < 0) {
+          return 0;
+        }
+      }
+      ```
+
+      #### Common fixes
+
+      Add a `return` statement that makes the return value explicit, even if
+      `null` is the appropriate value.
+  NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR:
+    aliasFor: HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR
+    comment: This is the new replacement for [HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR].
+  NULLABLE_TYPE_IN_CATCH_CLAUSE:
+    problemMessage: "A potentially nullable type can't be used in an 'on' clause because it isn't valid to throw a nullable expression."
+    correctionMessage: Try using a non-nullable type.
+    hasPublishedDocs: true
+    comment: No parameters.
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when the type following `on` in a
+      `catch` clause is a nullable type. It isn't valid to specify a nullable
+      type because it isn't possible to catch `null` (because it's a runtime
+      error to throw `null`).
+
+      #### Example
+
+      The following code produces this diagnostic because the exception type is
+      specified to allow `null` when `null` can't be thrown:
+
+      ```dart
+      void f() {
+        try {
+          // ...
+        } on [!FormatException?!] {
+        }
+      }
+      ```
+
+      #### Common fixes
+
+      Remove the question mark from the type:
+
+      ```dart
+      void f() {
+        try {
+          // ...
+        } on FormatException {
+        }
+      }
+      ```
+  NULL_ARGUMENT_TO_NON_NULL_TYPE:
+    problemMessage: "'{0}' shouldn't be called with a null argument for the non-nullable type argument '{1}'."
+    correctionMessage: Try adding a non-null argument.
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the name of the method being invoked
+      1: the type argument associated with the method
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when `null` is passed to either the
+      constructor `Future.value` or the method `Completer.complete` when the type
+      argument used to create the instance was non-nullable. Even though the type
+      system can't express this restriction, passing in a `null` results in a
+      runtime exception.
+
+      #### Example
+
+      The following code produces this diagnostic because `null` is being passed
+      to the constructor `Future.value` even though the type argument is the
+      non-nullable type `String`:
+
+      ```dart
+      Future<String> f() {
+        return Future.value([!null!]);
+      }
+      ```
+
+      #### Common fixes
+
+      Pass in a non-null value:
+
+      ```dart
+      Future<String> f() {
+        return Future.value('');
+      }
+      ```
+  NULL_AWARE_BEFORE_OPERATOR:
+    problemMessage: "The left operand uses '?.', so its value can be null."
+    comment: |-
+      When the left operand of a binary expression uses '?.' operator, it can be
+      `null`.
+  NULL_AWARE_IN_CONDITION:
+    problemMessage: "The value of the '?.' operator can be 'null', which isn't appropriate in a condition."
+    correctionMessage: "Try replacing the '?.' with a '.', testing the left-hand side for null if necessary."
+    comment: |-
+      A condition in a control flow statement could evaluate to `null` because it
+      uses the null-aware '?.' operator.
+  NULL_AWARE_IN_LOGICAL_OPERATOR:
+    problemMessage: "The value of the '?.' operator can be 'null', which isn't appropriate as an operand of a logical operator."
+    comment: |-
+      A condition in operands of a logical operator could evaluate to `null`
+      because it uses the null-aware '?.' operator.
+  OVERRIDE_ON_NON_OVERRIDING_FIELD:
+    aliasFor: HintCode.OVERRIDE_ON_NON_OVERRIDING_FIELD
+    comment: This is the new replacement for [HintCode.OVERRIDE_ON_NON_OVERRIDING_FIELD].
+  RECEIVER_OF_TYPE_NEVER:
+    problemMessage: "The receiver is of type 'Never', and will never complete with a value."
+    correctionMessage: Try checking for throw expressions or type errors in the receiver
+    comment: |-
+      It is not an error to call or tear-off a method, setter, or getter, or to
+      read or write a field, on a receiver of static type `Never`.
+      Implementations that provide feedback about dead or unreachable code are
+      encouraged to indicate that any arguments to the invocation are
+      unreachable.
+
+      It is not an error to apply an expression of type `Never` in the function
+      position of a function call. Implementations that provide feedback about
+      dead or unreachable code are encouraged to indicate that any arguments to
+      the call are unreachable.
+
+      Parameters: none
+  REMOVED_LINT_USE:
+    problemMessage: "'{0}' was removed in Dart '{1}'"
+    correctionMessage: "Remove the reference to '{0}'."
+    comment: |-
+      An error code indicating use of a removed lint rule.
+
+      Parameters:
+      0: the rule name
+      1: the SDK version in which the lint was removed
+  REPLACED_LINT_USE:
+    problemMessage:  "'{0}' was replaced by '{2}' in Dart '{1}'."
+    correctionMessage: "Replace '{0}' with '{1}'."
+    comment: |-
+      An error code indicating use of a removed lint rule.
+
+      Parameters:
+      0: the rule name
+      1: the SDK version in which the lint was removed
+      2: the name of a replacing lint
+  RETURN_OF_DO_NOT_STORE:
+    problemMessage: "'{0}' is annotated with 'doNotStore' and shouldn't be returned unless '{1}' is also annotated."
+    correctionMessage: "Annotate '{1}' with 'doNotStore'."
+    comment: |-
+      Parameters:
+      0: the name of the annotated function being invoked
+      1: the name of the function containing the return
+    hasPublishedDocs: true
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a value that is annotated with
+      the `[doNotStore][meta-doNotStore]` annotation is returned from a method,
+      getter, or function that doesn't have the same annotation.
+
+      #### Example
+
+      The following code produces this diagnostic because the result of invoking
+      `f` shouldn't be stored, but the function `g` isn't annotated to preserve
+      that semantic:
+
+      ```dart
+      import 'package:meta/meta.dart';
+
+      @doNotStore
+      int f() => 0;
+
+      int g() => [!f()!];
+      ```
+
+      #### Common fixes
+
+      If the value that shouldn't be stored is the correct value to return, then
+      mark the function with the `[doNotStore][meta-doNotStore]` annotation:
+
+      ```dart
+      import 'package:meta/meta.dart';
+
+      @doNotStore
+      int f() => 0;
+
+      @doNotStore
+      int g() => f();
+      ```
+
+      Otherwise, return a different value from the function:
+
+      ```dart
+      import 'package:meta/meta.dart';
+
+      @doNotStore
+      int f() => 0;
+
+      int g() => 0;
+      ```
   SDK_VERSION_ASYNC_EXPORTED_FROM_CORE:
     problemMessage: "The class '{0}' wasn't exported from 'dart:core' until version 2.1, but this code is required to be able to run on earlier versions."
     correctionMessage: "Try either importing 'dart:async' or updating the SDK constraints."
@@ -23355,34 +23305,329 @@
       const a = [1, 2];
       var b = [...a];
       ```
-  UNNECESSARY_NON_NULL_ASSERTION:
-    problemMessage: "The '!' will have no effect because the receiver can't be null."
-    correctionMessage: "Try removing the '!' operator."
+  TEXT_DIRECTION_CODE_POINT_IN_COMMENT:
+    problemMessage: The Unicode code point 'U+{0}' changes the appearance of text from how it's interpreted by the compiler.
+    correctionMessage: Try removing the code point or using the Unicode escape sequence '\u{0}'.
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the unicode sequence of the code point.
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when it encounters source that
+      contains text direction Unicode code points. These code points cause
+      source code in either a string literal or a comment to be interpreted
+      and compiled differently than how it appears in editors, leading to
+      possible security vulnerabilities.
+
+      #### Example
+
+      The following code produces this diagnostic twice because there are
+      hidden characters at the start and end of the label string:
+
+      ```dart
+      var label = '[!I!]nteractive text[!'!];
+      ```
+
+      #### Common fixes
+
+      If the code points are intended to be included in the string literal,
+      then escape them:
+
+      ```dart
+      var label = '\u202AInteractive text\u202C';
+      ```
+
+      If the code points aren't intended to be included in the string literal,
+      then remove them:
+
+      ```dart
+      var label = 'Interactive text';
+      ```
+  TEXT_DIRECTION_CODE_POINT_IN_LITERAL:
+    problemMessage: The Unicode code point 'U+{0}' changes the appearance of text from how it's interpreted by the compiler.
+    correctionMessage: Try removing the code point or using the Unicode escape sequence '\u{0}'.
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the unicode sequence of the code point.
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when it encounters source that
+      contains text direction Unicode code points. These code points cause
+      source code in either a string literal or a comment to be interpreted
+      and compiled differently than how it appears in editors, leading to
+      possible security vulnerabilities.
+
+      #### Example
+
+      The following code produces this diagnostic twice because there are
+      hidden characters at the start and end of the label string:
+
+      ```dart
+      var label = '[!I!]nteractive text[!'!];
+      ```
+
+      #### Common fixes
+
+      If the code points are intended to be included in the string literal,
+      then escape them:
+
+      ```dart
+      var label = '\u202AInteractive text\u202C';
+      ```
+
+      If the code points aren't intended to be included in the string literal,
+      then remove them:
+
+      ```dart
+      var label = 'Interactive text';
+      ```
+  TYPE_CHECK_IS_NOT_NULL:
+    sharedName: TYPE_CHECK_WITH_NULL
+    problemMessage: "Tests for non-null should be done with '!= null'."
+    correctionMessage: "Try replacing the 'is! Null' check with '!= null'."
     hasPublishedDocs: true
     comment: No parameters.
     documentation: |-
       #### Description
 
-      The analyzer produces this diagnostic when the operand of the `!` operator
-      can't be `null`.
+      The analyzer produces this diagnostic when there's a type check (using the
+      `as` operator) where the type is `Null`. There's only one value whose type
+      is `Null`, so the code is both more readable and more performant when it
+      tests for `null` explicitly.
 
-      #### Example
+      #### Examples
 
-      The following code produces this diagnostic because `x` can't be `null`:
+      The following code produces this diagnostic because the code is testing to
+      see whether the value of `s` is `null` by using a type check:
 
       ```dart
-      int f(int x) {
-        return x[!!!];
+      void f(String? s) {
+        if ([!s is Null!]) {
+          return;
+        }
+        print(s);
+      }
+      ```
+
+      The following code produces this diagnostic because the code is testing to
+      see whether the value of `s` is something other than `null` by using a type
+      check:
+
+      ```dart
+      void f(String? s) {
+        if ([!s is! Null!]) {
+          print(s);
+        }
       }
       ```
 
       #### Common fixes
 
-      Remove the null check operator (`!`):
+      Replace the type check with the equivalent comparison with `null`:
 
       ```dart
-      int f(int x) {
-        return x;
+      void f(String? s) {
+        if (s == null) {
+          return;
+        }
+        print(s);
+      }
+      ```
+  TYPE_CHECK_IS_NULL:
+    sharedName: TYPE_CHECK_WITH_NULL
+    problemMessage: "Tests for null should be done with '== null'."
+    correctionMessage: "Try replacing the 'is Null' check with '== null'."
+    hasPublishedDocs: true
+    comment: No parameters.
+  UNDEFINED_HIDDEN_NAME:
+    problemMessage: "The library '{0}' doesn't export a member with the hidden name '{1}'."
+    correctionMessage: Try removing the name from the list of hidden members.
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the name of the library being imported
+      1: the name in the hide clause that isn't defined in the library
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a hide combinator includes a
+      name that isn't defined by the library being imported.
+
+      #### Example
+
+      The following code produces this diagnostic because `dart:math` doesn't
+      define the name `String`:
+
+      ```dart
+      import 'dart:math' hide [!String!], max;
+
+      var x = min(0, 1);
+      ```
+
+      #### Common fixes
+
+      If a different name should be hidden, then correct the name. Otherwise,
+      remove the name from the list:
+
+      ```dart
+      import 'dart:math' hide max;
+
+      var x = min(0, 1);
+      ```
+  UNDEFINED_SHOWN_NAME:
+    problemMessage: "The library '{0}' doesn't export a member with the shown name '{1}'."
+    correctionMessage: Try removing the name from the list of shown members.
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the name of the library being imported
+      1: the name in the show clause that isn't defined in the library
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a show combinator includes a
+      name that isn't defined by the library being imported.
+
+      #### Example
+
+      The following code produces this diagnostic because `dart:math` doesn't
+      define the name `String`:
+
+      ```dart
+      import 'dart:math' show min, [!String!];
+
+      var x = min(0, 1);
+      ```
+
+      #### Common fixes
+
+      If a different name should be shown, then correct the name. Otherwise,
+      remove the name from the list:
+
+      ```dart
+      import 'dart:math' show min;
+
+      var x = min(0, 1);
+      ```
+  UNNECESSARY_CAST:
+    aliasFor: HintCode.UNNECESSARY_CAST
+    comment: This is the new replacement for [HintCode.UNNECESSARY_CAST].
+  UNNECESSARY_CAST_PATTERN:
+    problemMessage: Unnecessary cast pattern.
+    correctionMessage: Try removing the cast pattern.
+    comment: No parameters.
+  UNNECESSARY_FINAL:
+    aliasFor: HintCode.UNNECESSARY_FINAL
+    comment: This is the new replacement for [HintCode.UNNECESSARY_FINAL].
+  UNNECESSARY_TYPE_CHECK_FALSE:
+    aliasFor: HintCode.UNNECESSARY_TYPE_CHECK_FALSE
+    comment: This is the new replacement for [HintCode.UNNECESSARY_TYPE_CHECK_FALSE].
+  UNNECESSARY_TYPE_CHECK_TRUE:
+    aliasFor: HintCode.UNNECESSARY_TYPE_CHECK_TRUE
+    comment: This is the new replacement for [HintCode.UNNECESSARY_TYPE_CHECK_TRUE].
+  UNNECESSARY_WILDCARD_PATTERN:
+    problemMessage: Unnecessary wildcard pattern.
+    correctionMessage: Try removing the wildcard pattern.
+    comment: No parameters.
+  UNUSED_CATCH_CLAUSE:
+    problemMessage: "The exception variable '{0}' isn't used, so the 'catch' clause can be removed."
+    correctionMessage: Try removing the catch clause.
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the name of the exception variable
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when a `catch` clause is found, and
+      neither the exception parameter nor the optional stack trace parameter are
+      used in the `catch` block.
+
+      #### Example
+
+      The following code produces this diagnostic because `e` isn't referenced:
+
+      ```dart
+      void f() {
+        try {
+          int.parse(';');
+        } on FormatException catch ([!e!]) {
+          // ignored
+        }
       }
       ```
 
+      #### Common fixes
+
+      Remove the unused `catch` clause:
+
+      ```dart
+      void f() {
+        try {
+          int.parse(';');
+        } on FormatException {
+          // ignored
+        }
+      }
+      ```
+  UNUSED_CATCH_STACK:
+    problemMessage: "The stack trace variable '{0}' isn't used and can be removed."
+    correctionMessage: Try removing the stack trace variable, or using it.
+    hasPublishedDocs: true
+    comment: |-
+      Parameters:
+      0: the name of the stack trace variable
+    documentation: |-
+      #### Description
+
+      The analyzer produces this diagnostic when the stack trace parameter in a
+      `catch` clause isn't referenced within the body of the `catch` block.
+
+      #### Example
+
+      The following code produces this diagnostic because `stackTrace` isn't
+      referenced:
+
+      ```dart
+      void f() {
+        try {
+          // ...
+        } catch (exception, [!stackTrace!]) {
+          // ...
+        }
+      }
+      ```
+
+      #### Common fixes
+
+      If you need to reference the stack trace parameter, then add a reference to
+      it. Otherwise, remove it:
+
+      ```dart
+      void f() {
+        try {
+          // ...
+        } catch (exception) {
+          // ...
+        }
+      }
+      ```
+  UNUSED_ELEMENT:
+    aliasFor: HintCode.UNUSED_ELEMENT
+    comment: This is the new replacement for [HintCode.UNUSED_ELEMENT].
+  UNUSED_ELEMENT_PARAMETER:
+    aliasFor: HintCode.UNUSED_ELEMENT_PARAMETER
+    comment: This is the new replacement for [HintCode.UNUSED_ELEMENT_PARAMETER].
+  UNUSED_FIELD:
+    aliasFor: HintCode.UNUSED_FIELD
+    comment: This is the new replacement for [HintCode.UNUSED_FIELD].
+  UNUSED_IMPORT:
+    aliasFor: HintCode.UNUSED_IMPORT
+    comment: This is the new replacement for [HintCode.UNUSED_IMPORT].
+  UNUSED_LOCAL_VARIABLE:
+    aliasFor: HintCode.UNUSED_LOCAL_VARIABLE
+    comment: This is the new replacement for [HintCode.UNUSED_LOCAL_VARIABLE].
diff --git a/analyzer/pubspec.yaml b/analyzer/pubspec.yaml
index 37f04e0..b9f7d88 100644
--- a/analyzer/pubspec.yaml
+++ b/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 5.4.0
+version: 5.5.0
 description: This package provides a library that performs static analysis of Dart code.
 repository: https://github.com/dart-lang/sdk/tree/main/pkg/analyzer
 
@@ -7,7 +7,7 @@
   sdk: '>=2.17.0 <3.0.0'
 
 dependencies:
-  _fe_analyzer_shared: ^52.0.0
+  _fe_analyzer_shared: ^53.0.0
   collection: ^1.17.0
   convert: ^3.0.0
   crypto: ^3.0.0
diff --git a/analyzer/tool/diagnostics/diagnostics.md b/analyzer/tool/diagnostics/diagnostics.md
index b7ddcc9..1891321 100644
--- a/analyzer/tool/diagnostics/diagnostics.md
+++ b/analyzer/tool/diagnostics/diagnostics.md
@@ -284,6 +284,7 @@
 that might work in unexpected ways.
 
 [ffi]: https://dart.dev/guides/libraries/c-interop
+[IEEE 754]: https://en.wikipedia.org/wiki/IEEE_754
 [meta-doNotStore]: https://pub.dev/documentation/meta/latest/meta/doNotStore-constant.html
 [meta-factory]: https://pub.dev/documentation/meta/latest/meta/factory-constant.html
 [meta-immutable]: https://pub.dev/documentation/meta/latest/meta/immutable-constant.html
@@ -3320,10 +3321,12 @@
 C<T> newC<T>() => C<T>();
 {% endprettify %}
 
-### continue_label_on_switch
+### continue_label_invalid
 
-_A `continue` label resolves to a `switch` statement, but the label must be on a
-loop or a switch member._
+<a id="continue_label_on_switch" aria-hidden="true"></a>_(Previously known as `continue_label_on_switch`)_
+
+_The label used in a 'continue' statement must be defined on either a loop or a
+switch member._
 
 #### Description
 
@@ -3339,7 +3342,7 @@
 void f(int i) {
   l: switch (i) {
     case 0:
-      continue [!l!];
+      [!continue l;!]
   }
 }
 {% endprettify %}
@@ -6715,7 +6718,7 @@
 
 ### for_in_of_invalid_type
 
-_The type '{0}' used in the 'for' loop must implement {1}._
+_The type '{0}' used in the 'for' loop must implement '{1}'._
 
 #### Description
 
@@ -7619,7 +7622,7 @@
 Given a [part file][] named `part.dart` that contains the following:
 
 {% prettify dart tag=pre+code %}
-// @dart = 2.6
+// @dart = 2.14
 part of 'test.dart';
 {% endprettify %}
 
@@ -7627,7 +7630,7 @@
 must have the same language version as the defining compilation unit:
 
 {% prettify dart tag=pre+code %}
-// @dart = 2.5
+// @dart = 2.15
 part [!'part.dart'!];
 {% endprettify %}
 
@@ -8794,6 +8797,9 @@
 
 _'{1}.{0}' ('{2}') isn't a valid concrete implementation of '{3}.{0}' ('{4}')._
 
+_The setter '{1}.{0}' ('{2}') isn't a valid concrete implementation of '{3}.{0}'
+('{4}')._
+
 #### Description
 
 The analyzer produces this diagnostic when all of the following are true:
@@ -9001,7 +9007,7 @@
 the word `dart` and the version number:
 
 {% prettify dart tag=pre+code %}
-[!// @Dart 2.9!]
+[!// @Dart 2.13!]
 {% endprettify %}
 
 #### Common fixes
@@ -9010,7 +9016,7 @@
 the comment to follow the correct format:
 
 {% prettify dart tag=pre+code %}
-// @dart = 2.9
+// @dart = 2.13
 {% endprettify %}
 
 ### invalid_literal_annotation
@@ -9310,6 +9316,8 @@
 
 _'{1}.{0}' ('{2}') isn't a valid override of '{3}.{0}' ('{4}')._
 
+_The setter '{1}.{0}' ('{2}') isn't a valid override of '{3}.{0}' ('{4}')._
+
 #### Description
 
 The analyzer produces this diagnostic when a member of a class is found
@@ -11108,11 +11116,11 @@
 
 ### missing_override_of_must_be_overridden
 
-_Missing concrete override implementation of '{0}' and '{1}'._
+_Missing concrete implementation of '{0}'._
 
-_Missing concrete override implementation of '{0}', '{1}', and {2} more._
+_Missing concrete implementations of '{0}' and '{1}'._
 
-_Missing concrete override implementation of '{0}'._
+_Missing concrete implementations of '{0}', '{1}', and {2} more._
 
 #### Description
 
@@ -11449,6 +11457,9 @@
 _The class doesn't have a concrete implementation of the super-invoked member
 '{0}'._
 
+_The class doesn't have a concrete implementation of the super-invoked setter
+'{0}'._
+
 #### Description
 
 The analyzer produces this diagnostic when a [mixin application][] contains
@@ -14866,16 +14877,16 @@
 Given a file named `a.dart` containing the following code:
 
 {% prettify dart tag=pre+code %}
-class A {
+mixin A {
   void _foo() {}
 }
 
-class B {
+mixin B {
   void _foo() {}
 }
 {% endprettify %}
 
-The following code produces this diagnostic because the classes `A` and `B`
+The following code produces this diagnostic because the mixins `A` and `B`
 both define the method `_foo`:
 
 {% prettify dart tag=pre+code %}
@@ -19350,6 +19361,43 @@
 aren't yet, and if those names aren't imported by other imports, then add
 the missing references to those names.
 
+### unnecessary_nan_comparison
+
+_A double can't equal 'double.nan', so the condition is always 'false'._
+
+_A double can't equal 'double.nan', so the condition is always 'true'._
+
+#### Description
+
+The analyzer produces this diagnostic when a value is compared to
+`double.nan` using either `==` or `!=`.
+
+Dart follows the [IEEE 754] floating-point standard for the semantics of
+floating point operations, which states that, for any floating point value
+`x` (including NaN, positive infinity, and negative infinity),
+- `NaN == x` is always false
+- `NaN != x` is always true
+
+As a result, comparing any value to NaN is pointless because the result is
+already known (based on the comparison operator being used).
+
+#### Example
+
+The following code produces this diagnostic because `d` is being compared
+to `double.nan`:
+
+{% prettify dart tag=pre+code %}
+bool isNaN(double d) => d [!== double.nan!];
+{% endprettify %}
+
+#### Common fixes
+
+Use the getter `double.isNaN` instead:
+
+{% prettify dart tag=pre+code %}
+bool isNaN(double d) => d.isNaN;
+{% endprettify %}
+
 ### unnecessary_non_null_assertion
 
 _The '!' will have no effect because the receiver can't be null._
@@ -19429,9 +19477,9 @@
 
 ### unnecessary_null_comparison
 
-_The operand can't be null, so the condition is always false._
+_The operand can't be null, so the condition is always 'false'._
 
-_The operand can't be null, so the condition is always true._
+_The operand can't be null, so the condition is always 'true'._
 
 #### Description
 
diff --git a/analyzer/tool/diagnostics/generate.dart b/analyzer/tool/diagnostics/generate.dart
index 7c29e74..e8c353a 100644
--- a/analyzer/tool/diagnostics/generate.dart
+++ b/analyzer/tool/diagnostics/generate.dart
@@ -142,6 +142,9 @@
     for (var errorEntry in messages.entries) {
       var errorName = errorEntry.key;
       var errorCodeInfo = errorEntry.value;
+      if (errorCodeInfo is AliasErrorCodeInfo) {
+        continue;
+      }
       var name = errorCodeInfo.sharedName ?? errorName;
       var info = infoByName[name];
       var message = convertTemplate(
@@ -192,6 +195,7 @@
 that might work in unexpected ways.
 
 [ffi]: https://dart.dev/guides/libraries/c-interop
+[IEEE 754]: https://en.wikipedia.org/wiki/IEEE_754
 [meta-doNotStore]: https://pub.dev/documentation/meta/latest/meta/doNotStore-constant.html
 [meta-factory]: https://pub.dev/documentation/meta/latest/meta/factory-constant.html
 [meta-immutable]: https://pub.dev/documentation/meta/latest/meta/immutable-constant.html
diff --git a/analyzer/tool/experiments/generate.dart b/analyzer/tool/experiments/generate.dart
index 3a28263..a733526 100644
--- a/analyzer/tool/experiments/generate.dart
+++ b/analyzer/tool/experiments/generate.dart
@@ -15,10 +15,10 @@
 }
 
 List<GeneratedContent> get allTargets {
-  Map<dynamic, dynamic> experimentsYaml = loadYaml(File(join(
+  var experimentsYaml = loadYaml(File(join(
           normalize(join(pkg_root.packageRoot, '../tools')),
           'experimental_features.yaml'))
-      .readAsStringSync());
+      .readAsStringSync()) as Map;
 
   return <GeneratedContent>[
     GeneratedFile('lib/src/dart/analysis/experiments.g.dart',
@@ -70,15 +70,16 @@
     if (features != null) return features;
 
     features = <String, dynamic>{};
-    Map yamlFeatures = experimentsYaml['features'];
+    var yamlFeatures = experimentsYaml['features'] as Map;
     for (MapEntry entry in yamlFeatures.entries) {
-      String category = (entry.value as YamlMap)['category'] ?? 'language';
+      var category =
+          (entry.value as YamlMap)['category'] as String? ?? 'language';
       if (category != "language") {
         // Skip a feature with a category that's not language. In the future
         // possibly allow e.g. 'analyzer' etc.
         continue;
       }
-      features[entry.key] = entry.value;
+      features[entry.key as String] = entry.value;
     }
 
     return _features = features;
@@ -214,7 +215,7 @@
     for (var key in keysSorted) {
       var entry = features[key] as YamlMap;
       bool shipped = entry['enabledIn'] != null;
-      bool? expired = entry['expired'];
+      var expired = entry['expired'] as bool?;
       out.write('''
       /// Expiration status of the experiment "$key"
       static const bool ${keyToIdentifier(key)} = ${expired == true};
diff --git a/analyzer/tool/messages/error_code_documentation_info.dart b/analyzer/tool/messages/error_code_documentation_info.dart
index 9eedda1..7130eb5 100644
--- a/analyzer/tool/messages/error_code_documentation_info.dart
+++ b/analyzer/tool/messages/error_code_documentation_info.dart
@@ -100,7 +100,7 @@
   /// the snippet.
   static const String languagePrefix = '%language=';
 
-  /// The prefix used on directive lines to indicate the uri of an auxiliary
+  /// The prefix used on directive lines to indicate the URI of an auxiliary
   /// file that is needed for testing purposes.
   static const String uriDirectivePrefix = '%uri="';
 
diff --git a/analyzer/tool/messages/error_code_info.dart b/analyzer/tool/messages/error_code_info.dart
index f2ce958..7e87c5f 100644
--- a/analyzer/tool/messages/error_code_info.dart
+++ b/analyzer/tool/messages/error_code_info.dart
@@ -46,6 +46,13 @@
       severity: 'WARNING',
       extraImports: ['package:analyzer/src/error/analyzer_error_code.dart']),
   ErrorClassInfo(
+      filePath: 'lib/src/error/codes.g.dart',
+      name: 'WarningCode',
+      superclass: 'AnalyzerErrorCode',
+      type: 'STATIC_WARNING',
+      severity: 'WARNING',
+      extraImports: ['package:analyzer/src/error/analyzer_error_code.dart']),
+  ErrorClassInfo(
       filePath: 'lib/src/dart/error/ffi_code.g.dart',
       name: 'FfiCode',
       superclass: 'AnalyzerErrorCode',
@@ -141,12 +148,32 @@
         problem('value associated with error $className.$errorName is not a '
             'map');
       }
+
       try {
-        (result[className] ??= {})[errorName] =
-            AnalyzerErrorCodeInfo.fromYaml(errorValue);
+        var aliasFor = errorValue['aliasFor'];
+        if (aliasFor is String) {
+          var aliasForPath = aliasFor.split('.');
+          if (aliasForPath.isEmpty) {
+            problem("The 'aliasFor' value at '$className.$errorName is empty");
+          }
+          var node = yaml;
+          for (var key in aliasForPath) {
+            var value = node[key];
+            if (value is! Map<Object?, Object?>) {
+              problem('No Map value at "$aliasFor", aliased from '
+                  '$className.$errorName');
+            }
+            node = value;
+          }
+
+          (result[className] ??= {})[errorName] = AliasErrorCodeInfo(
+              aliasFor: aliasFor, comment: errorValue['comment'] as String?);
+        } else {
+          (result[className] ??= {})[errorName] =
+              AnalyzerErrorCodeInfo.fromYaml(errorValue);
+        }
       } catch (e) {
-        problem('while processing '
-            '$className.$errorName, $e');
+        problem('while processing $className.$errorName, $e');
       }
     }
   }
@@ -232,6 +259,27 @@
   return lines;
 }
 
+/// An [AnalyzerErrorCodeInfo] which is an alias for another, for incremental
+/// deprecation purposes.
+class AliasErrorCodeInfo extends AnalyzerErrorCodeInfo {
+  String aliasFor;
+
+  AliasErrorCodeInfo({required this.aliasFor, super.comment})
+      : super(
+            documentation: null,
+            hasPublishedDocs: false,
+            isUnresolvedIdentifier: false,
+            sharedName: null,
+            problemMessage: 'UNUSED',
+            correctionMessage: null);
+
+  String get aliasForClass => aliasFor.split('.').first;
+
+  String get aliasForFilePath => errorClasses
+      .firstWhere((element) => element.name == aliasForClass)
+      .filePath;
+}
+
 /// In-memory representation of error code information obtained from the
 /// analyzer's `messages.yaml` file.
 class AnalyzerErrorCodeInfo extends ErrorCodeInfo {
diff --git a/analyzer/tool/messages/generate.dart b/analyzer/tool/messages/generate.dart
index a36bdb5..3e737ae 100644
--- a/analyzer/tool/messages/generate.dart
+++ b/analyzer/tool/messages/generate.dart
@@ -91,6 +91,11 @@
       if (errorClass.includeCfeMessages) {
         shouldGenerateFastaAnalyzerErrorCodes = true;
       }
+      analyzerMessages[errorClass.name]!.forEach((_, errorCodeInfo) {
+        if (errorCodeInfo is AliasErrorCodeInfo) {
+          imports.add(errorCodeInfo.aliasForFilePath.toPackageAnalyzerUri);
+        }
+      });
     }
     out.writeln();
     for (var importPath in imports.toList()..sort()) {
@@ -113,12 +118,17 @@
         var errorName = entry.key;
         var errorCodeInfo = entry.value;
 
-        generatedCodes.add('${errorClass.name}.$errorName');
-
         out.writeln();
         out.write(errorCodeInfo.toAnalyzerComments(indent: '  '));
-        out.writeln('  static const ${errorClass.name} $errorName =');
-        out.writeln(errorCodeInfo.toAnalyzerCode(errorClass.name, errorName));
+        if (errorCodeInfo is AliasErrorCodeInfo) {
+          out.writeln(
+              '  static const ${errorCodeInfo.aliasForClass} $errorName =');
+          out.writeln('${errorCodeInfo.aliasFor};');
+        } else {
+          generatedCodes.add('${errorClass.name}.$errorName');
+          out.writeln('  static const ${errorClass.name} $errorName =');
+          out.writeln(errorCodeInfo.toAnalyzerCode(errorClass.name, errorName));
+        }
       }
       out.writeln();
       out.writeln('/// Initialize a newly created error code to have the given '
@@ -363,3 +373,8 @@
     }
   }
 }
+
+extension on String {
+  String get toPackageAnalyzerUri =>
+      replaceFirst(RegExp('^lib/'), 'package:analyzer/');
+}
diff --git a/analyzer/tool/summary/mini_ast.dart b/analyzer/tool/summary/mini_ast.dart
index 8d9079d..6fd56bd 100644
--- a/analyzer/tool/summary/mini_ast.dart
+++ b/analyzer/tool/summary/mini_ast.dart
@@ -184,7 +184,7 @@
     if (precedingComments != null) {
       push(Comment(precedingComments));
     } else {
-      push(NullValue.Comments);
+      push(NullValues.Comments);
     }
   }
 
@@ -321,7 +321,7 @@
   @override
   void endImport(Token importKeyword, Token? augmentToken, Token? semicolon) {
     debugEvent("Import");
-    pop(NullValue.Prefix); // Prefix identifier
+    pop(NullValues.Prefix); // Prefix identifier
     pop(); // URI
     pop(); // Metadata
     pop(); // Comment
@@ -365,7 +365,7 @@
     debugEvent("MetadataStar");
     push(
         popList(count, List<Annotation?>.filled(count, null, growable: true)) ??
-            NullValue.Metadata);
+            NullValues.Metadata);
   }
 
   @override
@@ -453,7 +453,7 @@
   @override
   void handleFunctionBodySkipped(Token token, bool isExpressionBody) {
     if (isExpressionBody) pop();
-    push(NullValue.FunctionBody);
+    push(NullValues.FunctionBody);
   }
 
   @override
@@ -476,7 +476,7 @@
   @override
   void handleImportPrefix(Token? deferredKeyword, Token? asKeyword) {
     debugEvent("ImportPrefix");
-    pushIfNull(asKeyword, NullValue.Prefix);
+    pushIfNull(asKeyword, NullValues.Prefix);
   }
 
   @override
@@ -494,7 +494,7 @@
   @override
   void handleInvalidTypeArguments(Token token) {
     debugEvent("InvalidTypeArguments");
-    pop(NullValue.TypeArguments);
+    pop(NullValues.TypeArguments);
   }
 
   @override
@@ -559,7 +559,7 @@
   @override
   void handleNativeFunctionBodySkipped(Token nativeToken, Token semicolon) {
     debugEvent("NativeFunctionBodySkipped");
-    push(NullValue.FunctionBody);
+    push(NullValues.FunctionBody);
   }
 
   @override
@@ -588,7 +588,7 @@
   @override
   void handleRecoverImport(Token? semicolon) {
     debugEvent("RecoverImport");
-    pop(NullValue.Prefix); // Prefix identifier
+    pop(NullValues.Prefix); // Prefix identifier
   }
 
   @override
diff --git a/dds_service_extensions/BUILD.gn b/dds_service_extensions/BUILD.gn
index 508ef72..efac5e2 100644
--- a/dds_service_extensions/BUILD.gn
+++ b/dds_service_extensions/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by package_importer.py for dds_service_extensions-1.3.2
+# This file is generated by package_importer.py for dds_service_extensions-1.3.3
 
 import("//build/dart/dart_library.gni")
 
diff --git a/dds_service_extensions/CHANGELOG.md b/dds_service_extensions/CHANGELOG.md
index 5269ecb..702bd28 100644
--- a/dds_service_extensions/CHANGELOG.md
+++ b/dds_service_extensions/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.3.3
+
+- Updated `vm_service` version to ^11.0.0.
+
 ## 1.3.2
 
 - Updated `vm_service` version to ^10.0.0.
diff --git a/dds_service_extensions/pubspec.yaml b/dds_service_extensions/pubspec.yaml
index 6735107..c400e97 100644
--- a/dds_service_extensions/pubspec.yaml
+++ b/dds_service_extensions/pubspec.yaml
@@ -1,5 +1,5 @@
 name: dds_service_extensions
-version: 1.3.2
+version: 1.3.3
 description: >-
   Extension methods for `package:vm_service`, used to make requests a
   Dart Development Service (DDS) instance.
@@ -10,7 +10,7 @@
 
 dependencies:
   async: ^2.4.1
-  vm_service: ^10.0.0
+  vm_service: ^11.0.0
 
 # We use 'any' version constraints here as we get our package versions from
 # the dart-lang/sdk repo's DEPS file. Note that this is a special case; the
diff --git a/devtools_shared/BUILD.gn b/devtools_shared/BUILD.gn
index 1fe3493..c200000 100644
--- a/devtools_shared/BUILD.gn
+++ b/devtools_shared/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by package_importer.py for devtools_shared-2.21.0-dev.0
+# This file is generated by package_importer.py for devtools_shared-2.21.1
 
 import("//build/dart/dart_library.gni")
 
diff --git a/devtools_shared/pubspec.yaml b/devtools_shared/pubspec.yaml
index a88b8b6..49621db 100644
--- a/devtools_shared/pubspec.yaml
+++ b/devtools_shared/pubspec.yaml
@@ -1,7 +1,7 @@
 name: devtools_shared
 description: Package of shared structures between devtools_app, dds, and other tools.
 
-version: 2.21.0-dev.0
+version: 2.21.1
 
 repository: https://github.com/flutter/devtools/tree/master/packages/devtools_shared
 
@@ -12,7 +12,7 @@
   path: ^1.8.0
   shelf: ^1.1.0
   usage: ^4.0.0
-  vm_service: '>=9.0.0 <11.0.0'
+  vm_service: ">=10.1.0 <12.0.0"
   webkit_inspection_protocol: '>=0.5.0 <2.0.0'
 
 dev_dependencies:
diff --git a/vm_service/BUILD.gn b/vm_service/BUILD.gn
index 63e8a02..3d8614e 100644
--- a/vm_service/BUILD.gn
+++ b/vm_service/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by package_importer.py for vm_service-10.1.2
+# This file is generated by package_importer.py for vm_service-11.0.1
 
 import("//build/dart/dart_library.gni")
 
diff --git a/vm_service/CHANGELOG.md b/vm_service/CHANGELOG.md
index ca4237d..e40cded 100644
--- a/vm_service/CHANGELOG.md
+++ b/vm_service/CHANGELOG.md
@@ -1,5 +1,14 @@
 # Changelog
 
+## 11.0.1
+- Fix bug where code would try to call `.toJson()` on `int`s.
+
+## 11.0.0
+- Change `HttpProfileRequestRef.id` type from `int` to `String`.
+- Change `SocketStatistic.id` type from `int` to `String`.
+- Change `ext.dart.io.getHttpProfileRequest` `id` parameter type from `int` to `String`.
+- Change `ext.dart.io.socketProfilingEnabled` parameter from 'enable' to 'enabled'.
+
 ## 10.1.2
 - Fix bug where code would try to call `.toJson()` on `String`s.
 
diff --git a/vm_service/lib/src/dart_io_extensions.dart b/vm_service/lib/src/dart_io_extensions.dart
index a33ff29..7759466 100644
--- a/vm_service/lib/src/dart_io_extensions.dart
+++ b/vm_service/lib/src/dart_io_extensions.dart
@@ -77,9 +77,10 @@
   /// Warning: The returned [Future] will not complete if the target isolate is paused
   /// and will only complete when the isolate is resumed.
   @Deprecated('Use httpEnableTimelineLogging instead.')
-  Future<Success> setHttpEnableTimelineLogging(String isolateId, bool enable) =>
+  Future<Success> setHttpEnableTimelineLogging(
+          String isolateId, bool enabled) =>
       _callHelper('ext.dart.io.setHttpEnableTimelineLogging', isolateId, args: {
-        'enable': enable,
+        'enabled': enabled,
       });
 
   /// The `httpEnableTimelineLogging` RPC is used to set and inspect the value of
@@ -119,7 +120,8 @@
 
   /// The `getHttpProfileRequest` RPC is used to retrieve an instance of
   /// [HttpProfileRequest], which includes request and response body data.
-  Future<HttpProfileRequest> getHttpProfileRequest(String isolateId, int id) =>
+  Future<HttpProfileRequest> getHttpProfileRequest(
+          String isolateId, String id) =>
       _callHelper('ext.dart.io.getHttpProfileRequest', isolateId, args: {
         'id': id,
       });
@@ -205,7 +207,7 @@
       json == null ? null : SocketStatistic._fromJson(json);
 
   /// The unique ID associated with this socket.
-  final int id;
+  final String id;
 
   /// The time, in microseconds, that this socket was created.
   final int startTime;
@@ -364,7 +366,7 @@
   /// The ID associated with this request.
   ///
   /// This ID corresponds to the ID of the timeline event for this request.
-  final int id;
+  final String id;
 
   /// The HTTP request method associated with this request.
   final String method;
@@ -411,7 +413,7 @@
         super._fromJson(json);
 
   HttpProfileRequest({
-    required int id,
+    required String id,
     required String isolateId,
     required String method,
     required Uri uri,
diff --git a/vm_service/lib/src/vm_service.dart b/vm_service/lib/src/vm_service.dart
index 0c09d70..e3281a3 100644
--- a/vm_service/lib/src/vm_service.dart
+++ b/vm_service/lib/src/vm_service.dart
@@ -2976,7 +2976,7 @@
     json.addAll({
       'decl': decl?.toJson(),
       'name': name,
-      'value': value?.toJson(),
+      'value': value is int || value is String ? value : value?.toJson(),
     });
     return json;
   }
@@ -3040,7 +3040,7 @@
     json['type'] = type;
     json.addAll({
       'name': name ?? '',
-      'value': value?.toJson(),
+      'value': value is int || value is String ? value : value?.toJson(),
       'declarationTokenPos': declarationTokenPos ?? -1,
       'scopeStartTokenPos': scopeStartTokenPos ?? -1,
       'scopeEndTokenPos': scopeEndTokenPos ?? -1,
@@ -3114,7 +3114,8 @@
       'breakpointNumber': breakpointNumber ?? -1,
       'enabled': enabled ?? false,
       'resolved': resolved ?? false,
-      'location': location?.toJson(),
+      'location':
+          location is int || location is String ? location : location?.toJson(),
     });
     _setIfNotNull(
         json, 'isSyntheticAsyncContinuation', isSyntheticAsyncContinuation);
@@ -3653,7 +3654,7 @@
   Map<String, dynamic> toJson() {
     final json = <String, dynamic>{};
     json.addAll({
-      'value': value?.toJson(),
+      'value': value is int || value is String ? value : value?.toJson(),
     });
     return json;
   }
@@ -4538,7 +4539,12 @@
       'static': isStatic ?? false,
     });
     _setIfNotNull(json, 'location', location?.toJson());
-    _setIfNotNull(json, 'staticValue', staticValue?.toJson());
+    _setIfNotNull(
+        json,
+        'staticValue',
+        staticValue is int || staticValue is String
+            ? staticValue
+            : staticValue?.toJson());
     return json;
   }
 
@@ -4770,7 +4776,7 @@
     json['type'] = type;
     json.addAll({
       'name': name ?? '',
-      'owner': owner?.toJson(),
+      'owner': owner is int || owner is String ? owner : owner?.toJson(),
       'static': isStatic ?? false,
       'const': isConst ?? false,
       'implicit': implicit ?? false,
@@ -4872,7 +4878,7 @@
     json['type'] = type;
     json.addAll({
       'name': name ?? '',
-      'owner': owner?.toJson(),
+      'owner': owner is int || owner is String ? owner : owner?.toJson(),
       'static': isStatic ?? false,
       'const': isConst ?? false,
       'implicit': implicit ?? false,
@@ -6106,7 +6112,12 @@
       'source': source?.toJson(),
     });
     _setIfNotNull(json, 'parentListIndex', parentListIndex);
-    _setIfNotNull(json, 'parentField', parentField?.toJson());
+    _setIfNotNull(
+        json,
+        'parentField',
+        parentField is int || parentField is String
+            ? parentField
+            : parentField?.toJson());
     return json;
   }
 
@@ -6462,8 +6473,8 @@
   Map<String, dynamic> toJson() {
     final json = <String, dynamic>{};
     json.addAll({
-      'key': key?.toJson(),
-      'value': value?.toJson(),
+      'key': key is int || key is String ? key : key?.toJson(),
+      'value': value is int || value is String ? value : value?.toJson(),
     });
     return json;
   }
diff --git a/vm_service/pubspec.yaml b/vm_service/pubspec.yaml
index 034d8fc..794c07f 100644
--- a/vm_service/pubspec.yaml
+++ b/vm_service/pubspec.yaml
@@ -1,5 +1,5 @@
 name: vm_service
-version: 10.1.2
+version: 11.0.1
 description: >-
   A library to communicate with a service implementing the Dart VM
   service protocol.
@@ -24,7 +24,7 @@
   path: any
   pub_semver: any
   test_package: any
-  test: any
+  # test: any
 
 dependency_overrides:
   test_package:
diff --git a/vm_service/tool/dart/generate_dart.dart b/vm_service/tool/dart/generate_dart.dart
index ec06cf6..05571fa 100644
--- a/vm_service/tool/dart/generate_dart.dart
+++ b/vm_service/tool/dart/generate_dart.dart
@@ -1664,6 +1664,12 @@
         gen.write('.toJson()');
       }
       gen.write(').toList()');
+    } else if (field.type.isMultipleReturns) {
+      gen.write('''
+${field.generatableName} is int || ${field.generatableName} is String
+    ? ${field.generatableName}
+    : ${field.generatableName}?.toJson()
+''');
     } else {
       gen.write('${field.generatableName}?.toJson()');
     }