Better performance on long lists containing comments.

Fix #484.

R=tjblasi@google.com

Review URL: https://codereview.chromium.org//1595553004 .
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3e419b4..f0b9659 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 0.2.4
+
+* Better handling for long collections with comments (#484).
+
 # 0.2.3
 
 * Support messages in assert() (#411).
diff --git a/bin/format.dart b/bin/format.dart
index 84794dd..705f3af 100644
--- a/bin/format.dart
+++ b/bin/format.dart
@@ -14,7 +14,7 @@
 import 'package:dart_style/src/source_code.dart';
 
 // Note: The following line of code is modified by tool/grind.dart.
-const version = "0.2.3";
+const version = "0.2.4";
 
 void main(List<String> args) {
   var parser = new ArgParser(allowTrailingOptions: true);
diff --git a/lib/src/chunk_builder.dart b/lib/src/chunk_builder.dart
index 54695cf..0f265ec 100644
--- a/lib/src/chunk_builder.dart
+++ b/lib/src/chunk_builder.dart
@@ -384,7 +384,11 @@
 
   /// Ends the innermost rule.
   void endRule() {
-    _rules.removeLast();
+    if (_lazyRules.isNotEmpty) {
+      _lazyRules.removeLast();
+    } else {
+      _rules.removeLast();
+    }
   }
 
   /// Pre-emptively forces all of the current rules to become hard splits.
diff --git a/lib/src/source_visitor.dart b/lib/src/source_visitor.dart
index 529e420..48306ac 100644
--- a/lib/src/source_visitor.dart
+++ b/lib/src/source_visitor.dart
@@ -1880,25 +1880,42 @@
 
     _startLiteralBody(leftBracket);
 
-    // Always use a hard rule to split the elements. The parent chunk of
-    // the collection will handle the unsplit case, so this only comes
-    // into play when the collection is split.
-    var rule = new Rule.hard();
-    builder.startRule(rule);
-
     // If a collection contains a line comment, we assume it's a big complex
     // blob of data with some documented structure. In that case, the user
     // probably broke the elements into lines deliberately, so preserve those.
     var preserveNewlines = _containsLineComments(elements, rightBracket);
 
+    var rule;
+    var lineRule;
+    if (preserveNewlines) {
+      // Newlines are significant, so we'll explicitly write those. Elements
+      // on the same line all share an argument-list-like rule that allows
+      // splitting between zero, one, or all of them. This is faster in long
+      // lists than using individual splits after each element.
+      lineRule = new TypeArgumentRule();
+      builder.startLazyRule(lineRule);
+    } else {
+      // Newlines aren't significant, so use a hard rule to split the elements.
+      // The parent chunk of the collection will handle the unsplit case, so
+      // this only comes into play when the collection is split.
+      rule = new Rule.hard();
+      builder.startRule(rule);
+    }
+
     for (var element in elements) {
       if (element != elements.first) {
         if (preserveNewlines) {
+          // See if the next element is on the next line.
           if (_endLine(element.beginToken.previous) !=
               _startLine(element.beginToken)) {
             oneOrTwoNewlines();
+
+            // Start a new rule for the new line.
+            builder.endRule();
+            lineRule = new TypeArgumentRule();
+            builder.startLazyRule(lineRule);
           } else {
-            soloSplit();
+            lineRule.beforeArgument(split());
           }
         } else {
           builder.split(nest: false, space: true);
diff --git a/pubspec.yaml b/pubspec.yaml
index ef995a4..fe4953b 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: dart_style
-version: 0.2.3
+version: 0.2.4
 author: Dart Team <misc@dartlang.org>
 description: Opinionated, automatic Dart source code formatter.
 homepage: https://github.com/dart-lang/dart_style
diff --git a/test/regression/0400/0484.stmt b/test/regression/0400/0484.stmt
new file mode 100644
index 0000000..f52a190
--- /dev/null
+++ b/test/regression/0400/0484.stmt
@@ -0,0 +1,29 @@
+>>>
+var list = [
+  // comment
+  function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3), function(a: 1, b: 2, c: 3),
+];
+<<<
+var list = [
+  // comment
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+  function(a: 1, b: 2, c: 3),
+];
\ No newline at end of file