Add set literal spread collection parsing support

Change-Id: I12f4675a3a034a82acc16c4d189b001d52c23039
Reviewed-on: https://dart-review.googlesource.com/c/89681
Reviewed-by: Brian Wilkerson <brianwilkerson@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 44249b8..b4e158e 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -328,6 +328,58 @@
     expect(value2.value, 6);
   }
 
+  void test_setLiteral_spread_typed() {
+    // TODO(danrubel): Revise this once AST supports new syntax
+    SetLiteral set = parseExpression('<int>{...[3]}',
+        parseSetLiterals: true,
+        errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 6, 3)]);
+    expect(set.constKeyword, isNull);
+    expect(set.typeArguments, isNotNull);
+    expect(set.elements, hasLength(1));
+    ListLiteral list = set.elements[0];
+    expect(list.elements, hasLength(1));
+  }
+
+  void test_setLiteral_spreadQ_typed() {
+    // TODO(danrubel): Revise this once AST supports new syntax
+    SetLiteral set = parseExpression('<int>{...?[3]}',
+        parseSetLiterals: true,
+        errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 6, 4)]);
+    expect(set.constKeyword, isNull);
+    expect(set.typeArguments, isNotNull);
+    expect(set.elements, hasLength(1));
+    ListLiteral list = set.elements[0];
+    expect(list.elements, hasLength(1));
+  }
+
+  void test_setLiteral_spread2() {
+    // TODO(danrubel): Revise this once AST supports new syntax
+    SetLiteral set = parseExpression('{3, ...[4]}',
+        parseSetLiterals: true,
+        errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 4, 3)]);
+    expect(set.constKeyword, isNull);
+    expect(set.typeArguments, isNull);
+    expect(set.elements, hasLength(2));
+    IntegerLiteral value = set.elements[0];
+    expect(value.value, 3);
+    ListLiteral list = set.elements[1];
+    expect(list.elements, hasLength(1));
+  }
+
+  void test_setLiteral_spread2Q() {
+    // TODO(danrubel): Revise this once AST supports new syntax
+    SetLiteral set = parseExpression('{3, ...?[4]}',
+        parseSetLiterals: true,
+        errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 4, 4)]);
+    expect(set.constKeyword, isNull);
+    expect(set.typeArguments, isNull);
+    expect(set.elements, hasLength(2));
+    IntegerLiteral value = set.elements[0];
+    expect(value.value, 3);
+    ListLiteral list = set.elements[1];
+    expect(list.elements, hasLength(1));
+  }
+
   void test_setLiteral_const_typeArgument() {
     SetLiteral set = parseExpression('const <int>{3}', parseSetLiterals: true);
     expect(set.constKeyword, isNotNull);
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index 6ab177a..48e16d1 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -4186,12 +4186,7 @@
         token = next;
         break;
       }
-      if (optional('...', next) || optional('...?', next)) {
-        token = parseExpression(token.next);
-        listener.handleSpreadExpression(next);
-      } else {
-        token = parseExpression(token);
-      }
+      token = parseSpreadExpressionOrExpression(token);
       next = token.next;
       ++count;
       if (!optional(',', next)) {
@@ -4228,6 +4223,17 @@
     return token;
   }
 
+  Token parseSpreadExpressionOrExpression(Token token) {
+    Token next = token.next;
+    if (optional('...', next) || optional('...?', next)) {
+      token = parseExpression(token.next);
+      listener.handleSpreadExpression(next);
+    } else {
+      token = parseExpression(token);
+    }
+    return token;
+  }
+
   /// This method parses the portion of a set or map literal that starts with
   /// the left curly brace when there are no leading type arguments.
   Token parseLiteralSetOrMapSuffix(final Token start, Token constKeyword) {
@@ -4369,7 +4375,7 @@
 
     bool old = mayParseFunctionExpressions;
     mayParseFunctionExpressions = true;
-    token = parseExpression(token);
+    token = parseSpreadExpressionOrExpression(token);
     mayParseFunctionExpressions = old;
 
     return parseLiteralSetRest(token, constKeyword, beginToken);
@@ -4408,7 +4414,7 @@
           break;
         }
       }
-      token = parseExpression(token);
+      token = parseSpreadExpressionOrExpression(token);
       ++count;
     }
     assert(optional('}', token));