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);
+}