Flow analysis: Use blocks internally in mini_ast representation.

For convenience in creating tests, the public mini_ast methods for
creating constructs like loops, try/catch, etc. accept lists of
statements as an argument where technically the language would expect
a single statement.  This CL changes the internal representation so
that each of these statement lists is converted into a single
statement by wrapping it in a block.

This makes the mini_ast representation more closely match the
representation used internally by the analyzer and CFE.

Change-Id: If2bf8a1cde694206b91b57c5907806b1965d4d99
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/193880
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
index 77f2cf0..9e1ca0a 100644
--- a/pkg/_fe_analyzer_shared/test/mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -37,7 +37,7 @@
     new _Break(branchTargetPlaceholder);
 
 SwitchCase case_(List<Statement> body, {bool hasLabel = false}) =>
-    SwitchCase._(hasLabel, body);
+    SwitchCase._(hasLabel, new _Block(body));
 
 /// Creates a pseudo-statement whose function is to verify that flow analysis
 /// considers [variable]'s assigned state to be [expectedAssignedState].
@@ -79,7 +79,7 @@
     new _Declare(variable, initializer, isFinal, isLate);
 
 Statement do_(List<Statement> body, Expression condition) =>
-    _Do(body, condition);
+    _Do(block(body), condition);
 
 /// Creates a pseudo-expression having type [typeStr] that otherwise has no
 /// effect on flow analysis.
@@ -92,7 +92,7 @@
 Statement for_(Statement? initializer, Expression? condition,
         Expression? updater, List<Statement> body,
         {bool forCollection = false}) =>
-    new _For(initializer, condition, updater, body, forCollection);
+    new _For(initializer, condition, updater, block(body), forCollection);
 
 /// Creates a "for each" statement where the identifier being assigned to by the
 /// iteration is not a local variable.
@@ -103,7 +103,7 @@
 ///       for (x in iterable) { ... }
 ///     }
 Statement forEachWithNonVariable(Expression iterable, List<Statement> body) =>
-    new _ForEach(null, iterable, body, false);
+    new _ForEach(null, iterable, block(body), false);
 
 /// Creates a "for each" statement where the identifier being assigned to by the
 /// iteration is a variable that is being declared by the "for each" statement.
@@ -116,7 +116,7 @@
     Var variable, Expression iterable, List<Statement> body) {
   // ignore: unnecessary_null_comparison
   assert(variable != null);
-  return new _ForEach(variable, iterable, body, true);
+  return new _ForEach(variable, iterable, block(body), true);
 }
 
 /// Creates a "for each" statement where the identifier being assigned to by the
@@ -131,7 +131,7 @@
     Var variable, Expression iterable, List<Statement> body) {
   // ignore: unnecessary_null_comparison
   assert(variable != null);
-  return new _ForEach(variable, iterable, body, false);
+  return new _ForEach(variable, iterable, block(body), false);
 }
 
 /// Creates a [Statement] that, when analyzed, will cause [callback] to be
@@ -142,7 +142,7 @@
 
 Statement if_(Expression condition, List<Statement> ifTrue,
         [List<Statement>? ifFalse]) =>
-    new _If(condition, ifTrue, ifFalse);
+    new _If(condition, block(ifTrue), ifFalse == null ? null : block(ifFalse));
 
 Statement implicitThis_whyNotPromoted(String staticType,
         void Function(Map<Type, NonPromotionReason>) callback) =>
@@ -150,7 +150,7 @@
 
 Statement labeled(Statement body) => new _LabeledStatement(body);
 
-Statement localFunction(List<Statement> body) => _LocalFunction(body);
+Statement localFunction(List<Statement> body) => _LocalFunction(block(body));
 
 Statement return_() => new _Return();
 
@@ -163,10 +163,11 @@
 
 Expression throw_(Expression operand) => new _Throw(operand);
 
-TryBuilder try_(List<Statement> body) => new _TryStatement(body, [], null);
+TryBuilder try_(List<Statement> body) =>
+    new _TryStatement(block(body), [], null);
 
 Statement while_(Expression condition, List<Statement> body) =>
-    new _While(condition, body);
+    new _While(condition, block(body));
 
 /// Placeholder used by [branchTarget] to tie `break` and `continue` statements
 /// to their branch targets.
@@ -481,13 +482,14 @@
   /// they contain.
   void run(List<Statement> statements) {
     var assignedVariables = AssignedVariables<Node, Var>();
-    statements._preVisit(assignedVariables);
+    var b = block(statements);
+    b._preVisit(assignedVariables);
     var flow = legacy
         ? FlowAnalysis<Node, Statement, Expression, Var, Type>.legacy(
             this, assignedVariables)
         : FlowAnalysis<Node, Statement, Expression, Var, Type>(
             this, assignedVariables);
-    statements._visit(this, flow);
+    b._visit(this, flow);
     flow.finish();
   }
 
@@ -601,12 +603,15 @@
 /// to create instances of this class.
 class SwitchCase implements _Visitable<void> {
   final bool _hasLabel;
-  final List<Statement> _body;
+  final _Block _body;
 
   SwitchCase._(this._hasLabel, this._body);
 
-  String toString() =>
-      [if (_hasLabel) '<label>:', 'case <value>:', ..._body].join(' ');
+  String toString() => [
+        if (_hasLabel) '<label>:',
+        'case <value>:',
+        ..._body.statements
+      ].join(' ');
 
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
     _body._preVisit(assignedVariables);
@@ -713,13 +718,17 @@
 
   @override
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
-    statements._preVisit(assignedVariables);
+    for (var statement in statements) {
+      statement._preVisit(assignedVariables);
+    }
   }
 
   @override
   void _visit(
       Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    statements._visit(h, flow);
+    for (var statement in statements) {
+      statement._visit(h, flow);
+    }
   }
 }
 
@@ -765,7 +774,7 @@
 /// Representation of a single catch clause in a try/catch statement.  Use
 /// [catch_] to create instances of this class.
 class _CatchClause implements _Visitable<void> {
-  final List<Statement> _body;
+  final Statement _body;
   final Var? _exception;
   final Var? _stackTrace;
 
@@ -780,7 +789,7 @@
     } else {
       initialPart = 'on ...';
     }
-    return '$initialPart ${block(_body)}';
+    return '$initialPart $_body';
   }
 
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
@@ -973,13 +982,13 @@
 }
 
 class _Do extends Statement {
-  final List<Statement> body;
+  final Statement body;
   final Expression condition;
 
   _Do(this.body, this.condition) : super._();
 
   @override
-  String toString() => 'do ${block(body)} while ($condition);';
+  String toString() => 'do $body while ($condition);';
 
   @override
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
@@ -1051,7 +1060,7 @@
   final Statement? initializer;
   final Expression? condition;
   final Expression? updater;
-  final List<Statement> body;
+  final Statement body;
   final bool forCollection;
 
   _For(this.initializer, this.condition, this.updater, this.body,
@@ -1074,7 +1083,7 @@
     if (updater != null) {
       buffer.write(' $updater');
     }
-    buffer.write(') ${block(body)}');
+    buffer.write(') $body');
     return buffer.toString();
   }
 
@@ -1105,7 +1114,7 @@
 class _ForEach extends Statement {
   final Var? variable;
   final Expression iterable;
-  final List<Statement> body;
+  final Statement body;
   final bool declaresVariable;
 
   _ForEach(this.variable, this.iterable, this.body, this.declaresVariable)
@@ -1121,7 +1130,7 @@
     } else {
       declarationPart = variable!.name;
     }
-    return 'for ($declarationPart in $iterable) ${block(body)}';
+    return 'for ($declarationPart in $iterable) $body';
   }
 
   @override
@@ -1192,15 +1201,14 @@
 
 class _If extends Statement {
   final Expression condition;
-  final List<Statement> ifTrue;
-  final List<Statement>? ifFalse;
+  final Statement ifTrue;
+  final Statement? ifFalse;
 
   _If(this.condition, this.ifTrue, this.ifFalse) : super._();
 
   @override
   String toString() =>
-      'if ($condition) ${block(ifTrue)}' +
-      (ifFalse == null ? '' : 'else ${block(ifFalse!)}');
+      'if ($condition) $ifTrue' + (ifFalse == null ? '' : 'else $ifFalse');
 
   @override
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
@@ -1299,12 +1307,12 @@
 }
 
 class _LocalFunction extends Statement {
-  final List<Statement> body;
+  final Statement body;
 
   _LocalFunction(this.body) : super._();
 
   @override
-  String toString() => '() ${block(body)}';
+  String toString() => '() $body';
 
   @override
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
@@ -1561,7 +1569,9 @@
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
     expression._preVisit(assignedVariables);
     assignedVariables.beginNode();
-    cases._preVisit(assignedVariables);
+    for (var case_ in cases) {
+      case_._preVisit(assignedVariables);
+    }
     assignedVariables.endNode(this);
   }
 
@@ -1572,7 +1582,9 @@
     flow.switchStatement_expressionEnd(this);
     var oldSwitch = h._currentSwitch;
     h._currentSwitch = this;
-    cases._visit(h, flow);
+    for (var case_ in cases) {
+      case_._visit(h, flow);
+    }
     h._currentSwitch = oldSwitch;
     flow.switchStatement_end(isExhaustive);
   }
@@ -1635,9 +1647,9 @@
 }
 
 class _TryStatement extends TryStatement {
-  final List<Statement> _body;
+  final Statement _body;
   final List<_CatchClause> _catches;
-  final List<Statement>? _finally;
+  final Statement? _finally;
   final _bodyNode = Node._();
 
   _TryStatement(this._body, this._catches, this._finally) : super._();
@@ -1646,14 +1658,14 @@
   TryStatement catch_(
       {Var? exception, Var? stackTrace, required List<Statement> body}) {
     assert(_finally == null, 'catch after finally');
-    return _TryStatement(
-        _body, [..._catches, _CatchClause(body, exception, stackTrace)], null);
+    return _TryStatement(_body,
+        [..._catches, _CatchClause(block(body), exception, stackTrace)], null);
   }
 
   @override
   Statement finally_(List<Statement> statements) {
     assert(_finally == null, 'multiple finally clauses');
-    return _TryStatement(_body, _catches, statements);
+    return _TryStatement(_body, _catches, block(statements));
   }
 
   @override
@@ -1666,7 +1678,9 @@
     }
     _body._preVisit(assignedVariables);
     assignedVariables.endNode(_bodyNode);
-    _catches._preVisit(assignedVariables);
+    for (var catch_ in _catches) {
+      catch_._preVisit(assignedVariables);
+    }
     if (_finally != null) {
       if (_catches.isNotEmpty) {
         assignedVariables.endNode(this);
@@ -1687,7 +1701,9 @@
     _body._visit(h, flow);
     if (_catches.isNotEmpty) {
       flow.tryCatchStatement_bodyEnd(_bodyNode);
-      _catches._visit(h, flow);
+      for (var catch_ in _catches) {
+        catch_._visit(h, flow);
+      }
       flow.tryCatchStatement_end();
     }
     if (_finally != null) {
@@ -1744,12 +1760,12 @@
 
 class _While extends Statement {
   final Expression condition;
-  final List<Statement> body;
+  final Statement body;
 
   _While(this.condition, this.body) : super._();
 
   @override
-  String toString() => 'while ($condition) ${block(body)}';
+  String toString() => 'while ($condition) $body';
 
   @override
   void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
@@ -1892,18 +1908,3 @@
     return type;
   }
 }
-
-extension on List<_Visitable<void>> {
-  void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
-    for (var element in this) {
-      element._preVisit(assignedVariables);
-    }
-  }
-
-  void _visit(
-      Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
-    for (var element in this) {
-      element._visit(h, flow);
-    }
-  }
-}