Update parser to support simple if/else control flow in literal lists, sets, and maps

Change-Id: I740beea833ed1ad76582ad5232549bd204981808
Reviewed-on: https://dart-review.googlesource.com/c/90901
Commit-Queue: Dan Rubel <danrubel@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
index 88972ed..a6c75c5 100644
--- a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
@@ -1230,7 +1230,6 @@
     assertHasRegion(HighlightRegionType.KEYWORD, 'if');
   }
 
-  @failingTest
   test_KEYWORD_if_map() async {
     addTestFile('''
 f(a, b) {
@@ -1241,7 +1240,6 @@
     assertHasRegion(HighlightRegionType.KEYWORD, 'if');
   }
 
-  @failingTest
   test_KEYWORD_if_set() async {
     addTestFile('''
 f(a, b) {
@@ -1252,7 +1250,6 @@
     assertHasRegion(HighlightRegionType.KEYWORD, 'if');
   }
 
-  @failingTest
   test_KEYWORD_ifElse_list() async {
     addTestFile('''
 f(a, b) {
@@ -1264,7 +1261,6 @@
     assertHasRegion(HighlightRegionType.KEYWORD, 'else');
   }
 
-  @failingTest
   test_KEYWORD_ifElse_map() async {
     addTestFile('''
 f(a, b) {
@@ -1276,7 +1272,6 @@
     assertHasRegion(HighlightRegionType.KEYWORD, 'else');
   }
 
-  @failingTest
   test_KEYWORD_ifElse_set() async {
     addTestFile('''
 f(a, b) {
diff --git a/pkg/analysis_server/test/analysis/notification_highlights_test.dart b/pkg/analysis_server/test/analysis/notification_highlights_test.dart
index 7d0fba2..9e1b109 100644
--- a/pkg/analysis_server/test/analysis/notification_highlights_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_highlights_test.dart
@@ -1079,7 +1079,6 @@
     assertHasRegion(HighlightRegionType.KEYWORD, 'if');
   }
 
-  @failingTest
   test_KEYWORD_if_map() async {
     addTestFile('''
 f(a, b) {
@@ -1090,7 +1089,6 @@
     assertHasRegion(HighlightRegionType.KEYWORD, 'if');
   }
 
-  @failingTest
   test_KEYWORD_if_set() async {
     addTestFile('''
 f(a, b) {
@@ -1101,7 +1099,6 @@
     assertHasRegion(HighlightRegionType.KEYWORD, 'if');
   }
 
-  @failingTest
   test_KEYWORD_ifElse_list() async {
     addTestFile('''
 f(a, b) {
@@ -1113,7 +1110,6 @@
     assertHasRegion(HighlightRegionType.KEYWORD, 'else');
   }
 
-  @failingTest
   test_KEYWORD_ifElse_map() async {
     addTestFile('''
 f(a, b) {
@@ -1125,7 +1121,6 @@
     assertHasRegion(HighlightRegionType.KEYWORD, 'else');
   }
 
-  @failingTest
   test_KEYWORD_ifElse_set() async {
     addTestFile('''
 f(a, b) {
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index d2e66e4..31b8756 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -282,19 +282,40 @@
   }
 
   @override
+  void handleElseControlFlow(Token elseToken) {
+    push(elseToken);
+  }
+
+  @override
   void endIfControlFlow(Token token) {
-    CollectionElement thenElement = pop();
+    var thenElement = pop();
     ParenthesizedExpression condition = pop();
     Token ifToken = pop();
+    pushIfControlFlowInfo(ifToken, condition, thenElement, null, null);
+  }
+
+  @override
+  void endIfElseControlFlow(Token token) {
+    var elseElement = pop();
+    Token elseToken = pop();
+    var thenElement = pop();
+    ParenthesizedExpression condition = pop();
+    Token ifToken = pop();
+    pushIfControlFlowInfo(
+        ifToken, condition, thenElement, elseToken, elseElement);
+  }
+
+  void pushIfControlFlowInfo(Token ifToken, ParenthesizedExpression condition,
+      var thenElement, Token elseToken, var elseElement) {
     if (enableControlFlowCollections) {
-      push(ast.collectionIfElement(
-          ifKeyword: ifToken,
-          leftParenthesis: condition.leftParenthesis,
-          condition: condition.expression,
-          rightParenthesis: condition.rightParenthesis,
-          thenElement: thenElement,
-          elseKeyword: null,
-          elseElement: null));
+      push(new _ControlFlowInfo(
+          ifToken,
+          condition.leftParenthesis,
+          condition.expression,
+          condition.rightParenthesis,
+          thenElement,
+          elseToken,
+          elseElement));
     } else {
       handleRecoverableError(
           templateUnexpectedToken.withArguments(ifToken), ifToken, ifToken);
@@ -894,7 +915,13 @@
     debugEvent("LiteralList");
 
     if (enableControlFlowCollections || enableSpreadCollections) {
-      List<CollectionElement> elements = popTypedList(count);
+      List<CollectionElement> elements = <CollectionElement>[];
+      popTypedList(count)?.forEach((element) {
+        elements.add(element is _EntryInfo
+            ? element.asCollectionElement(ast)
+            : element as CollectionElement);
+      });
+
       TypeArgumentList typeArguments = pop();
       push(ast.listLiteral2(
         constKeyword: constKeyword,
@@ -968,8 +995,13 @@
     debugEvent("LiteralSet");
 
     if (enableControlFlowCollections || enableSpreadCollections) {
-      List<CollectionElement> elements =
-          popTypedList(count) ?? <CollectionElement>[];
+      List<CollectionElement> elements = <CollectionElement>[];
+      popTypedList(count)?.forEach((element) {
+        elements.add(element is _EntryInfo
+            ? element.asCollectionElement(ast)
+            : element as CollectionElement);
+      });
+
       TypeArgumentList typeArguments = pop();
       push(ast.setLiteral2(
         constKeyword: constKeyword,
@@ -996,9 +1028,9 @@
     if (enableControlFlowCollections || enableSpreadCollections) {
       List<MapElement> entries = <MapElement>[];
       popTypedList(count)?.forEach((entry) {
-        if (entry is MapElement) {
-          entries.add(entry);
-        }
+        entries.add(entry is _EntryInfo
+            ? entry.asMapElement(ast)
+            : entry as MapElement);
       });
 
       TypeArgumentList typeArguments = pop();
@@ -3122,3 +3154,58 @@
 
   _ConstructorNameWithInvalidTypeArgs(this.name, this.invalidTypeArgs);
 }
+
+abstract class _EntryInfo {
+  CollectionElement asCollectionElement(AstFactory ast);
+  MapElement asMapElement(AstFactory ast);
+}
+
+class _ControlFlowInfo implements _EntryInfo {
+  final Token ifToken;
+  final Token leftParenthesis;
+  final Expression conditionExpression;
+  final Token rightParenthesis;
+  final thenElement;
+  final Token elseToken;
+  final elseElement;
+
+  _ControlFlowInfo(
+      this.ifToken,
+      this.leftParenthesis,
+      this.conditionExpression,
+      this.rightParenthesis,
+      this.thenElement,
+      this.elseToken,
+      this.elseElement);
+
+  @override
+  CollectionElement asCollectionElement(AstFactory ast) =>
+      ast.collectionIfElement(
+        ifKeyword: ifToken,
+        leftParenthesis: leftParenthesis,
+        condition: conditionExpression,
+        rightParenthesis: rightParenthesis,
+        thenElement: thenElement is _EntryInfo
+            ? thenElement.asCollectionElement(ast)
+            : thenElement as CollectionElement,
+        elseKeyword: elseToken,
+        elseElement: elseElement is _EntryInfo
+            ? elseElement.asCollectionElement(ast)
+            : elseElement as CollectionElement,
+      );
+
+  @override
+  MapElement asMapElement(AstFactory ast) => ast.mapIfElement(
+        ifKeyword: ifToken,
+        leftParenthesis: leftParenthesis,
+        condition: conditionExpression,
+        rightParenthesis: rightParenthesis,
+        thenElement: thenElement is _EntryInfo
+            ? thenElement.asMapElement(ast)
+            : thenElement as MapElement,
+        elseKeyword: elseToken,
+        elseElement: elseElement is _EntryInfo
+            ? elseElement.asMapElement(ast)
+            : elseElement as MapElement,
+      );
+}
diff --git a/pkg/analyzer/test/generated/parser_fasta_listener.dart b/pkg/analyzer/test/generated/parser_fasta_listener.dart
index c558376..5a2a061 100644
--- a/pkg/analyzer/test/generated/parser_fasta_listener.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_listener.dart
@@ -801,6 +801,12 @@
   }
 
   @override
+  void endIfElseControlFlow(Token token) {
+    end('IfControlFlow');
+    super.endIfElseControlFlow(token);
+  }
+
+  @override
   void endIfStatement(Token ifToken, Token elseToken) {
     end('IfStatement');
     super.endIfStatement(ifToken, elseToken);
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index 5829f98..1c07949 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -151,6 +151,22 @@
     expect(condition.value, isTrue);
     IntegerLiteral thenElement = second.thenElement;
     expect(thenElement.value, 2);
+    expect(second.elseElement, isNull);
+  }
+
+  void test_listLiteral_ifElse() {
+    ListLiteral2 list = parseCollectionLiteral('[1, if (true) 2 else 5]');
+    expect(list.elements, hasLength(2));
+    IntegerLiteral first = list.elements[0];
+    expect(first.value, 1);
+
+    CollectionIfElement second = list.elements[1];
+    BooleanLiteral condition = second.condition;
+    expect(condition.value, isTrue);
+    IntegerLiteral thenElement = second.thenElement;
+    expect(thenElement.value, 2);
+    IntegerLiteral elseElement = second.elseElement;
+    expect(elseElement.value, 5);
   }
 
   void test_listLiteral_ifSpread() {
@@ -164,6 +180,23 @@
     expect(condition.value, isTrue);
     SpreadElement thenElement = second.thenElement;
     expect(thenElement.spreadOperator.lexeme, '...');
+    expect(second.elseElement, isNull);
+  }
+
+  void test_listLiteral_ifElseSpread() {
+    ListLiteral2 list =
+        parseCollectionLiteral('[1, if (true) ...[2] else ...?[5]]');
+    expect(list.elements, hasLength(2));
+    IntegerLiteral first = list.elements[0];
+    expect(first.value, 1);
+
+    CollectionIfElement second = list.elements[1];
+    BooleanLiteral condition = second.condition;
+    expect(condition.value, isTrue);
+    SpreadElement thenElement = second.thenElement;
+    expect(thenElement.spreadOperator.lexeme, '...');
+    SpreadElement elseElement = second.elseElement;
+    expect(elseElement.spreadOperator.lexeme, '...?');
   }
 
   void test_listLiteral_spread() {
@@ -190,6 +223,77 @@
     expect(spreadExpression.elements, hasLength(1));
   }
 
+  void test_mapLiteral_if() {
+    MapLiteral2 map = parseCollectionLiteral('{1:1, if (true) 2:4}');
+    expect(map.entries, hasLength(2));
+    MapLiteralEntry first = map.entries[0];
+    IntegerLiteral firstValue = first.value;
+    expect(firstValue.value, 1);
+
+    MapIfElement second = map.entries[1];
+    BooleanLiteral condition = second.condition;
+    expect(condition.value, isTrue);
+    MapLiteralEntry thenElement = second.thenElement;
+    IntegerLiteral thenElementValue = thenElement.value;
+    expect(thenElementValue.value, 4);
+    expect(second.elseElement, isNull);
+  }
+
+  void test_mapLiteral_ifElse() {
+    MapLiteral2 map = parseCollectionLiteral('{1:1, if (true) 2:4 else 5:6}');
+    expect(map.entries, hasLength(2));
+    MapLiteralEntry first = map.entries[0];
+    IntegerLiteral firstValue = first.value;
+    expect(firstValue.value, 1);
+
+    MapIfElement second = map.entries[1];
+    BooleanLiteral condition = second.condition;
+    expect(condition.value, isTrue);
+    MapLiteralEntry thenElement = second.thenElement;
+    IntegerLiteral thenElementValue = thenElement.value;
+    expect(thenElementValue.value, 4);
+    MapLiteralEntry elseElement = second.elseElement;
+    IntegerLiteral elseElementValue = elseElement.value;
+    expect(elseElementValue.value, 6);
+  }
+
+  void test_mapLiteral_ifSpread() {
+    MapLiteral2 map = parseCollectionLiteral('{1:1, if (true) ...{2:4}}');
+    expect(map.entries, hasLength(2));
+    MapLiteralEntry first = map.entries[0];
+    IntegerLiteral firstValue = first.value;
+    expect(firstValue.value, 1);
+
+    MapIfElement second = map.entries[1];
+    BooleanLiteral condition = second.condition;
+    expect(condition.value, isTrue);
+    SpreadElement thenElement = second.thenElement;
+    expect(thenElement.spreadOperator.lexeme, '...');
+    expect(second.elseElement, isNull);
+  }
+
+  void test_mapLiteral_ifElseSpread() {
+    MapLiteral2 map =
+        parseCollectionLiteral('{1:7, if (true) ...{2:4} else ...?{5:6}}');
+    expect(map.entries, hasLength(2));
+    MapLiteralEntry first = map.entries[0];
+    IntegerLiteral firstValue = first.value;
+    expect(firstValue.value, 7);
+
+    MapIfElement second = map.entries[1];
+    BooleanLiteral condition = second.condition;
+    expect(condition.value, isTrue);
+    SpreadElement thenElement = second.thenElement;
+    expect(thenElement.spreadOperator.lexeme, '...');
+    SpreadElement elseElement = second.elseElement;
+    expect(elseElement.spreadOperator.lexeme, '...?');
+    MapLiteral2 elseElementExpression = elseElement.expression;
+    expect(elseElementExpression.entries, hasLength(1));
+    MapLiteralEntry entry = elseElementExpression.entries[0];
+    IntegerLiteral entryValue = entry.value;
+    expect(entryValue.value, 6);
+  }
+
   void test_mapLiteral_spread() {
     MapLiteral2 map = parseCollectionLiteral('{1: 2, ...{3: 4}}');
     expect(map.constKeyword, isNull);
@@ -262,6 +366,69 @@
     expect(spreadExpression.entries, hasLength(1));
   }
 
+  void test_setLiteral_if() {
+    SetLiteral2 setLiteral = parseCollectionLiteral('{1, if (true) 2}');
+    expect(setLiteral.elements, hasLength(2));
+    IntegerLiteral first = setLiteral.elements[0];
+    expect(first.value, 1);
+
+    CollectionIfElement second = setLiteral.elements[1];
+    BooleanLiteral condition = second.condition;
+    expect(condition.value, isTrue);
+    IntegerLiteral thenElement = second.thenElement;
+    expect(thenElement.value, 2);
+    expect(second.elseElement, isNull);
+  }
+
+  void test_setLiteral_ifElse() {
+    SetLiteral2 setLiteral = parseCollectionLiteral('{1, if (true) 2 else 5}');
+    expect(setLiteral.elements, hasLength(2));
+    IntegerLiteral first = setLiteral.elements[0];
+    expect(first.value, 1);
+
+    CollectionIfElement second = setLiteral.elements[1];
+    BooleanLiteral condition = second.condition;
+    expect(condition.value, isTrue);
+    IntegerLiteral thenElement = second.thenElement;
+    expect(thenElement.value, 2);
+    IntegerLiteral elseElement = second.elseElement;
+    expect(elseElement.value, 5);
+  }
+
+  void test_setLiteral_ifSpread() {
+    SetLiteral2 setLiteral = parseCollectionLiteral('{1, if (true) ...[2]}');
+    expect(setLiteral.elements, hasLength(2));
+    IntegerLiteral first = setLiteral.elements[0];
+    expect(first.value, 1);
+
+    CollectionIfElement second = setLiteral.elements[1];
+    BooleanLiteral condition = second.condition;
+    expect(condition.value, isTrue);
+    SpreadElement thenElement = second.thenElement;
+    expect(thenElement.spreadOperator.lexeme, '...');
+    expect(second.elseElement, isNull);
+  }
+
+  void test_setLiteral_ifElseSpread() {
+    SetLiteral2 setLiteral =
+        parseCollectionLiteral('{1, if (true) ...{2} else ...?[5]}');
+    expect(setLiteral.elements, hasLength(2));
+    IntegerLiteral first = setLiteral.elements[0];
+    expect(first.value, 1);
+
+    CollectionIfElement second = setLiteral.elements[1];
+    BooleanLiteral condition = second.condition;
+    expect(condition.value, isTrue);
+    SpreadElement thenElement = second.thenElement;
+    expect(thenElement.spreadOperator.lexeme, '...');
+    SetLiteral2 theExpression = thenElement.expression;
+    expect(theExpression.elements, hasLength(1));
+    SpreadElement elseElement = second.elseElement;
+    expect(elseElement.spreadOperator.lexeme, '...?');
+    ListLiteral2 elseExpression = elseElement.expression;
+    expect(elseExpression.elements, hasLength(1));
+  }
+
   void test_setLiteral_spread2() {
     SetLiteral2 set = parseCollectionLiteral('{3, ...[4]}');
     expect(set.constKeyword, isNull);
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 21f1eff..ace876e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -3528,6 +3528,19 @@
   }
 
   @override
+  void endIfElseControlFlow(Token token) {
+    debugEvent("IfElseControlFlow");
+    // TODO(danrubel) implement control flow support
+    pop(); // else entry
+    var entry = pop(); // then entry
+    pop(); // parenthesized expression
+    Token ifToken = pop();
+    push(entry); // push the entry back on the stack and drop the rest
+    handleRecoverableError(
+        fasta.templateUnexpectedToken.withArguments(ifToken), ifToken, ifToken);
+  }
+
+  @override
   void handleSpreadExpression(Token spreadToken) {
     debugEvent("SpreadExpression");
     // TODO(danrubel) implement spread expression support
diff --git a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
index 3292dd8..b909283 100644
--- a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
+++ b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
@@ -646,6 +646,11 @@
   }
 
   @override
+  void endIfElseControlFlow(Token token) {
+    listener?.endIfElseControlFlow(token);
+  }
+
+  @override
   void endIfStatement(Token ifToken, Token elseToken) {
     listener?.endIfStatement(ifToken, elseToken);
   }
@@ -981,6 +986,11 @@
   }
 
   @override
+  void handleElseControlFlow(Token elseToken) {
+    listener?.handleElseControlFlow(elseToken);
+  }
+
+  @override
   void handleEmptyStatement(Token token) {
     listener?.handleEmptyStatement(token);
   }
diff --git a/pkg/front_end/lib/src/fasta/parser/listener.dart b/pkg/front_end/lib/src/fasta/parser/listener.dart
index 101e349..0345607 100644
--- a/pkg/front_end/lib/src/fasta/parser/listener.dart
+++ b/pkg/front_end/lib/src/fasta/parser/listener.dart
@@ -1077,6 +1077,10 @@
   /// Called before parsing an `if` control flow list, set, or map entry.
   void beginIfControlFlow(Token ifToken) {}
 
+  /// Called before parsing the `else` portion of an `if` control flow list,
+  /// set, or map entry.
+  void handleElseControlFlow(Token elseToken) {}
+
   /// Called after parsing an `if` control flow list, set, or map entry.
   /// Substructures:
   /// - if conditional expression
@@ -1085,6 +1089,15 @@
     logEvent("IfControlFlow");
   }
 
+  /// Called after parsing an if-else control flow list, set, or map entry.
+  /// Substructures:
+  /// - if conditional expression
+  /// - then expression
+  /// - else expression
+  void endIfElseControlFlow(Token token) {
+    logEvent("IfElseControlFlow");
+  }
+
   /// Called after parsing a list, set, or map entry that starts with
   /// one of the spread collection tokens `...` or `...?`.  Substructures:
   /// - expression
diff --git a/pkg/front_end/lib/src/fasta/parser/literal_entry_info_impl.dart b/pkg/front_end/lib/src/fasta/parser/literal_entry_info_impl.dart
index b9bc2a4..5f200e9 100644
--- a/pkg/front_end/lib/src/fasta/parser/literal_entry_info_impl.dart
+++ b/pkg/front_end/lib/src/fasta/parser/literal_entry_info_impl.dart
@@ -70,7 +70,9 @@
 
   @override
   LiteralEntryInfo computeNext(Token token) {
-    // TODO(danrubel): handle `else'
+    if (optional('else', token.next)) {
+      return const IfElse();
+    }
     return const IfComplete();
   }
 }
@@ -82,11 +84,55 @@
 
   @override
   LiteralEntryInfo computeNext(Token token) {
-    // TODO(danrubel): handle `else'
+    if (optional('else', token.next)) {
+      return const IfElse();
+    }
     return const IfComplete();
   }
 }
 
+/// A step for parsing the `else` portion of an `if` control flow.
+class IfElse extends LiteralEntryInfo {
+  const IfElse() : super(false);
+
+  @override
+  Token parse(Token token, Parser parser) {
+    Token elseToken = token.next;
+    assert(optional('else', elseToken));
+    parser.listener.handleElseControlFlow(elseToken);
+    return elseToken;
+  }
+
+  @override
+  LiteralEntryInfo computeNext(Token token) {
+    assert(optional('else', token));
+    Token next = token.next;
+    if (optional('...', next) || optional('...?', next)) {
+      return const ElseSpread();
+    }
+    // TODO(danrubel): nested control flow structures
+    return const ElseEntry();
+  }
+}
+
+class ElseSpread extends SpreadOperator {
+  const ElseSpread();
+
+  @override
+  LiteralEntryInfo computeNext(Token token) {
+    return const IfElseComplete();
+  }
+}
+
+class ElseEntry extends LiteralEntryInfo {
+  const ElseEntry() : super(true);
+
+  @override
+  LiteralEntryInfo computeNext(Token token) {
+    return const IfElseComplete();
+  }
+}
+
 class IfComplete extends LiteralEntryInfo {
   const IfComplete() : super(false);
 
@@ -97,6 +143,16 @@
   }
 }
 
+class IfElseComplete extends LiteralEntryInfo {
+  const IfElseComplete() : super(false);
+
+  @override
+  Token parse(Token token, Parser parser) {
+    parser.listener.endIfElseControlFlow(token);
+    return token;
+  }
+}
+
 /// The first step when processing a spread entry.
 class SpreadOperator extends LiteralEntryInfo {
   const SpreadOperator() : super(false);
diff --git a/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart b/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart
index b87ff91..f300037 100644
--- a/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart
@@ -383,6 +383,12 @@
   }
 
   @override
+  void endIfElseControlFlow(Token token) {
+    // TODO(danrubel) add support for if control flow collection entries
+    // but for now this is ignored and an error reported in the body builder.
+  }
+
+  @override
   void handleSpreadExpression(Token spreadToken) {
     // TODO(danrubel) add support for spread collections
     // but for now this is ignored and an error reported in the body builder.
diff --git a/pkg/front_end/test/fasta/parser/literal_entry_info_test.dart b/pkg/front_end/test/fasta/parser/literal_entry_info_test.dart
index a087fe3..380347f 100644
--- a/pkg/front_end/test/fasta/parser/literal_entry_info_test.dart
+++ b/pkg/front_end/test/fasta/parser/literal_entry_info_test.dart
@@ -71,6 +71,21 @@
     );
   }
 
+  test_ifElse() {
+    parseEntry(
+      'before if (true) 2 else 5',
+      [
+        'beginIfControlFlow if',
+        'handleLiteralBool true',
+        'handleParenthesizedCondition (',
+        'handleLiteralInt 2',
+        'handleElseControlFlow else',
+        'handleLiteralInt 5',
+        'endIfElseControlFlow 5',
+      ],
+    );
+  }
+
   test_ifSpreadQ() {
     parseEntry(
       'before if (true) ...?[2]',
@@ -87,6 +102,29 @@
     );
   }
 
+  test_ifElseSpreadQ() {
+    parseEntry(
+      'before if (true) ...?[2] else ... const {5}',
+      [
+        'beginIfControlFlow if',
+        'handleLiteralBool true',
+        'handleParenthesizedCondition (',
+        'handleNoTypeArguments [',
+        'handleLiteralInt 2',
+        'handleLiteralList 1, [, null, ]',
+        'handleSpreadExpression ...?',
+        'handleElseControlFlow else',
+        'beginConstLiteral {',
+        'handleNoTypeArguments {',
+        'handleLiteralInt 5',
+        'handleLiteralSet 1, {, const, }',
+        'endConstLiteral ',
+        'handleSpreadExpression ...',
+        'endIfElseControlFlow }',
+      ],
+    );
+  }
+
   test_intLiteral() {
     parseEntry('before 1', [
       'handleLiteralInt 1',
@@ -302,6 +340,16 @@
   }
 
   @override
+  void endIfElseControlFlow(Token token) {
+    calls.add('endIfElseControlFlow $token');
+  }
+
+  @override
+  void handleElseControlFlow(Token elseToken) {
+    calls.add('handleElseControlFlow $elseToken');
+  }
+
+  @override
   void handleIdentifier(Token token, IdentifierContext context) {
     calls.add('handleIdentifier $token $context');
   }
@@ -336,6 +384,12 @@
   }
 
   @override
+  void handleLiteralSet(
+      int count, Token beginToken, Token constKeyword, Token token) {
+    calls.add('handleLiteralSet $count, $beginToken, $constKeyword, $token');
+  }
+
+  @override
   void handleNoArguments(Token token) {
     calls.add('handleNoArguments $token');
   }