[_fe_analyzer_shared] Include errors in analysis result

This propagates information about reported error to the caller of
a shared type analysis. This is used to properly turn errors into
invalid expressions/patterns, as is normally done in the CFE in
face of errors.

Change-Id: Ibb8adedccb8314fabfe18ecaa3559e32ad7267ca
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/286145
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analysis_result.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analysis_result.dart
index 3560bd9..3e4f236 100644
--- a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analysis_result.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analysis_result.dart
@@ -160,8 +160,28 @@
   Type resolveShorting() => type;
 }
 
+/// Result for analyzing a switch expression in
+/// [TypeAnalyzer.analyzeSwitchExpression].
+class SwitchExpressionResult<Type extends Object, Error>
+    extends SimpleTypeAnalysisResult<Type> {
+  /// Errors for non-bool guards.
+  ///
+  /// The key is the case index of the erroneous guard.
+  ///
+  /// This is `null` if no such errors where found.
+  final Map<int, Error>? nonBooleanGuardErrors;
+
+  /// Error for when the switch statement was non exhaustive.
+  final Error? nonExhaustiveSwitchError;
+
+  SwitchExpressionResult(
+      {required super.type,
+      required this.nonBooleanGuardErrors,
+      required this.nonExhaustiveSwitchError});
+}
+
 /// Container for the result of running type analysis on an integer literal.
-class SwitchStatementTypeAnalysisResult<Type> {
+class SwitchStatementTypeAnalysisResult<Type extends Object, Error> {
   /// Whether the switch statement had a `default` clause.
   final bool hasDefault;
 
@@ -182,12 +202,30 @@
   /// The static type of the scrutinee expression.
   final Type scrutineeType;
 
+  /// Errors for the cases that don't complete normally.
+  ///
+  /// This is `null` if no such errors where found.
+  final Map<int, Error>? switchCaseCompletesNormallyErrors;
+
+  /// Errors for non-bool guards.
+  ///
+  /// The keys of the maps are case and head indices of the erroneous guard.
+  ///
+  /// This is `null` if no such errors where found.
+  final Map<int, Map<int, Error>>? nonBooleanGuardErrors;
+
+  /// Error for when the switch statement was non exhaustive.
+  final Error? nonExhaustiveSwitchError;
+
   SwitchStatementTypeAnalysisResult({
     required this.hasDefault,
     required this.isExhaustive,
     required this.lastCaseTerminates,
     required this.requiresExhaustivenessValidation,
     required this.scrutineeType,
+    required this.switchCaseCompletesNormallyErrors,
+    required this.nonBooleanGuardErrors,
+    required this.nonExhaustiveSwitchError,
   });
 }
 
@@ -202,3 +240,226 @@
   /// and can be removed.
   logicalAndPatternOperand,
 }
+
+/// Result for analyzing an assigned variable pattern in
+/// [TypeAnalyzer.analyzeAssignedVariablePattern].
+class AssignedVariablePatternResult<Error> {
+  /// Error for when a variable was assigned multiple times within a pattern.
+  final Error? duplicateAssignmentPatternVariableError;
+
+  /// Error for when the matched value type is not assignable to the variable
+  /// type in an irrefutable context.
+  final Error? patternTypeMismatchInIrrefutableContextError;
+
+  AssignedVariablePatternResult(
+      {required this.duplicateAssignmentPatternVariableError,
+      required this.patternTypeMismatchInIrrefutableContextError});
+}
+
+/// Result for analyzing an object pattern in
+/// [TypeAnalyzer.analyzeObjectPattern].
+class ObjectPatternResult<Type extends Object, Error> {
+  /// The required type of the object pattern.
+  final Type requiredType;
+
+  /// Errors for when the same property name was used multiple times in the
+  /// object pattern.
+  ///
+  /// The key is the index of the duplicate field within the object pattern.
+  ///
+  /// This is `null` if no such properties were found.
+  final Map<int, Error>? duplicateRecordPatternFieldErrors;
+
+  /// Error for when the matched value type is not assignable to the required
+  /// type in an irrefutable context.
+  final Error? patternTypeMismatchInIrrefutableContextError;
+
+  ObjectPatternResult(
+      {required this.requiredType,
+      required this.duplicateRecordPatternFieldErrors,
+      required this.patternTypeMismatchInIrrefutableContextError});
+}
+
+/// Result for analyzing a record pattern in
+/// [TypeAnalyzer.analyzeRecordPattern].
+class RecordPatternResult<Type extends Object, Error> {
+  /// The required type of the record pattern.
+  final Type requiredType;
+
+  /// Errors for when the same property name was used multiple times in the
+  /// record pattern.
+  ///
+  /// The key is the index of the duplicate field within the record pattern.
+  ///
+  /// This is `null` if no such errors where found.
+  final Map<int, Error>? duplicateRecordPatternFieldErrors;
+
+  /// Error for when the matched value type is not assignable to the required
+  /// type in an irrefutable context.
+  final Error? patternTypeMismatchInIrrefutableContextError;
+
+  RecordPatternResult(
+      {required this.requiredType,
+      required this.duplicateRecordPatternFieldErrors,
+      required this.patternTypeMismatchInIrrefutableContextError});
+}
+
+/// Result for analyzing a list pattern in [TypeAnalyzer.analyzeListPattern].
+class ListPatternResult<Type extends Object, Error> {
+  /// The required type of the list pattern.
+  final Type requiredType;
+
+  /// Errors for when multiple rest patterns occurred within the list pattern.
+  ///
+  /// The key is the index of the pattern within the list pattern.
+  ///
+  /// This is `null` if no such errors where found.
+  final Map<int, Error>? duplicateRestPatternErrors;
+
+  /// Error for when the matched value type is not assignable to the required
+  /// type in an irrefutable context.
+  final Error? patternTypeMismatchInIrrefutableContextError;
+
+  ListPatternResult(
+      {required this.requiredType,
+      required this.duplicateRestPatternErrors,
+      required this.patternTypeMismatchInIrrefutableContextError});
+}
+
+/// Result for analyzing a map pattern in [TypeAnalyzer.analyzeMapPattern].
+class MapPatternResult<Type extends Object, Error> {
+  /// The required type of the map pattern.
+  final Type requiredType;
+
+  /// Errors for when multiple rest patterns occurred within the map pattern.
+  ///
+  /// The key is the index of the pattern within the map pattern.
+  ///
+  /// This is `null` if no such errors where found.
+  final Map<int, Error>? duplicateRestPatternErrors;
+
+  /// Error for when the matched value type is not assignable to the required
+  /// type in an irrefutable context.
+  final Error? patternTypeMismatchInIrrefutableContextError;
+
+  MapPatternResult(
+      {required this.requiredType,
+      required this.duplicateRestPatternErrors,
+      required this.patternTypeMismatchInIrrefutableContextError});
+}
+
+/// Result for analyzing a constant pattern in
+/// [TypeAnalyzer.analyzeConstantPattern].
+class ConstantPatternResult<Type extends Object, Error> {
+  /// The static type of the constant expression.
+  final Type expressionType;
+
+  /// Error for when the pattern occurred in an irrefutable context.
+  final Error? refutablePatternInIrrefutableContextError;
+
+  /// Error for when the pattern, used as a case constant expression, does not
+  /// have a valid type wrt. the switch expression type.
+  final Error? caseExpressionTypeMismatchError;
+
+  ConstantPatternResult(
+      {required this.expressionType,
+      required this.refutablePatternInIrrefutableContextError,
+      required this.caseExpressionTypeMismatchError});
+}
+
+/// Result for analyzing a declared variable pattern in
+/// [TypeAnalyzer.analyzeDeclaredVariablePattern].
+class DeclaredVariablePatternResult<Type extends Object, Error> {
+  /// The static type of the variable.
+  final Type staticType;
+
+  /// Error for when the matched value type is not assignable to the static
+  /// type in an irrefutable context.
+  final Error? patternTypeMismatchInIrrefutableContextError;
+
+  DeclaredVariablePatternResult(
+      {required this.staticType,
+      required this.patternTypeMismatchInIrrefutableContextError});
+}
+
+/// Result for analyzing a logical or pattern in
+/// [TypeAnalyzer.analyzeLogicalOrPattern].
+class LogicalOrPatternResult<Error> {
+  /// Error for when the pattern occurred in an irrefutable context.
+  final Error? refutablePatternInIrrefutableContextError;
+
+  LogicalOrPatternResult(
+      {required this.refutablePatternInIrrefutableContextError});
+}
+
+/// Result for analyzing a relational pattern in
+/// [TypeAnalyzer.analyzeRelationalPattern].
+class RelationalPatternResult<Type extends Object, Error> {
+  /// The static type of the operand.
+  final Type operandType;
+
+  /// Error for when the pattern occurred in an irrefutable context.
+  final Error? refutablePatternInIrrefutableContextError;
+
+  /// Error for when the operand type is not assignable to the parameter type
+  /// of the relational operator.
+  final Error? argumentTypeNotAssignableError;
+
+  /// Error for when the relational operator does not return a bool.
+  final Error? operatorReturnTypeNotAssignableToBoolError;
+
+  RelationalPatternResult(
+      {required this.operandType,
+      required this.refutablePatternInIrrefutableContextError,
+      required this.argumentTypeNotAssignableError,
+      required this.operatorReturnTypeNotAssignableToBoolError});
+}
+
+/// Result for analyzing a null check or null assert pattern in
+/// [TypeAnalyzer.analyzeNullCheckOrAssertPattern].
+class NullCheckOrAssertPatternResult<Error> {
+  /// Error for when the pattern occurred in an irrefutable context.
+  final Error? refutablePatternInIrrefutableContextError;
+
+  /// Error for when the matched type is known to be non-null.
+  final Error? matchedTypeIsStrictlyNonNullableError;
+
+  NullCheckOrAssertPatternResult(
+      {required this.refutablePatternInIrrefutableContextError,
+      required this.matchedTypeIsStrictlyNonNullableError});
+}
+
+/// Result for analyzing a wildcard pattern
+/// [TypeAnalyzer.analyzeWildcardPattern].
+class WildcardPatternResult<Error> {
+  /// Error for when the matched value type is not assignable to the wildcard
+  /// type in an irrefutable context.
+  final Error? patternTypeMismatchInIrrefutableContextError;
+
+  WildcardPatternResult(
+      {required this.patternTypeMismatchInIrrefutableContextError});
+}
+
+/// Result for analyzing an if-case statement or element in
+/// [TypeAnalyzer.analyzeIfCaseStatement] and
+/// [TypeAnalyzer.analyzeIfCaseElement].
+class IfCaseStatementResult<Type extends Object, Error> {
+  /// The static type of the matched expression.
+  final Type matchedExpressionType;
+
+  /// Error for when the guard has a non-bool type.
+  final Error? nonBooleanGuardError;
+
+  IfCaseStatementResult(
+      {required this.matchedExpressionType,
+      required this.nonBooleanGuardError});
+}
+
+/// Result for analyzing a pattern-for-in statement or element in
+/// [TypeAnalyzer.analyzePatternForIn].
+class PatternForInResult<Error> {
+  /// Error for when the expression is not an iterable.
+  final Error? patternForInExpressionIsNotIterableError;
+
+  PatternForInResult({required this.patternForInExpressionIsNotIterableError});
+}
diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart
index 9e07327..5c2a74f 100644
--- a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart
@@ -280,7 +280,8 @@
     Expression extends Node,
     Variable extends Object,
     Type extends Object,
-    Pattern extends Node> {
+    Pattern extends Node,
+    Error> {
   /// Returns the type `bool`.
   Type get boolType;
 
@@ -290,8 +291,8 @@
   /// Returns the type `dynamic`.
   Type get dynamicType;
 
-  TypeAnalyzerErrors<Node, Statement, Expression, Variable, Type, Pattern>?
-      get errors;
+  TypeAnalyzerErrors<Node, Statement, Expression, Variable, Type, Pattern,
+      Error> get errors;
 
   /// Returns the type used by the client in the case of errors.
   Type get errorType;
@@ -319,23 +320,28 @@
   /// context.  [node] is the pattern itself, and [variable] is the variable
   /// being referenced.
   ///
+  /// Returns an [AssignedVariablePatternResult] with information about reported
+  /// errors.
+  ///
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// For wildcard patterns in an assignment context,
   /// [analyzeDeclaredVariablePattern] should be used instead.
   ///
   /// Stack effect: none.
-  void analyzeAssignedVariablePattern(
+  AssignedVariablePatternResult<Error> analyzeAssignedVariablePattern(
       MatchContext<Node, Expression, Pattern, Type, Variable> context,
       Pattern node,
       Variable variable) {
+    Error? duplicateAssignmentPatternVariableError;
     Map<Variable, Pattern>? assignedVariables = context.assignedVariables;
     if (assignedVariables != null) {
       Pattern? original = assignedVariables[variable];
       if (original == null) {
         assignedVariables[variable] = node;
       } else {
-        errors?.duplicateAssignmentPatternVariable(
+        duplicateAssignmentPatternVariableError =
+            errors.duplicateAssignmentPatternVariable(
           variable: variable,
           original: original,
           duplicate: node,
@@ -348,17 +354,24 @@
     assert(irrefutableContext != null,
         'Assigned variables must only appear in irrefutable pattern contexts');
     Type matchedType = flow.getMatchedValueType();
+    Error? patternTypeMismatchInIrrefutableContextError;
     if (irrefutableContext != null &&
         !operations.isAssignableTo(matchedType, variableDeclaredType)) {
-      errors?.patternTypeMismatchInIrrefutableContext(
-          pattern: node,
-          context: irrefutableContext,
-          matchedType: matchedType,
-          requiredType: variableDeclaredType);
+      patternTypeMismatchInIrrefutableContextError =
+          errors.patternTypeMismatchInIrrefutableContext(
+              pattern: node,
+              context: irrefutableContext,
+              matchedType: matchedType,
+              requiredType: variableDeclaredType);
     }
     flow.promoteForPattern(
         matchedType: matchedType, knownType: variableDeclaredType);
     flow.assignedVariablePattern(node, variable, matchedType);
+    return new AssignedVariablePatternResult(
+        duplicateAssignmentPatternVariableError:
+            duplicateAssignmentPatternVariableError,
+        patternTypeMismatchInIrrefutableContextError:
+            patternTypeMismatchInIrrefutableContextError);
   }
 
   /// Computes the type schema for a variable pattern appearing in an assignment
@@ -384,7 +397,7 @@
         knownType: requiredType,
         matchFailsIfWrongType: false);
     if (matchedTypeIsSubtypeOfRequired) {
-      errors?.matchedTypeIsSubtypeOfRequired(
+      errors.matchedTypeIsSubtypeOfRequired(
         pattern: pattern,
         matchedType: matchedValueType,
         requiredType: requiredType,
@@ -413,27 +426,29 @@
   ///
   /// See [dispatchPattern] for the meaning of [context].
   ///
-  /// Returns the static type of [expression].
+  /// Returns a [ConstantPatternResult] with the static type of [expression]
+  /// and information about reported errors.
   ///
   /// Stack effect: pushes (Expression).
-  Type analyzeConstantPattern(
+  ConstantPatternResult<Type, Error> analyzeConstantPattern(
       MatchContext<Node, Expression, Pattern, Type, Variable> context,
       Node node,
       Expression expression) {
     // Stack: ()
-    TypeAnalyzerErrors<Node, Node, Expression, Variable, Type, Pattern>?
-        errors = this.errors;
     Node? irrefutableContext = context.irrefutableContext;
+    Error? refutablePatternInIrrefutableContextError;
     if (irrefutableContext != null) {
-      errors?.refutablePatternInIrrefutableContext(
-          pattern: node, context: irrefutableContext);
+      refutablePatternInIrrefutableContextError =
+          errors.refutablePatternInIrrefutableContext(
+              pattern: node, context: irrefutableContext);
     }
     Type matchedType = flow.getMatchedValueType();
     Type expressionType = analyzeExpression(expression, matchedType);
     flow.constantPattern_end(expression, expressionType,
         patternsEnabled: options.patternsEnabled);
     // Stack: (Expression)
-    if (errors != null && !options.patternsEnabled) {
+    Error? caseExpressionTypeMismatchError;
+    if (!options.patternsEnabled) {
       Expression? switchScrutinee = context.switchScrutinee;
       if (switchScrutinee != null) {
         bool nullSafetyEnabled = options.nullSafetyEnabled;
@@ -441,7 +456,7 @@
             ? operations.isSubtypeOf(expressionType, matchedType)
             : operations.isAssignableTo(expressionType, matchedType);
         if (!matches) {
-          errors.caseExpressionTypeMismatch(
+          caseExpressionTypeMismatchError = errors.caseExpressionTypeMismatch(
               caseExpression: expression,
               scrutinee: switchScrutinee,
               caseExpressionType: expressionType,
@@ -450,7 +465,11 @@
         }
       }
     }
-    return expressionType;
+    return new ConstantPatternResult(
+        expressionType: expressionType,
+        refutablePatternInIrrefutableContextError:
+            refutablePatternInIrrefutableContextError,
+        caseExpressionTypeMismatchError: caseExpressionTypeMismatchError);
   }
 
   /// Computes the type schema for a constant pattern.
@@ -460,7 +479,7 @@
     // Constant patterns are only allowed in refutable contexts, and refutable
     // contexts don't propagate a type schema into the scrutinee.  So this
     // code path is only reachable if the user's code contains errors.
-    errors?.assertInErrorRecovery();
+    errors.assertInErrorRecovery();
     return unknownType;
   }
 
@@ -473,10 +492,11 @@
   ///
   /// See [dispatchPattern] for the meaning of [context].
   ///
-  /// Returns the static type of the variable (possibly inferred).
+  /// Returns a [DeclaredVariablePatternResult] with the static type of the
+  /// variable (possibly inferred) and information about reported errors.
   ///
   /// Stack effect: none.
-  Type analyzeDeclaredVariablePattern(
+  DeclaredVariablePatternResult<Type, Error> analyzeDeclaredVariablePattern(
     MatchContext<Node, Expression, Pattern, Type, Variable> context,
     Pattern node,
     Variable variable,
@@ -487,13 +507,15 @@
     Type staticType =
         declaredType ?? variableTypeFromInitializerType(matchedType);
     Node? irrefutableContext = context.irrefutableContext;
+    Error? patternTypeMismatchInIrrefutableContextError;
     if (irrefutableContext != null &&
         !operations.isAssignableTo(matchedType, staticType)) {
-      errors?.patternTypeMismatchInIrrefutableContext(
-          pattern: node,
-          context: irrefutableContext,
-          matchedType: matchedType,
-          requiredType: staticType);
+      patternTypeMismatchInIrrefutableContextError =
+          errors.patternTypeMismatchInIrrefutableContext(
+              pattern: node,
+              context: irrefutableContext,
+              matchedType: matchedType,
+              requiredType: staticType);
     }
     flow.promoteForPattern(matchedType: matchedType, knownType: staticType);
     bool isImplicitlyTyped = declaredType == null;
@@ -508,7 +530,10 @@
     setVariableType(variable, staticType);
     (context.componentVariables[variableName] ??= []).add(variable);
     flow.assignMatchedPatternVariable(variable, promotionKey);
-    return staticType;
+    return new DeclaredVariablePatternResult(
+        staticType: staticType,
+        patternTypeMismatchInIrrefutableContextError:
+            patternTypeMismatchInIrrefutableContextError);
   }
 
   /// Computes the type schema for a variable pattern in a non-assignment
@@ -550,12 +575,15 @@
   /// wishes to use to represent that variable.  This is used to join together
   /// variables that appear in different branches of logical-or patterns.
   ///
+  /// Returns a [IfCaseStatementResult] with the static type of [expression] and
+  /// information about reported errors.
+  ///
   /// 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
   /// [handleNoCollectionElement].  If there is no guard, the representation
   /// for `guard` will be pushed by [handleNoGuard].
-  void analyzeIfCaseElement({
+  IfCaseStatementResult<Type, Error> analyzeIfCaseElement({
     required Node node,
     required Expression expression,
     required Pattern pattern,
@@ -585,14 +613,19 @@
     _finishJoinedPatternVariables(
         variables, componentVariables, patternVariablePromotionKeys,
         location: JoinedPatternVariableLocation.singlePattern);
+    Error? nonBooleanGuardError;
     if (guard != null) {
-      _checkGuardType(guard, analyzeExpression(guard, boolType));
+      nonBooleanGuardError =
+          _checkGuardType(guard, analyzeExpression(guard, boolType));
     } else {
       handleNoGuard(node, 0);
     }
     // Stack: (Expression, Pattern, Guard)
     flow.ifCaseStatement_thenBegin(guard);
     _analyzeIfElementCommon(node, ifTrue, ifFalse, context);
+    return new IfCaseStatementResult(
+        matchedExpressionType: initializerType,
+        nonBooleanGuardError: nonBooleanGuardError);
   }
 
   /// Analyzes a statement of the form `if (expression case pattern) ifTrue` or
@@ -602,14 +635,15 @@
   /// the expression, [pattern] for the pattern to match, [ifTrue] for the
   /// "then" branch, and [ifFalse] for the "else" branch (if present).
   ///
-  /// Returns the static type of [expression].
+  /// Returns a [IfCaseStatementResult] with the static type of [expression] and
+  /// information about reported errors.
   ///
   /// Stack effect: pushes (Expression scrutinee, Pattern, Expression guard,
   /// Statement ifTrue, Statement ifFalse).  If there is no `else` clause, the
   /// representation for `ifFalse` will be pushed by [handleNoStatement].  If
   /// there is no guard, the representation for `guard` will be pushed by
   /// [handleNoGuard].
-  Type analyzeIfCaseStatement(
+  IfCaseStatementResult<Type, Error> analyzeIfCaseStatement(
     Statement node,
     Expression expression,
     Pattern pattern,
@@ -644,15 +678,19 @@
 
     handle_ifCaseStatement_afterPattern(node: node);
     // Stack: (Expression, Pattern)
+    Error? nonBooleanGuardError;
     if (guard != null) {
-      _checkGuardType(guard, analyzeExpression(guard, boolType));
+      nonBooleanGuardError =
+          _checkGuardType(guard, analyzeExpression(guard, boolType));
     } else {
       handleNoGuard(node, 0);
     }
     // Stack: (Expression, Pattern, Guard)
     flow.ifCaseStatement_thenBegin(guard);
     _analyzeIfCommon(node, ifTrue, ifFalse);
-    return initializerType;
+    return new IfCaseStatementResult(
+        matchedExpressionType: initializerType,
+        nonBooleanGuardError: nonBooleanGuardError);
   }
 
   /// Analyzes a collection element of the form `if (condition) ifTrue` or
@@ -718,10 +756,13 @@
   /// the list element type (if explicitly supplied), and [elements] is the
   /// list of subpatterns.
   ///
+  /// Returns a [ListPatternResult] with the required type and information about
+  /// reported errors.
+  ///
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (n * Pattern) where n = elements.length.
-  Type analyzeListPattern(
+  ListPatternResult<Type, Error> analyzeListPattern(
       MatchContext<Node, Expression, Pattern, Type, Variable> context,
       Pattern node,
       {Type? elementType,
@@ -747,10 +788,12 @@
         matchMayFailEvenIfCorrectType: true);
     // Stack: ()
     Node? previousRestPattern;
-    for (Node element in elements) {
+    Map<int, Error>? duplicateRestPatternErrors;
+    for (int i = 0; i < elements.length; i++) {
+      Node element = elements[i];
       if (isRestPatternElement(element)) {
         if (previousRestPattern != null) {
-          errors?.duplicateRestPattern(
+          (duplicateRestPatternErrors ??= {})[i] = errors.duplicateRestPattern(
             mapOrListPattern: node,
             original: previousRestPattern,
             duplicate: element,
@@ -774,15 +817,21 @@
     }
     // Stack: (n * Pattern) where n = elements.length
     Node? irrefutableContext = context.irrefutableContext;
+    Error? patternTypeMismatchInIrrefutableContextError;
     if (irrefutableContext != null &&
         !operations.isAssignableTo(matchedType, requiredType)) {
-      errors?.patternTypeMismatchInIrrefutableContext(
-          pattern: node,
-          context: irrefutableContext,
-          matchedType: matchedType,
-          requiredType: requiredType);
+      patternTypeMismatchInIrrefutableContextError =
+          errors.patternTypeMismatchInIrrefutableContext(
+              pattern: node,
+              context: irrefutableContext,
+              matchedType: matchedType,
+              requiredType: requiredType);
     }
-    return requiredType;
+    return new ListPatternResult(
+        requiredType: requiredType,
+        duplicateRestPatternErrors: duplicateRestPatternErrors,
+        patternTypeMismatchInIrrefutableContextError:
+            patternTypeMismatchInIrrefutableContextError);
   }
 
   /// Computes the type schema for a list pattern.  [elementType] is the list
@@ -866,18 +915,22 @@
   /// Analyzes a logical-or pattern.  [node] is the pattern itself, and [lhs]
   /// and [rhs] are the left and right sides of the `||` operator.
   ///
+  /// Returns a [LogicalOrPatternResult] with information about reported errors.
+  ///
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (Pattern left, Pattern right)
-  void analyzeLogicalOrPattern(
+  LogicalOrPatternResult<Error> analyzeLogicalOrPattern(
       MatchContext<Node, Expression, Pattern, Type, Variable> context,
       Pattern node,
       Node lhs,
       Node rhs) {
     Node? irrefutableContext = context.irrefutableContext;
+    Error? refutablePatternInIrrefutableContextError;
     if (irrefutableContext != null) {
-      errors?.refutablePatternInIrrefutableContext(
-          pattern: node, context: irrefutableContext);
+      refutablePatternInIrrefutableContextError =
+          errors.refutablePatternInIrrefutableContext(
+              pattern: node, context: irrefutableContext);
       // Avoid cascading errors
       context = context.makeRefutable();
     }
@@ -933,6 +986,9 @@
     // flow control branches, the normal join process will combine promotions
     // accordingly.
     flow.logicalOrPattern_end();
+    return new LogicalOrPatternResult(
+        refutablePatternInIrrefutableContextError:
+            refutablePatternInIrrefutableContextError);
   }
 
   /// Computes the type schema for a logical-or pattern.  [lhs] and [rhs] are
@@ -943,7 +999,7 @@
     // Logical-or patterns are only allowed in refutable contexts, and
     // refutable contexts don't propagate a type schema into the scrutinee.
     // So this code path is only reachable if the user's code contains errors.
-    errors?.assertInErrorRecovery();
+    errors.assertInErrorRecovery();
     return unknownType;
   }
 
@@ -951,10 +1007,13 @@
   /// contain explicit type arguments (if specified), and [elements] is the
   /// list of subpatterns.
   ///
+  /// Returns a [MapPatternResult] with the required type and information about
+  /// reported errors.
+  ///
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (n * MapPatternElement) where n = elements.length.
-  Type analyzeMapPattern(
+  MapPatternResult<Type, Error> analyzeMapPattern(
     MatchContext<Node, Expression, Pattern, Type, Variable> context,
     Pattern node, {
     required MapPatternTypeArguments<Type>? typeArguments,
@@ -996,10 +1055,12 @@
 
     bool hasDuplicateRestPatternReported = false;
     Node? previousRestPattern;
-    for (Node element in elements) {
+    Map<int, Error>? duplicateRestPatternErrors;
+    for (int i = 0; i < elements.length; i++) {
+      Node element = elements[i];
       if (isRestPatternElement(element)) {
         if (previousRestPattern != null) {
-          errors?.duplicateRestPattern(
+          (duplicateRestPatternErrors ??= {})[i] = errors.duplicateRestPattern(
             mapOrListPattern: node,
             original: previousRestPattern,
             duplicate: element,
@@ -1026,12 +1087,12 @@
         assert(isRestPatternElement(element));
         if (!hasDuplicateRestPatternReported) {
           if (i != elements.length - 1) {
-            errors?.restPatternNotLastInMap(node: node, element: element);
+            errors.restPatternNotLastInMap(node: node, element: element);
           }
         }
         Pattern? subPattern = getRestPatternElementPattern(element);
         if (subPattern != null) {
-          errors?.restPatternWithSubPatternInMap(node: node, element: element);
+          errors.restPatternWithSubPatternInMap(node: node, element: element);
           flow.pushSubpattern(dynamicType);
           dispatchPattern(
             context.withUnnecessaryWildcardKind(null),
@@ -1044,16 +1105,22 @@
     }
     // Stack: (n * MapPatternElement) where n = elements.length
     Node? irrefutableContext = context.irrefutableContext;
+    Error? patternTypeMismatchInIrrefutableContextError;
     if (irrefutableContext != null &&
         !operations.isAssignableTo(matchedType, requiredType)) {
-      errors?.patternTypeMismatchInIrrefutableContext(
+      patternTypeMismatchInIrrefutableContextError =
+          errors.patternTypeMismatchInIrrefutableContext(
         pattern: node,
         context: irrefutableContext,
         matchedType: matchedType,
         requiredType: requiredType,
       );
     }
-    return requiredType;
+    return new MapPatternResult(
+        requiredType: requiredType,
+        duplicateRestPatternErrors: duplicateRestPatternErrors,
+        patternTypeMismatchInIrrefutableContextError:
+            patternTypeMismatchInIrrefutableContextError);
   }
 
   /// Computes the type schema for a map pattern.  [typeArguments] contain
@@ -1094,25 +1161,32 @@
   /// itself, [innerPattern] is the sub-pattern, and [isAssert] indicates
   /// whether this is a null-check or a null-assert pattern.
   ///
+  /// Returns a [NullCheckOrAssertPatternResult] with information about
+  /// reported errors.
+  ///
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (Pattern innerPattern).
-  void analyzeNullCheckOrAssertPattern(
+  NullCheckOrAssertPatternResult<Error> analyzeNullCheckOrAssertPattern(
       MatchContext<Node, Expression, Pattern, Type, Variable> context,
       Pattern node,
       Pattern innerPattern,
       {required bool isAssert}) {
     // Stack: ()
+    Error? refutablePatternInIrrefutableContextError;
+    Error? matchedTypeIsStrictlyNonNullableError;
     Node? irrefutableContext = context.irrefutableContext;
     bool matchedTypeIsStrictlyNonNullable =
         flow.nullCheckOrAssertPattern_begin(isAssert: isAssert);
     if (irrefutableContext != null && !isAssert) {
-      errors?.refutablePatternInIrrefutableContext(
-          pattern: node, context: irrefutableContext);
+      refutablePatternInIrrefutableContextError =
+          errors.refutablePatternInIrrefutableContext(
+              pattern: node, context: irrefutableContext);
       // Avoid cascading errors
       context = context.makeRefutable();
     } else if (matchedTypeIsStrictlyNonNullable) {
-      errors?.matchedTypeIsStrictlyNonNullable(
+      matchedTypeIsStrictlyNonNullableError =
+          errors.matchedTypeIsStrictlyNonNullable(
         pattern: node,
         matchedType: flow.getMatchedValueType(),
       );
@@ -1123,6 +1197,12 @@
     );
     // Stack: (Pattern)
     flow.nullCheckOrAssertPattern_end();
+
+    return new NullCheckOrAssertPatternResult(
+        refutablePatternInIrrefutableContextError:
+            refutablePatternInIrrefutableContextError,
+        matchedTypeIsStrictlyNonNullableError:
+            matchedTypeIsStrictlyNonNullableError);
   }
 
   /// Computes the type schema for a null-check or null-assert pattern.
@@ -1138,7 +1218,7 @@
       // Null-check patterns are only allowed in refutable contexts, and
       // refutable contexts don't propagate a type schema into the scrutinee.
       // So this code path is only reachable if the user's code contains errors.
-      errors?.assertInErrorRecovery();
+      errors.assertInErrorRecovery();
       return unknownType;
     }
   }
@@ -1148,15 +1228,19 @@
   /// irrefutable contexts, but can be `null` in refutable contexts, then
   /// [downwardInferObjectPatternRequiredType] is invoked to infer the type.
   ///
+  /// Returns a [ObjectPatternResult] with the required type and information
+  /// about reported errors.
+  ///
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (n * Pattern) where n = fields.length.
-  Type analyzeObjectPattern(
+  ObjectPatternResult<Type, Error> analyzeObjectPattern(
     MatchContext<Node, Expression, Pattern, Type, Variable> context,
     Pattern node, {
     required List<RecordPatternField<Node, Pattern>> fields,
   }) {
-    _reportDuplicateRecordPatternFields(node, fields);
+    Map<int, Error>? duplicateRecordPatternFieldErrors =
+        _reportDuplicateRecordPatternFields(node, fields);
 
     Type matchedType = flow.getMatchedValueType();
     Type requiredType = downwardInferObjectPatternRequiredType(
@@ -1174,9 +1258,11 @@
     }
 
     Node? irrefutableContext = context.irrefutableContext;
+    Error? patternTypeMismatchInIrrefutableContextError;
     if (irrefutableContext != null &&
         !operations.isAssignableTo(matchedType, requiredType)) {
-      errors?.patternTypeMismatchInIrrefutableContext(
+      patternTypeMismatchInIrrefutableContextError =
+          errors.patternTypeMismatchInIrrefutableContext(
         pattern: node,
         context: irrefutableContext,
         matchedType: matchedType,
@@ -1200,7 +1286,11 @@
     }
     // Stack: (n * Pattern) where n = fields.length
 
-    return requiredType;
+    return new ObjectPatternResult(
+        requiredType: requiredType,
+        duplicateRecordPatternFieldErrors: duplicateRecordPatternFieldErrors,
+        patternTypeMismatchInIrrefutableContextError:
+            patternTypeMismatchInIrrefutableContextError);
   }
 
   /// Computes the type schema for an object pattern.  [type] is the type
@@ -1239,7 +1329,7 @@
     if (componentVariables.isNotEmpty) {
       // Declared pattern variables should never appear in a pattern assignment
       // so this should never happen.
-      errors?.assertInErrorRecovery();
+      errors.assertInErrorRecovery();
     }
     flow.patternAssignment_end();
     // Stack: (Expression, Pattern)
@@ -1258,7 +1348,9 @@
   /// `for (<keyword> <pattern> in <expression>) <body>`
   ///
   /// Stack effect: pushes (Expression, Pattern).
-  void analyzePatternForIn({
+  ///
+  /// Returns a [PatternForInResult] containing information on reported errors.
+  PatternForInResult<Error> analyzePatternForIn({
     required Node node,
     required bool hasAwait,
     required Pattern pattern,
@@ -1273,6 +1365,7 @@
     Type expressionType = analyzeExpression(expression, expressionTypeSchema);
     // Stack: (Expression)
 
+    Error? patternForInExpressionIsNotIterableError;
     Type? elementType = hasAwait
         ? operations.matchStreamType(expressionType)
         : operations.matchIterableType(expressionType);
@@ -1280,7 +1373,8 @@
       if (operations.isDynamic(expressionType)) {
         elementType = dynamicType;
       } else {
-        errors?.patternForInExpressionIsNotIterable(
+        patternForInExpressionIsNotIterableError =
+            errors.patternForInExpressionIsNotIterable(
           node: node,
           expression: expression,
           expressionType: expressionType,
@@ -1307,6 +1401,10 @@
     dispatchBody();
     flow.forEach_end();
     flow.patternForIn_end();
+
+    return new PatternForInResult(
+        patternForInExpressionIsNotIterableError:
+            patternForInExpressionIsNotIterableError);
   }
 
   /// Analyzes a patternVariableDeclaration node of the form
@@ -1329,7 +1427,7 @@
       {required bool isFinal, required bool isLate}) {
     // Stack: ()
     if (isLate && !isVariablePattern(pattern)) {
-      errors?.patternDoesNotAllowLate(pattern: pattern);
+      errors.patternDoesNotAllowLate(pattern: pattern);
     }
     if (isLate) {
       flow.lateInitializer_begin(node);
@@ -1365,10 +1463,13 @@
   /// Analyzes a record pattern.  [node] is the pattern itself, and [fields]
   /// is the list of subpatterns.
   ///
+  /// Returns a [RecordPatternResult] with the required type and information
+  /// about reported errors.
+  ///
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (n * Pattern) where n = fields.length.
-  Type analyzeRecordPattern(
+  RecordPatternResult<Type, Error> analyzeRecordPattern(
     MatchContext<Node, Expression, Pattern, Type, Variable> context,
     Pattern node, {
     required List<RecordPatternField<Node, Pattern>> fields,
@@ -1400,7 +1501,8 @@
       }
     }
 
-    _reportDuplicateRecordPatternFields(node, fields);
+    Map<int, Error>? duplicateRecordPatternFieldErrors =
+        _reportDuplicateRecordPatternFields(node, fields);
 
     // Build the required type.
     int requiredTypePositionalCount = 0;
@@ -1445,9 +1547,11 @@
     // Stack: (n * Pattern) where n = fields.length
 
     Node? irrefutableContext = context.irrefutableContext;
+    Error? patternTypeMismatchInIrrefutableContextError;
     if (irrefutableContext != null &&
         !operations.isAssignableTo(matchedType, requiredType)) {
-      errors?.patternTypeMismatchInIrrefutableContext(
+      patternTypeMismatchInIrrefutableContextError =
+          errors.patternTypeMismatchInIrrefutableContext(
         pattern: node,
         context: irrefutableContext,
         matchedType: matchedType,
@@ -1461,7 +1565,11 @@
         matchedType: matchedType,
         knownType: demonstratedType,
         matchFailsIfWrongType: false);
-    return requiredType;
+    return new RecordPatternResult(
+        requiredType: requiredType,
+        duplicateRecordPatternFieldErrors: duplicateRecordPatternFieldErrors,
+        patternTypeMismatchInIrrefutableContextError:
+            patternTypeMismatchInIrrefutableContextError);
   }
 
   /// Computes the type schema for a record pattern.
@@ -1491,22 +1599,23 @@
   /// This method will invoke [resolveRelationalPatternOperator] to obtain
   /// information about the operator.
   ///
-  /// Returns the type of the [operand].
+  /// Returns a [RelationalPatternResult] with the type of the [operand] and
+  /// information about reported errors.
   ///
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: pushes (Expression).
-  Type analyzeRelationalPattern(
+  RelationalPatternResult<Type, Error> analyzeRelationalPattern(
       MatchContext<Node, Expression, Pattern, Type, Variable> context,
       Pattern node,
       Expression operand) {
     // Stack: ()
-    TypeAnalyzerErrors<Node, Node, Expression, Variable, Type, Pattern>?
-        errors = this.errors;
+    Error? refutablePatternInIrrefutableContextError;
     Node? irrefutableContext = context.irrefutableContext;
     if (irrefutableContext != null) {
-      errors?.refutablePatternInIrrefutableContext(
-          pattern: node, context: irrefutableContext);
+      refutablePatternInIrrefutableContextError =
+          errors.refutablePatternInIrrefutableContext(
+              pattern: node, context: irrefutableContext);
     }
     Type matchedValueType = flow.getMatchedValueType();
     RelationalOperatorResolution<Type>? operator =
@@ -1531,26 +1640,33 @@
         break;
     }
     // Stack: (Expression)
-    if (errors != null && operator != null) {
+    Error? argumentTypeNotAssignableError;
+    Error? operatorReturnTypeNotAssignableToBoolError;
+    if (operator != null) {
       Type argumentType =
           isEquality ? operations.promoteToNonNull(operandType) : operandType;
       if (!operations.isAssignableTo(argumentType, operator.parameterType)) {
-        errors.argumentTypeNotAssignable(
+        argumentTypeNotAssignableError = errors.argumentTypeNotAssignable(
           argument: operand,
           argumentType: argumentType,
           parameterType: operator.parameterType,
         );
       }
       if (!operations.isAssignableTo(operator.returnType, boolType)) {
-        errors.relationalPatternOperatorReturnTypeNotAssignableToBool(
+        operatorReturnTypeNotAssignableToBoolError =
+            errors.relationalPatternOperatorReturnTypeNotAssignableToBool(
           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;
+    return new RelationalPatternResult(
+        operandType: operandType,
+        refutablePatternInIrrefutableContextError:
+            refutablePatternInIrrefutableContextError,
+        operatorReturnTypeNotAssignableToBoolError:
+            operatorReturnTypeNotAssignableToBoolError,
+        argumentTypeNotAssignableError: argumentTypeNotAssignableError);
   }
 
   /// Computes the type schema for a relational pattern.
@@ -1560,15 +1676,18 @@
     // Relational patterns are only allowed in refutable contexts, and refutable
     // contexts don't propagate a type schema into the scrutinee.  So this
     // code path is only reachable if the user's code contains errors.
-    errors?.assertInErrorRecovery();
+    errors.assertInErrorRecovery();
     return unknownType;
   }
 
   /// Analyzes an expression of the form `switch (expression) { cases }`.
   ///
+  /// Returns a [SwitchExpressionResult] with the static type of the switch
+  /// expression and information about reported errors.
+  ///
   /// Stack effect: pushes (Expression, n * ExpressionCase), where n is the
   /// number of cases.
-  SimpleTypeAnalysisResult<Type> analyzeSwitchExpression(
+  SwitchExpressionResult<Type, Error> analyzeSwitchExpression(
       Expression node, Expression scrutinee, int numCases, Type context) {
     // Stack: ()
     Type expressionType = analyzeExpression(scrutinee, unknownType);
@@ -1576,6 +1695,7 @@
     handleSwitchScrutinee(expressionType);
     flow.switchStatement_expressionEnd(null, scrutinee, expressionType);
     Type? lubType;
+    Map<int, Error>? nonBooleanGuardErrors;
     for (int i = 0; i < numCases; i++) {
       // Stack: (Expression, i * ExpressionCase)
       SwitchExpressionMemberInfo<Node, Expression, Variable> memberInfo =
@@ -1607,7 +1727,11 @@
         guard = memberInfo.head.guard;
         bool hasGuard = guard != null;
         if (hasGuard) {
-          _checkGuardType(guard, analyzeExpression(guard, boolType));
+          Error? nonBooleanGuardError =
+              _checkGuardType(guard, analyzeExpression(guard, boolType));
+          if (nonBooleanGuardError != null) {
+            (nonBooleanGuardErrors ??= {})[i] = nonBooleanGuardError;
+          }
           // Stack: (Expression, i * ExpressionCase, Pattern, Expression)
         } else {
           handleNoGuard(node, i);
@@ -1633,20 +1757,25 @@
     }
     lubType ??= dynamicType;
     // Stack: (Expression, numCases * ExpressionCase)
+    Error? nonExhaustiveSwitchError;
     bool isProvenExhaustive = flow.switchStatement_end(true);
     if (options.errorOnSwitchExhaustiveness &&
         !isProvenExhaustive &&
         !isLegacySwitchExhaustive(node, expressionType)) {
-      errors?.nonExhaustiveSwitch(node: node, scrutineeType: expressionType);
+      nonExhaustiveSwitchError =
+          errors.nonExhaustiveSwitch(node: node, scrutineeType: expressionType);
     }
-    return new SimpleTypeAnalysisResult<Type>(type: lubType);
+    return new SwitchExpressionResult(
+        type: lubType,
+        nonBooleanGuardErrors: nonBooleanGuardErrors,
+        nonExhaustiveSwitchError: nonExhaustiveSwitchError);
   }
 
   /// Analyzes a statement of the form `switch (expression) { cases }`.
   ///
   /// Stack effect: pushes (Expression, n * StatementCase), where n is the
   /// number of cases after merging together cases that share a body.
-  SwitchStatementTypeAnalysisResult<Type> analyzeSwitchStatement(
+  SwitchStatementTypeAnalysisResult<Type, Error> analyzeSwitchStatement(
       Statement node, Expression scrutinee, final int numCases) {
     // Stack: ()
     Type scrutineeType = analyzeExpression(scrutinee, unknownType);
@@ -1655,6 +1784,8 @@
     flow.switchStatement_expressionEnd(node, scrutinee, scrutineeType);
     bool hasDefault = false;
     bool lastCaseTerminates = true;
+    Map<int, Error>? switchCaseCompletesNormallyErrors;
+    Map<int, Map<int, Error>>? nonBooleanGuardErrors;
     for (int caseIndex = 0; caseIndex < numCases; caseIndex++) {
       // Stack: (Expression, numExecutionPaths * StatementCase)
       flow.switchStatement_beginAlternatives();
@@ -1694,7 +1825,12 @@
           //         numHeads * CaseHead, Pattern),
           guard = head.guard;
           if (guard != null) {
-            _checkGuardType(guard, analyzeExpression(guard, boolType));
+            Error? nonBooleanGuardError =
+                _checkGuardType(guard, analyzeExpression(guard, boolType));
+            if (nonBooleanGuardError != null) {
+              ((nonBooleanGuardErrors ??= {})[caseIndex] ??= {})[headIndex] =
+                  nonBooleanGuardError;
+            }
             // Stack: (Expression, numExecutionPaths * StatementCase,
             //         numHeads * CaseHead, Pattern, Expression),
           } else {
@@ -1736,7 +1872,8 @@
           options.nullSafetyEnabled &&
           !options.patternsEnabled &&
           !lastCaseTerminates) {
-        errors?.switchCaseCompletesNormally(node: node, caseIndex: caseIndex);
+        (switchCaseCompletesNormallyErrors ??= {})[caseIndex] = errors
+            .switchCaseCompletesNormally(node: node, caseIndex: caseIndex);
       }
       handleMergedStatementCase(node,
           caseIndex: caseIndex, isTerminating: lastCaseTerminates);
@@ -1756,18 +1893,23 @@
       requiresExhaustivenessValidation = false;
     }
     bool isProvenExhaustive = flow.switchStatement_end(isExhaustive);
+    Error? nonExhaustiveSwitchError;
     if (options.errorOnSwitchExhaustiveness &&
         requiresExhaustivenessValidation &&
         !isProvenExhaustive &&
         !isLegacySwitchExhaustive(node, scrutineeType)) {
-      errors?.nonExhaustiveSwitch(node: node, scrutineeType: scrutineeType);
+      nonExhaustiveSwitchError =
+          errors.nonExhaustiveSwitch(node: node, scrutineeType: scrutineeType);
     }
-    return new SwitchStatementTypeAnalysisResult<Type>(
+    return new SwitchStatementTypeAnalysisResult(
       hasDefault: hasDefault,
       isExhaustive: isExhaustive,
       lastCaseTerminates: lastCaseTerminates,
       requiresExhaustivenessValidation: requiresExhaustivenessValidation,
       scrutineeType: scrutineeType,
+      switchCaseCompletesNormallyErrors: switchCaseCompletesNormallyErrors,
+      nonBooleanGuardErrors: nonBooleanGuardErrors,
+      nonExhaustiveSwitchError: nonExhaustiveSwitchError,
     );
   }
 
@@ -1793,19 +1935,23 @@
 
   /// Analyzes a wildcard pattern.  [node] is the pattern.
   ///
+  /// Returns a [WildcardPattern] with information about reported errors.
+  ///
   /// See [dispatchPattern] for the meaning of [context].
   ///
   /// Stack effect: none.
-  void analyzeWildcardPattern({
+  WildcardPatternResult<Error> analyzeWildcardPattern({
     required MatchContext<Node, Expression, Pattern, Type, Variable> context,
     required Pattern node,
     required Type? declaredType,
   }) {
     Type matchedType = flow.getMatchedValueType();
     Node? irrefutableContext = context.irrefutableContext;
+    Error? patternTypeMismatchInIrrefutableContextError;
     if (irrefutableContext != null && declaredType != null) {
       if (!operations.isAssignableTo(matchedType, declaredType)) {
-        errors?.patternTypeMismatchInIrrefutableContext(
+        patternTypeMismatchInIrrefutableContextError =
+            errors.patternTypeMismatchInIrrefutableContext(
           pattern: node,
           context: irrefutableContext,
           matchedType: matchedType,
@@ -1825,11 +1971,14 @@
     UnnecessaryWildcardKind? unnecessaryWildcardKind =
         context.unnecessaryWildcardKind;
     if (isAlwaysMatching && unnecessaryWildcardKind != null) {
-      errors?.unnecessaryWildcardPattern(
+      errors.unnecessaryWildcardPattern(
         pattern: node,
         kind: unnecessaryWildcardKind,
       );
     }
+    return new WildcardPatternResult(
+        patternTypeMismatchInIrrefutableContextError:
+            patternTypeMismatchInIrrefutableContextError);
   }
 
   /// Computes the type schema for a wildcard pattern.  [declaredType] is the
@@ -2184,14 +2333,15 @@
     // Stack: (CollectionElement ifTrue, CollectionElement ifFalse)
   }
 
-  void _checkGuardType(Expression expression, Type type) {
+  Error? _checkGuardType(Expression expression, Type type) {
     // TODO(paulberry): harmonize this with analyzer's checkForNonBoolExpression
     // TODO(paulberry): spec says the type must be `bool` or `dynamic`.  This
     // logic permits `T extends bool`, `T promoted to bool`, or `Never`.  What
     // do we want?
     if (!operations.isAssignableTo(type, boolType)) {
-      errors?.nonBooleanCondition(node: expression);
+      return errors.nonBooleanCondition(node: expression);
     }
+    return null;
   }
 
   void _finishJoinedPatternVariables(
@@ -2242,7 +2392,7 @@
           if (inconsistencyFound &&
               location == JoinedPatternVariableLocation.singlePattern &&
               variable != null) {
-            errors?.inconsistentJoinedPatternVariable(
+            errors.inconsistentJoinedPatternVariable(
                 variable: variable, component: component);
           }
         }
@@ -2307,17 +2457,17 @@
   }
 
   /// Reports errors for duplicate named record fields.
-  void _reportDuplicateRecordPatternFields(
-    Pattern pattern,
-    List<RecordPatternField<Node, Pattern>> fields,
-  ) {
+  Map<int, Error>? _reportDuplicateRecordPatternFields(
+      Pattern pattern, List<RecordPatternField<Node, Pattern>> fields) {
+    Map<int, Error>? errorResults;
     Map<String, RecordPatternField<Node, Pattern>> nameToField = {};
-    for (RecordPatternField<Node, Pattern> field in fields) {
+    for (int i = 0; i < fields.length; i++) {
+      RecordPatternField<Node, Pattern> field = fields[i];
       String? name = field.name;
       if (name != null) {
         RecordPatternField<Node, Pattern>? original = nameToField[name];
         if (original != null) {
-          errors?.duplicateRecordPatternField(
+          (errorResults ??= {})[i] = errors.duplicateRecordPatternField(
             objectOrRecordPattern: pattern,
             name: name,
             original: original,
@@ -2328,6 +2478,7 @@
         }
       }
     }
+    return errorResults;
   }
 
   bool _structurallyEqualAfterNormTypes(Type type1, Type type2) {
@@ -2345,10 +2496,11 @@
     Expression extends Node,
     Variable extends Object,
     Type extends Object,
-    Pattern extends Node> implements TypeAnalyzerErrorsBase {
+    Pattern extends Node,
+    Error> implements TypeAnalyzerErrorsBase {
   /// Called if [argument] has type [argumentType], which is not assignable
   /// to [parameterType].
-  void argumentTypeNotAssignable({
+  Error argumentTypeNotAssignable({
     required Expression argument,
     required Type argumentType,
     required Type parameterType,
@@ -2356,7 +2508,7 @@
 
   /// Called if pattern support is disabled and a case constant's static type
   /// doesn't properly match the scrutinee's static type.
-  void caseExpressionTypeMismatch(
+  Error caseExpressionTypeMismatch(
       {required Expression scrutinee,
       required Expression caseExpression,
       required Type scrutineeType,
@@ -2364,14 +2516,16 @@
       required bool nullSafetyEnabled});
 
   /// Called for variable that is assigned more than once.
-  void duplicateAssignmentPatternVariable({
+  ///
+  /// Returns an error object that is passed on the the caller.
+  Error duplicateAssignmentPatternVariable({
     required Variable variable,
     required Pattern original,
     required Pattern duplicate,
   });
 
   /// Called for a pair of named fields have the same name.
-  void duplicateRecordPatternField({
+  Error duplicateRecordPatternField({
     required Pattern objectOrRecordPattern,
     required String name,
     required RecordPatternField<Node, Pattern> original,
@@ -2379,7 +2533,7 @@
   });
 
   /// Called for a duplicate rest pattern found in a list or map pattern.
-  void duplicateRestPattern({
+  Error duplicateRestPattern({
     required Pattern mapOrListPattern,
     required Node original,
     required Node duplicate,
@@ -2395,7 +2549,7 @@
 
   /// 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({
+  Error matchedTypeIsStrictlyNonNullable({
     required Pattern pattern,
     required Type matchedType,
   });
@@ -2409,7 +2563,7 @@
   });
 
   /// Called if the static type of a condition is not assignable to `bool`.
-  void nonBooleanCondition({required Expression node});
+  Error nonBooleanCondition({required Expression node});
 
   /// Called if [TypeAnalyzerOptions.errorOnSwitchExhaustiveness] is `true`, and
   /// a switch that is required to be exhaustive cannot be proven by flow
@@ -2418,7 +2572,7 @@
   /// [node] is the offending switch expression or switch statement, and
   /// [scrutineeType] is the static type of the switch statement's scrutinee
   /// expression.
-  void nonExhaustiveSwitch({required Node node, required Type scrutineeType});
+  Error nonExhaustiveSwitch({required Node node, required Type scrutineeType});
 
   /// Called if a pattern is illegally used in a variable declaration statement
   /// that is marked `late`, and that pattern is not allowed in such a
@@ -2432,7 +2586,7 @@
   /// that should be an `Iterable` (or dynamic) is actually not.
   ///
   /// [expressionType] is the actual type of the [expression].
-  void patternForInExpressionIsNotIterable({
+  Error patternForInExpressionIsNotIterable({
     required Node node,
     required Expression expression,
     required Type expressionType,
@@ -2445,7 +2599,7 @@
   /// the containing AST node that established an irrefutable context,
   /// [matchedType] is the matched type, and [requiredType] is the required
   /// type.
-  void patternTypeMismatchInIrrefutableContext(
+  Error patternTypeMismatchInIrrefutableContext(
       {required Pattern pattern,
       required Node context,
       required Type matchedType,
@@ -2457,12 +2611,12 @@
   /// containing AST node that established an irrefutable context.
   ///
   /// TODO(paulberry): move this error reporting to the parser.
-  void refutablePatternInIrrefutableContext(
+  Error refutablePatternInIrrefutableContext(
       {required Node pattern, required Node context});
 
   /// Called if the [returnType] of the invoked relational operator is not
   /// assignable to `bool`.
-  void relationalPatternOperatorReturnTypeNotAssignableToBool({
+  Error relationalPatternOperatorReturnTypeNotAssignableToBool({
     required Pattern pattern,
     required Type returnType,
   });
@@ -2484,7 +2638,7 @@
   ///
   /// [node] is the AST node of the switch statement.  [caseIndex] is the index
   /// of the merged case with the erroneous case body.
-  void switchCaseCompletesNormally(
+  Error switchCaseCompletesNormally(
       {required Statement node, required int caseIndex});
 
   /// Called when a wildcard pattern appears in the context where it is not
diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
index 1fd5a6d..c1366ce 100644
--- a/pkg/_fe_analyzer_shared/test/mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -2737,8 +2737,9 @@
   @override
   void visit(Harness h, SharedMatchContext context) {
     var matchedType = h.typeAnalyzer.flow.getMatchedValueType();
-    var requiredType = h.typeAnalyzer.analyzeListPattern(context, this,
+    var listPatternResult = h.typeAnalyzer.analyzeListPattern(context, this,
         elementType: _elementType, elements: _elements);
+    var requiredType = listPatternResult.requiredType;
     h.irBuilder.atom(matchedType.type, Kind.type, location: location);
     h.irBuilder.atom(requiredType.type, Kind.type, location: location);
     h.irBuilder.apply(
@@ -2929,8 +2930,9 @@
   @override
   void visit(Harness h, SharedMatchContext context) {
     var matchedType = h.typeAnalyzer.flow.getMatchedValueType();
-    var requiredType = h.typeAnalyzer.analyzeMapPattern(context, this,
+    var mapPatternResult = h.typeAnalyzer.analyzeMapPattern(context, this,
         typeArguments: _typeArguments, elements: _elements);
+    var requiredType = mapPatternResult.requiredType;
     h.irBuilder.atom(matchedType.type, Kind.type, location: location);
     h.irBuilder.atom(requiredType.type, Kind.type, location: location);
     h.irBuilder.apply(
@@ -2976,7 +2978,8 @@
 
 class _MiniAstErrors
     implements
-        TypeAnalyzerErrors<Node, Statement, Expression, Var, Type, Pattern>,
+        TypeAnalyzerErrors<Node, Statement, Expression, Var, Type, Pattern,
+            void>,
         VariableBinderErrors<Node, Var> {
   final Set<String> _accumulatedErrors = {};
 
@@ -3248,7 +3251,7 @@
 }
 
 class _MiniAstTypeAnalyzer
-    with TypeAnalyzer<Node, Statement, Expression, Var, Type, Pattern> {
+    with TypeAnalyzer<Node, Statement, Expression, Var, Type, Pattern, void> {
   final Harness _harness;
 
   @override
@@ -4137,8 +4140,9 @@
   @override
   void visit(Harness h, SharedMatchContext context) {
     var matchedType = h.typeAnalyzer.flow.getMatchedValueType();
-    var requiredType =
+    var objectPatternResult =
         h.typeAnalyzer.analyzeObjectPattern(context, this, fields: fields);
+    var requiredType = objectPatternResult.requiredType;
     h.irBuilder.atom(matchedType.type, Kind.type, location: location);
     h.irBuilder.atom(requiredType.type, Kind.type, location: location);
     h.irBuilder.apply(
@@ -4407,8 +4411,9 @@
   @override
   void visit(Harness h, SharedMatchContext context) {
     var matchedType = h.typeAnalyzer.flow.getMatchedValueType();
-    var requiredType =
+    var recordPatternResult =
         h.typeAnalyzer.analyzeRecordPattern(context, this, fields: fields);
+    var requiredType = recordPatternResult.requiredType;
     h.irBuilder.atom(matchedType.type, Kind.type, location: location);
     h.irBuilder.atom(requiredType.type, Kind.type, location: location);
     h.irBuilder.apply(
@@ -4922,8 +4927,10 @@
       h.typeAnalyzer.handleAssignedVariablePattern(this);
     } else {
       var matchedType = h.typeAnalyzer.flow.getMatchedValueType();
-      var staticType = h.typeAnalyzer.analyzeDeclaredVariablePattern(
-          context, this, variable, variable.name, declaredType);
+      var declaredVariablePatternResult = h.typeAnalyzer
+          .analyzeDeclaredVariablePattern(
+              context, this, variable, variable.name, declaredType);
+      var staticType = declaredVariablePatternResult.staticType;
       h.typeAnalyzer.handleDeclaredVariablePattern(this,
           matchedType: matchedType, staticType: staticType);
     }
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 9d130cb..e7fb749 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -3664,12 +3664,10 @@
     ResolverVisitor resolverVisitor,
     SharedMatchContext context,
   ) {
-    declaredElement!.type = resolverVisitor.analyzeDeclaredVariablePattern(
-        context,
-        this,
-        declaredElement!,
-        declaredElement!.name,
-        type?.typeOrThrow);
+    declaredElement!.type = resolverVisitor
+        .analyzeDeclaredVariablePattern(context, this, declaredElement!,
+            declaredElement!.name, type?.typeOrThrow)
+        .staticType;
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/resolver/list_pattern_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/list_pattern_resolver.dart
index ec5a887..4edfbdf 100644
--- a/pkg/analyzer/lib/src/dart/resolver/list_pattern_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/list_pattern_resolver.dart
@@ -30,8 +30,10 @@
       }
     }
 
-    node.requiredType = resolverVisitor.analyzeListPattern(context, node,
-        elementType: typeArguments?.arguments.first.typeOrThrow,
-        elements: node.elements);
+    node.requiredType = resolverVisitor
+        .analyzeListPattern(context, node,
+            elementType: typeArguments?.arguments.first.typeOrThrow,
+            elements: node.elements)
+        .requiredType;
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/resolver/shared_type_analyzer.dart b/pkg/analyzer/lib/src/dart/resolver/shared_type_analyzer.dart
index 1ceb938..7c1cbaa 100644
--- a/pkg/analyzer/lib/src/dart/resolver/shared_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/shared_type_analyzer.dart
@@ -23,7 +23,7 @@
 class SharedTypeAnalyzerErrors
     implements
         shared.TypeAnalyzerErrors<AstNode, Statement, Expression,
-            PromotableElement, DartType, DartPattern> {
+            PromotableElement, DartType, DartPattern, void> {
   final ErrorReporter _errorReporter;
 
   SharedTypeAnalyzerErrors(this._errorReporter);
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index d85d20b..e30efc1 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -154,7 +154,7 @@
     with
         ErrorDetectionHelpers,
         TypeAnalyzer<AstNode, Statement, Expression, PromotableElement,
-            DartType, DartPattern> {
+            DartType, DartPattern, void> {
   /// Debug-only: if `true`, manipulations of [_rewriteStack] performed by
   /// [popRewrite], [pushRewrite], and [replaceExpression] will be printed.
   static const bool _debugRewriteStack = false;
@@ -1563,7 +1563,7 @@
       node,
       typeArguments: typeArguments,
       elements: node.elements,
-    );
+    ).requiredType;
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 8d98d1a..732a7f7 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -8515,7 +8515,7 @@
   }
 
   @override
-  Expression buildProblem(Message message, int charOffset, int length,
+  InvalidExpression buildProblem(Message message, int charOffset, int length,
       {List<LocatedMessage>? context,
       bool suppressMessage = false,
       Expression? expression}) {
@@ -9282,10 +9282,13 @@
     } else if (inAssignmentPattern) {
       String name = variable.lexeme;
       if (keyword != null || type != null) {
-        pattern = new InvalidPattern(buildProblem(
-            fasta.templatePatternAssignmentDeclaresVariable.withArguments(name),
-            variable.charOffset,
-            variable.charCount));
+        pattern = new InvalidPattern(
+            buildProblem(
+                fasta.templatePatternAssignmentDeclaresVariable
+                    .withArguments(name),
+                variable.charOffset,
+                variable.charCount),
+            declaredVariables: const []);
       } else {
         Expression variableUse = toValue(scopeLookup(scope, name, variable));
         if (variableUse is VariableGet) {
@@ -9334,10 +9337,10 @@
         name = pattern.variableName;
       }
       if (name == null) {
-        push(new InvalidPattern(buildProblem(
-            fasta.messageUnspecifiedGetterNameInObjectPattern,
-            colon.charOffset,
-            noLength)));
+        push(new InvalidPattern(
+            buildProblem(fasta.messageUnspecifiedGetterNameInObjectPattern,
+                colon.charOffset, noLength),
+            declaredVariables: const []));
       } else {
         push(new NamedPattern(name, pattern, colon.charOffset));
       }
diff --git a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
index ed5e0d47..6762465 100644
--- a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
@@ -3667,8 +3667,6 @@
 }
 
 abstract class Pattern extends TreeNode with InternalTreeNode {
-  Expression? error;
-
   Pattern(int fileOffset) {
     this.fileOffset = fileOffset;
   }
@@ -4236,11 +4234,13 @@
 }
 
 class PatternAssignment extends InternalExpression {
-  final Pattern pattern;
-  final Expression expression;
+  Pattern pattern;
+  Expression expression;
 
   PatternAssignment(this.pattern, this.expression, {required int fileOffset}) {
     super.fileOffset = fileOffset;
+    pattern.parent = this;
+    expression.parent = this;
   }
 
   @override
@@ -4730,7 +4730,11 @@
 class InvalidPattern extends Pattern {
   final Expression invalidExpression;
 
-  InvalidPattern(this.invalidExpression) : super(invalidExpression.fileOffset) {
+  @override
+  final List<VariableDeclaration> declaredVariables;
+
+  InvalidPattern(this.invalidExpression, {required this.declaredVariables})
+      : super(invalidExpression.fileOffset) {
     invalidExpression.parent = this;
   }
 
@@ -4739,9 +4743,6 @@
       visitor.visitInvalidPattern(this, arg);
 
   @override
-  List<VariableDeclaration> get declaredVariables => const [];
-
-  @override
   void toTextInternal(AstPrinter printer) {
     printer.writeExpression(invalidExpression);
   }
@@ -4797,9 +4798,6 @@
 
   /// Operator accessed on a receiver of an invalid type.
   Invalid,
-
-  /// Erroneous operator access.
-  Error,
 }
 
 /// Kinds of lowerings of objects pattern property access.
diff --git a/pkg/front_end/lib/src/fasta/type_inference/delayed_expressions.dart b/pkg/front_end/lib/src/fasta/type_inference/delayed_expressions.dart
index c173676..56fc31e 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/delayed_expressions.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/delayed_expressions.dart
@@ -653,7 +653,13 @@
   final int fileOffset;
 
   DelayedRecordNameGet(this._receiver, this._recordType, this._name,
-      {required this.fileOffset});
+      {required this.fileOffset})
+      : assert(
+            _recordType.named
+                    .where((element) => element.name == _name)
+                    .length ==
+                1,
+            "Invalid record type $_recordType for named access of '$_name'.");
 
   @override
   Expression createExpression(TypeEnvironment typeEnvironment) {
diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
index cfe7265..20333f2 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
@@ -9,7 +9,7 @@
 abstract class InferenceHelper {
   Uri get uri;
 
-  Expression buildProblem(Message message, int charOffset, int length,
+  InvalidExpression buildProblem(Message message, int charOffset, int length,
       {List<LocatedMessage>? context,
       bool suppressMessage = false,
       Expression? expression});
diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart
index 8070842..4ec048d 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart
@@ -98,7 +98,7 @@
 class InferenceVisitorImpl extends InferenceVisitorBase
     with
         TypeAnalyzer<TreeNode, Statement, Expression, VariableDeclaration,
-            DartType, Pattern>,
+            DartType, Pattern, InvalidExpression>,
         StackChecker
     implements
         ExpressionVisitor1<ExpressionInferenceResult, DartType>,
@@ -1150,7 +1150,8 @@
     Expression read;
     if (readTarget.isMissing) {
       read = createMissingPropertyGet(
-          node.readOffset, readReceiver, readType, node.propertyName);
+          node.readOffset, readType, node.propertyName,
+          receiver: readReceiver);
     } else {
       assert(readTarget.isExtensionMember);
       read = new StaticInvocation(
@@ -1852,13 +1853,11 @@
     assert(checkStackBase(node, stackBase = stackHeight));
 
     // TODO(scheglov) Pass actual variables, not just `{}`.
-    DartType scrutineeType = analyzeIfCaseStatement(
-        node,
-        node.expression,
-        node.patternGuard.pattern,
-        node.patternGuard.guard,
-        node.then,
-        node.otherwise, {});
+    IfCaseStatementResult<DartType, InvalidExpression> analysisResult =
+        analyzeIfCaseStatement(node, node.expression, node.patternGuard.pattern,
+            node.patternGuard.guard, node.then, node.otherwise, {});
+
+    DartType scrutineeType = analysisResult.matchedExpressionType;
 
     assert(checkStack(node, stackBase, [
       /* ifFalse = */ ValueKinds.StatementOrNull,
@@ -1879,7 +1878,10 @@
       then = node.then = (rewrite as Statement)..parent = node;
     }
     rewrite = popRewrite(NullValues.Expression);
-    if (!identical(node.patternGuard.guard, rewrite)) {
+    InvalidExpression? guardError = analysisResult.nonBooleanGuardError;
+    if (guardError != null) {
+      node.patternGuard.guard = guardError..parent = node.patternGuard;
+    } else if (!identical(node.patternGuard.guard, rewrite)) {
       node.patternGuard.guard = (rewrite as Expression)
         ..parent = node.patternGuard;
     }
@@ -2203,19 +2205,20 @@
               inferredTypeArgument: inferredTypeArgument,
               inferredSpreadTypes: inferredSpreadTypes,
               inferredConditionTypes: inferredConditionTypes);
-      analyzeIfCaseElement(
-          node: element,
-          expression: element.expression,
-          pattern: element.patternGuard.pattern,
-          variables: {
-            for (VariableDeclaration variable
-                in element.patternGuard.pattern.declaredVariables)
-              variable.name!: variable
-          },
-          guard: element.patternGuard.guard,
-          ifTrue: element.then,
-          ifFalse: element.otherwise,
-          context: context);
+      IfCaseStatementResult<DartType, InvalidExpression> analysisResult =
+          analyzeIfCaseElement(
+              node: element,
+              expression: element.expression,
+              pattern: element.patternGuard.pattern,
+              variables: {
+                for (VariableDeclaration variable
+                    in element.patternGuard.pattern.declaredVariables)
+                  variable.name!: variable
+              },
+              guard: element.patternGuard.guard,
+              ifTrue: element.then,
+              ifFalse: element.otherwise,
+              context: context);
 
       assert(checkStack(element, stackBase, [
         /* ifFalse = */ ValueKinds.ExpressionOrNull,
@@ -2237,7 +2240,10 @@
 
       PatternGuard patternGuard = element.patternGuard;
       rewrite = popRewrite(NullValues.Expression);
-      if (!identical(patternGuard.guard, rewrite)) {
+      InvalidExpression? guardError = analysisResult.nonBooleanGuardError;
+      if (guardError != null) {
+        patternGuard.guard = guardError..parent = patternGuard;
+      } else if (!identical(patternGuard.guard, rewrite)) {
         patternGuard.guard = (rewrite as Expression?)?..parent = patternGuard;
       }
 
@@ -8088,8 +8094,9 @@
     assert(checkStackBase(node, stackBase = stackHeight));
 
     Expression expression = node.expression;
-    SimpleTypeAnalysisResult<DartType> analysisResult = analyzeSwitchExpression(
-        node, expression, node.cases.length, typeContext);
+    SwitchExpressionResult<DartType, InvalidExpression> analysisResult =
+        analyzeSwitchExpression(
+            node, expression, node.cases.length, typeContext);
     DartType valueType = analysisResult.type;
 
     assert(checkStack(node, stackBase, [
@@ -8140,8 +8147,15 @@
       SwitchExpressionCase switchCase = node.cases[caseIndex];
       Expression body = switchCase.expression;
 
-      Pattern pattern = switchCase.patternGuard.pattern;
-      Expression? guard = switchCase.patternGuard.guard;
+      PatternGuard patternGuard = switchCase.patternGuard;
+      Pattern pattern = patternGuard.pattern;
+      Expression? guard = patternGuard.guard;
+
+      InvalidExpression? guardError =
+          analysisResult.nonBooleanGuardErrors?[caseIndex];
+      if (guardError != null) {
+        guard = patternGuard.guard = guardError..parent = patternGuard;
+      }
 
       replacementStatements.addAll(pattern.declaredVariables);
 
@@ -8216,7 +8230,8 @@
     List<SwitchCaseInfo> previousSwitchPatternInfo = _switchCasePatternInfo;
     _switchCasePatternInfo = [];
     Expression expression = node.expression;
-    SwitchStatementTypeAnalysisResult<DartType> analysisResult =
+    SwitchStatementTypeAnalysisResult<DartType, InvalidExpression>
+        analysisResult =
         analyzeSwitchStatement(node, expression, node.cases.length);
 
     assert(checkStack(node, stackBase, [
@@ -8319,7 +8334,8 @@
     _switchCasePatternInfo = [];
 
     Expression expression = node.expression;
-    SwitchStatementTypeAnalysisResult<DartType> analysisResult =
+    SwitchStatementTypeAnalysisResult<DartType, InvalidExpression>
+        analysisResult =
         analyzeSwitchStatement(node, expression, node.cases.length);
 
     assert(checkStack(node, stackBase, [
@@ -8413,8 +8429,15 @@
       for (int headIndex = 0;
           headIndex < switchCase.patternGuards.length;
           headIndex++) {
-        Pattern pattern = switchCase.patternGuards[headIndex].pattern;
-        Expression? guard = switchCase.patternGuards[headIndex].guard;
+        PatternGuard patternGuard = switchCase.patternGuards[headIndex];
+        Pattern pattern = patternGuard.pattern;
+        Expression? guard = patternGuard.guard;
+
+        InvalidExpression? guardError =
+            analysisResult.nonBooleanGuardErrors?[caseIndex]?[headIndex];
+        if (guardError != null) {
+          guard = patternGuard.guard = guardError..parent = patternGuard;
+        }
 
         replacementStatements.addAll(pattern.declaredVariables);
 
@@ -9003,11 +9026,8 @@
     int? stackBase;
     assert(checkStackBase(node, stackBase = stackHeight));
 
-    Pattern pattern = node.pattern;
-    Expression initializer = node.initializer;
-
     // TODO(cstefantsova): Support late variables.
-    analyzePatternVariableDeclaration(node, pattern, initializer,
+    analyzePatternVariableDeclaration(node, node.pattern, node.initializer,
         isFinal: node.isFinal, isLate: false);
 
     assert(checkStack(node, stackBase, [
@@ -9016,13 +9036,17 @@
     ]));
 
     Object? rewrite = popRewrite();
-    if (!identical(rewrite, pattern)) {
-      pattern = rewrite as Pattern;
+    if (!identical(rewrite, node.pattern)) {
+      node.pattern = rewrite as Pattern..parent = node;
     }
 
+    assert(checkStack(node, stackBase, [
+      /* initializer = */ ValueKinds.Expression,
+    ]));
+
     rewrite = popRewrite();
-    if (!identical(initializer, rewrite)) {
-      initializer = rewrite as Expression;
+    if (!identical(node.initializer, rewrite)) {
+      node.initializer = rewrite as Expression;
     }
 
     MatchingCache matchingCache = createMatchingCache();
@@ -9031,7 +9055,7 @@
     // TODO(cstefantsova): Do we need a more precise type for the variable?
     DartType matchedType = const DynamicType();
     CacheableExpression matchedExpression =
-        matchingCache.createRootExpression(initializer, matchedType);
+        matchingCache.createRootExpression(node.initializer, matchedType);
 
     DelayedExpression matchingExpression =
         matchingExpressionVisitor.visitPattern(node.pattern, matchedExpression);
@@ -10073,15 +10097,27 @@
 
     node.matchedType = flow.getMatchedValueType();
 
-    DartType inferredType = analyzeDeclaredVariablePattern(
-        context, node, node.variable, node.variable.name!, node.type);
+    DeclaredVariablePatternResult<DartType, InvalidExpression> analysisResult =
+        analyzeDeclaredVariablePattern(
+            context, node, node.variable, node.variable.name!, node.type);
+
+    Pattern? replacement;
+
+    InvalidExpression? error =
+        analysisResult.patternTypeMismatchInIrrefutableContextError;
+    if (error != null) {
+      replacement =
+          new InvalidPattern(error, declaredVariables: node.declaredVariables);
+    }
+
+    DartType inferredType = analysisResult.staticType;
     instrumentation?.record(uriForInstrumentation, node.variable.fileOffset,
         'type', new InstrumentationValueForType(inferredType));
     if (node.type == null) {
       node.variable.type = inferredType;
     }
 
-    pushRewrite(node);
+    pushRewrite(replacement ?? node);
 
     assert(checkStack(node, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
@@ -10093,10 +10129,20 @@
     int? stackBase;
     assert(checkStackBase(node, stackBase = stackHeight));
 
-    analyzeWildcardPattern(
-        context: context, node: node, declaredType: node.type);
+    WildcardPatternResult<InvalidExpression> analysisResult =
+        analyzeWildcardPattern(
+            context: context, node: node, declaredType: node.type);
 
-    pushRewrite(node);
+    Pattern? replacement;
+
+    InvalidExpression? error =
+        analysisResult.patternTypeMismatchInIrrefutableContextError;
+    if (error != null) {
+      replacement =
+          new InvalidPattern(error, declaredVariables: node.declaredVariables);
+    }
+
+    pushRewrite(replacement ?? node);
 
     assert(checkStack(node, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
@@ -10108,9 +10154,20 @@
     int? stackBase;
     assert(checkStackBase(node, stackBase = stackHeight));
 
-    node.expressionType =
+    ConstantPatternResult<DartType, InvalidExpression> analysisResult =
         analyzeConstantPattern(context, node, node.expression);
 
+    Pattern? replacement;
+
+    InvalidExpression? error =
+        analysisResult.refutablePatternInIrrefutableContextError;
+    if (error != null) {
+      replacement =
+          new InvalidPattern(error, declaredVariables: node.declaredVariables);
+    }
+
+    node.expressionType = analysisResult.expressionType;
+
     ObjectAccessTarget equalsInvokeTarget = findInterfaceMember(
         node.expressionType, equalsName, node.fileOffset,
         includeExtensionMethods: true,
@@ -10131,7 +10188,7 @@
       node.expression = (rewrite as Expression)..parent = node;
     }
 
-    pushRewrite(node);
+    pushRewrite(replacement ?? node);
 
     assert(checkStack(node, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
@@ -10172,13 +10229,23 @@
     int? stackBase;
     assert(checkStackBase(node, stackBase = stackHeight));
 
-    analyzeLogicalOrPattern(context, node, node.left, node.right);
+    LogicalOrPatternResult<InvalidExpression> analysisResult =
+        analyzeLogicalOrPattern(context, node, node.left, node.right);
 
     assert(checkStack(node, stackBase, [
       /* right = */ ValueKinds.Pattern,
       /* left = */ ValueKinds.Pattern,
     ]));
 
+    Pattern? replacement;
+
+    InvalidExpression? error =
+        analysisResult.refutablePatternInIrrefutableContextError;
+    if (error != null) {
+      replacement =
+          new InvalidPattern(error, declaredVariables: node.declaredVariables);
+    }
+
     Object? rewrite = popRewrite();
     if (!identical(rewrite, node.right)) {
       node.right = (rewrite as Pattern)..parent = node;
@@ -10189,7 +10256,7 @@
       node.left = (rewrite as Pattern)..parent = node;
     }
 
-    pushRewrite(node);
+    pushRewrite(replacement ?? node);
 
     assert(checkStack(node, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
@@ -10230,19 +10297,29 @@
     int? stackBase;
     assert(checkStackBase(node, stackBase = stackHeight));
 
-    analyzeNullCheckOrAssertPattern(context, node, node.pattern,
-        isAssert: true);
+    NullCheckOrAssertPatternResult<InvalidExpression> analysisResult =
+        analyzeNullCheckOrAssertPattern(context, node, node.pattern,
+            isAssert: true);
 
     assert(checkStack(node, stackBase, [
       /* subpattern = */ ValueKinds.Pattern,
     ]));
 
+    Pattern? replacement;
+
+    InvalidExpression? error =
+        analysisResult.refutablePatternInIrrefutableContextError;
+    if (error != null) {
+      replacement =
+          new InvalidPattern(error, declaredVariables: node.declaredVariables);
+    }
+
     Object? rewrite = popRewrite();
     if (!identical(rewrite, node.pattern)) {
       node.pattern = (rewrite as Pattern)..parent = node;
     }
 
-    pushRewrite(node);
+    pushRewrite(replacement ?? node);
 
     assert(checkStack(node, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
@@ -10363,22 +10440,37 @@
       node.lengthCheckType = equalsInvokeTarget.getFunctionType(this);
     }
 
-    analyzeListPattern(context, node,
-        elements: node.patterns, elementType: node.typeArgument);
+    ListPatternResult<DartType, InvalidExpression> analysisResult =
+        analyzeListPattern(context, node,
+            elements: node.patterns, elementType: node.typeArgument);
 
     assert(checkStack(node, stackBase, [
       /* subpatterns = */ ...repeatedKind(
           ValueKinds.Pattern, node.patterns.length)
     ]));
 
+    Pattern? replacement;
+
+    InvalidExpression? error =
+        analysisResult.patternTypeMismatchInIrrefutableContextError;
+    if (error != null) {
+      replacement =
+          new InvalidPattern(error, declaredVariables: node.declaredVariables);
+    }
+
     for (int i = node.patterns.length - 1; i >= 0; i--) {
       Object? rewrite = popRewrite();
-      if (!identical(rewrite, node.patterns[i])) {
+      InvalidExpression? error = analysisResult.duplicateRestPatternErrors?[i];
+      if (error != null) {
+        node.patterns[i] = new InvalidPattern(error,
+            declaredVariables: node.patterns[i].declaredVariables)
+          ..parent = node;
+      } else if (!identical(rewrite, node.patterns[i])) {
         node.patterns[i] = (rewrite as Pattern)..parent = node;
       }
     }
 
-    pushRewrite(node);
+    pushRewrite(replacement ?? node);
 
     assert(checkStack(node, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
@@ -10398,8 +10490,9 @@
 
     node.matchedType = flow.getMatchedValueType();
 
-    analyzeObjectPattern(context, node,
-        fields: <RecordPatternField<TreeNode, Pattern>>[
+    ObjectPatternResult<DartType, InvalidExpression> analysisResult =
+        analyzeObjectPattern(context, node,
+            fields: <RecordPatternField<TreeNode, Pattern>>[
           for (NamedPattern field in node.fields)
             new RecordPatternField(
                 node: field, name: field.name, pattern: field.pattern)
@@ -10410,10 +10503,25 @@
           ValueKinds.Pattern, node.fields.length)
     ]));
 
+    Pattern? replacement;
+
+    InvalidExpression? error =
+        analysisResult.patternTypeMismatchInIrrefutableContextError;
+    if (error != null) {
+      replacement =
+          new InvalidPattern(error, declaredVariables: node.declaredVariables);
+    }
+
     for (int i = node.fields.length - 1; i >= 0; i--) {
       NamedPattern field = node.fields[i];
       Object? rewrite = popRewrite();
-      if (!identical(rewrite, field.pattern)) {
+      InvalidExpression? error =
+          analysisResult.duplicateRecordPatternFieldErrors?[i];
+      if (error != null) {
+        field.pattern = new InvalidPattern(error,
+            declaredVariables: field.pattern.declaredVariables)
+          ..parent = field;
+      } else if (!identical(rewrite, field.pattern)) {
         field.pattern = (rewrite as Pattern)..parent = field;
       }
     }
@@ -10477,9 +10585,11 @@
           case ObjectAccessTargetKind.nullableCallFunction:
           case ObjectAccessTargetKind.missing:
           case ObjectAccessTargetKind.ambiguous:
-            // TODO(johnniwinther): Provide the right receiver.
-            field.error = createMissingPropertyGet(field.fileOffset,
-                new NullLiteral(), node.objectType, field.fieldName);
+            field.pattern = new InvalidPattern(
+                createMissingPropertyGet(
+                    field.fileOffset, node.objectType, field.fieldName),
+                declaredVariables: field.pattern.declaredVariables)
+              ..parent = field;
             field.accessKind = ObjectAccessKind.Error;
             break;
           case ObjectAccessTargetKind.invalid:
@@ -10509,14 +10619,15 @@
         }
       } else {
         field.accessKind = ObjectAccessKind.Error;
-        field.error = helper.buildProblem(
-            messageUnspecifiedGetterNameInObjectPattern,
-            node.fileOffset,
-            noLength);
+        field.pattern = new InvalidPattern(
+            helper.buildProblem(messageUnspecifiedGetterNameInObjectPattern,
+                node.fileOffset, noLength),
+            declaredVariables: field.pattern.declaredVariables)
+          ..parent = field;
       }
     }
 
-    pushRewrite(node);
+    pushRewrite(replacement ?? node);
 
     assert(checkStack(node, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
@@ -10555,18 +10666,30 @@
 
     node.matchedType = flow.getMatchedValueType();
 
-    DartType expressionType =
+    RelationalPatternResult<DartType, InvalidExpression> analysisResult =
         analyzeRelationalPattern(context, node, node.expression);
 
     assert(checkStack(node, stackBase, [
       /* expression = */ ValueKinds.Expression,
     ]));
 
+    Pattern? replacement;
+
+    InvalidExpression? error =
+        analysisResult.refutablePatternInIrrefutableContextError ??
+            analysisResult.operatorReturnTypeNotAssignableToBoolError ??
+            analysisResult.argumentTypeNotAssignableError;
+    if (error != null) {
+      replacement =
+          new InvalidPattern(error, declaredVariables: node.declaredVariables);
+    }
+
     Object? rewrite = popRewrite();
     if (!identical(rewrite, node.expression)) {
       node.expression = (rewrite as Expression)..parent = node;
     }
 
+    DartType expressionType = analysisResult.operandType;
     node.expressionType = expressionType;
 
     switch (node.kind) {
@@ -10627,15 +10750,11 @@
           case ObjectAccessTargetKind.nullableInlineClassMember:
           case ObjectAccessTargetKind.missing:
           case ObjectAccessTargetKind.ambiguous:
-            // TODO(johnniwinther): Provide the right receiver and argument.
-            node.error = createMissingMethodInvocation(
-                node.fileOffset,
-                new NullLiteral(),
-                node.matchedType,
-                node.name,
-                new Arguments([])..fileOffset = node.fileOffset,
-                isExpressionInvocation: false);
-            node.accessKind = RelationAccessKind.Error;
+            replacement ??= new InvalidPattern(
+                createMissingMethodInvocation(
+                    node.fileOffset, node.matchedType, node.name,
+                    isExpressionInvocation: false),
+                declaredVariables: node.declaredVariables);
             break;
           case ObjectAccessTargetKind.objectMember:
           case ObjectAccessTargetKind.superMember:
@@ -10669,7 +10788,7 @@
         break;
     }
 
-    pushRewrite(node);
+    pushRewrite(replacement ?? node);
 
     assert(checkStack(node, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
@@ -10689,8 +10808,20 @@
             : new MapPatternTypeArguments<DartType>(
                 keyType: node.keyType ?? const DynamicType(),
                 valueType: node.valueType ?? const DynamicType());
-    DartType mapType = analyzeMapPattern(context, node,
-        typeArguments: typeArguments, elements: node.entries);
+    MapPatternResult<DartType, InvalidExpression> analysisResult =
+        analyzeMapPattern(context, node,
+            typeArguments: typeArguments, elements: node.entries);
+
+    Pattern? replacement;
+
+    InvalidExpression? error =
+        analysisResult.patternTypeMismatchInIrrefutableContextError;
+    if (error != null) {
+      replacement =
+          new InvalidPattern(error, declaredVariables: node.declaredVariables);
+    }
+
+    DartType mapType = analysisResult.requiredType;
 
     // TODO(johnniwinther): How does `mapType` relate to `node.mapType`?
     DartType keyType = node.keyType ?? const DynamicType();
@@ -10766,6 +10897,15 @@
 
     for (int i = node.entries.length - 1; i >= 0; i--) {
       Object? rewrite = popRewrite();
+      InvalidExpression? error = analysisResult.duplicateRestPatternErrors?[i];
+      if (error != null) {
+        node.entries[i] = new MapPatternEntry(
+            new ConstantPattern(new NullLiteral()),
+            new InvalidPattern(error,
+                declaredVariables: node.entries[i].value.declaredVariables),
+            node.entries[i].fileOffset)
+          ..parent = node;
+      }
       if (!identical(node.entries[i], rewrite)) {
         node.entries[i] = (rewrite as MapPatternEntry)..parent = node;
       }
@@ -10779,7 +10919,7 @@
       }
     }
 
-    pushRewrite(node);
+    pushRewrite(replacement ?? node);
 
     assert(checkStack(node, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
@@ -10815,12 +10955,24 @@
                 : fieldPattern,
             name: fieldPattern is NamedPattern ? fieldPattern.name : null)
     ];
-    DartType recordType = analyzeRecordPattern(context, node, fields: fields);
+    RecordPatternResult<DartType, InvalidExpression> analysisResult =
+        analyzeRecordPattern(context, node, fields: fields);
 
     assert(checkStack(node, stackBase, [
       /* fields = */ ...repeatedKind(ValueKinds.Pattern, node.patterns.length)
     ]));
 
+    Pattern? replacement;
+
+    InvalidExpression? error =
+        analysisResult.patternTypeMismatchInIrrefutableContextError ??
+            analysisResult.duplicateRecordPatternFieldErrors?.values.first;
+    if (error != null) {
+      replacement =
+          new InvalidPattern(error, declaredVariables: node.declaredVariables);
+    }
+
+    DartType recordType = analysisResult.requiredType;
     node.type = recordType as RecordType;
 
     // TODO(johnniwinther): How does `recordType` relate to `node.recordType`?
@@ -10853,7 +11005,7 @@
       }
     }
 
-    pushRewrite(node);
+    pushRewrite(replacement ?? node);
 
     assert(checkStack(node, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
@@ -10865,10 +11017,8 @@
     int? stackBase;
     assert(checkStackBase(node, stackBase = stackHeight));
 
-    Expression expression = node.expression;
-    Pattern pattern = node.pattern;
     ExpressionTypeAnalysisResult<DartType> analysisResult =
-        analyzePatternAssignment(node, pattern, expression);
+        analyzePatternAssignment(node, node.pattern, node.expression);
 
     assert(checkStack(node, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
@@ -10876,8 +11026,8 @@
     ]));
 
     Object? rewrite = popRewrite();
-    if (!identical(pattern, rewrite)) {
-      pattern = rewrite as Pattern;
+    if (!identical(node.pattern, rewrite)) {
+      node.pattern = rewrite as Pattern..parent = node;
     }
 
     assert(checkStack(node, stackBase, [
@@ -10885,8 +11035,8 @@
     ]));
 
     rewrite = popRewrite();
-    if (!identical(expression, rewrite)) {
-      expression = rewrite as Expression;
+    if (!identical(node.expression, rewrite)) {
+      node.expression = rewrite as Expression..parent = node;
     }
 
     assert(checkStack(node, stackBase, [/*empty*/]));
@@ -10897,7 +11047,7 @@
     // TODO(cstefantsova): Do we need a more precise type for the variable?
     DartType matchedType = const DynamicType();
     CacheableExpression matchedExpression =
-        matchingCache.createRootExpression(expression, matchedType);
+        matchingCache.createRootExpression(node.expression, matchedType);
 
     DelayedExpression matchingExpression =
         matchingExpressionVisitor.visitPattern(node.pattern, matchedExpression);
@@ -10942,6 +11092,7 @@
         matchedType: node.matchedType, requiredType: node.variable.type);
 
     // TODO(johnniwinther): Share this through the type analyzer.
+    Pattern? replacement;
     VariableDeclarationImpl variable = node.variable as VariableDeclarationImpl;
     if (isNonNullableByDefault) {
       bool isDefinitelyAssigned = flowAnalysis.isAssigned(variable);
@@ -10949,32 +11100,47 @@
       if ((variable.isLate && variable.isFinal) ||
           variable.isLateFinalWithoutInitializer) {
         if (isDefinitelyAssigned) {
-          node.error = helper.buildProblem(
-              templateLateDefinitelyAssignedError
-                  .withArguments(node.variable.name!),
-              node.fileOffset,
-              node.variable.name!.length);
+          replacement = new InvalidPattern(
+              helper.buildProblem(
+                  templateLateDefinitelyAssignedError
+                      .withArguments(node.variable.name!),
+                  node.fileOffset,
+                  node.variable.name!.length),
+              declaredVariables: node.declaredVariables);
         }
       } else if (variable.isStaticLate) {
         if (!isDefinitelyUnassigned) {
-          node.error = helper.buildProblem(
-              templateFinalPossiblyAssignedError
-                  .withArguments(node.variable.name!),
-              node.fileOffset,
-              node.variable.name!.length);
+          replacement = new InvalidPattern(
+              helper.buildProblem(
+                  templateFinalPossiblyAssignedError
+                      .withArguments(node.variable.name!),
+                  node.fileOffset,
+                  node.variable.name!.length),
+              declaredVariables: node.declaredVariables);
         }
       } else if (variable.isFinal && variable.hasDeclaredInitializer) {
-        node.error = helper.buildProblem(
-            templateCannotAssignToFinalVariable
-                .withArguments(node.variable.name!),
-            node.fileOffset,
-            node.variable.name!.length);
+        replacement = new InvalidPattern(
+            helper.buildProblem(
+                templateCannotAssignToFinalVariable
+                    .withArguments(node.variable.name!),
+                node.fileOffset,
+                node.variable.name!.length),
+            declaredVariables: node.declaredVariables);
       }
     }
 
-    analyzeAssignedVariablePattern(context, node, node.variable);
+    AssignedVariablePatternResult<InvalidExpression> analysisResult =
+        analyzeAssignedVariablePattern(context, node, node.variable);
 
-    pushRewrite(node);
+    InvalidExpression? error =
+        analysisResult.duplicateAssignmentPatternVariableError ??
+            analysisResult.patternTypeMismatchInIrrefutableContextError;
+    if (error != null) {
+      replacement ??=
+          new InvalidPattern(error, declaredVariables: node.declaredVariables);
+    }
+
+    pushRewrite(replacement ?? node);
 
     assert(checkStack(node, stackBase, [
       /* pattern = */ ValueKinds.Pattern,
diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor_base.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor_base.dart
index 276552d..65cd26f 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor_base.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor_base.dart
@@ -2410,7 +2410,9 @@
     // ignore: unnecessary_null_comparison
     assert(isImplicitCall != null);
     Expression error = createMissingMethodInvocation(
-        fileOffset, receiver, receiverType, name, arguments,
+        fileOffset, receiverType, name,
+        receiver: receiver,
+        arguments: arguments,
         isExpressionInvocation: isExpressionInvocation,
         implicitInvocationPropertyName: implicitInvocationPropertyName,
         extensionAccessCandidates:
@@ -3945,7 +3947,7 @@
       int length,
       DartType receiverType,
       Name name,
-      Expression wrappedExpression,
+      Expression? wrappedExpression,
       List<ExtensionAccessCandidate>? extensionAccessCandidates,
       Template<Message Function(String, DartType, bool)> missingTemplate,
       Template<Message Function(String, DartType, bool)> ambiguousTemplate) {
@@ -3962,37 +3964,60 @@
           .toList();
       template = ambiguousTemplate;
     }
-    return helper.wrapInProblem(
-        wrappedExpression,
-        template.withArguments(name.text, resolveTypeParameter(receiverType),
-            isNonNullableByDefault),
-        fileOffset,
-        length,
-        context: context);
+    if (wrappedExpression != null) {
+      return helper.wrapInProblem(
+          wrappedExpression,
+          template.withArguments(name.text, resolveTypeParameter(receiverType),
+              isNonNullableByDefault),
+          fileOffset,
+          length,
+          context: context);
+    } else {
+      return helper.buildProblem(
+          template.withArguments(name.text, resolveTypeParameter(receiverType),
+              isNonNullableByDefault),
+          fileOffset,
+          length,
+          context: context);
+    }
   }
 
-  Expression createMissingMethodInvocation(int fileOffset, Expression receiver,
-      DartType receiverType, Name name, Arguments arguments,
-      {required bool isExpressionInvocation,
+  Expression createMissingMethodInvocation(
+      int fileOffset, DartType receiverType, Name name,
+      {Expression? receiver,
+      Arguments? arguments,
+      required bool isExpressionInvocation,
       Name? implicitInvocationPropertyName,
       List<ExtensionAccessCandidate>? extensionAccessCandidates}) {
     // ignore: unnecessary_null_comparison
     assert(isExpressionInvocation != null);
+    assert((receiver == null) == (arguments == null),
+        "Receiver and arguments must be supplied together.");
     if (implicitInvocationPropertyName != null) {
       assert(extensionAccessCandidates == null);
-      return helper.wrapInProblem(
-          _createInvalidInvocation(fileOffset, receiver, name, arguments),
-          templateInvokeNonFunction
-              .withArguments(implicitInvocationPropertyName.text),
-          fileOffset,
-          implicitInvocationPropertyName.text.length);
+      if (receiver != null) {
+        return helper.wrapInProblem(
+            _createInvalidInvocation(fileOffset, receiver, name, arguments!),
+            templateInvokeNonFunction
+                .withArguments(implicitInvocationPropertyName.text),
+            fileOffset,
+            implicitInvocationPropertyName.text.length);
+      } else {
+        return helper.buildProblem(
+            templateInvokeNonFunction
+                .withArguments(implicitInvocationPropertyName.text),
+            fileOffset,
+            implicitInvocationPropertyName.text.length);
+      }
     } else {
       return _reportMissingOrAmbiguousMember(
           fileOffset,
           isExpressionInvocation ? noLength : name.text.length,
           receiverType,
           name,
-          _createInvalidInvocation(fileOffset, receiver, name, arguments),
+          receiver != null
+              ? _createInvalidInvocation(fileOffset, receiver, name, arguments!)
+              : null,
           extensionAccessCandidates,
           receiverType is ExtensionType
               ? templateUndefinedExtensionMethod
@@ -4021,12 +4046,12 @@
 
     switch (readTarget.kind) {
       case ObjectAccessTargetKind.missing:
-        read = createMissingPropertyGet(
-            fileOffset, receiver, receiverType, propertyName);
+        read = createMissingPropertyGet(fileOffset, receiverType, propertyName,
+            receiver: receiver);
         break;
       case ObjectAccessTargetKind.ambiguous:
-        read = createMissingPropertyGet(
-            fileOffset, receiver, receiverType, propertyName,
+        read = createMissingPropertyGet(fileOffset, receiverType, propertyName,
+            receiver: receiver,
             extensionAccessCandidates: readTarget.candidates);
         break;
       case ObjectAccessTargetKind.extensionMember:
@@ -4184,9 +4209,10 @@
     return new PropertyGetInferenceResult(readResult, readTarget.member);
   }
 
-  Expression createMissingPropertyGet(int fileOffset, Expression receiver,
-      DartType receiverType, Name propertyName,
-      {List<ExtensionAccessCandidate>? extensionAccessCandidates}) {
+  Expression createMissingPropertyGet(
+      int fileOffset, DartType receiverType, Name propertyName,
+      {Expression? receiver,
+      List<ExtensionAccessCandidate>? extensionAccessCandidates}) {
     Template<Message Function(String, DartType, bool)> templateMissing;
     if (receiverType is ExtensionType) {
       templateMissing = templateUndefinedExtensionGetter;
@@ -4198,7 +4224,9 @@
         propertyName.text.length,
         receiverType,
         propertyName,
-        _createInvalidGet(fileOffset, receiver, propertyName),
+        receiver != null
+            ? _createInvalidGet(fileOffset, receiver, propertyName)
+            : null,
         extensionAccessCandidates,
         templateMissing,
         templateAmbiguousExtensionProperty);
diff --git a/pkg/front_end/lib/src/fasta/type_inference/matching_expressions.dart b/pkg/front_end/lib/src/fasta/type_inference/matching_expressions.dart
index 86aa205..be89351 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/matching_expressions.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/matching_expressions.dart
@@ -19,9 +19,6 @@
 
   DelayedExpression visitPattern(
       Pattern node, CacheableExpression matchedExpression) {
-    if (node.error != null) {
-      return new FixedExpression(node.error!, const InvalidType());
-    }
     return node.acceptPattern1(this, matchedExpression);
   }
 
@@ -459,7 +456,9 @@
               fileOffset: field.fileOffset);
           break;
         case ObjectAccessKind.Error:
-          expression = new FixedExpression(field.error!, const InvalidType());
+          expression = new FixedExpression(
+              (field.pattern as InvalidPattern).invalidExpression,
+              const InvalidType());
           break;
       }
       CacheableExpression objectExpression =
@@ -622,9 +621,6 @@
                 const InvalidType(),
                 fileOffset: node.fileOffset);
             break;
-          case RelationAccessKind.Error:
-            expression = new FixedExpression(node.error!, const InvalidType());
-            break;
         }
         return matchingCache.createComparisonExpression(
             matchedExpression, node.name.text, constant, expression,
diff --git a/pkg/front_end/lib/src/fasta/type_inference/shared_type_analyzer.dart b/pkg/front_end/lib/src/fasta/type_inference/shared_type_analyzer.dart
index e86f8ce..c6a523f 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/shared_type_analyzer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/shared_type_analyzer.dart
@@ -19,7 +19,7 @@
 class SharedTypeAnalyzerErrors
     implements
         TypeAnalyzerErrors<TreeNode, Statement, Expression, VariableDeclaration,
-            DartType, Pattern> {
+            DartType, Pattern, InvalidExpression> {
   final InferenceVisitorImpl visitor;
   final InferenceHelper helper;
 
@@ -37,12 +37,12 @@
       required this.isNonNullableByDefault});
 
   @override
-  void argumentTypeNotAssignable({
+  InvalidExpression argumentTypeNotAssignable({
     required Expression argument,
     required DartType argumentType,
     required DartType parameterType,
   }) {
-    helper.addProblem(
+    return helper.buildProblem(
         templateArgumentTypeNotAssignable.withArguments(
             argumentType, parameterType, isNonNullableByDefault),
         argument.fileOffset,
@@ -55,13 +55,13 @@
   }
 
   @override
-  void caseExpressionTypeMismatch(
+  InvalidExpression caseExpressionTypeMismatch(
       {required Expression scrutinee,
       required Expression caseExpression,
       required DartType caseExpressionType,
       required DartType scrutineeType,
       required bool nullSafetyEnabled}) {
-    helper.addProblem(
+    return helper.buildProblem(
         nullSafetyEnabled
             ? templateSwitchExpressionNotSubtype.withArguments(
                 caseExpressionType, scrutineeType, nullSafetyEnabled)
@@ -76,12 +76,12 @@
   }
 
   @override
-  void duplicateAssignmentPatternVariable({
+  InvalidExpression duplicateAssignmentPatternVariable({
     required VariableDeclaration variable,
     required Pattern original,
     required Pattern duplicate,
   }) {
-    duplicate.error = helper.buildProblem(
+    return helper.buildProblem(
         templateDuplicatePatternAssignmentVariable
             .withArguments(variable.name!),
         duplicate.fileOffset,
@@ -93,13 +93,13 @@
   }
 
   @override
-  void duplicateRecordPatternField({
+  InvalidExpression duplicateRecordPatternField({
     required Pattern objectOrRecordPattern,
     required String name,
     required RecordPatternField<TreeNode, Pattern> original,
     required RecordPatternField<TreeNode, Pattern> duplicate,
   }) {
-    objectOrRecordPattern.error = helper.buildProblem(
+    return helper.buildProblem(
         templateDuplicateRecordPatternField.withArguments(name),
         duplicate.pattern.fileOffset,
         noLength,
@@ -110,12 +110,12 @@
   }
 
   @override
-  void duplicateRestPattern({
+  InvalidExpression duplicateRestPattern({
     required Pattern mapOrListPattern,
     required TreeNode original,
     required TreeNode duplicate,
   }) {
-    mapOrListPattern.error = helper.buildProblem(
+    return helper.buildProblem(
         messageDuplicateRestElementInPattern, duplicate.fileOffset, noLength,
         context: [
           messageDuplicateRestElementInPatternContext.withLocation(
@@ -130,19 +130,21 @@
   }) {
     // TODO(cstefantsova): Currently this error is reported elsewhere due to
     // the order the types are inferred.
+    // TODO(johnniwinther): How should we handle errors that are not report
+    // here? Should we have a sentinel error node, allow a nullable result, or ?
   }
 
   @override
-  void matchedTypeIsStrictlyNonNullable({
+  InvalidExpression matchedTypeIsStrictlyNonNullable({
     required Pattern pattern,
     required DartType matchedType,
   }) {
     // These are only warnings, so we don't update `pattern.error`.
     if (pattern is NullAssertPattern) {
-      helper.addProblem(
+      return helper.buildProblem(
           messageUnnecessaryNullAssertPattern, pattern.fileOffset, noLength);
     } else {
-      helper.addProblem(
+      return helper.buildProblem(
           messageUnnecessaryNullCheckPattern, pattern.fileOffset, noLength);
     }
   }
@@ -157,10 +159,9 @@
   }
 
   @override
-  void nonBooleanCondition({required Expression node}) {
-    // TODO(johnniwinther): Find a way to propagate the error state to the
-    // parent of the guard.
-    helper.addProblem(messageNonBoolCondition, node.fileOffset, noLength);
+  InvalidExpression nonBooleanCondition({required Expression node}) {
+    return helper.buildProblem(
+        messageNonBoolCondition, node.fileOffset, noLength);
   }
 
   @override
@@ -170,7 +171,7 @@
   }
 
   @override
-  void nonExhaustiveSwitch(
+  InvalidExpression nonExhaustiveSwitch(
       {required TreeNode node, required DartType scrutineeType}) {
     // Report the error on the scrutinee expression, to match what the full
     // exhaustiveness algorithm does
@@ -180,7 +181,7 @@
     } else {
       fileOffset = (node as SwitchExpression).expression.fileOffset;
     }
-    helper.addProblem(
+    return helper.buildProblem(
         templateNonExhaustiveSwitch.withArguments(scrutineeType,
             scrutineeType.toText(textStrategy), isNonNullableByDefault),
         fileOffset,
@@ -188,7 +189,7 @@
   }
 
   @override
-  void patternForInExpressionIsNotIterable({
+  InvalidExpression patternForInExpressionIsNotIterable({
     required TreeNode node,
     required Expression expression,
     required DartType expressionType,
@@ -197,12 +198,12 @@
   }
 
   @override
-  void patternTypeMismatchInIrrefutableContext(
+  InvalidExpression patternTypeMismatchInIrrefutableContext(
       {required Pattern pattern,
       required TreeNode context,
       required DartType matchedType,
       required DartType requiredType}) {
-    pattern.error = helper.buildProblem(
+    return helper.buildProblem(
         templatePatternTypeMismatchInIrrefutableContext.withArguments(
             matchedType, requiredType, isNonNullableByDefault),
         pattern.fileOffset,
@@ -210,20 +211,18 @@
   }
 
   @override
-  void refutablePatternInIrrefutableContext(
+  InvalidExpression refutablePatternInIrrefutableContext(
       {required covariant Pattern pattern, required TreeNode context}) {
-    pattern.error = helper.buildProblem(
-        messageRefutablePatternInIrrefutableContext,
-        pattern.fileOffset,
-        noLength);
+    return helper.buildProblem(messageRefutablePatternInIrrefutableContext,
+        pattern.fileOffset, noLength);
   }
 
   @override
-  void relationalPatternOperatorReturnTypeNotAssignableToBool({
+  InvalidExpression relationalPatternOperatorReturnTypeNotAssignableToBool({
     required Pattern pattern,
     required DartType returnType,
   }) {
-    pattern.error = helper.buildProblem(
+    return helper.buildProblem(
         templateInvalidAssignmentError.withArguments(returnType,
             coreTypes.boolNonNullableRawType, isNonNullableByDefault),
         pattern.fileOffset,
@@ -243,9 +242,9 @@
   }
 
   @override
-  void switchCaseCompletesNormally(
+  InvalidExpression switchCaseCompletesNormally(
       {required covariant SwitchStatement node, required int caseIndex}) {
-    helper.addProblem(messageSwitchCaseFallThrough,
+    return helper.buildProblem(messageSwitchCaseFallThrough,
         node.cases[caseIndex].fileOffset, noLength);
   }
 
diff --git a/pkg/front_end/testcases/class_modifiers/subtype_function.dart.strong.expect b/pkg/front_end/testcases/class_modifiers/subtype_function.dart.strong.expect
index c7953d7..6cfad95 100644
--- a/pkg/front_end/testcases/class_modifiers/subtype_function.dart.strong.expect
+++ b/pkg/front_end/testcases/class_modifiers/subtype_function.dart.strong.expect
@@ -2,10 +2,37 @@
 //
 // Problems in library:
 //
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:7: Error: The type 'A' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class A extends Function {}
+//       ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:17: Error: The class 'Function' can't be extended outside of its library because it's a final class.
+// class A extends Function {}
+//                 ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:7:7: Error: The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class B implements Function {}
+//       ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:7:20: Error: The class 'Function' can't be implemented outside of its library because it's a final class.
+// class B implements Function {}
+//                    ^
+//
 // pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:14: Error: The class 'Function' can't be used as a mixin because it isn't a mixin class nor a mixin.
 // class C with Function {}
 //              ^
 //
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:14: Error: The mixin 'Function' can't be mixed-in outside of its library because it's a final mixin.
+// class C with Function {}
+//              ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:7: Error: The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class C with Function {}
+//       ^
+//
 // pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:7: Error: Extending 'Function' is deprecated because 'Function' is final class.
 // Try removing 'Function' from the 'extends' clause.
 // class A extends Function {}
diff --git a/pkg/front_end/testcases/class_modifiers/subtype_function.dart.strong.transformed.expect b/pkg/front_end/testcases/class_modifiers/subtype_function.dart.strong.transformed.expect
index c7953d7..6cfad95 100644
--- a/pkg/front_end/testcases/class_modifiers/subtype_function.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/class_modifiers/subtype_function.dart.strong.transformed.expect
@@ -2,10 +2,37 @@
 //
 // Problems in library:
 //
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:7: Error: The type 'A' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class A extends Function {}
+//       ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:17: Error: The class 'Function' can't be extended outside of its library because it's a final class.
+// class A extends Function {}
+//                 ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:7:7: Error: The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class B implements Function {}
+//       ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:7:20: Error: The class 'Function' can't be implemented outside of its library because it's a final class.
+// class B implements Function {}
+//                    ^
+//
 // pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:14: Error: The class 'Function' can't be used as a mixin because it isn't a mixin class nor a mixin.
 // class C with Function {}
 //              ^
 //
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:14: Error: The mixin 'Function' can't be mixed-in outside of its library because it's a final mixin.
+// class C with Function {}
+//              ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:7: Error: The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class C with Function {}
+//       ^
+//
 // pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:7: Error: Extending 'Function' is deprecated because 'Function' is final class.
 // Try removing 'Function' from the 'extends' clause.
 // class A extends Function {}
diff --git a/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.expect b/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.expect
index c7953d7..6cfad95 100644
--- a/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.expect
+++ b/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.expect
@@ -2,10 +2,37 @@
 //
 // Problems in library:
 //
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:7: Error: The type 'A' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class A extends Function {}
+//       ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:17: Error: The class 'Function' can't be extended outside of its library because it's a final class.
+// class A extends Function {}
+//                 ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:7:7: Error: The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class B implements Function {}
+//       ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:7:20: Error: The class 'Function' can't be implemented outside of its library because it's a final class.
+// class B implements Function {}
+//                    ^
+//
 // pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:14: Error: The class 'Function' can't be used as a mixin because it isn't a mixin class nor a mixin.
 // class C with Function {}
 //              ^
 //
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:14: Error: The mixin 'Function' can't be mixed-in outside of its library because it's a final mixin.
+// class C with Function {}
+//              ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:7: Error: The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class C with Function {}
+//       ^
+//
 // pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:7: Error: Extending 'Function' is deprecated because 'Function' is final class.
 // Try removing 'Function' from the 'extends' clause.
 // class A extends Function {}
diff --git a/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.modular.expect b/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.modular.expect
index c7953d7..6cfad95 100644
--- a/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.modular.expect
@@ -2,10 +2,37 @@
 //
 // Problems in library:
 //
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:7: Error: The type 'A' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class A extends Function {}
+//       ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:17: Error: The class 'Function' can't be extended outside of its library because it's a final class.
+// class A extends Function {}
+//                 ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:7:7: Error: The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class B implements Function {}
+//       ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:7:20: Error: The class 'Function' can't be implemented outside of its library because it's a final class.
+// class B implements Function {}
+//                    ^
+//
 // pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:14: Error: The class 'Function' can't be used as a mixin because it isn't a mixin class nor a mixin.
 // class C with Function {}
 //              ^
 //
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:14: Error: The mixin 'Function' can't be mixed-in outside of its library because it's a final mixin.
+// class C with Function {}
+//              ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:7: Error: The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class C with Function {}
+//       ^
+//
 // pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:7: Error: Extending 'Function' is deprecated because 'Function' is final class.
 // Try removing 'Function' from the 'extends' clause.
 // class A extends Function {}
diff --git a/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.outline.expect b/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.outline.expect
index e4913a1..94939a4 100644
--- a/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.outline.expect
@@ -2,10 +2,37 @@
 //
 // Problems in library:
 //
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:7: Error: The type 'A' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class A extends Function {}
+//       ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:17: Error: The class 'Function' can't be extended outside of its library because it's a final class.
+// class A extends Function {}
+//                 ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:7:7: Error: The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class B implements Function {}
+//       ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:7:20: Error: The class 'Function' can't be implemented outside of its library because it's a final class.
+// class B implements Function {}
+//                    ^
+//
 // pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:14: Error: The class 'Function' can't be used as a mixin because it isn't a mixin class nor a mixin.
 // class C with Function {}
 //              ^
 //
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:14: Error: The mixin 'Function' can't be mixed-in outside of its library because it's a final mixin.
+// class C with Function {}
+//              ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:7: Error: The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class C with Function {}
+//       ^
+//
 // pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:7: Error: Extending 'Function' is deprecated because 'Function' is final class.
 // Try removing 'Function' from the 'extends' clause.
 // class A extends Function {}
diff --git a/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.transformed.expect b/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.transformed.expect
index c7953d7..6cfad95 100644
--- a/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/class_modifiers/subtype_function.dart.weak.transformed.expect
@@ -2,10 +2,37 @@
 //
 // Problems in library:
 //
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:7: Error: The type 'A' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class A extends Function {}
+//       ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:17: Error: The class 'Function' can't be extended outside of its library because it's a final class.
+// class A extends Function {}
+//                 ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:7:7: Error: The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class B implements Function {}
+//       ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:7:20: Error: The class 'Function' can't be implemented outside of its library because it's a final class.
+// class B implements Function {}
+//                    ^
+//
 // pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:14: Error: The class 'Function' can't be used as a mixin because it isn't a mixin class nor a mixin.
 // class C with Function {}
 //              ^
 //
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:14: Error: The mixin 'Function' can't be mixed-in outside of its library because it's a final mixin.
+// class C with Function {}
+//              ^
+//
+// pkg/front_end/testcases/class_modifiers/subtype_function.dart:9:7: Error: The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'Function' is 'final'.
+// Try adding 'base', 'final', or 'sealed' to the type.
+// class C with Function {}
+//       ^
+//
 // pkg/front_end/testcases/class_modifiers/subtype_function.dart:5:7: Error: Extending 'Function' is deprecated because 'Function' is final class.
 // Try removing 'Function' from the 'extends' clause.
 // class A extends Function {}
diff --git a/pkg/front_end/testcases/modular.status b/pkg/front_end/testcases/modular.status
index 4211ebc..36480fe 100644
--- a/pkg/front_end/testcases/modular.status
+++ b/pkg/front_end/testcases/modular.status
@@ -85,5 +85,4 @@
 nnbd_mixed/messages_with_types_opt_out: TypeCheckError
 no_such_method_forwarders/mixin_nsm: TypeCheckError
 patterns/pattern_types: TypeCheckError
-patterns/shared_errors: TypeCheckError
 runtime_checks_new/mixin_forwarding_stub_getter: TypeCheckError
diff --git a/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart
new file mode 100644
index 0000000..3d6741b
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart
@@ -0,0 +1,9 @@
+// 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.
+
+method() {
+  var ([double v1] && [num v2]) = [42];
+  print(v1);
+  print(v2);
+}
diff --git a/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.strong.expect b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.strong.expect
new file mode 100644
index 0000000..22c9007
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.strong.expect
@@ -0,0 +1,22 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method method() → dynamic {
+  core::double v1;
+  core::num v2;
+  {
+    final dynamic #0#0 = <core::double>[42.0];
+    late final core::bool #0#3 = #0#0{core::List<core::double>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1;
+    late final core::double #0#4 = #0#0{core::List<core::double>}.{core::List::[]}(0){(core::int) → core::double};
+    if(!(#0#3 && (#0#4 is{ForNonNullableByDefault} core::double && (let final dynamic #t1 = v1 = #0#4 in true)) && (#0#3 && (#0#4 is{ForNonNullableByDefault} core::num && (let final dynamic #t2 = v2 = #0#4 in true)))))
+      throw new _in::ReachabilityError::•();
+  }
+  core::print(v1);
+  core::print(v2);
+}
+
+constants  {
+  #C1 = 1
+}
diff --git a/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.strong.transformed.expect
new file mode 100644
index 0000000..05d0615
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.strong.transformed.expect
@@ -0,0 +1,26 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method method() → dynamic {
+  core::double v1;
+  core::num v2;
+  {
+    final dynamic #0#0 = core::_GrowableList::_literal1<core::double>(42.0);
+    function ##0#3#initializer() → core::bool
+      return #0#0{core::List<core::double>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1;
+    late final core::bool #0#3 = ##0#3#initializer(){() → core::bool};
+    function ##0#4#initializer() → core::double
+      return #0#0{core::List<core::double>}.{core::List::[]}(0){(core::int) → core::double};
+    late final core::double #0#4 = ##0#4#initializer(){() → core::double};
+    if(!(#0#3 && (#0#4 is{ForNonNullableByDefault} core::double && (let final core::double #t1 = v1 = #0#4 in true)) && (#0#3 && (#0#4 is{ForNonNullableByDefault} core::num && (let final core::double #t2 = v2 = #0#4 in true)))))
+      throw new _in::ReachabilityError::•();
+  }
+  core::print(v1);
+  core::print(v2);
+}
+
+constants  {
+  #C1 = 1
+}
diff --git a/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.textual_outline.expect b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.textual_outline.expect
new file mode 100644
index 0000000..83d2302
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.textual_outline.expect
@@ -0,0 +1 @@
+method() {}
diff --git a/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..83d2302
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.textual_outline_modelled.expect
@@ -0,0 +1 @@
+method() {}
diff --git a/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.weak.expect b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.weak.expect
new file mode 100644
index 0000000..22c9007
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.weak.expect
@@ -0,0 +1,22 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method method() → dynamic {
+  core::double v1;
+  core::num v2;
+  {
+    final dynamic #0#0 = <core::double>[42.0];
+    late final core::bool #0#3 = #0#0{core::List<core::double>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1;
+    late final core::double #0#4 = #0#0{core::List<core::double>}.{core::List::[]}(0){(core::int) → core::double};
+    if(!(#0#3 && (#0#4 is{ForNonNullableByDefault} core::double && (let final dynamic #t1 = v1 = #0#4 in true)) && (#0#3 && (#0#4 is{ForNonNullableByDefault} core::num && (let final dynamic #t2 = v2 = #0#4 in true)))))
+      throw new _in::ReachabilityError::•();
+  }
+  core::print(v1);
+  core::print(v2);
+}
+
+constants  {
+  #C1 = 1
+}
diff --git a/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.weak.modular.expect b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.weak.modular.expect
new file mode 100644
index 0000000..22c9007
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.weak.modular.expect
@@ -0,0 +1,22 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method method() → dynamic {
+  core::double v1;
+  core::num v2;
+  {
+    final dynamic #0#0 = <core::double>[42.0];
+    late final core::bool #0#3 = #0#0{core::List<core::double>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1;
+    late final core::double #0#4 = #0#0{core::List<core::double>}.{core::List::[]}(0){(core::int) → core::double};
+    if(!(#0#3 && (#0#4 is{ForNonNullableByDefault} core::double && (let final dynamic #t1 = v1 = #0#4 in true)) && (#0#3 && (#0#4 is{ForNonNullableByDefault} core::num && (let final dynamic #t2 = v2 = #0#4 in true)))))
+      throw new _in::ReachabilityError::•();
+  }
+  core::print(v1);
+  core::print(v2);
+}
+
+constants  {
+  #C1 = 1
+}
diff --git a/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.weak.outline.expect b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.weak.outline.expect
new file mode 100644
index 0000000..befb402
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.weak.outline.expect
@@ -0,0 +1,5 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+static method method() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.weak.transformed.expect b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.weak.transformed.expect
new file mode 100644
index 0000000..05d0615
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/invalid_pattern_declares_variables.dart.weak.transformed.expect
@@ -0,0 +1,26 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method method() → dynamic {
+  core::double v1;
+  core::num v2;
+  {
+    final dynamic #0#0 = core::_GrowableList::_literal1<core::double>(42.0);
+    function ##0#3#initializer() → core::bool
+      return #0#0{core::List<core::double>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1;
+    late final core::bool #0#3 = ##0#3#initializer(){() → core::bool};
+    function ##0#4#initializer() → core::double
+      return #0#0{core::List<core::double>}.{core::List::[]}(0){(core::int) → core::double};
+    late final core::double #0#4 = ##0#4#initializer(){() → core::double};
+    if(!(#0#3 && (#0#4 is{ForNonNullableByDefault} core::double && (let final core::double #t1 = v1 = #0#4 in true)) && (#0#3 && (#0#4 is{ForNonNullableByDefault} core::num && (let final core::double #t2 = v2 = #0#4 in true)))))
+      throw new _in::ReachabilityError::•();
+  }
+  core::print(v1);
+  core::print(v2);
+}
+
+constants  {
+  #C1 = 1
+}
diff --git a/pkg/front_end/testcases/patterns/non_bool_guard.dart b/pkg/front_end/testcases/patterns/non_bool_guard.dart
new file mode 100644
index 0000000..a1edb72
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/non_bool_guard.dart
@@ -0,0 +1,25 @@
+// 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.
+
+String test1(List<int> v) {
+  switch (v) {
+    case [var a, _] when a - 1:
+      return "match";
+    default:
+      return "no match";
+  }
+}
+
+String test2(List<int> v) {
+  if (v case [var a, _] when a - 1) {
+    return "match";
+  }
+  return "no match";
+}
+
+String test3(List<int> v) =>
+  switch (v) {
+    [var a, _] when a - 1 => "match",
+    _ => "no match"
+  };
diff --git a/pkg/front_end/testcases/patterns/non_bool_guard.dart.strong.expect b/pkg/front_end/testcases/patterns/non_bool_guard.dart.strong.expect
new file mode 100644
index 0000000..c6f1884
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/non_bool_guard.dart.strong.expect
@@ -0,0 +1,73 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/non_bool_guard.dart:7:28: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//     case [var a, _] when a - 1:
+//                            ^
+//
+// pkg/front_end/testcases/patterns/non_bool_guard.dart:15:32: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//   if (v case [var a, _] when a - 1) {
+//                                ^
+//
+// pkg/front_end/testcases/patterns/non_bool_guard.dart:23:23: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//     [var a, _] when a - 1 => "match",
+//                       ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method test1(core::List<core::int> v) → core::String {
+  #L1:
+  {
+    core::int a;
+    final core::List<core::int> #0#0 = v;
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t1 = a = #0#0.{core::List::[]}(0){(core::int) → core::int} in true) && (let final dynamic #t2 = #0#0.{core::List::[]}(1){(core::int) → core::int} in true) && invalid-expression "pkg/front_end/testcases/patterns/non_bool_guard.dart:7:28: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+    case [var a, _] when a - 1:
+                           ^") {
+      {
+        return "match";
+      }
+    }
+    else {
+      {
+        return "no match";
+      }
+    }
+  }
+}
+static method test2(core::List<core::int> v) → core::String {
+  {
+    core::int a;
+    final core::List<core::int> #0#0 = v;
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t3 = a = #0#0.{core::List::[]}(0){(core::int) → core::int} in true) && (let final dynamic #t4 = #0#0.{core::List::[]}(1){(core::int) → core::int} in true) && invalid-expression "pkg/front_end/testcases/patterns/non_bool_guard.dart:15:32: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+  if (v case [var a, _] when a - 1) {
+                               ^") {
+      return "match";
+    }
+  }
+  return "no match";
+}
+static method test3(core::List<core::int> v) → core::String
+  return block {
+    core::String #t5;
+    core::int a;
+    final core::List<core::int> #0#0 = v;
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t6 = a = #0#0.{core::List::[]}(0){(core::int) → core::int} in true) && (let final dynamic #t7 = #0#0.{core::List::[]}(1){(core::int) → core::int} in true) && invalid-expression "pkg/front_end/testcases/patterns/non_bool_guard.dart:23:23: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+    [var a, _] when a - 1 => \"match\",
+                      ^")
+      #t5 = "match";
+    else
+      if(true)
+        #t5 = "no match";
+  } =>#t5;
+
+constants  {
+  #C1 = 2
+}
diff --git a/pkg/front_end/testcases/patterns/non_bool_guard.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/non_bool_guard.dart.strong.transformed.expect
new file mode 100644
index 0000000..3b921f5
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/non_bool_guard.dart.strong.transformed.expect
@@ -0,0 +1,73 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/non_bool_guard.dart:7:28: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//     case [var a, _] when a - 1:
+//                            ^
+//
+// pkg/front_end/testcases/patterns/non_bool_guard.dart:15:32: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//   if (v case [var a, _] when a - 1) {
+//                                ^
+//
+// pkg/front_end/testcases/patterns/non_bool_guard.dart:23:23: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//     [var a, _] when a - 1 => "match",
+//                       ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method test1(core::List<core::int> v) → core::String {
+  #L1:
+  {
+    core::int a;
+    final core::List<core::int> #0#0 = v;
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final core::int #t1 = a = #0#0.{core::List::[]}(0){(core::int) → core::int} in true) && (let final core::int #t2 = #0#0.{core::List::[]}(1){(core::int) → core::int} in true) && invalid-expression "pkg/front_end/testcases/patterns/non_bool_guard.dart:7:28: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+    case [var a, _] when a - 1:
+                           ^") {
+      {
+        return "match";
+      }
+    }
+    else {
+      {
+        return "no match";
+      }
+    }
+  }
+}
+static method test2(core::List<core::int> v) → core::String {
+  {
+    core::int a;
+    final core::List<core::int> #0#0 = v;
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final core::int #t3 = a = #0#0.{core::List::[]}(0){(core::int) → core::int} in true) && (let final core::int #t4 = #0#0.{core::List::[]}(1){(core::int) → core::int} in true) && invalid-expression "pkg/front_end/testcases/patterns/non_bool_guard.dart:15:32: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+  if (v case [var a, _] when a - 1) {
+                               ^") {
+      return "match";
+    }
+  }
+  return "no match";
+}
+static method test3(core::List<core::int> v) → core::String
+  return block {
+    core::String #t5;
+    core::int a;
+    final core::List<core::int> #0#0 = v;
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final core::int #t6 = a = #0#0.{core::List::[]}(0){(core::int) → core::int} in true) && (let final core::int #t7 = #0#0.{core::List::[]}(1){(core::int) → core::int} in true) && invalid-expression "pkg/front_end/testcases/patterns/non_bool_guard.dart:23:23: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+    [var a, _] when a - 1 => \"match\",
+                      ^")
+      #t5 = "match";
+    else
+      if(true)
+        #t5 = "no match";
+  } =>#t5;
+
+constants  {
+  #C1 = 2
+}
diff --git a/pkg/front_end/testcases/patterns/non_bool_guard.dart.textual_outline.expect b/pkg/front_end/testcases/patterns/non_bool_guard.dart.textual_outline.expect
new file mode 100644
index 0000000..e4559d3
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/non_bool_guard.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+String test1(List<int> v) {}
+String test2(List<int> v) {}
+String test3(List<int> v) => switch (v) {  };
diff --git a/pkg/front_end/testcases/patterns/non_bool_guard.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/patterns/non_bool_guard.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..c4d75c0
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/non_bool_guard.dart.textual_outline_modelled.expect
@@ -0,0 +1,7 @@
+String test1(List<int> v) {}
+String test2(List<int> v) {}
+String test3(List<int> v) => 
+switch (v) {}
+---- unknown chunk starts ----
+;
+---- unknown chunk ends ----
diff --git a/pkg/front_end/testcases/patterns/non_bool_guard.dart.weak.expect b/pkg/front_end/testcases/patterns/non_bool_guard.dart.weak.expect
new file mode 100644
index 0000000..c6f1884
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/non_bool_guard.dart.weak.expect
@@ -0,0 +1,73 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/non_bool_guard.dart:7:28: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//     case [var a, _] when a - 1:
+//                            ^
+//
+// pkg/front_end/testcases/patterns/non_bool_guard.dart:15:32: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//   if (v case [var a, _] when a - 1) {
+//                                ^
+//
+// pkg/front_end/testcases/patterns/non_bool_guard.dart:23:23: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//     [var a, _] when a - 1 => "match",
+//                       ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method test1(core::List<core::int> v) → core::String {
+  #L1:
+  {
+    core::int a;
+    final core::List<core::int> #0#0 = v;
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t1 = a = #0#0.{core::List::[]}(0){(core::int) → core::int} in true) && (let final dynamic #t2 = #0#0.{core::List::[]}(1){(core::int) → core::int} in true) && invalid-expression "pkg/front_end/testcases/patterns/non_bool_guard.dart:7:28: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+    case [var a, _] when a - 1:
+                           ^") {
+      {
+        return "match";
+      }
+    }
+    else {
+      {
+        return "no match";
+      }
+    }
+  }
+}
+static method test2(core::List<core::int> v) → core::String {
+  {
+    core::int a;
+    final core::List<core::int> #0#0 = v;
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t3 = a = #0#0.{core::List::[]}(0){(core::int) → core::int} in true) && (let final dynamic #t4 = #0#0.{core::List::[]}(1){(core::int) → core::int} in true) && invalid-expression "pkg/front_end/testcases/patterns/non_bool_guard.dart:15:32: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+  if (v case [var a, _] when a - 1) {
+                               ^") {
+      return "match";
+    }
+  }
+  return "no match";
+}
+static method test3(core::List<core::int> v) → core::String
+  return block {
+    core::String #t5;
+    core::int a;
+    final core::List<core::int> #0#0 = v;
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t6 = a = #0#0.{core::List::[]}(0){(core::int) → core::int} in true) && (let final dynamic #t7 = #0#0.{core::List::[]}(1){(core::int) → core::int} in true) && invalid-expression "pkg/front_end/testcases/patterns/non_bool_guard.dart:23:23: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+    [var a, _] when a - 1 => \"match\",
+                      ^")
+      #t5 = "match";
+    else
+      if(true)
+        #t5 = "no match";
+  } =>#t5;
+
+constants  {
+  #C1 = 2
+}
diff --git a/pkg/front_end/testcases/patterns/non_bool_guard.dart.weak.modular.expect b/pkg/front_end/testcases/patterns/non_bool_guard.dart.weak.modular.expect
new file mode 100644
index 0000000..c6f1884
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/non_bool_guard.dart.weak.modular.expect
@@ -0,0 +1,73 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/non_bool_guard.dart:7:28: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//     case [var a, _] when a - 1:
+//                            ^
+//
+// pkg/front_end/testcases/patterns/non_bool_guard.dart:15:32: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//   if (v case [var a, _] when a - 1) {
+//                                ^
+//
+// pkg/front_end/testcases/patterns/non_bool_guard.dart:23:23: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//     [var a, _] when a - 1 => "match",
+//                       ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method test1(core::List<core::int> v) → core::String {
+  #L1:
+  {
+    core::int a;
+    final core::List<core::int> #0#0 = v;
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t1 = a = #0#0.{core::List::[]}(0){(core::int) → core::int} in true) && (let final dynamic #t2 = #0#0.{core::List::[]}(1){(core::int) → core::int} in true) && invalid-expression "pkg/front_end/testcases/patterns/non_bool_guard.dart:7:28: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+    case [var a, _] when a - 1:
+                           ^") {
+      {
+        return "match";
+      }
+    }
+    else {
+      {
+        return "no match";
+      }
+    }
+  }
+}
+static method test2(core::List<core::int> v) → core::String {
+  {
+    core::int a;
+    final core::List<core::int> #0#0 = v;
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t3 = a = #0#0.{core::List::[]}(0){(core::int) → core::int} in true) && (let final dynamic #t4 = #0#0.{core::List::[]}(1){(core::int) → core::int} in true) && invalid-expression "pkg/front_end/testcases/patterns/non_bool_guard.dart:15:32: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+  if (v case [var a, _] when a - 1) {
+                               ^") {
+      return "match";
+    }
+  }
+  return "no match";
+}
+static method test3(core::List<core::int> v) → core::String
+  return block {
+    core::String #t5;
+    core::int a;
+    final core::List<core::int> #0#0 = v;
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t6 = a = #0#0.{core::List::[]}(0){(core::int) → core::int} in true) && (let final dynamic #t7 = #0#0.{core::List::[]}(1){(core::int) → core::int} in true) && invalid-expression "pkg/front_end/testcases/patterns/non_bool_guard.dart:23:23: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+    [var a, _] when a - 1 => \"match\",
+                      ^")
+      #t5 = "match";
+    else
+      if(true)
+        #t5 = "no match";
+  } =>#t5;
+
+constants  {
+  #C1 = 2
+}
diff --git a/pkg/front_end/testcases/patterns/non_bool_guard.dart.weak.outline.expect b/pkg/front_end/testcases/patterns/non_bool_guard.dart.weak.outline.expect
new file mode 100644
index 0000000..46f1fb3
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/non_bool_guard.dart.weak.outline.expect
@@ -0,0 +1,10 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method test1(core::List<core::int> v) → core::String
+  ;
+static method test2(core::List<core::int> v) → core::String
+  ;
+static method test3(core::List<core::int> v) → core::String
+  ;
diff --git a/pkg/front_end/testcases/patterns/non_bool_guard.dart.weak.transformed.expect b/pkg/front_end/testcases/patterns/non_bool_guard.dart.weak.transformed.expect
new file mode 100644
index 0000000..3b921f5
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/non_bool_guard.dart.weak.transformed.expect
@@ -0,0 +1,73 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/non_bool_guard.dart:7:28: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//     case [var a, _] when a - 1:
+//                            ^
+//
+// pkg/front_end/testcases/patterns/non_bool_guard.dart:15:32: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//   if (v case [var a, _] when a - 1) {
+//                                ^
+//
+// pkg/front_end/testcases/patterns/non_bool_guard.dart:23:23: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//     [var a, _] when a - 1 => "match",
+//                       ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method test1(core::List<core::int> v) → core::String {
+  #L1:
+  {
+    core::int a;
+    final core::List<core::int> #0#0 = v;
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final core::int #t1 = a = #0#0.{core::List::[]}(0){(core::int) → core::int} in true) && (let final core::int #t2 = #0#0.{core::List::[]}(1){(core::int) → core::int} in true) && invalid-expression "pkg/front_end/testcases/patterns/non_bool_guard.dart:7:28: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+    case [var a, _] when a - 1:
+                           ^") {
+      {
+        return "match";
+      }
+    }
+    else {
+      {
+        return "no match";
+      }
+    }
+  }
+}
+static method test2(core::List<core::int> v) → core::String {
+  {
+    core::int a;
+    final core::List<core::int> #0#0 = v;
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final core::int #t3 = a = #0#0.{core::List::[]}(0){(core::int) → core::int} in true) && (let final core::int #t4 = #0#0.{core::List::[]}(1){(core::int) → core::int} in true) && invalid-expression "pkg/front_end/testcases/patterns/non_bool_guard.dart:15:32: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+  if (v case [var a, _] when a - 1) {
+                               ^") {
+      return "match";
+    }
+  }
+  return "no match";
+}
+static method test3(core::List<core::int> v) → core::String
+  return block {
+    core::String #t5;
+    core::int a;
+    final core::List<core::int> #0#0 = v;
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final core::int #t6 = a = #0#0.{core::List::[]}(0){(core::int) → core::int} in true) && (let final core::int #t7 = #0#0.{core::List::[]}(1){(core::int) → core::int} in true) && invalid-expression "pkg/front_end/testcases/patterns/non_bool_guard.dart:23:23: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+    [var a, _] when a - 1 => \"match\",
+                      ^")
+      #t5 = "match";
+    else
+      if(true)
+        #t5 = "no match";
+  } =>#t5;
+
+constants  {
+  #C1 = 2
+}
diff --git a/pkg/front_end/testcases/patterns/pattern_types.dart.strong.expect b/pkg/front_end/testcases/patterns/pattern_types.dart.strong.expect
index 2b00c98..b25d765 100644
--- a/pkg/front_end/testcases/patterns/pattern_types.dart.strong.expect
+++ b/pkg/front_end/testcases/patterns/pattern_types.dart.strong.expect
@@ -226,40 +226,73 @@
     core::bool #0#14#isSet = false;
     dynamic #0#15;
     core::bool #0#15#isSet = false;
-    if(#0#0 is{ForNonNullableByDefault} Null && (let final dynamic #t1 = hashCode = #0#0{Null}.{core::Object::hashCode}{core::int} in true) || #0#0 is{ForNonNullableByDefault} Null && (let final dynamic #t2 = toString = #0#0{Null}.{core::Object::toString}{() → core::String} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t3 = field = #0#5#isSet ?{dynamic} #0#5{dynamic} : let final dynamic #t4 = #0#5#isSet = true in #0#5 = #0#0{self::Class}.{self::Class::field}{dynamic} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t5 = method = #0#6#isSet ?{() → void} #0#6{() → void} : let final dynamic #t6 = #0#6#isSet = true in #0#6 = #0#0{self::Class}.{self::Class::method}{() → void} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t7 = extensionGetter = self::_extension#0|get#extensionGetter(#0#0{self::Class}) in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t8 = extensionMethod = self::_extension#0|extensionMethod(#0#0{self::Class}) in true) || #0#0 is{ForNonNullableByDefault} dynamic && (let final dynamic #t9 = dynamicAccess = #0#0{dynamic}.dynamicAccess in true) || #0#0 is{ForNonNullableByDefault} () → void && (let final dynamic #t10 = call = #0#12#isSet ?{() → void} #0#12{() → void} : let final dynamic #t11 = #0#12#isSet = true in #0#12 = #0#0{() → void}.call in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String}) && (let final dynamic #t12 = $1 = #0#14#isSet ?{core::int} #0#14{core::int} : let final dynamic #t13 = #0#14#isSet = true in #0#14 = #0#0{(core::int, {required named: core::String})}.$1{core::int} in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String}) && (let final dynamic #t14 = named = #0#15#isSet ?{core::String} #0#15{core::String} : let final dynamic #t15 = #0#15#isSet = true in #0#15 = #0#0{(core::int, {required named: core::String})}.named{core::String} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t16 = missing = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:75:16: Error: The getter 'missing' isn't defined for the class 'Class'.
+    if(#0#0 is{ForNonNullableByDefault} Null && (let final dynamic #t1 = hashCode = #0#0{Null}.{core::Object::hashCode}{core::int} in true) || #0#0 is{ForNonNullableByDefault} Null && (let final dynamic #t2 = toString = #0#0{Null}.{core::Object::toString}{() → core::String} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t3 = field = #0#5#isSet ?{dynamic} #0#5{dynamic} : let final dynamic #t4 = #0#5#isSet = true in #0#5 = #0#0{self::Class}.{self::Class::field}{dynamic} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t5 = method = #0#6#isSet ?{() → void} #0#6{() → void} : let final dynamic #t6 = #0#6#isSet = true in #0#6 = #0#0{self::Class}.{self::Class::method}{() → void} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t7 = extensionGetter = self::_extension#0|get#extensionGetter(#0#0{self::Class}) in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t8 = extensionMethod = self::_extension#0|extensionMethod(#0#0{self::Class}) in true) || #0#0 is{ForNonNullableByDefault} dynamic && (let final dynamic #t9 = dynamicAccess = #0#0{dynamic}.dynamicAccess in true) || #0#0 is{ForNonNullableByDefault} () → void && (let final dynamic #t10 = call = #0#12#isSet ?{() → void} #0#12{() → void} : let final dynamic #t11 = #0#12#isSet = true in #0#12 = #0#0{() → void}.call in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String}) && (let final dynamic #t12 = $1 = #0#14#isSet ?{core::int} #0#14{core::int} : let final dynamic #t13 = #0#14#isSet = true in #0#14 = #0#0{(core::int, {required named: core::String})}.$1{core::int} in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String}) && (let final dynamic #t14 = named = #0#15#isSet ?{core::String} #0#15{core::String} : let final dynamic #t15 = #0#15#isSet = true in #0#15 = #0#0{(core::int, {required named: core::String})}.named{core::String} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t16 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:75:16: Error: The getter 'missing' isn't defined for the class 'Class'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'missing'.
     case Class(: var missing): // Error: missing getter
-               ^^^^^^^" in null{<unresolved>}.missing in true) || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t17 = field#1 = #0#5#isSet ?{invalid-type} #0#5{invalid-type} : let final dynamic #t18 = #0#5#isSet = true in #0#5 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:76:17: Error: The getter 'field' isn't defined for the class 'Class?'.
+               ^^^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:75:16: Error: The getter 'missing' isn't defined for the class 'Class'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'missing'.
+    case Class(: var missing): // Error: missing getter
+               ^^^^^^^") || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t17 = #0#5#isSet ?{invalid-type} #0#5{invalid-type} : let final dynamic #t18 = #0#5#isSet = true in #0#5 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:76:17: Error: The getter 'field' isn't defined for the class 'Class?'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'field'.
     case Class_(: var field): // Error: nullable member get
-                ^^^^^" in null{<unresolved>}.field in true) || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t19 = method#1 = #0#6#isSet ?{invalid-type} #0#6{invalid-type} : let final dynamic #t20 = #0#6#isSet = true in #0#6 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:77:17: Error: The getter 'method' isn't defined for the class 'Class?'.
+                ^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:76:17: Error: The getter 'field' isn't defined for the class 'Class?'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'field'.
+    case Class_(: var field): // Error: nullable member get
+                ^^^^^") || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t19 = #0#6#isSet ?{invalid-type} #0#6{invalid-type} : let final dynamic #t20 = #0#6#isSet = true in #0#6 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:77:17: Error: The getter 'method' isn't defined for the class 'Class?'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'method'.
     case Class_(: var method): // Error: nullable member tear-off
-                ^^^^^^" in null{<unresolved>}.method in true) || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t21 = extensionGetter#1 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:78:17: Error: The getter 'extensionGetter' isn't defined for the class 'Class?'.
+                ^^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:77:17: Error: The getter 'method' isn't defined for the class 'Class?'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'method'.
+    case Class_(: var method): // Error: nullable member tear-off
+                ^^^^^^") || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t21 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:78:17: Error: The getter 'extensionGetter' isn't defined for the class 'Class?'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'extensionGetter'.
     case Class_(: var extensionGetter): // Error: nullable extension member get
-                ^^^^^^^^^^^^^^^" in null{<unresolved>}.extensionGetter in true) || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t22 = extensionMethod#1 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:79:17: Error: The getter 'extensionMethod' isn't defined for the class 'Class?'.
+                ^^^^^^^^^^^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:78:17: Error: The getter 'extensionGetter' isn't defined for the class 'Class?'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'extensionGetter'.
+    case Class_(: var extensionGetter): // Error: nullable extension member get
+                ^^^^^^^^^^^^^^^") || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t22 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:79:17: Error: The getter 'extensionMethod' isn't defined for the class 'Class?'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'extensionMethod'.
     case Class_(: var extensionMethod): // Error: nullable extension tear-off
-                ^^^^^^^^^^^^^^^" in null{<unresolved>}.extensionMethod in true) || #0#0 is{ForNonNullableByDefault} () →? void && (let final dynamic #t23 = call#1 = #0#12#isSet ?{invalid-type} #0#12{invalid-type} : let final dynamic #t24 = #0#12#isSet = true in #0#12 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:80:21: Error: The getter 'call' isn't defined for the class 'void Function()?'.
+                ^^^^^^^^^^^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:79:17: Error: The getter 'extensionMethod' isn't defined for the class 'Class?'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'extensionMethod'.
+    case Class_(: var extensionMethod): // Error: nullable extension tear-off
+                ^^^^^^^^^^^^^^^") || #0#0 is{ForNonNullableByDefault} () →? void && (let final dynamic #t23 = #0#12#isSet ?{invalid-type} #0#12{invalid-type} : let final dynamic #t24 = #0#12#isSet = true in #0#12 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:80:21: Error: The getter 'call' isn't defined for the class 'void Function()?'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'call'.
     case Function1_(: var call): // Error: nullable function tear-off
-                    ^^^^" in null{<unresolved>}.call in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String})? && (let final dynamic #t25 = $1#1 = #0#14#isSet ?{invalid-type} #0#14{invalid-type} : let final dynamic #t26 = #0#14#isSet = true in #0#14 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:81:19: Error: The getter '\$1' isn't defined for the class '(int, {String named})?'.
+                    ^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:80:21: Error: The getter 'call' isn't defined for the class 'void Function()?'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'call'.
+    case Function1_(: var call): // Error: nullable function tear-off
+                    ^^^^") || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String})? && (let final dynamic #t25 = #0#14#isSet ?{invalid-type} #0#14{invalid-type} : let final dynamic #t26 = #0#14#isSet = true in #0#14 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:81:19: Error: The getter '\$1' isn't defined for the class '(int, {String named})?'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named '\$1'.
     case Record1_(: var \$1): // Error: nullable record index get
-                  ^^" in null{<unresolved>}.$1 in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String})? && (let final dynamic #t27 = named#1 = #0#15#isSet ?{invalid-type} #0#15{invalid-type} : let final dynamic #t28 = #0#15#isSet = true in #0#15 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:82:19: Error: The getter 'named' isn't defined for the class '(int, {String named})?'.
+                  ^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:81:19: Error: The getter '\$1' isn't defined for the class '(int, {String named})?'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named '\$1'.
+    case Record1_(: var \$1): // Error: nullable record index get
+                  ^^") || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String})? && (let final dynamic #t27 = #0#15#isSet ?{invalid-type} #0#15{invalid-type} : let final dynamic #t28 = #0#15#isSet = true in #0#15 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:82:19: Error: The getter 'named' isn't defined for the class '(int, {String named})?'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'named'.
     case Record1_(: var named): // Error: nullable record named get
-                  ^^^^^" in null{<unresolved>}.named in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t29 = ambiguousField = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:83:16: Error: The getter 'ambiguousField' isn't defined for the class 'Class'.
+                  ^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:82:19: Error: The getter 'named' isn't defined for the class '(int, {String named})?'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'named'.
+    case Record1_(: var named): // Error: nullable record named get
+                  ^^^^^") || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t29 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:83:16: Error: The getter 'ambiguousField' isn't defined for the class 'Class'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'ambiguousField'.
     case Class(: var ambiguousField): // Error: ambiguous get
-               ^^^^^^^^^^^^^^" in null{<unresolved>}.ambiguousField in true) || #0#0 is{ForNonNullableByDefault} invalid-type) {
+               ^^^^^^^^^^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:83:16: Error: The getter 'ambiguousField' isn't defined for the class 'Class'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'ambiguousField'.
+    case Class(: var ambiguousField): // Error: ambiguous get
+               ^^^^^^^^^^^^^^") || #0#0 is{ForNonNullableByDefault} invalid-type) {
     }
   }
 }
@@ -344,10 +377,9 @@
     if(self::_extension#0|<=(#15#0, #C1)) {
     }
   }
-  {
-    final self::Class #16#0 = cls;
-    if(#16#0.{self::Class::<}(#C2){(core::int) → core::bool}) {
-    }
+  if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:113:18: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+  if (cls case < '0') {} // Error: invalid instance < argument
+                 ^") {
   }
   {
     final self::Class #17#0 = cls;
@@ -377,23 +409,23 @@
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing method, or defining a method named '<'.
   if (cls_ case < 0) {} // Error: nullable instance <
-                ^" in null{<unresolved>}.<()) {
+                ^") {
   }
   if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:120:17: Error: The method '<=' isn't defined for the class 'Class?'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing method, or defining a method named '<='.
   if (cls_ case <= 0) {} // Error: nullable extension <=
-                ^^" in null{<unresolved>}.<=()) {
+                ^^") {
   }
   if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:121:19: Error: The method '<' isn't defined for the class 'String'.
 Try correcting the name to the name of an existing method, or defining a method named '<'.
   if (string case < 0) {} // Error: missing <
-                  ^" in null{<unresolved>}.<()) {
+                  ^") {
   }
   if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:122:19: Error: The method '<=' isn't defined for the class 'String'.
 Try correcting the name to the name of an existing method, or defining a method named '<='.
   if (string case <= 0) {} // Error: ambiguous <=
-                  ^^" in null{<unresolved>}.<=()) {
+                  ^^") {
   }
   {
     final invalid-type #26#0 = invalid;
@@ -417,10 +449,10 @@
                          ^^^^^^") {
     }
   }
-  {
-    final self::Class2 #29#0 = cls2;
-    if(#29#0 =={self::Class2::==}{(self::Class2) → core::bool} #C1) {
-    }
+  if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:126:20: Error: The argument type 'int' can't be assigned to the parameter type 'Class2'.
+ - 'Class2' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+  if (cls2 case == 0) {} // Error: invalid instance == argument
+                   ^") {
   }
   {
     final self::Class2 #30#0 = cls2;
@@ -434,10 +466,10 @@
                          ^^^^^^")) {
     }
   }
-  {
-    final self::Class2 #31#0 = cls2;
-    if(!(#31#0 =={self::Class2::==}{(self::Class2) → core::bool} #C1)) {
-    }
+  if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:128:20: Error: The argument type 'int' can't be assigned to the parameter type 'Class2'.
+ - 'Class2' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+  if (cls2 case != 0) {} // Error: invalid instance == argument negated
+                   ^") {
   }
   {
     final self::Class2 #32#0 = cls2;
@@ -451,10 +483,10 @@
                         ^^^^^^"){(self::Class2) → core::bool}) {
     }
   }
-  {
-    final self::Class2 #33#0 = cls2;
-    if(#33#0.{self::Class2::<}(#C1){(self::Class2) → core::bool}) {
-    }
+  if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:130:19: Error: The argument type 'int' can't be assigned to the parameter type 'Class2'.
+ - 'Class2' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+  if (cls2 case < 0) {} // Error: invalid instance < argument
+                  ^") {
   }
   {
     final self::Class2? #34#0 = cls2_;
diff --git a/pkg/front_end/testcases/patterns/pattern_types.dart.weak.expect b/pkg/front_end/testcases/patterns/pattern_types.dart.weak.expect
index 8def158..3f707d2 100644
--- a/pkg/front_end/testcases/patterns/pattern_types.dart.weak.expect
+++ b/pkg/front_end/testcases/patterns/pattern_types.dart.weak.expect
@@ -227,40 +227,73 @@
     core::bool #0#14#isSet = false;
     dynamic #0#15;
     core::bool #0#15#isSet = false;
-    if(#0#0 is{ForNonNullableByDefault} Null && (let final dynamic #t1 = hashCode = #0#0{Null}.{core::Object::hashCode}{core::int} in true) || #0#0 is{ForNonNullableByDefault} Null && (let final dynamic #t2 = toString = #0#0{Null}.{core::Object::toString}{() → core::String} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t3 = field = #0#5#isSet ?{dynamic} #0#5{dynamic} : let final dynamic #t4 = #0#5#isSet = true in #0#5 = #0#0{self::Class}.{self::Class::field}{dynamic} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t5 = method = #0#6#isSet ?{() → void} #0#6{() → void} : let final dynamic #t6 = #0#6#isSet = true in #0#6 = #0#0{self::Class}.{self::Class::method}{() → void} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t7 = extensionGetter = self::_extension#0|get#extensionGetter(#0#0{self::Class}) in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t8 = extensionMethod = self::_extension#0|extensionMethod(#0#0{self::Class}) in true) || #0#0 is{ForNonNullableByDefault} dynamic && (let final dynamic #t9 = dynamicAccess = #0#0{dynamic}.dynamicAccess in true) || #0#0 is{ForNonNullableByDefault} () → void && (let final dynamic #t10 = call = #0#12#isSet ?{() → void} #0#12{() → void} : let final dynamic #t11 = #0#12#isSet = true in #0#12 = #0#0{() → void}.call in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String}) && (let final dynamic #t12 = $1 = #0#14#isSet ?{core::int} #0#14{core::int} : let final dynamic #t13 = #0#14#isSet = true in #0#14 = #0#0{(core::int, {required named: core::String})}.$1{core::int} in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String}) && (let final dynamic #t14 = named = #0#15#isSet ?{core::String} #0#15{core::String} : let final dynamic #t15 = #0#15#isSet = true in #0#15 = #0#0{(core::int, {required named: core::String})}.named{core::String} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t16 = missing = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:75:16: Error: The getter 'missing' isn't defined for the class 'Class'.
+    if(#0#0 is{ForNonNullableByDefault} Null && (let final dynamic #t1 = hashCode = #0#0{Null}.{core::Object::hashCode}{core::int} in true) || #0#0 is{ForNonNullableByDefault} Null && (let final dynamic #t2 = toString = #0#0{Null}.{core::Object::toString}{() → core::String} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t3 = field = #0#5#isSet ?{dynamic} #0#5{dynamic} : let final dynamic #t4 = #0#5#isSet = true in #0#5 = #0#0{self::Class}.{self::Class::field}{dynamic} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t5 = method = #0#6#isSet ?{() → void} #0#6{() → void} : let final dynamic #t6 = #0#6#isSet = true in #0#6 = #0#0{self::Class}.{self::Class::method}{() → void} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t7 = extensionGetter = self::_extension#0|get#extensionGetter(#0#0{self::Class}) in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t8 = extensionMethod = self::_extension#0|extensionMethod(#0#0{self::Class}) in true) || #0#0 is{ForNonNullableByDefault} dynamic && (let final dynamic #t9 = dynamicAccess = #0#0{dynamic}.dynamicAccess in true) || #0#0 is{ForNonNullableByDefault} () → void && (let final dynamic #t10 = call = #0#12#isSet ?{() → void} #0#12{() → void} : let final dynamic #t11 = #0#12#isSet = true in #0#12 = #0#0{() → void}.call in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String}) && (let final dynamic #t12 = $1 = #0#14#isSet ?{core::int} #0#14{core::int} : let final dynamic #t13 = #0#14#isSet = true in #0#14 = #0#0{(core::int, {required named: core::String})}.$1{core::int} in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String}) && (let final dynamic #t14 = named = #0#15#isSet ?{core::String} #0#15{core::String} : let final dynamic #t15 = #0#15#isSet = true in #0#15 = #0#0{(core::int, {required named: core::String})}.named{core::String} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t16 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:75:16: Error: The getter 'missing' isn't defined for the class 'Class'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'missing'.
     case Class(: var missing): // Error: missing getter
-               ^^^^^^^" in null{<unresolved>}.missing in true) || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t17 = field#1 = #0#5#isSet ?{invalid-type} #0#5{invalid-type} : let final dynamic #t18 = #0#5#isSet = true in #0#5 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:76:17: Error: The getter 'field' isn't defined for the class 'Class?'.
+               ^^^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:75:16: Error: The getter 'missing' isn't defined for the class 'Class'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'missing'.
+    case Class(: var missing): // Error: missing getter
+               ^^^^^^^") || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t17 = #0#5#isSet ?{invalid-type} #0#5{invalid-type} : let final dynamic #t18 = #0#5#isSet = true in #0#5 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:76:17: Error: The getter 'field' isn't defined for the class 'Class?'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'field'.
     case Class_(: var field): // Error: nullable member get
-                ^^^^^" in null{<unresolved>}.field in true) || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t19 = method#1 = #0#6#isSet ?{invalid-type} #0#6{invalid-type} : let final dynamic #t20 = #0#6#isSet = true in #0#6 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:77:17: Error: The getter 'method' isn't defined for the class 'Class?'.
+                ^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:76:17: Error: The getter 'field' isn't defined for the class 'Class?'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'field'.
+    case Class_(: var field): // Error: nullable member get
+                ^^^^^") || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t19 = #0#6#isSet ?{invalid-type} #0#6{invalid-type} : let final dynamic #t20 = #0#6#isSet = true in #0#6 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:77:17: Error: The getter 'method' isn't defined for the class 'Class?'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'method'.
     case Class_(: var method): // Error: nullable member tear-off
-                ^^^^^^" in null{<unresolved>}.method in true) || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t21 = extensionGetter#1 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:78:17: Error: The getter 'extensionGetter' isn't defined for the class 'Class?'.
+                ^^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:77:17: Error: The getter 'method' isn't defined for the class 'Class?'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'method'.
+    case Class_(: var method): // Error: nullable member tear-off
+                ^^^^^^") || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t21 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:78:17: Error: The getter 'extensionGetter' isn't defined for the class 'Class?'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'extensionGetter'.
     case Class_(: var extensionGetter): // Error: nullable extension member get
-                ^^^^^^^^^^^^^^^" in null{<unresolved>}.extensionGetter in true) || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t22 = extensionMethod#1 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:79:17: Error: The getter 'extensionMethod' isn't defined for the class 'Class?'.
+                ^^^^^^^^^^^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:78:17: Error: The getter 'extensionGetter' isn't defined for the class 'Class?'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'extensionGetter'.
+    case Class_(: var extensionGetter): // Error: nullable extension member get
+                ^^^^^^^^^^^^^^^") || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t22 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:79:17: Error: The getter 'extensionMethod' isn't defined for the class 'Class?'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'extensionMethod'.
     case Class_(: var extensionMethod): // Error: nullable extension tear-off
-                ^^^^^^^^^^^^^^^" in null{<unresolved>}.extensionMethod in true) || #0#0 is{ForNonNullableByDefault} () →? void && (let final dynamic #t23 = call#1 = #0#12#isSet ?{invalid-type} #0#12{invalid-type} : let final dynamic #t24 = #0#12#isSet = true in #0#12 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:80:21: Error: The getter 'call' isn't defined for the class 'void Function()?'.
+                ^^^^^^^^^^^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:79:17: Error: The getter 'extensionMethod' isn't defined for the class 'Class?'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'extensionMethod'.
+    case Class_(: var extensionMethod): // Error: nullable extension tear-off
+                ^^^^^^^^^^^^^^^") || #0#0 is{ForNonNullableByDefault} () →? void && (let final dynamic #t23 = #0#12#isSet ?{invalid-type} #0#12{invalid-type} : let final dynamic #t24 = #0#12#isSet = true in #0#12 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:80:21: Error: The getter 'call' isn't defined for the class 'void Function()?'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'call'.
     case Function1_(: var call): // Error: nullable function tear-off
-                    ^^^^" in null{<unresolved>}.call in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String})? && (let final dynamic #t25 = $1#1 = #0#14#isSet ?{invalid-type} #0#14{invalid-type} : let final dynamic #t26 = #0#14#isSet = true in #0#14 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:81:19: Error: The getter '\$1' isn't defined for the class '(int, {String named})?'.
+                    ^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:80:21: Error: The getter 'call' isn't defined for the class 'void Function()?'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'call'.
+    case Function1_(: var call): // Error: nullable function tear-off
+                    ^^^^") || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String})? && (let final dynamic #t25 = #0#14#isSet ?{invalid-type} #0#14{invalid-type} : let final dynamic #t26 = #0#14#isSet = true in #0#14 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:81:19: Error: The getter '\$1' isn't defined for the class '(int, {String named})?'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named '\$1'.
     case Record1_(: var \$1): // Error: nullable record index get
-                  ^^" in null{<unresolved>}.$1 in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String})? && (let final dynamic #t27 = named#1 = #0#15#isSet ?{invalid-type} #0#15{invalid-type} : let final dynamic #t28 = #0#15#isSet = true in #0#15 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:82:19: Error: The getter 'named' isn't defined for the class '(int, {String named})?'.
+                  ^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:81:19: Error: The getter '\$1' isn't defined for the class '(int, {String named})?'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named '\$1'.
+    case Record1_(: var \$1): // Error: nullable record index get
+                  ^^") || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String})? && (let final dynamic #t27 = #0#15#isSet ?{invalid-type} #0#15{invalid-type} : let final dynamic #t28 = #0#15#isSet = true in #0#15 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:82:19: Error: The getter 'named' isn't defined for the class '(int, {String named})?'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'named'.
     case Record1_(: var named): // Error: nullable record named get
-                  ^^^^^" in null{<unresolved>}.named in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t29 = ambiguousField = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:83:16: Error: The getter 'ambiguousField' isn't defined for the class 'Class'.
+                  ^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:82:19: Error: The getter 'named' isn't defined for the class '(int, {String named})?'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'named'.
+    case Record1_(: var named): // Error: nullable record named get
+                  ^^^^^") || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t29 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:83:16: Error: The getter 'ambiguousField' isn't defined for the class 'Class'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'ambiguousField'.
     case Class(: var ambiguousField): // Error: ambiguous get
-               ^^^^^^^^^^^^^^" in null{<unresolved>}.ambiguousField in true) || #0#0 is{ForNonNullableByDefault} invalid-type) {
+               ^^^^^^^^^^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:83:16: Error: The getter 'ambiguousField' isn't defined for the class 'Class'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'ambiguousField'.
+    case Class(: var ambiguousField): // Error: ambiguous get
+               ^^^^^^^^^^^^^^") || #0#0 is{ForNonNullableByDefault} invalid-type) {
     }
   }
 }
@@ -345,10 +378,9 @@
     if(self::_extension#0|<=(#15#0, #C1)) {
     }
   }
-  {
-    final self::Class #16#0 = cls;
-    if(#16#0.{self::Class::<}(#C2){(core::int) → core::bool}) {
-    }
+  if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:113:18: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+  if (cls case < '0') {} // Error: invalid instance < argument
+                 ^") {
   }
   {
     final self::Class #17#0 = cls;
@@ -378,23 +410,23 @@
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing method, or defining a method named '<'.
   if (cls_ case < 0) {} // Error: nullable instance <
-                ^" in null{<unresolved>}.<()) {
+                ^") {
   }
   if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:120:17: Error: The method '<=' isn't defined for the class 'Class?'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing method, or defining a method named '<='.
   if (cls_ case <= 0) {} // Error: nullable extension <=
-                ^^" in null{<unresolved>}.<=()) {
+                ^^") {
   }
   if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:121:19: Error: The method '<' isn't defined for the class 'String'.
 Try correcting the name to the name of an existing method, or defining a method named '<'.
   if (string case < 0) {} // Error: missing <
-                  ^" in null{<unresolved>}.<()) {
+                  ^") {
   }
   if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:122:19: Error: The method '<=' isn't defined for the class 'String'.
 Try correcting the name to the name of an existing method, or defining a method named '<='.
   if (string case <= 0) {} // Error: ambiguous <=
-                  ^^" in null{<unresolved>}.<=()) {
+                  ^^") {
   }
   {
     final invalid-type #26#0 = invalid;
@@ -418,10 +450,10 @@
                          ^^^^^^") {
     }
   }
-  {
-    final self::Class2 #29#0 = cls2;
-    if(#29#0 =={self::Class2::==}{(self::Class2) → core::bool} #C1) {
-    }
+  if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:126:20: Error: The argument type 'int' can't be assigned to the parameter type 'Class2'.
+ - 'Class2' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+  if (cls2 case == 0) {} // Error: invalid instance == argument
+                   ^") {
   }
   {
     final self::Class2 #30#0 = cls2;
@@ -435,10 +467,10 @@
                          ^^^^^^")) {
     }
   }
-  {
-    final self::Class2 #31#0 = cls2;
-    if(!(#31#0 =={self::Class2::==}{(self::Class2) → core::bool} #C1)) {
-    }
+  if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:128:20: Error: The argument type 'int' can't be assigned to the parameter type 'Class2'.
+ - 'Class2' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+  if (cls2 case != 0) {} // Error: invalid instance == argument negated
+                   ^") {
   }
   {
     final self::Class2 #32#0 = cls2;
@@ -452,10 +484,10 @@
                         ^^^^^^"){(self::Class2) → core::bool}) {
     }
   }
-  {
-    final self::Class2 #33#0 = cls2;
-    if(#33#0.{self::Class2::<}(#C1){(self::Class2) → core::bool}) {
-    }
+  if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:130:19: Error: The argument type 'int' can't be assigned to the parameter type 'Class2'.
+ - 'Class2' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+  if (cls2 case < 0) {} // Error: invalid instance < argument
+                  ^") {
   }
   {
     final self::Class2? #34#0 = cls2_;
diff --git a/pkg/front_end/testcases/patterns/pattern_types.dart.weak.modular.expect b/pkg/front_end/testcases/patterns/pattern_types.dart.weak.modular.expect
index 8def158..3f707d2 100644
--- a/pkg/front_end/testcases/patterns/pattern_types.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/patterns/pattern_types.dart.weak.modular.expect
@@ -227,40 +227,73 @@
     core::bool #0#14#isSet = false;
     dynamic #0#15;
     core::bool #0#15#isSet = false;
-    if(#0#0 is{ForNonNullableByDefault} Null && (let final dynamic #t1 = hashCode = #0#0{Null}.{core::Object::hashCode}{core::int} in true) || #0#0 is{ForNonNullableByDefault} Null && (let final dynamic #t2 = toString = #0#0{Null}.{core::Object::toString}{() → core::String} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t3 = field = #0#5#isSet ?{dynamic} #0#5{dynamic} : let final dynamic #t4 = #0#5#isSet = true in #0#5 = #0#0{self::Class}.{self::Class::field}{dynamic} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t5 = method = #0#6#isSet ?{() → void} #0#6{() → void} : let final dynamic #t6 = #0#6#isSet = true in #0#6 = #0#0{self::Class}.{self::Class::method}{() → void} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t7 = extensionGetter = self::_extension#0|get#extensionGetter(#0#0{self::Class}) in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t8 = extensionMethod = self::_extension#0|extensionMethod(#0#0{self::Class}) in true) || #0#0 is{ForNonNullableByDefault} dynamic && (let final dynamic #t9 = dynamicAccess = #0#0{dynamic}.dynamicAccess in true) || #0#0 is{ForNonNullableByDefault} () → void && (let final dynamic #t10 = call = #0#12#isSet ?{() → void} #0#12{() → void} : let final dynamic #t11 = #0#12#isSet = true in #0#12 = #0#0{() → void}.call in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String}) && (let final dynamic #t12 = $1 = #0#14#isSet ?{core::int} #0#14{core::int} : let final dynamic #t13 = #0#14#isSet = true in #0#14 = #0#0{(core::int, {required named: core::String})}.$1{core::int} in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String}) && (let final dynamic #t14 = named = #0#15#isSet ?{core::String} #0#15{core::String} : let final dynamic #t15 = #0#15#isSet = true in #0#15 = #0#0{(core::int, {required named: core::String})}.named{core::String} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t16 = missing = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:75:16: Error: The getter 'missing' isn't defined for the class 'Class'.
+    if(#0#0 is{ForNonNullableByDefault} Null && (let final dynamic #t1 = hashCode = #0#0{Null}.{core::Object::hashCode}{core::int} in true) || #0#0 is{ForNonNullableByDefault} Null && (let final dynamic #t2 = toString = #0#0{Null}.{core::Object::toString}{() → core::String} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t3 = field = #0#5#isSet ?{dynamic} #0#5{dynamic} : let final dynamic #t4 = #0#5#isSet = true in #0#5 = #0#0{self::Class}.{self::Class::field}{dynamic} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t5 = method = #0#6#isSet ?{() → void} #0#6{() → void} : let final dynamic #t6 = #0#6#isSet = true in #0#6 = #0#0{self::Class}.{self::Class::method}{() → void} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t7 = extensionGetter = self::_extension#0|get#extensionGetter(#0#0{self::Class}) in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t8 = extensionMethod = self::_extension#0|extensionMethod(#0#0{self::Class}) in true) || #0#0 is{ForNonNullableByDefault} dynamic && (let final dynamic #t9 = dynamicAccess = #0#0{dynamic}.dynamicAccess in true) || #0#0 is{ForNonNullableByDefault} () → void && (let final dynamic #t10 = call = #0#12#isSet ?{() → void} #0#12{() → void} : let final dynamic #t11 = #0#12#isSet = true in #0#12 = #0#0{() → void}.call in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String}) && (let final dynamic #t12 = $1 = #0#14#isSet ?{core::int} #0#14{core::int} : let final dynamic #t13 = #0#14#isSet = true in #0#14 = #0#0{(core::int, {required named: core::String})}.$1{core::int} in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String}) && (let final dynamic #t14 = named = #0#15#isSet ?{core::String} #0#15{core::String} : let final dynamic #t15 = #0#15#isSet = true in #0#15 = #0#0{(core::int, {required named: core::String})}.named{core::String} in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t16 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:75:16: Error: The getter 'missing' isn't defined for the class 'Class'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'missing'.
     case Class(: var missing): // Error: missing getter
-               ^^^^^^^" in null{<unresolved>}.missing in true) || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t17 = field#1 = #0#5#isSet ?{invalid-type} #0#5{invalid-type} : let final dynamic #t18 = #0#5#isSet = true in #0#5 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:76:17: Error: The getter 'field' isn't defined for the class 'Class?'.
+               ^^^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:75:16: Error: The getter 'missing' isn't defined for the class 'Class'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'missing'.
+    case Class(: var missing): // Error: missing getter
+               ^^^^^^^") || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t17 = #0#5#isSet ?{invalid-type} #0#5{invalid-type} : let final dynamic #t18 = #0#5#isSet = true in #0#5 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:76:17: Error: The getter 'field' isn't defined for the class 'Class?'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'field'.
     case Class_(: var field): // Error: nullable member get
-                ^^^^^" in null{<unresolved>}.field in true) || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t19 = method#1 = #0#6#isSet ?{invalid-type} #0#6{invalid-type} : let final dynamic #t20 = #0#6#isSet = true in #0#6 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:77:17: Error: The getter 'method' isn't defined for the class 'Class?'.
+                ^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:76:17: Error: The getter 'field' isn't defined for the class 'Class?'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'field'.
+    case Class_(: var field): // Error: nullable member get
+                ^^^^^") || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t19 = #0#6#isSet ?{invalid-type} #0#6{invalid-type} : let final dynamic #t20 = #0#6#isSet = true in #0#6 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:77:17: Error: The getter 'method' isn't defined for the class 'Class?'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'method'.
     case Class_(: var method): // Error: nullable member tear-off
-                ^^^^^^" in null{<unresolved>}.method in true) || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t21 = extensionGetter#1 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:78:17: Error: The getter 'extensionGetter' isn't defined for the class 'Class?'.
+                ^^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:77:17: Error: The getter 'method' isn't defined for the class 'Class?'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'method'.
+    case Class_(: var method): // Error: nullable member tear-off
+                ^^^^^^") || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t21 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:78:17: Error: The getter 'extensionGetter' isn't defined for the class 'Class?'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'extensionGetter'.
     case Class_(: var extensionGetter): // Error: nullable extension member get
-                ^^^^^^^^^^^^^^^" in null{<unresolved>}.extensionGetter in true) || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t22 = extensionMethod#1 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:79:17: Error: The getter 'extensionMethod' isn't defined for the class 'Class?'.
+                ^^^^^^^^^^^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:78:17: Error: The getter 'extensionGetter' isn't defined for the class 'Class?'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'extensionGetter'.
+    case Class_(: var extensionGetter): // Error: nullable extension member get
+                ^^^^^^^^^^^^^^^") || #0#0 is{ForNonNullableByDefault} self::Class? && (let final dynamic #t22 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:79:17: Error: The getter 'extensionMethod' isn't defined for the class 'Class?'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'extensionMethod'.
     case Class_(: var extensionMethod): // Error: nullable extension tear-off
-                ^^^^^^^^^^^^^^^" in null{<unresolved>}.extensionMethod in true) || #0#0 is{ForNonNullableByDefault} () →? void && (let final dynamic #t23 = call#1 = #0#12#isSet ?{invalid-type} #0#12{invalid-type} : let final dynamic #t24 = #0#12#isSet = true in #0#12 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:80:21: Error: The getter 'call' isn't defined for the class 'void Function()?'.
+                ^^^^^^^^^^^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:79:17: Error: The getter 'extensionMethod' isn't defined for the class 'Class?'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'extensionMethod'.
+    case Class_(: var extensionMethod): // Error: nullable extension tear-off
+                ^^^^^^^^^^^^^^^") || #0#0 is{ForNonNullableByDefault} () →? void && (let final dynamic #t23 = #0#12#isSet ?{invalid-type} #0#12{invalid-type} : let final dynamic #t24 = #0#12#isSet = true in #0#12 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:80:21: Error: The getter 'call' isn't defined for the class 'void Function()?'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'call'.
     case Function1_(: var call): // Error: nullable function tear-off
-                    ^^^^" in null{<unresolved>}.call in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String})? && (let final dynamic #t25 = $1#1 = #0#14#isSet ?{invalid-type} #0#14{invalid-type} : let final dynamic #t26 = #0#14#isSet = true in #0#14 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:81:19: Error: The getter '\$1' isn't defined for the class '(int, {String named})?'.
+                    ^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:80:21: Error: The getter 'call' isn't defined for the class 'void Function()?'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'call'.
+    case Function1_(: var call): // Error: nullable function tear-off
+                    ^^^^") || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String})? && (let final dynamic #t25 = #0#14#isSet ?{invalid-type} #0#14{invalid-type} : let final dynamic #t26 = #0#14#isSet = true in #0#14 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:81:19: Error: The getter '\$1' isn't defined for the class '(int, {String named})?'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named '\$1'.
     case Record1_(: var \$1): // Error: nullable record index get
-                  ^^" in null{<unresolved>}.$1 in true) || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String})? && (let final dynamic #t27 = named#1 = #0#15#isSet ?{invalid-type} #0#15{invalid-type} : let final dynamic #t28 = #0#15#isSet = true in #0#15 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:82:19: Error: The getter 'named' isn't defined for the class '(int, {String named})?'.
+                  ^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:81:19: Error: The getter '\$1' isn't defined for the class '(int, {String named})?'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named '\$1'.
+    case Record1_(: var \$1): // Error: nullable record index get
+                  ^^") || #0#0 is{ForNonNullableByDefault} (core::int, {required named: core::String})? && (let final dynamic #t27 = #0#15#isSet ?{invalid-type} #0#15{invalid-type} : let final dynamic #t28 = #0#15#isSet = true in #0#15 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:82:19: Error: The getter 'named' isn't defined for the class '(int, {String named})?'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'named'.
     case Record1_(: var named): // Error: nullable record named get
-                  ^^^^^" in null{<unresolved>}.named in true) || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t29 = ambiguousField = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:83:16: Error: The getter 'ambiguousField' isn't defined for the class 'Class'.
+                  ^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:82:19: Error: The getter 'named' isn't defined for the class '(int, {String named})?'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'named'.
+    case Record1_(: var named): // Error: nullable record named get
+                  ^^^^^") || #0#0 is{ForNonNullableByDefault} self::Class && (let final dynamic #t29 = invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:83:16: Error: The getter 'ambiguousField' isn't defined for the class 'Class'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'ambiguousField'.
     case Class(: var ambiguousField): // Error: ambiguous get
-               ^^^^^^^^^^^^^^" in null{<unresolved>}.ambiguousField in true) || #0#0 is{ForNonNullableByDefault} invalid-type) {
+               ^^^^^^^^^^^^^^" in invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:83:16: Error: The getter 'ambiguousField' isn't defined for the class 'Class'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'ambiguousField'.
+    case Class(: var ambiguousField): // Error: ambiguous get
+               ^^^^^^^^^^^^^^") || #0#0 is{ForNonNullableByDefault} invalid-type) {
     }
   }
 }
@@ -345,10 +378,9 @@
     if(self::_extension#0|<=(#15#0, #C1)) {
     }
   }
-  {
-    final self::Class #16#0 = cls;
-    if(#16#0.{self::Class::<}(#C2){(core::int) → core::bool}) {
-    }
+  if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:113:18: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+  if (cls case < '0') {} // Error: invalid instance < argument
+                 ^") {
   }
   {
     final self::Class #17#0 = cls;
@@ -378,23 +410,23 @@
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing method, or defining a method named '<'.
   if (cls_ case < 0) {} // Error: nullable instance <
-                ^" in null{<unresolved>}.<()) {
+                ^") {
   }
   if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:120:17: Error: The method '<=' isn't defined for the class 'Class?'.
  - 'Class' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
 Try correcting the name to the name of an existing method, or defining a method named '<='.
   if (cls_ case <= 0) {} // Error: nullable extension <=
-                ^^" in null{<unresolved>}.<=()) {
+                ^^") {
   }
   if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:121:19: Error: The method '<' isn't defined for the class 'String'.
 Try correcting the name to the name of an existing method, or defining a method named '<'.
   if (string case < 0) {} // Error: missing <
-                  ^" in null{<unresolved>}.<()) {
+                  ^") {
   }
   if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:122:19: Error: The method '<=' isn't defined for the class 'String'.
 Try correcting the name to the name of an existing method, or defining a method named '<='.
   if (string case <= 0) {} // Error: ambiguous <=
-                  ^^" in null{<unresolved>}.<=()) {
+                  ^^") {
   }
   {
     final invalid-type #26#0 = invalid;
@@ -418,10 +450,10 @@
                          ^^^^^^") {
     }
   }
-  {
-    final self::Class2 #29#0 = cls2;
-    if(#29#0 =={self::Class2::==}{(self::Class2) → core::bool} #C1) {
-    }
+  if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:126:20: Error: The argument type 'int' can't be assigned to the parameter type 'Class2'.
+ - 'Class2' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+  if (cls2 case == 0) {} // Error: invalid instance == argument
+                   ^") {
   }
   {
     final self::Class2 #30#0 = cls2;
@@ -435,10 +467,10 @@
                          ^^^^^^")) {
     }
   }
-  {
-    final self::Class2 #31#0 = cls2;
-    if(!(#31#0 =={self::Class2::==}{(self::Class2) → core::bool} #C1)) {
-    }
+  if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:128:20: Error: The argument type 'int' can't be assigned to the parameter type 'Class2'.
+ - 'Class2' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+  if (cls2 case != 0) {} // Error: invalid instance == argument negated
+                   ^") {
   }
   {
     final self::Class2 #32#0 = cls2;
@@ -452,10 +484,10 @@
                         ^^^^^^"){(self::Class2) → core::bool}) {
     }
   }
-  {
-    final self::Class2 #33#0 = cls2;
-    if(#33#0.{self::Class2::<}(#C1){(self::Class2) → core::bool}) {
-    }
+  if(invalid-expression "pkg/front_end/testcases/patterns/pattern_types.dart:130:19: Error: The argument type 'int' can't be assigned to the parameter type 'Class2'.
+ - 'Class2' is from 'pkg/front_end/testcases/patterns/pattern_types.dart'.
+  if (cls2 case < 0) {} // Error: invalid instance < argument
+                  ^") {
   }
   {
     final self::Class2? #34#0 = cls2_;
diff --git a/pkg/front_end/testcases/patterns/shared_errors.dart.strong.expect b/pkg/front_end/testcases/patterns/shared_errors.dart.strong.expect
index 3ae32de..29b1a29 100644
--- a/pkg/front_end/testcases/patterns/shared_errors.dart.strong.expect
+++ b/pkg/front_end/testcases/patterns/shared_errors.dart.strong.expect
@@ -104,12 +104,12 @@
 }
 static method argumentTypeNotAssignable(self::Class cls) → dynamic {
   #L1:
-  {
-    final self::Class #0#0 = cls;
-    if(#0#0.{self::Class::>=}(#C1){(self::Class) → core::bool}) {
-      {
-        core::print(0);
-      }
+  if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:13:13: Error: The argument type 'int' can't be assigned to the parameter type 'Class'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/shared_errors.dart'.
+    case >= 0: // Error
+            ^") {
+    {
+      core::print(0);
     }
   }
 }
@@ -137,7 +137,7 @@
   core::String a = "";
   block {
     final dynamic #0#0 = list;
-    if(!(#0#0{core::List<core::String>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C2 && (let final dynamic #t1 = a = #0#0{core::List<core::String>}.{core::List::[]}(0){(core::int) → core::String} in true) && (let final dynamic #t2 = #0#0{core::List<core::String>}.{core::List::[]}(1){(core::int) → core::String} in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:31:7: Error: The variable 'a' is already assigned in this pattern.
+    if(!(#0#0{core::List<core::String>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t1 = a = #0#0{core::List<core::String>}.{core::List::[]}(0){(core::int) → core::String} in true) && (let final dynamic #t2 = #0#0{core::List<core::String>}.{core::List::[]}(1){(core::int) → core::String} in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:31:7: Error: The variable 'a' is already assigned in this pattern.
 Try renaming the variable.
   [a, a] = list; // Error
       ^")))
@@ -146,15 +146,19 @@
 }
 static method duplicateRecordPatternField(dynamic o) → dynamic {
   #L3:
-  if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:36:28: Error: The field 'field' is already matched in this pattern.
+  {
+    final dynamic #0#0 = o;
+    late final core::int #0#2 = #0#0{self::Class}.{self::Class::field}{core::int};
+    if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:36:28: Error: The field 'field' is already matched in this pattern.
 Try removing the duplicate field.
     case (field: 1, field: 2): // Error
-                           ^" || invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:37:33: Error: The field 'field' is already matched in this pattern.
+                           ^" || #0#0 is{ForNonNullableByDefault} self::Class && #C2 =={core::num::==}{(core::Object) → core::bool} #0#2 && (let final dynamic #t3 = #0#2 in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:37:33: Error: The field 'field' is already matched in this pattern.
 Try removing the duplicate field.
     case Class(field: 1, field: 2): // Error
-                                ^") {
-    {
-      core::print(0);
+                                ^")) {
+      {
+        core::print(0);
+      }
     }
   }
 }
@@ -162,10 +166,12 @@
   #L4:
   {
     final dynamic #0#0 = o;
-    if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:44:16: Error: At most one rest element is allowed in a list or map pattern.
+    core::int #0#2;
+    core::bool #0#2#isSet = false;
+    if(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && (#0#2#isSet ?{core::int} #0#2{core::int} : let final dynamic #t4 = #0#2#isSet = true in #0#2 = #0#0{core::List<dynamic>}.{core::List::length}{core::int}).{core::num::>=}(#C2){(core::num) → core::bool} && (let final dynamic #t5 = #0#0{core::List<dynamic>}.{core::List::[]}((#0#2#isSet ?{core::int} #0#2{core::int} : let final dynamic #t6 = #0#2#isSet = true in #0#2 = #0#0{core::List<dynamic>}.{core::List::length}{core::int}).{core::num::-}(1){(core::num) → core::int}){(core::int) → dynamic} in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:44:16: Error: At most one rest element is allowed in a list or map pattern.
 Try removing the duplicate rest element.
     case [..., ...]: // Error
-               ^" || #0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C1){(core::num) → core::bool}) {
+               ^") || #0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && (#0#2#isSet ?{core::int} #0#2{core::int} : let final dynamic #t7 = #0#2#isSet = true in #0#2 = #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}).{core::num::>=}(#C3){(core::num) → core::bool}) {
     }
   }
 }
@@ -176,7 +182,7 @@
     final core::List<core::int> #0#0 = list;
     late final core::int #0#4 = #0#0.{core::List::[]}(0){(core::int) → core::int};
     late final core::int #0#6 = #0#0.{core::List::[]}(1){(core::int) → core::int};
-    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C2 && (let final dynamic #t3 = #0#4! in let final dynamic #t4 = a = #0#4! in true) && (!(#0#6 == null) ?{core::bool} let final dynamic #t5 = b = #0#6 in true : false)) {
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t8 = #0#4! in let final dynamic #t9 = a = #0#4! in true) && (!(#0#6 == null) ?{core::bool} let final dynamic #t10 = b = #0#6 in true : false)) {
       core::print(0);
     }
   }
@@ -184,23 +190,26 @@
 static method nonBooleanCondition(core::int i) → dynamic {
   {
     final core::int #0#0 = i;
-    if(#C1 =={core::num::==}{(core::Object) → core::bool} #0#0 && i) {
+    if(#C3 =={core::num::==}{(core::Object) → core::bool} #0#0 && invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:56:21: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+  if (i case 0 when i) { // Error
+                    ^") {
       core::print(0);
     }
   }
 }
 static method refutablePatternInIrrefutableContext(core::int? x) → dynamic {
   core::int a;
-  if(!invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:62:9: Error: Refutable patterns can't be used in an irrefutable context.
-Try using an if-case, a 'switch' statement, or a 'switch' expression instead.
-  var (a?) = x; // Error
-        ^")
-    throw new _in::ReachabilityError::•();
+  {
+    final dynamic #0#0 = x;
+    if(!(!(#0#0 == null) ?{core::bool} let final dynamic #t11 = a = #0#0{core::int} in true : false))
+      throw new _in::ReachabilityError::•();
+  }
 }
 static method restPatternNotLastInMap(dynamic o) → dynamic {
   {
     final dynamic #0#0 = o;
-    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C3){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
+    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C2){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
       core::print(0);
     }
   }
@@ -208,16 +217,16 @@
 static method restPatternWithSubPatternInMap(dynamic o) → dynamic {
   {
     final dynamic #0#0 = o;
-    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C3){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
+    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C2){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
       core::print(0);
     }
   }
 }
 
 constants  {
-  #C1 = 0
-  #C2 = 2
-  #C3 = 1
+  #C1 = 2
+  #C2 = 1
+  #C3 = 0
   #C4 = 5
   #C5 = 3
 }
diff --git a/pkg/front_end/testcases/patterns/shared_errors.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/shared_errors.dart.strong.transformed.expect
new file mode 100644
index 0000000..e53cba4
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/shared_errors.dart.strong.transformed.expect
@@ -0,0 +1,238 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:13:13: Error: The argument type 'int' can't be assigned to the parameter type 'Class'.
+//  - 'Class' is from 'pkg/front_end/testcases/patterns/shared_errors.dart'.
+//     case >= 0: // Error
+//             ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:20:10: Error: A value of type 'Class' can't be assigned to a variable of type 'bool'.
+//  - 'Class' is from 'pkg/front_end/testcases/patterns/shared_errors.dart'.
+//     case > 0: // Error
+//          ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:26:12: Error: The matched value of type 'List<String>' isn't assignable to the required type 'List<int>'.
+//  - 'List' is from 'dart:core'.
+// Try changing the required type of the pattern, or the matched value type.
+//   var <int>[a] = list; // Error
+//            ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:31:7: Error: The variable 'a' is already assigned in this pattern.
+// Try renaming the variable.
+//   [a, a] = list; // Error
+//       ^
+// pkg/front_end/testcases/patterns/shared_errors.dart:31:4: Context: The first assigned variable pattern.
+//   [a, a] = list; // Error
+//    ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:36:28: Error: The field 'field' is already matched in this pattern.
+// Try removing the duplicate field.
+//     case (field: 1, field: 2): // Error
+//                            ^
+// pkg/front_end/testcases/patterns/shared_errors.dart:36:18: Context: The first field.
+//     case (field: 1, field: 2): // Error
+//                  ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:37:33: Error: The field 'field' is already matched in this pattern.
+// Try removing the duplicate field.
+//     case Class(field: 1, field: 2): // Error
+//                                 ^
+// pkg/front_end/testcases/patterns/shared_errors.dart:37:23: Context: The first field.
+//     case Class(field: 1, field: 2): // Error
+//                       ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:45:11: Error: At most one rest element is allowed in a list or map pattern.
+// Try removing the duplicate rest element.
+//     case {..., ...}: // Error
+//           ^
+// pkg/front_end/testcases/patterns/shared_errors.dart:45:16: Context: The first rest element.
+//     case {..., ...}: // Error
+//                ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:44:16: Error: At most one rest element is allowed in a list or map pattern.
+// Try removing the duplicate rest element.
+//     case [..., ...]: // Error
+//                ^
+// pkg/front_end/testcases/patterns/shared_errors.dart:44:11: Context: The first rest element.
+//     case [..., ...]: // Error
+//           ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:50:23: Warning: The null-assert pattern will have no effect because the matched type isn't nullable.
+// Try replacing the null-assert pattern with its nested pattern.
+//   if (list case [var a!, var b?]) { // Warnings
+//                       ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:50:31: Warning: The null-check pattern will have no effect because the matched type isn't nullable.
+// Try replacing the null-check pattern with its nested pattern.
+//   if (list case [var a!, var b?]) { // Warnings
+//                               ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:56:21: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//   if (i case 0 when i) { // Error
+//                     ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:62:9: Error: Refutable patterns can't be used in an irrefutable context.
+// Try using an if-case, a 'switch' statement, or a 'switch' expression instead.
+//   var (a?) = x; // Error
+//         ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:66:15: Error: The '...' pattern can appear only at the end in map patterns.
+//   if (o case {..., 5: 3}) { // Error
+//               ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:72:21: Error: A rest element in a map pattern can't have a subpattern.
+// Try removing the subpattern.
+//   if (o case {5: 3, ...var a}) { // Error
+//                     ^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  get field() → core::int
+    return 42;
+  operator >=(self::Class cls) → core::bool
+    return true;
+  operator >(core::int i) → self::Class
+    return new self::Class::•();
+}
+static method argumentTypeNotAssignable(self::Class cls) → dynamic {
+  #L1:
+  if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:13:13: Error: The argument type 'int' can't be assigned to the parameter type 'Class'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/shared_errors.dart'.
+    case >= 0: // Error
+            ^") {
+    {
+      core::print(0);
+    }
+  }
+}
+static method relationalPatternOperatorReturnTypeNotAssignableToBool(self::Class cls) → dynamic {
+  #L2:
+  if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:20:10: Error: A value of type 'Class' can't be assigned to a variable of type 'bool'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/shared_errors.dart'.
+    case > 0: // Error
+         ^") {
+    {
+      core::print(0);
+    }
+  }
+}
+static method patternTypeMismatchInIrrefutableContext(core::List<core::String> list) → dynamic {
+  core::int a;
+  if(!invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:26:12: Error: The matched value of type 'List<String>' isn't assignable to the required type 'List<int>'.
+ - 'List' is from 'dart:core'.
+Try changing the required type of the pattern, or the matched value type.
+  var <int>[a] = list; // Error
+           ^")
+    throw new _in::ReachabilityError::•();
+}
+static method duplicateAssignmentPatternVariable(core::List<core::String> list) → dynamic {
+  core::String a = "";
+  block {
+    final dynamic #0#0 = list;
+    if(!(#0#0{core::List<core::String>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final core::String #t1 = a = #0#0{core::List<core::String>}.{core::List::[]}(0){(core::int) → core::String} in true) && (let final core::String #t2 = #0#0{core::List<core::String>}.{core::List::[]}(1){(core::int) → core::String} in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:31:7: Error: The variable 'a' is already assigned in this pattern.
+Try renaming the variable.
+  [a, a] = list; // Error
+      ^")))
+      throw new _in::ReachabilityError::•();
+  } =>#0#0;
+}
+static method duplicateRecordPatternField(dynamic o) → dynamic {
+  #L3:
+  {
+    final dynamic #0#0 = o;
+    function ##0#2#initializer() → core::int
+      return #0#0{self::Class}.{self::Class::field}{core::int};
+    late final core::int #0#2 = ##0#2#initializer(){() → core::int};
+    if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:36:28: Error: The field 'field' is already matched in this pattern.
+Try removing the duplicate field.
+    case (field: 1, field: 2): // Error
+                           ^" || #0#0 is{ForNonNullableByDefault} self::Class && #C2 =={core::num::==}{(core::Object) → core::bool} #0#2 && (let final core::int #t3 = #0#2 in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:37:33: Error: The field 'field' is already matched in this pattern.
+Try removing the duplicate field.
+    case Class(field: 1, field: 2): // Error
+                                ^")) {
+      {
+        core::print(0);
+      }
+    }
+  }
+}
+static method duplicateRestPattern(dynamic o) → dynamic {
+  #L4:
+  {
+    final dynamic #0#0 = o;
+    core::int #0#2;
+    core::bool #0#2#isSet = false;
+    if(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && (#0#2#isSet ?{core::int} #0#2{core::int} : let final core::bool* #t4 = #0#2#isSet = true in #0#2 = #0#0{core::List<dynamic>}.{core::List::length}{core::int}).{core::num::>=}(#C2){(core::num) → core::bool} && (let final dynamic #t5 = #0#0{core::List<dynamic>}.{core::List::[]}((#0#2#isSet ?{core::int} #0#2{core::int} : let final core::bool* #t6 = #0#2#isSet = true in #0#2 = #0#0{core::List<dynamic>}.{core::List::length}{core::int}).{core::num::-}(1){(core::num) → core::int}){(core::int) → dynamic} in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:44:16: Error: At most one rest element is allowed in a list or map pattern.
+Try removing the duplicate rest element.
+    case [..., ...]: // Error
+               ^") || #0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && (#0#2#isSet ?{core::int} #0#2{core::int} : let final core::bool* #t7 = #0#2#isSet = true in #0#2 = #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}).{core::num::>=}(#C3){(core::num) → core::bool}) {
+    }
+  }
+}
+static method matchedTypeIsStrictlyNonNullable(core::List<core::int> list) → dynamic {
+  {
+    core::int a;
+    core::int b;
+    final core::List<core::int> #0#0 = list;
+    function ##0#4#initializer() → core::int
+      return #0#0.{core::List::[]}(0){(core::int) → core::int};
+    late final core::int #0#4 = ##0#4#initializer(){() → core::int};
+    function ##0#6#initializer() → core::int
+      return #0#0.{core::List::[]}(1){(core::int) → core::int};
+    late final core::int #0#6 = ##0#6#initializer(){() → core::int};
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final core::int #t8 = #0#4! in let final core::int #t9 = a = #0#4! in true) && (!(#0#6 == null) ?{core::bool} let final core::int #t10 = b = #0#6 in true : false)) {
+      core::print(0);
+    }
+  }
+}
+static method nonBooleanCondition(core::int i) → dynamic {
+  {
+    final core::int #0#0 = i;
+    if(#C3 =={core::num::==}{(core::Object) → core::bool} #0#0 && invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:56:21: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+  if (i case 0 when i) { // Error
+                    ^") {
+      core::print(0);
+    }
+  }
+}
+static method refutablePatternInIrrefutableContext(core::int? x) → dynamic {
+  core::int a;
+  {
+    final dynamic #0#0 = x;
+    if(!(!(#0#0 == null) ?{core::bool} let final core::int #t11 = a = #0#0{core::int} in true : false))
+      throw new _in::ReachabilityError::•();
+  }
+}
+static method restPatternNotLastInMap(dynamic o) → dynamic {
+  {
+    final dynamic #0#0 = o;
+    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C2){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
+      core::print(0);
+    }
+  }
+}
+static method restPatternWithSubPatternInMap(dynamic o) → dynamic {
+  {
+    final dynamic #0#0 = o;
+    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C2){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
+      core::print(0);
+    }
+  }
+}
+
+constants  {
+  #C1 = 2
+  #C2 = 1
+  #C3 = 0
+  #C4 = 5
+  #C5 = 3
+}
diff --git a/pkg/front_end/testcases/patterns/shared_errors.dart.weak.expect b/pkg/front_end/testcases/patterns/shared_errors.dart.weak.expect
index 3ae32de..29b1a29 100644
--- a/pkg/front_end/testcases/patterns/shared_errors.dart.weak.expect
+++ b/pkg/front_end/testcases/patterns/shared_errors.dart.weak.expect
@@ -104,12 +104,12 @@
 }
 static method argumentTypeNotAssignable(self::Class cls) → dynamic {
   #L1:
-  {
-    final self::Class #0#0 = cls;
-    if(#0#0.{self::Class::>=}(#C1){(self::Class) → core::bool}) {
-      {
-        core::print(0);
-      }
+  if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:13:13: Error: The argument type 'int' can't be assigned to the parameter type 'Class'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/shared_errors.dart'.
+    case >= 0: // Error
+            ^") {
+    {
+      core::print(0);
     }
   }
 }
@@ -137,7 +137,7 @@
   core::String a = "";
   block {
     final dynamic #0#0 = list;
-    if(!(#0#0{core::List<core::String>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C2 && (let final dynamic #t1 = a = #0#0{core::List<core::String>}.{core::List::[]}(0){(core::int) → core::String} in true) && (let final dynamic #t2 = #0#0{core::List<core::String>}.{core::List::[]}(1){(core::int) → core::String} in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:31:7: Error: The variable 'a' is already assigned in this pattern.
+    if(!(#0#0{core::List<core::String>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t1 = a = #0#0{core::List<core::String>}.{core::List::[]}(0){(core::int) → core::String} in true) && (let final dynamic #t2 = #0#0{core::List<core::String>}.{core::List::[]}(1){(core::int) → core::String} in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:31:7: Error: The variable 'a' is already assigned in this pattern.
 Try renaming the variable.
   [a, a] = list; // Error
       ^")))
@@ -146,15 +146,19 @@
 }
 static method duplicateRecordPatternField(dynamic o) → dynamic {
   #L3:
-  if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:36:28: Error: The field 'field' is already matched in this pattern.
+  {
+    final dynamic #0#0 = o;
+    late final core::int #0#2 = #0#0{self::Class}.{self::Class::field}{core::int};
+    if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:36:28: Error: The field 'field' is already matched in this pattern.
 Try removing the duplicate field.
     case (field: 1, field: 2): // Error
-                           ^" || invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:37:33: Error: The field 'field' is already matched in this pattern.
+                           ^" || #0#0 is{ForNonNullableByDefault} self::Class && #C2 =={core::num::==}{(core::Object) → core::bool} #0#2 && (let final dynamic #t3 = #0#2 in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:37:33: Error: The field 'field' is already matched in this pattern.
 Try removing the duplicate field.
     case Class(field: 1, field: 2): // Error
-                                ^") {
-    {
-      core::print(0);
+                                ^")) {
+      {
+        core::print(0);
+      }
     }
   }
 }
@@ -162,10 +166,12 @@
   #L4:
   {
     final dynamic #0#0 = o;
-    if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:44:16: Error: At most one rest element is allowed in a list or map pattern.
+    core::int #0#2;
+    core::bool #0#2#isSet = false;
+    if(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && (#0#2#isSet ?{core::int} #0#2{core::int} : let final dynamic #t4 = #0#2#isSet = true in #0#2 = #0#0{core::List<dynamic>}.{core::List::length}{core::int}).{core::num::>=}(#C2){(core::num) → core::bool} && (let final dynamic #t5 = #0#0{core::List<dynamic>}.{core::List::[]}((#0#2#isSet ?{core::int} #0#2{core::int} : let final dynamic #t6 = #0#2#isSet = true in #0#2 = #0#0{core::List<dynamic>}.{core::List::length}{core::int}).{core::num::-}(1){(core::num) → core::int}){(core::int) → dynamic} in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:44:16: Error: At most one rest element is allowed in a list or map pattern.
 Try removing the duplicate rest element.
     case [..., ...]: // Error
-               ^" || #0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C1){(core::num) → core::bool}) {
+               ^") || #0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && (#0#2#isSet ?{core::int} #0#2{core::int} : let final dynamic #t7 = #0#2#isSet = true in #0#2 = #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}).{core::num::>=}(#C3){(core::num) → core::bool}) {
     }
   }
 }
@@ -176,7 +182,7 @@
     final core::List<core::int> #0#0 = list;
     late final core::int #0#4 = #0#0.{core::List::[]}(0){(core::int) → core::int};
     late final core::int #0#6 = #0#0.{core::List::[]}(1){(core::int) → core::int};
-    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C2 && (let final dynamic #t3 = #0#4! in let final dynamic #t4 = a = #0#4! in true) && (!(#0#6 == null) ?{core::bool} let final dynamic #t5 = b = #0#6 in true : false)) {
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t8 = #0#4! in let final dynamic #t9 = a = #0#4! in true) && (!(#0#6 == null) ?{core::bool} let final dynamic #t10 = b = #0#6 in true : false)) {
       core::print(0);
     }
   }
@@ -184,23 +190,26 @@
 static method nonBooleanCondition(core::int i) → dynamic {
   {
     final core::int #0#0 = i;
-    if(#C1 =={core::num::==}{(core::Object) → core::bool} #0#0 && i) {
+    if(#C3 =={core::num::==}{(core::Object) → core::bool} #0#0 && invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:56:21: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+  if (i case 0 when i) { // Error
+                    ^") {
       core::print(0);
     }
   }
 }
 static method refutablePatternInIrrefutableContext(core::int? x) → dynamic {
   core::int a;
-  if(!invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:62:9: Error: Refutable patterns can't be used in an irrefutable context.
-Try using an if-case, a 'switch' statement, or a 'switch' expression instead.
-  var (a?) = x; // Error
-        ^")
-    throw new _in::ReachabilityError::•();
+  {
+    final dynamic #0#0 = x;
+    if(!(!(#0#0 == null) ?{core::bool} let final dynamic #t11 = a = #0#0{core::int} in true : false))
+      throw new _in::ReachabilityError::•();
+  }
 }
 static method restPatternNotLastInMap(dynamic o) → dynamic {
   {
     final dynamic #0#0 = o;
-    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C3){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
+    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C2){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
       core::print(0);
     }
   }
@@ -208,16 +217,16 @@
 static method restPatternWithSubPatternInMap(dynamic o) → dynamic {
   {
     final dynamic #0#0 = o;
-    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C3){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
+    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C2){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
       core::print(0);
     }
   }
 }
 
 constants  {
-  #C1 = 0
-  #C2 = 2
-  #C3 = 1
+  #C1 = 2
+  #C2 = 1
+  #C3 = 0
   #C4 = 5
   #C5 = 3
 }
diff --git a/pkg/front_end/testcases/patterns/shared_errors.dart.weak.modular.expect b/pkg/front_end/testcases/patterns/shared_errors.dart.weak.modular.expect
index 3ae32de..29b1a29 100644
--- a/pkg/front_end/testcases/patterns/shared_errors.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/patterns/shared_errors.dart.weak.modular.expect
@@ -104,12 +104,12 @@
 }
 static method argumentTypeNotAssignable(self::Class cls) → dynamic {
   #L1:
-  {
-    final self::Class #0#0 = cls;
-    if(#0#0.{self::Class::>=}(#C1){(self::Class) → core::bool}) {
-      {
-        core::print(0);
-      }
+  if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:13:13: Error: The argument type 'int' can't be assigned to the parameter type 'Class'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/shared_errors.dart'.
+    case >= 0: // Error
+            ^") {
+    {
+      core::print(0);
     }
   }
 }
@@ -137,7 +137,7 @@
   core::String a = "";
   block {
     final dynamic #0#0 = list;
-    if(!(#0#0{core::List<core::String>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C2 && (let final dynamic #t1 = a = #0#0{core::List<core::String>}.{core::List::[]}(0){(core::int) → core::String} in true) && (let final dynamic #t2 = #0#0{core::List<core::String>}.{core::List::[]}(1){(core::int) → core::String} in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:31:7: Error: The variable 'a' is already assigned in this pattern.
+    if(!(#0#0{core::List<core::String>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t1 = a = #0#0{core::List<core::String>}.{core::List::[]}(0){(core::int) → core::String} in true) && (let final dynamic #t2 = #0#0{core::List<core::String>}.{core::List::[]}(1){(core::int) → core::String} in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:31:7: Error: The variable 'a' is already assigned in this pattern.
 Try renaming the variable.
   [a, a] = list; // Error
       ^")))
@@ -146,15 +146,19 @@
 }
 static method duplicateRecordPatternField(dynamic o) → dynamic {
   #L3:
-  if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:36:28: Error: The field 'field' is already matched in this pattern.
+  {
+    final dynamic #0#0 = o;
+    late final core::int #0#2 = #0#0{self::Class}.{self::Class::field}{core::int};
+    if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:36:28: Error: The field 'field' is already matched in this pattern.
 Try removing the duplicate field.
     case (field: 1, field: 2): // Error
-                           ^" || invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:37:33: Error: The field 'field' is already matched in this pattern.
+                           ^" || #0#0 is{ForNonNullableByDefault} self::Class && #C2 =={core::num::==}{(core::Object) → core::bool} #0#2 && (let final dynamic #t3 = #0#2 in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:37:33: Error: The field 'field' is already matched in this pattern.
 Try removing the duplicate field.
     case Class(field: 1, field: 2): // Error
-                                ^") {
-    {
-      core::print(0);
+                                ^")) {
+      {
+        core::print(0);
+      }
     }
   }
 }
@@ -162,10 +166,12 @@
   #L4:
   {
     final dynamic #0#0 = o;
-    if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:44:16: Error: At most one rest element is allowed in a list or map pattern.
+    core::int #0#2;
+    core::bool #0#2#isSet = false;
+    if(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && (#0#2#isSet ?{core::int} #0#2{core::int} : let final dynamic #t4 = #0#2#isSet = true in #0#2 = #0#0{core::List<dynamic>}.{core::List::length}{core::int}).{core::num::>=}(#C2){(core::num) → core::bool} && (let final dynamic #t5 = #0#0{core::List<dynamic>}.{core::List::[]}((#0#2#isSet ?{core::int} #0#2{core::int} : let final dynamic #t6 = #0#2#isSet = true in #0#2 = #0#0{core::List<dynamic>}.{core::List::length}{core::int}).{core::num::-}(1){(core::num) → core::int}){(core::int) → dynamic} in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:44:16: Error: At most one rest element is allowed in a list or map pattern.
 Try removing the duplicate rest element.
     case [..., ...]: // Error
-               ^" || #0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C1){(core::num) → core::bool}) {
+               ^") || #0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && (#0#2#isSet ?{core::int} #0#2{core::int} : let final dynamic #t7 = #0#2#isSet = true in #0#2 = #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}).{core::num::>=}(#C3){(core::num) → core::bool}) {
     }
   }
 }
@@ -176,7 +182,7 @@
     final core::List<core::int> #0#0 = list;
     late final core::int #0#4 = #0#0.{core::List::[]}(0){(core::int) → core::int};
     late final core::int #0#6 = #0#0.{core::List::[]}(1){(core::int) → core::int};
-    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C2 && (let final dynamic #t3 = #0#4! in let final dynamic #t4 = a = #0#4! in true) && (!(#0#6 == null) ?{core::bool} let final dynamic #t5 = b = #0#6 in true : false)) {
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t8 = #0#4! in let final dynamic #t9 = a = #0#4! in true) && (!(#0#6 == null) ?{core::bool} let final dynamic #t10 = b = #0#6 in true : false)) {
       core::print(0);
     }
   }
@@ -184,23 +190,26 @@
 static method nonBooleanCondition(core::int i) → dynamic {
   {
     final core::int #0#0 = i;
-    if(#C1 =={core::num::==}{(core::Object) → core::bool} #0#0 && i) {
+    if(#C3 =={core::num::==}{(core::Object) → core::bool} #0#0 && invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:56:21: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+  if (i case 0 when i) { // Error
+                    ^") {
       core::print(0);
     }
   }
 }
 static method refutablePatternInIrrefutableContext(core::int? x) → dynamic {
   core::int a;
-  if(!invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:62:9: Error: Refutable patterns can't be used in an irrefutable context.
-Try using an if-case, a 'switch' statement, or a 'switch' expression instead.
-  var (a?) = x; // Error
-        ^")
-    throw new _in::ReachabilityError::•();
+  {
+    final dynamic #0#0 = x;
+    if(!(!(#0#0 == null) ?{core::bool} let final dynamic #t11 = a = #0#0{core::int} in true : false))
+      throw new _in::ReachabilityError::•();
+  }
 }
 static method restPatternNotLastInMap(dynamic o) → dynamic {
   {
     final dynamic #0#0 = o;
-    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C3){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
+    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C2){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
       core::print(0);
     }
   }
@@ -208,16 +217,16 @@
 static method restPatternWithSubPatternInMap(dynamic o) → dynamic {
   {
     final dynamic #0#0 = o;
-    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C3){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
+    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C2){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
       core::print(0);
     }
   }
 }
 
 constants  {
-  #C1 = 0
-  #C2 = 2
-  #C3 = 1
+  #C1 = 2
+  #C2 = 1
+  #C3 = 0
   #C4 = 5
   #C5 = 3
 }
diff --git a/pkg/front_end/testcases/patterns/shared_errors.dart.weak.transformed.expect b/pkg/front_end/testcases/patterns/shared_errors.dart.weak.transformed.expect
new file mode 100644
index 0000000..e53cba4
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/shared_errors.dart.weak.transformed.expect
@@ -0,0 +1,238 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:13:13: Error: The argument type 'int' can't be assigned to the parameter type 'Class'.
+//  - 'Class' is from 'pkg/front_end/testcases/patterns/shared_errors.dart'.
+//     case >= 0: // Error
+//             ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:20:10: Error: A value of type 'Class' can't be assigned to a variable of type 'bool'.
+//  - 'Class' is from 'pkg/front_end/testcases/patterns/shared_errors.dart'.
+//     case > 0: // Error
+//          ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:26:12: Error: The matched value of type 'List<String>' isn't assignable to the required type 'List<int>'.
+//  - 'List' is from 'dart:core'.
+// Try changing the required type of the pattern, or the matched value type.
+//   var <int>[a] = list; // Error
+//            ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:31:7: Error: The variable 'a' is already assigned in this pattern.
+// Try renaming the variable.
+//   [a, a] = list; // Error
+//       ^
+// pkg/front_end/testcases/patterns/shared_errors.dart:31:4: Context: The first assigned variable pattern.
+//   [a, a] = list; // Error
+//    ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:36:28: Error: The field 'field' is already matched in this pattern.
+// Try removing the duplicate field.
+//     case (field: 1, field: 2): // Error
+//                            ^
+// pkg/front_end/testcases/patterns/shared_errors.dart:36:18: Context: The first field.
+//     case (field: 1, field: 2): // Error
+//                  ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:37:33: Error: The field 'field' is already matched in this pattern.
+// Try removing the duplicate field.
+//     case Class(field: 1, field: 2): // Error
+//                                 ^
+// pkg/front_end/testcases/patterns/shared_errors.dart:37:23: Context: The first field.
+//     case Class(field: 1, field: 2): // Error
+//                       ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:45:11: Error: At most one rest element is allowed in a list or map pattern.
+// Try removing the duplicate rest element.
+//     case {..., ...}: // Error
+//           ^
+// pkg/front_end/testcases/patterns/shared_errors.dart:45:16: Context: The first rest element.
+//     case {..., ...}: // Error
+//                ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:44:16: Error: At most one rest element is allowed in a list or map pattern.
+// Try removing the duplicate rest element.
+//     case [..., ...]: // Error
+//                ^
+// pkg/front_end/testcases/patterns/shared_errors.dart:44:11: Context: The first rest element.
+//     case [..., ...]: // Error
+//           ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:50:23: Warning: The null-assert pattern will have no effect because the matched type isn't nullable.
+// Try replacing the null-assert pattern with its nested pattern.
+//   if (list case [var a!, var b?]) { // Warnings
+//                       ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:50:31: Warning: The null-check pattern will have no effect because the matched type isn't nullable.
+// Try replacing the null-check pattern with its nested pattern.
+//   if (list case [var a!, var b?]) { // Warnings
+//                               ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:56:21: Error: Conditions must have a static type of 'bool'.
+// Try changing the condition.
+//   if (i case 0 when i) { // Error
+//                     ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:62:9: Error: Refutable patterns can't be used in an irrefutable context.
+// Try using an if-case, a 'switch' statement, or a 'switch' expression instead.
+//   var (a?) = x; // Error
+//         ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:66:15: Error: The '...' pattern can appear only at the end in map patterns.
+//   if (o case {..., 5: 3}) { // Error
+//               ^
+//
+// pkg/front_end/testcases/patterns/shared_errors.dart:72:21: Error: A rest element in a map pattern can't have a subpattern.
+// Try removing the subpattern.
+//   if (o case {5: 3, ...var a}) { // Error
+//                     ^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  get field() → core::int
+    return 42;
+  operator >=(self::Class cls) → core::bool
+    return true;
+  operator >(core::int i) → self::Class
+    return new self::Class::•();
+}
+static method argumentTypeNotAssignable(self::Class cls) → dynamic {
+  #L1:
+  if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:13:13: Error: The argument type 'int' can't be assigned to the parameter type 'Class'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/shared_errors.dart'.
+    case >= 0: // Error
+            ^") {
+    {
+      core::print(0);
+    }
+  }
+}
+static method relationalPatternOperatorReturnTypeNotAssignableToBool(self::Class cls) → dynamic {
+  #L2:
+  if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:20:10: Error: A value of type 'Class' can't be assigned to a variable of type 'bool'.
+ - 'Class' is from 'pkg/front_end/testcases/patterns/shared_errors.dart'.
+    case > 0: // Error
+         ^") {
+    {
+      core::print(0);
+    }
+  }
+}
+static method patternTypeMismatchInIrrefutableContext(core::List<core::String> list) → dynamic {
+  core::int a;
+  if(!invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:26:12: Error: The matched value of type 'List<String>' isn't assignable to the required type 'List<int>'.
+ - 'List' is from 'dart:core'.
+Try changing the required type of the pattern, or the matched value type.
+  var <int>[a] = list; // Error
+           ^")
+    throw new _in::ReachabilityError::•();
+}
+static method duplicateAssignmentPatternVariable(core::List<core::String> list) → dynamic {
+  core::String a = "";
+  block {
+    final dynamic #0#0 = list;
+    if(!(#0#0{core::List<core::String>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final core::String #t1 = a = #0#0{core::List<core::String>}.{core::List::[]}(0){(core::int) → core::String} in true) && (let final core::String #t2 = #0#0{core::List<core::String>}.{core::List::[]}(1){(core::int) → core::String} in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:31:7: Error: The variable 'a' is already assigned in this pattern.
+Try renaming the variable.
+  [a, a] = list; // Error
+      ^")))
+      throw new _in::ReachabilityError::•();
+  } =>#0#0;
+}
+static method duplicateRecordPatternField(dynamic o) → dynamic {
+  #L3:
+  {
+    final dynamic #0#0 = o;
+    function ##0#2#initializer() → core::int
+      return #0#0{self::Class}.{self::Class::field}{core::int};
+    late final core::int #0#2 = ##0#2#initializer(){() → core::int};
+    if(invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:36:28: Error: The field 'field' is already matched in this pattern.
+Try removing the duplicate field.
+    case (field: 1, field: 2): // Error
+                           ^" || #0#0 is{ForNonNullableByDefault} self::Class && #C2 =={core::num::==}{(core::Object) → core::bool} #0#2 && (let final core::int #t3 = #0#2 in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:37:33: Error: The field 'field' is already matched in this pattern.
+Try removing the duplicate field.
+    case Class(field: 1, field: 2): // Error
+                                ^")) {
+      {
+        core::print(0);
+      }
+    }
+  }
+}
+static method duplicateRestPattern(dynamic o) → dynamic {
+  #L4:
+  {
+    final dynamic #0#0 = o;
+    core::int #0#2;
+    core::bool #0#2#isSet = false;
+    if(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && (#0#2#isSet ?{core::int} #0#2{core::int} : let final core::bool* #t4 = #0#2#isSet = true in #0#2 = #0#0{core::List<dynamic>}.{core::List::length}{core::int}).{core::num::>=}(#C2){(core::num) → core::bool} && (let final dynamic #t5 = #0#0{core::List<dynamic>}.{core::List::[]}((#0#2#isSet ?{core::int} #0#2{core::int} : let final core::bool* #t6 = #0#2#isSet = true in #0#2 = #0#0{core::List<dynamic>}.{core::List::length}{core::int}).{core::num::-}(1){(core::num) → core::int}){(core::int) → dynamic} in invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:44:16: Error: At most one rest element is allowed in a list or map pattern.
+Try removing the duplicate rest element.
+    case [..., ...]: // Error
+               ^") || #0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && (#0#2#isSet ?{core::int} #0#2{core::int} : let final core::bool* #t7 = #0#2#isSet = true in #0#2 = #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}).{core::num::>=}(#C3){(core::num) → core::bool}) {
+    }
+  }
+}
+static method matchedTypeIsStrictlyNonNullable(core::List<core::int> list) → dynamic {
+  {
+    core::int a;
+    core::int b;
+    final core::List<core::int> #0#0 = list;
+    function ##0#4#initializer() → core::int
+      return #0#0.{core::List::[]}(0){(core::int) → core::int};
+    late final core::int #0#4 = ##0#4#initializer(){() → core::int};
+    function ##0#6#initializer() → core::int
+      return #0#0.{core::List::[]}(1){(core::int) → core::int};
+    late final core::int #0#6 = ##0#6#initializer(){() → core::int};
+    if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final core::int #t8 = #0#4! in let final core::int #t9 = a = #0#4! in true) && (!(#0#6 == null) ?{core::bool} let final core::int #t10 = b = #0#6 in true : false)) {
+      core::print(0);
+    }
+  }
+}
+static method nonBooleanCondition(core::int i) → dynamic {
+  {
+    final core::int #0#0 = i;
+    if(#C3 =={core::num::==}{(core::Object) → core::bool} #0#0 && invalid-expression "pkg/front_end/testcases/patterns/shared_errors.dart:56:21: Error: Conditions must have a static type of 'bool'.
+Try changing the condition.
+  if (i case 0 when i) { // Error
+                    ^") {
+      core::print(0);
+    }
+  }
+}
+static method refutablePatternInIrrefutableContext(core::int? x) → dynamic {
+  core::int a;
+  {
+    final dynamic #0#0 = x;
+    if(!(!(#0#0 == null) ?{core::bool} let final core::int #t11 = a = #0#0{core::int} in true : false))
+      throw new _in::ReachabilityError::•();
+  }
+}
+static method restPatternNotLastInMap(dynamic o) → dynamic {
+  {
+    final dynamic #0#0 = o;
+    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C2){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
+      core::print(0);
+    }
+  }
+}
+static method restPatternWithSubPatternInMap(dynamic o) → dynamic {
+  {
+    final dynamic #0#0 = o;
+    if(#0#0 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && #0#0{core::Map<dynamic, dynamic>}.{core::Map::length}{core::int}.{core::num::>=}(#C2){(core::num) → core::bool} && #0#0{core::Map<dynamic, dynamic>}.{core::Map::containsKey}(#C4){(core::Object?) → core::bool} && #C5 =={core::num::==}{(core::Object) → core::bool} #0#0{core::Map<dynamic, dynamic>}.{core::Map::[]}(#C4){(core::Object?) → dynamic}) {
+      core::print(0);
+    }
+  }
+}
+
+constants  {
+  #C1 = 2
+  #C2 = 1
+  #C3 = 0
+  #C4 = 5
+  #C5 = 3
+}
diff --git a/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.strong.expect b/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.strong.expect
index 8e6b40b..8c6b94b 100644
--- a/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.strong.expect
+++ b/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.strong.expect
@@ -22,12 +22,15 @@
   {
     core::int as;
     final dynamic #0#0 = x;
-    late final invalid-type #0#2 = invalid-expression "pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart:10:12: Error: The getter 'as' isn't defined for the class 'C'.
+    if(#0#0 is{ForNonNullableByDefault} self::C && (let final dynamic #t1 = invalid-expression "pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart:10:12: Error: The getter 'as' isn't defined for the class 'C'.
  - 'C' is from 'pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'as'.
     case C(: int as):
-           ^^" in null{<unresolved>}.as;
-    if(#0#0 is{ForNonNullableByDefault} self::C && (#0#2 is{ForNonNullableByDefault} core::int && (let final dynamic #t1 = as = #0#2{core::int} in true))) {
+           ^^" in invalid-expression "pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart:10:12: Error: The getter 'as' isn't defined for the class 'C'.
+ - 'C' is from 'pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'as'.
+    case C(: int as):
+           ^^")) {
       {
         break #L1;
       }
diff --git a/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.strong.transformed.expect
index 9b45992..b3c1698 100644
--- a/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.strong.transformed.expect
@@ -22,14 +22,15 @@
   {
     core::int as;
     final dynamic #0#0 = x;
-    function ##0#2#initializer() → invalid-type
-      return invalid-expression "pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart:10:12: Error: The getter 'as' isn't defined for the class 'C'.
+    if(#0#0 is{ForNonNullableByDefault} self::C && (let final invalid-type #t1 = invalid-expression "pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart:10:12: Error: The getter 'as' isn't defined for the class 'C'.
  - 'C' is from 'pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'as'.
     case C(: int as):
-           ^^" in null{<unresolved>}.as;
-    late final invalid-type #0#2 = ##0#2#initializer(){() → invalid-type};
-    if(#0#0 is{ForNonNullableByDefault} self::C && (#0#2 is{ForNonNullableByDefault} core::int && (let final core::int #t1 = as = #0#2{core::int} in true))) {
+           ^^" in invalid-expression "pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart:10:12: Error: The getter 'as' isn't defined for the class 'C'.
+ - 'C' is from 'pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'as'.
+    case C(: int as):
+           ^^")) {
       {
         break #L1;
       }
diff --git a/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.weak.expect b/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.weak.expect
index 8e6b40b..8c6b94b 100644
--- a/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.weak.expect
+++ b/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.weak.expect
@@ -22,12 +22,15 @@
   {
     core::int as;
     final dynamic #0#0 = x;
-    late final invalid-type #0#2 = invalid-expression "pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart:10:12: Error: The getter 'as' isn't defined for the class 'C'.
+    if(#0#0 is{ForNonNullableByDefault} self::C && (let final dynamic #t1 = invalid-expression "pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart:10:12: Error: The getter 'as' isn't defined for the class 'C'.
  - 'C' is from 'pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'as'.
     case C(: int as):
-           ^^" in null{<unresolved>}.as;
-    if(#0#0 is{ForNonNullableByDefault} self::C && (#0#2 is{ForNonNullableByDefault} core::int && (let final dynamic #t1 = as = #0#2{core::int} in true))) {
+           ^^" in invalid-expression "pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart:10:12: Error: The getter 'as' isn't defined for the class 'C'.
+ - 'C' is from 'pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'as'.
+    case C(: int as):
+           ^^")) {
       {
         break #L1;
       }
diff --git a/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.weak.modular.expect b/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.weak.modular.expect
index 8e6b40b..8c6b94b 100644
--- a/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.weak.modular.expect
@@ -22,12 +22,15 @@
   {
     core::int as;
     final dynamic #0#0 = x;
-    late final invalid-type #0#2 = invalid-expression "pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart:10:12: Error: The getter 'as' isn't defined for the class 'C'.
+    if(#0#0 is{ForNonNullableByDefault} self::C && (let final dynamic #t1 = invalid-expression "pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart:10:12: Error: The getter 'as' isn't defined for the class 'C'.
  - 'C' is from 'pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'as'.
     case C(: int as):
-           ^^" in null{<unresolved>}.as;
-    if(#0#0 is{ForNonNullableByDefault} self::C && (#0#2 is{ForNonNullableByDefault} core::int && (let final dynamic #t1 = as = #0#2{core::int} in true))) {
+           ^^" in invalid-expression "pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart:10:12: Error: The getter 'as' isn't defined for the class 'C'.
+ - 'C' is from 'pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'as'.
+    case C(: int as):
+           ^^")) {
       {
         break #L1;
       }
diff --git a/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.weak.transformed.expect b/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.weak.transformed.expect
index 9b45992..b3c1698 100644
--- a/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart.weak.transformed.expect
@@ -22,14 +22,15 @@
   {
     core::int as;
     final dynamic #0#0 = x;
-    function ##0#2#initializer() → invalid-type
-      return invalid-expression "pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart:10:12: Error: The getter 'as' isn't defined for the class 'C'.
+    if(#0#0 is{ForNonNullableByDefault} self::C && (let final invalid-type #t1 = invalid-expression "pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart:10:12: Error: The getter 'as' isn't defined for the class 'C'.
  - 'C' is from 'pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'as'.
     case C(: int as):
-           ^^" in null{<unresolved>}.as;
-    late final invalid-type #0#2 = ##0#2#initializer(){() → invalid-type};
-    if(#0#0 is{ForNonNullableByDefault} self::C && (#0#2 is{ForNonNullableByDefault} core::int && (let final core::int #t1 = as = #0#2{core::int} in true))) {
+           ^^" in invalid-expression "pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart:10:12: Error: The getter 'as' isn't defined for the class 'C'.
+ - 'C' is from 'pkg/front_end/testcases/patterns/typed_variable_named_as_inside_extractor_pattern_implicitly_named.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'as'.
+    case C(: int as):
+           ^^")) {
       {
         break #L1;
       }
diff --git a/pkg/front_end/testcases/records/type_record_as_supertype.dart.strong.expect b/pkg/front_end/testcases/records/type_record_as_supertype.dart.strong.expect
index 2c8af64..df2e448 100644
--- a/pkg/front_end/testcases/records/type_record_as_supertype.dart.strong.expect
+++ b/pkg/front_end/testcases/records/type_record_as_supertype.dart.strong.expect
@@ -38,9 +38,9 @@
 // pkg/front_end/testcases/records/type_record_as_supertype.dart:22:16: Error: 'RR' is restricted and can't be extended or implemented.
 // abstract class C2 with RR {} // Error.
 //                ^
-// sdk/lib/core/record.dart:11:16: Context: This is the type denoted by the type alias.
-// abstract class Record {}
-//                ^
+// sdk/lib/core/record.dart:11:22: Context: This is the type denoted by the type alias.
+// abstract final class Record {}
+//                      ^
 //
 import self as self;
 import "dart:core" as core;
@@ -92,7 +92,7 @@
     : super core::Object::•()
     ;
 }
-abstract class _C1&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
+abstract final class _C1&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_C1&Object&Record
     : super core::Object::•()
     ;
@@ -102,7 +102,7 @@
     : super self::_C1&Object&Record::•()
     ;
 }
-abstract class _C2&Object&RR = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
+abstract final class _C2&Object&RR = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_C2&Object&RR
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/records/type_record_as_supertype.dart.strong.transformed.expect b/pkg/front_end/testcases/records/type_record_as_supertype.dart.strong.transformed.expect
index 1ace8f9..b4092d3 100644
--- a/pkg/front_end/testcases/records/type_record_as_supertype.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/records/type_record_as_supertype.dart.strong.transformed.expect
@@ -38,9 +38,9 @@
 // pkg/front_end/testcases/records/type_record_as_supertype.dart:22:16: Error: 'RR' is restricted and can't be extended or implemented.
 // abstract class C2 with RR {} // Error.
 //                ^
-// sdk/lib/core/record.dart:11:16: Context: This is the type denoted by the type alias.
-// abstract class Record {}
-//                ^
+// sdk/lib/core/record.dart:11:22: Context: This is the type denoted by the type alias.
+// abstract final class Record {}
+//                      ^
 //
 import self as self;
 import "dart:core" as core;
@@ -92,7 +92,7 @@
     : super core::Object::•()
     ;
 }
-abstract class _C1&Object&Record extends core::Object implements core::Record /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+abstract final class _C1&Object&Record extends core::Object implements core::Record /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_C1&Object&Record
     : super core::Object::•()
     ;
@@ -102,7 +102,7 @@
     : super self::_C1&Object&Record::•()
     ;
 }
-abstract class _C2&Object&RR extends core::Object implements core::Record /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+abstract final class _C2&Object&RR extends core::Object implements core::Record /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_C2&Object&RR
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.expect b/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.expect
index 2c8af64..df2e448 100644
--- a/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.expect
+++ b/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.expect
@@ -38,9 +38,9 @@
 // pkg/front_end/testcases/records/type_record_as_supertype.dart:22:16: Error: 'RR' is restricted and can't be extended or implemented.
 // abstract class C2 with RR {} // Error.
 //                ^
-// sdk/lib/core/record.dart:11:16: Context: This is the type denoted by the type alias.
-// abstract class Record {}
-//                ^
+// sdk/lib/core/record.dart:11:22: Context: This is the type denoted by the type alias.
+// abstract final class Record {}
+//                      ^
 //
 import self as self;
 import "dart:core" as core;
@@ -92,7 +92,7 @@
     : super core::Object::•()
     ;
 }
-abstract class _C1&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
+abstract final class _C1&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_C1&Object&Record
     : super core::Object::•()
     ;
@@ -102,7 +102,7 @@
     : super self::_C1&Object&Record::•()
     ;
 }
-abstract class _C2&Object&RR = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
+abstract final class _C2&Object&RR = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_C2&Object&RR
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.modular.expect b/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.modular.expect
index 2c8af64..df2e448 100644
--- a/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.modular.expect
@@ -38,9 +38,9 @@
 // pkg/front_end/testcases/records/type_record_as_supertype.dart:22:16: Error: 'RR' is restricted and can't be extended or implemented.
 // abstract class C2 with RR {} // Error.
 //                ^
-// sdk/lib/core/record.dart:11:16: Context: This is the type denoted by the type alias.
-// abstract class Record {}
-//                ^
+// sdk/lib/core/record.dart:11:22: Context: This is the type denoted by the type alias.
+// abstract final class Record {}
+//                      ^
 //
 import self as self;
 import "dart:core" as core;
@@ -92,7 +92,7 @@
     : super core::Object::•()
     ;
 }
-abstract class _C1&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
+abstract final class _C1&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_C1&Object&Record
     : super core::Object::•()
     ;
@@ -102,7 +102,7 @@
     : super self::_C1&Object&Record::•()
     ;
 }
-abstract class _C2&Object&RR = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
+abstract final class _C2&Object&RR = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_C2&Object&RR
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.outline.expect b/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.outline.expect
index f960292..c89ec82 100644
--- a/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.outline.expect
@@ -38,9 +38,9 @@
 // pkg/front_end/testcases/records/type_record_as_supertype.dart:22:16: Error: 'RR' is restricted and can't be extended or implemented.
 // abstract class C2 with RR {} // Error.
 //                ^
-// sdk/lib/core/record.dart:11:16: Context: This is the type denoted by the type alias.
-// abstract class Record {}
-//                ^
+// sdk/lib/core/record.dart:11:22: Context: This is the type denoted by the type alias.
+// abstract final class Record {}
+//                      ^
 //
 import self as self;
 import "dart:core" as core;
@@ -83,7 +83,7 @@
   synthetic constructor •() → self::B4
     ;
 }
-abstract class _C1&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
+abstract final class _C1&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_C1&Object&Record
     : super core::Object::•()
     ;
@@ -92,7 +92,7 @@
   synthetic constructor •() → self::C1
     ;
 }
-abstract class _C2&Object&RR = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
+abstract final class _C2&Object&RR = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_C2&Object&RR
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.transformed.expect b/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.transformed.expect
index 1ace8f9..b4092d3 100644
--- a/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/records/type_record_as_supertype.dart.weak.transformed.expect
@@ -38,9 +38,9 @@
 // pkg/front_end/testcases/records/type_record_as_supertype.dart:22:16: Error: 'RR' is restricted and can't be extended or implemented.
 // abstract class C2 with RR {} // Error.
 //                ^
-// sdk/lib/core/record.dart:11:16: Context: This is the type denoted by the type alias.
-// abstract class Record {}
-//                ^
+// sdk/lib/core/record.dart:11:22: Context: This is the type denoted by the type alias.
+// abstract final class Record {}
+//                      ^
 //
 import self as self;
 import "dart:core" as core;
@@ -92,7 +92,7 @@
     : super core::Object::•()
     ;
 }
-abstract class _C1&Object&Record extends core::Object implements core::Record /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+abstract final class _C1&Object&Record extends core::Object implements core::Record /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_C1&Object&Record
     : super core::Object::•()
     ;
@@ -102,7 +102,7 @@
     : super self::_C1&Object&Record::•()
     ;
 }
-abstract class _C2&Object&RR extends core::Object implements core::Record /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+abstract final class _C2&Object&RR extends core::Object implements core::Record /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_C2&Object&RR
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/records/type_record_unsupported.dart.strong.expect b/pkg/front_end/testcases/records/type_record_unsupported.dart.strong.expect
index fa21425..d9c5187 100644
--- a/pkg/front_end/testcases/records/type_record_unsupported.dart.strong.expect
+++ b/pkg/front_end/testcases/records/type_record_unsupported.dart.strong.expect
@@ -58,7 +58,7 @@
     : super core::Object::•()
     ;
 }
-abstract class _A3&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
+abstract final class _A3&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_A3&Object&Record
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/records/type_record_unsupported.dart.strong.transformed.expect b/pkg/front_end/testcases/records/type_record_unsupported.dart.strong.transformed.expect
index 4174f02..aea7b2e 100644
--- a/pkg/front_end/testcases/records/type_record_unsupported.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/records/type_record_unsupported.dart.strong.transformed.expect
@@ -58,7 +58,7 @@
     : super core::Object::•()
     ;
 }
-abstract class _A3&Object&Record extends core::Object implements core::Record /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+abstract final class _A3&Object&Record extends core::Object implements core::Record /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_A3&Object&Record
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.expect b/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.expect
index 5610029..fa3163b 100644
--- a/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.expect
+++ b/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.expect
@@ -58,7 +58,7 @@
     : super core::Object::•()
     ;
 }
-abstract class _A3&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
+abstract final class _A3&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_A3&Object&Record
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.modular.expect b/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.modular.expect
index 5610029..fa3163b 100644
--- a/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.modular.expect
@@ -58,7 +58,7 @@
     : super core::Object::•()
     ;
 }
-abstract class _A3&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
+abstract final class _A3&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_A3&Object&Record
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.outline.expect b/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.outline.expect
index 4dc5f91..53b2b68 100644
--- a/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.outline.expect
@@ -48,7 +48,7 @@
   synthetic constructor •() → self::A2
     ;
 }
-abstract class _A3&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
+abstract final class _A3&Object&Record = core::Object with core::Record /*isAnonymousMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_A3&Object&Record
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.transformed.expect b/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.transformed.expect
index 8bef6e6..fb6bddc 100644
--- a/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/records/type_record_unsupported.dart.weak.transformed.expect
@@ -58,7 +58,7 @@
     : super core::Object::•()
     ;
 }
-abstract class _A3&Object&Record extends core::Object implements core::Record /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
+abstract final class _A3&Object&Record extends core::Object implements core::Record /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::_A3&Object&Record
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index e2454e2..e987dd7 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -150,7 +150,6 @@
 nnbd/no_support_for_old_null_aware_index_access_syntax: RuntimeError # Expected.
 no_such_method_forwarders/mixin_nsm: TypeCheckError
 patterns/pattern_types: TypeCheckError
-patterns/shared_errors: TypeCheckError
 rasta/abstract_constructor: RuntimeError
 rasta/bad_constructor_redirection: RuntimeError
 rasta/bad_continue: RuntimeError
diff --git a/pkg/front_end/testcases/weak.status b/pkg/front_end/testcases/weak.status
index 75fe83c..3dc6e6f 100644
--- a/pkg/front_end/testcases/weak.status
+++ b/pkg/front_end/testcases/weak.status
@@ -232,7 +232,6 @@
 nnbd_mixed/messages_with_types_opt_out: TypeCheckError
 nnbd_mixed/mixin_from_opt_in/main: RuntimeError
 patterns/pattern_types: TypeCheckError
-patterns/shared_errors: TypeCheckError
 rasta/abstract_constructor: RuntimeError
 rasta/bad_constructor_redirection: RuntimeError
 rasta/bad_continue: RuntimeError
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index e32421c..a44c05e 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -13325,7 +13325,11 @@
   final Nullability declaredNullability;
 
   RecordType(this.positional, this.named, this.declaredNullability)
-      : assert(() {
+      : /*TODO(johnniwinther): Enabled this assert:
+        assert(named.length == named.map((p) => p.name).toSet().length,
+            "Named field types must have unique names in a RecordType: "
+            "${named}"),*/
+        assert(() {
           // Assert that the named field types are sorted.
           for (int i = 1; i < named.length; i++) {
             if (named[i].name.compareTo(named[i - 1].name) < 0) {