Patterns parsing: disallow unaryPattern or relationalPattern in unaryPattern.

The precedence-based pattern parser can understand a unary pattern
inside another unary pattern (e.g. `_ as int as num`) or a relational
pattern inside a unary pattern (e.g. `> 1?`), but the specification
prohibits these constructions because they're difficult to read and
not very useful.

This change updates the implementation to match the spec, by producing
the appropriate error.  The offset and length of the error cover the
inner pattern, so it should be easy to construct an analysis server
quick fix that inserts the necessary parentheses.

Bug: https://github.com/dart-lang/sdk/issues/50035
Change-Id: I33e74d6d1f863e7162851d26fefbacd4fd17277c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/292120
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index dfd21a6..3edbcd7 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -7192,6 +7192,19 @@
         r"""Try changing the inline function type (as in 'int f()') to a prefixed function type using the `Function` keyword (as in 'int Function() f').""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeInvalidInsideUnaryPattern =
+    messageInvalidInsideUnaryPattern;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageInvalidInsideUnaryPattern = const MessageCode(
+    "InvalidInsideUnaryPattern",
+    index: 150,
+    problemMessage:
+        r"""This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.""",
+    correctionMessage:
+        r"""Try combining into a single pattern if possible, or enclose the inner pattern in parentheses.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeInvalidNnbdDillLibrary = messageInvalidNnbdDillLibrary;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
index 2777ff4..6a8ac5d 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
@@ -333,6 +333,14 @@
   /// TODO(paulberry): remove this flag when appropriate.
   final bool allowPatterns;
 
+  /// Indicates whether the last pattern parsed is allowed inside unary
+  /// patterns.  This is set by [parsePrimaryPattern] and [parsePattern].
+  ///
+  /// TODO(paulberry): once this package can safely use Dart 3.0 features,
+  /// remove this boolean and instead return a record (Token, bool) from the
+  /// [parsePrimaryPattern] and [parsePattern].
+  bool isLastPatternAllowedInsideUnaryPattern = false;
+
   Parser(this.listener,
       {this.useImplicitCreationExpression = true, this.allowPatterns = false})
       : assert(listener != null); // ignore:unnecessary_null_comparison
@@ -9586,6 +9594,7 @@
       {int precedence = 1}) {
     assert(precedence >= 1);
     assert(precedence <= SELECTOR_PRECEDENCE);
+    Token start = token.next!;
     token = parsePrimaryPattern(token, patternContext);
     while (true) {
       Token next = token.next!;
@@ -9594,21 +9603,31 @@
       switch (next.lexeme) {
         // castPattern ::= primaryPattern 'as' type
         case 'as':
+          if (!isLastPatternAllowedInsideUnaryPattern) {
+            reportRecoverableErrorWithEnd(
+                start, token, codes.messageInvalidInsideUnaryPattern);
+          }
           Token operator = token = next;
           listener.beginAsOperatorType(token);
           TypeInfo typeInfo = computeTypeAfterIsOrAs(token);
           token = typeInfo.ensureTypeNotVoid(token, this);
           listener.endAsOperatorType(operator);
           listener.handleCastPattern(operator);
-          // TODO(paulberry): report error if cast is followed by something the
-          // grammar doesn't permit
           break;
         case '!':
+          if (!isLastPatternAllowedInsideUnaryPattern) {
+            reportRecoverableErrorWithEnd(
+                start, token, codes.messageInvalidInsideUnaryPattern);
+          }
           // nullAssertPattern ::= primaryPattern '!'
           listener.handleNullAssertPattern(next);
           token = next;
           break;
         case '?':
+          if (!isLastPatternAllowedInsideUnaryPattern) {
+            reportRecoverableErrorWithEnd(
+                start, token, codes.messageInvalidInsideUnaryPattern);
+          }
           // nullCheckPattern ::= primaryPattern '?'
           listener.handleNullCheckPattern(next);
           token = next;
@@ -9625,6 +9644,9 @@
           // Some other operator that doesn't belong in a pattern
           return token;
       }
+      // None of the pattern types handled by the switch above are valid inside
+      // a unary pattern.
+      isLastPatternAllowedInsideUnaryPattern = false;
     }
   }
 
@@ -9670,6 +9692,7 @@
         // skipOuterPattern would have skipped this pattern properly.
         assert(
             identical(inhibitPrinting(() => skipOuterPattern(start)), token));
+        isLastPatternAllowedInsideUnaryPattern = true;
         return token;
       case '{':
         // mapPattern        ::= typeArguments? '{' mapPatternEntries? '}'
@@ -9681,6 +9704,7 @@
         // skipOuterPattern would have skipped this pattern properly.
         assert(
             identical(inhibitPrinting(() => skipOuterPattern(start)), token));
+        isLastPatternAllowedInsideUnaryPattern = true;
         return token;
     }
     // Whatever was after the optional type arguments didn't parse as a pattern
@@ -9691,6 +9715,7 @@
       case 'var':
       case 'final':
         // variablePattern ::= ( 'var' | 'final' | 'final'? type )? identifier
+        isLastPatternAllowedInsideUnaryPattern = true;
         return parseVariablePattern(token, patternContext);
       case '(':
         // "(" could start a record type (which has to be followed by an
@@ -9700,6 +9725,7 @@
           if (typeInfo is ComplexTypeInfo &&
               typeInfo.isRecordType &&
               !typeInfo.recovered) {
+            isLastPatternAllowedInsideUnaryPattern = true;
             return parseVariablePattern(token, patternContext,
                 typeInfo: typeInfo);
           }
@@ -9721,6 +9747,7 @@
         // properly.
         assert(
             identical(inhibitPrinting(() => skipOuterPattern(start)), token));
+        isLastPatternAllowedInsideUnaryPattern = true;
         return token;
       case 'const':
         // constantPattern ::= booleanLiteral
@@ -9741,6 +9768,7 @@
         token = parsePrecedenceExpression(const_, EQUALITY_PRECEDENCE,
             /* allowCascades = */ false, ConstantPatternContext.explicit);
         listener.endConstantPattern(const_);
+        isLastPatternAllowedInsideUnaryPattern = true;
         return token;
     }
     TokenType type = next.type;
@@ -9755,10 +9783,12 @@
       token = parsePrecedenceExpression(next, SHIFT_PRECEDENCE,
           /* allowCascades = */ false, ConstantPatternContext.none);
       listener.handleRelationalPattern(operator);
+      isLastPatternAllowedInsideUnaryPattern = false;
       return token;
     }
     TypeInfo typeInfo = computeVariablePatternType(token);
     if (typeInfo != noType) {
+      isLastPatternAllowedInsideUnaryPattern = true;
       return parseVariablePattern(token, patternContext, typeInfo: typeInfo);
     }
     // objectPattern ::= typeName typeArguments? '(' patternFields? ')'
@@ -9795,6 +9825,7 @@
         // skipOuterPattern would have skipped this pattern properly.
         assert(
             identical(inhibitPrinting(() => skipOuterPattern(start)), token));
+        isLastPatternAllowedInsideUnaryPattern = true;
         return token;
       } else if (dot == null) {
         // It's a single identifier.  If it's a wildcard pattern or we're in an
@@ -9802,6 +9833,7 @@
         if (!patternContext.isRefutable || firstIdentifier.lexeme == '_') {
           // It's a wildcard pattern with no preceding type, so parse it as a
           // variable pattern.
+          isLastPatternAllowedInsideUnaryPattern = true;
           return parseVariablePattern(beforeFirstIdentifier, patternContext,
               typeInfo: typeInfo);
         }
@@ -9816,6 +9848,7 @@
     token = parsePrecedenceExpression(token, EQUALITY_PRECEDENCE,
         /* allowCascades = */ false, ConstantPatternContext.implicit);
     listener.endConstantPattern(/* constKeyword = */ null);
+    isLastPatternAllowedInsideUnaryPattern = true;
     return token;
   }
 
diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
index 75d1828..76ea438 100644
--- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
+++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
@@ -2229,6 +2229,8 @@
   status: needsEvaluation
 ParserErrorCode.INVALID_INITIALIZER:
   status: needsEvaluation
+ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN:
+  status: needsEvaluation
 ParserErrorCode.INVALID_LITERAL_IN_CONFIGURATION:
   status: needsEvaluation
 ParserErrorCode.INVALID_OPERATOR:
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
index 738d1d3..a9506d6 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
@@ -164,6 +164,7 @@
   ParserErrorCode.INTERFACE_MIXIN,
   ParserErrorCode.SEALED_MIXIN,
   ParserErrorCode.VARIABLE_PATTERN_KEYWORD_IN_DECLARATION_CONTEXT,
+  ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN,
 ];
 
 class ParserErrorCode extends ErrorCode {
@@ -1024,6 +1025,16 @@
     correctionMessage: "To initialize a field, use the syntax 'name = value'.",
   );
 
+  ///  No parameters.
+  static const ParserErrorCode INVALID_INSIDE_UNARY_PATTERN = ParserErrorCode(
+    'INVALID_INSIDE_UNARY_PATTERN',
+    "This pattern cannot appear inside a unary pattern (cast pattern, null "
+        "check pattern, or null assert pattern) without parentheses.",
+    correctionMessage:
+        "Try combining into a single pattern if possible, or enclose the inner "
+        "pattern in parentheses.",
+  );
+
   static const ParserErrorCode INVALID_LITERAL_IN_CONFIGURATION =
       ParserErrorCode(
     'INVALID_LITERAL_IN_CONFIGURATION',
diff --git a/pkg/analyzer/lib/src/error/error_code_values.g.dart b/pkg/analyzer/lib/src/error/error_code_values.g.dart
index 40ff150..1b3e48c 100644
--- a/pkg/analyzer/lib/src/error/error_code_values.g.dart
+++ b/pkg/analyzer/lib/src/error/error_code_values.g.dart
@@ -740,6 +740,7 @@
   ParserErrorCode.INVALID_GENERIC_FUNCTION_TYPE,
   ParserErrorCode.INVALID_HEX_ESCAPE,
   ParserErrorCode.INVALID_INITIALIZER,
+  ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN,
   ParserErrorCode.INVALID_LITERAL_IN_CONFIGURATION,
   ParserErrorCode.INVALID_OPERATOR,
   ParserErrorCode.INVALID_OPERATOR_FOR_SUPER,
diff --git a/pkg/analyzer/test/generated/patterns_parser_test.dart b/pkg/analyzer/test/generated/patterns_parser_test.dart
index 7cd7818..a71c9dd 100644
--- a/pkg/analyzer/test/generated/patterns_parser_test.dart
+++ b/pkg/analyzer/test/generated/patterns_parser_test.dart
@@ -595,6 +595,67 @@
 ''');
   }
 
+  test_cast_insideCast() {
+    _parse('''
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y as int as num:
+      break;
+  }
+}
+''', errors: [
+      error(ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN, 51, 8),
+    ]);
+    var node = findNode.singleGuardedPattern.pattern;
+    assertParsedNodeText(node, r'''
+CastPattern
+  pattern: CastPattern
+    pattern: ConstantPattern
+      expression: SimpleIdentifier
+        token: y
+    asToken: as
+    type: NamedType
+      name: SimpleIdentifier
+        token: int
+  asToken: as
+  type: NamedType
+    name: SimpleIdentifier
+      token: num
+''');
+  }
+
+  test_cast_insideCast_parenthesized() {
+    _parse('''
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case (y as int) as num:
+      break;
+  }
+}
+''');
+    var node = findNode.singleGuardedPattern.pattern;
+    assertParsedNodeText(node, r'''
+CastPattern
+  pattern: ParenthesizedPattern
+    leftParenthesis: (
+    pattern: CastPattern
+      pattern: ConstantPattern
+        expression: SimpleIdentifier
+          token: y
+      asToken: as
+      type: NamedType
+        name: SimpleIdentifier
+          token: int
+    rightParenthesis: )
+  asToken: as
+  type: NamedType
+    name: SimpleIdentifier
+      token: num
+''');
+  }
+
   test_cast_insideIfCase() {
     _parse('''
 void f(x) {
@@ -809,6 +870,61 @@
 ''');
   }
 
+  test_cast_insideNullAssert() {
+    _parse('''
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y as int!:
+      break;
+  }
+}
+''', errors: [
+      error(ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN, 51, 8),
+    ]);
+    var node = findNode.singleGuardedPattern.pattern;
+    assertParsedNodeText(node, r'''
+NullAssertPattern
+  pattern: CastPattern
+    pattern: ConstantPattern
+      expression: SimpleIdentifier
+        token: y
+    asToken: as
+    type: NamedType
+      name: SimpleIdentifier
+        token: int
+  operator: !
+''');
+  }
+
+  test_cast_insideNullCheck() {
+    _parse('''
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y as int? ?:
+      break;
+  }
+}
+''', errors: [
+      error(ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN, 51, 9),
+    ]);
+    var node = findNode.singleGuardedPattern.pattern;
+    assertParsedNodeText(node, r'''
+NullCheckPattern
+  pattern: CastPattern
+    pattern: ConstantPattern
+      expression: SimpleIdentifier
+        token: y
+    asToken: as
+    type: NamedType
+      name: SimpleIdentifier
+        token: int
+      question: ?
+  operator: ?
+''');
+  }
+
   test_cast_insideObject_explicitlyNamed() {
     _parse('''
 class C {
@@ -5082,6 +5198,33 @@
 ''');
   }
 
+  test_nullAssert_insideCast() {
+    _parse('''
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y! as num:
+      break;
+  }
+}
+''', errors: [
+      error(ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN, 51, 2),
+    ]);
+    var node = findNode.singleGuardedPattern.pattern;
+    assertParsedNodeText(node, r'''
+CastPattern
+  pattern: NullAssertPattern
+    pattern: ConstantPattern
+      expression: SimpleIdentifier
+        token: y
+    operator: !
+  asToken: as
+  type: NamedType
+    name: SimpleIdentifier
+      token: num
+''');
+  }
+
   test_nullAssert_insideIfCase() {
     _parse('''
 void f(x) {
@@ -5247,6 +5390,54 @@
 ''');
   }
 
+  test_nullAssert_insideNullAssert() {
+    _parse('''
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y!!:
+      break;
+  }
+}
+''', errors: [
+      error(ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN, 51, 2),
+    ]);
+    var node = findNode.singleGuardedPattern.pattern;
+    assertParsedNodeText(node, r'''
+NullAssertPattern
+  pattern: NullAssertPattern
+    pattern: ConstantPattern
+      expression: SimpleIdentifier
+        token: y
+    operator: !
+  operator: !
+''');
+  }
+
+  test_nullAssert_insideNullCheck() {
+    _parse('''
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y!?:
+      break;
+  }
+}
+''', errors: [
+      error(ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN, 51, 2),
+    ]);
+    var node = findNode.singleGuardedPattern.pattern;
+    assertParsedNodeText(node, r'''
+NullCheckPattern
+  pattern: NullAssertPattern
+    pattern: ConstantPattern
+      expression: SimpleIdentifier
+        token: y
+    operator: !
+  operator: ?
+''');
+  }
+
   test_nullAssert_insideObject_explicitlyNamed() {
     _parse('''
 class C {
@@ -5443,6 +5634,33 @@
 ''');
   }
 
+  test_nullCheck_insideCast() {
+    _parse('''
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y? as num:
+      break;
+  }
+}
+''', errors: [
+      error(ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN, 51, 2),
+    ]);
+    var node = findNode.singleGuardedPattern.pattern;
+    assertParsedNodeText(node, r'''
+CastPattern
+  pattern: NullCheckPattern
+    pattern: ConstantPattern
+      expression: SimpleIdentifier
+        token: y
+    operator: ?
+  asToken: as
+  type: NamedType
+    name: SimpleIdentifier
+      token: num
+''');
+  }
+
   test_nullCheck_insideIfCase() {
     _parse('''
 void f(x) {
@@ -5608,6 +5826,54 @@
 ''');
   }
 
+  test_nullCheck_insideNullAssert() {
+    _parse('''
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y?!:
+      break;
+  }
+}
+''', errors: [
+      error(ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN, 51, 2),
+    ]);
+    var node = findNode.singleGuardedPattern.pattern;
+    assertParsedNodeText(node, r'''
+NullAssertPattern
+  pattern: NullCheckPattern
+    pattern: ConstantPattern
+      expression: SimpleIdentifier
+        token: y
+    operator: ?
+  operator: !
+''');
+  }
+
+  test_nullCheck_insideNullCheck() {
+    _parse('''
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y? ?:
+      break;
+  }
+}
+''', errors: [
+      error(ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN, 51, 2),
+    ]);
+    var node = findNode.singleGuardedPattern.pattern;
+    assertParsedNodeText(node, r'''
+NullCheckPattern
+  pattern: NullCheckPattern
+    pattern: ConstantPattern
+      expression: SimpleIdentifier
+        token: y
+    operator: ?
+  operator: ?
+''');
+  }
+
   test_nullCheck_insideObject_explicitlyNamed() {
     _parse('''
 class C {
@@ -7896,6 +8162,50 @@
 ''');
   }
 
+  test_relational_insideNullCheck_equal() {
+    _parse('''
+void f(x) {
+  switch (x) {
+    case == 1?:
+      break;
+  }
+}
+''', errors: [
+      error(ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN, 36, 4),
+    ]);
+    var node = findNode.singleGuardedPattern.pattern;
+    assertParsedNodeText(node, r'''
+NullCheckPattern
+  pattern: RelationalPattern
+    operator: ==
+    operand: IntegerLiteral
+      literal: 1
+  operator: ?
+''');
+  }
+
+  test_relational_insideNullCheck_greaterThan() {
+    _parse('''
+void f(x) {
+  switch (x) {
+    case > 1?:
+      break;
+  }
+}
+''', errors: [
+      error(ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN, 36, 3),
+    ]);
+    var node = findNode.singleGuardedPattern.pattern;
+    assertParsedNodeText(node, r'''
+NullCheckPattern
+  pattern: RelationalPattern
+    operator: >
+    operand: IntegerLiteral
+      literal: 1
+  operator: ?
+''');
+  }
+
   test_relational_insideObject_explicitlyNamed() {
     _parse('''
 class C {
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 5cfaf11..ccc26ed 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -6708,6 +6708,18 @@
     }
     ```
 
+InvalidInsideUnaryPattern:
+  problemMessage: This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+  correctionMessage: Try combining into a single pattern if possible, or enclose the inner pattern in parentheses.
+  analyzerCode: ParserErrorCode.INVALID_INSIDE_UNARY_PATTERN
+  index: 150
+  experiments: patterns
+  comment: No parameters.
+  script: |
+    void f(x) {
+      if (x case _ as int as num) {}
+    }
+
 WeakReferenceNotStatic:
   problemMessage: "Weak reference pragma can be used on a static method only."
 
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideCast.dart b/pkg/front_end/parser_testcases/patterns/cast_insideCast.dart
new file mode 100644
index 0000000..8db848d
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideCast.dart
@@ -0,0 +1,7 @@
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y as int as num:
+      break;
+  }
+}
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideCast.dart.expect b/pkg/front_end/parser_testcases/patterns/cast_insideCast.dart.expect
new file mode 100644
index 0000000..d166736
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideCast.dart.expect
@@ -0,0 +1,74 @@
+Problems reported:
+
+parser/patterns/cast_insideCast:4:10: This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+    case y as int as num:
+         ^^^^^^^^
+
+beginCompilationUnit(void)
+  beginMetadataStar(void)
+  endMetadataStar(0)
+  beginTopLevelMember(void)
+    beginTopLevelMethod(, null, null)
+      handleVoidKeyword(void)
+      handleIdentifier(f, topLevelFunctionDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.TopLevelMethod)
+        beginMetadataStar(x)
+        endMetadataStar(0)
+        beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+          handleNoType(()
+          handleIdentifier(x, formalParameterDeclaration)
+          handleFormalParameterWithoutValue())
+        endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+      endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        beginMetadataStar(const)
+        endMetadataStar(0)
+        handleNoType(const)
+        beginVariablesDeclaration(y, null, const)
+          handleIdentifier(y, localVariableDeclaration)
+          beginInitializedIdentifier(y)
+            beginVariableInitializer(=)
+              handleLiteralInt(1)
+            endVariableInitializer(=)
+          endInitializedIdentifier(y)
+        endVariablesDeclaration(1, ;)
+        beginSwitchStatement(switch)
+          handleIdentifier(x, expression)
+          handleNoTypeArguments())
+          handleNoArguments())
+          handleSend(x, ))
+          handleParenthesizedCondition((, null, null)
+          beginSwitchBlock({)
+            beginCaseExpression(case)
+              beginConstantPattern(null)
+                handleIdentifier(y, expression)
+                handleNoTypeArguments(as)
+                handleNoArguments(as)
+                handleSend(y, as)
+              endConstantPattern(null)
+              beginAsOperatorType(as)
+                handleIdentifier(int, typeReference)
+                handleNoTypeArguments(as)
+                handleType(int, null)
+              endAsOperatorType(as)
+              handleCastPattern(as)
+              handleRecoverableError(InvalidInsideUnaryPattern, y, int)
+              beginAsOperatorType(as)
+                handleIdentifier(num, typeReference)
+                handleNoTypeArguments(:)
+                handleType(num, null)
+              endAsOperatorType(as)
+              handleCastPattern(as)
+              handleSwitchCaseNoWhenClause(num)
+            endCaseExpression(case, null, :)
+            beginSwitchCase(0, 1, case)
+              handleBreakStatement(false, break, ;)
+            endSwitchCase(0, 1, null, null, 1, case, })
+          endSwitchBlock(1, {, })
+        endSwitchStatement(switch, })
+      endBlockFunctionBody(2, {, })
+    endTopLevelMethod(void, null, })
+  endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideCast.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/cast_insideCast.dart.intertwined.expect
new file mode 100644
index 0000000..75c0465
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideCast.dart.intertwined.expect
@@ -0,0 +1,152 @@
+parseUnit(void)
+  skipErrorTokens(void)
+  listener: beginCompilationUnit(void)
+  syntheticPreviousToken(void)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(void)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl()
+      listener: beginTopLevelMember(void)
+      parseTopLevelMethod(, null, null, , Instance of 'VoidType', null, f, false)
+        listener: beginTopLevelMethod(, null, null)
+        listener: handleVoidKeyword(void)
+        ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+          listener: handleIdentifier(f, topLevelFunctionDeclaration)
+        parseMethodTypeVar(f)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(f, MemberKind.TopLevelMethod)
+            parseFormalParametersRest((, MemberKind.TopLevelMethod)
+              listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+              parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+                parseMetadataStar(()
+                  listener: beginMetadataStar(x)
+                  listener: endMetadataStar(0)
+                listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+                listener: handleNoType(()
+                ensureIdentifier((, formalParameterDeclaration)
+                  listener: handleIdentifier(x, formalParameterDeclaration)
+                listener: handleFormalParameterWithoutValue())
+                listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+              listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+        parseAsyncModifierOpt())
+          listener: handleAsyncModifier(null, null)
+          inPlainSync()
+        parseFunctionBody(), false, false)
+          listener: beginBlockFunctionBody({)
+          notEofOrValue(}, const)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrConstDeclaration({)
+                parseExpressionStatementOrDeclarationAfterModifiers(const, {, null, const, Instance of 'NoType', null)
+                  looksLikeLocalFunction(y)
+                  listener: beginMetadataStar(const)
+                  listener: endMetadataStar(0)
+                  listener: handleNoType(const)
+                  listener: beginVariablesDeclaration(y, null, const)
+                  parseVariablesDeclarationRest(const, true)
+                    parseOptionallyInitializedIdentifier(const)
+                      ensureIdentifier(const, localVariableDeclaration)
+                        listener: handleIdentifier(y, localVariableDeclaration)
+                      listener: beginInitializedIdentifier(y)
+                      parseVariableInitializerOpt(y)
+                        listener: beginVariableInitializer(=)
+                        parseExpression(=)
+                          looksLikeOuterPatternEquals(=)
+                            skipOuterPattern(=)
+                          parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
+                            parseUnaryExpression(=, true, ConstantPatternContext.none)
+                              parsePrimary(=, expression, ConstantPatternContext.none)
+                                parseLiteralInt(=)
+                                  listener: handleLiteralInt(1)
+                        listener: endVariableInitializer(=)
+                      listener: endInitializedIdentifier(y)
+                    ensureSemicolon(1)
+                    listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, switch)
+          parseStatement(;)
+            parseStatementX(;)
+              parseSwitchStatement(;)
+                listener: beginSwitchStatement(switch)
+                ensureParenthesizedCondition(switch, allowCase: false)
+                  parseExpressionInParenthesisRest((, allowCase: false)
+                    parseExpression(()
+                      looksLikeOuterPatternEquals(()
+                        skipOuterPattern(()
+                          skipObjectPatternRest(x)
+                      parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+                        parseUnaryExpression((, true, ConstantPatternContext.none)
+                          parsePrimary((, expression, ConstantPatternContext.none)
+                            parseSendOrFunctionLiteral((, expression, ConstantPatternContext.none)
+                              parseSend((, expression, ConstantPatternContext.none)
+                                isNextIdentifier(()
+                                ensureIdentifier((, expression)
+                                  listener: handleIdentifier(x, expression)
+                                listener: handleNoTypeArguments())
+                                parseArgumentsOpt(x)
+                                  listener: handleNoArguments())
+                                listener: handleSend(x, ))
+                    ensureCloseParen(x, ()
+                    listener: handleParenthesizedCondition((, null, null)
+                parseSwitchBlock())
+                  ensureBlock(), null, switch statement)
+                  listener: beginSwitchBlock({)
+                  notEofOrValue(}, case)
+                  peekPastLabels(case)
+                  listener: beginCaseExpression(case)
+                  parsePattern(case, PatternContext.matching, precedence: 1)
+                    parsePrimaryPattern(case, PatternContext.matching)
+                      listener: beginConstantPattern(null)
+                      parsePrecedenceExpression(case, 7, false, ConstantPatternContext.implicit)
+                        parseUnaryExpression(case, false, ConstantPatternContext.implicit)
+                          parsePrimary(case, expression, ConstantPatternContext.implicit)
+                            parseSendOrFunctionLiteral(case, expression, ConstantPatternContext.implicit)
+                              parseSend(case, expression, ConstantPatternContext.implicit)
+                                isNextIdentifier(case)
+                                ensureIdentifier(case, expression)
+                                  listener: handleIdentifier(y, expression)
+                                listener: handleNoTypeArguments(as)
+                                parseArgumentsOpt(y)
+                                  listener: handleNoArguments(as)
+                                listener: handleSend(y, as)
+                      listener: endConstantPattern(null)
+                    listener: beginAsOperatorType(as)
+                    computeTypeAfterIsOrAs(as)
+                    listener: handleIdentifier(int, typeReference)
+                    listener: handleNoTypeArguments(as)
+                    listener: handleType(int, null)
+                    listener: endAsOperatorType(as)
+                    listener: handleCastPattern(as)
+                    reportRecoverableErrorWithEnd(y, int, InvalidInsideUnaryPattern)
+                      listener: handleRecoverableError(InvalidInsideUnaryPattern, y, int)
+                    listener: beginAsOperatorType(as)
+                    computeTypeAfterIsOrAs(as)
+                    listener: handleIdentifier(num, typeReference)
+                    listener: handleNoTypeArguments(:)
+                    listener: handleType(num, null)
+                    listener: endAsOperatorType(as)
+                    listener: handleCastPattern(as)
+                  listener: handleSwitchCaseNoWhenClause(num)
+                  ensureColon(num)
+                  listener: endCaseExpression(case, null, :)
+                  peekPastLabels(break)
+                  parseStatementsInSwitchCase(:, break, case, 0, 1, null, null)
+                    listener: beginSwitchCase(0, 1, case)
+                    parseStatement(:)
+                      parseStatementX(:)
+                        parseBreakStatement(:)
+                          isBreakAllowed()
+                          ensureSemicolon(break)
+                          listener: handleBreakStatement(false, break, ;)
+                    peekPastLabels(})
+                    listener: endSwitchCase(0, 1, null, null, 1, case, })
+                  notEofOrValue(}, })
+                  listener: endSwitchBlock(1, {, })
+                listener: endSwitchStatement(switch, })
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(2, {, })
+        listener: endTopLevelMethod(void, null, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(void)
+  listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideCast.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/cast_insideCast.dart.parser.expect
new file mode 100644
index 0000000..242ee44
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideCast.dart.parser.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y as int as num:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken] as[KeywordToken] int[StringToken] as[KeywordToken] num[StringToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideCast.dart.scanner.expect b/pkg/front_end/parser_testcases/patterns/cast_insideCast.dart.scanner.expect
new file mode 100644
index 0000000..242ee44
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideCast.dart.scanner.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y as int as num:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken] as[KeywordToken] int[StringToken] as[KeywordToken] num[StringToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideCast_parenthesized.dart b/pkg/front_end/parser_testcases/patterns/cast_insideCast_parenthesized.dart
new file mode 100644
index 0000000..0a818dd
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideCast_parenthesized.dart
@@ -0,0 +1,7 @@
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case (y as int) as num:
+      break;
+  }
+}
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideCast_parenthesized.dart.expect b/pkg/front_end/parser_testcases/patterns/cast_insideCast_parenthesized.dart.expect
new file mode 100644
index 0000000..14b3a9c
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideCast_parenthesized.dart.expect
@@ -0,0 +1,68 @@
+beginCompilationUnit(void)
+  beginMetadataStar(void)
+  endMetadataStar(0)
+  beginTopLevelMember(void)
+    beginTopLevelMethod(, null, null)
+      handleVoidKeyword(void)
+      handleIdentifier(f, topLevelFunctionDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.TopLevelMethod)
+        beginMetadataStar(x)
+        endMetadataStar(0)
+        beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+          handleNoType(()
+          handleIdentifier(x, formalParameterDeclaration)
+          handleFormalParameterWithoutValue())
+        endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+      endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        beginMetadataStar(const)
+        endMetadataStar(0)
+        handleNoType(const)
+        beginVariablesDeclaration(y, null, const)
+          handleIdentifier(y, localVariableDeclaration)
+          beginInitializedIdentifier(y)
+            beginVariableInitializer(=)
+              handleLiteralInt(1)
+            endVariableInitializer(=)
+          endInitializedIdentifier(y)
+        endVariablesDeclaration(1, ;)
+        beginSwitchStatement(switch)
+          handleIdentifier(x, expression)
+          handleNoTypeArguments())
+          handleNoArguments())
+          handleSend(x, ))
+          handleParenthesizedCondition((, null, null)
+          beginSwitchBlock({)
+            beginCaseExpression(case)
+              beginConstantPattern(null)
+                handleIdentifier(y, expression)
+                handleNoTypeArguments(as)
+                handleNoArguments(as)
+                handleSend(y, as)
+              endConstantPattern(null)
+              beginAsOperatorType(as)
+                handleIdentifier(int, typeReference)
+                handleNoTypeArguments())
+                handleType(int, null)
+              endAsOperatorType(as)
+              handleCastPattern(as)
+              handleParenthesizedPattern(()
+              beginAsOperatorType(as)
+                handleIdentifier(num, typeReference)
+                handleNoTypeArguments(:)
+                handleType(num, null)
+              endAsOperatorType(as)
+              handleCastPattern(as)
+              handleSwitchCaseNoWhenClause(num)
+            endCaseExpression(case, null, :)
+            beginSwitchCase(0, 1, case)
+              handleBreakStatement(false, break, ;)
+            endSwitchCase(0, 1, null, null, 1, case, })
+          endSwitchBlock(1, {, })
+        endSwitchStatement(switch, })
+      endBlockFunctionBody(2, {, })
+    endTopLevelMethod(void, null, })
+  endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideCast_parenthesized.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/cast_insideCast_parenthesized.dart.intertwined.expect
new file mode 100644
index 0000000..80392a1
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideCast_parenthesized.dart.intertwined.expect
@@ -0,0 +1,155 @@
+parseUnit(void)
+  skipErrorTokens(void)
+  listener: beginCompilationUnit(void)
+  syntheticPreviousToken(void)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(void)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl()
+      listener: beginTopLevelMember(void)
+      parseTopLevelMethod(, null, null, , Instance of 'VoidType', null, f, false)
+        listener: beginTopLevelMethod(, null, null)
+        listener: handleVoidKeyword(void)
+        ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+          listener: handleIdentifier(f, topLevelFunctionDeclaration)
+        parseMethodTypeVar(f)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(f, MemberKind.TopLevelMethod)
+            parseFormalParametersRest((, MemberKind.TopLevelMethod)
+              listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+              parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+                parseMetadataStar(()
+                  listener: beginMetadataStar(x)
+                  listener: endMetadataStar(0)
+                listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+                listener: handleNoType(()
+                ensureIdentifier((, formalParameterDeclaration)
+                  listener: handleIdentifier(x, formalParameterDeclaration)
+                listener: handleFormalParameterWithoutValue())
+                listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+              listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+        parseAsyncModifierOpt())
+          listener: handleAsyncModifier(null, null)
+          inPlainSync()
+        parseFunctionBody(), false, false)
+          listener: beginBlockFunctionBody({)
+          notEofOrValue(}, const)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrConstDeclaration({)
+                parseExpressionStatementOrDeclarationAfterModifiers(const, {, null, const, Instance of 'NoType', null)
+                  looksLikeLocalFunction(y)
+                  listener: beginMetadataStar(const)
+                  listener: endMetadataStar(0)
+                  listener: handleNoType(const)
+                  listener: beginVariablesDeclaration(y, null, const)
+                  parseVariablesDeclarationRest(const, true)
+                    parseOptionallyInitializedIdentifier(const)
+                      ensureIdentifier(const, localVariableDeclaration)
+                        listener: handleIdentifier(y, localVariableDeclaration)
+                      listener: beginInitializedIdentifier(y)
+                      parseVariableInitializerOpt(y)
+                        listener: beginVariableInitializer(=)
+                        parseExpression(=)
+                          looksLikeOuterPatternEquals(=)
+                            skipOuterPattern(=)
+                          parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
+                            parseUnaryExpression(=, true, ConstantPatternContext.none)
+                              parsePrimary(=, expression, ConstantPatternContext.none)
+                                parseLiteralInt(=)
+                                  listener: handleLiteralInt(1)
+                        listener: endVariableInitializer(=)
+                      listener: endInitializedIdentifier(y)
+                    ensureSemicolon(1)
+                    listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, switch)
+          parseStatement(;)
+            parseStatementX(;)
+              parseSwitchStatement(;)
+                listener: beginSwitchStatement(switch)
+                ensureParenthesizedCondition(switch, allowCase: false)
+                  parseExpressionInParenthesisRest((, allowCase: false)
+                    parseExpression(()
+                      looksLikeOuterPatternEquals(()
+                        skipOuterPattern(()
+                          skipObjectPatternRest(x)
+                      parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+                        parseUnaryExpression((, true, ConstantPatternContext.none)
+                          parsePrimary((, expression, ConstantPatternContext.none)
+                            parseSendOrFunctionLiteral((, expression, ConstantPatternContext.none)
+                              parseSend((, expression, ConstantPatternContext.none)
+                                isNextIdentifier(()
+                                ensureIdentifier((, expression)
+                                  listener: handleIdentifier(x, expression)
+                                listener: handleNoTypeArguments())
+                                parseArgumentsOpt(x)
+                                  listener: handleNoArguments())
+                                listener: handleSend(x, ))
+                    ensureCloseParen(x, ()
+                    listener: handleParenthesizedCondition((, null, null)
+                parseSwitchBlock())
+                  ensureBlock(), null, switch statement)
+                  listener: beginSwitchBlock({)
+                  notEofOrValue(}, case)
+                  peekPastLabels(case)
+                  listener: beginCaseExpression(case)
+                  parsePattern(case, PatternContext.matching, precedence: 1)
+                    parsePrimaryPattern(case, PatternContext.matching)
+                      parseParenthesizedPatternOrRecordPattern(case, PatternContext.matching)
+                        parsePattern((, PatternContext.matching, precedence: 1)
+                          parsePrimaryPattern((, PatternContext.matching)
+                            listener: beginConstantPattern(null)
+                            parsePrecedenceExpression((, 7, false, ConstantPatternContext.implicit)
+                              parseUnaryExpression((, false, ConstantPatternContext.implicit)
+                                parsePrimary((, expression, ConstantPatternContext.implicit)
+                                  parseSendOrFunctionLiteral((, expression, ConstantPatternContext.implicit)
+                                    parseSend((, expression, ConstantPatternContext.implicit)
+                                      isNextIdentifier(()
+                                      ensureIdentifier((, expression)
+                                        listener: handleIdentifier(y, expression)
+                                      listener: handleNoTypeArguments(as)
+                                      parseArgumentsOpt(y)
+                                        listener: handleNoArguments(as)
+                                      listener: handleSend(y, as)
+                            listener: endConstantPattern(null)
+                          listener: beginAsOperatorType(as)
+                          computeTypeAfterIsOrAs(as)
+                          listener: handleIdentifier(int, typeReference)
+                          listener: handleNoTypeArguments())
+                          listener: handleType(int, null)
+                          listener: endAsOperatorType(as)
+                          listener: handleCastPattern(as)
+                        ensureCloseParen(int, ()
+                        listener: handleParenthesizedPattern(()
+                    listener: beginAsOperatorType(as)
+                    computeTypeAfterIsOrAs(as)
+                    listener: handleIdentifier(num, typeReference)
+                    listener: handleNoTypeArguments(:)
+                    listener: handleType(num, null)
+                    listener: endAsOperatorType(as)
+                    listener: handleCastPattern(as)
+                  listener: handleSwitchCaseNoWhenClause(num)
+                  ensureColon(num)
+                  listener: endCaseExpression(case, null, :)
+                  peekPastLabels(break)
+                  parseStatementsInSwitchCase(:, break, case, 0, 1, null, null)
+                    listener: beginSwitchCase(0, 1, case)
+                    parseStatement(:)
+                      parseStatementX(:)
+                        parseBreakStatement(:)
+                          isBreakAllowed()
+                          ensureSemicolon(break)
+                          listener: handleBreakStatement(false, break, ;)
+                    peekPastLabels(})
+                    listener: endSwitchCase(0, 1, null, null, 1, case, })
+                  notEofOrValue(}, })
+                  listener: endSwitchBlock(1, {, })
+                listener: endSwitchStatement(switch, })
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(2, {, })
+        listener: endTopLevelMethod(void, null, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(void)
+  listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideCast_parenthesized.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/cast_insideCast_parenthesized.dart.parser.expect
new file mode 100644
index 0000000..8445fd1
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideCast_parenthesized.dart.parser.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case (y as int) as num:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] ([BeginToken]y[StringToken] as[KeywordToken] int[StringToken])[SimpleToken] as[KeywordToken] num[StringToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideCast_parenthesized.dart.scanner.expect b/pkg/front_end/parser_testcases/patterns/cast_insideCast_parenthesized.dart.scanner.expect
new file mode 100644
index 0000000..8445fd1
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideCast_parenthesized.dart.scanner.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case (y as int) as num:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] ([BeginToken]y[StringToken] as[KeywordToken] int[StringToken])[SimpleToken] as[KeywordToken] num[StringToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideNullAssert.dart b/pkg/front_end/parser_testcases/patterns/cast_insideNullAssert.dart
new file mode 100644
index 0000000..ef4ffc9
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideNullAssert.dart
@@ -0,0 +1,7 @@
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y as int!:
+      break;
+  }
+}
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideNullAssert.dart.expect b/pkg/front_end/parser_testcases/patterns/cast_insideNullAssert.dart.expect
new file mode 100644
index 0000000..d87bf4f
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideNullAssert.dart.expect
@@ -0,0 +1,69 @@
+Problems reported:
+
+parser/patterns/cast_insideNullAssert:4:10: This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+    case y as int!:
+         ^^^^^^^^
+
+beginCompilationUnit(void)
+  beginMetadataStar(void)
+  endMetadataStar(0)
+  beginTopLevelMember(void)
+    beginTopLevelMethod(, null, null)
+      handleVoidKeyword(void)
+      handleIdentifier(f, topLevelFunctionDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.TopLevelMethod)
+        beginMetadataStar(x)
+        endMetadataStar(0)
+        beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+          handleNoType(()
+          handleIdentifier(x, formalParameterDeclaration)
+          handleFormalParameterWithoutValue())
+        endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+      endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        beginMetadataStar(const)
+        endMetadataStar(0)
+        handleNoType(const)
+        beginVariablesDeclaration(y, null, const)
+          handleIdentifier(y, localVariableDeclaration)
+          beginInitializedIdentifier(y)
+            beginVariableInitializer(=)
+              handleLiteralInt(1)
+            endVariableInitializer(=)
+          endInitializedIdentifier(y)
+        endVariablesDeclaration(1, ;)
+        beginSwitchStatement(switch)
+          handleIdentifier(x, expression)
+          handleNoTypeArguments())
+          handleNoArguments())
+          handleSend(x, ))
+          handleParenthesizedCondition((, null, null)
+          beginSwitchBlock({)
+            beginCaseExpression(case)
+              beginConstantPattern(null)
+                handleIdentifier(y, expression)
+                handleNoTypeArguments(as)
+                handleNoArguments(as)
+                handleSend(y, as)
+              endConstantPattern(null)
+              beginAsOperatorType(as)
+                handleIdentifier(int, typeReference)
+                handleNoTypeArguments(!)
+                handleType(int, null)
+              endAsOperatorType(as)
+              handleCastPattern(as)
+              handleRecoverableError(InvalidInsideUnaryPattern, y, int)
+              handleNullAssertPattern(!)
+              handleSwitchCaseNoWhenClause(!)
+            endCaseExpression(case, null, :)
+            beginSwitchCase(0, 1, case)
+              handleBreakStatement(false, break, ;)
+            endSwitchCase(0, 1, null, null, 1, case, })
+          endSwitchBlock(1, {, })
+        endSwitchStatement(switch, })
+      endBlockFunctionBody(2, {, })
+    endTopLevelMethod(void, null, })
+  endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideNullAssert.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/cast_insideNullAssert.dart.intertwined.expect
new file mode 100644
index 0000000..f807ba2
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideNullAssert.dart.intertwined.expect
@@ -0,0 +1,146 @@
+parseUnit(void)
+  skipErrorTokens(void)
+  listener: beginCompilationUnit(void)
+  syntheticPreviousToken(void)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(void)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl()
+      listener: beginTopLevelMember(void)
+      parseTopLevelMethod(, null, null, , Instance of 'VoidType', null, f, false)
+        listener: beginTopLevelMethod(, null, null)
+        listener: handleVoidKeyword(void)
+        ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+          listener: handleIdentifier(f, topLevelFunctionDeclaration)
+        parseMethodTypeVar(f)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(f, MemberKind.TopLevelMethod)
+            parseFormalParametersRest((, MemberKind.TopLevelMethod)
+              listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+              parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+                parseMetadataStar(()
+                  listener: beginMetadataStar(x)
+                  listener: endMetadataStar(0)
+                listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+                listener: handleNoType(()
+                ensureIdentifier((, formalParameterDeclaration)
+                  listener: handleIdentifier(x, formalParameterDeclaration)
+                listener: handleFormalParameterWithoutValue())
+                listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+              listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+        parseAsyncModifierOpt())
+          listener: handleAsyncModifier(null, null)
+          inPlainSync()
+        parseFunctionBody(), false, false)
+          listener: beginBlockFunctionBody({)
+          notEofOrValue(}, const)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrConstDeclaration({)
+                parseExpressionStatementOrDeclarationAfterModifiers(const, {, null, const, Instance of 'NoType', null)
+                  looksLikeLocalFunction(y)
+                  listener: beginMetadataStar(const)
+                  listener: endMetadataStar(0)
+                  listener: handleNoType(const)
+                  listener: beginVariablesDeclaration(y, null, const)
+                  parseVariablesDeclarationRest(const, true)
+                    parseOptionallyInitializedIdentifier(const)
+                      ensureIdentifier(const, localVariableDeclaration)
+                        listener: handleIdentifier(y, localVariableDeclaration)
+                      listener: beginInitializedIdentifier(y)
+                      parseVariableInitializerOpt(y)
+                        listener: beginVariableInitializer(=)
+                        parseExpression(=)
+                          looksLikeOuterPatternEquals(=)
+                            skipOuterPattern(=)
+                          parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
+                            parseUnaryExpression(=, true, ConstantPatternContext.none)
+                              parsePrimary(=, expression, ConstantPatternContext.none)
+                                parseLiteralInt(=)
+                                  listener: handleLiteralInt(1)
+                        listener: endVariableInitializer(=)
+                      listener: endInitializedIdentifier(y)
+                    ensureSemicolon(1)
+                    listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, switch)
+          parseStatement(;)
+            parseStatementX(;)
+              parseSwitchStatement(;)
+                listener: beginSwitchStatement(switch)
+                ensureParenthesizedCondition(switch, allowCase: false)
+                  parseExpressionInParenthesisRest((, allowCase: false)
+                    parseExpression(()
+                      looksLikeOuterPatternEquals(()
+                        skipOuterPattern(()
+                          skipObjectPatternRest(x)
+                      parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+                        parseUnaryExpression((, true, ConstantPatternContext.none)
+                          parsePrimary((, expression, ConstantPatternContext.none)
+                            parseSendOrFunctionLiteral((, expression, ConstantPatternContext.none)
+                              parseSend((, expression, ConstantPatternContext.none)
+                                isNextIdentifier(()
+                                ensureIdentifier((, expression)
+                                  listener: handleIdentifier(x, expression)
+                                listener: handleNoTypeArguments())
+                                parseArgumentsOpt(x)
+                                  listener: handleNoArguments())
+                                listener: handleSend(x, ))
+                    ensureCloseParen(x, ()
+                    listener: handleParenthesizedCondition((, null, null)
+                parseSwitchBlock())
+                  ensureBlock(), null, switch statement)
+                  listener: beginSwitchBlock({)
+                  notEofOrValue(}, case)
+                  peekPastLabels(case)
+                  listener: beginCaseExpression(case)
+                  parsePattern(case, PatternContext.matching, precedence: 1)
+                    parsePrimaryPattern(case, PatternContext.matching)
+                      listener: beginConstantPattern(null)
+                      parsePrecedenceExpression(case, 7, false, ConstantPatternContext.implicit)
+                        parseUnaryExpression(case, false, ConstantPatternContext.implicit)
+                          parsePrimary(case, expression, ConstantPatternContext.implicit)
+                            parseSendOrFunctionLiteral(case, expression, ConstantPatternContext.implicit)
+                              parseSend(case, expression, ConstantPatternContext.implicit)
+                                isNextIdentifier(case)
+                                ensureIdentifier(case, expression)
+                                  listener: handleIdentifier(y, expression)
+                                listener: handleNoTypeArguments(as)
+                                parseArgumentsOpt(y)
+                                  listener: handleNoArguments(as)
+                                listener: handleSend(y, as)
+                      listener: endConstantPattern(null)
+                    listener: beginAsOperatorType(as)
+                    computeTypeAfterIsOrAs(as)
+                    listener: handleIdentifier(int, typeReference)
+                    listener: handleNoTypeArguments(!)
+                    listener: handleType(int, null)
+                    listener: endAsOperatorType(as)
+                    listener: handleCastPattern(as)
+                    reportRecoverableErrorWithEnd(y, int, InvalidInsideUnaryPattern)
+                      listener: handleRecoverableError(InvalidInsideUnaryPattern, y, int)
+                    listener: handleNullAssertPattern(!)
+                  listener: handleSwitchCaseNoWhenClause(!)
+                  ensureColon(!)
+                  listener: endCaseExpression(case, null, :)
+                  peekPastLabels(break)
+                  parseStatementsInSwitchCase(:, break, case, 0, 1, null, null)
+                    listener: beginSwitchCase(0, 1, case)
+                    parseStatement(:)
+                      parseStatementX(:)
+                        parseBreakStatement(:)
+                          isBreakAllowed()
+                          ensureSemicolon(break)
+                          listener: handleBreakStatement(false, break, ;)
+                    peekPastLabels(})
+                    listener: endSwitchCase(0, 1, null, null, 1, case, })
+                  notEofOrValue(}, })
+                  listener: endSwitchBlock(1, {, })
+                listener: endSwitchStatement(switch, })
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(2, {, })
+        listener: endTopLevelMethod(void, null, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(void)
+  listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideNullAssert.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/cast_insideNullAssert.dart.parser.expect
new file mode 100644
index 0000000..ee4b623
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideNullAssert.dart.parser.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y as int!:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken] as[KeywordToken] int[StringToken]![SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideNullAssert.dart.scanner.expect b/pkg/front_end/parser_testcases/patterns/cast_insideNullAssert.dart.scanner.expect
new file mode 100644
index 0000000..ee4b623
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideNullAssert.dart.scanner.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y as int!:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken] as[KeywordToken] int[StringToken]![SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideNullCheck.dart b/pkg/front_end/parser_testcases/patterns/cast_insideNullCheck.dart
new file mode 100644
index 0000000..ee2e4fc
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideNullCheck.dart
@@ -0,0 +1,7 @@
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y as int? ?:
+      break;
+  }
+}
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideNullCheck.dart.expect b/pkg/front_end/parser_testcases/patterns/cast_insideNullCheck.dart.expect
new file mode 100644
index 0000000..f519d14
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideNullCheck.dart.expect
@@ -0,0 +1,69 @@
+Problems reported:
+
+parser/patterns/cast_insideNullCheck:4:10: This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+    case y as int? ?:
+         ^^^^^^^^^
+
+beginCompilationUnit(void)
+  beginMetadataStar(void)
+  endMetadataStar(0)
+  beginTopLevelMember(void)
+    beginTopLevelMethod(, null, null)
+      handleVoidKeyword(void)
+      handleIdentifier(f, topLevelFunctionDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.TopLevelMethod)
+        beginMetadataStar(x)
+        endMetadataStar(0)
+        beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+          handleNoType(()
+          handleIdentifier(x, formalParameterDeclaration)
+          handleFormalParameterWithoutValue())
+        endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+      endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        beginMetadataStar(const)
+        endMetadataStar(0)
+        handleNoType(const)
+        beginVariablesDeclaration(y, null, const)
+          handleIdentifier(y, localVariableDeclaration)
+          beginInitializedIdentifier(y)
+            beginVariableInitializer(=)
+              handleLiteralInt(1)
+            endVariableInitializer(=)
+          endInitializedIdentifier(y)
+        endVariablesDeclaration(1, ;)
+        beginSwitchStatement(switch)
+          handleIdentifier(x, expression)
+          handleNoTypeArguments())
+          handleNoArguments())
+          handleSend(x, ))
+          handleParenthesizedCondition((, null, null)
+          beginSwitchBlock({)
+            beginCaseExpression(case)
+              beginConstantPattern(null)
+                handleIdentifier(y, expression)
+                handleNoTypeArguments(as)
+                handleNoArguments(as)
+                handleSend(y, as)
+              endConstantPattern(null)
+              beginAsOperatorType(as)
+                handleIdentifier(int, typeReference)
+                handleNoTypeArguments(?)
+                handleType(int, ?)
+              endAsOperatorType(as)
+              handleCastPattern(as)
+              handleRecoverableError(InvalidInsideUnaryPattern, y, ?)
+              handleNullCheckPattern(?)
+              handleSwitchCaseNoWhenClause(?)
+            endCaseExpression(case, null, :)
+            beginSwitchCase(0, 1, case)
+              handleBreakStatement(false, break, ;)
+            endSwitchCase(0, 1, null, null, 1, case, })
+          endSwitchBlock(1, {, })
+        endSwitchStatement(switch, })
+      endBlockFunctionBody(2, {, })
+    endTopLevelMethod(void, null, })
+  endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideNullCheck.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/cast_insideNullCheck.dart.intertwined.expect
new file mode 100644
index 0000000..c443f0f
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideNullCheck.dart.intertwined.expect
@@ -0,0 +1,146 @@
+parseUnit(void)
+  skipErrorTokens(void)
+  listener: beginCompilationUnit(void)
+  syntheticPreviousToken(void)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(void)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl()
+      listener: beginTopLevelMember(void)
+      parseTopLevelMethod(, null, null, , Instance of 'VoidType', null, f, false)
+        listener: beginTopLevelMethod(, null, null)
+        listener: handleVoidKeyword(void)
+        ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+          listener: handleIdentifier(f, topLevelFunctionDeclaration)
+        parseMethodTypeVar(f)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(f, MemberKind.TopLevelMethod)
+            parseFormalParametersRest((, MemberKind.TopLevelMethod)
+              listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+              parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+                parseMetadataStar(()
+                  listener: beginMetadataStar(x)
+                  listener: endMetadataStar(0)
+                listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+                listener: handleNoType(()
+                ensureIdentifier((, formalParameterDeclaration)
+                  listener: handleIdentifier(x, formalParameterDeclaration)
+                listener: handleFormalParameterWithoutValue())
+                listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+              listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+        parseAsyncModifierOpt())
+          listener: handleAsyncModifier(null, null)
+          inPlainSync()
+        parseFunctionBody(), false, false)
+          listener: beginBlockFunctionBody({)
+          notEofOrValue(}, const)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrConstDeclaration({)
+                parseExpressionStatementOrDeclarationAfterModifiers(const, {, null, const, Instance of 'NoType', null)
+                  looksLikeLocalFunction(y)
+                  listener: beginMetadataStar(const)
+                  listener: endMetadataStar(0)
+                  listener: handleNoType(const)
+                  listener: beginVariablesDeclaration(y, null, const)
+                  parseVariablesDeclarationRest(const, true)
+                    parseOptionallyInitializedIdentifier(const)
+                      ensureIdentifier(const, localVariableDeclaration)
+                        listener: handleIdentifier(y, localVariableDeclaration)
+                      listener: beginInitializedIdentifier(y)
+                      parseVariableInitializerOpt(y)
+                        listener: beginVariableInitializer(=)
+                        parseExpression(=)
+                          looksLikeOuterPatternEquals(=)
+                            skipOuterPattern(=)
+                          parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
+                            parseUnaryExpression(=, true, ConstantPatternContext.none)
+                              parsePrimary(=, expression, ConstantPatternContext.none)
+                                parseLiteralInt(=)
+                                  listener: handleLiteralInt(1)
+                        listener: endVariableInitializer(=)
+                      listener: endInitializedIdentifier(y)
+                    ensureSemicolon(1)
+                    listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, switch)
+          parseStatement(;)
+            parseStatementX(;)
+              parseSwitchStatement(;)
+                listener: beginSwitchStatement(switch)
+                ensureParenthesizedCondition(switch, allowCase: false)
+                  parseExpressionInParenthesisRest((, allowCase: false)
+                    parseExpression(()
+                      looksLikeOuterPatternEquals(()
+                        skipOuterPattern(()
+                          skipObjectPatternRest(x)
+                      parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+                        parseUnaryExpression((, true, ConstantPatternContext.none)
+                          parsePrimary((, expression, ConstantPatternContext.none)
+                            parseSendOrFunctionLiteral((, expression, ConstantPatternContext.none)
+                              parseSend((, expression, ConstantPatternContext.none)
+                                isNextIdentifier(()
+                                ensureIdentifier((, expression)
+                                  listener: handleIdentifier(x, expression)
+                                listener: handleNoTypeArguments())
+                                parseArgumentsOpt(x)
+                                  listener: handleNoArguments())
+                                listener: handleSend(x, ))
+                    ensureCloseParen(x, ()
+                    listener: handleParenthesizedCondition((, null, null)
+                parseSwitchBlock())
+                  ensureBlock(), null, switch statement)
+                  listener: beginSwitchBlock({)
+                  notEofOrValue(}, case)
+                  peekPastLabels(case)
+                  listener: beginCaseExpression(case)
+                  parsePattern(case, PatternContext.matching, precedence: 1)
+                    parsePrimaryPattern(case, PatternContext.matching)
+                      listener: beginConstantPattern(null)
+                      parsePrecedenceExpression(case, 7, false, ConstantPatternContext.implicit)
+                        parseUnaryExpression(case, false, ConstantPatternContext.implicit)
+                          parsePrimary(case, expression, ConstantPatternContext.implicit)
+                            parseSendOrFunctionLiteral(case, expression, ConstantPatternContext.implicit)
+                              parseSend(case, expression, ConstantPatternContext.implicit)
+                                isNextIdentifier(case)
+                                ensureIdentifier(case, expression)
+                                  listener: handleIdentifier(y, expression)
+                                listener: handleNoTypeArguments(as)
+                                parseArgumentsOpt(y)
+                                  listener: handleNoArguments(as)
+                                listener: handleSend(y, as)
+                      listener: endConstantPattern(null)
+                    listener: beginAsOperatorType(as)
+                    computeTypeAfterIsOrAs(as)
+                    listener: handleIdentifier(int, typeReference)
+                    listener: handleNoTypeArguments(?)
+                    listener: handleType(int, ?)
+                    listener: endAsOperatorType(as)
+                    listener: handleCastPattern(as)
+                    reportRecoverableErrorWithEnd(y, ?, InvalidInsideUnaryPattern)
+                      listener: handleRecoverableError(InvalidInsideUnaryPattern, y, ?)
+                    listener: handleNullCheckPattern(?)
+                  listener: handleSwitchCaseNoWhenClause(?)
+                  ensureColon(?)
+                  listener: endCaseExpression(case, null, :)
+                  peekPastLabels(break)
+                  parseStatementsInSwitchCase(:, break, case, 0, 1, null, null)
+                    listener: beginSwitchCase(0, 1, case)
+                    parseStatement(:)
+                      parseStatementX(:)
+                        parseBreakStatement(:)
+                          isBreakAllowed()
+                          ensureSemicolon(break)
+                          listener: handleBreakStatement(false, break, ;)
+                    peekPastLabels(})
+                    listener: endSwitchCase(0, 1, null, null, 1, case, })
+                  notEofOrValue(}, })
+                  listener: endSwitchBlock(1, {, })
+                listener: endSwitchStatement(switch, })
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(2, {, })
+        listener: endTopLevelMethod(void, null, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(void)
+  listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideNullCheck.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/cast_insideNullCheck.dart.parser.expect
new file mode 100644
index 0000000..2e8de70
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideNullCheck.dart.parser.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y as int? ?:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken] as[KeywordToken] int[StringToken]?[SimpleToken] ?[SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/cast_insideNullCheck.dart.scanner.expect b/pkg/front_end/parser_testcases/patterns/cast_insideNullCheck.dart.scanner.expect
new file mode 100644
index 0000000..2e8de70
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/cast_insideNullCheck.dart.scanner.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y as int? ?:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken] as[KeywordToken] int[StringToken]?[SimpleToken] ?[SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/nullAssert_insideCast.dart b/pkg/front_end/parser_testcases/patterns/nullAssert_insideCast.dart
new file mode 100644
index 0000000..a9b78cc
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullAssert_insideCast.dart
@@ -0,0 +1,7 @@
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y! as num:
+      break;
+  }
+}
diff --git a/pkg/front_end/parser_testcases/patterns/nullAssert_insideCast.dart.expect b/pkg/front_end/parser_testcases/patterns/nullAssert_insideCast.dart.expect
new file mode 100644
index 0000000..657168f
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullAssert_insideCast.dart.expect
@@ -0,0 +1,69 @@
+Problems reported:
+
+parser/patterns/nullAssert_insideCast:4:10: This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+    case y! as num:
+         ^^
+
+beginCompilationUnit(void)
+  beginMetadataStar(void)
+  endMetadataStar(0)
+  beginTopLevelMember(void)
+    beginTopLevelMethod(, null, null)
+      handleVoidKeyword(void)
+      handleIdentifier(f, topLevelFunctionDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.TopLevelMethod)
+        beginMetadataStar(x)
+        endMetadataStar(0)
+        beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+          handleNoType(()
+          handleIdentifier(x, formalParameterDeclaration)
+          handleFormalParameterWithoutValue())
+        endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+      endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        beginMetadataStar(const)
+        endMetadataStar(0)
+        handleNoType(const)
+        beginVariablesDeclaration(y, null, const)
+          handleIdentifier(y, localVariableDeclaration)
+          beginInitializedIdentifier(y)
+            beginVariableInitializer(=)
+              handleLiteralInt(1)
+            endVariableInitializer(=)
+          endInitializedIdentifier(y)
+        endVariablesDeclaration(1, ;)
+        beginSwitchStatement(switch)
+          handleIdentifier(x, expression)
+          handleNoTypeArguments())
+          handleNoArguments())
+          handleSend(x, ))
+          handleParenthesizedCondition((, null, null)
+          beginSwitchBlock({)
+            beginCaseExpression(case)
+              beginConstantPattern(null)
+                handleIdentifier(y, expression)
+                handleNoTypeArguments(!)
+                handleNoArguments(!)
+                handleSend(y, !)
+              endConstantPattern(null)
+              handleNullAssertPattern(!)
+              handleRecoverableError(InvalidInsideUnaryPattern, y, !)
+              beginAsOperatorType(as)
+                handleIdentifier(num, typeReference)
+                handleNoTypeArguments(:)
+                handleType(num, null)
+              endAsOperatorType(as)
+              handleCastPattern(as)
+              handleSwitchCaseNoWhenClause(num)
+            endCaseExpression(case, null, :)
+            beginSwitchCase(0, 1, case)
+              handleBreakStatement(false, break, ;)
+            endSwitchCase(0, 1, null, null, 1, case, })
+          endSwitchBlock(1, {, })
+        endSwitchStatement(switch, })
+      endBlockFunctionBody(2, {, })
+    endTopLevelMethod(void, null, })
+  endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/nullAssert_insideCast.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/nullAssert_insideCast.dart.intertwined.expect
new file mode 100644
index 0000000..c45ac55
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullAssert_insideCast.dart.intertwined.expect
@@ -0,0 +1,146 @@
+parseUnit(void)
+  skipErrorTokens(void)
+  listener: beginCompilationUnit(void)
+  syntheticPreviousToken(void)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(void)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl()
+      listener: beginTopLevelMember(void)
+      parseTopLevelMethod(, null, null, , Instance of 'VoidType', null, f, false)
+        listener: beginTopLevelMethod(, null, null)
+        listener: handleVoidKeyword(void)
+        ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+          listener: handleIdentifier(f, topLevelFunctionDeclaration)
+        parseMethodTypeVar(f)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(f, MemberKind.TopLevelMethod)
+            parseFormalParametersRest((, MemberKind.TopLevelMethod)
+              listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+              parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+                parseMetadataStar(()
+                  listener: beginMetadataStar(x)
+                  listener: endMetadataStar(0)
+                listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+                listener: handleNoType(()
+                ensureIdentifier((, formalParameterDeclaration)
+                  listener: handleIdentifier(x, formalParameterDeclaration)
+                listener: handleFormalParameterWithoutValue())
+                listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+              listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+        parseAsyncModifierOpt())
+          listener: handleAsyncModifier(null, null)
+          inPlainSync()
+        parseFunctionBody(), false, false)
+          listener: beginBlockFunctionBody({)
+          notEofOrValue(}, const)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrConstDeclaration({)
+                parseExpressionStatementOrDeclarationAfterModifiers(const, {, null, const, Instance of 'NoType', null)
+                  looksLikeLocalFunction(y)
+                  listener: beginMetadataStar(const)
+                  listener: endMetadataStar(0)
+                  listener: handleNoType(const)
+                  listener: beginVariablesDeclaration(y, null, const)
+                  parseVariablesDeclarationRest(const, true)
+                    parseOptionallyInitializedIdentifier(const)
+                      ensureIdentifier(const, localVariableDeclaration)
+                        listener: handleIdentifier(y, localVariableDeclaration)
+                      listener: beginInitializedIdentifier(y)
+                      parseVariableInitializerOpt(y)
+                        listener: beginVariableInitializer(=)
+                        parseExpression(=)
+                          looksLikeOuterPatternEquals(=)
+                            skipOuterPattern(=)
+                          parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
+                            parseUnaryExpression(=, true, ConstantPatternContext.none)
+                              parsePrimary(=, expression, ConstantPatternContext.none)
+                                parseLiteralInt(=)
+                                  listener: handleLiteralInt(1)
+                        listener: endVariableInitializer(=)
+                      listener: endInitializedIdentifier(y)
+                    ensureSemicolon(1)
+                    listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, switch)
+          parseStatement(;)
+            parseStatementX(;)
+              parseSwitchStatement(;)
+                listener: beginSwitchStatement(switch)
+                ensureParenthesizedCondition(switch, allowCase: false)
+                  parseExpressionInParenthesisRest((, allowCase: false)
+                    parseExpression(()
+                      looksLikeOuterPatternEquals(()
+                        skipOuterPattern(()
+                          skipObjectPatternRest(x)
+                      parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+                        parseUnaryExpression((, true, ConstantPatternContext.none)
+                          parsePrimary((, expression, ConstantPatternContext.none)
+                            parseSendOrFunctionLiteral((, expression, ConstantPatternContext.none)
+                              parseSend((, expression, ConstantPatternContext.none)
+                                isNextIdentifier(()
+                                ensureIdentifier((, expression)
+                                  listener: handleIdentifier(x, expression)
+                                listener: handleNoTypeArguments())
+                                parseArgumentsOpt(x)
+                                  listener: handleNoArguments())
+                                listener: handleSend(x, ))
+                    ensureCloseParen(x, ()
+                    listener: handleParenthesizedCondition((, null, null)
+                parseSwitchBlock())
+                  ensureBlock(), null, switch statement)
+                  listener: beginSwitchBlock({)
+                  notEofOrValue(}, case)
+                  peekPastLabels(case)
+                  listener: beginCaseExpression(case)
+                  parsePattern(case, PatternContext.matching, precedence: 1)
+                    parsePrimaryPattern(case, PatternContext.matching)
+                      listener: beginConstantPattern(null)
+                      parsePrecedenceExpression(case, 7, false, ConstantPatternContext.implicit)
+                        parseUnaryExpression(case, false, ConstantPatternContext.implicit)
+                          parsePrimary(case, expression, ConstantPatternContext.implicit)
+                            parseSendOrFunctionLiteral(case, expression, ConstantPatternContext.implicit)
+                              parseSend(case, expression, ConstantPatternContext.implicit)
+                                isNextIdentifier(case)
+                                ensureIdentifier(case, expression)
+                                  listener: handleIdentifier(y, expression)
+                                listener: handleNoTypeArguments(!)
+                                parseArgumentsOpt(y)
+                                  listener: handleNoArguments(!)
+                                listener: handleSend(y, !)
+                      listener: endConstantPattern(null)
+                    listener: handleNullAssertPattern(!)
+                    reportRecoverableErrorWithEnd(y, !, InvalidInsideUnaryPattern)
+                      listener: handleRecoverableError(InvalidInsideUnaryPattern, y, !)
+                    listener: beginAsOperatorType(as)
+                    computeTypeAfterIsOrAs(as)
+                    listener: handleIdentifier(num, typeReference)
+                    listener: handleNoTypeArguments(:)
+                    listener: handleType(num, null)
+                    listener: endAsOperatorType(as)
+                    listener: handleCastPattern(as)
+                  listener: handleSwitchCaseNoWhenClause(num)
+                  ensureColon(num)
+                  listener: endCaseExpression(case, null, :)
+                  peekPastLabels(break)
+                  parseStatementsInSwitchCase(:, break, case, 0, 1, null, null)
+                    listener: beginSwitchCase(0, 1, case)
+                    parseStatement(:)
+                      parseStatementX(:)
+                        parseBreakStatement(:)
+                          isBreakAllowed()
+                          ensureSemicolon(break)
+                          listener: handleBreakStatement(false, break, ;)
+                    peekPastLabels(})
+                    listener: endSwitchCase(0, 1, null, null, 1, case, })
+                  notEofOrValue(}, })
+                  listener: endSwitchBlock(1, {, })
+                listener: endSwitchStatement(switch, })
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(2, {, })
+        listener: endTopLevelMethod(void, null, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(void)
+  listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/nullAssert_insideCast.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/nullAssert_insideCast.dart.parser.expect
new file mode 100644
index 0000000..efb4b36
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullAssert_insideCast.dart.parser.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y! as num:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken]![SimpleToken] as[KeywordToken] num[StringToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/nullAssert_insideCast.dart.scanner.expect b/pkg/front_end/parser_testcases/patterns/nullAssert_insideCast.dart.scanner.expect
new file mode 100644
index 0000000..efb4b36
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullAssert_insideCast.dart.scanner.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y! as num:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken]![SimpleToken] as[KeywordToken] num[StringToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullAssert.dart b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullAssert.dart
new file mode 100644
index 0000000..6fd84ee
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullAssert.dart
@@ -0,0 +1,7 @@
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y!!:
+      break;
+  }
+}
diff --git a/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullAssert.dart.expect b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullAssert.dart.expect
new file mode 100644
index 0000000..5be5708
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullAssert.dart.expect
@@ -0,0 +1,64 @@
+Problems reported:
+
+parser/patterns/nullAssert_insideNullAssert:4:10: This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+    case y!!:
+         ^^
+
+beginCompilationUnit(void)
+  beginMetadataStar(void)
+  endMetadataStar(0)
+  beginTopLevelMember(void)
+    beginTopLevelMethod(, null, null)
+      handleVoidKeyword(void)
+      handleIdentifier(f, topLevelFunctionDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.TopLevelMethod)
+        beginMetadataStar(x)
+        endMetadataStar(0)
+        beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+          handleNoType(()
+          handleIdentifier(x, formalParameterDeclaration)
+          handleFormalParameterWithoutValue())
+        endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+      endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        beginMetadataStar(const)
+        endMetadataStar(0)
+        handleNoType(const)
+        beginVariablesDeclaration(y, null, const)
+          handleIdentifier(y, localVariableDeclaration)
+          beginInitializedIdentifier(y)
+            beginVariableInitializer(=)
+              handleLiteralInt(1)
+            endVariableInitializer(=)
+          endInitializedIdentifier(y)
+        endVariablesDeclaration(1, ;)
+        beginSwitchStatement(switch)
+          handleIdentifier(x, expression)
+          handleNoTypeArguments())
+          handleNoArguments())
+          handleSend(x, ))
+          handleParenthesizedCondition((, null, null)
+          beginSwitchBlock({)
+            beginCaseExpression(case)
+              beginConstantPattern(null)
+                handleIdentifier(y, expression)
+                handleNoTypeArguments(!)
+                handleNoArguments(!)
+                handleSend(y, !)
+              endConstantPattern(null)
+              handleNullAssertPattern(!)
+              handleRecoverableError(InvalidInsideUnaryPattern, y, !)
+              handleNullAssertPattern(!)
+              handleSwitchCaseNoWhenClause(!)
+            endCaseExpression(case, null, :)
+            beginSwitchCase(0, 1, case)
+              handleBreakStatement(false, break, ;)
+            endSwitchCase(0, 1, null, null, 1, case, })
+          endSwitchBlock(1, {, })
+        endSwitchStatement(switch, })
+      endBlockFunctionBody(2, {, })
+    endTopLevelMethod(void, null, })
+  endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullAssert.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullAssert.dart.intertwined.expect
new file mode 100644
index 0000000..4d32d24
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullAssert.dart.intertwined.expect
@@ -0,0 +1,140 @@
+parseUnit(void)
+  skipErrorTokens(void)
+  listener: beginCompilationUnit(void)
+  syntheticPreviousToken(void)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(void)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl()
+      listener: beginTopLevelMember(void)
+      parseTopLevelMethod(, null, null, , Instance of 'VoidType', null, f, false)
+        listener: beginTopLevelMethod(, null, null)
+        listener: handleVoidKeyword(void)
+        ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+          listener: handleIdentifier(f, topLevelFunctionDeclaration)
+        parseMethodTypeVar(f)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(f, MemberKind.TopLevelMethod)
+            parseFormalParametersRest((, MemberKind.TopLevelMethod)
+              listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+              parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+                parseMetadataStar(()
+                  listener: beginMetadataStar(x)
+                  listener: endMetadataStar(0)
+                listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+                listener: handleNoType(()
+                ensureIdentifier((, formalParameterDeclaration)
+                  listener: handleIdentifier(x, formalParameterDeclaration)
+                listener: handleFormalParameterWithoutValue())
+                listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+              listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+        parseAsyncModifierOpt())
+          listener: handleAsyncModifier(null, null)
+          inPlainSync()
+        parseFunctionBody(), false, false)
+          listener: beginBlockFunctionBody({)
+          notEofOrValue(}, const)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrConstDeclaration({)
+                parseExpressionStatementOrDeclarationAfterModifiers(const, {, null, const, Instance of 'NoType', null)
+                  looksLikeLocalFunction(y)
+                  listener: beginMetadataStar(const)
+                  listener: endMetadataStar(0)
+                  listener: handleNoType(const)
+                  listener: beginVariablesDeclaration(y, null, const)
+                  parseVariablesDeclarationRest(const, true)
+                    parseOptionallyInitializedIdentifier(const)
+                      ensureIdentifier(const, localVariableDeclaration)
+                        listener: handleIdentifier(y, localVariableDeclaration)
+                      listener: beginInitializedIdentifier(y)
+                      parseVariableInitializerOpt(y)
+                        listener: beginVariableInitializer(=)
+                        parseExpression(=)
+                          looksLikeOuterPatternEquals(=)
+                            skipOuterPattern(=)
+                          parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
+                            parseUnaryExpression(=, true, ConstantPatternContext.none)
+                              parsePrimary(=, expression, ConstantPatternContext.none)
+                                parseLiteralInt(=)
+                                  listener: handleLiteralInt(1)
+                        listener: endVariableInitializer(=)
+                      listener: endInitializedIdentifier(y)
+                    ensureSemicolon(1)
+                    listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, switch)
+          parseStatement(;)
+            parseStatementX(;)
+              parseSwitchStatement(;)
+                listener: beginSwitchStatement(switch)
+                ensureParenthesizedCondition(switch, allowCase: false)
+                  parseExpressionInParenthesisRest((, allowCase: false)
+                    parseExpression(()
+                      looksLikeOuterPatternEquals(()
+                        skipOuterPattern(()
+                          skipObjectPatternRest(x)
+                      parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+                        parseUnaryExpression((, true, ConstantPatternContext.none)
+                          parsePrimary((, expression, ConstantPatternContext.none)
+                            parseSendOrFunctionLiteral((, expression, ConstantPatternContext.none)
+                              parseSend((, expression, ConstantPatternContext.none)
+                                isNextIdentifier(()
+                                ensureIdentifier((, expression)
+                                  listener: handleIdentifier(x, expression)
+                                listener: handleNoTypeArguments())
+                                parseArgumentsOpt(x)
+                                  listener: handleNoArguments())
+                                listener: handleSend(x, ))
+                    ensureCloseParen(x, ()
+                    listener: handleParenthesizedCondition((, null, null)
+                parseSwitchBlock())
+                  ensureBlock(), null, switch statement)
+                  listener: beginSwitchBlock({)
+                  notEofOrValue(}, case)
+                  peekPastLabels(case)
+                  listener: beginCaseExpression(case)
+                  parsePattern(case, PatternContext.matching, precedence: 1)
+                    parsePrimaryPattern(case, PatternContext.matching)
+                      listener: beginConstantPattern(null)
+                      parsePrecedenceExpression(case, 7, false, ConstantPatternContext.implicit)
+                        parseUnaryExpression(case, false, ConstantPatternContext.implicit)
+                          parsePrimary(case, expression, ConstantPatternContext.implicit)
+                            parseSendOrFunctionLiteral(case, expression, ConstantPatternContext.implicit)
+                              parseSend(case, expression, ConstantPatternContext.implicit)
+                                isNextIdentifier(case)
+                                ensureIdentifier(case, expression)
+                                  listener: handleIdentifier(y, expression)
+                                listener: handleNoTypeArguments(!)
+                                parseArgumentsOpt(y)
+                                  listener: handleNoArguments(!)
+                                listener: handleSend(y, !)
+                      listener: endConstantPattern(null)
+                    listener: handleNullAssertPattern(!)
+                    reportRecoverableErrorWithEnd(y, !, InvalidInsideUnaryPattern)
+                      listener: handleRecoverableError(InvalidInsideUnaryPattern, y, !)
+                    listener: handleNullAssertPattern(!)
+                  listener: handleSwitchCaseNoWhenClause(!)
+                  ensureColon(!)
+                  listener: endCaseExpression(case, null, :)
+                  peekPastLabels(break)
+                  parseStatementsInSwitchCase(:, break, case, 0, 1, null, null)
+                    listener: beginSwitchCase(0, 1, case)
+                    parseStatement(:)
+                      parseStatementX(:)
+                        parseBreakStatement(:)
+                          isBreakAllowed()
+                          ensureSemicolon(break)
+                          listener: handleBreakStatement(false, break, ;)
+                    peekPastLabels(})
+                    listener: endSwitchCase(0, 1, null, null, 1, case, })
+                  notEofOrValue(}, })
+                  listener: endSwitchBlock(1, {, })
+                listener: endSwitchStatement(switch, })
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(2, {, })
+        listener: endTopLevelMethod(void, null, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(void)
+  listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullAssert.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullAssert.dart.parser.expect
new file mode 100644
index 0000000..5d80805
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullAssert.dart.parser.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y!!:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken]![SimpleToken]![SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullAssert.dart.scanner.expect b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullAssert.dart.scanner.expect
new file mode 100644
index 0000000..5d80805
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullAssert.dart.scanner.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y!!:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken]![SimpleToken]![SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullCheck.dart b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullCheck.dart
new file mode 100644
index 0000000..bd7bb8d
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullCheck.dart
@@ -0,0 +1,7 @@
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y!?:
+      break;
+  }
+}
diff --git a/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullCheck.dart.expect b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullCheck.dart.expect
new file mode 100644
index 0000000..53179b0
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullCheck.dart.expect
@@ -0,0 +1,64 @@
+Problems reported:
+
+parser/patterns/nullAssert_insideNullCheck:4:10: This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+    case y!?:
+         ^^
+
+beginCompilationUnit(void)
+  beginMetadataStar(void)
+  endMetadataStar(0)
+  beginTopLevelMember(void)
+    beginTopLevelMethod(, null, null)
+      handleVoidKeyword(void)
+      handleIdentifier(f, topLevelFunctionDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.TopLevelMethod)
+        beginMetadataStar(x)
+        endMetadataStar(0)
+        beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+          handleNoType(()
+          handleIdentifier(x, formalParameterDeclaration)
+          handleFormalParameterWithoutValue())
+        endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+      endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        beginMetadataStar(const)
+        endMetadataStar(0)
+        handleNoType(const)
+        beginVariablesDeclaration(y, null, const)
+          handleIdentifier(y, localVariableDeclaration)
+          beginInitializedIdentifier(y)
+            beginVariableInitializer(=)
+              handleLiteralInt(1)
+            endVariableInitializer(=)
+          endInitializedIdentifier(y)
+        endVariablesDeclaration(1, ;)
+        beginSwitchStatement(switch)
+          handleIdentifier(x, expression)
+          handleNoTypeArguments())
+          handleNoArguments())
+          handleSend(x, ))
+          handleParenthesizedCondition((, null, null)
+          beginSwitchBlock({)
+            beginCaseExpression(case)
+              beginConstantPattern(null)
+                handleIdentifier(y, expression)
+                handleNoTypeArguments(!)
+                handleNoArguments(!)
+                handleSend(y, !)
+              endConstantPattern(null)
+              handleNullAssertPattern(!)
+              handleRecoverableError(InvalidInsideUnaryPattern, y, !)
+              handleNullCheckPattern(?)
+              handleSwitchCaseNoWhenClause(?)
+            endCaseExpression(case, null, :)
+            beginSwitchCase(0, 1, case)
+              handleBreakStatement(false, break, ;)
+            endSwitchCase(0, 1, null, null, 1, case, })
+          endSwitchBlock(1, {, })
+        endSwitchStatement(switch, })
+      endBlockFunctionBody(2, {, })
+    endTopLevelMethod(void, null, })
+  endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullCheck.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullCheck.dart.intertwined.expect
new file mode 100644
index 0000000..e624c7e
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullCheck.dart.intertwined.expect
@@ -0,0 +1,140 @@
+parseUnit(void)
+  skipErrorTokens(void)
+  listener: beginCompilationUnit(void)
+  syntheticPreviousToken(void)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(void)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl()
+      listener: beginTopLevelMember(void)
+      parseTopLevelMethod(, null, null, , Instance of 'VoidType', null, f, false)
+        listener: beginTopLevelMethod(, null, null)
+        listener: handleVoidKeyword(void)
+        ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+          listener: handleIdentifier(f, topLevelFunctionDeclaration)
+        parseMethodTypeVar(f)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(f, MemberKind.TopLevelMethod)
+            parseFormalParametersRest((, MemberKind.TopLevelMethod)
+              listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+              parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+                parseMetadataStar(()
+                  listener: beginMetadataStar(x)
+                  listener: endMetadataStar(0)
+                listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+                listener: handleNoType(()
+                ensureIdentifier((, formalParameterDeclaration)
+                  listener: handleIdentifier(x, formalParameterDeclaration)
+                listener: handleFormalParameterWithoutValue())
+                listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+              listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+        parseAsyncModifierOpt())
+          listener: handleAsyncModifier(null, null)
+          inPlainSync()
+        parseFunctionBody(), false, false)
+          listener: beginBlockFunctionBody({)
+          notEofOrValue(}, const)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrConstDeclaration({)
+                parseExpressionStatementOrDeclarationAfterModifiers(const, {, null, const, Instance of 'NoType', null)
+                  looksLikeLocalFunction(y)
+                  listener: beginMetadataStar(const)
+                  listener: endMetadataStar(0)
+                  listener: handleNoType(const)
+                  listener: beginVariablesDeclaration(y, null, const)
+                  parseVariablesDeclarationRest(const, true)
+                    parseOptionallyInitializedIdentifier(const)
+                      ensureIdentifier(const, localVariableDeclaration)
+                        listener: handleIdentifier(y, localVariableDeclaration)
+                      listener: beginInitializedIdentifier(y)
+                      parseVariableInitializerOpt(y)
+                        listener: beginVariableInitializer(=)
+                        parseExpression(=)
+                          looksLikeOuterPatternEquals(=)
+                            skipOuterPattern(=)
+                          parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
+                            parseUnaryExpression(=, true, ConstantPatternContext.none)
+                              parsePrimary(=, expression, ConstantPatternContext.none)
+                                parseLiteralInt(=)
+                                  listener: handleLiteralInt(1)
+                        listener: endVariableInitializer(=)
+                      listener: endInitializedIdentifier(y)
+                    ensureSemicolon(1)
+                    listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, switch)
+          parseStatement(;)
+            parseStatementX(;)
+              parseSwitchStatement(;)
+                listener: beginSwitchStatement(switch)
+                ensureParenthesizedCondition(switch, allowCase: false)
+                  parseExpressionInParenthesisRest((, allowCase: false)
+                    parseExpression(()
+                      looksLikeOuterPatternEquals(()
+                        skipOuterPattern(()
+                          skipObjectPatternRest(x)
+                      parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+                        parseUnaryExpression((, true, ConstantPatternContext.none)
+                          parsePrimary((, expression, ConstantPatternContext.none)
+                            parseSendOrFunctionLiteral((, expression, ConstantPatternContext.none)
+                              parseSend((, expression, ConstantPatternContext.none)
+                                isNextIdentifier(()
+                                ensureIdentifier((, expression)
+                                  listener: handleIdentifier(x, expression)
+                                listener: handleNoTypeArguments())
+                                parseArgumentsOpt(x)
+                                  listener: handleNoArguments())
+                                listener: handleSend(x, ))
+                    ensureCloseParen(x, ()
+                    listener: handleParenthesizedCondition((, null, null)
+                parseSwitchBlock())
+                  ensureBlock(), null, switch statement)
+                  listener: beginSwitchBlock({)
+                  notEofOrValue(}, case)
+                  peekPastLabels(case)
+                  listener: beginCaseExpression(case)
+                  parsePattern(case, PatternContext.matching, precedence: 1)
+                    parsePrimaryPattern(case, PatternContext.matching)
+                      listener: beginConstantPattern(null)
+                      parsePrecedenceExpression(case, 7, false, ConstantPatternContext.implicit)
+                        parseUnaryExpression(case, false, ConstantPatternContext.implicit)
+                          parsePrimary(case, expression, ConstantPatternContext.implicit)
+                            parseSendOrFunctionLiteral(case, expression, ConstantPatternContext.implicit)
+                              parseSend(case, expression, ConstantPatternContext.implicit)
+                                isNextIdentifier(case)
+                                ensureIdentifier(case, expression)
+                                  listener: handleIdentifier(y, expression)
+                                listener: handleNoTypeArguments(!)
+                                parseArgumentsOpt(y)
+                                  listener: handleNoArguments(!)
+                                listener: handleSend(y, !)
+                      listener: endConstantPattern(null)
+                    listener: handleNullAssertPattern(!)
+                    reportRecoverableErrorWithEnd(y, !, InvalidInsideUnaryPattern)
+                      listener: handleRecoverableError(InvalidInsideUnaryPattern, y, !)
+                    listener: handleNullCheckPattern(?)
+                  listener: handleSwitchCaseNoWhenClause(?)
+                  ensureColon(?)
+                  listener: endCaseExpression(case, null, :)
+                  peekPastLabels(break)
+                  parseStatementsInSwitchCase(:, break, case, 0, 1, null, null)
+                    listener: beginSwitchCase(0, 1, case)
+                    parseStatement(:)
+                      parseStatementX(:)
+                        parseBreakStatement(:)
+                          isBreakAllowed()
+                          ensureSemicolon(break)
+                          listener: handleBreakStatement(false, break, ;)
+                    peekPastLabels(})
+                    listener: endSwitchCase(0, 1, null, null, 1, case, })
+                  notEofOrValue(}, })
+                  listener: endSwitchBlock(1, {, })
+                listener: endSwitchStatement(switch, })
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(2, {, })
+        listener: endTopLevelMethod(void, null, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(void)
+  listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullCheck.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullCheck.dart.parser.expect
new file mode 100644
index 0000000..38bf836
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullCheck.dart.parser.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y!?:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken]![SimpleToken]?[SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullCheck.dart.scanner.expect b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullCheck.dart.scanner.expect
new file mode 100644
index 0000000..38bf836
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullAssert_insideNullCheck.dart.scanner.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y!?:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken]![SimpleToken]?[SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/nullCheck_insideCast.dart b/pkg/front_end/parser_testcases/patterns/nullCheck_insideCast.dart
new file mode 100644
index 0000000..2f24f4c
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullCheck_insideCast.dart
@@ -0,0 +1,7 @@
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y? as num:
+      break;
+  }
+}
diff --git a/pkg/front_end/parser_testcases/patterns/nullCheck_insideCast.dart.expect b/pkg/front_end/parser_testcases/patterns/nullCheck_insideCast.dart.expect
new file mode 100644
index 0000000..19cd339
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullCheck_insideCast.dart.expect
@@ -0,0 +1,69 @@
+Problems reported:
+
+parser/patterns/nullCheck_insideCast:4:10: This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+    case y? as num:
+         ^^
+
+beginCompilationUnit(void)
+  beginMetadataStar(void)
+  endMetadataStar(0)
+  beginTopLevelMember(void)
+    beginTopLevelMethod(, null, null)
+      handleVoidKeyword(void)
+      handleIdentifier(f, topLevelFunctionDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.TopLevelMethod)
+        beginMetadataStar(x)
+        endMetadataStar(0)
+        beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+          handleNoType(()
+          handleIdentifier(x, formalParameterDeclaration)
+          handleFormalParameterWithoutValue())
+        endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+      endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        beginMetadataStar(const)
+        endMetadataStar(0)
+        handleNoType(const)
+        beginVariablesDeclaration(y, null, const)
+          handleIdentifier(y, localVariableDeclaration)
+          beginInitializedIdentifier(y)
+            beginVariableInitializer(=)
+              handleLiteralInt(1)
+            endVariableInitializer(=)
+          endInitializedIdentifier(y)
+        endVariablesDeclaration(1, ;)
+        beginSwitchStatement(switch)
+          handleIdentifier(x, expression)
+          handleNoTypeArguments())
+          handleNoArguments())
+          handleSend(x, ))
+          handleParenthesizedCondition((, null, null)
+          beginSwitchBlock({)
+            beginCaseExpression(case)
+              beginConstantPattern(null)
+                handleIdentifier(y, expression)
+                handleNoTypeArguments(?)
+                handleNoArguments(?)
+                handleSend(y, ?)
+              endConstantPattern(null)
+              handleNullCheckPattern(?)
+              handleRecoverableError(InvalidInsideUnaryPattern, y, ?)
+              beginAsOperatorType(as)
+                handleIdentifier(num, typeReference)
+                handleNoTypeArguments(:)
+                handleType(num, null)
+              endAsOperatorType(as)
+              handleCastPattern(as)
+              handleSwitchCaseNoWhenClause(num)
+            endCaseExpression(case, null, :)
+            beginSwitchCase(0, 1, case)
+              handleBreakStatement(false, break, ;)
+            endSwitchCase(0, 1, null, null, 1, case, })
+          endSwitchBlock(1, {, })
+        endSwitchStatement(switch, })
+      endBlockFunctionBody(2, {, })
+    endTopLevelMethod(void, null, })
+  endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/nullCheck_insideCast.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/nullCheck_insideCast.dart.intertwined.expect
new file mode 100644
index 0000000..631273a
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullCheck_insideCast.dart.intertwined.expect
@@ -0,0 +1,146 @@
+parseUnit(void)
+  skipErrorTokens(void)
+  listener: beginCompilationUnit(void)
+  syntheticPreviousToken(void)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(void)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl()
+      listener: beginTopLevelMember(void)
+      parseTopLevelMethod(, null, null, , Instance of 'VoidType', null, f, false)
+        listener: beginTopLevelMethod(, null, null)
+        listener: handleVoidKeyword(void)
+        ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+          listener: handleIdentifier(f, topLevelFunctionDeclaration)
+        parseMethodTypeVar(f)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(f, MemberKind.TopLevelMethod)
+            parseFormalParametersRest((, MemberKind.TopLevelMethod)
+              listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+              parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+                parseMetadataStar(()
+                  listener: beginMetadataStar(x)
+                  listener: endMetadataStar(0)
+                listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+                listener: handleNoType(()
+                ensureIdentifier((, formalParameterDeclaration)
+                  listener: handleIdentifier(x, formalParameterDeclaration)
+                listener: handleFormalParameterWithoutValue())
+                listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+              listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+        parseAsyncModifierOpt())
+          listener: handleAsyncModifier(null, null)
+          inPlainSync()
+        parseFunctionBody(), false, false)
+          listener: beginBlockFunctionBody({)
+          notEofOrValue(}, const)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrConstDeclaration({)
+                parseExpressionStatementOrDeclarationAfterModifiers(const, {, null, const, Instance of 'NoType', null)
+                  looksLikeLocalFunction(y)
+                  listener: beginMetadataStar(const)
+                  listener: endMetadataStar(0)
+                  listener: handleNoType(const)
+                  listener: beginVariablesDeclaration(y, null, const)
+                  parseVariablesDeclarationRest(const, true)
+                    parseOptionallyInitializedIdentifier(const)
+                      ensureIdentifier(const, localVariableDeclaration)
+                        listener: handleIdentifier(y, localVariableDeclaration)
+                      listener: beginInitializedIdentifier(y)
+                      parseVariableInitializerOpt(y)
+                        listener: beginVariableInitializer(=)
+                        parseExpression(=)
+                          looksLikeOuterPatternEquals(=)
+                            skipOuterPattern(=)
+                          parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
+                            parseUnaryExpression(=, true, ConstantPatternContext.none)
+                              parsePrimary(=, expression, ConstantPatternContext.none)
+                                parseLiteralInt(=)
+                                  listener: handleLiteralInt(1)
+                        listener: endVariableInitializer(=)
+                      listener: endInitializedIdentifier(y)
+                    ensureSemicolon(1)
+                    listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, switch)
+          parseStatement(;)
+            parseStatementX(;)
+              parseSwitchStatement(;)
+                listener: beginSwitchStatement(switch)
+                ensureParenthesizedCondition(switch, allowCase: false)
+                  parseExpressionInParenthesisRest((, allowCase: false)
+                    parseExpression(()
+                      looksLikeOuterPatternEquals(()
+                        skipOuterPattern(()
+                          skipObjectPatternRest(x)
+                      parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+                        parseUnaryExpression((, true, ConstantPatternContext.none)
+                          parsePrimary((, expression, ConstantPatternContext.none)
+                            parseSendOrFunctionLiteral((, expression, ConstantPatternContext.none)
+                              parseSend((, expression, ConstantPatternContext.none)
+                                isNextIdentifier(()
+                                ensureIdentifier((, expression)
+                                  listener: handleIdentifier(x, expression)
+                                listener: handleNoTypeArguments())
+                                parseArgumentsOpt(x)
+                                  listener: handleNoArguments())
+                                listener: handleSend(x, ))
+                    ensureCloseParen(x, ()
+                    listener: handleParenthesizedCondition((, null, null)
+                parseSwitchBlock())
+                  ensureBlock(), null, switch statement)
+                  listener: beginSwitchBlock({)
+                  notEofOrValue(}, case)
+                  peekPastLabels(case)
+                  listener: beginCaseExpression(case)
+                  parsePattern(case, PatternContext.matching, precedence: 1)
+                    parsePrimaryPattern(case, PatternContext.matching)
+                      listener: beginConstantPattern(null)
+                      parsePrecedenceExpression(case, 7, false, ConstantPatternContext.implicit)
+                        parseUnaryExpression(case, false, ConstantPatternContext.implicit)
+                          parsePrimary(case, expression, ConstantPatternContext.implicit)
+                            parseSendOrFunctionLiteral(case, expression, ConstantPatternContext.implicit)
+                              parseSend(case, expression, ConstantPatternContext.implicit)
+                                isNextIdentifier(case)
+                                ensureIdentifier(case, expression)
+                                  listener: handleIdentifier(y, expression)
+                                listener: handleNoTypeArguments(?)
+                                parseArgumentsOpt(y)
+                                  listener: handleNoArguments(?)
+                                listener: handleSend(y, ?)
+                      listener: endConstantPattern(null)
+                    listener: handleNullCheckPattern(?)
+                    reportRecoverableErrorWithEnd(y, ?, InvalidInsideUnaryPattern)
+                      listener: handleRecoverableError(InvalidInsideUnaryPattern, y, ?)
+                    listener: beginAsOperatorType(as)
+                    computeTypeAfterIsOrAs(as)
+                    listener: handleIdentifier(num, typeReference)
+                    listener: handleNoTypeArguments(:)
+                    listener: handleType(num, null)
+                    listener: endAsOperatorType(as)
+                    listener: handleCastPattern(as)
+                  listener: handleSwitchCaseNoWhenClause(num)
+                  ensureColon(num)
+                  listener: endCaseExpression(case, null, :)
+                  peekPastLabels(break)
+                  parseStatementsInSwitchCase(:, break, case, 0, 1, null, null)
+                    listener: beginSwitchCase(0, 1, case)
+                    parseStatement(:)
+                      parseStatementX(:)
+                        parseBreakStatement(:)
+                          isBreakAllowed()
+                          ensureSemicolon(break)
+                          listener: handleBreakStatement(false, break, ;)
+                    peekPastLabels(})
+                    listener: endSwitchCase(0, 1, null, null, 1, case, })
+                  notEofOrValue(}, })
+                  listener: endSwitchBlock(1, {, })
+                listener: endSwitchStatement(switch, })
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(2, {, })
+        listener: endTopLevelMethod(void, null, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(void)
+  listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/nullCheck_insideCast.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/nullCheck_insideCast.dart.parser.expect
new file mode 100644
index 0000000..a2a3b3a
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullCheck_insideCast.dart.parser.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y? as num:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken]?[SimpleToken] as[KeywordToken] num[StringToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/nullCheck_insideCast.dart.scanner.expect b/pkg/front_end/parser_testcases/patterns/nullCheck_insideCast.dart.scanner.expect
new file mode 100644
index 0000000..a2a3b3a
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullCheck_insideCast.dart.scanner.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y? as num:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken]?[SimpleToken] as[KeywordToken] num[StringToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullAssert.dart b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullAssert.dart
new file mode 100644
index 0000000..2d858a8
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullAssert.dart
@@ -0,0 +1,7 @@
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y?!:
+      break;
+  }
+}
diff --git a/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullAssert.dart.expect b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullAssert.dart.expect
new file mode 100644
index 0000000..338b88e
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullAssert.dart.expect
@@ -0,0 +1,64 @@
+Problems reported:
+
+parser/patterns/nullCheck_insideNullAssert:4:10: This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+    case y?!:
+         ^^
+
+beginCompilationUnit(void)
+  beginMetadataStar(void)
+  endMetadataStar(0)
+  beginTopLevelMember(void)
+    beginTopLevelMethod(, null, null)
+      handleVoidKeyword(void)
+      handleIdentifier(f, topLevelFunctionDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.TopLevelMethod)
+        beginMetadataStar(x)
+        endMetadataStar(0)
+        beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+          handleNoType(()
+          handleIdentifier(x, formalParameterDeclaration)
+          handleFormalParameterWithoutValue())
+        endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+      endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        beginMetadataStar(const)
+        endMetadataStar(0)
+        handleNoType(const)
+        beginVariablesDeclaration(y, null, const)
+          handleIdentifier(y, localVariableDeclaration)
+          beginInitializedIdentifier(y)
+            beginVariableInitializer(=)
+              handleLiteralInt(1)
+            endVariableInitializer(=)
+          endInitializedIdentifier(y)
+        endVariablesDeclaration(1, ;)
+        beginSwitchStatement(switch)
+          handleIdentifier(x, expression)
+          handleNoTypeArguments())
+          handleNoArguments())
+          handleSend(x, ))
+          handleParenthesizedCondition((, null, null)
+          beginSwitchBlock({)
+            beginCaseExpression(case)
+              beginConstantPattern(null)
+                handleIdentifier(y, expression)
+                handleNoTypeArguments(?)
+                handleNoArguments(?)
+                handleSend(y, ?)
+              endConstantPattern(null)
+              handleNullCheckPattern(?)
+              handleRecoverableError(InvalidInsideUnaryPattern, y, ?)
+              handleNullAssertPattern(!)
+              handleSwitchCaseNoWhenClause(!)
+            endCaseExpression(case, null, :)
+            beginSwitchCase(0, 1, case)
+              handleBreakStatement(false, break, ;)
+            endSwitchCase(0, 1, null, null, 1, case, })
+          endSwitchBlock(1, {, })
+        endSwitchStatement(switch, })
+      endBlockFunctionBody(2, {, })
+    endTopLevelMethod(void, null, })
+  endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullAssert.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullAssert.dart.intertwined.expect
new file mode 100644
index 0000000..ebe1b2c
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullAssert.dart.intertwined.expect
@@ -0,0 +1,140 @@
+parseUnit(void)
+  skipErrorTokens(void)
+  listener: beginCompilationUnit(void)
+  syntheticPreviousToken(void)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(void)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl()
+      listener: beginTopLevelMember(void)
+      parseTopLevelMethod(, null, null, , Instance of 'VoidType', null, f, false)
+        listener: beginTopLevelMethod(, null, null)
+        listener: handleVoidKeyword(void)
+        ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+          listener: handleIdentifier(f, topLevelFunctionDeclaration)
+        parseMethodTypeVar(f)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(f, MemberKind.TopLevelMethod)
+            parseFormalParametersRest((, MemberKind.TopLevelMethod)
+              listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+              parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+                parseMetadataStar(()
+                  listener: beginMetadataStar(x)
+                  listener: endMetadataStar(0)
+                listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+                listener: handleNoType(()
+                ensureIdentifier((, formalParameterDeclaration)
+                  listener: handleIdentifier(x, formalParameterDeclaration)
+                listener: handleFormalParameterWithoutValue())
+                listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+              listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+        parseAsyncModifierOpt())
+          listener: handleAsyncModifier(null, null)
+          inPlainSync()
+        parseFunctionBody(), false, false)
+          listener: beginBlockFunctionBody({)
+          notEofOrValue(}, const)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrConstDeclaration({)
+                parseExpressionStatementOrDeclarationAfterModifiers(const, {, null, const, Instance of 'NoType', null)
+                  looksLikeLocalFunction(y)
+                  listener: beginMetadataStar(const)
+                  listener: endMetadataStar(0)
+                  listener: handleNoType(const)
+                  listener: beginVariablesDeclaration(y, null, const)
+                  parseVariablesDeclarationRest(const, true)
+                    parseOptionallyInitializedIdentifier(const)
+                      ensureIdentifier(const, localVariableDeclaration)
+                        listener: handleIdentifier(y, localVariableDeclaration)
+                      listener: beginInitializedIdentifier(y)
+                      parseVariableInitializerOpt(y)
+                        listener: beginVariableInitializer(=)
+                        parseExpression(=)
+                          looksLikeOuterPatternEquals(=)
+                            skipOuterPattern(=)
+                          parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
+                            parseUnaryExpression(=, true, ConstantPatternContext.none)
+                              parsePrimary(=, expression, ConstantPatternContext.none)
+                                parseLiteralInt(=)
+                                  listener: handleLiteralInt(1)
+                        listener: endVariableInitializer(=)
+                      listener: endInitializedIdentifier(y)
+                    ensureSemicolon(1)
+                    listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, switch)
+          parseStatement(;)
+            parseStatementX(;)
+              parseSwitchStatement(;)
+                listener: beginSwitchStatement(switch)
+                ensureParenthesizedCondition(switch, allowCase: false)
+                  parseExpressionInParenthesisRest((, allowCase: false)
+                    parseExpression(()
+                      looksLikeOuterPatternEquals(()
+                        skipOuterPattern(()
+                          skipObjectPatternRest(x)
+                      parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+                        parseUnaryExpression((, true, ConstantPatternContext.none)
+                          parsePrimary((, expression, ConstantPatternContext.none)
+                            parseSendOrFunctionLiteral((, expression, ConstantPatternContext.none)
+                              parseSend((, expression, ConstantPatternContext.none)
+                                isNextIdentifier(()
+                                ensureIdentifier((, expression)
+                                  listener: handleIdentifier(x, expression)
+                                listener: handleNoTypeArguments())
+                                parseArgumentsOpt(x)
+                                  listener: handleNoArguments())
+                                listener: handleSend(x, ))
+                    ensureCloseParen(x, ()
+                    listener: handleParenthesizedCondition((, null, null)
+                parseSwitchBlock())
+                  ensureBlock(), null, switch statement)
+                  listener: beginSwitchBlock({)
+                  notEofOrValue(}, case)
+                  peekPastLabels(case)
+                  listener: beginCaseExpression(case)
+                  parsePattern(case, PatternContext.matching, precedence: 1)
+                    parsePrimaryPattern(case, PatternContext.matching)
+                      listener: beginConstantPattern(null)
+                      parsePrecedenceExpression(case, 7, false, ConstantPatternContext.implicit)
+                        parseUnaryExpression(case, false, ConstantPatternContext.implicit)
+                          parsePrimary(case, expression, ConstantPatternContext.implicit)
+                            parseSendOrFunctionLiteral(case, expression, ConstantPatternContext.implicit)
+                              parseSend(case, expression, ConstantPatternContext.implicit)
+                                isNextIdentifier(case)
+                                ensureIdentifier(case, expression)
+                                  listener: handleIdentifier(y, expression)
+                                listener: handleNoTypeArguments(?)
+                                parseArgumentsOpt(y)
+                                  listener: handleNoArguments(?)
+                                listener: handleSend(y, ?)
+                      listener: endConstantPattern(null)
+                    listener: handleNullCheckPattern(?)
+                    reportRecoverableErrorWithEnd(y, ?, InvalidInsideUnaryPattern)
+                      listener: handleRecoverableError(InvalidInsideUnaryPattern, y, ?)
+                    listener: handleNullAssertPattern(!)
+                  listener: handleSwitchCaseNoWhenClause(!)
+                  ensureColon(!)
+                  listener: endCaseExpression(case, null, :)
+                  peekPastLabels(break)
+                  parseStatementsInSwitchCase(:, break, case, 0, 1, null, null)
+                    listener: beginSwitchCase(0, 1, case)
+                    parseStatement(:)
+                      parseStatementX(:)
+                        parseBreakStatement(:)
+                          isBreakAllowed()
+                          ensureSemicolon(break)
+                          listener: handleBreakStatement(false, break, ;)
+                    peekPastLabels(})
+                    listener: endSwitchCase(0, 1, null, null, 1, case, })
+                  notEofOrValue(}, })
+                  listener: endSwitchBlock(1, {, })
+                listener: endSwitchStatement(switch, })
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(2, {, })
+        listener: endTopLevelMethod(void, null, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(void)
+  listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullAssert.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullAssert.dart.parser.expect
new file mode 100644
index 0000000..5e64b7a
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullAssert.dart.parser.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y?!:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken]?[SimpleToken]![SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullAssert.dart.scanner.expect b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullAssert.dart.scanner.expect
new file mode 100644
index 0000000..5e64b7a
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullAssert.dart.scanner.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y?!:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken]?[SimpleToken]![SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullCheck.dart b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullCheck.dart
new file mode 100644
index 0000000..2620410
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullCheck.dart
@@ -0,0 +1,7 @@
+void f(x) {
+  const y = 1;
+  switch (x) {
+    case y? ?:
+      break;
+  }
+}
diff --git a/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullCheck.dart.expect b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullCheck.dart.expect
new file mode 100644
index 0000000..7a03826
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullCheck.dart.expect
@@ -0,0 +1,64 @@
+Problems reported:
+
+parser/patterns/nullCheck_insideNullCheck:4:10: This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+    case y? ?:
+         ^^
+
+beginCompilationUnit(void)
+  beginMetadataStar(void)
+  endMetadataStar(0)
+  beginTopLevelMember(void)
+    beginTopLevelMethod(, null, null)
+      handleVoidKeyword(void)
+      handleIdentifier(f, topLevelFunctionDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.TopLevelMethod)
+        beginMetadataStar(x)
+        endMetadataStar(0)
+        beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+          handleNoType(()
+          handleIdentifier(x, formalParameterDeclaration)
+          handleFormalParameterWithoutValue())
+        endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+      endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        beginMetadataStar(const)
+        endMetadataStar(0)
+        handleNoType(const)
+        beginVariablesDeclaration(y, null, const)
+          handleIdentifier(y, localVariableDeclaration)
+          beginInitializedIdentifier(y)
+            beginVariableInitializer(=)
+              handleLiteralInt(1)
+            endVariableInitializer(=)
+          endInitializedIdentifier(y)
+        endVariablesDeclaration(1, ;)
+        beginSwitchStatement(switch)
+          handleIdentifier(x, expression)
+          handleNoTypeArguments())
+          handleNoArguments())
+          handleSend(x, ))
+          handleParenthesizedCondition((, null, null)
+          beginSwitchBlock({)
+            beginCaseExpression(case)
+              beginConstantPattern(null)
+                handleIdentifier(y, expression)
+                handleNoTypeArguments(?)
+                handleNoArguments(?)
+                handleSend(y, ?)
+              endConstantPattern(null)
+              handleNullCheckPattern(?)
+              handleRecoverableError(InvalidInsideUnaryPattern, y, ?)
+              handleNullCheckPattern(?)
+              handleSwitchCaseNoWhenClause(?)
+            endCaseExpression(case, null, :)
+            beginSwitchCase(0, 1, case)
+              handleBreakStatement(false, break, ;)
+            endSwitchCase(0, 1, null, null, 1, case, })
+          endSwitchBlock(1, {, })
+        endSwitchStatement(switch, })
+      endBlockFunctionBody(2, {, })
+    endTopLevelMethod(void, null, })
+  endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullCheck.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullCheck.dart.intertwined.expect
new file mode 100644
index 0000000..c1a68e4
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullCheck.dart.intertwined.expect
@@ -0,0 +1,140 @@
+parseUnit(void)
+  skipErrorTokens(void)
+  listener: beginCompilationUnit(void)
+  syntheticPreviousToken(void)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(void)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl()
+      listener: beginTopLevelMember(void)
+      parseTopLevelMethod(, null, null, , Instance of 'VoidType', null, f, false)
+        listener: beginTopLevelMethod(, null, null)
+        listener: handleVoidKeyword(void)
+        ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+          listener: handleIdentifier(f, topLevelFunctionDeclaration)
+        parseMethodTypeVar(f)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(f, MemberKind.TopLevelMethod)
+            parseFormalParametersRest((, MemberKind.TopLevelMethod)
+              listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+              parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+                parseMetadataStar(()
+                  listener: beginMetadataStar(x)
+                  listener: endMetadataStar(0)
+                listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+                listener: handleNoType(()
+                ensureIdentifier((, formalParameterDeclaration)
+                  listener: handleIdentifier(x, formalParameterDeclaration)
+                listener: handleFormalParameterWithoutValue())
+                listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+              listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+        parseAsyncModifierOpt())
+          listener: handleAsyncModifier(null, null)
+          inPlainSync()
+        parseFunctionBody(), false, false)
+          listener: beginBlockFunctionBody({)
+          notEofOrValue(}, const)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrConstDeclaration({)
+                parseExpressionStatementOrDeclarationAfterModifiers(const, {, null, const, Instance of 'NoType', null)
+                  looksLikeLocalFunction(y)
+                  listener: beginMetadataStar(const)
+                  listener: endMetadataStar(0)
+                  listener: handleNoType(const)
+                  listener: beginVariablesDeclaration(y, null, const)
+                  parseVariablesDeclarationRest(const, true)
+                    parseOptionallyInitializedIdentifier(const)
+                      ensureIdentifier(const, localVariableDeclaration)
+                        listener: handleIdentifier(y, localVariableDeclaration)
+                      listener: beginInitializedIdentifier(y)
+                      parseVariableInitializerOpt(y)
+                        listener: beginVariableInitializer(=)
+                        parseExpression(=)
+                          looksLikeOuterPatternEquals(=)
+                            skipOuterPattern(=)
+                          parsePrecedenceExpression(=, 1, true, ConstantPatternContext.none)
+                            parseUnaryExpression(=, true, ConstantPatternContext.none)
+                              parsePrimary(=, expression, ConstantPatternContext.none)
+                                parseLiteralInt(=)
+                                  listener: handleLiteralInt(1)
+                        listener: endVariableInitializer(=)
+                      listener: endInitializedIdentifier(y)
+                    ensureSemicolon(1)
+                    listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, switch)
+          parseStatement(;)
+            parseStatementX(;)
+              parseSwitchStatement(;)
+                listener: beginSwitchStatement(switch)
+                ensureParenthesizedCondition(switch, allowCase: false)
+                  parseExpressionInParenthesisRest((, allowCase: false)
+                    parseExpression(()
+                      looksLikeOuterPatternEquals(()
+                        skipOuterPattern(()
+                          skipObjectPatternRest(x)
+                      parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+                        parseUnaryExpression((, true, ConstantPatternContext.none)
+                          parsePrimary((, expression, ConstantPatternContext.none)
+                            parseSendOrFunctionLiteral((, expression, ConstantPatternContext.none)
+                              parseSend((, expression, ConstantPatternContext.none)
+                                isNextIdentifier(()
+                                ensureIdentifier((, expression)
+                                  listener: handleIdentifier(x, expression)
+                                listener: handleNoTypeArguments())
+                                parseArgumentsOpt(x)
+                                  listener: handleNoArguments())
+                                listener: handleSend(x, ))
+                    ensureCloseParen(x, ()
+                    listener: handleParenthesizedCondition((, null, null)
+                parseSwitchBlock())
+                  ensureBlock(), null, switch statement)
+                  listener: beginSwitchBlock({)
+                  notEofOrValue(}, case)
+                  peekPastLabels(case)
+                  listener: beginCaseExpression(case)
+                  parsePattern(case, PatternContext.matching, precedence: 1)
+                    parsePrimaryPattern(case, PatternContext.matching)
+                      listener: beginConstantPattern(null)
+                      parsePrecedenceExpression(case, 7, false, ConstantPatternContext.implicit)
+                        parseUnaryExpression(case, false, ConstantPatternContext.implicit)
+                          parsePrimary(case, expression, ConstantPatternContext.implicit)
+                            parseSendOrFunctionLiteral(case, expression, ConstantPatternContext.implicit)
+                              parseSend(case, expression, ConstantPatternContext.implicit)
+                                isNextIdentifier(case)
+                                ensureIdentifier(case, expression)
+                                  listener: handleIdentifier(y, expression)
+                                listener: handleNoTypeArguments(?)
+                                parseArgumentsOpt(y)
+                                  listener: handleNoArguments(?)
+                                listener: handleSend(y, ?)
+                      listener: endConstantPattern(null)
+                    listener: handleNullCheckPattern(?)
+                    reportRecoverableErrorWithEnd(y, ?, InvalidInsideUnaryPattern)
+                      listener: handleRecoverableError(InvalidInsideUnaryPattern, y, ?)
+                    listener: handleNullCheckPattern(?)
+                  listener: handleSwitchCaseNoWhenClause(?)
+                  ensureColon(?)
+                  listener: endCaseExpression(case, null, :)
+                  peekPastLabels(break)
+                  parseStatementsInSwitchCase(:, break, case, 0, 1, null, null)
+                    listener: beginSwitchCase(0, 1, case)
+                    parseStatement(:)
+                      parseStatementX(:)
+                        parseBreakStatement(:)
+                          isBreakAllowed()
+                          ensureSemicolon(break)
+                          listener: handleBreakStatement(false, break, ;)
+                    peekPastLabels(})
+                    listener: endSwitchCase(0, 1, null, null, 1, case, })
+                  notEofOrValue(}, })
+                  listener: endSwitchBlock(1, {, })
+                listener: endSwitchStatement(switch, })
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(2, {, })
+        listener: endTopLevelMethod(void, null, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(void)
+  listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullCheck.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullCheck.dart.parser.expect
new file mode 100644
index 0000000..167e4cc
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullCheck.dart.parser.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y? ?:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken]?[SimpleToken] ?[SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullCheck.dart.scanner.expect b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullCheck.dart.scanner.expect
new file mode 100644
index 0000000..167e4cc
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/nullCheck_insideNullCheck.dart.scanner.expect
@@ -0,0 +1,17 @@
+void f(x) {
+const y = 1;
+switch (x) {
+case y? ?:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+const[KeywordToken] y[StringToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] y[StringToken]?[SimpleToken] ?[SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_equal.dart b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_equal.dart
new file mode 100644
index 0000000..c838bae
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_equal.dart
@@ -0,0 +1,6 @@
+void f(x) {
+  switch (x) {
+    case == 1?:
+      break;
+  }
+}
diff --git a/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_equal.dart.expect b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_equal.dart.expect
new file mode 100644
index 0000000..fe35ca7
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_equal.dart.expect
@@ -0,0 +1,48 @@
+Problems reported:
+
+parser/patterns/relational_insideNullCheck_equal:3:10: This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+    case == 1?:
+         ^^^^
+
+beginCompilationUnit(void)
+  beginMetadataStar(void)
+  endMetadataStar(0)
+  beginTopLevelMember(void)
+    beginTopLevelMethod(, null, null)
+      handleVoidKeyword(void)
+      handleIdentifier(f, topLevelFunctionDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.TopLevelMethod)
+        beginMetadataStar(x)
+        endMetadataStar(0)
+        beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+          handleNoType(()
+          handleIdentifier(x, formalParameterDeclaration)
+          handleFormalParameterWithoutValue())
+        endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+      endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        beginSwitchStatement(switch)
+          handleIdentifier(x, expression)
+          handleNoTypeArguments())
+          handleNoArguments())
+          handleSend(x, ))
+          handleParenthesizedCondition((, null, null)
+          beginSwitchBlock({)
+            beginCaseExpression(case)
+              handleLiteralInt(1)
+              handleRelationalPattern(==)
+              handleRecoverableError(InvalidInsideUnaryPattern, ==, 1)
+              handleNullCheckPattern(?)
+              handleSwitchCaseNoWhenClause(?)
+            endCaseExpression(case, null, :)
+            beginSwitchCase(0, 1, case)
+              handleBreakStatement(false, break, ;)
+            endSwitchCase(0, 1, null, null, 1, case, })
+          endSwitchBlock(1, {, })
+        endSwitchStatement(switch, })
+      endBlockFunctionBody(1, {, })
+    endTopLevelMethod(void, null, })
+  endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_equal.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_equal.dart.intertwined.expect
new file mode 100644
index 0000000..2d520005
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_equal.dart.intertwined.expect
@@ -0,0 +1,102 @@
+parseUnit(void)
+  skipErrorTokens(void)
+  listener: beginCompilationUnit(void)
+  syntheticPreviousToken(void)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(void)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl()
+      listener: beginTopLevelMember(void)
+      parseTopLevelMethod(, null, null, , Instance of 'VoidType', null, f, false)
+        listener: beginTopLevelMethod(, null, null)
+        listener: handleVoidKeyword(void)
+        ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+          listener: handleIdentifier(f, topLevelFunctionDeclaration)
+        parseMethodTypeVar(f)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(f, MemberKind.TopLevelMethod)
+            parseFormalParametersRest((, MemberKind.TopLevelMethod)
+              listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+              parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+                parseMetadataStar(()
+                  listener: beginMetadataStar(x)
+                  listener: endMetadataStar(0)
+                listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+                listener: handleNoType(()
+                ensureIdentifier((, formalParameterDeclaration)
+                  listener: handleIdentifier(x, formalParameterDeclaration)
+                listener: handleFormalParameterWithoutValue())
+                listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+              listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+        parseAsyncModifierOpt())
+          listener: handleAsyncModifier(null, null)
+          inPlainSync()
+        parseFunctionBody(), false, false)
+          listener: beginBlockFunctionBody({)
+          notEofOrValue(}, switch)
+          parseStatement({)
+            parseStatementX({)
+              parseSwitchStatement({)
+                listener: beginSwitchStatement(switch)
+                ensureParenthesizedCondition(switch, allowCase: false)
+                  parseExpressionInParenthesisRest((, allowCase: false)
+                    parseExpression(()
+                      looksLikeOuterPatternEquals(()
+                        skipOuterPattern(()
+                          skipObjectPatternRest(x)
+                      parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+                        parseUnaryExpression((, true, ConstantPatternContext.none)
+                          parsePrimary((, expression, ConstantPatternContext.none)
+                            parseSendOrFunctionLiteral((, expression, ConstantPatternContext.none)
+                              parseSend((, expression, ConstantPatternContext.none)
+                                isNextIdentifier(()
+                                ensureIdentifier((, expression)
+                                  listener: handleIdentifier(x, expression)
+                                listener: handleNoTypeArguments())
+                                parseArgumentsOpt(x)
+                                  listener: handleNoArguments())
+                                listener: handleSend(x, ))
+                    ensureCloseParen(x, ()
+                    listener: handleParenthesizedCondition((, null, null)
+                parseSwitchBlock())
+                  ensureBlock(), null, switch statement)
+                  listener: beginSwitchBlock({)
+                  notEofOrValue(}, case)
+                  peekPastLabels(case)
+                  listener: beginCaseExpression(case)
+                  parsePattern(case, PatternContext.matching, precedence: 1)
+                    parsePrimaryPattern(case, PatternContext.matching)
+                      parsePrecedenceExpression(==, 12, false, ConstantPatternContext.none)
+                        parseUnaryExpression(==, false, ConstantPatternContext.none)
+                          parsePrimary(==, expression, ConstantPatternContext.none)
+                            parseLiteralInt(==)
+                              listener: handleLiteralInt(1)
+                      listener: handleRelationalPattern(==)
+                    reportRecoverableErrorWithEnd(==, 1, InvalidInsideUnaryPattern)
+                      listener: handleRecoverableError(InvalidInsideUnaryPattern, ==, 1)
+                    listener: handleNullCheckPattern(?)
+                  listener: handleSwitchCaseNoWhenClause(?)
+                  ensureColon(?)
+                  listener: endCaseExpression(case, null, :)
+                  peekPastLabels(break)
+                  parseStatementsInSwitchCase(:, break, case, 0, 1, null, null)
+                    listener: beginSwitchCase(0, 1, case)
+                    parseStatement(:)
+                      parseStatementX(:)
+                        parseBreakStatement(:)
+                          isBreakAllowed()
+                          ensureSemicolon(break)
+                          listener: handleBreakStatement(false, break, ;)
+                    peekPastLabels(})
+                    listener: endSwitchCase(0, 1, null, null, 1, case, })
+                  notEofOrValue(}, })
+                  listener: endSwitchBlock(1, {, })
+                listener: endSwitchStatement(switch, })
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(1, {, })
+        listener: endTopLevelMethod(void, null, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(void)
+  listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_equal.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_equal.dart.parser.expect
new file mode 100644
index 0000000..ad4e00e
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_equal.dart.parser.expect
@@ -0,0 +1,15 @@
+void f(x) {
+switch (x) {
+case == 1?:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] ==[SimpleToken] 1[StringToken]?[SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_equal.dart.scanner.expect b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_equal.dart.scanner.expect
new file mode 100644
index 0000000..ad4e00e
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_equal.dart.scanner.expect
@@ -0,0 +1,15 @@
+void f(x) {
+switch (x) {
+case == 1?:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] ==[SimpleToken] 1[StringToken]?[SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_greaterThan.dart b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_greaterThan.dart
new file mode 100644
index 0000000..be493c2
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_greaterThan.dart
@@ -0,0 +1,6 @@
+void f(x) {
+  switch (x) {
+    case > 1?:
+      break;
+  }
+}
diff --git a/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_greaterThan.dart.expect b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_greaterThan.dart.expect
new file mode 100644
index 0000000..e1a4851
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_greaterThan.dart.expect
@@ -0,0 +1,48 @@
+Problems reported:
+
+parser/patterns/relational_insideNullCheck_greaterThan:3:10: This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+    case > 1?:
+         ^^^
+
+beginCompilationUnit(void)
+  beginMetadataStar(void)
+  endMetadataStar(0)
+  beginTopLevelMember(void)
+    beginTopLevelMethod(, null, null)
+      handleVoidKeyword(void)
+      handleIdentifier(f, topLevelFunctionDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.TopLevelMethod)
+        beginMetadataStar(x)
+        endMetadataStar(0)
+        beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+          handleNoType(()
+          handleIdentifier(x, formalParameterDeclaration)
+          handleFormalParameterWithoutValue())
+        endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+      endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        beginSwitchStatement(switch)
+          handleIdentifier(x, expression)
+          handleNoTypeArguments())
+          handleNoArguments())
+          handleSend(x, ))
+          handleParenthesizedCondition((, null, null)
+          beginSwitchBlock({)
+            beginCaseExpression(case)
+              handleLiteralInt(1)
+              handleRelationalPattern(>)
+              handleRecoverableError(InvalidInsideUnaryPattern, >, 1)
+              handleNullCheckPattern(?)
+              handleSwitchCaseNoWhenClause(?)
+            endCaseExpression(case, null, :)
+            beginSwitchCase(0, 1, case)
+              handleBreakStatement(false, break, ;)
+            endSwitchCase(0, 1, null, null, 1, case, })
+          endSwitchBlock(1, {, })
+        endSwitchStatement(switch, })
+      endBlockFunctionBody(1, {, })
+    endTopLevelMethod(void, null, })
+  endTopLevelDeclaration()
+endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_greaterThan.dart.intertwined.expect b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_greaterThan.dart.intertwined.expect
new file mode 100644
index 0000000..4b43213
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_greaterThan.dart.intertwined.expect
@@ -0,0 +1,102 @@
+parseUnit(void)
+  skipErrorTokens(void)
+  listener: beginCompilationUnit(void)
+  syntheticPreviousToken(void)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(void)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl()
+      listener: beginTopLevelMember(void)
+      parseTopLevelMethod(, null, null, , Instance of 'VoidType', null, f, false)
+        listener: beginTopLevelMethod(, null, null)
+        listener: handleVoidKeyword(void)
+        ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+          listener: handleIdentifier(f, topLevelFunctionDeclaration)
+        parseMethodTypeVar(f)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(f, f, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(f, MemberKind.TopLevelMethod)
+            parseFormalParametersRest((, MemberKind.TopLevelMethod)
+              listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+              parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+                parseMetadataStar(()
+                  listener: beginMetadataStar(x)
+                  listener: endMetadataStar(0)
+                listener: beginFormalParameter(x, MemberKind.TopLevelMethod, null, null, null)
+                listener: handleNoType(()
+                ensureIdentifier((, formalParameterDeclaration)
+                  listener: handleIdentifier(x, formalParameterDeclaration)
+                listener: handleFormalParameterWithoutValue())
+                listener: endFormalParameter(null, null, null, x, null, null, FormalParameterKind.requiredPositional, MemberKind.TopLevelMethod)
+              listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+        parseAsyncModifierOpt())
+          listener: handleAsyncModifier(null, null)
+          inPlainSync()
+        parseFunctionBody(), false, false)
+          listener: beginBlockFunctionBody({)
+          notEofOrValue(}, switch)
+          parseStatement({)
+            parseStatementX({)
+              parseSwitchStatement({)
+                listener: beginSwitchStatement(switch)
+                ensureParenthesizedCondition(switch, allowCase: false)
+                  parseExpressionInParenthesisRest((, allowCase: false)
+                    parseExpression(()
+                      looksLikeOuterPatternEquals(()
+                        skipOuterPattern(()
+                          skipObjectPatternRest(x)
+                      parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+                        parseUnaryExpression((, true, ConstantPatternContext.none)
+                          parsePrimary((, expression, ConstantPatternContext.none)
+                            parseSendOrFunctionLiteral((, expression, ConstantPatternContext.none)
+                              parseSend((, expression, ConstantPatternContext.none)
+                                isNextIdentifier(()
+                                ensureIdentifier((, expression)
+                                  listener: handleIdentifier(x, expression)
+                                listener: handleNoTypeArguments())
+                                parseArgumentsOpt(x)
+                                  listener: handleNoArguments())
+                                listener: handleSend(x, ))
+                    ensureCloseParen(x, ()
+                    listener: handleParenthesizedCondition((, null, null)
+                parseSwitchBlock())
+                  ensureBlock(), null, switch statement)
+                  listener: beginSwitchBlock({)
+                  notEofOrValue(}, case)
+                  peekPastLabels(case)
+                  listener: beginCaseExpression(case)
+                  parsePattern(case, PatternContext.matching, precedence: 1)
+                    parsePrimaryPattern(case, PatternContext.matching)
+                      parsePrecedenceExpression(>, 12, false, ConstantPatternContext.none)
+                        parseUnaryExpression(>, false, ConstantPatternContext.none)
+                          parsePrimary(>, expression, ConstantPatternContext.none)
+                            parseLiteralInt(>)
+                              listener: handleLiteralInt(1)
+                      listener: handleRelationalPattern(>)
+                    reportRecoverableErrorWithEnd(>, 1, InvalidInsideUnaryPattern)
+                      listener: handleRecoverableError(InvalidInsideUnaryPattern, >, 1)
+                    listener: handleNullCheckPattern(?)
+                  listener: handleSwitchCaseNoWhenClause(?)
+                  ensureColon(?)
+                  listener: endCaseExpression(case, null, :)
+                  peekPastLabels(break)
+                  parseStatementsInSwitchCase(:, break, case, 0, 1, null, null)
+                    listener: beginSwitchCase(0, 1, case)
+                    parseStatement(:)
+                      parseStatementX(:)
+                        parseBreakStatement(:)
+                          isBreakAllowed()
+                          ensureSemicolon(break)
+                          listener: handleBreakStatement(false, break, ;)
+                    peekPastLabels(})
+                    listener: endSwitchCase(0, 1, null, null, 1, case, })
+                  notEofOrValue(}, })
+                  listener: endSwitchBlock(1, {, })
+                listener: endSwitchStatement(switch, })
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(1, {, })
+        listener: endTopLevelMethod(void, null, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(void)
+  listener: endCompilationUnit(1, )
diff --git a/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_greaterThan.dart.parser.expect b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_greaterThan.dart.parser.expect
new file mode 100644
index 0000000..0456ecc
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_greaterThan.dart.parser.expect
@@ -0,0 +1,15 @@
+void f(x) {
+switch (x) {
+case > 1?:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] >[SimpleToken] 1[StringToken]?[SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_greaterThan.dart.scanner.expect b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_greaterThan.dart.scanner.expect
new file mode 100644
index 0000000..0456ecc
--- /dev/null
+++ b/pkg/front_end/parser_testcases/patterns/relational_insideNullCheck_greaterThan.dart.scanner.expect
@@ -0,0 +1,15 @@
+void f(x) {
+switch (x) {
+case > 1?:
+break;
+}
+}
+
+
+void[KeywordToken] f[StringToken]([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+switch[KeywordToken] ([BeginToken]x[StringToken])[SimpleToken] {[BeginToken]
+case[KeywordToken] >[SimpleToken] 1[StringToken]?[SimpleToken]:[SimpleToken]
+break[KeywordToken];[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/test/spell_checking_list_messages.txt b/pkg/front_end/test/spell_checking_list_messages.txt
index e744319..5f2c9ba 100644
--- a/pkg/front_end/test/spell_checking_list_messages.txt
+++ b/pkg/front_end/test/spell_checking_list_messages.txt
@@ -23,6 +23,7 @@
 augmented
 b
 c
+cast
 collide
 compilercontext.runincontext
 compilesdk
@@ -39,6 +40,7 @@
 dartbug.com
 dname
 e.g
+enclose
 exhaustively
 exportable
 f
diff --git a/pkg/front_end/testcases/late_lowering/caching.dart b/pkg/front_end/testcases/late_lowering/caching.dart
index 77c818d..395457c 100644
--- a/pkg/front_end/testcases/late_lowering/caching.dart
+++ b/pkg/front_end/testcases/late_lowering/caching.dart
@@ -15,7 +15,7 @@
   if (o case 1) {
     return 1;
   }
-  if (o case (f: >=3 as int && <5 as int)) {
+  if (o case (f: (>=3) as int && (<5) as int)) {
     return 2;
   }
   if (o case 6 || 7) {
@@ -39,10 +39,10 @@
   if (o case [3, 4, ..., 5]) {
     return 9;
   }
-  if (o case [4, 5, ...[<1 as int, >2 as int]]) {
+  if (o case [4, 5, ...[(<1) as int, (>2) as int]]) {
     return 10;
   }
-  if (o case [5, 6, ...[<1 as int, >2 as int], 7]) {
+  if (o case [5, 6, ...[(<1) as int, (>2) as int], 7]) {
     return 11;
   }
   if (o case Class(field: 1)) {
@@ -103,7 +103,7 @@
   print('o = $o');
   if (o case 1) {
     return 1;
-  } else if (o case (f: >=3 as int && <5 as int)) {
+  } else if (o case (f: (>=3) as int && (<5) as int)) {
     return 2;
   } else if (o case 6 || 7) {
     return 3;
@@ -119,9 +119,9 @@
     return 8;
   } else if (o case [3, 4, ..., 5]) {
     return 9;
-  } else if (o case [4, 5, ...[<1 as int, >2 as int]]) {
+  } else if (o case [4, 5, ...[(<1) as int, (>2) as int]]) {
     return 10;
-  } else if (o case [5, 6, ...[<1 as int, >2 as int], 7]) {
+  } else if (o case [5, 6, ...[(<1) as int, (>2) as int], 7]) {
     return 11;
   } else if (o case Class(field: 1)) {
     return 12;
@@ -167,7 +167,7 @@
   switch (o) {
     case 1:
       return 1;
-    case (f: >=3 as int && <5 as int):
+    case (f: (>=3) as int && (<5) as int):
       return 2;
     case 6 || 7:
       return 3;
@@ -183,9 +183,9 @@
       return 8;
     case [3, 4, ..., 5]:
       return 9;
-    case [4, 5, ...[<1 as int, >2 as int]]:
+    case [4, 5, ...[(<1) as int, (>2) as int]]:
       return 10;
-    case [5, 6, ...[<1 as int, >2 as int], 7]:
+    case [5, 6, ...[(<1) as int, (>2) as int], 7]:
       return 11;
     case Class(field: 1):
       return 12;
@@ -230,7 +230,7 @@
   print('o = $o');
   return switch (o) {
     1 => 1,
-    (f: >=3 as int && <5 as int) => 2,
+    (f: (>=3) as int && (<5) as int) => 2,
     6 || 7 => 3,
     (g: 8 as int) => 4,
     (a: _!) => 5,
@@ -238,8 +238,8 @@
     [1, 2] => 7,
     [2, 3, ...] => 8,
     [3, 4, ..., 5] => 9,
-    [4, 5, ...[<1 as int, >2 as int]] => 10,
-    [5, 6, ...[<1 as int, >2 as int], 7] => 11,
+    [4, 5, ...[(<1) as int, (>2) as int]] => 10,
+    [5, 6, ...[(<1) as int, (>2) as int], 7] => 11,
     Class(field: 1) => 12,
     Class(finalField: 2) => 13,
     Class(field: 3, getter: 4) => 14,
@@ -341,4 +341,4 @@
   if (expected != actual) {
     throw 'Expected $expected, actual $actual';
   }
-}
\ No newline at end of file
+}
diff --git a/pkg/front_end/testcases/patterns/caching.dart b/pkg/front_end/testcases/patterns/caching.dart
index 77c818d..395457c 100644
--- a/pkg/front_end/testcases/patterns/caching.dart
+++ b/pkg/front_end/testcases/patterns/caching.dart
@@ -15,7 +15,7 @@
   if (o case 1) {
     return 1;
   }
-  if (o case (f: >=3 as int && <5 as int)) {
+  if (o case (f: (>=3) as int && (<5) as int)) {
     return 2;
   }
   if (o case 6 || 7) {
@@ -39,10 +39,10 @@
   if (o case [3, 4, ..., 5]) {
     return 9;
   }
-  if (o case [4, 5, ...[<1 as int, >2 as int]]) {
+  if (o case [4, 5, ...[(<1) as int, (>2) as int]]) {
     return 10;
   }
-  if (o case [5, 6, ...[<1 as int, >2 as int], 7]) {
+  if (o case [5, 6, ...[(<1) as int, (>2) as int], 7]) {
     return 11;
   }
   if (o case Class(field: 1)) {
@@ -103,7 +103,7 @@
   print('o = $o');
   if (o case 1) {
     return 1;
-  } else if (o case (f: >=3 as int && <5 as int)) {
+  } else if (o case (f: (>=3) as int && (<5) as int)) {
     return 2;
   } else if (o case 6 || 7) {
     return 3;
@@ -119,9 +119,9 @@
     return 8;
   } else if (o case [3, 4, ..., 5]) {
     return 9;
-  } else if (o case [4, 5, ...[<1 as int, >2 as int]]) {
+  } else if (o case [4, 5, ...[(<1) as int, (>2) as int]]) {
     return 10;
-  } else if (o case [5, 6, ...[<1 as int, >2 as int], 7]) {
+  } else if (o case [5, 6, ...[(<1) as int, (>2) as int], 7]) {
     return 11;
   } else if (o case Class(field: 1)) {
     return 12;
@@ -167,7 +167,7 @@
   switch (o) {
     case 1:
       return 1;
-    case (f: >=3 as int && <5 as int):
+    case (f: (>=3) as int && (<5) as int):
       return 2;
     case 6 || 7:
       return 3;
@@ -183,9 +183,9 @@
       return 8;
     case [3, 4, ..., 5]:
       return 9;
-    case [4, 5, ...[<1 as int, >2 as int]]:
+    case [4, 5, ...[(<1) as int, (>2) as int]]:
       return 10;
-    case [5, 6, ...[<1 as int, >2 as int], 7]:
+    case [5, 6, ...[(<1) as int, (>2) as int], 7]:
       return 11;
     case Class(field: 1):
       return 12;
@@ -230,7 +230,7 @@
   print('o = $o');
   return switch (o) {
     1 => 1,
-    (f: >=3 as int && <5 as int) => 2,
+    (f: (>=3) as int && (<5) as int) => 2,
     6 || 7 => 3,
     (g: 8 as int) => 4,
     (a: _!) => 5,
@@ -238,8 +238,8 @@
     [1, 2] => 7,
     [2, 3, ...] => 8,
     [3, 4, ..., 5] => 9,
-    [4, 5, ...[<1 as int, >2 as int]] => 10,
-    [5, 6, ...[<1 as int, >2 as int], 7] => 11,
+    [4, 5, ...[(<1) as int, (>2) as int]] => 10,
+    [5, 6, ...[(<1) as int, (>2) as int], 7] => 11,
     Class(field: 1) => 12,
     Class(finalField: 2) => 13,
     Class(field: 3, getter: 4) => 14,
@@ -341,4 +341,4 @@
   if (expected != actual) {
     throw 'Expected $expected, actual $actual';
   }
-}
\ No newline at end of file
+}
diff --git a/pkg/front_end/testcases/patterns/const_patterns.dart b/pkg/front_end/testcases/patterns/const_patterns.dart
index bb90005..32a7752 100644
--- a/pkg/front_end/testcases/patterns/const_patterns.dart
+++ b/pkg/front_end/testcases/patterns/const_patterns.dart
@@ -33,12 +33,12 @@
       case value: // Ok
       case value!: // Ok
       case value?: // Ok
-      case value?!: // Ok
-      case value!?: // Ok
+      case (value?)!: // Ok
+      case (value!)?: // Ok
       case -42!: // Ok
       case -42?: // Ok
-      case -42!?: // Ok
-      case -42?!: // Ok
+      case (-42!)?: // Ok
+      case (-42?)!: // Ok
       case value as int: // Ok
       case -value: // Error
       case local: // Ok
diff --git a/tests/language/patterns/invalid_inside_unary_pattern_error_test.dart b/tests/language/patterns/invalid_inside_unary_pattern_error_test.dart
new file mode 100644
index 0000000..eae522e
--- /dev/null
+++ b/tests/language/patterns/invalid_inside_unary_pattern_error_test.dart
@@ -0,0 +1,123 @@
+// 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.
+
+// SharedOptions=--enable-experiment=patterns
+
+// Test that errors are generated if a unary pattern or a relational pattern
+// appears inside a unary pattern.  This is prohibited by the patterns grammar,
+// but accepted by the parser's precedence-based parsing logic (because it's not
+// actually ambiguous), so the parser has special logic to detect the error
+// condition.
+
+test_cast_insideCast(x) {
+  switch (x) {
+    case _ as int as num:
+    //   ^^^^^^^^
+    // [analyzer] SYNTACTIC_ERROR.INVALID_INSIDE_UNARY_PATTERN
+    // [cfe] This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+      break;
+  }
+}
+
+test_cast_insideNullAssert(x) {
+  switch (x) {
+    case _ as int!:
+    //   ^^^^^^^^
+    // [analyzer] SYNTACTIC_ERROR.INVALID_INSIDE_UNARY_PATTERN
+    // [cfe] This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+      break;
+  }
+}
+
+test_cast_insideNullCheck(x) {
+  switch (x) {
+    case _ as int? ?:
+    //   ^^^^^^^^^
+    // [analyzer] SYNTACTIC_ERROR.INVALID_INSIDE_UNARY_PATTERN
+    // [cfe] This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+      break;
+  }
+}
+
+test_nullAssert_insideCast(x) {
+  switch (x) {
+    case _! as num?:
+    //   ^^
+    // [analyzer] SYNTACTIC_ERROR.INVALID_INSIDE_UNARY_PATTERN
+    // [cfe] This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+      break;
+  }
+}
+
+test_nullAssert_insideNullAssert(x) {
+  switch (x) {
+    case _!!:
+    //   ^^
+    // [analyzer] SYNTACTIC_ERROR.INVALID_INSIDE_UNARY_PATTERN
+    // [cfe] This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+      break;
+  }
+}
+
+test_nullAssert_insideNullCheck(x) {
+  switch (x) {
+    case _!?:
+    //   ^^
+    // [analyzer] SYNTACTIC_ERROR.INVALID_INSIDE_UNARY_PATTERN
+    // [cfe] This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+      break;
+  }
+}
+
+test_nullCheck_insideCast(x) {
+  switch (x) {
+    case _? as num?:
+    //   ^^
+    // [analyzer] SYNTACTIC_ERROR.INVALID_INSIDE_UNARY_PATTERN
+    // [cfe] This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+      break;
+  }
+}
+
+test_nullCheck_insideNullAssert(x) {
+  switch (x) {
+    case _?!:
+    //   ^^
+    // [analyzer] SYNTACTIC_ERROR.INVALID_INSIDE_UNARY_PATTERN
+    // [cfe] This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+      break;
+  }
+}
+
+test_nullCheck_insideNullCheck(x) {
+  switch (x) {
+    case _? ?:
+    //   ^^
+    // [analyzer] SYNTACTIC_ERROR.INVALID_INSIDE_UNARY_PATTERN
+    // [cfe] This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+      break;
+  }
+}
+
+test_relational_insideNullCheck_equal(x) {
+  switch (x) {
+    case == 1?:
+    //   ^^^^
+    // [analyzer] SYNTACTIC_ERROR.INVALID_INSIDE_UNARY_PATTERN
+    // [cfe] This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+      break;
+  }
+}
+
+test_relational_insideNullCheck_greaterThan(x) {
+  switch (x) {
+    case > 1?:
+    //   ^^^
+    // [analyzer] SYNTACTIC_ERROR.INVALID_INSIDE_UNARY_PATTERN
+    // [cfe] This pattern cannot appear inside a unary pattern (cast pattern, null check pattern, or null assert pattern) without parentheses.
+      break;
+  }
+}
+
+main() {}
diff --git a/tests/language/patterns/invalid_inside_unary_pattern_parentheses_test.dart b/tests/language/patterns/invalid_inside_unary_pattern_parentheses_test.dart
new file mode 100644
index 0000000..07edb38
--- /dev/null
+++ b/tests/language/patterns/invalid_inside_unary_pattern_parentheses_test.dart
@@ -0,0 +1,123 @@
+// 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.
+
+// SharedOptions=--enable-experiment=patterns
+
+// Test that a unary pattern or a relational pattern may appear inside a unary
+// pattern as long as there are parentheses.
+
+import 'package:expect/expect.dart';
+
+test_cast_insideCast(x) {
+  switch (x) {
+    case (_ as int) as num:
+      break;
+    default:
+      Expect.fail('failed to match');
+  }
+}
+
+test_cast_insideNullAssert(x) {
+  switch (x) {
+    case (_ as int)!:
+      break;
+    default:
+      Expect.fail('failed to match');
+  }
+}
+
+test_cast_insideNullCheck(x) {
+  switch (x) {
+    case (_ as int?)?:
+      break;
+    default:
+      Expect.fail('failed to match');
+  }
+}
+
+test_nullAssert_insideCast(x) {
+  switch (x) {
+    case (_!) as num?:
+      break;
+    default:
+      Expect.fail('failed to match');
+  }
+}
+
+test_nullAssert_insideNullAssert(x) {
+  switch (x) {
+    case (_!)!:
+      break;
+    default:
+      Expect.fail('failed to match');
+  }
+}
+
+test_nullAssert_insideNullCheck(x) {
+  switch (x) {
+    case (_!)?:
+      break;
+    default:
+      Expect.fail('failed to match');
+  }
+}
+
+test_nullCheck_insideCast(x) {
+  switch (x) {
+    case (_?) as num?:
+      break;
+    default:
+      Expect.fail('failed to match');
+  }
+}
+
+test_nullCheck_insideNullAssert(x) {
+  switch (x) {
+    case (_?)!:
+      break;
+    default:
+      Expect.fail('failed to match');
+  }
+}
+
+test_nullCheck_insideNullCheck(x) {
+  switch (x) {
+    case (_?)?:
+      break;
+    default:
+      Expect.fail('failed to match');
+  }
+}
+
+test_relational_insideNullCheck_equal(x) {
+  switch (x) {
+    case (== 1)?:
+      break;
+    default:
+      Expect.fail('failed to match');
+  }
+}
+
+test_relational_insideNullCheck_greaterThan(x) {
+  switch (x) {
+    case (> 1)?:
+      break;
+    default:
+      Expect.fail('failed to match');
+  }
+}
+
+main() {
+  test_cast_insideCast(0);
+  test_cast_insideNullAssert(0);
+  test_cast_insideNullCheck(0);
+  test_nullAssert_insideCast(0);
+  test_nullAssert_insideNullAssert(0);
+  test_nullAssert_insideNullCheck(0);
+  test_nullCheck_insideCast(0);
+  test_nullCheck_insideNullAssert(0);
+  test_nullCheck_insideNullCheck(0);
+  test_relational_insideNullCheck_equal(1);
+  test_relational_insideNullCheck_greaterThan(2);
+}