Fix parse expression "a ~ b"

This fixes an infinite loop that I introduced in the parser
on Wed Feb 27 commit 8f12d634fea19d42c363bef65cffd5582a3997ec
when adding support for the "!" NNBD postfix assert non-null operator.

To the best of my knowledge, this problem only manifests
when parsing the expression "a ~ b".

Fix https://github.com/dart-lang/sdk/issues/36255

Change-Id: If20f45620eee0f7cf9b4b6a93640bd3b921d23b9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97265
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index f5becf3..55ece47 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -907,6 +907,21 @@
 @reflectiveTest
 class ExpressionParserTest_Fasta extends FastaParserTestCase
     with ExpressionParserTestMixin {
+  void test_binaryExpression_allOperators() {
+    // https://github.com/dart-lang/sdk/issues/36255
+    for (TokenType type in TokenType.all) {
+      if (type.precedence > 0) {
+        var source = 'a ${type.lexeme} b';
+        try {
+          parseExpression(source);
+        } on TestFailure {
+          // Ensure that there are no infinite loops or exceptions thrown
+          // by the parser. Test failures are fine.
+        }
+      }
+    }
+  }
+
   void test_listLiteral_spread() {
     // TODO(danrubel): Remove this once spread_collections is enabled by default
     ListLiteral list = parseExpression('[1, ...[2]]', errors: [
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index 774daef..afe9a91 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -3824,13 +3824,12 @@
             listener.handleUnaryPostfixAssignmentExpression(token.next);
             token = next;
           }
-        } else if (identical(tokenLevel, PREFIX_PRECEDENCE)) {
+        } else if (identical(tokenLevel, PREFIX_PRECEDENCE) &&
+            (identical(type, TokenType.BANG))) {
           // The '!' has prefix precedence but here it's being used as a
           // postfix operator to assert the expression has a non-null value.
-          if ((identical(type, TokenType.BANG))) {
-            listener.handleNonNullAssertExpression(token.next);
-            token = next;
-          }
+          listener.handleNonNullAssertExpression(token.next);
+          token = next;
         } else if (identical(tokenLevel, SELECTOR_PRECEDENCE)) {
           if (identical(type, TokenType.PERIOD) ||
               identical(type, TokenType.QUESTION_PERIOD)) {